cx88-input.c 16.2 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 28
#include <linux/input.h>
#include <linux/pci.h>
29
#include <linux/slab.h>
L
Linus Torvalds 已提交
30 31 32
#include <linux/module.h>

#include "cx88.h"
33
#include <media/ir-core.h>
34
#include <media/ir-common.h>
L
Linus Torvalds 已提交
35

36 37
#define MODULE_NAME "cx88xx"

L
Linus Torvalds 已提交
38 39 40
/* ---------------------------------------------------------------------- */

struct cx88_IR {
M
Mauro Carvalho Chehab 已提交
41
	struct cx88_core *core;
42
	struct input_dev *input;
43
	struct ir_dev_props props;
44
	u64 ir_type;
45 46 47

	int users;

M
Mauro Carvalho Chehab 已提交
48 49
	char name[32];
	char phys[32];
L
Linus Torvalds 已提交
50 51

	/* sample from gpio pin 16 */
52
	u32 sampling;
M
Mauro Carvalho Chehab 已提交
53 54
	u32 samples[16];
	int scount;
L
Linus Torvalds 已提交
55 56

	/* poll external decoder */
M
Mauro Carvalho Chehab 已提交
57
	int polling;
58
	struct hrtimer timer;
M
Mauro Carvalho Chehab 已提交
59 60 61 62 63
	u32 gpio_addr;
	u32 last_gpio;
	u32 mask_keycode;
	u32 mask_keydown;
	u32 mask_keyup;
L
Linus Torvalds 已提交
64 65
};

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

#define ir_dprintk(fmt, arg...)	if (ir_debug) \
71
	printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg)
L
Linus Torvalds 已提交
72 73 74 75 76 77

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

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

	/* read gpio value */
	gpio = cx_read(ir->gpio_addr);
82
	switch (core->boardnr) {
83
	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
84 85 86 87 88 89 90 91 92 93 94 95 96 97
		/* 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 */
98
		gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
99 100
		break;
	case CX88_BOARD_WINFAST_DTV1000:
101
	case CX88_BOARD_WINFAST_DTV1800H:
102
	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
103 104
		gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
		auxgpio = gpio;
105 106
		break;
	default:
107
		auxgpio = gpio;
108
	}
L
Linus Torvalds 已提交
109
	if (ir->polling) {
110
		if (ir->last_gpio == auxgpio)
L
Linus Torvalds 已提交
111
			return;
112
		ir->last_gpio = auxgpio;
L
Linus Torvalds 已提交
113 114 115 116 117
	}

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

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

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

128
		ir_keydown(ir->input, data, 0);
129 130

	} else if (ir->mask_keydown) {
L
Linus Torvalds 已提交
131
		/* bit set on keydown */
132 133
		if (gpio & ir->mask_keydown)
			ir_keydown(ir->input, data, 0);
L
Linus Torvalds 已提交
134 135 136

	} else if (ir->mask_keyup) {
		/* bit cleared on keydown */
137 138
		if (0 == (gpio & ir->mask_keyup))
			ir_keydown(ir->input, data, 0);
L
Linus Torvalds 已提交
139 140 141

	} else {
		/* can't distinguish keydown/up :-/ */
142
		ir_keydown(ir->input, data, 0);
L
Linus Torvalds 已提交
143 144 145
	}
}

146
static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
L
Linus Torvalds 已提交
147
{
148 149
	unsigned long missed;
	struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
L
Linus Torvalds 已提交
150 151

	cx88_ir_handle_key(ir);
152 153 154 155 156 157
	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 已提交
158 159
}

160
static int __cx88_ir_start(void *priv)
161
{
162 163 164 165 166 167 168 169
	struct cx88_core *core = priv;
	struct cx88_IR *ir;

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

	ir = core->ir;

170
	if (ir->polling) {
171 172 173 174 175
		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);
176 177
	}
	if (ir->sampling) {
178
		core->pci_irqmask |= PCI_INT_IR_SMPINT;
179 180 181
		cx_write(MO_DDS_IO, 0xa80a80);	/* 4 kHz sample rate */
		cx_write(MO_DDSCFG_IO, 0x5);	/* enable */
	}
182
	return 0;
183 184
}

185
static void __cx88_ir_stop(void *priv)
186
{
187 188 189 190 191 192 193
	struct cx88_core *core = priv;
	struct cx88_IR *ir;

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

	ir = core->ir;
194 195
	if (ir->sampling) {
		cx_write(MO_DDSCFG_IO, 0x0);
196
		core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
197 198
	}

199
	if (ir->polling)
200
		hrtimer_cancel(&ir->timer);
201 202
}

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
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);
}

static int cx88_ir_open(void *priv)
{
	struct cx88_core *core = priv;

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

static void cx88_ir_close(void *priv)
{
	struct cx88_core *core = priv;

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

L
Linus Torvalds 已提交
234 235 236 237 238
/* ---------------------------------------------------------------------- */

int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
	struct cx88_IR *ir;
239
	struct input_dev *input_dev;
240
	char *ir_codes = NULL;
241
	u64 ir_type = IR_TYPE_OTHER;
242
	int err = -ENOMEM;
243 244 245
	u32 hardware_mask = 0;	/* For devices with a hardware mask, when
				 * used with a full-code IR table
				 */
L
Linus Torvalds 已提交
246

247 248
	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
	input_dev = input_allocate_device();
249 250
	if (!ir || !input_dev)
		goto err_out_free;
251 252

	ir->input = input_dev;
L
Linus Torvalds 已提交
253 254

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

L
Linus Torvalds 已提交
410
	if (NULL == ir_codes) {
411 412
		err = -ENODEV;
		goto err_out_free;
L
Linus Torvalds 已提交
413 414
	}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	/*
	 * 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 已提交
430
	/* init input device */
431
	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
M
Mauro Carvalho Chehab 已提交
432
	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
L
Linus Torvalds 已提交
433

434
	ir->ir_type = ir_type;
435

436 437 438 439
	input_dev->name = ir->name;
	input_dev->phys = ir->phys;
	input_dev->id.bustype = BUS_PCI;
	input_dev->id.version = 1;
L
Linus Torvalds 已提交
440
	if (pci->subsystem_vendor) {
441 442
		input_dev->id.vendor = pci->subsystem_vendor;
		input_dev->id.product = pci->subsystem_device;
L
Linus Torvalds 已提交
443
	} else {
444 445
		input_dev->id.vendor = pci->vendor;
		input_dev->id.product = pci->device;
L
Linus Torvalds 已提交
446
	}
447
	input_dev->dev.parent = &pci->dev;
L
Linus Torvalds 已提交
448 449 450 451
	/* record handles to ourself */
	ir->core = core;
	core->ir = ir;

452 453 454
	ir->props.priv = core;
	ir->props.open = cx88_ir_open;
	ir->props.close = cx88_ir_close;
455
	ir->props.scanmask = hardware_mask;
L
Linus Torvalds 已提交
456 457

	/* all done */
458
	err = ir_input_register(ir->input, ir_codes, &ir->props, MODULE_NAME);
459
	if (err)
460
		goto err_out_free;
L
Linus Torvalds 已提交
461 462

	return 0;
463 464

 err_out_free:
465
	core->ir = NULL;
466 467
	kfree(ir);
	return err;
L
Linus Torvalds 已提交
468 469 470 471 472 473 474 475 476 477
}

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;

478
	cx88_ir_stop(core);
479
	ir_input_unregister(ir->input);
L
Linus Torvalds 已提交
480 481 482 483 484 485 486 487 488 489 490 491
	kfree(ir);

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

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

void cx88_ir_irq(struct cx88_core *core)
{
	struct cx88_IR *ir = core->ir;
492
	u32 samples, ircode;
493
	int i, start, range, toggle, dev, code;
L
Linus Torvalds 已提交
494 495 496 497 498 499 500

	if (NULL == ir)
		return;
	if (!ir->sampling)
		return;

	samples = cx_read(MO_SAMPLE_IO);
M
Mauro Carvalho Chehab 已提交
501
	if (0 != samples && 0xffffffff != samples) {
L
Linus Torvalds 已提交
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
		/* record sample data */
		if (ir->scount < ARRAY_SIZE(ir->samples))
			ir->samples[ir->scount++] = samples;
		return;
	}
	if (!ir->scount) {
		/* nothing to sample */
		return;
	}

	/* have a complete sample */
	if (ir->scount < ARRAY_SIZE(ir->samples))
		ir->samples[ir->scount++] = samples;
	for (i = 0; i < ir->scount; i++)
		ir->samples[i] = ~ir->samples[i];
	if (ir_debug)
M
Mauro Carvalho Chehab 已提交
518
		ir_dump_samples(ir->samples, ir->scount);
L
Linus Torvalds 已提交
519 520

	/* decode it */
521
	switch (core->boardnr) {
522 523
	case CX88_BOARD_TEVII_S460:
	case CX88_BOARD_TEVII_S420:
524
	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
525
	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
526 527 528 529 530
	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:
531
	case CX88_BOARD_PROF_7301:
532
	case CX88_BOARD_PROF_6200:
533 534 535 536 537 538 539 540 541 542 543
		ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);

		if (ircode == 0xffffffff) { /* decoding error */
			ir_dprintk("pulse distance decoding error\n");
			break;
		}

		ir_dprintk("pulse distance decoded: %x\n", ircode);

		if (ircode == 0) { /* key still pressed */
			ir_dprintk("pulse distance decoded repeat code\n");
544
			ir_repeat(ir->input);
545 546 547
			break;
		}

548
		if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
549
			ir_dprintk("pulse distance decoded wrong address\n");
550
			break;
551 552 553 554 555 556 557
		}

		if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
			ir_dprintk("pulse distance decoded wrong check sum\n");
			break;
		}

558 559
		ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff);
		ir_keydown(ir->input, (ircode >> 16) & 0xff, 0);
560
		break;
L
Linus Torvalds 已提交
561 562
	case CX88_BOARD_HAUPPAUGE:
	case CX88_BOARD_HAUPPAUGE_DVB_T1:
563 564
	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
C
 
Chris Pascoe 已提交
565
	case CX88_BOARD_HAUPPAUGE_HVR1100:
566
	case CX88_BOARD_HAUPPAUGE_HVR3000:
567 568
	case CX88_BOARD_HAUPPAUGE_HVR4000:
	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
569 570
	case CX88_BOARD_PCHDTV_HD3000:
	case CX88_BOARD_PCHDTV_HD5500:
571
	case CX88_BOARD_HAUPPAUGE_IRONLY:
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
		ir_dprintk("biphase decoded: %x\n", ircode);
		/*
		 * RC5 has an extension bit which adds a new range
		 * of available codes, this is detected here. Also
		 * hauppauge remotes (black/silver) always use
		 * specific device ids. If we do not filter the
		 * device ids then messages destined for devices
		 * such as TVs (id=0) will get through to the
		 * device causing mis-fired events.
		 */
		/* split rc5 data block ... */
		start = (ircode & 0x2000) >> 13;
		range = (ircode & 0x1000) >> 12;
		toggle= (ircode & 0x0800) >> 11;
		dev   = (ircode & 0x07c0) >> 6;
		code  = (ircode & 0x003f) | ((range << 6) ^ 0x0040);
		if( start != 1)
			/* no key pressed */
			break;
		if ( dev != 0x1e && dev != 0x1f )
			/* not a hauppauge remote */
			break;
595
		ir_keydown(ir->input, code, toggle);
596 597
		break;
	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
598 599 600
		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
		ir_dprintk("biphase decoded: %x\n", ircode);
		if ((ircode & 0xfffff000) != 0x3000)
L
Linus Torvalds 已提交
601
			break;
602 603 604
		/* Note: bit 0x800 being the toggle is assumed, not checked
		   with real hardware  */
		ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0);
L
Linus Torvalds 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
		break;
	}

	ir->scount = 0;
	return;
}

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

MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
MODULE_LICENSE("GPL");
/*
 * Local variables:
 * c-basic-offset: 8
 * End:
 */