USB: Add functionality to poll the USB keyboard via control EP
This allows the keyboard to avoid requests via Interrupt Endpoint altogether and
run all requests via Control Endpoint. This uses the Get_Report request.
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Remy Bohmer <linux@bohmer.net>
Rebased on current code.
Signed-off-by: Remy Bohmer <linux@bohmer.net>
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 69939f0..ef440e4 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -98,6 +98,26 @@
'|', '~', ':', '"', '~', '<', '>', '?'
};
+static int usb_kbd_irq_worker(struct usb_device *dev);
+
+/******************************************************************
+ * Interrupt polling
+ ******************************************************************/
+static inline void usb_kbd_poll_for_event(struct usb_device *dev)
+{
+#if defined(CONFIG_SYS_USB_EVENT_POLL)
+ usb_event_poll();
+ usb_kbd_irq_worker(dev);
+#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
+ struct usb_interface *iface;
+ iface = &dev->config.if_desc[0];
+ usb_get_report(dev, iface->desc.bInterfaceNumber,
+ 1, 1, new, sizeof(new));
+ if (memcmp(old, new, sizeof(new)))
+ usb_kbd_irq_worker(dev);
+#endif
+}
+
/******************************************************************
* Queue handling
******************************************************************/
@@ -121,9 +141,14 @@
/* test if a character is in the queue */
static int usb_kbd_testc(void)
{
-#ifdef CONFIG_SYS_USB_EVENT_POLL
- usb_event_poll();
-#endif
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+
+ dev = stdio_get_by_name("usbkbd");
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+
+ usb_kbd_poll_for_event(usb_kbd_dev);
+
if (usb_in_pointer == usb_out_pointer)
return 0; /* no data */
else
@@ -133,11 +158,16 @@
static int usb_kbd_getc(void)
{
char c;
- while (usb_in_pointer == usb_out_pointer) {
-#ifdef CONFIG_SYS_USB_EVENT_POLL
- usb_event_poll();
-#endif
- }
+
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+
+ dev = stdio_get_by_name("usbkbd");
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+
+ while (usb_in_pointer == usb_out_pointer)
+ usb_kbd_poll_for_event(usb_kbd_dev);
+
if ((usb_out_pointer+1) == USB_KBD_BUFFER_LEN)
usb_out_pointer = 0;
else
@@ -323,15 +353,10 @@
}
/* Interrupt service routine */
-static int usb_kbd_irq(struct usb_device *dev)
+static int usb_kbd_irq_worker(struct usb_device *dev)
{
int i, res;
- if ((dev->irq_status != 0) || (dev->irq_act_len != 8)) {
- USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",
- dev->irq_status, dev->irq_act_len);
- return 1;
- }
res = 0;
switch (new[0]) {
@@ -362,6 +387,17 @@
return 1; /* install IRQ Handler again */
}
+static int usb_kbd_irq(struct usb_device *dev)
+{
+ if ((dev->irq_status != 0) || (dev->irq_act_len != 8)) {
+ USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",
+ dev->irq_status, dev->irq_act_len);
+ return 1;
+ }
+
+ return usb_kbd_irq_worker(dev);
+}
+
/* probes the USB device dev for keyboard type */
static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
{