cx88-input.c 16.1 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_DTV2000H_PLUS:
104
	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
105 106
		gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
		auxgpio = gpio;
107 108
		break;
	default:
109
		auxgpio = gpio;
110
	}
L
Linus Torvalds 已提交
111
	if (ir->polling) {
112
		if (ir->last_gpio == auxgpio)
L
Linus Torvalds 已提交
113
			return;
114
		ir->last_gpio = auxgpio;
L
Linus Torvalds 已提交
115 116 117 118 119
	}

	/* 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 已提交
120 121 122 123
		   gpio, data,
		   ir->polling ? "poll" : "irq",
		   (gpio & ir->mask_keydown) ? " down" : "",
		   (gpio & ir->mask_keyup) ? " up" : "");
L
Linus Torvalds 已提交
124

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

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

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

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

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

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

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

	cx88_ir_handle_key(ir);
159 160 161 162 163 164
	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 已提交
165 166
}

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

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

	ir = core->ir;

177
	if (ir->polling) {
178 179 180 181 182
		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);
183 184
	}
	if (ir->sampling) {
185
		core->pci_irqmask |= PCI_INT_IR_SMPINT;
186 187
		cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */
		cx_write(MO_DDSCFG_IO, 0x5); /* enable */
188
	}
189
	return 0;
190 191
}

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

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

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

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

210 211 212 213 214 215 216 217 218 219 220 221 222 223
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);
}

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

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

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

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

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

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

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

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

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

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

423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
	/*
	 * 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 已提交
438
	/* init input device */
439
	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
M
Mauro Carvalho Chehab 已提交
440
	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
L
Linus Torvalds 已提交
441

442 443 444 445
	dev->input_name = ir->name;
	dev->input_phys = ir->phys;
	dev->input_id.bustype = BUS_PCI;
	dev->input_id.version = 1;
L
Linus Torvalds 已提交
446
	if (pci->subsystem_vendor) {
447 448
		dev->input_id.vendor = pci->subsystem_vendor;
		dev->input_id.product = pci->subsystem_device;
L
Linus Torvalds 已提交
449
	} else {
450 451
		dev->input_id.vendor = pci->vendor;
		dev->input_id.product = pci->device;
L
Linus Torvalds 已提交
452
	}
453 454 455 456 457 458 459
	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 已提交
460

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

	ir->core = core;
	core->ir = ir;
L
Linus Torvalds 已提交
471 472

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

	return 0;
478

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

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;

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

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

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

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

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

515 516 517 518 519
	/*
	 * 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 已提交
520
	samples = cx_read(MO_SAMPLE_IO);
521

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

525 526 527 528
	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));
529
		ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
530
		ir_raw_event_store_with_filter(ir->dev, &ev);
531
		samples <<= bits;
L
Linus Torvalds 已提交
532
	}
533
	ir_raw_event_handle(ir->dev);
L
Linus Torvalds 已提交
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 563 564
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;
}

565 566 567
void cx88_i2c_init_ir(struct cx88_core *core)
{
	struct i2c_board_info info;
568
	const unsigned short default_addr_list[] = {
569 570 571
		0x18, 0x6b, 0x71,
		I2C_CLIENT_END
	};
572 573 574 575 576
	const unsigned short pvr2000_addr_list[] = {
		0x18, 0x1a,
		I2C_CLIENT_END
	};
	const unsigned short *addr_list = default_addr_list;
577 578 579 580 581 582 583 584
	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);

585 586 587 588 589 590 591 592 593 594
	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;
	}

595 596 597 598 599 600 601 602 603 604 605 606 607 608
	/*
	 * 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";
609
			core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
610
			core->init_data.type = RC_TYPE_RC5;
611 612 613 614 615 616 617 618 619 620 621 622 623 624
			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 已提交
625 626 627 628 629
/* ---------------------------------------------------------------------- */

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