]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
[media] lirc_igorplugusb: handle hw buffer overruns better
authorJarod Wilson <jarod@redhat.com>
Tue, 19 Oct 2010 17:25:29 +0000 (14:25 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 22 Oct 2010 22:05:37 +0000 (20:05 -0200)
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/staging/lirc/lirc_igorplugusb.c

index b9a4ffd9c7a4e5f6860335484a2ae8d6f414db70..380b8fee9bc20d67d3b54f61f9d7311b4770a622 100644 (file)
@@ -54,7 +54,7 @@
 
 
 /* module identification */
-#define DRIVER_VERSION         "0.1"
+#define DRIVER_VERSION         "0.2"
 #define DRIVER_AUTHOR          \
        "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
 #define DRIVER_DESC            "Igorplug USB remote driver for LIRC"
@@ -276,6 +276,25 @@ static void set_use_dec(void *data)
        dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
 }
 
+static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
+                          int i, int max)
+{
+       int code;
+
+       /* MODE2: pulse/space (PULSE_BIT) in 1us units */
+       while (i < max) {
+               /* 1 Igor-tick = 85.333333 us */
+               code = (unsigned int)ir->buf_in[i] * 85 +
+                       (unsigned int)ir->buf_in[i] / 3;
+               ir->last_time.tv_usec += code;
+               if (ir->in_space)
+                       code |= PULSE_BIT;
+               lirc_buffer_write(buf, (unsigned char *)&code);
+               /* 1 chunk = CODE_LENGTH bytes */
+               ir->in_space ^= 1;
+               ++i;
+       }
+}
 
 /**
  * Called in user context.
@@ -299,24 +318,16 @@ static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
                              ir->buf_in, ir->len_in,
                              /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
        if (ret > 0) {
-               int i = DEVICE_HEADERLEN;
                int code, timediff;
                struct timeval now;
 
-               if (ret <= 1)  /* ACK packet has 1 byte --> ignore */
+               /* ACK packet has 1 byte --> ignore */
+               if (ret < DEVICE_HEADERLEN)
                        return -ENODATA;
 
                dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
                        ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
 
-               if (ir->buf_in[2] != 0) {
-                       printk(DRIVER_NAME "[%d]: Device buffer overrun.\n",
-                               ir->devnum);
-                       /* start at earliest byte */
-                       i = DEVICE_HEADERLEN + ir->buf_in[2];
-                       /* where are we now? space, gap or pulse? */
-               }
-
                do_gettimeofday(&now);
                timediff = now.tv_sec - ir->last_time.tv_sec;
                if (timediff + 1 > PULSE_MASK / 1000000)
@@ -333,18 +344,20 @@ static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
                lirc_buffer_write(buf, (unsigned char *)&code);
                ir->in_space = 1;   /* next comes a pulse */
 
-               /* MODE2: pulse/space (PULSE_BIT) in 1us units */
-
-               while (i < ret) {
-                       /* 1 Igor-tick = 85.333333 us */
-                       code = (unsigned int)ir->buf_in[i] * 85
-                               + (unsigned int)ir->buf_in[i] / 3;
-                       if (ir->in_space)
-                               code |= PULSE_BIT;
-                       lirc_buffer_write(buf, (unsigned char *)&code);
-                       /* 1 chunk = CODE_LENGTH bytes */
-                       ir->in_space ^= 1;
-                       ++i;
+               if (ir->buf_in[2] == 0)
+                       send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
+               else {
+                       printk(KERN_WARNING DRIVER_NAME
+                              "[%d]: Device buffer overrun.\n", ir->devnum);
+                       /* HHHNNNNNNNNNNNOOOOOOOO H = header
+                             <---[2]--->         N = newer
+                          <---------ret--------> O = older */
+                       ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
+                       /* keep even-ness to not desync pulse/pause */
+                       send_fragment(ir, buf, DEVICE_HEADERLEN +
+                                     ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
+                       send_fragment(ir, buf, DEVICE_HEADERLEN,
+                                     DEVICE_HEADERLEN + ir->buf_in[2]);
                }
 
                ret = usb_control_msg(
@@ -444,7 +457,7 @@ mem_failure_switch:
 
        switch (mem_failure) {
        case 9:
-               usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+               usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
                        ir->buf_in, ir->dma_in);
        case 3:
                kfree(driver);
@@ -460,7 +473,7 @@ mem_failure_switch:
        ir->d = driver;
        ir->devnum = devnum;
        ir->usbdev = dev;
-       ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+       ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
        ir->in_space = 1; /* First mode2 event is a space. */
        do_gettimeofday(&ir->last_time);