From 48c8073ec957b4b472835f4c7b6447f7e518e2f5 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 25 Sep 2011 20:00:37 +0100 Subject: 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 Cc: Remy Bohmer Rebased on current code. Signed-off-by: Remy Bohmer --- common/usb_kbd.c | 64 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 14 deletions(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 69939f06ac8..ef440e4723e 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -98,6 +98,26 @@ static unsigned char usb_kbd_numkey_shifted[] = { '|', '~', ':', '"', '~', '<', '>', '?' }; +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 @@ static void usb_kbd_put_queue(char data) /* 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_testc(void) 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 @@ static int usb_kbd_translate(unsigned char scancode, unsigned char modifier, } /* 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 @@ static int usb_kbd_irq(struct usb_device *dev) 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) { -- cgit v1.3.1 From 9a8c72a6c42471d503d573988510e8ec71edddaa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 10 Oct 2011 16:34:26 +0100 Subject: USB: Rework usb_kbd.c * Support dynamic allocation of devices * Passing data via usb device privptr * Reorder functions to avoid forward declarations * Introduce generic polling mechanism to fix musb and ehci-hcd breakage due to using "extern new;" to access keyboard driver data! Signed-off-by: Marek Vasut Acked-by: Mike Frysinger Cc: Remy Bohmer Cc: Wolfgang Denk --- common/usb_kbd.c | 587 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 325 insertions(+), 262 deletions(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index ef440e4723e..2d788314c8d 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -25,12 +25,18 @@ * */ #include +#include #include #include #include -#undef USB_KBD_DEBUG +#ifdef USB_KBD_DEBUG +#define USB_KBD_PRINTF(fmt, args...) printf(fmt, ##args) +#else +#define USB_KBD_PRINTF(fmt, args...) +#endif + /* * If overwrite_console returns 1, the stdin, stderr and stdout * are switched to the serial port, else the settings in the @@ -45,352 +51,257 @@ int overwrite_console(void) } #endif -#ifdef USB_KBD_DEBUG -#define USB_KBD_PRINTF(fmt, args...) printf(fmt, ##args) -#else -#define USB_KBD_PRINTF(fmt, args...) -#endif - - -#define REPEAT_RATE (40/4) /* 40msec -> 25cps */ -#define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */ +/* Keyboard sampling rate */ +#define REPEAT_RATE (40 / 4) /* 40msec -> 25cps */ +#define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */ #define NUM_LOCK 0x53 #define CAPS_LOCK 0x39 #define SCROLL_LOCK 0x47 - /* Modifier bits */ -#define LEFT_CNTR 0 -#define LEFT_SHIFT 1 -#define LEFT_ALT 2 -#define LEFT_GUI 3 -#define RIGHT_CNTR 4 -#define RIGHT_SHIFT 5 -#define RIGHT_ALT 6 -#define RIGHT_GUI 7 - -#define USB_KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */ - -static char usb_kbd_buffer[USB_KBD_BUFFER_LEN]; -static int usb_in_pointer; -static int usb_out_pointer; - -unsigned char new[8]; -unsigned char old[8]; -int repeat_delay; +#define LEFT_CNTR (1 << 0) +#define LEFT_SHIFT (1 << 1) +#define LEFT_ALT (1 << 2) +#define LEFT_GUI (1 << 3) +#define RIGHT_CNTR (1 << 4) +#define RIGHT_SHIFT (1 << 5) +#define RIGHT_ALT (1 << 6) +#define RIGHT_GUI (1 << 7) + +/* Size of the keyboard buffer */ +#define USB_KBD_BUFFER_LEN 0x20 + +/* Device name */ #define DEVNAME "usbkbd" -static unsigned char num_lock; -static unsigned char caps_lock; -static unsigned char scroll_lock; -static unsigned char ctrl; - -static unsigned char leds __attribute__((aligned(0x4))); -static unsigned char usb_kbd_numkey[] = { +/* Keyboard maps */ +static const unsigned char usb_kbd_numkey[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']', '\\', '#', ';', '\'', '`', ',', '.', '/' }; -static unsigned char usb_kbd_numkey_shifted[] = { +static const unsigned char usb_kbd_numkey_shifted[] = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?' }; -static int usb_kbd_irq_worker(struct usb_device *dev); +/* + * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this + * order. See usb_kbd_setled() function! + */ +#define USB_KBD_NUMLOCK (1 << 0) +#define USB_KBD_CAPSLOCK (1 << 1) +#define USB_KBD_SCROLLLOCK (1 << 2) +#define USB_KBD_CTRL (1 << 3) -/****************************************************************** - * 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 -} +#define USB_KBD_LEDMASK \ + (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK) -/****************************************************************** - * Queue handling - ******************************************************************/ -/* puts character in the queue and sets up the in and out pointer */ -static void usb_kbd_put_queue(char data) -{ - if ((usb_in_pointer+1) == USB_KBD_BUFFER_LEN) { - if (usb_out_pointer == 0) - return; /* buffer full */ - else - usb_in_pointer = 0; - } else { - if ((usb_in_pointer+1) == usb_out_pointer) - return; /* buffer full */ - usb_in_pointer++; - } - usb_kbd_buffer[usb_in_pointer] = data; - return; -} +struct usb_kbd_pdata { + uint32_t repeat_delay; -/* test if a character is in the queue */ -static int usb_kbd_testc(void) -{ - struct stdio_dev *dev; - struct usb_device *usb_kbd_dev; + uint32_t usb_in_pointer; + uint32_t usb_out_pointer; + uint8_t usb_kbd_buffer[USB_KBD_BUFFER_LEN]; - dev = stdio_get_by_name("usbkbd"); - usb_kbd_dev = (struct usb_device *)dev->priv; + uint8_t new[8]; + uint8_t old[8]; - usb_kbd_poll_for_event(usb_kbd_dev); + uint8_t flags; +}; - if (usb_in_pointer == usb_out_pointer) - return 0; /* no data */ - else - return 1; -} -/* gets the character from the queue */ -static int usb_kbd_getc(void) +/* Generic keyboard event polling. */ +void usb_kbd_generic_poll(void) { - char c; - struct stdio_dev *dev; struct usb_device *usb_kbd_dev; + struct usb_kbd_pdata *data; + struct usb_interface *iface; + struct usb_endpoint_descriptor *ep; + int pipe; + int maxp; - dev = stdio_get_by_name("usbkbd"); + /* Get the pointer to USB Keyboard device pointer */ + dev = stdio_get_by_name(DEVNAME); usb_kbd_dev = (struct usb_device *)dev->priv; + data = usb_kbd_dev->privptr; + iface = &usb_kbd_dev->config.if_desc[0]; + ep = &iface->ep_desc[0]; + pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress); - 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 - usb_out_pointer++; - c = usb_kbd_buffer[usb_out_pointer]; - return (int)c; - + /* Submit a interrupt transfer request */ + maxp = usb_maxpacket(usb_kbd_dev, pipe); + usb_submit_int_msg(usb_kbd_dev, pipe, data->new, + maxp > 8 ? 8 : maxp, ep->bInterval); } -/* forward decleration */ -static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum); - -/* search for keyboard and register it if found */ -int drv_usb_kbd_init(void) +/* Puts character in the queue and sets up the in and out pointer. */ +static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c) { - int error, i; - struct stdio_dev usb_kbd_dev, *old_dev; - struct usb_device *dev; - char *stdinname = getenv("stdin"); + if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) { + /* Check for buffer full. */ + if (data->usb_out_pointer == 0) + return; - usb_in_pointer = 0; - usb_out_pointer = 0; - /* scan all USB Devices */ - for (i = 0 ; i < USB_MAX_DEVICE ; i++) { - dev = usb_get_dev_index(i); /* get device */ - if (dev == NULL) - return -1; - if (dev->devnum != -1) { - /* Ok, we found a keyboard */ - if (usb_kbd_probe(dev, 0) == 1) { - /* check, if it is already registered */ - USB_KBD_PRINTF("USB KBD found set up " - "device.\n"); - old_dev = stdio_get_by_name(DEVNAME); - if (old_dev) { - /* already registered, just return ok */ - USB_KBD_PRINTF("USB KBD is already " - "registered.\n"); - return 1; - } - /* register the keyboard */ - USB_KBD_PRINTF("USB KBD register.\n"); - memset(&usb_kbd_dev, 0, - sizeof(struct stdio_dev)); - strcpy(usb_kbd_dev.name, DEVNAME); - usb_kbd_dev.flags = DEV_FLAGS_INPUT | - DEV_FLAGS_SYSTEM; - usb_kbd_dev.putc = NULL; - usb_kbd_dev.puts = NULL; - usb_kbd_dev.getc = usb_kbd_getc; - usb_kbd_dev.tstc = usb_kbd_testc; - usb_kbd_dev.priv = (void *)dev; - error = stdio_register(&usb_kbd_dev); - if (error == 0) { - /* - * check if this is the standard - * input device - */ - if (strcmp(stdinname, DEVNAME) == 0) { - /* reassign the console */ - if (overwrite_console()) - return 1; - error = console_assign(stdin, - DEVNAME); - if (error == 0) - return 1; - else - return error; - } - return 1; - } - return error; - } - } - } - /* no USB Keyboard found */ - return -1; -} + data->usb_in_pointer = 0; + } else { + /* Check for buffer full. */ + if (data->usb_in_pointer == data->usb_out_pointer - 1) + return; + data->usb_in_pointer++; + } -/* deregistering the keyboard */ -int usb_kbd_deregister(void) -{ -#ifdef CONFIG_SYS_STDIO_DEREGISTER - return stdio_deregister(DEVNAME); -#else - return 1; -#endif + data->usb_kbd_buffer[data->usb_in_pointer] = c; } -/************************************************************************** - * Low Level drivers +/* + * Set the LEDs. Since this is used in the irq routine, the control job is + * issued with a timeout of 0. This means, that the job is queued without + * waiting for job completion. */ - -/* set the LEDs. Since this is used in the irq routine, the control job - is issued with a timeout of 0. This means, that the job is queued without - waiting for job completion */ - static void usb_kbd_setled(struct usb_device *dev) { - struct usb_interface *iface; - iface = &dev->config.if_desc[0]; - leds = 0; - if (scroll_lock != 0) - leds |= 1; - leds <<= 1; - if (caps_lock != 0) - leds |= 1; - leds <<= 1; - if (num_lock != 0) - leds |= 1; + struct usb_interface *iface = &dev->config.if_desc[0]; + struct usb_kbd_pdata *data = dev->privptr; + uint32_t leds = data->flags & USB_KBD_LEDMASK; + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x200, iface->desc.bInterfaceNumber, (void *)&leds, 1, 0); - } - -#define CAPITAL_MASK 0x20 +#define CAPITAL_MASK 0x20 /* Translate the scancode in ASCII */ -static int usb_kbd_translate(unsigned char scancode, unsigned char modifier, - int pressed) +static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode, + unsigned char modifier, int pressed) { - unsigned char keycode; + uint8_t keycode = 0; + /* Key released */ if (pressed == 0) { - /* key released */ - repeat_delay = 0; + data->repeat_delay = 0; return 0; } + if (pressed == 2) { - repeat_delay++; - if (repeat_delay < REPEAT_DELAY) + data->repeat_delay++; + if (data->repeat_delay < REPEAT_DELAY) return 0; - repeat_delay = REPEAT_DELAY; + + data->repeat_delay = REPEAT_DELAY; } - keycode = 0; - if ((scancode > 3) && (scancode <= 0x1d)) { /* alpha numeric values */ - keycode = scancode - 4 + 0x61; - if (caps_lock) - /* switch to capital Letters */ + + /* Alphanumeric values */ + if ((scancode > 3) && (scancode <= 0x1d)) { + keycode = scancode - 4 + 'a'; + + if (data->flags & USB_KBD_CAPSLOCK) keycode &= ~CAPITAL_MASK; - if (((modifier&(1 << LEFT_SHIFT)) != 0) || - ((modifier&(1 << RIGHT_SHIFT)) != 0)) { + + if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) { + /* Handle CAPSLock + Shift pressed simultaneously */ if (keycode & CAPITAL_MASK) - /* switch to capital Letters */ keycode &= ~CAPITAL_MASK; else - /* switch to non capital Letters */ keycode |= CAPITAL_MASK; } } - if ((scancode > 0x1d) && (scancode < 0x3A)) { - if (((modifier&(1 << LEFT_SHIFT)) != 0) || - ((modifier&(1 << RIGHT_SHIFT)) != 0)) /* shifted */ - keycode = usb_kbd_numkey_shifted[scancode-0x1e]; - else /* non shifted */ - keycode = usb_kbd_numkey[scancode-0x1e]; + + if ((scancode > 0x1d) && (scancode < 0x3a)) { + /* Shift pressed */ + if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) + keycode = usb_kbd_numkey_shifted[scancode - 0x1e]; + else + keycode = usb_kbd_numkey[scancode - 0x1e]; } - if (ctrl) + if (data->flags & USB_KBD_CTRL) keycode = scancode - 0x3; if (pressed == 1) { if (scancode == NUM_LOCK) { - num_lock = ~num_lock; + data->flags ^= USB_KBD_NUMLOCK; return 1; } + if (scancode == CAPS_LOCK) { - caps_lock = ~caps_lock; + data->flags ^= USB_KBD_CAPSLOCK; return 1; } if (scancode == SCROLL_LOCK) { - scroll_lock = ~scroll_lock; + data->flags ^= USB_KBD_SCROLLLOCK; return 1; } } - if (keycode != 0) { + + /* Report keycode if any */ + if (keycode) { USB_KBD_PRINTF("%c", keycode); - usb_kbd_put_queue(keycode); + usb_kbd_put_queue(data, keycode); } + return 0; } +static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up) +{ + uint32_t res = 0; + struct usb_kbd_pdata *data = dev->privptr; + uint8_t *new; + uint8_t *old; + + if (up) { + new = data->old; + old = data->new; + } else { + new = data->new; + old = data->old; + } + + if ((old[i] > 3) && (memscan(new + 2, old[i], 6) == new + 8)) + res |= usb_kbd_translate(data, old[i], data->new[0], up); + + return res; +} + /* Interrupt service routine */ static int usb_kbd_irq_worker(struct usb_device *dev) { - int i, res; + struct usb_kbd_pdata *data = dev->privptr; + int i, res = 0; - res = 0; - - switch (new[0]) { - case 0x0: /* No combo key pressed */ - ctrl = 0; - break; - case 0x01: /* Left Ctrl pressed */ - case 0x10: /* Right Ctrl pressed */ - ctrl = 1; - break; - } + /* No combo key pressed */ + if (data->new[0] == 0x00) + data->flags &= ~USB_KBD_CTRL; + /* Left or Right Ctrl pressed */ + else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR)) + data->flags |= USB_KBD_CTRL; for (i = 2; i < 8; i++) { - if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8]) - res |= usb_kbd_translate(old[i], new[0], 0); - - if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8]) - res |= usb_kbd_translate(new[i], new[0], 1); + res |= usb_kbd_service_key(dev, i, 0); + res |= usb_kbd_service_key(dev, i, 1); } - if ((new[2] > 3) && (old[2] == new[2])) /* still pressed */ - res |= usb_kbd_translate(new[2], new[0], 2); + /* Key is still pressed */ + if ((data->new[2] > 3) && (data->old[2] == data->new[2])) + res |= usb_kbd_translate(data, data->new[2], data->new[0], 2); + if (res == 1) usb_kbd_setled(dev); - memcpy(&old[0], &new[0], 8); + memcpy(data->old, data->new, 8); - return 1; /* install IRQ Handler again */ + return 1; } +/* Keyboard interrupt handler */ 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", + USB_KBD_PRINTF("USB KBD: Error %lX, len %d\n", dev->irq_status, dev->irq_act_len); return 1; } @@ -398,50 +309,202 @@ static int usb_kbd_irq(struct usb_device *dev) return usb_kbd_irq_worker(dev); } -/* probes the USB device dev for keyboard type */ +/* 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; + struct usb_kbd_pdata *data = dev->privptr; + iface = &dev->config.if_desc[0]; + usb_get_report(dev, iface->desc.bInterfaceNumber, + 1, 1, data->new, sizeof(data->new)); + if (memcmp(data->old, data->new, sizeof(data->new))) + usb_kbd_irq_worker(dev); +#endif +} + +/* test if a character is in the queue */ +static int usb_kbd_testc(void) +{ + struct stdio_dev *dev; + struct usb_device *usb_kbd_dev; + struct usb_kbd_pdata *data; + + dev = stdio_get_by_name(DEVNAME); + usb_kbd_dev = (struct usb_device *)dev->priv; + data = usb_kbd_dev->privptr; + + usb_kbd_poll_for_event(usb_kbd_dev); + + return !(data->usb_in_pointer == data->usb_out_pointer); +} + +/* gets the character from the queue */ +static int usb_kbd_getc(void) +{ + struct stdio_dev *dev; + struct usb_device *usb_kbd_dev; + struct usb_kbd_pdata *data; + + dev = stdio_get_by_name(DEVNAME); + usb_kbd_dev = (struct usb_device *)dev->priv; + data = usb_kbd_dev->privptr; + + while (data->usb_in_pointer == data->usb_out_pointer) + usb_kbd_poll_for_event(usb_kbd_dev); + + if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1) + data->usb_out_pointer = 0; + else + data->usb_out_pointer++; + + return data->usb_kbd_buffer[data->usb_out_pointer]; +} + +/* probes the USB device dev for keyboard type. */ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface *iface; struct usb_endpoint_descriptor *ep; + struct usb_kbd_pdata *data; int pipe, maxp; if (dev->descriptor.bNumConfigurations != 1) return 0; + iface = &dev->config.if_desc[ifnum]; if (iface->desc.bInterfaceClass != 3) return 0; + if (iface->desc.bInterfaceSubClass != 1) return 0; + if (iface->desc.bInterfaceProtocol != 1) return 0; + if (iface->desc.bNumEndpoints != 1) return 0; ep = &iface->ep_desc[0]; + /* Check if endpoint 1 is interrupt endpoint */ if (!(ep->bEndpointAddress & 0x80)) return 0; + if ((ep->bmAttributes & 3) != 3) return 0; - USB_KBD_PRINTF("USB KBD found set protocol...\n"); - /* ok, we found a USB Keyboard, install it */ - /* usb_kbd_get_hid_desc(dev); */ - usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); - USB_KBD_PRINTF("USB KBD found set idle...\n"); - usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0); - memset(&new[0], 0, 8); - memset(&old[0], 0, 8); - repeat_delay = 0; + + USB_KBD_PRINTF("USB KBD: found set protocol...\n"); + + data = malloc(sizeof(struct usb_kbd_pdata)); + if (!data) { + printf("USB KBD: Error allocating private data\n"); + return 0; + } + + /* Clear private data */ + memset(data, 0, sizeof(struct usb_kbd_pdata)); + + /* Insert private data into USB device structure */ + dev->privptr = data; + + /* Set IRQ handler */ + dev->irq_handle = usb_kbd_irq; + pipe = usb_rcvintpipe(dev, ep->bEndpointAddress); maxp = usb_maxpacket(dev, pipe); - dev->irq_handle = usb_kbd_irq; - USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n"); - usb_submit_int_msg(dev, pipe, &new[0], maxp > 8 ? 8 : maxp, + + /* We found a USB Keyboard, install it. */ + usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); + + USB_KBD_PRINTF("USB KBD: found set idle...\n"); + usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0); + + USB_KBD_PRINTF("USB KBD: enable interrupt pipe...\n"); + usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp, ep->bInterval); + + /* Success. */ return 1; } +/* Search for keyboard and register it if found. */ +int drv_usb_kbd_init(void) +{ + struct stdio_dev usb_kbd_dev, *old_dev; + struct usb_device *dev; + char *stdinname = getenv("stdin"); + int error, i; + + /* Scan all USB Devices */ + for (i = 0; i < USB_MAX_DEVICE; i++) { + /* Get USB device. */ + dev = usb_get_dev_index(i); + if (!dev) + return -1; + + if (dev->devnum == -1) + continue; + + /* Try probing the keyboard */ + if (usb_kbd_probe(dev, 0) != 1) + continue; + + /* We found a keyboard, check if it is already registered. */ + USB_KBD_PRINTF("USB KBD: found set up device.\n"); + old_dev = stdio_get_by_name(DEVNAME); + if (old_dev) { + /* Already registered, just return ok. */ + USB_KBD_PRINTF("USB KBD: is already registered.\n"); + return 1; + } + + /* Register the keyboard */ + USB_KBD_PRINTF("USB KBD: register.\n"); + memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev)); + strcpy(usb_kbd_dev.name, DEVNAME); + usb_kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; + usb_kbd_dev.putc = NULL; + usb_kbd_dev.puts = NULL; + usb_kbd_dev.getc = usb_kbd_getc; + usb_kbd_dev.tstc = usb_kbd_testc; + usb_kbd_dev.priv = (void *)dev; + error = stdio_register(&usb_kbd_dev); + if (error) + return error; + + /* Check if this is the standard input device. */ + if (strcmp(stdinname, DEVNAME)) + return 1; + + /* Reassign the console */ + if (overwrite_console()) + return 1; + + error = console_assign(stdin, DEVNAME); + if (error) + return error; + + return 1; + } + + /* No USB Keyboard found */ + return -1; +} + +/* Deregister the keyboard. */ +int usb_kbd_deregister(void) +{ +#ifdef CONFIG_SYS_STDIO_DEREGISTER + return stdio_deregister(DEVNAME); +#else + return 1; +#endif +} #if 0 struct usb_hid_descriptor { -- cgit v1.3.1 From 5a1219efe912855f0fc64471d31c1c392d8ad488 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 10 Oct 2011 17:34:27 +0200 Subject: USB: Drop dead code from usb_kbd.c Signed-off-by: Marek Vasut Acked-by: Mike Frysinger Cc: Remy Bohmer Cc: Wolfgang Denk --- common/usb_kbd.c | 379 ------------------------------------------------------- 1 file changed, 379 deletions(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 2d788314c8d..75107c9a45d 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -505,382 +505,3 @@ int usb_kbd_deregister(void) return 1; #endif } - -#if 0 -struct usb_hid_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; /* 0x21 for HID */ - unsigned short bcdHID; /* release number */ - unsigned char bCountryCode; - unsigned char bNumDescriptors; - unsigned char bReportDescriptorType; - unsigned short wDescriptorLength; -} __packed; - -/* - * We parse each description item into this structure. Short items data - * values are expanded to 32-bit signed int, long items contain a pointer - * into the data area. - */ - -struct hid_item { - unsigned char format; - unsigned char size; - unsigned char type; - unsigned char tag; - union { - unsigned char u8; - char s8; - unsigned short u16; - short s16; - unsigned long u32; - long s32; - unsigned char *longdata; - } data; -}; - -/* - * HID report item format - */ - -#define HID_ITEM_FORMAT_SHORT 0 -#define HID_ITEM_FORMAT_LONG 1 - -/* - * Special tag indicating long items - */ - -#define HID_ITEM_TAG_LONG 15 - - -static struct usb_hid_descriptor usb_kbd_hid_desc; - -void usb_kbd_display_hid(struct usb_hid_descriptor *hid) -{ - printf("USB_HID_DESC:\n"); - printf(" bLenght 0x%x\n", hid->bLength); - printf(" bcdHID 0x%x\n", hid->bcdHID); - printf(" bCountryCode %d\n", hid->bCountryCode); - printf(" bNumDescriptors 0x%x\n", hid->bNumDescriptors); - printf(" bReportDescriptorType 0x%x\n", hid->bReportDescriptorType); - printf(" wDescriptorLength 0x%x\n", hid->wDescriptorLength); -} - - -/* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. - */ - -static int fetch_item(unsigned char *start, unsigned char *end, - struct hid_item *item) -{ - if ((end - start) > 0) { - unsigned char b = *start++; - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; - if (item->tag == HID_ITEM_TAG_LONG) { - item->format = HID_ITEM_FORMAT_LONG; - if ((end - start) >= 2) { - item->size = *start++; - item->tag = *start++; - if ((end - start) >= item->size) { - item->data.longdata = start; - start += item->size; - return item->size; - } - } - } else { - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - switch (item->size) { - case 0: - return item->size; - case 1: - if ((end - start) >= 1) { - item->data.u8 = *start++; - return item->size; - } - break; - case 2: - if ((end - start) >= 2) { - item->data.u16 = le16_to_cpu( - (unsigned short *)start); - start += 2; - return item->size; - } - case 3: - item->size++; - if ((end - start) >= 4) { - item->data.u32 = le32_to_cpu( - (unsigned long *)start); - start += 4; - return item->size; - } - } - } - } - return -1; -} - -/* - * HID report descriptor item type (prefix bit 2, 3) - */ - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 -/* - * HID report descriptor main item tags - */ - -#define HID_MAIN_ITEM_TAG_INPUT 8 -#define HID_MAIN_ITEM_TAG_OUTPUT 9 -#define HID_MAIN_ITEM_TAG_FEATURE 11 -#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 -#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 -/* - * HID report descriptor main item contents - */ - -#define HID_MAIN_ITEM_CONSTANT 0x001 -#define HID_MAIN_ITEM_VARIABLE 0x002 -#define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 -#define HID_MAIN_ITEM_NONLINEAR 0x010 -#define HID_MAIN_ITEM_NO_PREFERRED 0x020 -#define HID_MAIN_ITEM_NULL_STATE 0x040 -#define HID_MAIN_ITEM_VOLATILE 0x080 -#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 - -/* - * HID report descriptor collection item types - */ - -#define HID_COLLECTION_PHYSICAL 0 -#define HID_COLLECTION_APPLICATION 1 -#define HID_COLLECTION_LOGICAL 2 -/* - * HID report descriptor global item tags - */ - -#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 -#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 -#define HID_GLOBAL_ITEM_TAG_UNIT 6 -#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 -#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 -#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 -#define HID_GLOBAL_ITEM_TAG_PUSH 10 -#define HID_GLOBAL_ITEM_TAG_POP 11 - -/* - * HID report descriptor local item tags - */ - -#define HID_LOCAL_ITEM_TAG_USAGE 0 -#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 -#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 -#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 -#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 -#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 -#define HID_LOCAL_ITEM_TAG_DELIMITER 10 - - -static void usb_kbd_show_item(struct hid_item *item) -{ - switch (item->type) { - case HID_ITEM_TYPE_MAIN: - switch (item->tag) { - case HID_MAIN_ITEM_TAG_INPUT: - printf("Main Input"); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - printf("Main Output"); - break; - case HID_MAIN_ITEM_TAG_FEATURE: - printf("Main Feature"); - break; - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - printf("Main Begin Collection"); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - printf("Main End Collection"); - break; - default: - printf("Main reserved %d", item->tag); - break; - } - break; - case HID_ITEM_TYPE_GLOBAL: - switch (item->tag) { - case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: - printf("- Global Usage Page"); - break; - case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: - printf("- Global Logical Minimum"); - break; - case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - printf("- Global Logical Maximum"); - break; - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: - printf("- Global physical Minimum"); - break; - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - printf("- Global physical Maximum"); - break; - case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - printf("- Global Unit Exponent"); - break; - case HID_GLOBAL_ITEM_TAG_UNIT: - printf("- Global Unit"); - break; - case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: - printf("- Global Report Size"); - break; - case HID_GLOBAL_ITEM_TAG_REPORT_ID: - printf("- Global Report ID"); - break; - case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - printf("- Global Report Count"); - break; - case HID_GLOBAL_ITEM_TAG_PUSH: - printf("- Global Push"); - break; - case HID_GLOBAL_ITEM_TAG_POP: - printf("- Global Pop"); - break; - default: - printf("- Global reserved %d", item->tag); - break; - } - break; - case HID_ITEM_TYPE_LOCAL: - switch (item->tag) { - case HID_LOCAL_ITEM_TAG_USAGE: - printf("-- Local Usage"); - break; - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - printf("-- Local Usage Minimum"); - break; - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - printf("-- Local Usage Maximum"); - break; - case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX: - printf("-- Local Designator Index"); - break; - case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM: - printf("-- Local Designator Minimum"); - break; - case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM: - printf("-- Local Designator Maximum"); - break; - case HID_LOCAL_ITEM_TAG_STRING_INDEX: - printf("-- Local String Index"); - break; - case HID_LOCAL_ITEM_TAG_STRING_MINIMUM: - printf("-- Local String Minimum"); - break; - case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM: - printf("-- Local String Maximum"); - break; - case HID_LOCAL_ITEM_TAG_DELIMITER: - printf("-- Local Delimiter"); - break; - default: - printf("-- Local reserved %d", item->tag); - break; - } - break; - default: - printf("--- reserved %d", item->type); - break; - } - switch (item->size) { - case 1: - printf(" %d", item->data.u8); - break; - case 2: - printf(" %d", item->data.u16); - break; - case 4: - printf(" %ld", item->data.u32); - break; - } - printf("\n"); -} - - -static int usb_kbd_get_hid_desc(struct usb_device *dev) -{ - unsigned char buffer[256]; - struct usb_descriptor_header *head; - struct usb_config_descriptor *config; - int index, len, i; - unsigned char *start, *end; - struct hid_item item; - - if (usb_get_configuration_no(dev, &buffer[0], 0) == -1) - return -1; - head = (struct usb_descriptor_header *)&buffer[0]; - if (head->bDescriptorType != USB_DT_CONFIG) { - printf(" ERROR: NOT USB_CONFIG_DESC %x\n", - head->bDescriptorType); - return -1; - } - index = head->bLength; - config = (struct usb_config_descriptor *)&buffer[0]; - len = le16_to_cpu(config->wTotalLength); - /* - * Ok the first entry must be a configuration entry, - * now process the others - */ - head = (struct usb_descriptor_header *)&buffer[index]; - while (index+1 < len) { - if (head->bDescriptorType == USB_DT_HID) { - printf("HID desc found\n"); - memcpy(&usb_kbd_hid_desc, &buffer[index], - buffer[index]); - le16_to_cpus(&usb_kbd_hid_desc.bcdHID); - le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength); - usb_kbd_display_hid(&usb_kbd_hid_desc); - len = 0; - break; - } - index += head->bLength; - head = (struct usb_descriptor_header *)&buffer[index]; - } - if (len > 0) - return -1; - len = usb_kbd_hid_desc.wDescriptorLength; - index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], - len); - if (index < 0) { - printf("reading report descriptor failed\n"); - return -1; - } - printf(" report descriptor (size %u, read %d)\n", len, index); - start = &buffer[0]; - end = &buffer[len]; - i = 0; - do { - index = fetch_item(start, end, &item); - i += index; - i++; - if (index >= 0) - usb_kbd_show_item(&item); - - start += index; - start++; - } while (index >= 0); - -} - -#endif -- cgit v1.3.1 From b3813a221bc9770f67f54603c8e508b7fb93a7cd Mon Sep 17 00:00:00 2001 From: Veli-Pekka Peltola Date: Wed, 2 Nov 2011 16:59:55 +0200 Subject: cosmetic: remove excess whitespace from usb command help Signed-off-by: Veli-Pekka Peltola Cc: Remy Bohmer --- common/cmd_usb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 8c87265668d..aecde13bb44 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -701,10 +701,10 @@ U_BOOT_CMD( usb, 5, 1, do_usb, "USB sub-system", "reset - reset (rescan) USB controller\n" - "usb stop [f] - stop USB [f]=force stop\n" - "usb tree - show USB device tree\n" + "usb stop [f] - stop USB [f]=force stop\n" + "usb tree - show USB device tree\n" "usb info [dev] - show available USB devices\n" - "usb storage - show details of USB storage devices\n" + "usb storage - show details of USB storage devices\n" "usb dev [dev] - show or set current USB storage device\n" "usb part [dev] - print partition table of one or all USB storage" " devices\n" @@ -726,7 +726,7 @@ U_BOOT_CMD( usb, 5, 1, do_usb, "USB sub-system", "reset - reset (rescan) USB controller\n" - "usb tree - show USB device tree\n" - "usb info [dev] - show available USB devices" + "usb tree - show USB device tree\n" + "usb info [dev] - show available USB devices" ); #endif -- cgit v1.3.1 From 1af9f9633759a5f60e8b8bd4fcdb17a3d1aece5f Mon Sep 17 00:00:00 2001 From: Veli-Pekka Peltola Date: Wed, 2 Nov 2011 16:59:56 +0200 Subject: usb: add help for missing start subcommand Signed-off-by: Veli-Pekka Peltola Cc: Remy Bohmer --- common/cmd_usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/cmd_usb.c b/common/cmd_usb.c index aecde13bb44..d4ec2a291cd 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -700,7 +700,8 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) U_BOOT_CMD( usb, 5, 1, do_usb, "USB sub-system", - "reset - reset (rescan) USB controller\n" + "start - start (scan) USB controller\n" + "usb reset - reset (rescan) USB controller\n" "usb stop [f] - stop USB [f]=force stop\n" "usb tree - show USB device tree\n" "usb info [dev] - show available USB devices\n" @@ -725,7 +726,8 @@ U_BOOT_CMD( U_BOOT_CMD( usb, 5, 1, do_usb, "USB sub-system", - "reset - reset (rescan) USB controller\n" + "start - start (scan) USB controller\n" + "usb reset - reset (rescan) USB controller\n" "usb tree - show USB device tree\n" "usb info [dev] - show available USB devices" ); -- cgit v1.3.1