[U-Boot] [PATCH 7/7] usb: kbd: Add (optional) support for using an interrupt queue for polling

Hans de Goede hdegoede at redhat.com
Sat Sep 20 17:18:28 CEST 2014


Hi,

On 09/20/2014 05:01 PM, Hans de Goede wrote:
> Waiting an interrupt packet to complete in usb_kbd_poll_for_event, causes
> a 40 ms latency for each call to usb_kbd_testc, which is undesirable.
> 
> Using control messages leads to lower (but still not 0) latency, but some
> devices do not work well with control messages (e.g. my kvm behaves funny
> with them).
> 
> This commit adds support for using the int_queue mechanism which at least
> the ehci-hcd driver supports. This allows polling with 0 latency, while
> using interrupt packets.
> 
> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> ---
>  common/usb_kbd.c | 37 ++++++++++++++++++++++++++++++++++---
>  1 file changed, 34 insertions(+), 3 deletions(-)
> 
> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
> index 85ee1c8..278937c 100644
> --- a/common/usb_kbd.c
> +++ b/common/usb_kbd.c
> @@ -102,6 +102,7 @@ struct usb_kbd_pdata {
>  	unsigned long	intpipe;
>  	int		intpktsize;
>  	int		intinterval;
> +	struct int_queue *intq;
>  
>  	uint32_t	repeat_delay;
>  
> @@ -324,6 +325,15 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev)
>  		       1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE);
>  	if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE))
>  		usb_kbd_irq_worker(dev);
> +#elif	defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)
> +	struct usb_kbd_pdata *data = dev->privptr;
> +	if (poll_int_queue(dev, data->intq)) {
> +		usb_kbd_irq_worker(dev);
> +		/* We've consumed all queued int packets, create new */
> +		destroy_int_queue(dev, data->intq);
> +		data->intq = create_int_queue(dev, data->intpipe, 1,
> +				      USB_KBD_BOOT_REPORT_SIZE, data->new);
> +	}
>  #endif
>  }
>  
> @@ -441,8 +451,14 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
>  	usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
>  
>  	debug("USB KBD: enable interrupt pipe...\n");
> +#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
> +	data->intq = create_int_queue(dev, data->intpipe, 1,
> +				      USB_KBD_BOOT_REPORT_SIZE, data->new);
> +	if (!data->intq) {
> +#else
>  	if (usb_submit_int_msg(dev, data->intpipe, data->new, data->intpktsize,
>  			       data->intinterval) < 0) {
> +#endif
>  		printf("Failed to get keyboard state from device %04x:%04x\n",
>  		       dev->descriptor.idVendor, dev->descriptor.idProduct);
>  		/* Abort, we don't want to use that non-functional keyboard. */
> @@ -515,13 +531,28 @@ int drv_usb_kbd_init(void)
>  /* Deregister the keyboard. */
>  int usb_kbd_deregister(int force)
>  {
> -#ifdef CONFIG_SYS_STDIO_DEREGISTER
> +#if !defined(CONFIG_SYS_STDIO_DEREGISTER)
> +	return 1;
> +#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)
> +	struct stdio_dev *dev;
> +	struct usb_device *usb_kbd_dev;
> +	struct usb_kbd_pdata *data;
> +
> +	dev = stdio_get_by_name(DEVNAME);
> +	if (dev) {
> +		if (stdio_deregister_dev(dev, force) != 0)
> +			return 1;
> +		usb_kbd_dev = (struct usb_device *)dev->priv;

Hmm I've just realized that this is a use after free for dev.
I've fixed this in my local tree. I'll wait for review of the
other patches in this set before sending a v2.

Note this is not really a use after free, since stdio_deregister_dev
does not free dev, but it reallu should free dev, since stdio_register_dev
does a clone of the passed in dev, so stdio_deregister_dev should free it,
so as to not leak memory. Once that memory leak gets fixed, this will be
a use after free.

Likewise usb_kbd.c should free usb_kbd_pdata and the data->new buffer on
deregister. I'll add a fix plugging the memleak in usb_kbd.c to v2 of this
set.

Regards,

Hans


More information about the U-Boot mailing list