Note: this patch depends on the budget-ci patches which I recently posted to this list. budget-ci: convert to using ir-common, use RC5 addresses etc. From: Darren Salt <linux@xxxxxxxxxxxxxxxxxxxxxxxxxxx> This converts the budget-ci driver so that it uses ir-common for some of its IR processing. In particular, the keymap for the Nova-T (sub 13c2:1011) is switched to the Hauppauge grey/black keymap, of which the keys on the supplied R808 remote control form a subset. Both bytes from the MSP430 are now required; the interrupt code MUST return quickly from processing the first byte else it may miss the second byte. (The first byte has bit 6 set and the key code in bits 5..0; the second has bit 6 clear and has the RC5 address in bits 4..0 and a flag (edge signalling) in bit 5.) The second event from Zenith remote controls should still be ignored. I'm unable to test this, not having one of these. Key repeat is properly handled. This requires a small change in ir-common: it now treats the second and successive calls to ir_input_keydown (for the same device & key) without an intervening ir_input_nokey() call as repeat events, and causes input_event to be called with "key repeat" rather than "key down". Two module parameters are added. Both are boolean; the described action occurs when the corresponding value is non-zero. * ir_debug Some unknown keys will be logged. Both code and address are output. * ir_any_rc5_address The RC5 address (if known) will be ignored. The RC5 address for the R808 remote control for my old Nova-T is 0x1F; this is the only address configured in this patch, and if any supported card is recognised as Nova-T, input with any other address (e.g. 0x1E from the A415 remote control for my new Nova-T) will, by default, be rejected. Signed-off-by: Darren Salt <linux@xxxxxxxxxxxxxxxxxxxxxxxxxxx> diff --git a/linux/drivers/media/common/ir-functions.c b/linux/drivers/media/common/ir-functions.c --- a/linux/drivers/media/common/ir-functions.c Wed Mar 22 16:45:04 2006 +++ b/linux/drivers/media/common/ir-functions.c Thu Mar 23 02:27:41 2006 @@ -53,7 +53,7 @@ } dprintk(1,"%s: key event code=%d down=%d\n", dev->name,ir->keycode,ir->keypressed); - input_report_key(dev,ir->keycode,ir->keypressed); + input_event(dev, EV_KEY, ir->keycode, ir->keypressed); input_sync(dev); } @@ -106,8 +106,10 @@ ir->ir_raw = ir_raw; ir->keycode = keycode; ir->keypressed = 1; - ir_input_key_event(dev,ir); - } + } + else + ir->keypressed = 2; /* repeat */ + ir_input_key_event(dev, ir); #if 0 /* maybe do something like this ??? */ input_event(a, EV_IR, ir->ir_type, ir->ir_raw); diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig --- a/linux/drivers/media/dvb/ttpci/Kconfig Wed Mar 22 16:45:04 2006 +++ b/linux/drivers/media/dvb/ttpci/Kconfig Thu Mar 23 02:27:41 2006 @@ -85,6 +85,7 @@ select DVB_STV0297 select DVB_STV0299 select DVB_TDA1004X + select VIDEO_IR help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c --- a/linux/drivers/media/dvb/ttpci/budget-ci.c Wed Mar 22 16:45:04 2006 +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c Thu Mar 23 02:27:41 2006 @@ -5,6 +5,7 @@ * * msp430 IR support contributed by Jack Thomasson <jkt@xxxxxxxxxx> * partially based on the Siemens DVB driver by Ralph+Marcus Metzler + * modified to use ir-common by Darren Salt <linux@xxxxxxxxxxxxxxxxxxxxxxxxxxx> * * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@xxxxxxxxxxxxx> * @@ -37,6 +38,7 @@ #include <linux/interrupt.h> #include <linux/input.h> #include <linux/spinlock.h> +#include <media/ir-common.h> #include "dvb_ca_en50221.h" #include "stv0299.h" @@ -65,12 +67,36 @@ #define SLOTSTATUS_READY 8 #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) +/* We need some appropriate timeout due to the lack of key-up. This has to + * be longer than the RC's own repeat rate; we need to allow for occasional + * unreceived transmissions. + */ +#define IR_REPEAT_TIMEOUT 240 + +/* RC5 address wildcard */ +#define IR_ADDRESS_ANY 255 + +static int ir_debug = 0; +module_param(ir_debug, int, 0644); /* debug level [IR] */ +MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); + +static int ir_any_rc5_address = 0; +module_param(ir_any_rc5_address, int, 0644); +MODULE_PARM_DESC(ir_any_rc5_address, "allow any RC5 address [IR]"); + struct budget_ci_ir { struct input_dev *dev; struct tasklet_struct msp430_irq_tasklet; char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ char phys[32]; + struct ir_input_state state; + struct timer_list timeout; /* key-up */ + u8 address; + u8 keycode; + u8 keydown; + u8 last_edge; }; +#define IR_NO_DATA (u8)(0x80) struct budget_ci { struct budget budget; @@ -86,7 +112,7 @@ Hauppauge (from NOVA-CI-s box product) i've taken a "middle of the road" approach and note the differences */ -static u16 key_map[64] = { +static IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = { /* 0x0X */ KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, @@ -137,17 +163,10 @@ static void msp430_ir_debounce(unsigned long data) { - struct input_dev *dev = (struct input_dev *) data; - - if (dev->rep[0] == 0 || dev->rep[0] == ~0) { - input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); - return; - } - - dev->rep[0] = 0; - dev->timer.expires = jiffies + HZ * 350 / 1000; - add_timer(&dev->timer); - input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */ + struct budget_ci_ir *ir = (struct budget_ci_ir *) data; + ir->keycode = IR_NO_DATA; + ir->keydown = 0; + ir_input_nokey (ir->dev, &ir->state); } static void msp430_ir_interrupt(unsigned long data) @@ -158,31 +177,41 @@ ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; if (code & 0x40) { - code &= 0x3f; - - if (timer_pending(&dev->timer)) { - if (code == dev->repeat_key) { - ++dev->rep[0]; - return; - } - del_timer(&dev->timer); - input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); + budget_ci->ir.keycode = code & 0x3F; + return; + } + else if (ir_any_rc5_address || + (budget_ci->ir.address == IR_ADDRESS_ANY) || + (budget_ci->ir.address == (code & 0x1F))) { + if (timer_pending(&budget_ci->ir.timeout) && + ((code & 0x20) != budget_ci->ir.last_edge)) { + budget_ci->ir.keydown = 0; + del_timer(&budget_ci->ir.timeout); + ir_input_nokey(dev, &budget_ci->ir.state); } - if (!key_map[code]) { - printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code); - return; - } - - /* initialize debounce and repeat */ - dev->repeat_key = code; - /* Zenith remote _always_ sends 2 sequences */ - dev->rep[0] = ~0; - /* 350 milliseconds */ - dev->timer.expires = jiffies + HZ * 350 / 1000; - /* MAKE */ - input_event(dev, EV_KEY, key_map[code], !0); - add_timer(&dev->timer); + budget_ci->ir.last_edge = code & 0x20; + + code = budget_ci->ir.keycode; + budget_ci->ir.keycode = IR_NO_DATA; + + /* Zenith remote always sends 2 sequences: ignore the second. + * Also, if code == IR_NO_DATA, we've missed the first byte; + * if this happens, don't report a keypress. + */ + budget_ci->ir.keydown = (budget_ci->ir.keydown << 1) | 1; + if ((budget_ci->ir.keydown != 3) && (code != IR_NO_DATA)) + ir_input_keydown(dev, &budget_ci->ir.state, code, code); + + /* (re)start a key-up timeout */ + mod_timer(&budget_ci->ir.timeout, + jiffies + HZ * IR_REPEAT_TIMEOUT / 1000); + } + else { + if (ir_debug) + printk (KERN_DEBUG "budget-ci: received key %02X address %02X\n", + budget_ci->ir.keycode & 0x3F, code & 0x1F); + budget_ci->ir.keycode = IR_NO_DATA; } } @@ -190,7 +219,7 @@ { struct saa7146_dev *saa = budget_ci->budget.dev; struct input_dev *input_dev; - int i; + IR_KEYTAB_TYPE *keys; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) int error; #endif @@ -226,10 +255,27 @@ # endif #endif - set_bit(EV_KEY, input_dev->evbit); - for (i = 0; i < ARRAY_SIZE(key_map); i++) - if (key_map[i]) - set_bit(key_map[i], input_dev->keybit); + /* Select keymap */ + switch (budget_ci->budget.dev->pci->subsystem_device) { + case 0x100c: + case 0x100f: + case 0x1010: + case 0x1011: + case 0x1012: + case 0x1017: + budget_ci->ir.address = 0x1F; + keys = ir_codes_hauppauge_new; /* more keys defined than are physically present */ + break; + + default: /* unknown or insufficient information - FIXME */ + budget_ci->ir.address = IR_ADDRESS_ANY; + keys = ir_codes_budget_ci_old; + break; + } + ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, keys); + + input_dev->rep[REP_DELAY] = 1; + input_dev->rep[REP_PERIOD] = 1; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) error = input_register_device(input_dev); @@ -243,7 +289,13 @@ input_register_device(input_dev); #endif - input_dev->timer.function = msp430_ir_debounce; + /* initialise our key-up timeout handler */ + init_timer(&budget_ci->ir.timeout); + budget_ci->ir.timeout.function = msp430_ir_debounce; + budget_ci->ir.timeout.data = (unsigned long) &budget_ci->ir; + + budget_ci->ir.keycode = IR_NO_DATA; + budget_ci->ir.last_edge = 255; /* can't happen */ saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06); saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); @@ -261,8 +313,8 @@ saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); if (dev) { - if (del_timer(&dev->timer)) - input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); + if (del_timer(&budget_ci->ir.timeout)) + ir_input_nokey(dev, &budget_ci->ir.state); input_unregister_device(dev); } } -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | <URL:http://www.youmustbejoking.demon.co.uk/progs.packages.html> If you have a video recorder, there'll be three good programmes on at once. _______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb