Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d653c0af authored by Jarod Wilson's avatar Jarod Wilson Committed by Mauro Carvalho Chehab
Browse files

[media] lirc_igorplugusb: handle hw buffer overruns better

parent 917167e9
Loading
Loading
Loading
Loading
+38 −25
Original line number Diff line number Diff line
@@ -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(