cx88-input.c 16.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/*
 *
 * Device driver for GPIO attached remote control interfaces
 * on Conexant 2388x based TV/DVB cards.
 *
 * Copyright (c) 2003 Pavel Machek
 * Copyright (c) 2004 Gerd Knorr
8
 * Copyright (c) 2004, 2005 Chris Pascoe
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/init.h>
26
#include <linux/hrtimer.h>
L
Linus Torvalds 已提交
27
#include <linux/pci.h>
28
#include <linux/slab.h>
L
Linus Torvalds 已提交
29 30 31
#include <linux/module.h>

#include "cx88.h"
32
#include <media/rc-core.h>
L
Linus Torvalds 已提交
33

34 35
#define MODULE_NAME "cx88xx"

L
Linus Torvalds 已提交
36 37 38
/* ---------------------------------------------------------------------- */

struct cx88_IR {
M
Mauro Carvalho Chehab 已提交
39
	struct cx88_core *core;
40
	struct rc_dev *dev;
41 42 43

	int users;

M
Mauro Carvalho Chehab 已提交
44 45
	char name[32];
	char phys[32];
L
Linus Torvalds 已提交
46 47

	/* sample from gpio pin 16 */
48
	u32 sampling;
L
Linus Torvalds 已提交
49 50

	/* poll external decoder */
M
Mauro Carvalho Chehab 已提交
51
	int polling;
52
	struct hrtimer timer;
M
Mauro Carvalho Chehab 已提交
53 54 55 56 57
	u32 gpio_addr;
	u32 last_gpio;
	u32 mask_keycode;
	u32 mask_keydown;
	u32 mask_keyup;
L
Linus Torvalds 已提交
58 59
};

60 61 62 63
static unsigned ir_samplerate = 4;
module_param(ir_samplerate, uint, 0444);
MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4");

64
static int ir_debug;
M
Mauro Carvalho Chehab 已提交
65
module_param(ir_debug, int, 0644);	/* debug level [IR] */
L
Linus Torvalds 已提交
66 67 68
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");

#define ir_dprintk(fmt, arg...)	if (ir_debug) \
69
	printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg)
L
Linus Torvalds 已提交
70

71 72 73
#define dprintk(fmt, arg...)	if (ir_debug) \
	printk(KERN_DEBUG "cx88 IR: " fmt , ##arg)

L
Linus Torvalds 已提交
74 75 76 77 78
/* ---------------------------------------------------------------------- */

static void cx88_ir_handle_key(struct cx88_IR *ir)
{
	struct cx88_core *core = ir->core;
79
	u32 gpio, data, auxgpio;
L
Linus Torvalds 已提交
80 81 82

	/* read gpio value */
	gpio = cx_read(ir->gpio_addr);
83
	switch (core->boardnr) {
84
	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
85 86 87 88 89 90 91 92 93 94 95 96 97 98
		/* This board apparently uses a combination of 2 GPIO
		   to represent the keys. Additionally, the second GPIO
		   can be used for parity.

		   Example:

		   for key "5"
			gpio = 0x758, auxgpio = 0xe5 or 0xf5
		   for key "Power"
			gpio = 0x758, auxgpio = 0xed or 0xfd
		 */

		auxgpio = cx_read(MO_GP1_IO);
		/* Take out the parity part */
99
		gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
100 101
		break;
	case CX88_BOARD_WINFAST_DTV1000:
102
	case CX88_BOARD_WINFAST_DTV1800H:
103
	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
104 105
		gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
		auxgpio = gpio;
106 107
		break;
	default:
108
		auxgpio = gpio;
109
	}
L
Linus Torvalds 已提交
110
	if (ir->polling) {
111
		if (ir->last_gpio == auxgpio)
L
Linus Torvalds 已提交
112
			return;
113
		ir->last_gpio = auxgpio;
L
Linus Torvalds 已提交
114 115 116 117 118
	}

	/* extract data */
	data = ir_extract_bits(gpio, ir->mask_keycode);
	ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
M
Mauro Carvalho Chehab 已提交
119 120 121 122
		   gpio, data,
		   ir->polling ? "poll" : "irq",
		   (gpio & ir->mask_keydown) ? " down" : "",
		   (gpio & ir->mask_keyup) ? " up" : "");
L
Linus Torvalds 已提交
123

124
	if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) {
125 126 127 128
		u32 gpio_key = cx_read(MO_GP0_IO);

		data = (data << 4) | ((gpio_key & 0xf0) >> 4);

129
		rc_keydown(ir->dev, data, 0);
130 131

	} else if (ir->mask_keydown) {
L
Linus Torvalds 已提交
132
		/* bit set on keydown */
133
		if (gpio & ir->mask_keydown)
134
			rc_keydown_notimeout(ir->dev, data, 0);
135
		else
136
			rc_keyup(ir->dev);
L
Linus Torvalds 已提交
137 138 139

	} else if (ir->mask_keyup) {
		/* bit cleared on keydown */
140
		if (0 == (gpio & ir->mask_keyup))
141
			rc_keydown_notimeout(ir->dev, data, 0);
142
		else
143
			rc_keyup(ir->dev);
L
Linus Torvalds 已提交
144 145 146

	} else {
		/* can't distinguish keydown/up :-/ */
147 148
		rc_keydown_notimeout(ir->dev, data, 0);
		rc_keyup(ir->dev);
L
Linus Torvalds 已提交
149 150 151
	}
}

152
static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
L
Linus Torvalds 已提交
153
{
154 155
	unsigned long missed;
	struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
L
Linus Torvalds 已提交
156 157

	cx88_ir_handle_key(ir);
158 159 160 161 162 163
	missed = hrtimer_forward_now(&ir->timer,
				     ktime_set(0, ir->polling * 1000000));
	if (missed > 1)
		ir_dprintk("Missed ticks %ld\n", missed - 1);

	return HRTIMER_RESTART;
L
Linus Torvalds 已提交
164 165
}

166
static int __cx88_ir_start(void *priv)
167
{
168 169 170 171 172 173 174 175
	struct cx88_core *core = priv;
	struct cx88_IR *ir;

	if (!core || !core->ir)
		return -EINVAL;

	ir = core->ir;

176
	if (ir->polling) {
177 178 179 180 181
		hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		ir->timer.function = cx88_ir_work;
		hrtimer_start(&ir->timer,
			      ktime_set(0, ir->polling * 1000000),
			      HRTIMER_MODE_REL);
182 183
	}
	if (ir->sampling) {
184
		core->pci_irqmask |= PCI_INT_IR_SMPINT;
185 186
		cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */
		cx_write(MO_DDSCFG_IO, 0x5); /* enable */
187
	}
188
	return 0;
189 190
}

191
static void __cx88_ir_stop(void *priv)
192
{
193 194 195 196 197 198 199
	struct cx88_core *core = priv;
	struct cx88_IR *ir;

	if (!core || !core->ir)
		return;

	ir = core->ir;
200 201
	if (ir->sampling) {
		cx_write(MO_DDSCFG_IO, 0x0);
202
		core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
203 204
	}

205
	if (ir->polling)
206
		hrtimer_cancel(&ir->timer);
207 208
}

209 210 211 212 213 214 215 216 217 218 219 220 221 222
int cx88_ir_start(struct cx88_core *core)
{
	if (core->ir->users)
		return __cx88_ir_start(core);

	return 0;
}

void cx88_ir_stop(struct cx88_core *core)
{
	if (core->ir->users)
		__cx88_ir_stop(core);
}

223
static int cx88_ir_open(struct rc_dev *rc)
224
{
225
	struct cx88_core *core = rc->priv;
226 227 228 229 230

	core->ir->users++;
	return __cx88_ir_start(core);
}

231
static void cx88_ir_close(struct rc_dev *rc)
232
{
233
	struct cx88_core *core = rc->priv;
234 235 236 237 238 239

	core->ir->users--;
	if (!core->ir->users)
		__cx88_ir_stop(core);
}

L
Linus Torvalds 已提交
240 241 242 243 244
/* ---------------------------------------------------------------------- */

int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
	struct cx88_IR *ir;
245
	struct rc_dev *dev;
246
	char *ir_codes = NULL;
247
	u64 rc_type = RC_TYPE_OTHER;
248
	int err = -ENOMEM;
249 250 251
	u32 hardware_mask = 0;	/* For devices with a hardware mask, when
				 * used with a full-code IR table
				 */
L
Linus Torvalds 已提交
252

253
	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
254 255
	dev = rc_allocate_device();
	if (!ir || !dev)
256
		goto err_out_free;
257

258
	ir->dev = dev;
L
Linus Torvalds 已提交
259 260

	/* detect & configure */
261
	switch (core->boardnr) {
L
Linus Torvalds 已提交
262
	case CX88_BOARD_DNTV_LIVE_DVB_T:
263
	case CX88_BOARD_KWORLD_DVB_T:
264
	case CX88_BOARD_KWORLD_DVB_T_CX22702:
265
		ir_codes = RC_MAP_DNTV_LIVE_DVB_T;
M
Mauro Carvalho Chehab 已提交
266
		ir->gpio_addr = MO_GP1_IO;
L
Linus Torvalds 已提交
267
		ir->mask_keycode = 0x1f;
M
Mauro Carvalho Chehab 已提交
268 269
		ir->mask_keyup = 0x60;
		ir->polling = 50; /* ms */
L
Linus Torvalds 已提交
270
		break;
271
	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
272
		ir_codes = RC_MAP_CINERGY_1400;
273
		ir->sampling = 0xeb04; /* address */
274
		break;
L
Linus Torvalds 已提交
275 276
	case CX88_BOARD_HAUPPAUGE:
	case CX88_BOARD_HAUPPAUGE_DVB_T1:
277 278
	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
279
	case CX88_BOARD_HAUPPAUGE_HVR1100:
280
	case CX88_BOARD_HAUPPAUGE_HVR3000:
281 282
	case CX88_BOARD_HAUPPAUGE_HVR4000:
	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
283 284
	case CX88_BOARD_PCHDTV_HD3000:
	case CX88_BOARD_PCHDTV_HD5500:
285
	case CX88_BOARD_HAUPPAUGE_IRONLY:
286
		ir_codes = RC_MAP_HAUPPAUGE;
M
Mauro Carvalho Chehab 已提交
287
		ir->sampling = 1;
L
Linus Torvalds 已提交
288
		break;
289
	case CX88_BOARD_WINFAST_DTV2000H:
290
	case CX88_BOARD_WINFAST_DTV2000H_J:
291
	case CX88_BOARD_WINFAST_DTV1800H:
292
		ir_codes = RC_MAP_WINFAST;
M
Mauro Carvalho Chehab 已提交
293
		ir->gpio_addr = MO_GP0_IO;
L
Linus Torvalds 已提交
294
		ir->mask_keycode = 0x8f8;
M
Mauro Carvalho Chehab 已提交
295
		ir->mask_keyup = 0x100;
296
		ir->polling = 50; /* ms */
L
Linus Torvalds 已提交
297
		break;
298
	case CX88_BOARD_WINFAST2000XP_EXPERT:
299
	case CX88_BOARD_WINFAST_DTV1000:
300
	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
301
		ir_codes = RC_MAP_WINFAST;
302 303 304 305 306
		ir->gpio_addr = MO_GP0_IO;
		ir->mask_keycode = 0x8f8;
		ir->mask_keyup = 0x100;
		ir->polling = 1; /* ms */
		break;
L
Linus Torvalds 已提交
307
	case CX88_BOARD_IODATA_GVBCTV7E:
308
		ir_codes = RC_MAP_IODATA_BCTV7E;
M
Mauro Carvalho Chehab 已提交
309
		ir->gpio_addr = MO_GP0_IO;
L
Linus Torvalds 已提交
310 311
		ir->mask_keycode = 0xfd;
		ir->mask_keydown = 0x02;
M
Mauro Carvalho Chehab 已提交
312
		ir->polling = 5; /* ms */
L
Linus Torvalds 已提交
313
		break;
314
	case CX88_BOARD_PROLINK_PLAYTVPVR:
315
	case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
316 317 318 319 320 321 322 323
		/*
		 * It seems that this hardware is paired with NEC extended
		 * address 0x866b. So, unfortunately, its usage with other
		 * IR's with different address won't work. Still, there are
		 * other IR's from the same manufacturer that works, like the
		 * 002-T mini RC, provided with newer PV hardware
		 */
		ir_codes = RC_MAP_PIXELVIEW_MK12;
M
Mauro Carvalho Chehab 已提交
324 325
		ir->gpio_addr = MO_GP1_IO;
		ir->mask_keyup = 0x80;
326
		ir->polling = 10; /* ms */
327
		hardware_mask = 0x3f;	/* Hardware returns only 6 bits from command part */
328
		break;
329
	case CX88_BOARD_PROLINK_PV_8000GT:
330
	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
331
		ir_codes = RC_MAP_PIXELVIEW_NEW;
332 333 334 335 336
		ir->gpio_addr = MO_GP1_IO;
		ir->mask_keycode = 0x3f;
		ir->mask_keyup = 0x80;
		ir->polling = 1; /* ms */
		break;
337
	case CX88_BOARD_KWORLD_LTV883:
338
		ir_codes = RC_MAP_PIXELVIEW;
339 340 341 342 343
		ir->gpio_addr = MO_GP1_IO;
		ir->mask_keycode = 0x1f;
		ir->mask_keyup = 0x60;
		ir->polling = 1; /* ms */
		break;
M
Mauro Carvalho Chehab 已提交
344
	case CX88_BOARD_ADSTECH_DVB_T_PCI:
345
		ir_codes = RC_MAP_ADSTECH_DVB_T_PCI;
M
Mauro Carvalho Chehab 已提交
346
		ir->gpio_addr = MO_GP1_IO;
M
Mauro Carvalho Chehab 已提交
347
		ir->mask_keycode = 0xbf;
M
Mauro Carvalho Chehab 已提交
348 349 350 351
		ir->mask_keyup = 0x40;
		ir->polling = 50; /* ms */
		break;
	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
352
		ir_codes = RC_MAP_MSI_TVANYWHERE;
M
Mauro Carvalho Chehab 已提交
353 354 355 356
		ir->gpio_addr = MO_GP1_IO;
		ir->mask_keycode = 0x1f;
		ir->mask_keyup = 0x40;
		ir->polling = 1; /* ms */
M
Mauro Carvalho Chehab 已提交
357
		break;
358
	case CX88_BOARD_AVERTV_303:
359
	case CX88_BOARD_AVERTV_STUDIO_303:
360
		ir_codes         = RC_MAP_AVERTV_303;
361 362 363 364 365
		ir->gpio_addr    = MO_GP2_IO;
		ir->mask_keycode = 0xfb;
		ir->mask_keydown = 0x02;
		ir->polling      = 50; /* ms */
		break;
366 367 368 369 370
	case CX88_BOARD_OMICOM_SS4_PCI:
	case CX88_BOARD_SATTRADE_ST4200:
	case CX88_BOARD_TBS_8920:
	case CX88_BOARD_TBS_8910:
	case CX88_BOARD_PROF_7300:
371
	case CX88_BOARD_PROF_7301:
372
	case CX88_BOARD_PROF_6200:
373
		ir_codes = RC_MAP_TBS_NEC;
374 375
		ir->sampling = 0xff00; /* address */
		break;
376
	case CX88_BOARD_TEVII_S464:
377 378
	case CX88_BOARD_TEVII_S460:
	case CX88_BOARD_TEVII_S420:
379
		ir_codes = RC_MAP_TEVII_NEC;
380 381
		ir->sampling = 0xff00; /* address */
		break;
382
	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
383
		ir_codes         = RC_MAP_DNTV_LIVE_DVBT_PRO;
384
		ir->sampling     = 0xff00; /* address */
385
		break;
386
	case CX88_BOARD_NORWOOD_MICRO:
387
		ir_codes         = RC_MAP_NORWOOD;
388 389 390 391 392
		ir->gpio_addr    = MO_GP1_IO;
		ir->mask_keycode = 0x0e;
		ir->mask_keyup   = 0x80;
		ir->polling      = 50; /* ms */
		break;
393
	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
394
		ir_codes         = RC_MAP_NPGTECH;
395
		ir->gpio_addr    = MO_GP0_IO;
396
		ir->mask_keycode = 0xfa;
397
		ir->polling      = 50; /* ms */
398
		break;
399
	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
400
		ir_codes         = RC_MAP_PINNACLE_PCTV_HD;
401
		ir->sampling     = 1;
402
		break;
403
	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
404
		ir_codes         = RC_MAP_POWERCOLOR_REAL_ANGEL;
405
		ir->gpio_addr    = MO_GP2_IO;
406
		ir->mask_keycode = 0x7e;
407
		ir->polling      = 100; /* ms */
408
		break;
409 410
	case CX88_BOARD_TWINHAN_VP1027_DVBS:
		ir_codes         = RC_MAP_TWINHAN_VP1027_DVBS;
411
		rc_type          = RC_TYPE_NEC;
412 413
		ir->sampling     = 0xff00; /* address */
		break;
L
Linus Torvalds 已提交
414
	}
415

416
	if (!ir_codes) {
417 418
		err = -ENODEV;
		goto err_out_free;
L
Linus Torvalds 已提交
419 420
	}

421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
	/*
	 * The usage of mask_keycode were very convenient, due to several
	 * reasons. Among others, the scancode tables were using the scancode
	 * as the index elements. So, the less bits it was used, the smaller
	 * the table were stored. After the input changes, the better is to use
	 * the full scancodes, since it allows replacing the IR remote by
	 * another one. Unfortunately, there are still some hardware, like
	 * Pixelview Ultra Pro, where only part of the scancode is sent via
	 * GPIO. So, there's no way to get the full scancode. Due to that,
	 * hardware_mask were introduced here: it represents those hardware
	 * that has such limits.
	 */
	if (hardware_mask && !ir->mask_keycode)
		ir->mask_keycode = hardware_mask;

L
Linus Torvalds 已提交
436
	/* init input device */
437
	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
M
Mauro Carvalho Chehab 已提交
438
	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
L
Linus Torvalds 已提交
439

440 441 442 443
	dev->input_name = ir->name;
	dev->input_phys = ir->phys;
	dev->input_id.bustype = BUS_PCI;
	dev->input_id.version = 1;
L
Linus Torvalds 已提交
444
	if (pci->subsystem_vendor) {
445 446
		dev->input_id.vendor = pci->subsystem_vendor;
		dev->input_id.product = pci->subsystem_device;
L
Linus Torvalds 已提交
447
	} else {
448 449
		dev->input_id.vendor = pci->vendor;
		dev->input_id.product = pci->device;
L
Linus Torvalds 已提交
450
	}
451 452 453 454 455 456 457
	dev->dev.parent = &pci->dev;
	dev->map_name = ir_codes;
	dev->driver_name = MODULE_NAME;
	dev->priv = core;
	dev->open = cx88_ir_open;
	dev->close = cx88_ir_close;
	dev->scanmask = hardware_mask;
L
Linus Torvalds 已提交
458

459
	if (ir->sampling) {
460 461 462 463
		dev->driver_type = RC_DRIVER_IR_RAW;
		dev->timeout = 10 * 1000 * 1000; /* 10 ms */
	} else {
		dev->driver_type = RC_DRIVER_SCANCODE;
464
		dev->allowed_protos = rc_type;
465 466 467 468
	}

	ir->core = core;
	core->ir = ir;
L
Linus Torvalds 已提交
469 470

	/* all done */
471
	err = rc_register_device(dev);
472
	if (err)
473
		goto err_out_free;
L
Linus Torvalds 已提交
474 475

	return 0;
476

477 478
err_out_free:
	rc_free_device(dev);
479
	core->ir = NULL;
480 481
	kfree(ir);
	return err;
L
Linus Torvalds 已提交
482 483 484 485 486 487 488 489 490 491
}

int cx88_ir_fini(struct cx88_core *core)
{
	struct cx88_IR *ir = core->ir;

	/* skip detach on non attached boards */
	if (NULL == ir)
		return 0;

492
	cx88_ir_stop(core);
493
	rc_unregister_device(ir->dev);
L
Linus Torvalds 已提交
494 495 496 497 498 499 500 501 502 503 504 505
	kfree(ir);

	/* done */
	core->ir = NULL;
	return 0;
}

/* ---------------------------------------------------------------------- */

void cx88_ir_irq(struct cx88_core *core)
{
	struct cx88_IR *ir = core->ir;
506 507 508
	u32 samples;
	unsigned todo, bits;
	struct ir_raw_event ev;
L
Linus Torvalds 已提交
509

510
	if (!ir || !ir->sampling)
L
Linus Torvalds 已提交
511 512
		return;

513 514 515 516 517
	/*
	 * Samples are stored in a 32 bit register, oldest sample in
	 * the msb. A set bit represents space and an unset bit
	 * represents a pulse.
	 */
L
Linus Torvalds 已提交
518
	samples = cx_read(MO_SAMPLE_IO);
519

520
	if (samples == 0xff && ir->dev->idle)
521
		return;
522

523 524 525 526
	init_ir_raw_event(&ev);
	for (todo = 32; todo > 0; todo -= bits) {
		ev.pulse = samples & 0x80000000 ? false : true;
		bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
527
		ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
528
		ir_raw_event_store_with_filter(ir->dev, &ev);
529
		samples <<= bits;
L
Linus Torvalds 已提交
530
	}
531
	ir_raw_event_handle(ir->dev);
L
Linus Torvalds 已提交
532 533
}

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
	int flags, code;

	/* poll IR chip */
	flags = i2c_smbus_read_byte_data(ir->c, 0x10);
	if (flags < 0) {
		dprintk("read error\n");
		return 0;
	}
	/* key pressed ? */
	if (0 == (flags & 0x80))
		return 0;

	/* read actual key code */
	code = i2c_smbus_read_byte_data(ir->c, 0x00);
	if (code < 0) {
		dprintk("read error\n");
		return 0;
	}

	dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
		   code & 0xff, flags & 0xff);

	*ir_key = code & 0xff;
	*ir_raw = code;
	return 1;
}

563 564 565
void cx88_i2c_init_ir(struct cx88_core *core)
{
	struct i2c_board_info info;
566
	const unsigned short default_addr_list[] = {
567 568 569
		0x18, 0x6b, 0x71,
		I2C_CLIENT_END
	};
570 571 572 573 574
	const unsigned short pvr2000_addr_list[] = {
		0x18, 0x1a,
		I2C_CLIENT_END
	};
	const unsigned short *addr_list = default_addr_list;
575 576 577 578 579 580 581 582
	const unsigned short *addrp;
	/* Instantiate the IR receiver device, if present */
	if (0 != core->i2c_rc)
		return;

	memset(&info, 0, sizeof(struct i2c_board_info));
	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);

583 584 585 586 587 588 589 590 591 592
	switch (core->boardnr) {
	case CX88_BOARD_LEADTEK_PVR2000:
		addr_list = pvr2000_addr_list;
		core->init_data.name = "cx88 Leadtek PVR 2000 remote";
		core->init_data.type = RC_TYPE_UNKNOWN;
		core->init_data.get_key = get_key_pvr2000;
		core->init_data.ir_codes = RC_MAP_EMPTY;
		break;
	}

593 594 595 596 597 598 599 600 601 602 603 604 605 606
	/*
	 * We can't call i2c_new_probed_device() because it uses
	 * quick writes for probing and at least some RC receiver
	 * devices only reply to reads.
	 * Also, Hauppauge XVR needs to be specified, as address 0x71
	 * conflicts with another remote type used with saa7134
	 */
	for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
		info.platform_data = NULL;
		memset(&core->init_data, 0, sizeof(core->init_data));

		if (*addrp == 0x71) {
			/* Hauppauge XVR */
			core->init_data.name = "cx88 Hauppauge XVR remote";
607
			core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
608
			core->init_data.type = RC_TYPE_RC5;
609 610 611 612 613 614 615 616 617 618 619 620 621 622
			core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;

			info.platform_data = &core->init_data;
		}
		if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
					I2C_SMBUS_READ, 0,
					I2C_SMBUS_QUICK, NULL) >= 0) {
			info.addr = *addrp;
			i2c_new_device(&core->i2c_adap, &info);
			break;
		}
	}
}

L
Linus Torvalds 已提交
623 624 625 626 627
/* ---------------------------------------------------------------------- */

MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
MODULE_LICENSE("GPL");