]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/media/video/saa7134/saa7134-input.c
V4L/DVB: saa7134: don't wait too much to generate an IR event on raw_decode
[net-next-2.6.git] / drivers / media / video / saa7134 / saa7134-input.c
index 58a0cdc8414a36a654e8d2e067fd0821e89624ec..32859e549afa0a0da4314c1a5a5b5201e5e60079 100644 (file)
@@ -28,6 +28,8 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
+#define MODULE_NAME "saa7134"
+
 static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
@@ -66,6 +68,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
 /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
 static int saa7134_rc5_irq(struct saa7134_dev *dev);
 static int saa7134_nec_irq(struct saa7134_dev *dev);
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
 static void nec_task(unsigned long data);
 static void saa7134_nec_timer(unsigned long data);
 
@@ -401,10 +404,12 @@ void saa7134_input_irq(struct saa7134_dev *dev)
 
        if (ir->nec_gpio) {
                saa7134_nec_irq(dev);
-       } else if (!ir->polling && !ir->rc5_gpio) {
+       } else if (!ir->polling && !ir->rc5_gpio && !ir->raw_decode) {
                build_key(dev);
        } else if (ir->rc5_gpio) {
                saa7134_rc5_irq(dev);
+       } else if (ir->raw_decode) {
+               saa7134_raw_decode_irq(dev);
        }
 }
 
@@ -417,8 +422,22 @@ static void saa7134_input_timer(unsigned long data)
        mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
+void ir_raw_decode_timer_end(unsigned long data)
+{
+       struct saa7134_dev *dev = (struct saa7134_dev *)data;
+       struct card_ir *ir = dev->remote;
+
+       ir_raw_event_handle(dev->remote->dev);
+
+       ir->active = 0;
+}
+
 void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
 {
+       if (ir->running)
+               return;
+
+       ir->running = 1;
        if (ir->polling) {
                setup_timer(&ir->timer, saa7134_input_timer,
                            (unsigned long)dev);
@@ -441,13 +460,66 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
                setup_timer(&ir->timer_keyup, saa7134_nec_timer,
                            (unsigned long)dev);
                tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
+       } else if (ir->raw_decode) {
+               /* set timer_end for code completion */
+               init_timer(&ir->timer_end);
+               ir->timer_end.function = ir_raw_decode_timer_end;
+               ir->timer_end.data = (unsigned long)dev;
+               ir->active = 0;
        }
 }
 
 void saa7134_ir_stop(struct saa7134_dev *dev)
 {
+       struct card_ir *ir = dev->remote;
+
+       if (!ir->running)
+               return;
        if (dev->remote->polling)
                del_timer_sync(&dev->remote->timer);
+       else if (ir->rc5_gpio)
+               del_timer_sync(&ir->timer_end);
+       else if (ir->nec_gpio)
+               tasklet_kill(&ir->tlet);
+       else if (ir->raw_decode) {
+               del_timer_sync(&ir->timer_end);
+               ir->active = 0;
+       }
+
+       ir->running = 0;
+}
+
+int saa7134_ir_change_protocol(void *priv, u64 ir_type)
+{
+       struct saa7134_dev *dev = priv;
+       struct card_ir *ir = dev->remote;
+       u32 nec_gpio, rc5_gpio;
+
+       if (ir_type == IR_TYPE_RC5) {
+               dprintk("Changing protocol to RC5\n");
+               nec_gpio = 0;
+               rc5_gpio = 1;
+       } else if (ir_type == IR_TYPE_NEC) {
+               dprintk("Changing protocol to NEC\n");
+               nec_gpio = 1;
+               rc5_gpio = 0;
+       } else {
+               dprintk("IR protocol type %ud is not supported\n",
+                       (unsigned)ir_type);
+               return -EINVAL;
+       }
+
+       if (ir->running) {
+               saa7134_ir_stop(dev);
+               ir->nec_gpio = nec_gpio;
+               ir->rc5_gpio = rc5_gpio;
+               saa7134_ir_start(dev, ir);
+       } else {
+               ir->nec_gpio = nec_gpio;
+               ir->rc5_gpio = rc5_gpio;
+       }
+
+       return 0;
 }
 
 int saa7134_input_init1(struct saa7134_dev *dev)
@@ -461,6 +533,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        int polling      = 0;
        int rc5_gpio     = 0;
        int nec_gpio     = 0;
+       int raw_decode   = 0;
        u64 ir_type = IR_TYPE_OTHER;
        int err;
 
@@ -473,6 +546,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        switch (dev->board) {
        case SAA7134_BOARD_FLYVIDEO2000:
        case SAA7134_BOARD_FLYVIDEO3000:
+       case SAA7134_BOARD_HAWELL_HW_404M7:
        case SAA7134_BOARD_FLYTVPLATINUM_FM:
        case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
        case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
@@ -522,10 +596,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
                break;
        case SAA7134_BOARD_AVERMEDIA_M135A:
-               ir_codes     = &ir_codes_avermedia_m135a_table;
+               ir_codes     = &ir_codes_avermedia_m135a_rm_jx_table;
                mask_keydown = 0x0040000;
-               mask_keycode = 0x00013f;
-               nec_gpio     = 1;
+               mask_keycode = 0xffff;
+               raw_decode   = 1;
                break;
        case SAA7134_BOARD_AVERMEDIA_777:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -695,6 +769,9 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        }
 
        ir->dev = input_dev;
+       dev->remote = ir;
+
+       ir->running = 0;
 
        /* init hardware-specific stuff */
        ir->mask_keycode = mask_keycode;
@@ -703,6 +780,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        ir->polling      = polling;
        ir->rc5_gpio     = rc5_gpio;
        ir->nec_gpio     = nec_gpio;
+       ir->raw_decode   = raw_decode;
 
        /* init input device */
        snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -710,6 +788,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
                 pci_name(dev->pci));
 
+       if (ir_codes->ir_type != IR_TYPE_OTHER && !raw_decode) {
+               ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+               ir->props.priv = dev;
+               ir->props.change_protocol = saa7134_ir_change_protocol;
+
+               /* Set IR protocol */
+               saa7134_ir_change_protocol(ir->props.priv, ir_codes->ir_type);
+       }
        err = ir_input_init(input_dev, &ir->ir, ir_type);
        if (err < 0)
                goto err_out_free;
@@ -727,12 +813,16 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        }
        input_dev->dev.parent = &dev->pci->dev;
 
-       dev->remote = ir;
-       saa7134_ir_start(dev, ir);
-
-       err = ir_input_register(ir->dev, ir_codes, NULL);
+       err = ir_input_register(ir->dev, ir_codes, &ir->props, MODULE_NAME);
        if (err)
                goto err_out_stop;
+       if (ir_codes->ir_type != IR_TYPE_OTHER) {
+               err = ir_raw_event_register(ir->dev);
+               if (err)
+                       goto err_out_stop;
+       }
+
+       saa7134_ir_start(dev, ir);
 
        /* the remote isn't as bouncy as a keyboard */
        ir->dev->rep[REP_DELAY] = repeat_delay;
@@ -754,6 +844,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
                return;
 
        saa7134_ir_stop(dev);
+       ir_raw_event_unregister(dev->remote->dev);
        ir_input_unregister(dev->remote->dev);
        kfree(dev->remote);
        dev->remote = NULL;
@@ -837,6 +928,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
                dev->init_data.name = "BeholdTV";
                dev->init_data.get_key = get_key_beholdm6xx;
                dev->init_data.ir_codes = &ir_codes_behold_table;
+               dev->init_data.type = IR_TYPE_NEC;
                info.addr = 0x2d;
                break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
@@ -859,6 +951,33 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
        i2c_new_device(&dev->i2c_adap, &info);
 }
 
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
+{
+       struct card_ir  *ir = dev->remote;
+       unsigned long   timeout;
+       int count, pulse, oldpulse;
+
+       /* Generate initial event */
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+       ir_raw_event_store(dev->remote->dev, pulse? IR_PULSE : IR_SPACE);
+
+
+       /*
+        * Wait 15 ms from the start of the first IR event before processing
+        * the event. This time is enough for NEC protocol. May need adjustments
+        * to work with other protocols.
+        */
+       if (!ir->active) {
+               timeout = jiffies + jiffies_to_msecs(15);
+               mod_timer(&ir->timer_end, timeout);
+               ir->active = 1;
+       }
+
+       return 1;
+}
+
 static int saa7134_rc5_irq(struct saa7134_dev *dev)
 {
        struct card_ir *ir = dev->remote;
@@ -901,7 +1020,6 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev)
        return 1;
 }
 
-
 /* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
    The first pulse (start) has 9 + 4.5 ms
  */