Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754320AbZF3SEU (ORCPT ); Tue, 30 Jun 2009 14:04:20 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752596AbZF3SEI (ORCPT ); Tue, 30 Jun 2009 14:04:08 -0400 Received: from khc.piap.pl ([195.187.100.11]:49817 "EHLO khc.piap.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752517AbZF3SEG (ORCPT ); Tue, 30 Jun 2009 14:04:06 -0400 To: linux-input@vger.kernel.org Cc: lkml , linux-media@vger.kernel.org Subject: Re: RFC: Remote control sensors and Linux input layer References: From: Krzysztof Halasa Date: Tue, 30 Jun 2009 20:04:05 +0200 In-Reply-To: (Krzysztof Halasa's message of "Tue\, 30 Jun 2009 16\:37\:08 +0200") Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 11263 Lines: 363 > I'm attaching a test patch for "1" and "3". It's incomplete, breaks > bttv, but it currently works with my Philips RC and Super 007 DVB-T > board. Well, the patch (against 2.6.30): --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -260,47 +260,12 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high) } EXPORT_SYMBOL_GPL(ir_decode_biphase); -/* RC5 decoding stuff, moved from bttv-input.c to share it with - * saa7134 */ - -/* decode raw bit pattern to RC5 code */ -static u32 ir_rc5_decode(unsigned int code) -{ - unsigned int org_code = code; - unsigned int pair; - unsigned int rc5 = 0; - int i; - - for (i = 0; i < 14; ++i) { - pair = code & 0x3; - code >>= 2; - - rc5 <<= 1; - switch (pair) { - case 0: - case 2: - break; - case 1: - rc5 |= 1; - break; - case 3: - dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code); - return 0; - } - } - dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " - "instr=%x\n", rc5, org_code, RC5_START(rc5), - RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); - return rc5; -} - void ir_rc5_timer_end(unsigned long data) { struct card_ir *ir = (struct card_ir *)data; struct timeval tv; unsigned long current_jiffies, timeout; u32 gap; - u32 rc5 = 0; /* get time */ current_jiffies = jiffies; @@ -317,46 +282,46 @@ void ir_rc5_timer_end(unsigned long data) /* signal we're ready to start a new code */ ir->active = 0; - /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ - if (gap < 28000) { - dprintk(1, "ir-common: spurious timer_end\n"); + if (ir->last_bit == 1 && (ir->code & 2)) + ir->last_bit--; /* bit1: 1 -> bit0: 0 doesn't generate an IRQ */ + + if (ir->last_bit) { + /* ignore spurious codes (caused by light/other remotes) */ + dprintk(1, "ir-common: short code: %X\n", ir->code); return; } - if (ir->last_bit < 20) { - /* ignore spurious codes (caused by light/other remotes) */ - dprintk(1, "ir-common: short code: %x\n", ir->code); - } else { - ir->code = (ir->code << ir->shift_by) | 1; - rc5 = ir_rc5_decode(ir->code); - - /* two start bits? */ - if (RC5_START(rc5) != ir->start) { - dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5)); - - /* right address? */ - } else if (RC5_ADDR(rc5) == ir->addr) { - u32 toggle = RC5_TOGGLE(rc5); - u32 instr = RC5_INSTR(rc5); - - /* Good code, decide if repeat/repress */ - if (toggle != RC5_TOGGLE(ir->last_rc5) || - instr != RC5_INSTR(ir->last_rc5)) { - dprintk(1, "ir-common: instruction %x, toggle %x\n", instr, - toggle); - ir_input_nokey(ir->dev, &ir->ir); - ir_input_keydown(ir->dev, &ir->ir, instr, - instr); - } + //ir->code = (ir->code << ir->shift_by) | 1; /* FIXME check bttv */ - /* Set/reset key-up timer */ - timeout = current_jiffies + - msecs_to_jiffies(ir->rc5_key_timeout); - mod_timer(&ir->timer_keyup, timeout); + if (!RC5_ADDR(ir->code)) { + dprintk(1, "ir-common: bad RC5 code 0x%x\n", ir->code); + return; + } - /* Save code for repeat test */ - ir->last_rc5 = rc5; + dprintk(1, "ir-common: rc5=0x%X, toggle=0x%X, address=0x%X, instr=%x\n", + ir->code, RC5_TOGGLE(ir->code), RC5_ADDR(ir->code), + RC5_INSTR(ir->code)); + + if (RC5_ADDR(ir->code) == ir->addr) { + u32 toggle = RC5_TOGGLE(ir->code); + u32 instr = RC5_INSTR(ir->code); + + /* Good code, decide if repeat/repress */ + if (toggle != RC5_TOGGLE(ir->last_rc5) || + instr != RC5_INSTR(ir->last_rc5)) { + dprintk(1, "ir-common: instruction %x, toggle %x\n", + instr, toggle); + ir_input_nokey(ir->dev, &ir->ir); + ir_input_keydown(ir->dev, &ir->ir, instr, instr); } + + /* Set/reset key-up timer */ + timeout = current_jiffies + + msecs_to_jiffies(ir->rc5_key_timeout); + mod_timer(&ir->timer_keyup, timeout); + + /* Save code for repeat test */ + ir->last_rc5 = ir->code; } } EXPORT_SYMBOL_GPL(ir_rc5_timer_end); --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1487,6 +1487,53 @@ IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_pv951); +/* + Philips RC2592 with MODE pressed, used by Philips TV sets + RC5 group = 8, commands are 7-bit wide (1 start bit) +*/ +IR_KEYTAB_TYPE ir_codes_rc2592_sat[IR_KEYTAB_SIZE] = { + [ 0x00 ] = KEY_0, + [ 0x01 ] = KEY_1, + [ 0x02 ] = KEY_2, + [ 0x03 ] = KEY_3, + [ 0x04 ] = KEY_4, + [ 0x05 ] = KEY_5, + [ 0x06 ] = KEY_6, + [ 0x07 ] = KEY_7, + [ 0x08 ] = KEY_8, + [ 0x09 ] = KEY_9, + + [ 0x0C ] = KEY_SUSPEND, + + [ 0x6B ] = KEY_RED, + [ 0x6C ] = KEY_GREEN, + [ 0x6D ] = KEY_YELLOW, + [ 0x6E ] = KEY_BLUE, + [ 0x6F ] = KEY_OPTION, /* white */ + + [ 0x2A ] = KEY_TIME, + [ 0x2C ] = KEY_QUESTION, + [ 0x2B ] = KEY_ZOOM, + [ 0x3C ] = KEY_TEXT, + + [ 0x52 ] = KEY_MENU, + [ 0x57 ] = KEY_OK, + [ 0x50 ] = KEY_UP, + [ 0x51 ] = KEY_DOWN, + [ 0x55 ] = KEY_LEFT, + [ 0x56 ] = KEY_RIGHT, + + [ 0x20 ] = KEY_CHANNELUP, + [ 0x21 ] = KEY_CHANNELDOWN, + + [ 0x0F ] = KEY_INFO, /* i+ */ + [ 0x22 ] = KEY_PREVIOUS, /* P

has_remote == SAA7134_REMOTE_GPIO && dev->remote) { if (dev->remote->mask_keydown & 0x10000) irq2_mask |= SAA7134_IRQ2_INTE_GPIO16; - else if (dev->remote->mask_keydown & 0x40000) + if (dev->remote->mask_keydown & 0x40000) irq2_mask |= SAA7134_IRQ2_INTE_GPIO18; - else if (dev->remote->mask_keyup & 0x40000) + if (dev->remote->mask_keyup & 0x40000) irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A; } --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -374,7 +374,6 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir) ir->timer_keyup.data = (unsigned long)ir; ir->shift_by = 2; ir->start = 0x2; - ir->addr = 0x17; ir->rc5_key_timeout = ir_rc5_key_timeout; ir->rc5_remote_gap = ir_rc5_remote_gap; } else if (ir->nec_gpio) { @@ -402,6 +401,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) int rc5_gpio = 0; int nec_gpio = 0; int ir_type = IR_TYPE_OTHER; + int addr = 0; int err; if (dev->has_remote != SAA7134_REMOTE_GPIO) @@ -483,6 +483,12 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPMODE1, 0x1); saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); break; + case SAA7134_BOARD_AVERMEDIA_SUPER_007: + ir_codes = ir_codes_rc2592_sat; + addr = 8; + mask_keyup = 0x40000; + rc5_gpio = 1; + break; case SAA7134_BOARD_KWORLD_TERMINATOR: ir_codes = ir_codes_pixelview; mask_keycode = 0x00001f; @@ -562,6 +568,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_ASUSTeK_P7131_ANALOG: ir_codes = ir_codes_asus_pc39; + addr = 0x17; mask_keydown = 0x0040000; rc5_gpio = 1; break; @@ -623,6 +630,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir->mask_keyup = mask_keyup; ir->polling = polling; ir->rc5_gpio = rc5_gpio; + ir->addr = addr; ir->nec_gpio = nec_gpio; /* init input device */ @@ -748,26 +756,60 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev) tv.tv_usec - ir->base_time.tv_usec; } + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); + printk(KERN_DEBUG "rc5 irq: %lu %lu %u gap %u\n", tv.tv_sec, tv.tv_usec, + (saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) / 0x40000) & 1, gap); + /* active code => add bit */ if (ir->active) { /* only if in the code (otherwise spurious IRQ or timer late) */ - if (ir->last_bit < 28) { - ir->last_bit = (gap - ir_rc5_remote_gap / 2) / - ir_rc5_remote_gap; - ir->code |= 1 << ir->last_bit; + gap = (gap + ir_rc5_remote_gap / 2) / ir_rc5_remote_gap; + if (ir->last_bit && ir->code) { + u32 last = ir->code >> ir->last_bit; + + printk(KERN_DEBUG "RC5 gap %u last %X last_bit %u code " + "0x%X\n", gap, last, ir->last_bit, ir->code); + + if ((last & 1) == 1) { + if (gap == 2) /* 1 -> 1 */ + ir->code |= 1 << --ir->last_bit; + else if (gap == 3) /* 1 -> 00 */ + ir->last_bit -= 2; + else if (gap == 4) /* 1 -> 01 */ + ir->code |= 1 << (ir->last_bit -= 2); + else + goto invalid; + } else if ((last & 3) == 0) { + if (gap == 2) /* 00 -> 0 */ + ir->last_bit--; + else if (gap == 3) /* 00 -> 1 */ + ir->code |= 1 << --ir->last_bit; + else + goto invalid; + } else + goto invalid; + + printk(KERN_DEBUG "RC5: last_bit %u, code 0x%X\n", + ir->last_bit, ir->code); } /* starting new code */ } else { ir->active = 1; - ir->code = 0; - ir->base_time = tv; - ir->last_bit = 0; + ir->code = 0x2000; /* start bit is always '1' */ + ir->last_bit = 13; timeout = current_jiffies + (500 + 30 * HZ) / 1000; mod_timer(&ir->timer_end, timeout); } + ir->base_time = tv; + return 1; + +invalid: + ir->code = 0; /* mark as invalid */ return 1; } --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -37,10 +37,10 @@ #define IR_KEYCODE(tab,code) (((unsigned)code < IR_KEYTAB_SIZE) \ ? tab[code] : KEY_RESERVED) -#define RC5_START(x) (((x)>>12)&3) +#define RC5_START(x) (((x) >> 13) & 1) #define RC5_TOGGLE(x) (((x)>>11)&1) #define RC5_ADDR(x) (((x)>>6)&31) -#define RC5_INSTR(x) ((x)&63) +#define RC5_INSTR(x) ((((~(x)) >> 6) & 0x40) | ((x) & 0x3F)) struct ir_input_state { /* configuration */ @@ -136,6 +136,7 @@ extern IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_rc2592_sat[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE]; -- Krzysztof Halasa -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/