[SeaBIOS] [PATCH] Support multiple USB HID keyboards/mice

Daniel Khodabakhsh posted 1 patch 2 weeks ago
src/hw/usb-hid.c | 108 +++++++++++++++++++++++++++++++++--------------
1 file changed, 77 insertions(+), 31 deletions(-)
[SeaBIOS] [PATCH] Support multiple USB HID keyboards/mice
Posted by Daniel Khodabakhsh 2 weeks ago
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
From 354935deae7cb79ee9a400222ed950314694194a Mon Sep 17 00:00:00 2001
From: Daniel Khodabakhsh <d.khodabakhsh@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 <kevin@koconnor.net>
+// Copyright (C) 2024  Daniel Khodabakhsh <d.khodabakhsh@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

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH] Support multiple USB HID keyboards/mice
Posted by Daniel Khodabakhsh 2 weeks ago
From 354935deae7cb79ee9a400222ed950314694194a Mon Sep 17 00:00:00 2001
From: Daniel Khodabakhsh <d.khodabakhsh@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 <kevin@koconnor.net>
+// Copyright (C) 2024  Daniel Khodabakhsh <d.khodabakhsh@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.khodabakhsh@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
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH] Support multiple USB HID keyboards/mice
Posted by Daniel Khodabakhsh 2 days, 20 hours ago
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.khodabakhsh@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 <kevin@koconnor.net>
+// Copyright (C) 2024  Daniel Khodabakhsh <d.khodabakhsh@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.khodabakhsh@gmail.com> wrote:
>
> From 354935deae7cb79ee9a400222ed950314694194a Mon Sep 17 00:00:00 2001
> From: Daniel Khodabakhsh <d.khodabakhsh@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 <kevin@koconnor.net>
> +// Copyright (C) 2024  Daniel Khodabakhsh <d.khodabakhsh@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.khodabakhsh@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
From f6a653b0fcac0359d598c342ed0a51b05d6ebe16 Mon Sep 17 00:00:00 2001
From: Daniel Khodabakhsh <d.khodabakhsh@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 <kevin@koconnor.net>
+// Copyright (C) 2024  Daniel Khodabakhsh <d.khodabakhsh@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

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org