Hi Gerd, Thanks for the reviews!
> > seabios has a linked list implementation (see src/list.h). > Please use that instead of rolling your own. > > Otherwise the patch looks sane on a quick glance. > Thanks for this suggestion as well. I tried it out but I'm having trouble getting it to work. My SeaBIOS hangs after the splash screen. I believe it's due to how the hlist_for_each_entry macro retrieves the node container via the inner macro call to container_of. Since the containers are in FSEG (so they can be used during runtime) I believe they need to be retrieved with GET_GLOBAL (like I do in the previous patches' for loops). I attached the hlist version as 0001-Use-hlists-to-track-USB-HID-devices.patch Is it necessary to use hlist? Linked lists are simple enough and I'm not using the double-linked list nature of hlist. I made a few more tweaks to the original linked list approach as 0001-Support-multiple-USB-HID-devices-3.patch Cheers, - Daniel K.
From 4d647e6a33638e0e889607d01de24df39ded59fd Mon Sep 17 00:00:00 2001 From: Daniel Khodabakhsh <d.khodabak...@gmail.com> Date: Wed, 13 Nov 2024 01:54:06 -0800 Subject: [PATCH] Use hlists to track USB HID devices. --- src/hw/usb-hid.c | 123 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 39 deletions(-) diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c index dec198ac..b1432888 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 "list.h" // hlist_* +#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 hlist_node node; +}; + +static struct mutex_s usb_hid_lock; + +struct hlist_head keyboards VARFSEG = { .first = NULL }; +struct hlist_head mice VARFSEG = { .first = NULL }; + +static int +add_pipe_node(struct hlist_head *list + , 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_pipe_node = malloc_fseg(sizeof(struct pipe_node)); + if (!new_pipe_node) { + warn_noalloc(); + return -1; + } + + new_pipe_node->pipe = pipe; + mutex_lock(&usb_hid_lock); + hlist_add_head(&new_pipe_node->node, list); + 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(&keyboards, 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(&mice, usbdev, epdesc)) return -1; dprintf(1, "USB mouse initialized\n"); @@ -325,16 +348,22 @@ 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); + struct pipe_node *keyboard; + struct hlist_head keyboards_global = GET_GLOBAL(keyboards); + hlist_for_each_entry(keyboard, &keyboards_global, node) { + struct usb_pipe *pipe = GET_GLOBALFLAT(keyboard->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 +373,12 @@ usb_kbd_active(void) { if (! CONFIG_USB_KEYBOARD) return 0; - return GET_GLOBAL(keyboard_pipe) != NULL; + + struct hlist_head keyboards_global = GET_GLOBAL(keyboards); + if (!hlist_empty(&keyboards_global)) + return 1; + + return 0; } // Handle a ps2 style keyboard command. @@ -390,16 +424,22 @@ 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); + struct pipe_node *mouse; + struct hlist_head mouse_global = GET_GLOBAL(mice); + hlist_for_each_entry(mouse, &mouse_global, node) { + struct usb_pipe *pipe = GET_GLOBALFLAT(mouse->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,12 @@ usb_mouse_active(void) { if (! CONFIG_USB_MOUSE) return 0; - return GET_GLOBAL(mouse_pipe) != NULL; + + struct hlist_head mouse_global = GET_GLOBAL(mice); + if (!hlist_empty(&mouse_global)) + return 1; + + return 0; } // Handle a ps2 style mouse command. -- 2.46.0
From 699c68f45e8a51173d2b1eaea0407d742edc1e8f 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 | 111 ++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 39 deletions(-) diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c index dec198ac..3bcee51d 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 *keyboards VARFSEG = NULL; +struct pipe_node *mice VARFSEG = NULL; + +static int +add_pipe_node(struct pipe_node **list + , 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_node = malloc_fseg(sizeof(struct pipe_node)); + if (!new_node) { + warn_noalloc(); + return -1; + } + + new_node->pipe = pipe; + + mutex_lock(&usb_hid_lock); + new_node->next = *list; + *list = new_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(&keyboards, 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(&mice, 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(keyboards); 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,8 @@ usb_kbd_active(void) { if (! CONFIG_USB_KEYBOARD) return 0; - return GET_GLOBAL(keyboard_pipe) != NULL; + + return GET_GLOBAL(keyboards) != NULL; } // Handle a ps2 style keyboard command. @@ -390,16 +418,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(mice); 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 +441,8 @@ usb_mouse_active(void) { if (! CONFIG_USB_MOUSE) return 0; - return GET_GLOBAL(mouse_pipe) != NULL; + + return GET_GLOBAL(mice) != NULL; } // Handle a ps2 style mouse command. -- 2.46.0
_______________________________________________ SeaBIOS mailing list -- seabios@seabios.org To unsubscribe send an email to seabios-le...@seabios.org