X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=common%2Fusb_kbd.c;h=a6221ef71647c20ddef7d68b50346ab6c126d60c;hb=515f613253cf0a892c3a321770ab927fa3d925cf;hp=0227024441710041a4cbcb2fd5c30920ad9078a6;hpb=7c0e5d865ff0b86dfce492b656238919c659d756;p=oweals%2Fu-boot.git diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 0227024441..a6221ef716 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -1,17 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2001 * Denis Peter, MPL AG Switzerland * * Part of this source has been derived from the Linux USB * project. - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include +#include #include #include +#include #include +#include #include #include @@ -72,13 +75,12 @@ static const unsigned char usb_kbd_num_keypad[] = { '.', 0, 0, 0, '=' }; -/* - * map arrow keys to ^F/^B ^N/^P, can't really use the proper - * ANSI sequence for arrow keys because the queuing code breaks - * when a single keypress expands to 3 queue elements - */ -static const unsigned char usb_kbd_arrow[] = { - 0x6, 0x2, 0xe, 0x10 +static const u8 usb_special_keys[] = { +#ifdef CONFIG_USB_KEYBOARD_FN_KEYS + '2', 'H', '5', '3', 'F', '6', 'C', 'D', 'B', 'A' +#else + 'C', 'D', 'B', 'A' +#endif }; /* @@ -93,12 +95,6 @@ static const unsigned char usb_kbd_arrow[] = { #define USB_KBD_LEDMASK \ (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK) -/* - * USB Keyboard reports are 8 bytes in boot protocol. - * Appendix B of HID Device Class Definition 1.11 - */ -#define USB_KBD_BOOT_REPORT_SIZE 8 - struct usb_kbd_pdata { unsigned long intpipe; int intpktsize; @@ -124,7 +120,7 @@ extern int __maybe_unused net_busy_flag; static unsigned long __maybe_unused kbd_testc_tms; /* 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) +static void usb_kbd_put_queue(struct usb_kbd_pdata *data, u8 c) { if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) { /* Check for buffer full. */ @@ -197,7 +193,7 @@ static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode, } } - if ((scancode > 0x1d) && (scancode < 0x3a)) { + if ((scancode > 0x1d) && (scancode < 0x39)) { /* Shift pressed */ if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) keycode = usb_kbd_numkey_shifted[scancode - 0x1e]; @@ -205,10 +201,6 @@ static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode, keycode = usb_kbd_numkey[scancode - 0x1e]; } - /* Arrow keys */ - if ((scancode >= 0x4f) && (scancode <= 0x52)) - keycode = usb_kbd_arrow[scancode - 0x4f]; - /* Numeric keypad */ if ((scancode >= 0x54) && (scancode <= 0x67)) keycode = usb_kbd_num_keypad[scancode - 0x54]; @@ -236,9 +228,55 @@ static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode, if (keycode) { debug("%c", keycode); usb_kbd_put_queue(data, keycode); + return 0; } +#ifdef CONFIG_USB_KEYBOARD_FN_KEYS + if (scancode < 0x3a || scancode > 0x52 || + scancode == 0x46 || scancode == 0x47) + return 1; + + usb_kbd_put_queue(data, 0x1b); + if (scancode < 0x3e) { + /* F1 - F4 */ + usb_kbd_put_queue(data, 0x4f); + usb_kbd_put_queue(data, scancode - 0x3a + 'P'); + return 0; + } + usb_kbd_put_queue(data, '['); + if (scancode < 0x42) { + /* F5 - F8 */ + usb_kbd_put_queue(data, '1'); + if (scancode == 0x3e) + --scancode; + keycode = scancode - 0x3f + '7'; + } else if (scancode < 0x49) { + /* F9 - F12 */ + usb_kbd_put_queue(data, '2'); + if (scancode > 0x43) + ++scancode; + keycode = scancode - 0x42 + '0'; + } else { + /* + * INSERT, HOME, PAGE UP, DELETE, END, PAGE DOWN, + * RIGHT, LEFT, DOWN, UP + */ + keycode = usb_special_keys[scancode - 0x49]; + } + usb_kbd_put_queue(data, keycode); + if (scancode < 0x4f && scancode != 0x4a && scancode != 0x4d) + usb_kbd_put_queue(data, '~'); return 0; +#else + /* Left, Right, Up, Down */ + if (scancode > 0x4e && scancode < 0x53) { + usb_kbd_put_queue(data, 0x1b); + usb_kbd_put_queue(data, '['); + usb_kbd_put_queue(data, usb_special_keys[scancode - 0x4f]); + return 0; + } + return 1; +#endif /* CONFIG_USB_KEYBOARD_FN_KEYS */ } static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up) @@ -314,11 +352,10 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev) #if defined(CONFIG_SYS_USB_EVENT_POLL) struct usb_kbd_pdata *data = dev->privptr; - /* Submit a interrupt transfer request */ - usb_submit_int_msg(dev, data->intpipe, &data->new[0], data->intpktsize, - data->intinterval); - - usb_kbd_irq_worker(dev); + /* Submit an interrupt transfer request */ + if (usb_int_msg(dev, data->intpipe, &data->new[0], + data->intpktsize, data->intinterval, true) >= 0) + usb_kbd_irq_worker(dev); #elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) || \ defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) #if defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) @@ -366,7 +403,7 @@ static int usb_kbd_testc(struct stdio_dev *sdev) return 0; kbd_testc_tms = get_timer(0); #endif - dev = stdio_get_by_name(DEVNAME); + dev = stdio_get_by_name(sdev->name); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; @@ -382,12 +419,14 @@ static int usb_kbd_getc(struct stdio_dev *sdev) struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; - dev = stdio_get_by_name(DEVNAME); + dev = stdio_get_by_name(sdev->name); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; - while (data->usb_in_pointer == data->usb_out_pointer) + while (data->usb_in_pointer == data->usb_out_pointer) { + WATCHDOG_RESET(); usb_kbd_poll_for_event(usb_kbd_dev); + } if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1) data->usb_out_pointer = 0; @@ -398,7 +437,7 @@ static int usb_kbd_getc(struct stdio_dev *sdev) } /* probes the USB device dev for keyboard type. */ -static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) +static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) { struct usb_interface *iface; struct usb_endpoint_descriptor *ep; @@ -409,13 +448,13 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) iface = &dev->config.if_desc[ifnum]; - if (iface->desc.bInterfaceClass != 3) + if (iface->desc.bInterfaceClass != USB_CLASS_HID) return 0; - if (iface->desc.bInterfaceSubClass != 1) + if (iface->desc.bInterfaceSubClass != USB_SUB_HID_BOOT) return 0; - if (iface->desc.bInterfaceProtocol != 1) + if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD) return 0; if (iface->desc.bNumEndpoints != 1) @@ -474,9 +513,12 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) USB_KBD_BOOT_REPORT_SIZE, data->new, data->intinterval); if (!data->intq) { +#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) + if (usb_get_report(dev, iface->desc.bInterfaceNumber, + 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE) < 0) { #else - if (usb_submit_int_msg(dev, data->intpipe, data->new, data->intpktsize, - data->intinterval) < 0) { + if (usb_int_msg(dev, data->intpipe, data->new, data->intpktsize, + data->intinterval, false) < 0) { #endif printf("Failed to get keyboard state from device %04x:%04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -495,14 +537,14 @@ static int probe_usb_keyboard(struct usb_device *dev) int error; /* Try probing the keyboard */ - if (usb_kbd_probe(dev, 0) != 1) + if (usb_kbd_probe_dev(dev, 0) != 1) return -ENOENT; /* Register the keyboard */ debug("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.flags = DEV_FLAGS_INPUT; usb_kbd_dev.getc = usb_kbd_getc; usb_kbd_dev.tstc = usb_kbd_testc; usb_kbd_dev.priv = (void *)dev; @@ -510,8 +552,8 @@ static int probe_usb_keyboard(struct usb_device *dev) if (error) return error; - stdinname = getenv("stdin"); -#ifdef CONFIG_CONSOLE_MUX + stdinname = env_get("stdin"); +#if CONFIG_IS_ENABLED(CONSOLE_MUX) error = iomux_doenv(stdin, stdinname); if (error) return error; @@ -532,41 +574,13 @@ static int probe_usb_keyboard(struct usb_device *dev) return 0; } +#if !CONFIG_IS_ENABLED(DM_USB) /* Search for keyboard and register it if found. */ int drv_usb_kbd_init(void) { int error, i; debug("%s: Probing for keyboard\n", __func__); -#ifdef CONFIG_DM_USB - /* - * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB - * keyboard driver and then most of this file can be removed. - */ - struct udevice *bus; - struct uclass *uc; - int ret; - - ret = uclass_get(UCLASS_USB, &uc); - if (ret) - return ret; - uclass_foreach_dev(bus, uc) { - for (i = 0; i < USB_MAX_DEVICE; i++) { - struct usb_device *dev; - - dev = usb_get_dev_index(bus, i); /* get device */ - debug("i=%d, %p\n", i, dev); - if (!dev) - break; /* no more devices available */ - - error = probe_usb_keyboard(dev); - if (!error) - return 1; - if (error && error != -ENOENT) - return error; - } /* for */ - } -#else /* Scan all USB Devices */ for (i = 0; i < USB_MAX_DEVICE; i++) { struct usb_device *dev; @@ -585,7 +599,6 @@ int drv_usb_kbd_init(void) if (error && error != -ENOENT) return error; } -#endif /* No USB Keyboard found */ return -1; @@ -594,7 +607,7 @@ int drv_usb_kbd_init(void) /* Deregister the keyboard. */ int usb_kbd_deregister(int force) { -#ifdef CONFIG_SYS_STDIO_DEREGISTER +#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER) struct stdio_dev *dev; struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; @@ -605,8 +618,8 @@ int usb_kbd_deregister(int force) data = usb_kbd_dev->privptr; if (stdio_deregister_dev(dev, force) != 0) return 1; -#ifdef CONFIG_CONSOLE_MUX - if (iomux_doenv(stdin, getenv("stdin")) != 0) +#if CONFIG_IS_ENABLED(CONSOLE_MUX) + if (iomux_doenv(stdin, env_get("stdin")) != 0) return 1; #endif #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE @@ -621,3 +634,78 @@ int usb_kbd_deregister(int force) return 1; #endif } + +#endif + +#if CONFIG_IS_ENABLED(DM_USB) + +static int usb_kbd_probe(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parent_priv(dev); + + return probe_usb_keyboard(udev); +} + +static int usb_kbd_remove(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parent_priv(dev); + struct usb_kbd_pdata *data; + struct stdio_dev *sdev; + int ret; + + sdev = stdio_get_by_name(DEVNAME); + if (!sdev) { + ret = -ENXIO; + goto err; + } + data = udev->privptr; + if (stdio_deregister_dev(sdev, true)) { + ret = -EPERM; + goto err; + } +#if CONFIG_IS_ENABLED(CONSOLE_MUX) + if (iomux_doenv(stdin, env_get("stdin"))) { + ret = -ENOLINK; + goto err; + } +#endif +#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE + destroy_int_queue(udev, data->intq); +#endif + free(data->new); + free(data); + + return 0; +err: + printf("%s: warning, ret=%d", __func__, ret); + return ret; +} + +static const struct udevice_id usb_kbd_ids[] = { + { .compatible = "usb-keyboard" }, + { } +}; + +U_BOOT_DRIVER(usb_kbd) = { + .name = "usb_kbd", + .id = UCLASS_KEYBOARD, + .of_match = usb_kbd_ids, + .probe = usb_kbd_probe, + .remove = usb_kbd_remove, +}; + +static const struct usb_device_id kbd_id_table[] = { + { + .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_SUB_HID_BOOT, + .bInterfaceProtocol = USB_PROT_HID_KEYBOARD, + }, + { } /* Terminating entry */ +}; + +U_BOOT_USB_DEVICE(usb_kbd, kbd_id_table); + +#endif