cx88-input.c 15.4 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-common.h>
L
Linus Torvalds 已提交
34

35 36
#define MODULE_NAME "cx88xx"

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

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

	int users;

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

	/* sample from gpio pin 16 */
51
	u32 sampling;
M
Mauro Carvalho Chehab 已提交
52 53 54
	u32 samples[16];
	int scount;
	unsigned long release;
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_input_keydown(ir->input, &ir->ir, data);
129 130 131
		ir_input_nokey(ir->input, &ir->ir);

	} else if (ir->mask_keydown) {
L
Linus Torvalds 已提交
132 133
		/* bit set on keydown */
		if (gpio & ir->mask_keydown) {
134
			ir_input_keydown(ir->input, &ir->ir, data);
L
Linus Torvalds 已提交
135
		} else {
136
			ir_input_nokey(ir->input, &ir->ir);
L
Linus Torvalds 已提交
137 138 139 140 141
		}

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

	} else {
		/* can't distinguish keydown/up :-/ */
149
		ir_input_keydown(ir->input, &ir->ir, data);
150
		ir_input_nokey(ir->input, &ir->ir);
L
Linus Torvalds 已提交
151 152 153
	}
}

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

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

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

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

	ir = core->ir;

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

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

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

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

207
	if (ir->polling)
208
		hrtimer_cancel(&ir->timer);
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 234 235 236 237 238 239 240 241
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 已提交
242 243 244 245 246
/* ---------------------------------------------------------------------- */

int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
	struct cx88_IR *ir;
247
	struct input_dev *input_dev;
248
	char *ir_codes = NULL;
249
	u64 ir_type = IR_TYPE_OTHER;
250
	int err = -ENOMEM;
L
Linus Torvalds 已提交
251

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

	ir->input = input_dev;
L
Linus Torvalds 已提交
258 259

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

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

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

417
	err = ir_input_init(input_dev, &ir->ir, ir_type);
418 419 420
	if (err < 0)
		goto err_out_free;

421 422 423 424
	input_dev->name = ir->name;
	input_dev->phys = ir->phys;
	input_dev->id.bustype = BUS_PCI;
	input_dev->id.version = 1;
L
Linus Torvalds 已提交
425
	if (pci->subsystem_vendor) {
426 427
		input_dev->id.vendor = pci->subsystem_vendor;
		input_dev->id.product = pci->subsystem_device;
L
Linus Torvalds 已提交
428
	} else {
429 430
		input_dev->id.vendor = pci->vendor;
		input_dev->id.product = pci->device;
L
Linus Torvalds 已提交
431
	}
432
	input_dev->dev.parent = &pci->dev;
L
Linus Torvalds 已提交
433 434 435 436
	/* record handles to ourself */
	ir->core = core;
	core->ir = ir;

437 438 439
	ir->props.priv = core;
	ir->props.open = cx88_ir_open;
	ir->props.close = cx88_ir_close;
L
Linus Torvalds 已提交
440 441

	/* all done */
442
	err = ir_input_register(ir->input, ir_codes, &ir->props, MODULE_NAME);
443
	if (err)
444
		goto err_out_free;
L
Linus Torvalds 已提交
445 446

	return 0;
447 448

 err_out_free:
449
	core->ir = NULL;
450 451
	kfree(ir);
	return err;
L
Linus Torvalds 已提交
452 453 454 455 456 457 458 459 460 461
}

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;

462
	cx88_ir_stop(core);
463
	ir_input_unregister(ir->input);
L
Linus Torvalds 已提交
464 465 466 467 468 469 470 471 472 473 474 475
	kfree(ir);

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

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

void cx88_ir_irq(struct cx88_core *core)
{
	struct cx88_IR *ir = core->ir;
476
	u32 samples, ircode;
477
	int i, start, range, toggle, dev, code;
L
Linus Torvalds 已提交
478 479 480 481 482 483 484

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

	samples = cx_read(MO_SAMPLE_IO);
M
Mauro Carvalho Chehab 已提交
485
	if (0 != samples && 0xffffffff != samples) {
L
Linus Torvalds 已提交
486 487 488 489 490 491 492
		/* record sample data */
		if (ir->scount < ARRAY_SIZE(ir->samples))
			ir->samples[ir->scount++] = samples;
		return;
	}
	if (!ir->scount) {
		/* nothing to sample */
M
Mauro Carvalho Chehab 已提交
493
		if (ir->ir.keypressed && time_after(jiffies, ir->release))
494
			ir_input_nokey(ir->input, &ir->ir);
L
Linus Torvalds 已提交
495 496 497 498 499 500 501 502 503
		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 已提交
504
		ir_dump_samples(ir->samples, ir->scount);
L
Linus Torvalds 已提交
505 506

	/* decode it */
507
	switch (core->boardnr) {
508 509
	case CX88_BOARD_TEVII_S460:
	case CX88_BOARD_TEVII_S420:
510
	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
511
	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
512 513 514 515 516
	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:
517
	case CX88_BOARD_PROF_7301:
518
	case CX88_BOARD_PROF_6200:
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
		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");
			ir->release = jiffies + msecs_to_jiffies(120);
			break;
		}

534
		if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
535
			ir_dprintk("pulse distance decoded wrong address\n");
536
			break;
537 538 539 540 541 542 543 544 545
		}

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

		ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f);

546
		ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f);
547 548
		ir->release = jiffies + msecs_to_jiffies(120);
		break;
L
Linus Torvalds 已提交
549 550
	case CX88_BOARD_HAUPPAUGE:
	case CX88_BOARD_HAUPPAUGE_DVB_T1:
551 552
	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
C
 
Chris Pascoe 已提交
553
	case CX88_BOARD_HAUPPAUGE_HVR1100:
554
	case CX88_BOARD_HAUPPAUGE_HVR3000:
555 556
	case CX88_BOARD_HAUPPAUGE_HVR4000:
	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
557 558
	case CX88_BOARD_PCHDTV_HD3000:
	case CX88_BOARD_PCHDTV_HD5500:
559
	case CX88_BOARD_HAUPPAUGE_IRONLY:
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
		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;
583
		ir_input_keydown(ir->input, &ir->ir, code);
584 585 586
		ir->release = jiffies + msecs_to_jiffies(120);
		break;
	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
587 588 589
		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
		ir_dprintk("biphase decoded: %x\n", ircode);
		if ((ircode & 0xfffff000) != 0x3000)
L
Linus Torvalds 已提交
590
			break;
591
		ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f);
L
Linus Torvalds 已提交
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
		ir->release = jiffies + msecs_to_jiffies(120);
		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:
 */