aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2008-08-05 09:03:17 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-12 07:36:47 -0400
commit622ecb300345d308c8b4a983ac112b1985d7d156 (patch)
tree2dd9156f8a5bb27826a939034d1ffa7cac671211 /drivers/media
parentd56dc61265d2527a63ab5b0f03199a43cd89ca36 (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.c140
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 */
66static int saa7134_rc5_irq(struct saa7134_dev *dev); 66static int saa7134_rc5_irq(struct saa7134_dev *dev);
67static int saa7134_nec_irq(struct saa7134_dev *dev);
68static void nec_task(unsigned long data);
69static 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
694static 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
704static 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
802static 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}