From 9b2393812e2b844919ac601b893e6210d5eb6e2c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:51:26 +0200 Subject: usb: kbd: Fix unaligned buffer usage in usb_kbd_setled() Signed-off-by: Hans de Goede --- common/usb_kbd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index c34fd5c..87f4125 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -170,11 +170,12 @@ static void usb_kbd_setled(struct usb_device *dev) { struct usb_interface *iface = &dev->config.if_desc[0]; struct usb_kbd_pdata *data = dev->privptr; - uint32_t leds = data->flags & USB_KBD_LEDMASK; + ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN); + *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); + 0x200, iface->desc.bInterfaceNumber, leds, 1, 0); } #define CAPITAL_MASK 0x20 -- cgit v1.1 From 0ea09dfe873657df47d83d5d4e0090bbf05c6abb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:34 +0200 Subject: usb: kbd: Do not treat -ENODEV as an error for usb_kbd_deregister ENODEV menas no usb keyboard was registered, threat this as a successful usb_kbd_deregister. Signed-off-by: Hans de Goede --- common/usb_kbd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 87f4125..4c17b0d 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -8,6 +8,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include #include #include @@ -559,7 +560,11 @@ int drv_usb_kbd_init(void) int usb_kbd_deregister(void) { #ifdef CONFIG_SYS_STDIO_DEREGISTER - return stdio_deregister(DEVNAME); + int ret = stdio_deregister(DEVNAME); + if (ret && ret != -ENODEV) + return ret; + + return 0; #else return 1; #endif -- cgit v1.1 From 6e78c74f62ebfa378d1a2f9b83423b23545c28bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:35 +0200 Subject: usb: kbd: On a "usb reset" call usb_kbd_deregister() before calling usb_stop() We need to call usb_kbd_deregister() before calling usb_stop(). usbkbd's stdio_dev->priv points to the usb_device, and usb_kbd_testc dereferences usb_device->privptr. usb_stop zeros usb_device, leaving usb_device->privptr NULL, causing bad things (tm) to happen once control returns to the main loop and usb_kbd_testc gets called. Calling usb_kbd_deregister() avoids this. Note that we do not allow the "usb reset" to continue when the deregister fails. This will be fixed in a later patch. For the same reasons always fail "usb stop" if the usb_kbd_deregister() fails, even in the force path. This can happen when CONFIG_SYS_STDIO_DEREGISTER is not set. Signed-off-by: Hans de Goede --- common/cmd_usb.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'common') diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 2519497..b2aa44c 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -430,6 +430,16 @@ static int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif /* CONFIG_USB_STORAGE */ +static int do_usb_stop_keyboard(void) +{ +#ifdef CONFIG_USB_KEYBOARD + if (usb_kbd_deregister() != 0) { + printf("USB not stopped: usbkbd still using USB\n"); + return 1; + } +#endif + return 0; +} /****************************************************************************** * usb command intepreter @@ -450,6 +460,8 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if ((strncmp(argv[1], "reset", 5) == 0) || (strncmp(argv[1], "start", 5) == 0)) { bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start"); + if (do_usb_stop_keyboard() != 0) + return 1; usb_stop(); printf("(Re)start USB...\n"); if (usb_init() >= 0) { @@ -468,19 +480,10 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } if (strncmp(argv[1], "stop", 4) == 0) { -#ifdef CONFIG_USB_KEYBOARD - if (argc == 2) { - if (usb_kbd_deregister() != 0) { - printf("USB not stopped: usbkbd still" - " using USB\n"); - return 1; - } - } else { - /* forced stop, switch console in to serial */ + if (argc != 2) console_assign(stdin, "serial"); - usb_kbd_deregister(); - } -#endif + if (do_usb_stop_keyboard() != 0) + return 1; printf("stopping USB..\n"); usb_stop(); return 0; -- cgit v1.1 From 3f78a28037c65b92d2717b7787902a853c2506a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:36 +0200 Subject: usb: kbd: Remove check for already being registered We now always properly deregister the keyboard before calling drv_usb_kbd_init(), so we can drop the check for already being registered. Signed-off-by: Hans de Goede --- common/usb_kbd.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 4c17b0d..d4d5f48 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -490,7 +490,7 @@ 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) { - struct stdio_dev usb_kbd_dev, *old_dev; + struct stdio_dev usb_kbd_dev; struct usb_device *dev; char *stdinname = getenv("stdin"); int error, i; @@ -509,16 +509,6 @@ int drv_usb_kbd_init(void) if (usb_kbd_probe(dev, 0) != 1) continue; - /* We found a keyboard, check if it is already registered. */ - debug("USB KBD: found set up device.\n"); - old_dev = stdio_get_by_name(DEVNAME); - if (old_dev) { - /* Already registered, just return ok. */ - debug("USB KBD: is already registered.\n"); - usb_kbd_deregister(); - return 1; - } - /* Register the keyboard */ debug("USB KBD: register.\n"); memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev)); -- cgit v1.1 From 32d019265d1f0c334f2f86407abf295d46bd2f4d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:37 +0200 Subject: stdio: Add force parameter to stdio_deregister In some cases we really want to move forward with a deregister, add a force parameter to allow this, and replace the dev with a nulldev in this case. Signed-off-by: Hans de Goede --- common/stdio.c | 13 ++++++++++--- common/usb_kbd.c | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/stdio.c b/common/stdio.c index c878103..8232815 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -34,6 +34,9 @@ char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" }; #define CONFIG_SYS_DEVICE_NULLDEV 1 #endif +#ifdef CONFIG_SYS_STDIO_DEREGISTER +#define CONFIG_SYS_DEVICE_NULLDEV 1 +#endif #ifdef CONFIG_SYS_DEVICE_NULLDEV void nulldev_putc(struct stdio_dev *dev, const char c) @@ -172,7 +175,7 @@ int stdio_register(struct stdio_dev *dev) * returns 0 if success, -1 if device is assigned and 1 if devname not found */ #ifdef CONFIG_SYS_STDIO_DEREGISTER -int stdio_deregister_dev(struct stdio_dev *dev) +int stdio_deregister_dev(struct stdio_dev *dev, int force) { int l; struct list_head *pos; @@ -181,6 +184,10 @@ int stdio_deregister_dev(struct stdio_dev *dev) /* get stdio devices (ListRemoveItem changes the dev list) */ for (l=0 ; l< MAX_FILES; l++) { if (stdio_devices[l] == dev) { + if (force) { + strcpy(temp_names[l], "nulldev"); + continue; + } /* Device is assigned -> report error */ return -1; } @@ -202,7 +209,7 @@ int stdio_deregister_dev(struct stdio_dev *dev) return 0; } -int stdio_deregister(const char *devname) +int stdio_deregister(const char *devname, int force) { struct stdio_dev *dev; @@ -211,7 +218,7 @@ int stdio_deregister(const char *devname) if (!dev) /* device not found */ return -ENODEV; - return stdio_deregister_dev(dev); + return stdio_deregister_dev(dev, force); } #endif /* CONFIG_SYS_STDIO_DEREGISTER */ diff --git a/common/usb_kbd.c b/common/usb_kbd.c index d4d5f48..dcb693d 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -550,7 +550,7 @@ int drv_usb_kbd_init(void) int usb_kbd_deregister(void) { #ifdef CONFIG_SYS_STDIO_DEREGISTER - int ret = stdio_deregister(DEVNAME); + int ret = stdio_deregister(DEVNAME, 0); if (ret && ret != -ENODEV) return ret; -- cgit v1.1 From 8a8a2257ec55a997d97edf6664249a628248fe01 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:38 +0200 Subject: usb: kbd: Allow "usb reset" to continue when an usb kbd is used Use the new force parameter to make the stdio_deregister succeed, replacing stdin with a nulldev, and assume that the usb keyboard will come back after the reset. Signed-off-by: Hans de Goede --- common/cmd_usb.c | 8 ++++---- common/usb_kbd.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'common') diff --git a/common/cmd_usb.c b/common/cmd_usb.c index b2aa44c..c192498 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -430,10 +430,10 @@ static int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif /* CONFIG_USB_STORAGE */ -static int do_usb_stop_keyboard(void) +static int do_usb_stop_keyboard(int force) { #ifdef CONFIG_USB_KEYBOARD - if (usb_kbd_deregister() != 0) { + if (usb_kbd_deregister(force) != 0) { printf("USB not stopped: usbkbd still using USB\n"); return 1; } @@ -460,7 +460,7 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if ((strncmp(argv[1], "reset", 5) == 0) || (strncmp(argv[1], "start", 5) == 0)) { bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start"); - if (do_usb_stop_keyboard() != 0) + if (do_usb_stop_keyboard(1) != 0) return 1; usb_stop(); printf("(Re)start USB...\n"); @@ -482,7 +482,7 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (strncmp(argv[1], "stop", 4) == 0) { if (argc != 2) console_assign(stdin, "serial"); - if (do_usb_stop_keyboard() != 0) + if (do_usb_stop_keyboard(0) != 0) return 1; printf("stopping USB..\n"); usb_stop(); diff --git a/common/usb_kbd.c b/common/usb_kbd.c index dcb693d..fdc083c 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -547,10 +547,10 @@ int drv_usb_kbd_init(void) } /* Deregister the keyboard. */ -int usb_kbd_deregister(void) +int usb_kbd_deregister(int force) { #ifdef CONFIG_SYS_STDIO_DEREGISTER - int ret = stdio_deregister(DEVNAME, 0); + int ret = stdio_deregister(DEVNAME, force); if (ret && ret != -ENODEV) return ret; -- cgit v1.1