diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-08-05 09:03:17 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-12 07:36:47 -0400 |
commit | 622ecb300345d308c8b4a983ac112b1985d7d156 (patch) | |
tree | 2dd9156f8a5bb27826a939034d1ffa7cac671211 /drivers/media | |
parent | d56dc61265d2527a63ab5b0f03199a43cd89ca36 (diff) |
V4L/DVB (8625): saa7134: Add NEC prococol IR decoding capability
This patch adds the capability of decoding NEC protocol, received via GPIO18 line.
This GPIO port can trigger saa7134 IRQ.
A future improvement would be to make it a little more generic to work also
with GPIO16 line.
A pure IRQ code didn't work, since some delays were introduced on the tests we
did.
A possible approach would be to use polling at a rate of 2.5 ms or less. If a
new code were taken, a code similar to nec_task() could be used. However, this
would add an extra overhead to kernel, and will consume more power.
Due to that, we took an hybrid approach: an IRQ upper half to trigger when a
new key is received and a bottom half to convert pulse-distance into a keycode.
The bottom half is polling based, to improve performance. During the bottom
half proccess, GPIO18 IRQ line is disabled, preventing IRQ reentrancy and
improving performance a little bit.
Thanks to Sistema Fenix (http://www.sistemafenix.com.br/) for sponsoring this
development.
Signed-off-by: Gilberto <gilberto@sistemafenix.com.br>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/saa7134/saa7134-input.c | 140 |
1 files changed, 134 insertions, 6 deletions
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index ad08d13dffdd..ac6beb2df83d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -62,8 +62,11 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of " | |||
62 | #define i2cdprintk(fmt, arg...) if (ir_debug) \ | 62 | #define i2cdprintk(fmt, arg...) if (ir_debug) \ |
63 | printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) | 63 | printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) |
64 | 64 | ||
65 | /** rc5 functions */ | 65 | /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */ |
66 | static int saa7134_rc5_irq(struct saa7134_dev *dev); | 66 | static int saa7134_rc5_irq(struct saa7134_dev *dev); |
67 | static int saa7134_nec_irq(struct saa7134_dev *dev); | ||
68 | static void nec_task(unsigned long data); | ||
69 | static void saa7134_nec_timer(unsigned long data); | ||
67 | 70 | ||
68 | /* -------------------- GPIO generic keycode builder -------------------- */ | 71 | /* -------------------- GPIO generic keycode builder -------------------- */ |
69 | 72 | ||
@@ -280,7 +283,9 @@ void saa7134_input_irq(struct saa7134_dev *dev) | |||
280 | { | 283 | { |
281 | struct card_ir *ir = dev->remote; | 284 | struct card_ir *ir = dev->remote; |
282 | 285 | ||
283 | if (!ir->polling && !ir->rc5_gpio) { | 286 | if (ir->nec_gpio) { |
287 | saa7134_nec_irq(dev); | ||
288 | } else if (!ir->polling && !ir->rc5_gpio) { | ||
284 | build_key(dev); | 289 | build_key(dev); |
285 | } else if (ir->rc5_gpio) { | 290 | } else if (ir->rc5_gpio) { |
286 | saa7134_rc5_irq(dev); | 291 | saa7134_rc5_irq(dev); |
@@ -316,6 +321,10 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir) | |||
316 | ir->addr = 0x17; | 321 | ir->addr = 0x17; |
317 | ir->rc5_key_timeout = ir_rc5_key_timeout; | 322 | ir->rc5_key_timeout = ir_rc5_key_timeout; |
318 | ir->rc5_remote_gap = ir_rc5_remote_gap; | 323 | ir->rc5_remote_gap = ir_rc5_remote_gap; |
324 | } else if (ir->nec_gpio) { | ||
325 | setup_timer(&ir->timer_keyup, saa7134_nec_timer, | ||
326 | (unsigned long)dev); | ||
327 | tasklet_init(&ir->tlet, nec_task, (unsigned long)dev); | ||
319 | } | 328 | } |
320 | } | 329 | } |
321 | 330 | ||
@@ -335,6 +344,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
335 | u32 mask_keyup = 0; | 344 | u32 mask_keyup = 0; |
336 | int polling = 0; | 345 | int polling = 0; |
337 | int rc5_gpio = 0; | 346 | int rc5_gpio = 0; |
347 | int nec_gpio = 0; | ||
338 | int ir_type = IR_TYPE_OTHER; | 348 | int ir_type = IR_TYPE_OTHER; |
339 | int err; | 349 | int err; |
340 | 350 | ||
@@ -533,6 +543,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
533 | ir->mask_keyup = mask_keyup; | 543 | ir->mask_keyup = mask_keyup; |
534 | ir->polling = polling; | 544 | ir->polling = polling; |
535 | ir->rc5_gpio = rc5_gpio; | 545 | ir->rc5_gpio = rc5_gpio; |
546 | ir->nec_gpio = nec_gpio; | ||
536 | 547 | ||
537 | /* init input device */ | 548 | /* init input device */ |
538 | snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", | 549 | snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", |
@@ -675,8 +686,125 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev) | |||
675 | return 1; | 686 | return 1; |
676 | } | 687 | } |
677 | 688 | ||
678 | /* ---------------------------------------------------------------------- | 689 | |
679 | * Local variables: | 690 | /* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms |
680 | * c-basic-offset: 8 | 691 | The first pulse (start) has 9 + 4.5 ms |
681 | * End: | ||
682 | */ | 692 | */ |
693 | |||
694 | static void saa7134_nec_timer(unsigned long data) | ||
695 | { | ||
696 | struct saa7134_dev *dev = (struct saa7134_dev *) data; | ||
697 | struct card_ir *ir = dev->remote; | ||
698 | |||
699 | dprintk("Cancel key repeat\n"); | ||
700 | |||
701 | ir_input_nokey(ir->dev, &ir->ir); | ||
702 | } | ||
703 | |||
704 | static void nec_task(unsigned long data) | ||
705 | { | ||
706 | struct saa7134_dev *dev = (struct saa7134_dev *) data; | ||
707 | struct card_ir *ir; | ||
708 | struct timeval tv; | ||
709 | int count, pulse, oldpulse, gap; | ||
710 | u32 ircode = 0, not_code = 0; | ||
711 | int ngap = 0; | ||
712 | |||
713 | if (!data) { | ||
714 | printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n"); | ||
715 | /* GPIO will be kept disabled */ | ||
716 | return; | ||
717 | } | ||
718 | |||
719 | ir = dev->remote; | ||
720 | |||
721 | /* rising SAA7134_GPIO_GPRESCAN reads the status */ | ||
722 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
723 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
724 | |||
725 | oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown; | ||
726 | pulse = oldpulse; | ||
727 | |||
728 | do_gettimeofday(&tv); | ||
729 | ir->base_time = tv; | ||
730 | |||
731 | /* Decode NEC pulsecode. This code can take up to 76.5 ms to run. | ||
732 | Unfortunately, using IRQ to decode pulse didn't work, since it uses | ||
733 | a pulse train of 38KHz. This means one pulse on each 52 us | ||
734 | */ | ||
735 | do { | ||
736 | /* Wait until the end of pulse/space or 5 ms */ | ||
737 | for (count = 0; count < 500; count++) { | ||
738 | udelay(10); | ||
739 | /* rising SAA7134_GPIO_GPRESCAN reads the status */ | ||
740 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
741 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
742 | pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) | ||
743 | & ir->mask_keydown; | ||
744 | if (pulse != oldpulse) | ||
745 | break; | ||
746 | } | ||
747 | |||
748 | do_gettimeofday(&tv); | ||
749 | gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + | ||
750 | tv.tv_usec - ir->base_time.tv_usec; | ||
751 | |||
752 | if (!pulse) { | ||
753 | /* Bit 0 has 560 us, while bit 1 has 1120 us. | ||
754 | Do something only if bit == 1 | ||
755 | */ | ||
756 | if (ngap && (gap > 560 + 280)) { | ||
757 | unsigned int shift = ngap - 1; | ||
758 | |||
759 | /* Address first, then command */ | ||
760 | if (shift < 8) { | ||
761 | shift += 8; | ||
762 | ircode |= 1 << shift; | ||
763 | } else if (shift < 16) { | ||
764 | not_code |= 1 << shift; | ||
765 | } else if (shift < 24) { | ||
766 | shift -= 16; | ||
767 | ircode |= 1 << shift; | ||
768 | } else { | ||
769 | shift -= 24; | ||
770 | not_code |= 1 << shift; | ||
771 | } | ||
772 | } | ||
773 | ngap++; | ||
774 | } | ||
775 | |||
776 | |||
777 | ir->base_time = tv; | ||
778 | |||
779 | /* TIMEOUT - Long pulse */ | ||
780 | if (gap >= 5000) | ||
781 | break; | ||
782 | oldpulse = pulse; | ||
783 | } while (ngap < 32); | ||
784 | |||
785 | if (ngap == 32) { | ||
786 | /* FIXME: should check if not_code == ~ircode */ | ||
787 | ir->code = ir_extract_bits(ircode, ir->mask_keycode); | ||
788 | |||
789 | dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n", | ||
790 | ir->code, ircode, not_code); | ||
791 | |||
792 | ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code); | ||
793 | } else | ||
794 | dprintk("Repeat last key\n"); | ||
795 | |||
796 | /* Keep repeating the last key */ | ||
797 | mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150)); | ||
798 | |||
799 | saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); | ||
800 | } | ||
801 | |||
802 | static int saa7134_nec_irq(struct saa7134_dev *dev) | ||
803 | { | ||
804 | struct card_ir *ir = dev->remote; | ||
805 | |||
806 | saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); | ||
807 | tasklet_schedule(&ir->tlet); | ||
808 | |||
809 | return 1; | ||
810 | } | ||