[media] lirc_igorplugusb: handle hw buffer overruns better

Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Jarod Wilson 2010-10-19 14:25:29 -03:00 коммит произвёл Mauro Carvalho Chehab
Родитель 917167e9a3
Коммит d653c0af49
1 изменённых файлов: 38 добавлений и 25 удалений

Просмотреть файл

@ -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);