Reworked the change a bit to escalate memory errors allowing usb.c:configure_usb_device() to free memory during device initialisation. Also removed some code duplication.
>From f6a653b0fcac0359d598c342ed0a51b05d6ebe16 Mon Sep 17 00:00:00 2001 From: Daniel Khodabakhsh <d.khodabak...@gmail.com> Date: Thu, 7 Nov 2024 10:34:47 -0800 Subject: [PATCH] Support multiple USB HID devices by storing them in a linked list. --- src/hw/usb-hid.c | 121 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 39 deletions(-) diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c index dec198ac..2350e121 100644 --- a/src/hw/usb-hid.c +++ b/src/hw/usb-hid.c @@ -1,20 +1,54 @@ // Code for handling USB Human Interface Devices (HID). // // Copyright (C) 2009 Kevin O'Connor <ke...@koconnor.net> +// Copyright (C) 2024 Daniel Khodabakhsh <d.khodabak...@gmail.com> // // This file may be distributed under the terms of the GNU LGPLv3 license. #include "biosvar.h" // GET_GLOBAL #include "config.h" // CONFIG_* -#include "output.h" // dprintf +#include "output.h" // dprintf, warn_noalloc +#include "malloc.h" // malloc_fseg #include "ps2port.h" // ATKBD_CMD_GETID +#include "stacks.h" // mutex_lock, mutex_unlock #include "usb.h" // usb_ctrlrequest #include "usb-hid.h" // usb_keyboard_setup #include "util.h" // process_key -struct usb_pipe *keyboard_pipe VARFSEG; -struct usb_pipe *mouse_pipe VARFSEG; +struct pipe_node { + struct usb_pipe *pipe; + struct pipe_node *next; +}; + +struct mutex_s usb_hid_lock; + +struct pipe_node *keyboard_pipe_node VARFSEG = NULL; +struct pipe_node *mouse_pipe_node VARFSEG = NULL; +static int +add_pipe_node(struct pipe_node **root_node + , struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc) +{ + struct usb_pipe *pipe = usb_alloc_pipe(usbdev, epdesc); + if (!pipe) + return -1; + + struct pipe_node *new_root_node = malloc_fseg(sizeof(struct pipe_node)); + if (!new_root_node) { + warn_noalloc(); + return -1; + } + + new_root_node->pipe = pipe; + + mutex_lock(&usb_hid_lock); + new_root_node->next = *root_node; + *root_node = new_root_node; + mutex_unlock(&usb_hid_lock); + + return 0; +} /**************************************************************** * Setup @@ -64,9 +98,6 @@ usb_kbd_setup(struct usbdevice_s *usbdev { if (! CONFIG_USB_KEYBOARD) return -1; - if (keyboard_pipe) - // XXX - this enables the first found keyboard (could be random) - return -1; if (epdesc->wMaxPacketSize < sizeof(struct keyevent) || epdesc->wMaxPacketSize > MAX_KBD_EVENT) { @@ -76,19 +107,16 @@ usb_kbd_setup(struct usbdevice_s *usbdev } // Enable "boot" protocol. - int ret = set_protocol(usbdev->defpipe, 0, usbdev->iface->bInterfaceNumber); - if (ret) { + if (set_protocol(usbdev->defpipe, 0, usbdev->iface->bInterfaceNumber)) { dprintf(3, "Failed to set boot protocol\n"); return -1; } // Periodically send reports to enable key repeat. - ret = set_idle(usbdev->defpipe, KEYREPEATMS); - if (ret) + if (set_idle(usbdev->defpipe, KEYREPEATMS)) dprintf(3, "Warning: Failed to set key repeat rate\n"); - keyboard_pipe = usb_alloc_pipe(usbdev, epdesc); - if (!keyboard_pipe) + if (add_pipe_node(&keyboard_pipe_node, usbdev, epdesc)) return -1; dprintf(1, "USB keyboard initialized\n"); @@ -109,9 +137,6 @@ usb_mouse_setup(struct usbdevice_s *usbdev { if (! CONFIG_USB_MOUSE) return -1; - if (mouse_pipe) - // XXX - this enables the first found mouse (could be random) - return -1; if (epdesc->wMaxPacketSize < sizeof(struct mouseevent) || epdesc->wMaxPacketSize > MAX_MOUSE_EVENT) { @@ -121,12 +146,10 @@ usb_mouse_setup(struct usbdevice_s *usbdev } // Enable "boot" protocol. - int ret = set_protocol(usbdev->defpipe, 0, usbdev->iface->bInterfaceNumber); - if (ret) + if (set_protocol(usbdev->defpipe, 0, usbdev->iface->bInterfaceNumber)) return -1; - mouse_pipe = usb_alloc_pipe(usbdev, epdesc); - if (!mouse_pipe) + if (add_pipe_node(&mouse_pipe_node, usbdev, epdesc)) return -1; dprintf(1, "USB mouse initialized\n"); @@ -325,16 +348,20 @@ usb_check_key(void) { if (! CONFIG_USB_KEYBOARD) return; - struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe); - if (!pipe) - return; - for (;;) { - u8 data[MAX_KBD_EVENT]; - int ret = usb_poll_intr(pipe, data); - if (ret) - break; - handle_key((void*)data); + for (struct pipe_node *node = GET_GLOBAL(keyboard_pipe_node); node; node = GET_GLOBALFLAT(node->next)) { + struct usb_pipe *pipe = GET_GLOBALFLAT(node->pipe); + + if (!pipe) + continue; + + for (;;) { + u8 data[MAX_KBD_EVENT]; + int ret = usb_poll_intr(pipe, data); + if (ret) + break; + handle_key((void*)data); + } } } @@ -344,7 +371,13 @@ usb_kbd_active(void) { if (! CONFIG_USB_KEYBOARD) return 0; - return GET_GLOBAL(keyboard_pipe) != NULL; + + for (struct pipe_node *node = GET_GLOBAL(keyboard_pipe_node); node; node = GET_GLOBALFLAT(node->next)) { + if (GET_GLOBALFLAT(node->pipe)) + return 1; + } + + return 0; } // Handle a ps2 style keyboard command. @@ -390,16 +423,20 @@ usb_check_mouse(void) { if (! CONFIG_USB_MOUSE) return; - struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe); - if (!pipe) - return; - for (;;) { - u8 data[MAX_MOUSE_EVENT]; - int ret = usb_poll_intr(pipe, data); - if (ret) - break; - handle_mouse((void*)data); + for (struct pipe_node *node = GET_GLOBAL(mouse_pipe_node); node; node = GET_GLOBALFLAT(node->next)) { + struct usb_pipe *pipe = GET_GLOBALFLAT(node->pipe); + + if (!pipe) + continue; + + for (;;) { + u8 data[MAX_MOUSE_EVENT]; + int ret = usb_poll_intr(pipe, data); + if (ret) + break; + handle_mouse((void*)data); + } } } @@ -409,7 +446,13 @@ usb_mouse_active(void) { if (! CONFIG_USB_MOUSE) return 0; - return GET_GLOBAL(mouse_pipe) != NULL; + + for (struct pipe_node *node = GET_GLOBAL(mouse_pipe_node); node; node = GET_GLOBALFLAT(node->next)) { + if (GET_GLOBALFLAT(node->pipe)) + return 1; + } + + return 0; } // Handle a ps2 style mouse command. -- 2.46.0 On Sun, Oct 27, 2024 at 8:53 AM Daniel Khodabakhsh <d.khodabak...@gmail.com> wrote: > > From 354935deae7cb79ee9a400222ed950314694194a Mon Sep 17 00:00:00 2001 > From: Daniel Khodabakhsh <d.khodabak...@gmail.com> > Date: Sat, 26 Oct 2024 04:18:49 -0700 > Subject: [PATCH] Support multiple USB HID devices by storing them in a linked > list. > > --- > src/hw/usb-hid.c | 108 +++++++++++++++++++++++++++++++++-------------- > 1 file changed, 77 insertions(+), 31 deletions(-) > > diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c > index dec198ac..b7d5533e 100644 > --- a/src/hw/usb-hid.c > +++ b/src/hw/usb-hid.c > @@ -1,20 +1,44 @@ > // Code for handling USB Human Interface Devices (HID). > // > // Copyright (C) 2009 Kevin O'Connor <ke...@koconnor.net> > +// Copyright (C) 2024 Daniel Khodabakhsh <d.khodabak...@gmail.com> > // > // This file may be distributed under the terms of the GNU LGPLv3 license. > > #include "biosvar.h" // GET_GLOBAL > #include "config.h" // CONFIG_* > -#include "output.h" // dprintf > +#include "output.h" // dprintf, warn_noalloc > +#include "malloc.h" // malloc_fseg > #include "ps2port.h" // ATKBD_CMD_GETID > +#include "stacks.h" // mutex_lock, mutex_unlock > #include "usb.h" // usb_ctrlrequest > #include "usb-hid.h" // usb_keyboard_setup > #include "util.h" // process_key > > -struct usb_pipe *keyboard_pipe VARFSEG; > -struct usb_pipe *mouse_pipe VARFSEG; > +struct pipe_node { > + struct usb_pipe *pipe; > + struct pipe_node *next; > +}; > + > +struct mutex_s usb_hid_lock; > + > +struct pipe_node *keyboard_pipe_node VARFSEG = NULL; > +struct pipe_node *mouse_pipe_node VARFSEG = NULL; > > +static struct pipe_node* > +add_pipe_node(struct pipe_node *old_root_node, struct usb_pipe *pipe) > +{ > + struct pipe_node *new_root_node = malloc_fseg(sizeof(struct pipe_node)); > + if (!new_root_node) { > + warn_noalloc(); > + return old_root_node; > + } > + > + new_root_node->pipe = pipe; > + new_root_node->next = old_root_node; > + > + return new_root_node; > +} > > /**************************************************************** > * Setup > @@ -64,9 +88,6 @@ usb_kbd_setup(struct usbdevice_s *usbdev > { > if (! CONFIG_USB_KEYBOARD) > return -1; > - if (keyboard_pipe) > - // XXX - this enables the first found keyboard (could be random) > - return -1; > > if (epdesc->wMaxPacketSize < sizeof(struct keyevent) > || epdesc->wMaxPacketSize > MAX_KBD_EVENT) { > @@ -87,10 +108,14 @@ usb_kbd_setup(struct usbdevice_s *usbdev > if (ret) > dprintf(3, "Warning: Failed to set key repeat rate\n"); > > - keyboard_pipe = usb_alloc_pipe(usbdev, epdesc); > + struct usb_pipe *keyboard_pipe = usb_alloc_pipe(usbdev, epdesc); > if (!keyboard_pipe) > return -1; > > + mutex_lock(&usb_hid_lock); > + keyboard_pipe_node = add_pipe_node(keyboard_pipe_node, keyboard_pipe); > + mutex_unlock(&usb_hid_lock); > + > dprintf(1, "USB keyboard initialized\n"); > return 0; > } > @@ -109,9 +134,6 @@ usb_mouse_setup(struct usbdevice_s *usbdev > { > if (! CONFIG_USB_MOUSE) > return -1; > - if (mouse_pipe) > - // XXX - this enables the first found mouse (could be random) > - return -1; > > if (epdesc->wMaxPacketSize < sizeof(struct mouseevent) > || epdesc->wMaxPacketSize > MAX_MOUSE_EVENT) { > @@ -125,10 +147,14 @@ usb_mouse_setup(struct usbdevice_s *usbdev > if (ret) > return -1; > > - mouse_pipe = usb_alloc_pipe(usbdev, epdesc); > + struct usb_pipe *mouse_pipe = usb_alloc_pipe(usbdev, epdesc); > if (!mouse_pipe) > return -1; > > + mutex_lock(&usb_hid_lock); > + mouse_pipe_node = add_pipe_node(mouse_pipe_node, mouse_pipe); > + mutex_unlock(&usb_hid_lock); > + > dprintf(1, "USB mouse initialized\n"); > return 0; > } > @@ -325,16 +351,20 @@ usb_check_key(void) > { > if (! CONFIG_USB_KEYBOARD) > return; > - struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe); > - if (!pipe) > - return; > > - for (;;) { > - u8 data[MAX_KBD_EVENT]; > - int ret = usb_poll_intr(pipe, data); > - if (ret) > - break; > - handle_key((void*)data); > + for (struct pipe_node *node = GET_GLOBAL(keyboard_pipe_node); > node; node = GET_GLOBALFLAT(node->next)) { > + struct usb_pipe *pipe = GET_GLOBALFLAT(node->pipe); > + > + if (!pipe) > + continue; > + > + for (;;) { > + u8 data[MAX_KBD_EVENT]; > + int ret = usb_poll_intr(pipe, data); > + if (ret) > + break; > + handle_key((void*)data); > + } > } > } > > @@ -344,7 +374,13 @@ usb_kbd_active(void) > { > if (! CONFIG_USB_KEYBOARD) > return 0; > - return GET_GLOBAL(keyboard_pipe) != NULL; > + > + for (struct pipe_node *node = GET_GLOBAL(keyboard_pipe_node); > node; node = GET_GLOBALFLAT(node->next)) { > + if (GET_GLOBALFLAT(node->pipe)) > + return 1; > + } > + > + return 0; > } > > // Handle a ps2 style keyboard command. > @@ -390,16 +426,20 @@ usb_check_mouse(void) > { > if (! CONFIG_USB_MOUSE) > return; > - struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe); > - if (!pipe) > - return; > > - for (;;) { > - u8 data[MAX_MOUSE_EVENT]; > - int ret = usb_poll_intr(pipe, data); > - if (ret) > - break; > - handle_mouse((void*)data); > + for (struct pipe_node *node = GET_GLOBAL(mouse_pipe_node); node; > node = GET_GLOBALFLAT(node->next)) { > + struct usb_pipe *pipe = GET_GLOBALFLAT(node->pipe); > + > + if (!pipe) > + continue; > + > + for (;;) { > + u8 data[MAX_MOUSE_EVENT]; > + int ret = usb_poll_intr(pipe, data); > + if (ret) > + break; > + handle_mouse((void*)data); > + } > } > } > > @@ -409,7 +449,13 @@ usb_mouse_active(void) > { > if (! CONFIG_USB_MOUSE) > return 0; > - return GET_GLOBAL(mouse_pipe) != NULL; > + > + for (struct pipe_node *node = GET_GLOBAL(mouse_pipe_node); node; > node = GET_GLOBALFLAT(node->next)) { > + if (GET_GLOBALFLAT(node->pipe)) > + return 1; > + } > + > + return 0; > } > > // Handle a ps2 style mouse command. > -- > 2.46.0 > > > On Sun, Oct 27, 2024 at 1:46 AM Daniel Khodabakhsh > <d.khodabak...@gmail.com> wrote: > > > > This change allows the use of multiple USB HID keyboards and mice. > > It's similar to the change by Stef van Os from this thread: > > > > https://mail.coreboot.org/hyperkitty/list/seabios@seabios.org/thread/O6Y4LUKPFZLNBBJUGKB6MUHG4LPCP3KB/ > > > > however this new change uses the linked list approach instead of a fixed > > array. > > > > Tested on QEMU and an Asus KGPE-D16 with 2 keyboards and one mice
0001-Support-multiple-USB-HID-devices.patch
Description: Binary data
_______________________________________________ SeaBIOS mailing list -- seabios@seabios.org To unsubscribe send an email to seabios-le...@seabios.org