[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:
Родитель
917167e9a3
Коммит
d653c0af49
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче