From 0d99451f5e5374ef741093e371fd405ed981b40d Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 6 Nov 2024 14:36:35 +0100 Subject: [PATCH 01/25] usb: move phy to union with pci_dev in hcd_info_t JIRA: RTOS-937 --- usb/hcd.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/usb/hcd.h b/usb/hcd.h index a9d6aec..c64e9e2 100644 --- a/usb/hcd.h +++ b/usb/hcd.h @@ -23,9 +23,19 @@ typedef struct { char type[HCD_TYPE_LEN]; uintptr_t hcdaddr; - uintptr_t phyaddr; int irq; - int clk; + union { + struct { + uintptr_t addr; + int clk; + } phy; + + struct { + unsigned char bus; + unsigned char dev; + unsigned char func; + } pci_devId; + }; } hcd_info_t; typedef struct hcd_ops { From e8d3500cd113a05a76d3d969945b2953ae7fd945 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 18 Oct 2024 09:41:52 +0200 Subject: [PATCH 02/25] usb: fix urbSync transfers The reply data was not copied by the responder to the buffer address provided by the sender. JIRA: RTOS-937 --- usb/drv.c | 1 + usb/usb.c | 10 +++++----- usb/usbhost.h | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/usb/drv.c b/usb/drv.c index d2b9eab..0acd184 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -561,6 +561,7 @@ static int _usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) t->port = drv->port; t->pipeid = urb->pipe; + t->msg = *msg; /* For async urbs only allocate resources. The transfer would be executed, * upon receiving usb_submit_t msg later */ diff --git a/usb/usb.c b/usb/usb.c index 0d84a2e..faeeb2f 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -213,14 +214,13 @@ static void usb_urbAsyncCompleted(usb_transfer_t *t) static void usb_urbSyncCompleted(usb_transfer_t *t) { - msg_t msg = { 0 }; + msg_t msg = t->msg; - msg.type = mtDevCtl; - msg.pid = t->pid; msg.o.err = (t->error != 0) ? -t->error : t->transferred; - if (t->direction == usb_dir_in) - msg.o.data = t->buffer; + if ((t->direction == usb_dir_in) && (t->error == 0)) { + memcpy(msg.o.data, t->buffer, min(msg.o.size, t->transferred)); + } /* TODO: it should be non-blocking */ msgRespond(usb_common.port, &msg, t->rid); diff --git a/usb/usbhost.h b/usb/usbhost.h index e4569b4..08269ea 100644 --- a/usb/usbhost.h +++ b/usb/usbhost.h @@ -64,6 +64,7 @@ typedef struct usb_transfer { unsigned long rid; unsigned int port; pid_t pid; + msg_t msg; struct _usb_dev *hub; From 1992a84eed64c4c450cb9728475399cc6a734576 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 6 Nov 2024 15:31:57 +0100 Subject: [PATCH 03/25] libusb: lookup `devfs` in addition to `/dev` when connecting This allows usb to be loaded from syspage (e.g. so that umass can be used for rootfs mounting) JIRA: RTOS-937 --- libusb/driver.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/libusb/driver.c b/libusb/driver.c index fe92268..02fdaaf 100644 --- a/libusb/driver.c +++ b/libusb/driver.c @@ -23,14 +23,33 @@ static struct { } usbdrv_common; +static void usb_hostLookup(oid_t *oid) +{ + int ret; + + for (;;) { + ret = lookup("devfs/usb", NULL, oid); + if (ret >= 0) { + break; + } + + ret = lookup("/dev/usb", NULL, oid); + if (ret >= 0) { + break; + } + + usleep(1000000); + } +} + + int usb_connect(const usb_device_id_t *filters, int nfilters, unsigned drvport) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; oid_t oid; - while (lookup("/dev/usb", NULL, &oid) < 0) - usleep(1000000); + usb_hostLookup(&oid); msg.type = mtDevCtl; msg.i.size = sizeof(*filters) * nfilters; From 6241f9569c60d7458be0dd13363787b1aa5abec7 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 3 Jan 2025 11:59:25 +0100 Subject: [PATCH 04/25] drv: fix drvBind to fail if no driver is matched drvBind always succeeded even when no driver has been found for a device JIRA: RTOS-937 --- usb/drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/usb/drv.c b/usb/drv.c index 0acd184..f46b77f 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -368,11 +368,14 @@ int usb_drvBind(usb_dev_t *dev) dev->ifs[i].driver = drv; umsg->insertion.interface = i; msgSend(drv->port, &msg); + if (msg.o.err == 0) { + return 0; + } } /* TODO: Make a device orphaned */ } - return 0; + return -1; } From 0791bfa25af983ed32adfae1ea1992adb98203ae Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 3 Jan 2025 12:03:00 +0100 Subject: [PATCH 05/25] drv: wait for any drivers to be added before trying to match iface drvBind races with drvAdd. This change ensures that devices won't be orphaned if added by hcd before adding the corresponding driver in the single-driver scenario. This does not fix the race in case of multi-driver scenario, though, hence the "orphaned" todo is left untouched JIRA: RTOS-937 --- usb/drv.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/usb/drv.c b/usb/drv.c index f46b77f..d30be01 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -29,6 +29,7 @@ struct { handle_t lock; usb_drv_t *drvs; + handle_t drvAddedCond; } usbdrv_common; @@ -251,11 +252,10 @@ static usb_drv_t *usb_drvMatchIface(usb_dev_t *dev, usb_iface_t *iface) int i, match, bestmatch = 0; mutexLock(usbdrv_common.lock); - drv = usbdrv_common.drvs; - if (drv == NULL) { - mutexUnlock(usbdrv_common.lock); - return NULL; + while (usbdrv_common.drvs == NULL) { + condWait(usbdrv_common.drvAddedCond, usbdrv_common.lock, 0); } + drv = usbdrv_common.drvs; do { for (i = 0; i < drv->nfilters; i++) { @@ -363,6 +363,9 @@ int usb_drvBind(usb_dev_t *dev) umsg->insertion.descriptor = dev->desc; umsg->insertion.locationID = dev->locationID; + /* FIXME: drvAdd races with drvMatchIface in multi-driver scenario. + * Devices may become orphaned forever if they get added by hcd before the driver + * is connected */ for (i = 0; i < dev->nifs; i++) { if ((drv = usb_drvMatchIface(dev, &dev->ifs[i])) != NULL) { dev->ifs[i].driver = drv; @@ -417,6 +420,7 @@ void usb_drvAdd(usb_drv_t *drv) idtree_init(&drv->pipes); idtree_init(&drv->urbs); LIST_ADD(&usbdrv_common.drvs, drv); + condSignal(usbdrv_common.drvAddedCond); mutexUnlock(usbdrv_common.lock); } @@ -617,10 +621,20 @@ void usb_drvPipeFree(usb_drv_t *drv, usb_pipe_t *pipe) int usb_drvInit(void) { - if (mutexCreate(&usbdrv_common.lock) != 0) { + int ret; + + ret = mutexCreate(&usbdrv_common.lock); + if (ret != 0) { USB_LOG("usbdrv: Can't create mutex!\n"); return -ENOMEM; } + ret = condCreate(&usbdrv_common.drvAddedCond); + if (ret != 0) { + USB_LOG("usbdrv: Can't create cond!\n"); + resourceDestroy(usbdrv_common.lock); + return -ENOMEM; + } + return 0; } From 0602c75a9be9663086a929520fde7554d6c51c13 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 10 Jan 2025 10:30:18 +0100 Subject: [PATCH 06/25] usb: add port change detect workaround for L2 TTs JIRA: RTOS-937 --- usb/dev.c | 10 +++--- usb/dev.h | 5 ++- usb/hub.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++-------- usb/hub.h | 5 +++ 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/usb/dev.c b/usb/dev.c index 01b0476..d963e6b 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -210,7 +210,6 @@ static int usb_getConfiguration(usb_dev_t *dev) /* Get first nine bytes to get to know configuration len */ if (usb_getDescriptor(dev, USB_DESC_CONFIG, 0, (char *)&pre, sizeof(pre)) < 0) { - USB_LOG("usb: Fail to get configuration descriptor\n"); return -1; } @@ -224,7 +223,6 @@ static int usb_getConfiguration(usb_dev_t *dev) /* TODO: Handle multiple configuration devices */ if (usb_getDescriptor(dev, USB_DESC_CONFIG, 0, (char *)conf, pre.wTotalLength) < 0) { - USB_LOG("usb: Fail to get configuration descriptor\n"); free(conf); return -1; } @@ -420,7 +418,7 @@ static int usb_getAllStringDescs(usb_dev_t *dev) int usb_devEnumerate(usb_dev_t *dev) { - int addr; + int addr, ret; if (usb_genLocationID(dev) < 0) { USB_LOG("usb: Fail to generate location ID\n"); @@ -525,9 +523,11 @@ usb_dev_t *usb_devFind(usb_dev_t *hub, int locationID) } -void usb_devDisconnected(usb_dev_t *dev) +void usb_devDisconnected(usb_dev_t *dev, bool silent) { - printf("usb: Device disconnected addr %d locationID: %08x\n", dev->address, dev->locationID); + if (!silent) { + printf("usb: Device disconnected addr %d locationID: %08x\n", dev->address, dev->locationID); + } usb_devSetChild(dev->hub, dev->port, NULL); usb_devUnbind(dev); usb_devDestroy(dev); diff --git a/usb/dev.h b/usb/dev.h index 901f2d5..b74a6a1 100644 --- a/usb/dev.h +++ b/usb/dev.h @@ -16,6 +16,7 @@ #define _USB_DEV_H_ #include +#include #include "usbhost.h" @@ -33,6 +34,8 @@ typedef struct { typedef struct _usb_dev { + struct _usb_dev *next, *prev; + enum usb_speed speed; usb_device_desc_t desc; usb_configuration_desc_t *conf; @@ -71,7 +74,7 @@ usb_dev_t *usb_devAlloc(void); int usb_devEnumerate(usb_dev_t *dev); -void usb_devDisconnected(usb_dev_t *dev); +void usb_devDisconnected(usb_dev_t *dev, bool silent); int usb_devInit(void); diff --git a/usb/hub.c b/usb/hub.c index eb6d8df..a9b856f 100644 --- a/usb/hub.c +++ b/usb/hub.c @@ -37,6 +37,7 @@ #define HUB_DEBOUNCE_STABLE 100000 #define HUB_DEBOUNCE_PERIOD 25000 #define HUB_DEBOUNCE_TIMEOUT 1500000 +#define HUB_TT_POLL_DELAY_MS 1000000 typedef struct _hub_event { @@ -50,6 +51,7 @@ struct { handle_t lock; handle_t cond; hub_event_t *events; + usb_dev_t *tts; } hub_common; @@ -170,7 +172,14 @@ static int hub_interruptInit(usb_dev_t *hub) } -static int hub_poll(usb_dev_t *hub) +static int hub_isTT(usb_dev_t *dev) +{ + /* TODO support MTTs */ + return dev->desc.bDeviceClass == USB_CLASS_HUB && dev->desc.bDeviceProtocol == USB_HUB_PROTO_SINGLE_TT; +} + + +static int hub_requestStatus(usb_dev_t *hub) { return usb_transferSubmit(hub->statusTransfer, hub->irqPipe, NULL); } @@ -248,6 +257,31 @@ static int hub_portDebounce(usb_dev_t *hub, int port) } +static void hub_ttAdd(usb_dev_t *hub) +{ + mutexLock(hub_common.lock); + LIST_ADD(&hub_common.tts, hub); + mutexUnlock(hub_common.lock); +} + + +static void hub_ttRemove(usb_dev_t *hub) +{ + mutexLock(hub_common.lock); + LIST_REMOVE(&hub_common.tts, hub); + mutexUnlock(hub_common.lock); +} + + +static void hub_devDisconnect(usb_dev_t *dev, bool silent) +{ + usb_devDisconnected(dev, silent); + if (hub_isTT(dev)) { + hub_ttRemove(dev); + } +} + + static void hub_devConnected(usb_dev_t *hub, int port) { usb_dev_t *dev; @@ -284,7 +318,6 @@ static void hub_devConnected(usb_dev_t *hub, int port) break; } else if (ret != 0) { - printf("usb: Enumeration failed retries left: %d\n", retries); dev->hcd->ops->pipeDestroy(dev->hcd, dev->ctrlPipe); if (dev->address != 0) hcd_addrFree(hub->hcd, dev->address); @@ -293,8 +326,10 @@ static void hub_devConnected(usb_dev_t *hub, int port) } } while (ret != 0 && retries > 0); - if (ret != 0) - usb_devDisconnected(dev); + if (ret != 0) { + printf("usb: Enumeration failed despite %d attempts\n", HUB_ENUM_RETRIES); + hub_devDisconnect(dev, true); + } } @@ -302,14 +337,18 @@ static void hub_connectstatus(usb_dev_t *hub, int port, usb_port_status_t *statu { int pstatus; - if (hub->devs[port - 1] != NULL) - usb_devDisconnected(hub->devs[port - 1]); + if (hub->devs[port - 1] != NULL) { + hub_devDisconnect(hub->devs[port - 1], false); + } - if ((pstatus = hub_portDebounce(hub, port)) < 0) + pstatus = hub_portDebounce(hub, port); + if (pstatus < 0) { return; + } - if (pstatus) + if (pstatus) { hub_devConnected(hub, port); + } } @@ -348,13 +387,31 @@ static uint32_t hub_getStatus(usb_dev_t *hub) if (hub->statusTransfer->error == 0 && hub->statusTransfer->transferred > 0) memcpy(&status, hub->statusTransfer->buffer, sizeof(status)); - hub_poll(hub); + hub_requestStatus(hub); } return status; } +static void hub_ttStatus(void) +{ + usb_dev_t *hub; + int i; + + hub = hub_common.tts; + if (hub == NULL) { + return; + } + + do { + for (i = 0; i < hub->nports; i++) { + hub_portstatus(hub, i + 1); + } + } while ((hub = hub->next) != hub_common.tts); +} + + static void hub_thread(void *args) { hub_event_t *ev; @@ -363,8 +420,10 @@ static void hub_thread(void *args) for (;;) { mutexLock(hub_common.lock); - while (hub_common.events == NULL) - condWait(hub_common.cond, hub_common.lock, 0); + while (hub_common.events == NULL) { + condWait(hub_common.cond, hub_common.lock, HUB_TT_POLL_DELAY_MS); + hub_ttStatus(); + } ev = hub_common.events; LIST_REMOVE(&hub_common.events, ev); mutexUnlock(hub_common.lock); @@ -431,7 +490,16 @@ int hub_conf(usb_dev_t *hub) if (hub_interruptInit(hub) != 0) return -EINVAL; - return hub_poll(hub); + if (hub_isTT(hub)) { + // FIXME Interrupt pipe notifications from tier 2 TTs never come, which is + // either a quirk in currently tested hw or an issue in the hcd driver + + // In addition to request an interrupt request, actively poll the status as well + // for as a workaround + hub_ttAdd(hub); + } + + return hub_requestStatus(hub); } diff --git a/usb/hub.h b/usb/hub.h index 05143bf..fffc3b4 100644 --- a/usb/hub.h +++ b/usb/hub.h @@ -53,6 +53,11 @@ #define USB_HUB_MAX_PORTS 15 +/* hub-specific protocol codes */ +#define USB_HUB_PROTO_ROOT 0x0 +#define USB_HUB_PROTO_SINGLE_TT 0x1 + + typedef struct usb_port_status { uint16_t wPortStatus; uint16_t wPortChange; From 77aab0926c0c78d96d241bdc2ca38eba5293733c Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 3 Jan 2025 10:54:19 +0100 Subject: [PATCH 07/25] dev: deduce product name from class if string descriptors are unavailable JIRA: RTOS-937 --- libusb/usb.h | 1 + usb/dev.c | 94 +++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/libusb/usb.h b/libusb/usb.h index b6f290a..38bb6be 100644 --- a/libusb/usb.h +++ b/libusb/usb.h @@ -59,6 +59,7 @@ #define CLASS_REQ_SET_CONTROL_LINE_STATE 0x22 /* class codes */ +#define USB_CLASS_HID 0x3 #define USB_CLASS_MASS_STORAGE 0x8 #define USB_CLASS_HUB 0x9 diff --git a/usb/dev.c b/usb/dev.c index d963e6b..25e5766 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -372,14 +372,75 @@ static int usb_getStringDesc(usb_dev_t *dev, char **buf, int index) } +#define USB_STRING_MAX_LEN 255 + + +static void usb_fallbackProductString(usb_dev_t *dev) +{ + char product[USB_STRING_MAX_LEN] = { 0 }; + + switch (dev->desc.bDeviceClass) { + case USB_CLASS_HID: + strcpy(product, "USB HID"); + break; + case USB_CLASS_HUB: + switch (dev->desc.bDeviceProtocol) { + case USB_HUB_PROTO_ROOT: + strcpy(product, "USB Root Hub"); + break; + case USB_HUB_PROTO_SINGLE_TT: + strcpy(product, "USB Single TT Hub"); + break; + default: + strcpy(product, "USB Hub"); + break; + } + break; + case USB_CLASS_MASS_STORAGE: + strcpy(product, "USB Mass Storage"); + break; + default: + strcpy(product, "Unknown USB Device"); + break; + } + + dev->product = calloc(sizeof(char), strnlen(product, USB_STRING_MAX_LEN) + 1); + strcpy(dev->product, product); +} + + +static void usb_fallbackManufacturerString(usb_dev_t *dev) +{ + char manufacturer[] = "Generic"; + + dev->manufacturer = calloc(sizeof(char), strnlen(manufacturer, USB_STRING_MAX_LEN) + 1); + strcpy(dev->manufacturer, manufacturer); +} + + +static void usb_fallbackSerialNumberString(usb_dev_t *dev) +{ + char serialNumber[] = "Unknown"; + + dev->serialNumber = calloc(sizeof(char), strnlen(serialNumber, USB_STRING_MAX_LEN) + 1); + strcpy(dev->serialNumber, serialNumber); +} + + static int usb_getAllStringDescs(usb_dev_t *dev) { usb_string_desc_t desc = { 0 }; - int i; + int i, ret; + /* Get an array of language ids */ + /* String descriptors are optional. If a device omits all string descriptors, + * it must not return this array, so the following call is allowed to fail in + * that case */ if (usb_getDescriptor(dev, USB_DESC_STRING, 0, (char *)&desc, sizeof(desc)) < 0) { - USB_LOG("usb: Fail to get configuration descriptor\n"); - return -1; + usb_fallbackManufacturerString(dev); + usb_fallbackProductString(dev); + usb_fallbackSerialNumberString(dev); + return -ENOTSUP; } if (desc.bLength < 4) @@ -389,18 +450,24 @@ static int usb_getAllStringDescs(usb_dev_t *dev) dev->langId = desc.wData[0] | ((uint16_t)desc.wData[1] << 8); if (dev->desc.iManufacturer != 0) { - if (usb_getStringDesc(dev, &dev->manufacturer, dev->desc.iManufacturer) != 0) - return -ENOMEM; + ret = usb_getStringDesc(dev, &dev->manufacturer, dev->desc.iManufacturer); + } + if (dev->desc.iManufacturer == 0 || ret != 0) { + usb_fallbackManufacturerString(dev); } if (dev->desc.iProduct != 0) { - if (usb_getStringDesc(dev, &dev->product, dev->desc.iProduct) != 0) - return -ENOMEM; + ret = usb_getStringDesc(dev, &dev->product, dev->desc.iProduct); + } + if (dev->desc.iProduct == 0 || ret != 0) { + usb_fallbackProductString(dev); } if (dev->desc.iSerialNumber != 0) { - if (usb_getStringDesc(dev, &dev->serialNumber, dev->desc.iSerialNumber) != 0) - return -ENOMEM; + ret = usb_getStringDesc(dev, &dev->serialNumber, dev->desc.iSerialNumber); + } + if (dev->desc.iSerialNumber == 0 || ret != 0) { + usb_fallbackSerialNumberString(dev); } for (i = 0; i < dev->nifs; i++) { @@ -418,7 +485,7 @@ static int usb_getAllStringDescs(usb_dev_t *dev) int usb_devEnumerate(usb_dev_t *dev) { - int addr, ret; + int addr; if (usb_genLocationID(dev) < 0) { USB_LOG("usb: Fail to generate location ID\n"); @@ -453,16 +520,13 @@ int usb_devEnumerate(usb_dev_t *dev) return -1; } - if (usb_getAllStringDescs(dev) < 0) { - USB_LOG("usb: Fail to get string descriptors\n"); - return -1; - } + (void)usb_getAllStringDescs(dev); if (!usb_isRoothub(dev)) usb_devSetChild(dev->hub, dev->port, dev); USB_LOG("usb: New device addr: %d locationID: %08x %s, %s\n", dev->address, dev->locationID, - dev->manufacturer, dev->product); + dev->manufacturer, dev->product); if (dev->desc.bDeviceClass == USB_CLASS_HUB) { if (hub_conf(dev) != 0) From 76cc2f7e09518abc623b0aa94c989b06c4fdbe8f Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 27 Mar 2025 16:10:59 +0100 Subject: [PATCH 08/25] hcd: use uint32_t for base/phybase instead of int JIRA: RTOS-937 --- usb/hcd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usb/hcd.h b/usb/hcd.h index c64e9e2..da48e2b 100644 --- a/usb/hcd.h +++ b/usb/hcd.h @@ -58,7 +58,7 @@ typedef struct hcd { uint32_t addrmask[4]; usb_transfer_t *transfers; handle_t transLock; - volatile int *base, *phybase; + volatile uint32_t *base, *phybase; void *priv; } hcd_t; From 743b0bc7683952d794fff211f2601859b64bf8ee Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 6 Nov 2024 18:41:23 +0100 Subject: [PATCH 09/25] libusb/driver: add generic insertion/deletion/completion handling Every driver talking to usb host implements some sort of this handling loop, so it's better to move it to libusb to eliminate redundancy. This is also a first step in making the driver logic expressible via handler functions API only JIRA: RTOS-970 --- libusb/driver.c | 88 ++++++++++++++++++++++++++++++++++++++++------ libusb/usbdriver.h | 18 +++++++++- 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/libusb/driver.c b/libusb/driver.c index 02fdaaf..bcb970b 100644 --- a/libusb/driver.c +++ b/libusb/driver.c @@ -14,12 +14,27 @@ #include #include #include +#include +#include #include +#include #include +#ifndef USB_N_UMSG_THREADS +#define USB_N_UMSG_THREADS 2 +#endif + +#ifndef USB_UMSG_PRIO +#define USB_UMSG_PRIO 3 +#endif + + static struct { - unsigned port; + char ustack[USB_N_UMSG_THREADS - 1][2048] __attribute__((aligned(8))); + const usb_handlers_t *handlers; + unsigned srvport; + unsigned drvport; } usbdrv_common; @@ -43,11 +58,43 @@ static void usb_hostLookup(oid_t *oid) } -int usb_connect(const usb_device_id_t *filters, int nfilters, unsigned drvport) +static void usb_thread(void *arg) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; + int ret; + + for (;;) { + ret = usb_eventsWait(usbdrv_common.drvport, &msg); + if (ret < 0) { + /* TODO should the thread abort the loop on error? */ + continue; + } + + switch (umsg->type) { + case usb_msg_insertion: + usbdrv_common.handlers->insertion(&umsg->insertion); + break; + case usb_msg_deletion: + usbdrv_common.handlers->deletion(&umsg->deletion); + break; + case usb_msg_connect: + usbdrv_common.handlers->completion(&umsg->completion, msg.i.data, msg.i.size); + break; + default: + fprintf(stderr, "usbdrv: Error when receiving event from host\n"); + break; + } + } +} + + +int usb_driverRun(const usb_handlers_t *handlers, const usb_device_id_t *filters, unsigned int nfilters) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; oid_t oid; + int ret, i; usb_hostLookup(&oid); @@ -56,15 +103,28 @@ int usb_connect(const usb_device_id_t *filters, int nfilters, unsigned drvport) msg.i.data = (void *)filters; umsg->type = usb_msg_connect; - umsg->connect.port = drvport; + umsg->connect.port = usbdrv_common.drvport; umsg->connect.nfilters = nfilters; - if (msgSend(oid.port, &msg) < 0) + if (msgSend(oid.port, &msg) < 0) { return -1; + } + + usbdrv_common.srvport = oid.port; + usbdrv_common.handlers = handlers; + + for (i = 0; i < USB_N_UMSG_THREADS - 1; i++) { + ret = beginthread(usb_thread, USB_UMSG_PRIO, usbdrv_common.ustack[i], sizeof(usbdrv_common.ustack[i]), NULL); + if (ret < 0) { + fprintf(stderr, "usbdrv: fail to beginthread ret: %d\n", ret); + return 1; + } + } - usbdrv_common.port = oid.port; + priority(USB_UMSG_PRIO); + usb_thread(NULL); - return oid.port; + return 0; } @@ -102,8 +162,10 @@ int usb_open(usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) umsg->open.dir = dir; umsg->open.locationID = dev->locationID; - if ((ret = msgSend(usbdrv_common.port, &msg)) != 0) + ret = msgSend(usbdrv_common.srvport, &msg); + if (ret != 0) { return ret; + } return msg.o.err; } @@ -129,7 +191,7 @@ static int usb_urbSubmitSync(usb_urb_t *urb, void *data) msg.o.size = urb->size; } - if ((ret = msgSend(usbdrv_common.port, &msg)) != 0) + if ((ret = msgSend(usbdrv_common.srvport, &msg)) != 0) return ret; return msg.o.err; @@ -209,8 +271,10 @@ int usb_urbAlloc(unsigned pipe, void *data, usb_dir_t dir, size_t size, int type msg.type = mtDevCtl; umsg->type = usb_msg_urb; - if ((ret = msgSend(usbdrv_common.port, &msg)) < 0) + ret = msgSend(usbdrv_common.srvport, &msg); + if (ret < 0) { return ret; + } /* URB id */ return msg.o.err; @@ -234,8 +298,10 @@ int usb_transferAsync(unsigned pipe, unsigned urbid, size_t size, usb_setup_pack } msg.type = mtDevCtl; umsg->type = usb_msg_urbcmd; - if ((ret = msgSend(usbdrv_common.port, &msg)) < 0) + ret = msgSend(usbdrv_common.srvport, &msg); + if (ret < 0) { return ret; + } return 0; } @@ -254,7 +320,7 @@ int usb_urbFree(unsigned pipe, unsigned urb) msg.type = mtDevCtl; umsg->type = usb_msg_urbcmd; - if ((ret = msgSend(usbdrv_common.port, &msg)) < 0) + if ((ret = msgSend(usbdrv_common.srvport, &msg)) < 0) return ret; return 0; diff --git a/libusb/usbdriver.h b/libusb/usbdriver.h index ba928ac..6d252ba 100644 --- a/libusb/usbdriver.h +++ b/libusb/usbdriver.h @@ -139,13 +139,29 @@ typedef struct { } usb_modeswitch_t; +typedef int (*usb_completion_handler_t)(usb_completion_t *completion, const char *data, size_t len); + + +typedef int (*usb_insertion_handler_t)(usb_devinfo_t *devinfo); + + +typedef int (*usb_deletion_handler_t)(usb_deletion_t *deletion); + + +typedef struct { + usb_insertion_handler_t insertion; + usb_deletion_handler_t deletion; + usb_completion_handler_t completion; +} usb_handlers_t; + + int usb_modeswitchHandle(usb_devinfo_t *dev, const usb_modeswitch_t *mode); const usb_modeswitch_t *usb_modeswitchFind(uint16_t vid, uint16_t pid, const usb_modeswitch_t *modes, int nmodes); -int usb_connect(const usb_device_id_t *filters, int nfilters, unsigned drvport); +int usb_driverRun(const usb_handlers_t *handlers, const usb_device_id_t *filters, unsigned int nfilters); int usb_eventsWait(int port, msg_t *msg); From f16b50080d34fa4ecbe79e0c24f0f0af816bdb24 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 7 Nov 2024 16:52:31 +0100 Subject: [PATCH 10/25] libusb/driver: add usb_driver_t struct and run drivers from it JIRA: RTOS-970 --- libusb/driver.c | 11 +++++++++-- libusb/usbdriver.h | 24 ++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libusb/driver.c b/libusb/driver.c index bcb970b..2d7ac9f 100644 --- a/libusb/driver.c +++ b/libusb/driver.c @@ -89,13 +89,20 @@ static void usb_thread(void *arg) } -int usb_driverRun(const usb_handlers_t *handlers, const usb_device_id_t *filters, unsigned int nfilters) +int usb_driverRun(usb_driver_t *driver) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; + const usb_device_id_t *filters = driver->filters; + unsigned int nfilters = driver->nfilters; oid_t oid; int ret, i; + ret = driver->ops->init(driver); + if (ret < 0) { + return 1; + } + usb_hostLookup(&oid); msg.type = mtDevCtl; @@ -111,7 +118,7 @@ int usb_driverRun(const usb_handlers_t *handlers, const usb_device_id_t *filters } usbdrv_common.srvport = oid.port; - usbdrv_common.handlers = handlers; + usbdrv_common.handlers = driver->handlers; for (i = 0; i < USB_N_UMSG_THREADS - 1; i++) { ret = beginthread(usb_thread, USB_UMSG_PRIO, usbdrv_common.ustack[i], sizeof(usbdrv_common.ustack[i]), NULL); diff --git a/libusb/usbdriver.h b/libusb/usbdriver.h index 6d252ba..f80b02c 100644 --- a/libusb/usbdriver.h +++ b/libusb/usbdriver.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -98,7 +99,8 @@ typedef struct { enum { urbcmd_submit, urbcmd_cancel, - urbcmd_free } cmd; + urbcmd_free + } cmd; } usb_urbcmd_t; @@ -155,13 +157,31 @@ typedef struct { } usb_handlers_t; +typedef struct usb_driver_t usb_driver_t; + + +typedef struct { + int (*init)(usb_driver_t *driver); + int (*destroy)(usb_driver_t *driver); +} usb_driverOps_t; + + +struct usb_driver_t { + const usb_handlers_t *handlers; + const usb_driverOps_t *ops; + const usb_device_id_t *filters; + unsigned int nfilters; + uintptr_t *priv; +}; + + int usb_modeswitchHandle(usb_devinfo_t *dev, const usb_modeswitch_t *mode); const usb_modeswitch_t *usb_modeswitchFind(uint16_t vid, uint16_t pid, const usb_modeswitch_t *modes, int nmodes); -int usb_driverRun(const usb_handlers_t *handlers, const usb_device_id_t *filters, unsigned int nfilters); +int usb_driverRun(usb_driver_t *driver); int usb_eventsWait(int port, msg_t *msg); From 2a4fe5c510489a4dc10a51e2b49fafe7ea66b76c Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 8 Nov 2024 11:02:20 +0100 Subject: [PATCH 11/25] libusb/driver: generalize pipeOps It is now possible to substitute driver-side pipe operations (e.g. the hostdriver can now provide its own implementations that does not use msg API and call the host functions directly) JIRA: RTOS-970 --- libusb/driver.c | 147 +++++++++++++++++++++++++++++++-------------- libusb/usbdriver.h | 48 +++++++++------ 2 files changed, 134 insertions(+), 61 deletions(-) diff --git a/libusb/driver.c b/libusb/driver.c index 2d7ac9f..a935ba3 100644 --- a/libusb/driver.c +++ b/libusb/driver.c @@ -3,8 +3,8 @@ * * libusb/driver.c * - * Copyright 2021 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -30,14 +30,40 @@ #endif +static usb_pipeOps_t usbprocdrv_pipeOps; + + static struct { char ustack[USB_N_UMSG_THREADS - 1][2048] __attribute__((aligned(8))); - const usb_handlers_t *handlers; unsigned srvport; unsigned drvport; } usbdrv_common; +int usb_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) +{ + return drv->pipeOps->open(drv, dev, type, dir); +} + + +int usb_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) +{ + return drv->pipeOps->urbAlloc(drv, pipe, data, dir, size, type); +} + + +int usb_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb) +{ + return drv->pipeOps->urbFree(drv, pipe, urb); +} + + +int usb_transferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) +{ + return drv->pipeOps->transferAsync(drv, pipe, urbid, size, setup); +} + + static void usb_hostLookup(oid_t *oid) { int ret; @@ -60,6 +86,7 @@ static void usb_hostLookup(oid_t *oid) static void usb_thread(void *arg) { + usb_driver_t *drv = (usb_driver_t *)arg; msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; int ret; @@ -73,13 +100,13 @@ static void usb_thread(void *arg) switch (umsg->type) { case usb_msg_insertion: - usbdrv_common.handlers->insertion(&umsg->insertion); + drv->handlers->insertion(drv, &umsg->insertion); break; case usb_msg_deletion: - usbdrv_common.handlers->deletion(&umsg->deletion); + drv->handlers->deletion(drv, &umsg->deletion); break; - case usb_msg_connect: - usbdrv_common.handlers->completion(&umsg->completion, msg.i.data, msg.i.size); + case usb_msg_completion: + drv->handlers->completion(drv, &umsg->completion, msg.i.data, msg.i.size); break; default: fprintf(stderr, "usbdrv: Error when receiving event from host\n"); @@ -89,21 +116,10 @@ static void usb_thread(void *arg) } -int usb_driverRun(usb_driver_t *driver) +static int usb_connect(const usb_device_id_t *filters, unsigned int nfilters) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; - const usb_device_id_t *filters = driver->filters; - unsigned int nfilters = driver->nfilters; - oid_t oid; - int ret, i; - - ret = driver->ops->init(driver); - if (ret < 0) { - return 1; - } - - usb_hostLookup(&oid); msg.type = mtDevCtl; msg.i.size = sizeof(*filters) * nfilters; @@ -113,15 +129,37 @@ int usb_driverRun(usb_driver_t *driver) umsg->connect.port = usbdrv_common.drvport; umsg->connect.nfilters = nfilters; - if (msgSend(oid.port, &msg) < 0) { - return -1; + return msgSend(usbdrv_common.srvport, &msg) < 0; +} + + +int usb_procDrvRun(usb_driver_t *drv) +{ + oid_t oid; + int ret, i; + + /* usb_procDrvRun is invoked iff drivers are in the proc variant */ + drv->pipeOps = &usbprocdrv_pipeOps; + + ret = drv->ops->init(drv); + if (ret < 0) { + return 1; } + usb_hostLookup(&oid); usbdrv_common.srvport = oid.port; - usbdrv_common.handlers = driver->handlers; + + if (portCreate(&usbdrv_common.drvport) != 0) { + return -1; + } + + ret = usb_connect(drv->filters, drv->nfilters); + if (ret < 0) { + return -1; + } for (i = 0; i < USB_N_UMSG_THREADS - 1; i++) { - ret = beginthread(usb_thread, USB_UMSG_PRIO, usbdrv_common.ustack[i], sizeof(usbdrv_common.ustack[i]), NULL); + ret = beginthread(usb_thread, USB_UMSG_PRIO, usbdrv_common.ustack[i], sizeof(usbdrv_common.ustack[i]), drv); if (ret < 0) { fprintf(stderr, "usbdrv: fail to beginthread ret: %d\n", ret); return 1; @@ -129,7 +167,7 @@ int usb_driverRun(usb_driver_t *driver) } priority(USB_UMSG_PRIO); - usb_thread(NULL); + usb_thread(drv); return 0; } @@ -153,7 +191,7 @@ int usb_eventsWait(int port, msg_t *msg) } -int usb_open(usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) +static int usbprocdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; @@ -178,7 +216,7 @@ int usb_open(usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) } -static int usb_urbSubmitSync(usb_urb_t *urb, void *data) +static int usbprocdrv_urbSubmitSync(usb_driver_t *drv, usb_urb_t *urb, void *data) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; @@ -205,7 +243,7 @@ static int usb_urbSubmitSync(usb_urb_t *urb, void *data) } -int usb_transferControl(unsigned pipe, usb_setup_packet_t *setup, void *data, size_t size, usb_dir_t dir) +int usb_transferControl(usb_driver_t *drv, unsigned pipe, usb_setup_packet_t *setup, void *data, size_t size, usb_dir_t dir) { usb_urb_t urb = { .pipe = pipe, @@ -216,11 +254,11 @@ int usb_transferControl(unsigned pipe, usb_setup_packet_t *setup, void *data, si .sync = 1 }; - return usb_urbSubmitSync(&urb, data); + return drv->pipeOps->submitSync(drv, &urb, data); } -int usb_transferBulk(unsigned pipe, void *data, size_t size, usb_dir_t dir) +int usb_transferBulk(usb_driver_t *drv, unsigned pipe, void *data, size_t size, usb_dir_t dir) { usb_urb_t urb = { .pipe = pipe, @@ -230,11 +268,11 @@ int usb_transferBulk(unsigned pipe, void *data, size_t size, usb_dir_t dir) .sync = 1 }; - return usb_urbSubmitSync(&urb, data); + return drv->pipeOps->submitSync(drv, &urb, data); } -int usb_setConfiguration(unsigned pipe, int conf) +int usb_setConfiguration(usb_driver_t *drv, unsigned pipe, int conf) { usb_setup_packet_t setup = (usb_setup_packet_t) { .bmRequestType = REQUEST_DIR_HOST2DEV | REQUEST_TYPE_STANDARD | REQUEST_RECIPIENT_DEVICE, @@ -244,11 +282,11 @@ int usb_setConfiguration(unsigned pipe, int conf) .wLength = 0, }; - return usb_transferControl(pipe, &setup, NULL, 0, usb_dir_out); + return usb_transferControl(drv, pipe, &setup, NULL, 0, usb_dir_out); } -int usb_clearFeatureHalt(unsigned pipe, int ep) +int usb_clearFeatureHalt(usb_driver_t *drv, unsigned pipe, int ep) { usb_setup_packet_t setup = (usb_setup_packet_t) { .bmRequestType = REQUEST_DIR_HOST2DEV | REQUEST_TYPE_STANDARD | REQUEST_RECIPIENT_DEVICE, @@ -258,11 +296,11 @@ int usb_clearFeatureHalt(unsigned pipe, int ep) .wLength = 0, }; - return usb_transferControl(pipe, &setup, NULL, 0, usb_dir_out); + return usb_transferControl(drv, pipe, &setup, NULL, 0, usb_dir_out); } -int usb_urbAlloc(unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) +static int usbprocdrv_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; @@ -288,7 +326,7 @@ int usb_urbAlloc(unsigned pipe, void *data, usb_dir_t dir, size_t size, int type } -int usb_transferAsync(unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) +static int usbprocdrv_transferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; @@ -314,7 +352,7 @@ int usb_transferAsync(unsigned pipe, unsigned urbid, size_t size, usb_setup_pack } -int usb_urbFree(unsigned pipe, unsigned urb) +static int usbprocdrv_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; @@ -416,26 +454,47 @@ void usb_dumpStringDesc(FILE *stream, usb_string_desc_t *descr) } -int usb_modeswitchHandle(usb_devinfo_t *dev, const usb_modeswitch_t *mode) +int usb_modeswitchHandle(usb_driver_t *drv, usb_devinfo_t *dev, const usb_modeswitch_t *mode) { char msg[sizeof(mode->msg)]; - int pipeCtrl, pipeIn, pipeOut; + int pipeCtrl, pipeIn, pipeOut, ret; - if ((pipeCtrl = usb_open(dev, usb_transfer_control, 0)) < 0) + pipeCtrl = usb_open(drv, dev, usb_transfer_control, 0); + if (pipeCtrl < 0) { return -EINVAL; + } - if (usb_setConfiguration(pipeCtrl, 1) != 0) + ret = usb_setConfiguration(drv, pipeCtrl, 1); + if (ret != 0) { return -EINVAL; + } - if ((pipeIn = usb_open(dev, usb_transfer_bulk, usb_dir_in)) < 0) + pipeIn = usb_open(drv, dev, usb_transfer_bulk, usb_dir_in); + if (pipeIn < 0) { return -EINVAL; + } - if ((pipeOut = usb_open(dev, usb_transfer_bulk, usb_dir_out)) < 0) + pipeOut = usb_open(drv, dev, usb_transfer_bulk, usb_dir_out); + if (pipeOut < 0) { return -EINVAL; + } memcpy(msg, mode->msg, sizeof(msg)); - if (usb_transferBulk(pipeOut, msg, sizeof(msg), usb_dir_out) < 0) + + ret = usb_transferBulk(drv, pipeOut, msg, sizeof(msg), usb_dir_out); + if (ret < 0) { return -EINVAL; + } return 0; } + + +static usb_pipeOps_t usbprocdrv_pipeOps = { + .open = usbprocdrv_open, + .submitSync = usbprocdrv_urbSubmitSync, + .transferAsync = usbprocdrv_transferAsync, + + .urbFree = usbprocdrv_urbFree, + .urbAlloc = usbprocdrv_urbAlloc, +}; diff --git a/libusb/usbdriver.h b/libusb/usbdriver.h index f80b02c..f79ebce 100644 --- a/libusb/usbdriver.h +++ b/libusb/usbdriver.h @@ -141,13 +141,16 @@ typedef struct { } usb_modeswitch_t; -typedef int (*usb_completion_handler_t)(usb_completion_t *completion, const char *data, size_t len); +typedef struct usb_driver usb_driver_t; -typedef int (*usb_insertion_handler_t)(usb_devinfo_t *devinfo); +typedef int (*usb_completion_handler_t)(usb_driver_t *drv, usb_completion_t *completion, const char *data, size_t len); -typedef int (*usb_deletion_handler_t)(usb_deletion_t *deletion); +typedef int (*usb_insertion_handler_t)(usb_driver_t *drv, usb_devinfo_t *devinfo); + + +typedef int (*usb_deletion_handler_t)(usb_driver_t *drv, usb_deletion_t *deletion); typedef struct { @@ -157,58 +160,69 @@ typedef struct { } usb_handlers_t; -typedef struct usb_driver_t usb_driver_t; - - typedef struct { int (*init)(usb_driver_t *driver); int (*destroy)(usb_driver_t *driver); } usb_driverOps_t; -struct usb_driver_t { +typedef struct { + int (*open)(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir); + + /* TODO rename to transferSync, submitAsync */ + int (*submitSync)(usb_driver_t *drv, usb_urb_t *urb, void *data); + int (*transferAsync)(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup); + + int (*urbFree)(usb_driver_t *drv, unsigned pipe, unsigned urb); + int (*urbAlloc)(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type); +} usb_pipeOps_t; + + +struct usb_driver { const usb_handlers_t *handlers; const usb_driverOps_t *ops; + const usb_pipeOps_t *pipeOps; const usb_device_id_t *filters; unsigned int nfilters; uintptr_t *priv; + uintptr_t *pipePriv; }; -int usb_modeswitchHandle(usb_devinfo_t *dev, const usb_modeswitch_t *mode); +int usb_modeswitchHandle(usb_driver_t *drv, usb_devinfo_t *dev, const usb_modeswitch_t *mode); const usb_modeswitch_t *usb_modeswitchFind(uint16_t vid, uint16_t pid, const usb_modeswitch_t *modes, int nmodes); -int usb_driverRun(usb_driver_t *driver); +int usb_procDrvRun(usb_driver_t *driver); int usb_eventsWait(int port, msg_t *msg); -int usb_open(usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir); +int usb_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir); -int usb_transferControl(unsigned pipe, usb_setup_packet_t *setup, void *data, size_t size, usb_dir_t dir); +int usb_transferControl(usb_driver_t *drv, unsigned pipe, usb_setup_packet_t *setup, void *data, size_t size, usb_dir_t dir); -int usb_transferBulk(unsigned pipe, void *data, size_t size, usb_dir_t dir); +int usb_transferBulk(usb_driver_t *drv, unsigned pipe, void *data, size_t size, usb_dir_t dir); -int usb_transferAsync(unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup); +int usb_transferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup); -int usb_setConfiguration(unsigned pipe, int conf); +int usb_setConfiguration(usb_driver_t *drv, unsigned pipe, int conf); -int usb_urbAlloc(unsigned pipe, void *data, usb_dir_t dir, size_t size, int type); +int usb_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type); -int usb_urbFree(unsigned pipe, unsigned urb); +int usb_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb); -int usb_clearFeatureHalt(unsigned pipe, int ep); +int usb_clearFeatureHalt(usb_driver_t *drv, unsigned pipe, int ep); void usb_dumpDeviceDescriptor(FILE *stream, usb_device_desc_t *descr); From 824615b34eeb4f08d158c9d64cd49fe05073f4d0 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 14 Nov 2024 16:18:04 +0100 Subject: [PATCH 12/25] usb: add ability to run device drivers from usbhost process This makes it possible to run drivers straight from the usbhost process thereby allowing for various optimizations based on shared memory between device driver and host driver -- ability to bypass msg-passing, as included in this change, being a prime example. It also moves out procdrv implementation details to seperate file from libusb/driver.c JIRA: RTOS-970 --- libusb/Makefile | 3 +- libusb/driver.c | 291 ++--------------------------------- libusb/procdriver.c | 307 +++++++++++++++++++++++++++++++++++++ libusb/usbdriver.h | 32 ++-- libusb/usbprocdriver.h | 24 +++ usb/Makefile | 6 +- usb/dev.c | 1 + usb/dev.h | 4 +- usb/drv.c | 341 ++++++++++++++++++++++++++++++++++------- usb/drv.h | 54 +++++-- usb/hub.c | 1 + usb/usb.c | 173 ++++++++++++++++----- usb/usbhost.h | 67 ++++++-- 13 files changed, 899 insertions(+), 405 deletions(-) create mode 100644 libusb/procdriver.c create mode 100644 libusb/usbprocdriver.h diff --git a/libusb/Makefile b/libusb/Makefile index 3d9d166..f471aee 100644 --- a/libusb/Makefile +++ b/libusb/Makefile @@ -7,6 +7,7 @@ NAME := libusb LOCAL_PATH := $(call my-dir) HEADERS := $(wildcard $(LOCAL_PATH)*.h) -LOCAL_SRCS := cdc_client.c hid_client.c driver.c +LOCAL_SRCS := cdc_client.c hid_client.c driver.c procdriver.c LOCAL_CFLAGS := -I$(LOCAL_PATH) + include $(static-lib.mk) diff --git a/libusb/driver.c b/libusb/driver.c index a935ba3..17e0fef 100644 --- a/libusb/driver.c +++ b/libusb/driver.c @@ -12,32 +12,34 @@ */ #include -#include -#include #include #include #include #include #include +#include -#ifndef USB_N_UMSG_THREADS -#define USB_N_UMSG_THREADS 2 -#endif -#ifndef USB_UMSG_PRIO -#define USB_UMSG_PRIO 3 -#endif +static struct { + usb_driver_t *registeredDrivers; +} usbdrv_common; -static usb_pipeOps_t usbprocdrv_pipeOps; +void usb_driverRegister(usb_driver_t *driver) +{ + LIST_ADD(&usbdrv_common.registeredDrivers, driver); +} -static struct { - char ustack[USB_N_UMSG_THREADS - 1][2048] __attribute__((aligned(8))); - unsigned srvport; - unsigned drvport; -} usbdrv_common; +usb_driver_t *usb_registeredDriverPop(void) +{ + usb_driver_t *drv = usbdrv_common.registeredDrivers; + if (drv != NULL) { + LIST_REMOVE(&usbdrv_common.registeredDrivers, drv); + } + return drv; +} int usb_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) @@ -64,185 +66,6 @@ int usb_transferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t s } -static void usb_hostLookup(oid_t *oid) -{ - int ret; - - for (;;) { - ret = lookup("devfs/usb", NULL, oid); - if (ret >= 0) { - break; - } - - ret = lookup("/dev/usb", NULL, oid); - if (ret >= 0) { - break; - } - - usleep(1000000); - } -} - - -static void usb_thread(void *arg) -{ - usb_driver_t *drv = (usb_driver_t *)arg; - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; - int ret; - - for (;;) { - ret = usb_eventsWait(usbdrv_common.drvport, &msg); - if (ret < 0) { - /* TODO should the thread abort the loop on error? */ - continue; - } - - switch (umsg->type) { - case usb_msg_insertion: - drv->handlers->insertion(drv, &umsg->insertion); - break; - case usb_msg_deletion: - drv->handlers->deletion(drv, &umsg->deletion); - break; - case usb_msg_completion: - drv->handlers->completion(drv, &umsg->completion, msg.i.data, msg.i.size); - break; - default: - fprintf(stderr, "usbdrv: Error when receiving event from host\n"); - break; - } - } -} - - -static int usb_connect(const usb_device_id_t *filters, unsigned int nfilters) -{ - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; - - msg.type = mtDevCtl; - msg.i.size = sizeof(*filters) * nfilters; - msg.i.data = (void *)filters; - - umsg->type = usb_msg_connect; - umsg->connect.port = usbdrv_common.drvport; - umsg->connect.nfilters = nfilters; - - return msgSend(usbdrv_common.srvport, &msg) < 0; -} - - -int usb_procDrvRun(usb_driver_t *drv) -{ - oid_t oid; - int ret, i; - - /* usb_procDrvRun is invoked iff drivers are in the proc variant */ - drv->pipeOps = &usbprocdrv_pipeOps; - - ret = drv->ops->init(drv); - if (ret < 0) { - return 1; - } - - usb_hostLookup(&oid); - usbdrv_common.srvport = oid.port; - - if (portCreate(&usbdrv_common.drvport) != 0) { - return -1; - } - - ret = usb_connect(drv->filters, drv->nfilters); - if (ret < 0) { - return -1; - } - - for (i = 0; i < USB_N_UMSG_THREADS - 1; i++) { - ret = beginthread(usb_thread, USB_UMSG_PRIO, usbdrv_common.ustack[i], sizeof(usbdrv_common.ustack[i]), drv); - if (ret < 0) { - fprintf(stderr, "usbdrv: fail to beginthread ret: %d\n", ret); - return 1; - } - } - - priority(USB_UMSG_PRIO); - usb_thread(drv); - - return 0; -} - - -int usb_eventsWait(int port, msg_t *msg) -{ - msg_rid_t rid; - int err; - - do { - err = msgRecv(port, msg, &rid); - if (err < 0 && err != -EINTR) - return -1; - } while (err == -EINTR); - - if (msgRespond(port, msg, rid) < 0) - return -1; - - return 0; -} - - -static int usbprocdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) -{ - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int ret; - - msg.type = mtDevCtl; - umsg->type = usb_msg_open; - - umsg->open.bus = dev->bus; - umsg->open.dev = dev->dev; - umsg->open.iface = dev->interface; - umsg->open.type = type; - umsg->open.dir = dir; - umsg->open.locationID = dev->locationID; - - ret = msgSend(usbdrv_common.srvport, &msg); - if (ret != 0) { - return ret; - } - - return msg.o.err; -} - - -static int usbprocdrv_urbSubmitSync(usb_driver_t *drv, usb_urb_t *urb, void *data) -{ - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int ret; - - msg.type = mtDevCtl; - umsg->type = usb_msg_urb; - - memcpy(&umsg->urb, urb, sizeof(usb_urb_t)); - - if (urb->dir == usb_dir_out) { - msg.i.data = data; - msg.i.size = urb->size; - } - else { - msg.o.data = data; - msg.o.size = urb->size; - } - - if ((ret = msgSend(usbdrv_common.srvport, &msg)) != 0) - return ret; - - return msg.o.err; -} - - int usb_transferControl(usb_driver_t *drv, unsigned pipe, usb_setup_packet_t *setup, void *data, size_t size, usb_dir_t dir) { usb_urb_t urb = { @@ -300,78 +123,6 @@ int usb_clearFeatureHalt(usb_driver_t *drv, unsigned pipe, int ep) } -static int usbprocdrv_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) -{ - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int ret; - usb_urb_t *urb = &umsg->urb; - - urb->pipe = pipe; - urb->type = type; - urb->dir = dir; - urb->size = size; - urb->sync = 0; - - msg.type = mtDevCtl; - umsg->type = usb_msg_urb; - - ret = msgSend(usbdrv_common.srvport, &msg); - if (ret < 0) { - return ret; - } - - /* URB id */ - return msg.o.err; -} - - -static int usbprocdrv_transferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) -{ - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int ret; - usb_urbcmd_t *urbcmd = &umsg->urbcmd; - - urbcmd->pipeid = pipe; - urbcmd->size = size; - urbcmd->urbid = urbid; - urbcmd->cmd = urbcmd_submit; - - if (setup != NULL) { - memcpy(&urbcmd->setup, setup, sizeof(*setup)); - } - msg.type = mtDevCtl; - umsg->type = usb_msg_urbcmd; - ret = msgSend(usbdrv_common.srvport, &msg); - if (ret < 0) { - return ret; - } - - return 0; -} - - -static int usbprocdrv_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb) -{ - msg_t msg = { 0 }; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int ret; - usb_urbcmd_t *urbcmd = &umsg->urbcmd; - - urbcmd->pipeid = pipe; - urbcmd->urbid = urb; - urbcmd->cmd = urbcmd_free; - - msg.type = mtDevCtl; - umsg->type = usb_msg_urbcmd; - if ((ret = msgSend(usbdrv_common.srvport, &msg)) < 0) - return ret; - - return 0; -} - - const usb_modeswitch_t *usb_modeswitchFind(uint16_t vid, uint16_t pid, const usb_modeswitch_t *modes, int nmodes) { int i; @@ -488,13 +239,3 @@ int usb_modeswitchHandle(usb_driver_t *drv, usb_devinfo_t *dev, const usb_modesw return 0; } - - -static usb_pipeOps_t usbprocdrv_pipeOps = { - .open = usbprocdrv_open, - .submitSync = usbprocdrv_urbSubmitSync, - .transferAsync = usbprocdrv_transferAsync, - - .urbFree = usbprocdrv_urbFree, - .urbAlloc = usbprocdrv_urbAlloc, -}; diff --git a/libusb/procdriver.c b/libusb/procdriver.c new file mode 100644 index 0000000..a57e995 --- /dev/null +++ b/libusb/procdriver.c @@ -0,0 +1,307 @@ +/* + * Phoenix-RTOS + * + * libusb/procdriver.c + * + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch + * + * %LICENSE% + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#ifndef USB_N_UMSG_THREADS +#define USB_N_UMSG_THREADS 2 +#endif + +#ifndef USB_UMSG_PRIO +#define USB_UMSG_PRIO 3 +#endif + + +static usb_pipeOps_t usbprocdrv_pipeOps; + + +static struct { + char ustack[USB_N_UMSG_THREADS - 1][2048] __attribute__((aligned(8))); + unsigned srvport; + unsigned drvport; +} usbprocdrv_common; + + +static void usb_hostLookup(oid_t *oid) +{ + int ret; + + for (;;) { + ret = lookup("devfs/usb", NULL, oid); + if (ret >= 0) { + break; + } + + ret = lookup("/dev/usb", NULL, oid); + if (ret >= 0) { + break; + } + + usleep(1000000); + } +} + + +static void usb_thread(void *arg) +{ + usb_driver_t *drv = (usb_driver_t *)arg; + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; + int ret; + + for (;;) { + ret = usb_eventsWait(usbprocdrv_common.drvport, &msg); + if (ret < 0) { + fprintf(stderr, "usbdrv: error when receiving event from host\n"); + continue; + } + + switch (umsg->type) { + case usb_msg_insertion: + drv->handlers.insertion(drv, &umsg->insertion); + break; + case usb_msg_deletion: + drv->handlers.deletion(drv, &umsg->deletion); + break; + case usb_msg_completion: + drv->handlers.completion(drv, &umsg->completion, msg.i.data, msg.i.size); + break; + default: + fprintf(stderr, "usbdrv: unknown msg type\n"); + break; + } + } +} + + +static int usb_connect(const usb_device_id_t *filters, unsigned int nfilters) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; + + msg.type = mtDevCtl; + msg.i.size = sizeof(*filters) * nfilters; + msg.i.data = (void *)filters; + + umsg->type = usb_msg_connect; + umsg->connect.port = usbprocdrv_common.drvport; + umsg->connect.nfilters = nfilters; + + return msgSend(usbprocdrv_common.srvport, &msg) < 0; +} + + +int usb_driverProcRun(usb_driver_t *drv, void *args) +{ + oid_t oid; + int ret, i; + + /* usb_driverProcRun is invoked iff drivers are in the proc variant */ + drv->pipeOps = &usbprocdrv_pipeOps; + + ret = drv->ops.init(drv, args); + if (ret < 0) { + return -1; + } + + usb_hostLookup(&oid); + usbprocdrv_common.srvport = oid.port; + + ret = portCreate(&usbprocdrv_common.drvport); + if (ret != 0) { + return -1; + } + + ret = usb_connect(drv->filters, drv->nfilters); + if (ret < 0) { + return -1; + } + + for (i = 0; i < USB_N_UMSG_THREADS - 1; i++) { + ret = beginthread(usb_thread, USB_UMSG_PRIO, usbprocdrv_common.ustack[i], sizeof(usbprocdrv_common.ustack[i]), drv); + if (ret < 0) { + fprintf(stderr, "usbdrv: fail to beginthread ret: %d\n", ret); + return -1; + } + } + + priority(USB_UMSG_PRIO); + usb_thread(drv); + + return 0; +} + + +int usb_eventsWait(int port, msg_t *msg) +{ + msg_rid_t rid; + int err; + + do { + err = msgRecv(port, msg, &rid); + if (err < 0 && err != -EINTR) + return -1; + } while (err == -EINTR); + + if (msgRespond(port, msg, rid) < 0) + return -1; + + return 0; +} + + +static int usbprocdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; + int ret; + + msg.type = mtDevCtl; + umsg->type = usb_msg_open; + + umsg->open.bus = dev->bus; + umsg->open.dev = dev->dev; + umsg->open.iface = dev->interface; + umsg->open.type = type; + umsg->open.dir = dir; + umsg->open.locationID = dev->locationID; + + ret = msgSend(usbprocdrv_common.srvport, &msg); + if (ret != 0) { + return ret; + } + + return msg.o.err; +} + + +static int usbprocdrv_urbSubmitSync(usb_driver_t *drv, usb_urb_t *urb, void *data) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; + int ret; + + msg.type = mtDevCtl; + umsg->type = usb_msg_urb; + + memcpy(&umsg->urb, urb, sizeof(usb_urb_t)); + + if (urb->dir == usb_dir_out) { + msg.i.data = data; + msg.i.size = urb->size; + } + else { + msg.o.data = data; + msg.o.size = urb->size; + } + + ret = msgSend(usbprocdrv_common.srvport, &msg); + if (ret != 0) { + return ret; + } + + return msg.o.err; +} + + +static int usbprocdrv_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; + int ret; + usb_urb_t *urb = &umsg->urb; + + urb->pipe = pipe; + urb->type = type; + urb->dir = dir; + urb->size = size; + urb->sync = 0; + + msg.type = mtDevCtl; + umsg->type = usb_msg_urb; + + ret = msgSend(usbprocdrv_common.srvport, &msg); + if (ret < 0) { + return ret; + } + + /* URB id */ + return msg.o.err; +} + + +static int usbprocdrv_transferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; + int ret; + usb_urbcmd_t *urbcmd = &umsg->urbcmd; + + urbcmd->pipeid = pipe; + urbcmd->size = size; + urbcmd->urbid = urbid; + urbcmd->cmd = urbcmd_submit; + + if (setup != NULL) { + memcpy(&urbcmd->setup, setup, sizeof(*setup)); + } + msg.type = mtDevCtl; + umsg->type = usb_msg_urbcmd; + ret = msgSend(usbprocdrv_common.srvport, &msg); + if (ret < 0) { + return ret; + } + + return 0; +} + + +static int usbprocdrv_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb) +{ + msg_t msg = { 0 }; + usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; + int ret; + usb_urbcmd_t *urbcmd = &umsg->urbcmd; + + urbcmd->pipeid = pipe; + urbcmd->urbid = urb; + urbcmd->cmd = urbcmd_free; + + msg.type = mtDevCtl; + umsg->type = usb_msg_urbcmd; + + ret = msgSend(usbprocdrv_common.srvport, &msg); + if (ret < 0) { + return ret; + } + + return 0; +} + + +static usb_pipeOps_t usbprocdrv_pipeOps = { + .open = usbprocdrv_open, + .submitSync = usbprocdrv_urbSubmitSync, + .transferAsync = usbprocdrv_transferAsync, + + .urbFree = usbprocdrv_urbFree, + .urbAlloc = usbprocdrv_urbAlloc, +}; diff --git a/libusb/usbdriver.h b/libusb/usbdriver.h index f79ebce..91001f7 100644 --- a/libusb/usbdriver.h +++ b/libusb/usbdriver.h @@ -6,8 +6,8 @@ * * libusb/usbdriver.h * - * Copyright 2021 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -26,6 +26,11 @@ #define USBDRV_ANY ((unsigned)-1) +/* clang-format off */ +typedef enum { usb_drvType_none = 0, usb_drvType_hcd, usb_drvType_intrn, usb_drvType_extrn } usb_drvType_t; +/* clang-format on */ + + enum { usbdrv_nomatch = 0x0, usbdrv_match = 0x01, @@ -161,7 +166,7 @@ typedef struct { typedef struct { - int (*init)(usb_driver_t *driver); + int (*init)(usb_driver_t *driver, void *args); int (*destroy)(usb_driver_t *driver); } usb_driverOps_t; @@ -179,13 +184,17 @@ typedef struct { struct usb_driver { - const usb_handlers_t *handlers; - const usb_driverOps_t *ops; + usb_driver_t *next, *prev; + + char name[10]; + usb_handlers_t handlers; + usb_driverOps_t ops; const usb_pipeOps_t *pipeOps; const usb_device_id_t *filters; unsigned int nfilters; - uintptr_t *priv; - uintptr_t *pipePriv; + + void *priv; + void *hostPriv; }; @@ -195,9 +204,6 @@ int usb_modeswitchHandle(usb_driver_t *drv, usb_devinfo_t *dev, const usb_modesw const usb_modeswitch_t *usb_modeswitchFind(uint16_t vid, uint16_t pid, const usb_modeswitch_t *modes, int nmodes); -int usb_procDrvRun(usb_driver_t *driver); - - int usb_eventsWait(int port, msg_t *msg); @@ -240,4 +246,10 @@ void usb_dumpEndpointDesc(FILE *stream, usb_endpoint_desc_t *descr); void usb_dumpStringDesc(FILE *stream, usb_string_desc_t *descr); +void usb_driverRegister(usb_driver_t *driver); + + +usb_driver_t *usb_registeredDriverPop(void); + + #endif /* _USBDRIVER_H_ */ diff --git a/libusb/usbprocdriver.h b/libusb/usbprocdriver.h new file mode 100644 index 0000000..0d38e25 --- /dev/null +++ b/libusb/usbprocdriver.h @@ -0,0 +1,24 @@ +/* + * Phoenix-RTOS + * + * Libusb process driver interface + * + * libusb/usbprocdriver.h + * + * Copyright 2024 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + +#ifndef _PROCDRIVER_H_ +#define _PROCDRIVER_H_ + +#include +#include + + +int usb_driverProcRun(usb_driver_t *driver, void *args); + + +#endif diff --git a/usb/Makefile b/usb/Makefile index 4a4eb99..d6d3cbe 100644 --- a/usb/Makefile +++ b/usb/Makefile @@ -7,7 +7,11 @@ NAME := usb LOCAL_SRCS := usb.c dev.c drv.c hcd.c hub.c mem.c LOCAL_HEADERS := hcd.h hub.h dev.h drv.h usbhost.h -LIBS := $(USB_HCD_LIBS) +LIBS := $(USB_HCD_LIBS) $(USB_HOSTDRV_LIBS) libusb DEPS := libusb +ifneq ($(USB_HOSTDRV_LIBS),) + CFLAGS += -DUSB_INTERNAL_ONLY +endif + include $(binary.mk) diff --git a/usb/dev.c b/usb/dev.c index 25e5766..fc26898 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -46,6 +46,7 @@ int usb_devCtrl(usb_dev_t *dev, usb_dir_t dir, usb_setup_packet_t *setup, char * .setup = (usb_setup_packet_t *)usbdev_common.setupBuf, .buffer = usbdev_common.ctrlBuf, .size = len, + .recipient = usb_drvType_hcd, }; int ret; diff --git a/usb/dev.h b/usb/dev.h index b74a6a1..e533941 100644 --- a/usb/dev.h +++ b/usb/dev.h @@ -29,7 +29,7 @@ typedef struct { void *classDesc; char *str; - struct _usb_drv *driver; + struct usb_drvpriv *driver; } usb_iface_t; @@ -56,7 +56,7 @@ typedef struct _usb_dev { /* Hub fields */ struct _usb_dev **devs; - struct usb_transfer *statusTransfer; + usb_transfer_t *statusTransfer; usb_pipe_t *irqPipe; int nports; } usb_dev_t; diff --git a/usb/drv.c b/usb/drv.c index d30be01..1f28ef3 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -3,8 +3,8 @@ * * USB Host Driver * - * Copyright 2021, 2022 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2022, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -26,20 +27,21 @@ #include "drv.h" #include "hcd.h" + struct { handle_t lock; - usb_drv_t *drvs; + usb_drvpriv_t *drvs; handle_t drvAddedCond; } usbdrv_common; -static usb_pipe_t *_usb_pipeFind(usb_drv_t *drv, int pipeid) +static usb_pipe_t *_usb_pipeFind(usb_drvpriv_t *drv, int pipeid) { return lib_treeof(usb_pipe_t, linkage, idtree_find(&drv->pipes, pipeid)); } -static usb_transfer_t *_usb_transferFind(usb_drv_t *drv, int id) +static usb_transfer_t *_usb_transferFind(usb_drvpriv_t *drv, int id) { usb_transfer_t *t; @@ -67,7 +69,7 @@ void usb_transferPut(usb_transfer_t *t) } -static int _usb_pipeAdd(usb_drv_t *drv, usb_pipe_t *pipe) +static int _usb_pipeAdd(usb_drvpriv_t *drv, usb_pipe_t *pipe) { if (idtree_alloc(&drv->pipes, &pipe->linkage) < 0) return -1; @@ -76,7 +78,7 @@ static int _usb_pipeAdd(usb_drv_t *drv, usb_pipe_t *pipe) } -static usb_pipe_t *usb_pipeAlloc(usb_drv_t *drv, usb_dev_t *dev, usb_endpoint_desc_t *desc) +static usb_pipe_t *usb_pipeAlloc(usb_drvpriv_t *drv, usb_dev_t *dev, usb_endpoint_desc_t *desc) { usb_pipe_t *pipe; @@ -96,7 +98,7 @@ static usb_pipe_t *usb_pipeAlloc(usb_drv_t *drv, usb_dev_t *dev, usb_endpoint_de } -static usb_pipe_t *_usb_drvPipeOpen(usb_drv_t *drv, hcd_t *hcd, int locationID, int ifaceID, int dir, int type) +static usb_pipe_t *_usb_drvPipeOpen(usb_drvpriv_t *drv, hcd_t *hcd, int locationID, int ifaceID, int dir, int type) { usb_endpoint_desc_t *desc; usb_pipe_t *pipe = NULL; @@ -117,8 +119,9 @@ static usb_pipe_t *_usb_drvPipeOpen(usb_drv_t *drv, hcd_t *hcd, int locationID, iface = &dev->ifs[ifaceID]; /* Driver and interface mismatch */ - if (iface->driver != drv) + if (iface->driver != drv) { return NULL; + } desc = iface->eps; if (type == usb_transfer_control) { @@ -160,7 +163,7 @@ usb_pipe_t *usb_pipeOpen(usb_dev_t *dev, int iface, int dir, int type) } -int usb_drvPipeOpen(usb_drv_t *drv, hcd_t *hcd, int locationID, int iface, int dir, int type) +int usb_drvPipeOpen(usb_drvpriv_t *drv, hcd_t *hcd, int locationID, int iface, int dir, int type) { usb_pipe_t *pipe = NULL; int pipeId = -1; @@ -174,7 +177,7 @@ int usb_drvPipeOpen(usb_drv_t *drv, hcd_t *hcd, int locationID, int iface, int d } -static int _usb_drvTransfer(usb_drv_t *drv, usb_transfer_t *t) +static int _usb_drvTransfer(usb_drvpriv_t *drv, usb_transfer_t *t) { usb_pipe_t *pipe; @@ -188,7 +191,7 @@ static int _usb_drvTransfer(usb_drv_t *drv, usb_transfer_t *t) } -int usb_drvTransfer(usb_drv_t *drv, usb_transfer_t *t, int pipeId) +int usb_drvTransfer(usb_drvpriv_t *drv, usb_transfer_t *t, int pipeId) { int ret; @@ -200,7 +203,7 @@ int usb_drvTransfer(usb_drv_t *drv, usb_transfer_t *t, int pipeId) } -static int usb_drvcmp(usb_device_desc_t *dev, usb_interface_desc_t *iface, usb_device_id_t *filter) +static int usb_drvcmp(usb_device_desc_t *dev, usb_interface_desc_t *iface, const usb_device_id_t *filter) { int match = usbdrv_match; @@ -246,9 +249,9 @@ static int usb_drvcmp(usb_device_desc_t *dev, usb_interface_desc_t *iface, usb_d } -static usb_drv_t *usb_drvMatchIface(usb_dev_t *dev, usb_iface_t *iface) +static usb_drvpriv_t *usb_drvMatchIface(usb_dev_t *dev, usb_iface_t *iface) { - usb_drv_t *drv, *best = NULL; + usb_drvpriv_t *drv, *best = NULL; int i, match, bestmatch = 0; mutexLock(usbdrv_common.lock); @@ -258,8 +261,9 @@ static usb_drv_t *usb_drvMatchIface(usb_dev_t *dev, usb_iface_t *iface) drv = usbdrv_common.drvs; do { - for (i = 0; i < drv->nfilters; i++) { - match = usb_drvcmp(&dev->desc, iface->desc, &drv->filters[i]); + for (i = 0; i < drv->driver.nfilters; i++) { + match = usb_drvcmp(&dev->desc, iface->desc, &drv->driver.filters[i]); + if (match > bestmatch) { bestmatch = match; best = drv; @@ -282,7 +286,7 @@ static int _usb_urbCancel(usb_transfer_t *t, usb_pipe_t *pipe) } -static int _usb_urbFree(usb_transfer_t *t, usb_drv_t *drv, usb_pipe_t *pipe) +static int _usb_urbFree(usb_transfer_t *t, usb_drvpriv_t *drv, usb_pipe_t *pipe) { /* Remove from the drv's urbs tree. * No need to cancel the transfer, it will be @@ -295,7 +299,7 @@ static int _usb_urbFree(usb_transfer_t *t, usb_drv_t *drv, usb_pipe_t *pipe) } -static void _usb_pipeFree(usb_drv_t *drv, usb_pipe_t *pipe) +static void _usb_pipeFree(usb_drvpriv_t *drv, usb_pipe_t *pipe) { rbnode_t *n, *nn; usb_transfer_t *t; @@ -319,7 +323,7 @@ static void _usb_pipeFree(usb_drv_t *drv, usb_pipe_t *pipe) } -int usb_drvUnbind(usb_drv_t *drv, usb_dev_t *dev, int iface) +int usb_drvUnbind(usb_drvpriv_t *drv, usb_dev_t *dev, int iface) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; @@ -344,17 +348,22 @@ int usb_drvUnbind(usb_drv_t *drv, usb_dev_t *dev, int iface) umsg->deletion.dev = dev->address; umsg->deletion.interface = iface; + if (drv->type == usb_drvType_intrn) { + return drv->driver.handlers.deletion(&drv->driver, &umsg->deletion); + } + /* TODO: use non blocking version of msgSend */ - return msgSend(drv->port, &msg); + return msgSend(drv->extrn.port, &msg); } int usb_drvBind(usb_dev_t *dev) { - usb_drv_t *drv; + usb_drvpriv_t *drv; + msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int i; + int i, err; msg.type = mtDevCtl; umsg->type = usb_msg_insertion; @@ -367,11 +376,27 @@ int usb_drvBind(usb_dev_t *dev) * Devices may become orphaned forever if they get added by hcd before the driver * is connected */ for (i = 0; i < dev->nifs; i++) { - if ((drv = usb_drvMatchIface(dev, &dev->ifs[i])) != NULL) { + drv = usb_drvMatchIface(dev, &dev->ifs[i]); + if (drv != NULL) { dev->ifs[i].driver = drv; umsg->insertion.interface = i; - msgSend(drv->port, &msg); - if (msg.o.err == 0) { + + switch (drv->type) { + case usb_drvType_intrn: + err = drv->driver.handlers.insertion(&drv->driver, &umsg->insertion); + break; + case usb_drvType_extrn: + err = msgSend(drv->extrn.port, &msg); + if (err == 0) { + err = msg.o.err; + } + break; + default: + USB_LOG("usb: unexpected driver type: %d\n", drv->type); + break; + } + + if (err == 0) { return 0; } } @@ -382,14 +407,14 @@ int usb_drvBind(usb_dev_t *dev) } -usb_drv_t *_usb_drvFind(pid_t pid) +static usb_drvpriv_t *_usb_drvFind(int id) { - usb_drv_t *drv, *res = NULL; + usb_drvpriv_t *drv, *res = NULL; drv = usbdrv_common.drvs; if (drv != NULL) { do { - if (drv->pid == pid) { + if (drv->extrn.id == id) { res = drv; break; } @@ -402,19 +427,19 @@ usb_drv_t *_usb_drvFind(pid_t pid) } -usb_drv_t *usb_drvFind(int pid) +usb_drvpriv_t *usb_drvFind(int id) { - usb_drv_t *drv; + usb_drvpriv_t *drv; mutexLock(usbdrv_common.lock); - drv = _usb_drvFind(pid); + drv = _usb_drvFind(id); mutexUnlock(usbdrv_common.lock); return drv; } -void usb_drvAdd(usb_drv_t *drv) +void usb_drvAdd(usb_drvpriv_t *drv) { mutexLock(usbdrv_common.lock); idtree_init(&drv->pipes); @@ -488,19 +513,12 @@ static int _usb_urbSubmit(usb_transfer_t *t, usb_pipe_t *pipe) } -static int _usb_handleUrbcmd(msg_t *msg) +static int _usb_handleUrbcmd(usb_drvpriv_t *drv, usb_urbcmd_t *urbcmd) { - usb_msg_t *umsg = (usb_msg_t *)msg->i.raw; - usb_urbcmd_t *urbcmd = &umsg->urbcmd; usb_transfer_t *t; usb_pipe_t *pipe; - usb_drv_t *drv; int ret; - drv = _usb_drvFind(msg->pid); - if (drv == NULL) - return -EINVAL; - pipe = _usb_pipeFind(drv, urbcmd->pipeid); if (pipe == NULL) return -EINVAL; @@ -540,9 +558,18 @@ static int _usb_handleUrbcmd(msg_t *msg) int usb_handleUrbcmd(msg_t *msg) { int ret; + usb_msg_t *umsg = (usb_msg_t *)msg->i.raw; + usb_urbcmd_t *urbcmd = &umsg->urbcmd; + usb_drvpriv_t *drv; mutexLock(usbdrv_common.lock); - ret = _usb_handleUrbcmd(msg); + drv = _usb_drvFind(msg->pid); + if (drv == NULL) { + ret = -EINVAL; + } + else { + ret = _usb_handleUrbcmd(drv, urbcmd); + } mutexUnlock(usbdrv_common.lock); return ret; @@ -553,11 +580,12 @@ static int _usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) { usb_msg_t *umsg = (usb_msg_t *)msg->i.raw; usb_urb_t *urb = &umsg->urb; - usb_drv_t *drv; + usb_drvpriv_t *drv; usb_transfer_t *t; - int ret = 0; + int ret; - if ((drv = _usb_drvFind(msg->pid)) == NULL) { + drv = _usb_drvFind(msg->pid); + if (drv == NULL) { USB_LOG("usb: driver pid %d does not exist!\n", msg->pid); return -EINVAL; } @@ -566,14 +594,24 @@ static int _usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) if (t == NULL) return -ENOMEM; - t->port = drv->port; + t->recipient = drv->type; + if (t->recipient == usb_drvType_extrn) { + t->extrn.port = drv->extrn.port; + t->extrn.odata = msg->o.data; + t->extrn.osize = msg->o.size; + } + else { + USB_LOG("usb: urb handler/recipient type mismatch\n"); + return -EINVAL; + } t->pipeid = urb->pipe; - t->msg = *msg; + t->ops = usbprocdrv_transferOpsGet(); /* For async urbs only allocate resources. The transfer would be executed, * upon receiving usb_submit_t msg later */ if (!urb->sync) { - if (idtree_alloc(&drv->urbs, &t->linkage) < 0) { + ret = idtree_alloc(&drv->urbs, &t->linkage); + if (ret < 0) { usb_transferFree(t); return -ENOMEM; } @@ -582,13 +620,16 @@ static int _usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) ret = t->linkage.id; } else { - t->rid = rid; - t->pid = msg->pid; + t->extrn.rid = rid; + t->extrn.pid = msg->pid; - if (_usb_drvTransfer(drv, t) < 0) { + ret = _usb_drvTransfer(drv, t); + if (ret < 0) { usb_transferFree(t); return -EINVAL; } + + ret = 0; } /* For async urbs, respond immediately and send usb_completion msg later. @@ -609,7 +650,7 @@ int usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) } -void usb_drvPipeFree(usb_drv_t *drv, usb_pipe_t *pipe) +void usb_drvPipeFree(usb_drvpriv_t *drv, usb_pipe_t *pipe) { mutexLock(usbdrv_common.lock); @@ -638,3 +679,199 @@ int usb_drvInit(void) return 0; } + + +static int usblibdrv_handleUrb(usb_driver_t *drv, usb_urb_t *urb, void *data) +{ + usb_drvpriv_t *drvpriv = (usb_drvpriv_t *)drv->hostPriv; + usb_transfer_t *t; + int ret = 0; + + t = usb_transferAlloc(urb->sync, urb->type, &urb->setup, urb->dir, urb->size, data); + if (t == NULL) { + return -ENOMEM; + } + + t->pipeid = urb->pipe; + t->ops = usblibdrv_transferOpsGet(); + t->recipient = drvpriv->type; + if (t->recipient == usb_drvType_intrn) { + t->intrn.finishedCond = &drvpriv->intrn.finishedCond; + t->intrn.drv = drv; + } + else { + USB_LOG("usb: urb handler/recipient type mismatch\n"); + usb_transferFree(t); + return -EINVAL; + } + + /* For async urbs only allocate resources. The transfer would be executed, + * upon receiving usb_submit_t msg later */ + if (urb->sync == 0) { + if (idtree_alloc(&drvpriv->urbs, &t->linkage) < 0) { + usb_transferFree(t); + return -ENOMEM; + } + + t->refcnt = 1; + ret = t->linkage.id; + } + else { + if (_usb_drvTransfer(drvpriv, t) < 0) { + usb_transferFree(t); + return -EINVAL; + } + + mutexLock(drvpriv->intrn.transferLock); + while (!usb_transferCheck(t)) { + condWait(*t->intrn.finishedCond, drvpriv->intrn.transferLock, 0); + } + mutexUnlock(drvpriv->intrn.transferLock); + + if ((t->direction == usb_dir_in) && (t->error == 0)) { + memcpy(data, t->buffer, min(t->size, t->transferred)); + } + + ret = (t->error != 0) ? -t->error : t->transferred; + usb_transferFree(t); + } + + return ret; +} + + +static int usblibdrv_urbSubmitSync(usb_driver_t *drv, usb_urb_t *urb, void *data) +{ + USB_TRACE("") + return usblibdrv_handleUrb(drv, urb, data); +} + + +static int usblibdrv_urbTransferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) +{ + USB_TRACE("") + usb_urbcmd_t urbcmd = { 0 }; + usb_drvpriv_t *drvpriv = (usb_drvpriv_t *)drv->hostPriv; + int ret; + + urbcmd.pipeid = pipe; + urbcmd.size = size; + urbcmd.urbid = urbid; + urbcmd.cmd = urbcmd_submit; + + if (setup != NULL) { + memcpy(&urbcmd.setup, setup, sizeof(*setup)); + } + + mutexLock(usbdrv_common.lock); + ret = _usb_handleUrbcmd(drvpriv, &urbcmd); + mutexUnlock(usbdrv_common.lock); + + return ret; +} + + +static void usblibdrv_urbSyncCompleted(usb_transfer_t *t) +{ + USB_TRACE("") + condSignal(*t->intrn.finishedCond); +} + + +static void usblibdrv_urbAsyncCompleted(usb_transfer_t *t) +{ + USB_TRACE("") + usb_completion_t c = { 0 }; + usb_driver_t *drv = t->intrn.drv; + void *data = NULL; + int size = 0; + + c.pipeid = t->pipeid; + c.urbid = t->linkage.id; + c.transferred = t->transferred; + c.err = t->error; + + if (t->direction == usb_dir_in) { + size = t->transferred; + data = t->buffer; + } + t->state = urb_idle; + + drv->handlers.completion(drv, &c, data, size); + usb_transferPut(t); +} + + +static int usblibdrv_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) +{ + USB_TRACE("") + usb_urb_t urb = { 0 }; + urb.pipe = pipe; + urb.type = type; + urb.dir = dir; + urb.size = size; + urb.sync = 0; + + return usblibdrv_handleUrb(drv, &urb, data); +} + + +static int usblibdrv_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb) +{ + USB_TRACE("") + usb_urbcmd_t urbcmd = { 0 }; + usb_drvpriv_t *drvpriv = (usb_drvpriv_t *)drv->hostPriv; + int ret; + + urbcmd.pipeid = pipe; + urbcmd.urbid = urb; + urbcmd.cmd = urbcmd_free; + + mutexLock(usbdrv_common.lock); + ret = _usb_handleUrbcmd(drvpriv, &urbcmd); + mutexUnlock(usbdrv_common.lock); + + return ret; +} + + +static usb_transferOps_t usblibdrv_transferOps = { + .urbSyncCompleted = usblibdrv_urbSyncCompleted, + .urbAsyncCompleted = usblibdrv_urbAsyncCompleted, +}; + + +static usb_pipeOps_t usblibdrv_pipeOps = { + .open = usblibdrv_open, + .submitSync = usblibdrv_urbSubmitSync, + .transferAsync = usblibdrv_urbTransferAsync, + .urbAlloc = usblibdrv_urbAlloc, + .urbFree = usblibdrv_urbFree, +}; + + +const usb_transferOps_t *usblibdrv_transferOpsGet(void) +{ + return &usblibdrv_transferOps; +} + + +int usb_libDrvInit(usb_driver_t *drv) +{ + drv->pipeOps = &usblibdrv_pipeOps; + + /* TODO: make a thread here so the faulty driver cannot block us */ + /* TODO: add some sort of universal argument passing API, i.e. a linked list + of (char*, int) pairs through which the usbhost can influence the driver's configuration */ + return drv->ops.init(drv, NULL); +} + + +void usb_libDrvDestroy(usb_driver_t *drv) +{ + int ret; + ret = drv->ops.destroy(drv); + if (ret < 0) { + USB_LOG("usb: driver destroy failed: %d\n", ret); + } +} diff --git a/usb/drv.h b/usb/drv.h index df1831e..7e6442b 100644 --- a/usb/drv.h +++ b/usb/drv.h @@ -3,8 +3,8 @@ * * USB Host Driver * - * Copyright 2021 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -16,51 +16,73 @@ #define _USB_DRV_H_ #include +#include #include "dev.h" #include "hcd.h" -typedef struct _usb_drv { - struct _usb_drv *next, *prev; - pid_t pid; - unsigned port; - unsigned nfilters; - usb_device_id_t *filters; + +#define PORT_INTERNAL (-1) + + +typedef struct usb_drvpriv { + struct usb_drvpriv *next, *prev; + + usb_drvType_t type; + union { + struct { + handle_t transferLock; + handle_t finishedCond; + } intrn; + + struct { + int id; + unsigned port; + } extrn; + }; + + usb_driver_t driver; idtree_t pipes; idtree_t urbs; -} usb_drv_t; +} usb_drvpriv_t; + + +usb_drvpriv_t *usb_drvFind(int id); + + +int usb_libDrvInit(usb_driver_t *drv); -usb_drv_t *usb_drvFind(int pid); +void usb_libDrvDestroy(usb_driver_t *drv); -void usb_drvAdd(usb_drv_t *drv); +void usb_drvAdd(usb_drvpriv_t *drv); int usb_drvBind(usb_dev_t *dev); -int usb_drvUnbind(usb_drv_t *drv, usb_dev_t *dev, int iface); +int usb_drvUnbind(usb_drvpriv_t *drv, usb_dev_t *dev, int iface); int usb_drvInit(void); -int usb_drvPipeOpen(usb_drv_t *drv, hcd_t *hcd, int locationID, int iface, int dir, int type); +int usb_drvPipeOpen(usb_drvpriv_t *drv, hcd_t *hcd, int locationID, int iface, int dir, int type); usb_pipe_t *usb_pipeOpen(usb_dev_t *dev, int iface, int dir, int type); -void usb_drvPipeFree(usb_drv_t *drv, usb_pipe_t *pipe); +void usb_drvPipeFree(usb_drvpriv_t *drv, usb_pipe_t *pipe); -int usb_drvTransfer(usb_drv_t *drv, usb_transfer_t *t, int pipeId); +int usb_drvTransfer(usb_drvpriv_t *drv, usb_transfer_t *t, int pipeId); int usb_urbAllocHandle(msg_t *msg, unsigned int port, unsigned long rid); -int usb_drvTransferAsync(usb_drv_t *drv, int urbid, int pipeid); +int usb_drvTransferAsync(usb_drvpriv_t *drv, int urbid, int pipeid); int usb_handleUrbcmd(msg_t *msg); diff --git a/usb/hub.c b/usb/hub.c index a9b856f..f1032f2 100644 --- a/usb/hub.c +++ b/usb/hub.c @@ -165,6 +165,7 @@ static int hub_interruptInit(usb_dev_t *hub) t->direction = usb_dir_in; t->size = (hub->nports / 8) + 1; t->hub = hub; + t->recipient = usb_drvType_hcd; hub->statusTransfer = t; diff --git a/usb/usb.c b/usb/usb.c index faeeb2f..116bb52 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -34,7 +34,6 @@ #include "hcd.h" #include "hub.h" - #define N_STATUSTHRS 1 #define STATUSTHR_PRIO 3 #define MSGTHR_PRIO 3 @@ -45,16 +44,61 @@ static struct { handle_t transferLock; handle_t finishedCond; hcd_t *hcds; - usb_drv_t *drvs; + usb_drvpriv_t *drvs; usb_transfer_t *finished; int nhcd; uint32_t port; } usb_common; -int usb_transferCheck(usb_transfer_t *t) +static int usb_internalDriverInit(usb_driver_t *driver) { - int val; + usb_drvpriv_t *priv; + int ret; + + ret = usb_libDrvInit(driver); + if (ret < 0) { + return ret; + } + + priv = malloc(sizeof(usb_drvpriv_t)); + if (priv == NULL) { + USB_LOG("usb: malloc failed!\n"); + usb_libDrvDestroy(driver); + return -ENOMEM; + } + + priv->type = usb_drvType_intrn; + + ret = mutexCreate(&priv->intrn.transferLock); + if (ret != 0) { + USB_LOG("usb: Can't create mutex!\n"); + free(priv); + usb_libDrvDestroy(driver); + return -ENOMEM; + } + + ret = condCreate(&priv->intrn.finishedCond); + if (ret != 0) { + USB_LOG("usb: Can't create cond!\n"); + resourceDestroy(priv->intrn.transferLock); + free(priv); + usb_libDrvDestroy(driver); + return -ENOMEM; + } + + driver->hostPriv = (void *)priv; + priv->driver = *driver; + + usb_drvAdd(priv); + + return 0; +} + + +bool usb_transferCheck(usb_transfer_t *t) +{ + bool val; mutexLock(usb_common.transferLock); val = t->finished; @@ -69,8 +113,13 @@ int usb_transferSubmit(usb_transfer_t *t, usb_pipe_t *pipe, handle_t *cond) hcd_t *hcd = pipe->dev->hcd; int ret = 0; + if (t->recipient == usb_drvType_none) { + USB_LOG("usb: transfer recipient unspecified!\n"); + return -EINVAL; + } + mutexLock(usb_common.transferLock); - t->finished = 0; + t->finished = false; t->error = 0; t->transferred = 0; if (t->direction == usb_dir_in) @@ -96,10 +145,10 @@ int usb_transferSubmit(usb_transfer_t *t, usb_pipe_t *pipe, handle_t *cond) /* Called by the hcd driver */ void usb_transferFinished(usb_transfer_t *t, int status) { - int urbtrans = 0; + bool urbtrans = false; mutexLock(usb_common.transferLock); - t->finished = 1; + t->finished = true; if (status >= 0) { t->transferred = status; @@ -110,25 +159,26 @@ void usb_transferFinished(usb_transfer_t *t, int status) t->error = -status; } - /* URB transfer */ - if (t->port != 0) { - urbtrans = 1; + /* If recipient is not HCD, this is an URB transfer */ + if (t->recipient != usb_drvType_hcd) { + urbtrans = true; t->state = urb_completed; LIST_ADD(&usb_common.finished, t); } mutexUnlock(usb_common.transferLock); - /* Internal transfer */ - if (!urbtrans) { - if (t->type == usb_transfer_interrupt && t->transferred > 0) - hub_notify(t->hub); - else - usb_devSignal(); + if (urbtrans) { + condSignal(usb_common.finishedCond); } else { - /* URB transfer */ - condSignal(usb_common.finishedCond); + /* Internal HCD transfer */ + if (t->type == usb_transfer_interrupt && t->transferred > 0) { + hub_notify(t->hub); + } + else { + usb_devSignal(); + } } } @@ -142,20 +192,24 @@ static int usb_devsList(char *buffer, size_t size) static int usb_handleConnect(msg_t *msg, usb_connect_t *c) { - usb_drv_t *drv; + usb_drvpriv_t *drv; - if ((drv = malloc(sizeof(usb_drv_t))) == NULL) + drv = malloc(sizeof(usb_drvpriv_t)); + if (drv == NULL) { return -ENOMEM; + } - if ((drv->filters = malloc(sizeof(usb_device_id_t) * c->nfilters)) == NULL) { + drv->driver.filters = malloc(sizeof(usb_device_id_t) * c->nfilters); + if (drv->driver.filters == NULL) { free(drv); return -ENOMEM; } - drv->pid = msg->pid; - drv->port = c->port; - drv->nfilters = c->nfilters; - memcpy(drv->filters, msg->i.data, msg->i.size); + drv->type = usb_drvType_extrn; + drv->extrn.id = msg->pid; + drv->extrn.port = c->port; + drv->driver.nfilters = c->nfilters; + memcpy((void *)drv->driver.filters, msg->i.data, msg->i.size); usb_drvAdd(drv); /* TODO: handle orphaned devices */ @@ -166,7 +220,7 @@ static int usb_handleConnect(msg_t *msg, usb_connect_t *c) static int usb_handleOpen(usb_open_t *o, msg_t *msg) { - usb_drv_t *drv; + usb_drvpriv_t *drv; int pipe; hcd_t *hcd; @@ -207,23 +261,25 @@ static void usb_urbAsyncCompleted(usb_transfer_t *t) } t->state = urb_idle; - msgSend(t->port, &msg); + msgSend(t->extrn.port, &msg); usb_transferPut(t); } static void usb_urbSyncCompleted(usb_transfer_t *t) { - msg_t msg = t->msg; + msg_t msg = { 0 }; + msg.type = mtDevCtl; + msg.pid = t->extrn.pid; msg.o.err = (t->error != 0) ? -t->error : t->transferred; if ((t->direction == usb_dir_in) && (t->error == 0)) { - memcpy(msg.o.data, t->buffer, min(msg.o.size, t->transferred)); + memcpy(t->extrn.odata, t->buffer, min(t->extrn.osize, t->transferred)); } /* TODO: it should be non-blocking */ - msgRespond(usb_common.port, &msg, t->rid); + msgRespond(usb_common.port, &msg, t->extrn.rid); usb_transferFree(t); } @@ -240,10 +296,12 @@ static void usb_statusthr(void *arg) LIST_REMOVE(&usb_common.finished, t); mutexUnlock(usb_common.transferLock); - if (t->async) - usb_urbAsyncCompleted(t); - else - usb_urbSyncCompleted(t); + if (t->async) { + t->ops->urbAsyncCompleted(t); + } + else { + t->ops->urbSyncCompleted(t); + } } } @@ -308,6 +366,7 @@ int main(int argc, char *argv[]) { oid_t oid; int i; + usb_driver_t *drv; if (mutexCreate(&usb_common.transferLock) != 0) { USB_LOG("usb: Can't create mutex!\n"); @@ -315,7 +374,7 @@ int main(int argc, char *argv[]) } if (condCreate(&usb_common.finishedCond) != 0) { - USB_LOG("usb: Can't create mutex!\n"); + USB_LOG("usb: Can't create cond!\n"); return 1; } @@ -329,6 +388,17 @@ int main(int argc, char *argv[]) return 1; } + for (;;) { + drv = usb_registeredDriverPop(); + if (drv != NULL) { + USB_LOG("usb: Initializing driver as host-side: %s\n", drv->name); + usb_internalDriverInit(drv); + } + else { + break; + } + } + if (hub_init() != 0) { USB_LOG("usb: Fail to init hub driver!\n"); return 1; @@ -365,3 +435,36 @@ int main(int argc, char *argv[]) return 0; } + + +int usblibdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) +{ + usb_drvpriv_t *drvpriv = (usb_drvpriv_t *)drv->hostPriv; + int pipe; + hcd_t *hcd; + + hcd = hcd_find(usb_common.hcds, dev->locationID); + if (hcd == NULL) { + USB_LOG("usb: Failed to find dev: %d\n", dev->locationID); + return -EINVAL; + } + + pipe = usb_drvPipeOpen(drvpriv, hcd, dev->locationID, dev->interface, dir, type); + if (pipe < 0) { + return -EINVAL; + } + + return pipe; +} + + +static usb_transferOps_t usbprocdrv_transferOps = { + .urbSyncCompleted = usb_urbSyncCompleted, + .urbAsyncCompleted = usb_urbAsyncCompleted, +}; + + +const usb_transferOps_t *usbprocdrv_transferOpsGet(void) +{ + return &usbprocdrv_transferOps; +} diff --git a/usb/usbhost.h b/usb/usbhost.h index 08269ea..4588a8b 100644 --- a/usb/usbhost.h +++ b/usb/usbhost.h @@ -3,8 +3,8 @@ * * USB Host * - * Copyright 2021 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -19,11 +19,12 @@ #include #include + enum { urb_idle, urb_completed, urb_ongoing }; typedef struct { idnode_t linkage; - struct _usb_drv *drv; + struct usb_drvpriv *drv; usb_transfer_type_t type; usb_dir_t dir; @@ -41,13 +42,29 @@ static inline int usb_pipeid(usb_pipe_t *pipe) return pipe->linkage.id; } + +typedef struct usb_transfer_t usb_transfer_t; + + +typedef struct { + void (*urbSyncCompleted)(usb_transfer_t *t); + void (*urbAsyncCompleted)(usb_transfer_t *t); +} usb_transferOps_t; + + +const usb_transferOps_t *usblibdrv_transferOpsGet(void); + + +const usb_transferOps_t *usbprocdrv_transferOpsGet(void); + + /* Used to handle both internal and external transfers */ -typedef struct usb_transfer { - struct usb_transfer *next, *prev; +struct usb_transfer_t { + usb_transfer_t *next, *prev; usb_setup_packet_t *setup; unsigned async; - volatile int finished; + volatile bool finished; volatile int error; char *buffer; @@ -57,23 +74,43 @@ typedef struct usb_transfer { int direction; int pipeid; - /* Used only for URBs handling */ + usb_drvType_t recipient; + + /* Used only for URBs handling (recipient other than hcd) */ idnode_t linkage; int state; int refcnt; - unsigned long rid; - unsigned int port; - pid_t pid; - msg_t msg; + union { + struct { + size_t osize; + void *odata; + + unsigned long rid; + unsigned int port; + pid_t pid; + } extrn; + struct { + handle_t *finishedCond; + usb_driver_t *drv; + } intrn; + }; struct _usb_dev *hub; void *hcdpriv; -} usb_transfer_t; + + /* URB transfer on completion callbacks */ + const usb_transferOps_t *ops; +}; #define USB_LOG(fmt, ...) do { printf(fmt, ##__VA_ARGS__); } while (0); +#define USB_TRACE(fmt, ...) \ + if (0) { \ + printf("usb, %s: " fmt "\n", __func__ __VA_OPT__(, ) __VA_ARGS__); \ + } + int usb_memInit(void); @@ -96,7 +133,7 @@ void usb_freeAligned(void *addr, size_t size); void usb_transferFinished(usb_transfer_t *t, int status); -int usb_transferCheck(usb_transfer_t *t); +bool usb_transferCheck(usb_transfer_t *t); int usb_transferSubmit(usb_transfer_t *t, usb_pipe_t *pipe, handle_t *cond); @@ -107,4 +144,8 @@ void usb_transferFree(usb_transfer_t *t); void usb_transferPut(usb_transfer_t *t); + +int usblibdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir); + + #endif From 50c9489fe6069b8fe2c1bd2cbc9e4f5c83daaacd Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Mon, 2 Dec 2024 13:27:45 +0100 Subject: [PATCH 13/25] usb: add option to restrict to internal drivers only Adds options to exclude external driver logic from the usbhost driver if for instance no such driver is ever expected to be run. JIRA: RTOS-970 --- usb/drv.c | 2 ++ usb/hub.c | 1 - usb/usb.c | 96 +++++++++++++++++++++++++++++---------------------- usb/usbhost.h | 1 - 4 files changed, 56 insertions(+), 44 deletions(-) diff --git a/usb/drv.c b/usb/drv.c index 1f28ef3..c76e47f 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -555,6 +555,7 @@ static int _usb_handleUrbcmd(usb_drvpriv_t *drv, usb_urbcmd_t *urbcmd) } +#ifndef USB_INTERNAL_ONLY int usb_handleUrbcmd(msg_t *msg) { int ret; @@ -648,6 +649,7 @@ int usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) return ret; } +#endif void usb_drvPipeFree(usb_drvpriv_t *drv, usb_pipe_t *pipe) diff --git a/usb/hub.c b/usb/hub.c index f1032f2..97f7841 100644 --- a/usb/hub.c +++ b/usb/hub.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/usb/usb.c b/usb/usb.c index 116bb52..9fadf91 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include +#include #include "drv.h" #include "hcd.h" @@ -40,14 +40,17 @@ static struct { - char stack[N_STATUSTHRS][2048] __attribute__((aligned(8))); +#ifndef USB_INTERNAL_ONLY + char ustack[2048] __attribute__((aligned(8))); + uint32_t port; +#endif + char stack[N_STATUSTHRS - 1][2048] __attribute__((aligned(8))); handle_t transferLock; handle_t finishedCond; hcd_t *hcds; usb_drvpriv_t *drvs; usb_transfer_t *finished; int nhcd; - uint32_t port; } usb_common; @@ -183,13 +186,13 @@ void usb_transferFinished(usb_transfer_t *t, int status) } +#ifndef USB_INTERNAL_ONLY static int usb_devsList(char *buffer, size_t size) { return 0; } - static int usb_handleConnect(msg_t *msg, usb_connect_t *c) { usb_drvpriv_t *drv; @@ -284,28 +287,6 @@ static void usb_urbSyncCompleted(usb_transfer_t *t) } -static void usb_statusthr(void *arg) -{ - usb_transfer_t *t; - - for (;;) { - mutexLock(usb_common.transferLock); - while (usb_common.finished == NULL) - condWait(usb_common.finishedCond, usb_common.transferLock, 0); - t = usb_common.finished; - LIST_REMOVE(&usb_common.finished, t); - mutexUnlock(usb_common.transferLock); - - if (t->async) { - t->ops->urbAsyncCompleted(t); - } - else { - t->ops->urbSyncCompleted(t); - } - } -} - - static void usb_msgthr(void *arg) { unsigned port = (int)arg; @@ -362,9 +343,46 @@ static void usb_msgthr(void *arg) } +static usb_transferOps_t usbprocdrv_transferOps = { + .urbSyncCompleted = usb_urbSyncCompleted, + .urbAsyncCompleted = usb_urbAsyncCompleted, +}; + + +const usb_transferOps_t *usbprocdrv_transferOpsGet(void) +{ + return &usbprocdrv_transferOps; +} +#endif + + +static void usb_statusthr(void *arg) +{ + usb_transfer_t *t; + + for (;;) { + mutexLock(usb_common.transferLock); + while (usb_common.finished == NULL) + condWait(usb_common.finishedCond, usb_common.transferLock, 0); + t = usb_common.finished; + LIST_REMOVE(&usb_common.finished, t); + mutexUnlock(usb_common.transferLock); + + if (t->async) { + t->ops->urbAsyncCompleted(t); + } + else { + t->ops->urbSyncCompleted(t); + } + } +} + + int main(int argc, char *argv[]) { +#ifndef USB_INTERNAL_ONLY oid_t oid; +#endif int i; usb_driver_t *drv; @@ -409,6 +427,7 @@ int main(int argc, char *argv[]) return 1; } +#ifndef USB_INTERNAL_ONLY if (portCreate(&usb_common.port) != 0) { USB_LOG("usb: Can't create port!\n"); return 1; @@ -422,16 +441,21 @@ int main(int argc, char *argv[]) return 1; } - for (i = 0; i < N_STATUSTHRS; i++) { + if (beginthread(usb_msgthr, MSGTHR_PRIO, &usb_common.ustack, sizeof(usb_common.ustack), (void *)usb_common.port) != 0) { + USB_LOG("usb: Fail to run msgthr!\n"); + return 1; + } +#endif + + for (i = 0; i < N_STATUSTHRS - 1; i++) { if (beginthread(usb_statusthr, STATUSTHR_PRIO, &usb_common.stack[i], sizeof(usb_common.stack[i]), NULL) != 0) { USB_LOG("usb: Fail to init hub driver!\n"); return 1; } } - priority(MSGTHR_PRIO); - - usb_msgthr((void *)usb_common.port); + priority(STATUSTHR_PRIO); + usb_statusthr(NULL); return 0; } @@ -456,15 +480,3 @@ int usblibdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t ty return pipe; } - - -static usb_transferOps_t usbprocdrv_transferOps = { - .urbSyncCompleted = usb_urbSyncCompleted, - .urbAsyncCompleted = usb_urbAsyncCompleted, -}; - - -const usb_transferOps_t *usbprocdrv_transferOpsGet(void) -{ - return &usbprocdrv_transferOps; -} diff --git a/usb/usbhost.h b/usb/usbhost.h index 4588a8b..d0a071e 100644 --- a/usb/usbhost.h +++ b/usb/usbhost.h @@ -15,7 +15,6 @@ #define _USB_HOST_H_ #include -#include #include #include From 7807d8b67aa4cda4fc479c1da8233a694d4a119a Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Tue, 17 Dec 2024 10:21:37 +0100 Subject: [PATCH 14/25] usb/hcd: avoid potential race by initializing roothub before hcd init If hcd became operational before returning from hcd init, it could try to access hcd->roothub while it was still uninitialized JIRA: RTOS-970 --- usb/hcd.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/usb/hcd.c b/usb/hcd.c index 7af0bc2..9d425c2 100644 --- a/usb/hcd.c +++ b/usb/hcd.c @@ -153,7 +153,7 @@ static int hcd_roothubInit(hcd_t *hcd) hub->port = 1; hub->hcd = hcd; - return usb_devEnumerate(hub); + return EOK; } @@ -162,31 +162,42 @@ hcd_t *hcd_init(void) const hcd_info_t *info; const hcd_ops_t *ops; hcd_t *hcd, *res = NULL; - int nhcd, i; + int nhcd, i, ret; int num = 1; if ((nhcd = hcd_getInfo(&info)) <= 0) return NULL; for (i = 0; i < nhcd; i++) { - if ((ops = hcd_lookup(info[i].type)) == NULL) { + ops = hcd_lookup(info[i].type); + if (ops == NULL) { USB_LOG("usb-hcd: No ops found for hcd type %s\n", info[i].type); continue; } - if ((hcd = hcd_create(ops, &info[i], num++)) == NULL) { + hcd = hcd_create(ops, &info[i], num++); + if (hcd == NULL) { USB_LOG("usb-hcd: Not enough memory to allocate hcd type: %s\n", info[i].type); return res; } - if (hcd->ops->init(hcd) != 0) { + ret = hcd_roothubInit(hcd); + if (ret != 0) { + USB_LOG("usb-hcd: Fail to initialize roothub: %s\n", info[i].type); + hcd_free(hcd); + continue; + } + + ret = hcd->ops->init(hcd); + if (ret != 0) { USB_LOG("usb-hcd: Fail to initialize hcd type: %s\n", info[i].type); hcd_free(hcd); continue; } - if (hcd_roothubInit(hcd) != 0) { - USB_LOG("usb-hcd: Fail to initialize roothub: %s\n", info[i].type); + ret = usb_devEnumerate(hcd->roothub); + if (ret != 0) { + USB_LOG("usb-hcd: Fail to enumerate devices: %s\n", info[i].type); hcd_free(hcd); continue; } From 61db7c564e15959f0c00f3e51b72452098b6a453 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 23 Apr 2025 11:42:47 +0200 Subject: [PATCH 15/25] libusb: fix insertion result not being passed to msg sender JIRA: RTOS-1024 --- libusb/procdriver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libusb/procdriver.c b/libusb/procdriver.c index a57e995..c7345a2 100644 --- a/libusb/procdriver.c +++ b/libusb/procdriver.c @@ -76,7 +76,7 @@ static void usb_thread(void *arg) switch (umsg->type) { case usb_msg_insertion: - drv->handlers.insertion(drv, &umsg->insertion); + msg.o.err = drv->handlers.insertion(drv, &umsg->insertion); break; case usb_msg_deletion: drv->handlers.deletion(drv, &umsg->deletion); From 5294de4f8da83dfef77633aafbad80cc37b0d2c8 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Tue, 18 Mar 2025 12:08:30 +0100 Subject: [PATCH 16/25] usb: pass device insertion result from driver to usbhost Drivers can now return some useful information back to the usbhost about the state of inserted device JIRA: RTOS-1024 --- libusb/procdriver.c | 42 ++++++++++++++++++------------------------ libusb/usbdriver.h | 20 +++++++++++++++----- usb/dev.c | 9 +++++++-- usb/drv.c | 9 +++++++-- usb/drv.h | 2 +- 5 files changed, 48 insertions(+), 34 deletions(-) diff --git a/libusb/procdriver.c b/libusb/procdriver.c index c7345a2..9f603df 100644 --- a/libusb/procdriver.c +++ b/libusb/procdriver.c @@ -65,18 +65,25 @@ static void usb_thread(void *arg) usb_driver_t *drv = (usb_driver_t *)arg; msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; + usb_event_insertion_t event; int ret; + msg_rid_t rid; for (;;) { - ret = usb_eventsWait(usbprocdrv_common.drvport, &msg); - if (ret < 0) { - fprintf(stderr, "usbdrv: error when receiving event from host\n"); - continue; - } + do { + ret = msgRecv(usbprocdrv_common.drvport, &msg, &rid); + if (ret < 0 && ret != -EINTR) { + fprintf(stderr, "usbdrv: error when receiving event from host\n"); + continue; + } + } while (ret == -EINTR); switch (umsg->type) { case usb_msg_insertion: - msg.o.err = drv->handlers.insertion(drv, &umsg->insertion); + msg.o.err = drv->handlers.insertion(drv, &umsg->insertion, &event); + if (msg.o.err == 0) { + memcpy(msg.o.raw, &event, sizeof(usb_event_insertion_t)); + } break; case usb_msg_deletion: drv->handlers.deletion(drv, &umsg->deletion); @@ -88,6 +95,11 @@ static void usb_thread(void *arg) fprintf(stderr, "usbdrv: unknown msg type\n"); break; } + + ret = msgRespond(usbprocdrv_common.drvport, &msg, rid); + if (ret < 0) { + fprintf(stderr, "usbdrv: error when replying to host\n"); + } } } @@ -150,24 +162,6 @@ int usb_driverProcRun(usb_driver_t *drv, void *args) } -int usb_eventsWait(int port, msg_t *msg) -{ - msg_rid_t rid; - int err; - - do { - err = msgRecv(port, msg, &rid); - if (err < 0 && err != -EINTR) - return -1; - } while (err == -EINTR); - - if (msgRespond(port, msg, rid) < 0) - return -1; - - return 0; -} - - static int usbprocdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir) { msg_t msg = { 0 }; diff --git a/libusb/usbdriver.h b/libusb/usbdriver.h index 91001f7..48e6e88 100644 --- a/libusb/usbdriver.h +++ b/libusb/usbdriver.h @@ -23,6 +23,9 @@ #include #include +#define USB_DRVNAME_MAX 10 +#define USB_STR_MAX 255 + #define USBDRV_ANY ((unsigned)-1) @@ -146,13 +149,23 @@ typedef struct { } usb_modeswitch_t; +typedef struct { + bool deviceCreated; /* Set to true by the insertion handler if a device file for the inserted device has been created */ + char devPath[32]; /* Path to device file */ +} usb_event_insertion_t; + + typedef struct usb_driver usb_driver_t; typedef int (*usb_completion_handler_t)(usb_driver_t *drv, usb_completion_t *completion, const char *data, size_t len); -typedef int (*usb_insertion_handler_t)(usb_driver_t *drv, usb_devinfo_t *devinfo); +/* + * Returns 0 if insertion succeeds. Implementations can assume `event` is a valid pointer provided by the caller. + * The event struct is populated only if insertion succeeds (its contents must be valid after the call) + */ +typedef int (*usb_insertion_handler_t)(usb_driver_t *drv, usb_devinfo_t *devinfo, usb_event_insertion_t *event); typedef int (*usb_deletion_handler_t)(usb_driver_t *drv, usb_deletion_t *deletion); @@ -186,7 +199,7 @@ typedef struct { struct usb_driver { usb_driver_t *next, *prev; - char name[10]; + char name[USB_DRVNAME_MAX]; usb_handlers_t handlers; usb_driverOps_t ops; const usb_pipeOps_t *pipeOps; @@ -204,9 +217,6 @@ int usb_modeswitchHandle(usb_driver_t *drv, usb_devinfo_t *dev, const usb_modesw const usb_modeswitch_t *usb_modeswitchFind(uint16_t vid, uint16_t pid, const usb_modeswitch_t *modes, int nmodes); -int usb_eventsWait(int port, msg_t *msg); - - int usb_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t type, usb_dir_t dir); diff --git a/usb/dev.c b/usb/dev.c index fc26898..0c82927 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -486,7 +486,8 @@ static int usb_getAllStringDescs(usb_dev_t *dev) int usb_devEnumerate(usb_dev_t *dev) { - int addr; + int addr, iface; + usb_event_insertion_t insertion = { 0 }; if (usb_genLocationID(dev) < 0) { USB_LOG("usb: Fail to generate location ID\n"); @@ -533,11 +534,15 @@ int usb_devEnumerate(usb_dev_t *dev) if (hub_conf(dev) != 0) return -1; } - else if (usb_drvBind(dev) != 0) { + else if (usb_drvBind(dev, &insertion, &iface) != 0) { USB_LOG("usb: Fail to match drivers for device\n"); /* TODO: make device orphaned */ } + if (insertion.deviceCreated) { + fprintf(stderr, "usb: Driver bound to device with addr %d: %s\n", dev->address, insertion.devPath); + } + return 0; } diff --git a/usb/drv.c b/usb/drv.c index c76e47f..02c9642 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -357,7 +357,7 @@ int usb_drvUnbind(usb_drvpriv_t *drv, usb_dev_t *dev, int iface) } -int usb_drvBind(usb_dev_t *dev) +int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) { usb_drvpriv_t *drv; @@ -380,16 +380,21 @@ int usb_drvBind(usb_dev_t *dev) if (drv != NULL) { dev->ifs[i].driver = drv; umsg->insertion.interface = i; + *iface = i; switch (drv->type) { case usb_drvType_intrn: - err = drv->driver.handlers.insertion(&drv->driver, &umsg->insertion); + err = drv->driver.handlers.insertion(&drv->driver, &umsg->insertion, event); break; case usb_drvType_extrn: err = msgSend(drv->extrn.port, &msg); if (err == 0) { err = msg.o.err; } + + if (err == 0) { + memcpy(event, msg.o.raw, sizeof(usb_event_insertion_t)); + } break; default: USB_LOG("usb: unexpected driver type: %d\n", drv->type); diff --git a/usb/drv.h b/usb/drv.h index 7e6442b..29e9bf5 100644 --- a/usb/drv.h +++ b/usb/drv.h @@ -58,7 +58,7 @@ void usb_libDrvDestroy(usb_driver_t *drv); void usb_drvAdd(usb_drvpriv_t *drv); -int usb_drvBind(usb_dev_t *dev); +int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface); int usb_drvUnbind(usb_drvpriv_t *drv, usb_dev_t *dev, int iface); From 7e41edf451d0a183077aa87b35034f3b6e77120c Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 27 Mar 2025 15:38:34 +0100 Subject: [PATCH 17/25] libusb: move external headers to `include` dir JIRA: RTOS-1024 --- libusb/Makefile | 3 +-- libusb/{ => include}/cdc.h | 0 libusb/{ => include}/cdc_client.h | 0 libusb/{ => include}/hid.h | 0 libusb/{ => include}/hid_client.h | 0 libusb/{ => include}/usb.h | 0 libusb/{ => include}/usbclient.h | 0 libusb/{ => include}/usbdriver.h | 0 libusb/{ => include}/usbprocdriver.h | 0 9 files changed, 1 insertion(+), 2 deletions(-) rename libusb/{ => include}/cdc.h (100%) rename libusb/{ => include}/cdc_client.h (100%) rename libusb/{ => include}/hid.h (100%) rename libusb/{ => include}/hid_client.h (100%) rename libusb/{ => include}/usb.h (100%) rename libusb/{ => include}/usbclient.h (100%) rename libusb/{ => include}/usbdriver.h (100%) rename libusb/{ => include}/usbprocdriver.h (100%) diff --git a/libusb/Makefile b/libusb/Makefile index f471aee..55c618d 100644 --- a/libusb/Makefile +++ b/libusb/Makefile @@ -1,12 +1,11 @@ # # Makefile for Phoenix-RTOS libusb # -# Copyright 2021 Phoenix Systems +# Copyright 2025 Phoenix Systems # NAME := libusb LOCAL_PATH := $(call my-dir) -HEADERS := $(wildcard $(LOCAL_PATH)*.h) LOCAL_SRCS := cdc_client.c hid_client.c driver.c procdriver.c LOCAL_CFLAGS := -I$(LOCAL_PATH) diff --git a/libusb/cdc.h b/libusb/include/cdc.h similarity index 100% rename from libusb/cdc.h rename to libusb/include/cdc.h diff --git a/libusb/cdc_client.h b/libusb/include/cdc_client.h similarity index 100% rename from libusb/cdc_client.h rename to libusb/include/cdc_client.h diff --git a/libusb/hid.h b/libusb/include/hid.h similarity index 100% rename from libusb/hid.h rename to libusb/include/hid.h diff --git a/libusb/hid_client.h b/libusb/include/hid_client.h similarity index 100% rename from libusb/hid_client.h rename to libusb/include/hid_client.h diff --git a/libusb/usb.h b/libusb/include/usb.h similarity index 100% rename from libusb/usb.h rename to libusb/include/usb.h diff --git a/libusb/usbclient.h b/libusb/include/usbclient.h similarity index 100% rename from libusb/usbclient.h rename to libusb/include/usbclient.h diff --git a/libusb/usbdriver.h b/libusb/include/usbdriver.h similarity index 100% rename from libusb/usbdriver.h rename to libusb/include/usbdriver.h diff --git a/libusb/usbprocdriver.h b/libusb/include/usbprocdriver.h similarity index 100% rename from libusb/usbprocdriver.h rename to libusb/include/usbprocdriver.h From 29f3c918cc683ad6683e6cdabf71431d2ce790d8 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 10 Apr 2025 15:35:41 +0200 Subject: [PATCH 18/25] unify libusb/usb log prints JIRA: RTOS-1024 --- libusb/log.h | 30 ++++++++++++++++++++++++++++++ libusb/procdriver.c | 14 ++++++++++---- usb/dev.c | 41 +++++++++++++++++++++-------------------- usb/drv.c | 33 ++++++++++++++++++--------------- usb/hcd.c | 16 +++++++++++----- usb/hub.c | 23 ++++++++++++++--------- usb/log.h | 28 ++++++++++++++++++++++++++++ usb/usb.c | 41 +++++++++++++++++++++-------------------- usb/usbhost.h | 8 -------- 9 files changed, 153 insertions(+), 81 deletions(-) create mode 100644 libusb/log.h create mode 100644 usb/log.h diff --git a/libusb/log.h b/libusb/log.h new file mode 100644 index 0000000..8ec52ab --- /dev/null +++ b/libusb/log.h @@ -0,0 +1,30 @@ + +/* + * Phoenix-RTOS + * + * Libusb driver interface + * + * libusb/log.h + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + + +#ifndef _LIBUSB_LOG_H_ +#define _LIBUSB_LOG_H_ + + +#define LIBUSB_LOG_TAG "libusb" +#define LIBUSB_TRACE 0 + +/* clang-format off */ +#define log_msg(fmt, ...) do { fprintf(stderr, LIBUSB_LOG_TAG ": " fmt, ##__VA_ARGS__); } while (0) +#define log_trace(fmt, ...) do { if (LIBUSB_TRACE != 0) log_msg("%s: " fmt, __func__ __VA_OPT__(, ) ##__VA_ARGS__); } while (0) +#define log_error(fmt, ...) log_msg(fmt, ##__VA_ARGS__) +/* clang-format on */ + + +#endif diff --git a/libusb/procdriver.c b/libusb/procdriver.c index 9f603df..284dd46 100644 --- a/libusb/procdriver.c +++ b/libusb/procdriver.c @@ -20,6 +20,8 @@ #include #include +#include "log.h" + #ifndef USB_N_UMSG_THREADS #define USB_N_UMSG_THREADS 2 @@ -30,6 +32,10 @@ #endif +#undef LIBUSB_LOG_TAG +#define LIBUSB_LOG_TAG "libusb(procdriver)" + + static usb_pipeOps_t usbprocdrv_pipeOps; @@ -73,7 +79,7 @@ static void usb_thread(void *arg) do { ret = msgRecv(usbprocdrv_common.drvport, &msg, &rid); if (ret < 0 && ret != -EINTR) { - fprintf(stderr, "usbdrv: error when receiving event from host\n"); + log_error("error when receiving event from host\n"); continue; } } while (ret == -EINTR); @@ -92,13 +98,13 @@ static void usb_thread(void *arg) drv->handlers.completion(drv, &umsg->completion, msg.i.data, msg.i.size); break; default: - fprintf(stderr, "usbdrv: unknown msg type\n"); + log_error("unknown msg type\n"); break; } ret = msgRespond(usbprocdrv_common.drvport, &msg, rid); if (ret < 0) { - fprintf(stderr, "usbdrv: error when replying to host\n"); + log_error("error when replying to host\n"); } } } @@ -150,7 +156,7 @@ int usb_driverProcRun(usb_driver_t *drv, void *args) for (i = 0; i < USB_N_UMSG_THREADS - 1; i++) { ret = beginthread(usb_thread, USB_UMSG_PRIO, usbprocdrv_common.ustack[i], sizeof(usbprocdrv_common.ustack[i]), drv); if (ret < 0) { - fprintf(stderr, "usbdrv: fail to beginthread ret: %d\n", ret); + log_error("fail to beginthread ret: %d\n", ret); return -1; } } diff --git a/usb/dev.c b/usb/dev.c index 0c82927..1a22d8e 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -27,6 +27,7 @@ #include "drv.h" #include "hcd.h" #include "hub.h" +#include "log.h" #define USBDEV_BUF_SIZE 0x200 @@ -244,7 +245,7 @@ static int usb_getConfiguration(usb_dev_t *dev) uint8_t len = ((struct usb_desc_header *)ptr)->bLength; if ((len < sizeof(struct usb_desc_header)) || (len > size)) { - USB_LOG("usb: Invalid descriptor size: %u\n", len); + log_error("Invalid descriptor size: %u\n", len); break; } @@ -268,7 +269,7 @@ static int usb_getConfiguration(usb_dev_t *dev) } } else { - USB_LOG("usb: Interface descriptor with invalid size\n"); + log_error("Interface descriptor with invalid size\n"); ret = -1; } break; @@ -296,7 +297,7 @@ static int usb_getConfiguration(usb_dev_t *dev) } } else { - USB_LOG("usb: Endpoint descriptor with invalid size\n"); + log_error("Endpoint descriptor with invalid size\n"); ret = -1; } break; @@ -309,7 +310,7 @@ static int usb_getConfiguration(usb_dev_t *dev) dev->desc.bDeviceProtocol = ((usb_interface_association_desc_t *)ptr)->bFunctionProtocol; } else { - USB_LOG("usb: Interface assoctiation descriptor with invalid size\n"); + log_error("Interface assoctiation descriptor with invalid size\n"); ret = -1; } break; @@ -319,7 +320,7 @@ static int usb_getConfiguration(usb_dev_t *dev) break; default: - USB_LOG("usb: Ignoring unkonown descriptor type: 0x%02x\n", ((struct usb_desc_header *)ptr)->bDescriptorType); + log_error("Ignoring unkonown descriptor type: 0x%02x\n", ((struct usb_desc_header *)ptr)->bDescriptorType); break; } @@ -336,7 +337,7 @@ static int usb_getConfiguration(usb_dev_t *dev) } if (ret != 0) { - USB_LOG("usb: Fail to parse interface descriptors\n"); + log_error("Fail to parse interface descriptors\n"); free(dev->ifs); dev->ifs = NULL; dev->nifs = 0; @@ -357,7 +358,7 @@ static int usb_getStringDesc(usb_dev_t *dev, char **buf, int index) size_t asciisz; if (usb_getDescriptor(dev, USB_DESC_STRING, index, (char *)&desc, sizeof(desc)) < 0) { - USB_LOG("usb: Fail to get string descriptor\n"); + log_error("Fail to get string descriptor\n"); return -1; } asciisz = (desc.bLength - 2) / 2; @@ -490,12 +491,12 @@ int usb_devEnumerate(usb_dev_t *dev) usb_event_insertion_t insertion = { 0 }; if (usb_genLocationID(dev) < 0) { - USB_LOG("usb: Fail to generate location ID\n"); + log_error("Fail to generate location ID\n"); return -1; } if (usb_getDevDesc(dev) < 0) { - USB_LOG("usb: Fail to get device descriptor\n"); + log_error("Fail to get device descriptor\n"); return -1; } @@ -503,22 +504,22 @@ int usb_devEnumerate(usb_dev_t *dev) dev->ctrlPipe->maxPacketLen = dev->desc.bMaxPacketSize0; if ((addr = hcd_addrAlloc(dev->hcd)) < 0) { - USB_LOG("usb: Fail to add device to hcd\n"); + log_error("Fail to add device to hcd\n"); return -1; } if (usb_setAddress(dev, addr) < 0) { - USB_LOG("usb: Fail to set device address\n"); + log_error("Fail to set device address\n"); return -1; } if (usb_getDevDesc(dev) < 0) { - USB_LOG("usb: Fail to get device descriptor\n"); + log_error("Fail to get device descriptor\n"); return -1; } if (usb_getConfiguration(dev) < 0) { - USB_LOG("usb: Fail to get configuration descriptor\n"); + log_error("Fail to get configuration descriptor\n"); return -1; } @@ -527,7 +528,7 @@ int usb_devEnumerate(usb_dev_t *dev) if (!usb_isRoothub(dev)) usb_devSetChild(dev->hub, dev->port, dev); - USB_LOG("usb: New device addr: %d locationID: %08x %s, %s\n", dev->address, dev->locationID, + log_info("New device addr: %d locationID: %08x %s, %s\n", dev->address, dev->locationID, dev->manufacturer, dev->product); if (dev->desc.bDeviceClass == USB_CLASS_HUB) { @@ -535,12 +536,12 @@ int usb_devEnumerate(usb_dev_t *dev) return -1; } else if (usb_drvBind(dev, &insertion, &iface) != 0) { - USB_LOG("usb: Fail to match drivers for device\n"); + log_msg("Fail to match drivers for device\n"); /* TODO: make device orphaned */ } if (insertion.deviceCreated) { - fprintf(stderr, "usb: Driver bound to device with addr %d: %s\n", dev->address, insertion.devPath); + log_info("Driver bound to device with addr %d: %s\n", dev->address, insertion.devPath); } return 0; @@ -596,7 +597,7 @@ usb_dev_t *usb_devFind(usb_dev_t *hub, int locationID) void usb_devDisconnected(usb_dev_t *dev, bool silent) { if (!silent) { - printf("usb: Device disconnected addr %d locationID: %08x\n", dev->address, dev->locationID); + log_info("Device disconnected addr %d locationID: %08x\n", dev->address, dev->locationID); } usb_devSetChild(dev->hub, dev->port, NULL); usb_devUnbind(dev); @@ -619,20 +620,20 @@ int usb_isRoothub(usb_dev_t *dev) int usb_devInit(void) { if (mutexCreate(&usbdev_common.lock) != 0) { - USB_LOG("usbdev: Can't create mutex!\n"); + log_error("Can't create mutex!\n"); return -ENOMEM; } if (condCreate(&usbdev_common.cond) != 0) { resourceDestroy(usbdev_common.lock); - USB_LOG("usbdev: Can't create cond!\n"); + log_error("Can't create cond!\n"); return -ENOMEM; } if ((usbdev_common.setupBuf = usb_alloc(USBDEV_BUF_SIZE)) == NULL) { resourceDestroy(usbdev_common.lock); resourceDestroy(usbdev_common.cond); - USB_LOG("usbdev: Fail to allocate buffer!\n"); + log_error("Fail to allocate buffer!\n"); return -ENOMEM; } diff --git a/usb/drv.c b/usb/drv.c index 02c9642..18535f5 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -26,7 +26,10 @@ #include "drv.h" #include "hcd.h" +#include "log.h" +#undef USB_LOG_TAG +#define USB_LOG_TAG "usbdrv" struct { handle_t lock; @@ -107,12 +110,12 @@ static usb_pipe_t *_usb_drvPipeOpen(usb_drvpriv_t *drv, hcd_t *hcd, int location int i; if ((dev = usb_devFind(hcd->roothub, locationID)) == NULL) { - USB_LOG("usb: Fail to find device\n"); + log_error("Fail to find device\n"); return NULL; } if (dev->nifs < ifaceID) { - USB_LOG("usb: Fail to find iface\n"); + log_error("Fail to find iface\n"); return NULL; } @@ -397,7 +400,7 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) } break; default: - USB_LOG("usb: unexpected driver type: %d\n", drv->type); + log_error("unexpected driver type: %d\n", drv->type); break; } @@ -592,7 +595,7 @@ static int _usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) drv = _usb_drvFind(msg->pid); if (drv == NULL) { - USB_LOG("usb: driver pid %d does not exist!\n", msg->pid); + log_error("driver pid %d does not exist!\n", msg->pid); return -EINVAL; } @@ -607,7 +610,7 @@ static int _usb_handleUrb(msg_t *msg, unsigned int port, unsigned long rid) t->extrn.osize = msg->o.size; } else { - USB_LOG("usb: urb handler/recipient type mismatch\n"); + log_error("urb handler/recipient type mismatch\n"); return -EINVAL; } t->pipeid = urb->pipe; @@ -673,13 +676,13 @@ int usb_drvInit(void) ret = mutexCreate(&usbdrv_common.lock); if (ret != 0) { - USB_LOG("usbdrv: Can't create mutex!\n"); + log_error("Can't create mutex!\n"); return -ENOMEM; } ret = condCreate(&usbdrv_common.drvAddedCond); if (ret != 0) { - USB_LOG("usbdrv: Can't create cond!\n"); + log_error("Can't create cond!\n"); resourceDestroy(usbdrv_common.lock); return -ENOMEM; } @@ -707,7 +710,7 @@ static int usblibdrv_handleUrb(usb_driver_t *drv, usb_urb_t *urb, void *data) t->intrn.drv = drv; } else { - USB_LOG("usb: urb handler/recipient type mismatch\n"); + log_error("urb handler/recipient type mismatch\n"); usb_transferFree(t); return -EINVAL; } @@ -749,14 +752,14 @@ static int usblibdrv_handleUrb(usb_driver_t *drv, usb_urb_t *urb, void *data) static int usblibdrv_urbSubmitSync(usb_driver_t *drv, usb_urb_t *urb, void *data) { - USB_TRACE("") + log_trace(""); return usblibdrv_handleUrb(drv, urb, data); } static int usblibdrv_urbTransferAsync(usb_driver_t *drv, unsigned pipe, unsigned urbid, size_t size, usb_setup_packet_t *setup) { - USB_TRACE("") + log_trace(""); usb_urbcmd_t urbcmd = { 0 }; usb_drvpriv_t *drvpriv = (usb_drvpriv_t *)drv->hostPriv; int ret; @@ -780,14 +783,14 @@ static int usblibdrv_urbTransferAsync(usb_driver_t *drv, unsigned pipe, unsigned static void usblibdrv_urbSyncCompleted(usb_transfer_t *t) { - USB_TRACE("") + log_trace(""); condSignal(*t->intrn.finishedCond); } static void usblibdrv_urbAsyncCompleted(usb_transfer_t *t) { - USB_TRACE("") + log_trace(""); usb_completion_t c = { 0 }; usb_driver_t *drv = t->intrn.drv; void *data = NULL; @@ -811,7 +814,7 @@ static void usblibdrv_urbAsyncCompleted(usb_transfer_t *t) static int usblibdrv_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_dir_t dir, size_t size, int type) { - USB_TRACE("") + log_trace(""); usb_urb_t urb = { 0 }; urb.pipe = pipe; urb.type = type; @@ -825,7 +828,7 @@ static int usblibdrv_urbAlloc(usb_driver_t *drv, unsigned pipe, void *data, usb_ static int usblibdrv_urbFree(usb_driver_t *drv, unsigned pipe, unsigned urb) { - USB_TRACE("") + log_trace(""); usb_urbcmd_t urbcmd = { 0 }; usb_drvpriv_t *drvpriv = (usb_drvpriv_t *)drv->hostPriv; int ret; @@ -879,6 +882,6 @@ void usb_libDrvDestroy(usb_driver_t *drv) int ret; ret = drv->ops.destroy(drv); if (ret < 0) { - USB_LOG("usb: driver destroy failed: %d\n", ret); + log_error("driver destroy failed: %d\n", ret); } } diff --git a/usb/hcd.c b/usb/hcd.c index 9d425c2..a61cf55 100644 --- a/usb/hcd.c +++ b/usb/hcd.c @@ -21,6 +21,12 @@ #include "dev.h" #include "hub.h" #include "hcd.h" +#include "log.h" + + +#undef USB_LOG_TAG +#define USB_LOG_TAG "usb-hcd" + struct hcd_ops_node { struct hcd_ops_node *prev, *next; @@ -171,33 +177,33 @@ hcd_t *hcd_init(void) for (i = 0; i < nhcd; i++) { ops = hcd_lookup(info[i].type); if (ops == NULL) { - USB_LOG("usb-hcd: No ops found for hcd type %s\n", info[i].type); + log_error("No ops found for hcd type %s\n", info[i].type); continue; } hcd = hcd_create(ops, &info[i], num++); if (hcd == NULL) { - USB_LOG("usb-hcd: Not enough memory to allocate hcd type: %s\n", info[i].type); + log_error("Not enough memory to allocate hcd type: %s\n", info[i].type); return res; } ret = hcd_roothubInit(hcd); if (ret != 0) { - USB_LOG("usb-hcd: Fail to initialize roothub: %s\n", info[i].type); + log_error("Fail to initialize roothub: %s\n", info[i].type); hcd_free(hcd); continue; } ret = hcd->ops->init(hcd); if (ret != 0) { - USB_LOG("usb-hcd: Fail to initialize hcd type: %s\n", info[i].type); + log_error("Fail to initialize hcd type: %s\n", info[i].type); hcd_free(hcd); continue; } ret = usb_devEnumerate(hcd->roothub); if (ret != 0) { - USB_LOG("usb-hcd: Fail to enumerate devices: %s\n", info[i].type); + log_error("Fail to enumerate devices: %s\n", info[i].type); hcd_free(hcd); continue; } diff --git a/usb/hub.c b/usb/hub.c index 97f7841..f8a265d 100644 --- a/usb/hub.c +++ b/usb/hub.c @@ -31,6 +31,7 @@ #include "drv.h" #include "hcd.h" #include "dev.h" +#include "log.h" #define HUB_ENUM_RETRIES 3 #define HUB_DEBOUNCE_STABLE 100000 @@ -39,6 +40,10 @@ #define HUB_TT_POLL_DELAY_MS 1000000 +#undef USB_LOG_TAG +#define USB_LOG_TAG "usbhub" + + typedef struct _hub_event { struct _hub_event *next, *prev; usb_dev_t *hub; @@ -143,20 +148,20 @@ static int hub_interruptInit(usb_dev_t *hub) usb_transfer_t *t; if ((t = calloc(1, sizeof(usb_transfer_t))) == NULL) { - USB_LOG("hub: Out of memory!\n"); + log_error("Out of memory!\n"); return -ENOMEM; } if ((t->buffer = usb_alloc(sizeof(uint32_t))) == NULL) { free(t); - USB_LOG("hub: Out of memory!\n"); + log_error("Out of memory!\n"); return -ENOMEM; } if ((hub->irqPipe = usb_pipeOpen(hub, 0, usb_dir_in, usb_transfer_interrupt)) == NULL) { usb_free(t->buffer, sizeof(uint32_t)); free(t); - USB_LOG("hub: Fail to open interrupt pipe!\n"); + log_error("Fail to open interrupt pipe!\n"); return -ENOMEM; } @@ -290,7 +295,7 @@ static void hub_devConnected(usb_dev_t *hub, int port) int retries = HUB_ENUM_RETRIES; if ((dev = usb_devAlloc()) == NULL) { - USB_LOG("hub: Not enough memory to allocate a new device!\n"); + log_error("Not enough memory to allocate a new device!\n"); return; } @@ -300,7 +305,7 @@ static void hub_devConnected(usb_dev_t *hub, int port) do { if ((ret = hub_portReset(hub, port, &status)) < 0) { - USB_LOG("hub: fail to reset port %d\n", port); + log_error("fail to reset port %d\n", port); break; } @@ -462,12 +467,12 @@ int hub_conf(usb_dev_t *hub) int i; if (hub_setConf(hub, 1) < 0) { - USB_LOG("hub: Fail to set configuration!\n"); + log_error("Fail to set configuration!\n"); return -EINVAL; } if (hub_getDesc(hub, buf, sizeof(buf)) < 0) { - USB_LOG("hub: Fail to get descriptor\n"); + log_error("Fail to get descriptor\n"); return -EINVAL; } @@ -475,13 +480,13 @@ int hub_conf(usb_dev_t *hub) desc = (usb_hub_desc_t *)buf; hub->nports = min(USB_HUB_MAX_PORTS, desc->bNbrPorts); if ((hub->devs = calloc(hub->nports, sizeof(usb_dev_t *))) == NULL) { - USB_LOG("hub: Out of memory!\n"); + log_error("Out of memory!\n"); return -ENOMEM; } for (i = 0; i < hub->nports; i++) { if (hub_setPortPower(hub, i + 1) < 0) { - USB_LOG("hub: Fail to set port %d power!\n", i + 1); + log_error("Fail to set port %d power!\n", i + 1); free(hub->devs); return -EINVAL; } diff --git a/usb/log.h b/usb/log.h new file mode 100644 index 0000000..b9946e0 --- /dev/null +++ b/usb/log.h @@ -0,0 +1,28 @@ +/* + * Phoenix-RTOS + * + * usb/log.h + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _USB_LOG_H_ +#define _USB_LOG_H_ + +#define USB_LOG_TAG "usb" +#define USB_TRACE 0 + +/* clang-format off */ +#define log_info(fmt, ...) do { fprintf(stdout, USB_LOG_TAG ": " fmt, ##__VA_ARGS__); } while (0) +#define log_msg(fmt, ...) do { fprintf(stderr, USB_LOG_TAG ": " fmt, ##__VA_ARGS__); } while (0) +#define log_trace(fmt, ...) do { if (USB_TRACE != 0) log_msg("%s: " fmt, __func__ __VA_OPT__(, ) ##__VA_ARGS__); } while (0) +#define log_error(fmt, ...) log_msg(fmt, ##__VA_ARGS__) +/* clang-format on */ + +#endif diff --git a/usb/usb.c b/usb/usb.c index 9fadf91..38fd303 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -33,6 +33,7 @@ #include "drv.h" #include "hcd.h" #include "hub.h" +#include "log.h" #define N_STATUSTHRS 1 #define STATUSTHR_PRIO 3 @@ -66,7 +67,7 @@ static int usb_internalDriverInit(usb_driver_t *driver) priv = malloc(sizeof(usb_drvpriv_t)); if (priv == NULL) { - USB_LOG("usb: malloc failed!\n"); + log_error("malloc failed!\n"); usb_libDrvDestroy(driver); return -ENOMEM; } @@ -75,7 +76,7 @@ static int usb_internalDriverInit(usb_driver_t *driver) ret = mutexCreate(&priv->intrn.transferLock); if (ret != 0) { - USB_LOG("usb: Can't create mutex!\n"); + log_error("Can't create mutex!\n"); free(priv); usb_libDrvDestroy(driver); return -ENOMEM; @@ -83,7 +84,7 @@ static int usb_internalDriverInit(usb_driver_t *driver) ret = condCreate(&priv->intrn.finishedCond); if (ret != 0) { - USB_LOG("usb: Can't create cond!\n"); + log_error("Can't create cond!\n"); resourceDestroy(priv->intrn.transferLock); free(priv); usb_libDrvDestroy(driver); @@ -117,7 +118,7 @@ int usb_transferSubmit(usb_transfer_t *t, usb_pipe_t *pipe, handle_t *cond) int ret = 0; if (t->recipient == usb_drvType_none) { - USB_LOG("usb: transfer recipient unspecified!\n"); + log_error("transfer recipient unspecified!\n"); return -EINVAL; } @@ -228,12 +229,12 @@ static int usb_handleOpen(usb_open_t *o, msg_t *msg) hcd_t *hcd; if ((drv = usb_drvFind(msg->pid)) == NULL) { - USB_LOG("usb: Fail to find driver pid: %d\n", msg->pid); + log_error("Fail to find driver pid: %d\n", msg->pid); return -EINVAL; } if ((hcd = hcd_find(usb_common.hcds, o->locationID)) == NULL) { - USB_LOG("usb: Fail to find dev: %d\n", o->dev); + log_error("Fail to find dev: %d\n", o->dev); return -EINVAL; } @@ -328,13 +329,13 @@ static void usb_msgthr(void *arg) break; default: msg.o.err = -EINVAL; - USB_LOG("usb: unsupported usb_msg type: %d\n", umsg->type); + log_error("unsupported usb_msg type: %d\n", umsg->type); break; } break; default: msg.o.err = -EINVAL; - USB_LOG("usb: unsupported msg type\n"); + log_error("unsupported msg type\n"); } if (resp) @@ -387,29 +388,29 @@ int main(int argc, char *argv[]) usb_driver_t *drv; if (mutexCreate(&usb_common.transferLock) != 0) { - USB_LOG("usb: Can't create mutex!\n"); + log_error("Can't create mutex!\n"); return 1; } if (condCreate(&usb_common.finishedCond) != 0) { - USB_LOG("usb: Can't create cond!\n"); + log_error("Can't create cond!\n"); return 1; } if (usb_memInit() != 0) { - USB_LOG("usb: Can't initiate memory management!\n"); + log_error("Can't initiate memory management!\n"); return 1; } if (usb_devInit() != 0) { - USB_LOG("usb: Fail to init devices!\n"); + log_error("Fail to init devices!\n"); return 1; } for (;;) { drv = usb_registeredDriverPop(); if (drv != NULL) { - USB_LOG("usb: Initializing driver as host-side: %s\n", drv->name); + log_msg("Initializing driver as host-side: %s\n", drv->name); usb_internalDriverInit(drv); } else { @@ -418,18 +419,18 @@ int main(int argc, char *argv[]) } if (hub_init() != 0) { - USB_LOG("usb: Fail to init hub driver!\n"); + log_error("Fail to init hub driver!\n"); return 1; } if ((usb_common.hcds = hcd_init()) == NULL) { - USB_LOG("usb: Fail to init hcds!\n"); + log_error("Fail to init hcds!\n"); return 1; } #ifndef USB_INTERNAL_ONLY if (portCreate(&usb_common.port) != 0) { - USB_LOG("usb: Can't create port!\n"); + log_error("Can't create port!\n"); return 1; } @@ -437,19 +438,19 @@ int main(int argc, char *argv[]) oid.id = 0; if (create_dev(&oid, "/dev/usb") != 0) { - USB_LOG("usb: Can't create dev!\n"); + log_error("Can't create dev!\n"); return 1; } if (beginthread(usb_msgthr, MSGTHR_PRIO, &usb_common.ustack, sizeof(usb_common.ustack), (void *)usb_common.port) != 0) { - USB_LOG("usb: Fail to run msgthr!\n"); + log_error("Fail to run msgthr!\n"); return 1; } #endif for (i = 0; i < N_STATUSTHRS - 1; i++) { if (beginthread(usb_statusthr, STATUSTHR_PRIO, &usb_common.stack[i], sizeof(usb_common.stack[i]), NULL) != 0) { - USB_LOG("usb: Fail to init hub driver!\n"); + log_error("Fail to init hub driver!\n"); return 1; } } @@ -469,7 +470,7 @@ int usblibdrv_open(usb_driver_t *drv, usb_devinfo_t *dev, usb_transfer_type_t ty hcd = hcd_find(usb_common.hcds, dev->locationID); if (hcd == NULL) { - USB_LOG("usb: Failed to find dev: %d\n", dev->locationID); + log_error("Failed to find dev: %d\n", dev->locationID); return -EINVAL; } diff --git a/usb/usbhost.h b/usb/usbhost.h index d0a071e..27f3bfe 100644 --- a/usb/usbhost.h +++ b/usb/usbhost.h @@ -103,14 +103,6 @@ struct usb_transfer_t { }; -#define USB_LOG(fmt, ...) do { printf(fmt, ##__VA_ARGS__); } while (0); - -#define USB_TRACE(fmt, ...) \ - if (0) { \ - printf("usb, %s: " fmt "\n", __func__ __VA_OPT__(, ) __VA_ARGS__); \ - } - - int usb_memInit(void); From 7085871c08abf2107c7a546410fa3edeb88f2504 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 25 Apr 2025 10:51:27 +0200 Subject: [PATCH 19/25] usb/usb: replace USB_INTERNAL_ONLY ifdefs to always create /dev/usb JIRA: RTOS-1024 --- usb/usb.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/usb/usb.c b/usb/usb.c index 38fd303..33a03a5 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -41,10 +41,8 @@ static struct { -#ifndef USB_INTERNAL_ONLY char ustack[2048] __attribute__((aligned(8))); uint32_t port; -#endif char stack[N_STATUSTHRS - 1][2048] __attribute__((aligned(8))); handle_t transferLock; handle_t finishedCond; @@ -187,13 +185,13 @@ void usb_transferFinished(usb_transfer_t *t, int status) } -#ifndef USB_INTERNAL_ONLY static int usb_devsList(char *buffer, size_t size) { return 0; } +#ifndef USB_INTERNAL_ONLY static int usb_handleConnect(msg_t *msg, usb_connect_t *c) { usb_drvpriv_t *drv; @@ -286,6 +284,7 @@ static void usb_urbSyncCompleted(usb_transfer_t *t) msgRespond(usb_common.port, &msg, t->extrn.rid); usb_transferFree(t); } +#endif /* USB_INTERNAL_ONLY */ static void usb_msgthr(void *arg) @@ -294,13 +293,15 @@ static void usb_msgthr(void *arg) msg_rid_t rid; msg_t msg; usb_msg_t *umsg; - int resp; + bool respond; int ret; for (;;) { - if (msgRecv(port, &msg, &rid) < 0) + ret = msgRecv(port, &msg, &rid); + if (ret < 0) { continue; - resp = 1; + } + respond = true; switch (msg.type) { case mtRead: msg.o.err = usb_devsList(msg.o.data, msg.o.size); @@ -308,6 +309,7 @@ static void usb_msgthr(void *arg) case mtDevCtl: umsg = (usb_msg_t *)msg.i.raw; switch (umsg->type) { +#ifndef USB_INTERNAL_ONLY case usb_msg_connect: msg.o.err = usb_handleConnect(&msg, &umsg->connect); break; @@ -318,7 +320,7 @@ static void usb_msgthr(void *arg) ret = usb_handleUrb(&msg, port, rid); if (umsg->urb.sync && ret == 0) { /* Block the sender until the transfer finishes */ - resp = 0; + respond = false; } else { msg.o.err = ret; @@ -327,6 +329,7 @@ static void usb_msgthr(void *arg) case usb_msg_urbcmd: msg.o.err = usb_handleUrbcmd(&msg); break; +#endif default: msg.o.err = -EINVAL; log_error("unsupported usb_msg type: %d\n", umsg->type); @@ -338,12 +341,14 @@ static void usb_msgthr(void *arg) log_error("unsupported msg type\n"); } - if (resp) + if (respond) { msgRespond(port, &msg, rid); + } } } +#ifndef USB_INTERNAL_ONLY static usb_transferOps_t usbprocdrv_transferOps = { .urbSyncCompleted = usb_urbSyncCompleted, .urbAsyncCompleted = usb_urbAsyncCompleted, @@ -381,9 +386,7 @@ static void usb_statusthr(void *arg) int main(int argc, char *argv[]) { -#ifndef USB_INTERNAL_ONLY oid_t oid; -#endif int i; usb_driver_t *drv; @@ -428,7 +431,6 @@ int main(int argc, char *argv[]) return 1; } -#ifndef USB_INTERNAL_ONLY if (portCreate(&usb_common.port) != 0) { log_error("Can't create port!\n"); return 1; @@ -446,7 +448,6 @@ int main(int argc, char *argv[]) log_error("Fail to run msgthr!\n"); return 1; } -#endif for (i = 0; i < N_STATUSTHRS - 1; i++) { if (beginthread(usb_statusthr, STATUSTHR_PRIO, &usb_common.stack[i], sizeof(usb_common.stack[i]), NULL) != 0) { From 90bc6539a61c2a40d03c0eb51046cca74c0ac2fa Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 28 Mar 2025 10:40:53 +0100 Subject: [PATCH 20/25] libusb: fix driver name passing if using procdriver JIRA: RTOS-1024 --- libusb/include/usbdriver.h | 1 + libusb/procdriver.c | 7 +++++-- usb/usb.c | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libusb/include/usbdriver.h b/libusb/include/usbdriver.h index 48e6e88..0f01444 100644 --- a/libusb/include/usbdriver.h +++ b/libusb/include/usbdriver.h @@ -57,6 +57,7 @@ typedef struct { typedef struct { unsigned port; unsigned nfilters; + char name[USB_DRVNAME_MAX]; } usb_connect_t; diff --git a/libusb/procdriver.c b/libusb/procdriver.c index 284dd46..caaea36 100644 --- a/libusb/procdriver.c +++ b/libusb/procdriver.c @@ -110,10 +110,12 @@ static void usb_thread(void *arg) } -static int usb_connect(const usb_device_id_t *filters, unsigned int nfilters) +static int usb_connect(usb_driver_t *drv) { msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)&msg.i.raw; + const usb_device_id_t *filters = drv->filters; + unsigned int nfilters = drv->nfilters; msg.type = mtDevCtl; msg.i.size = sizeof(*filters) * nfilters; @@ -122,6 +124,7 @@ static int usb_connect(const usb_device_id_t *filters, unsigned int nfilters) umsg->type = usb_msg_connect; umsg->connect.port = usbprocdrv_common.drvport; umsg->connect.nfilters = nfilters; + strncpy(umsg->connect.name, drv->name, USB_DRVNAME_MAX); return msgSend(usbprocdrv_common.srvport, &msg) < 0; } @@ -148,7 +151,7 @@ int usb_driverProcRun(usb_driver_t *drv, void *args) return -1; } - ret = usb_connect(drv->filters, drv->nfilters); + ret = usb_connect(drv); if (ret < 0) { return -1; } diff --git a/usb/usb.c b/usb/usb.c index 33a03a5..acd4ced 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -211,6 +211,7 @@ static int usb_handleConnect(msg_t *msg, usb_connect_t *c) drv->extrn.id = msg->pid; drv->extrn.port = c->port; drv->driver.nfilters = c->nfilters; + memcpy(drv->driver.name, c->name, sizeof(char) * USB_DRVNAME_MAX); memcpy((void *)drv->driver.filters, msg->i.data, msg->i.size); usb_drvAdd(drv); From beda0f0a182273b5b850f8ced4e256cac3cc5004 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 3 Apr 2025 09:09:58 +0200 Subject: [PATCH 21/25] usb: preserve utf16 value of string descriptors Some devices store information in device descriptors in ASCII (even though string descriptors are to be treated as UTF16 per USB spec...), in which case converting from UTF16 to ASCII no matter what would cause loss of information JIRA: RTOS-1024 --- libusb/include/usbdriver.h | 2 +- usb/dev.c | 136 +++++++++++++++++++++++++++---------- usb/dev.h | 16 +++-- 3 files changed, 115 insertions(+), 39 deletions(-) diff --git a/libusb/include/usbdriver.h b/libusb/include/usbdriver.h index 0f01444..b2fe613 100644 --- a/libusb/include/usbdriver.h +++ b/libusb/include/usbdriver.h @@ -24,7 +24,7 @@ #include #define USB_DRVNAME_MAX 10 -#define USB_STR_MAX 255 +#define USB_STR_MAX 254 /* per USB 2.0 spec */ #define USBDRV_ANY ((unsigned)-1) diff --git a/usb/dev.c b/usb/dev.c index 1a22d8e..d911d02 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -131,13 +131,14 @@ void usb_devFree(usb_dev_t *dev) { int i; - free(dev->manufacturer); - free(dev->product); - free(dev->serialNumber); + free(dev->manufacturer.str); + free(dev->product.str); + free(dev->serialNumber.str); free(dev->conf); - for (i = 0; i < dev->nifs; i++) - free(dev->ifs[i].str); + for (i = 0; i < dev->nifs; i++) { + free(dev->ifs[i].name.str); + } usb_drvPipeFree(NULL, dev->ctrlPipe); if (dev->statusTransfer != NULL) { @@ -351,81 +352,143 @@ static int usb_getConfiguration(usb_dev_t *dev) } -static int usb_getStringDesc(usb_dev_t *dev, char **buf, int index) +static int usb_getStringDesc(usb_dev_t *dev, usb_lenStr_t *dest, int index) { usb_string_desc_t desc = { 0 }; - int i; - size_t asciisz; if (usb_getDescriptor(dev, USB_DESC_STRING, index, (char *)&desc, sizeof(desc)) < 0) { log_error("Fail to get string descriptor\n"); return -1; } - asciisz = (desc.bLength - 2) / 2; - /* Convert from unicode to ascii */ - if ((*buf = calloc(1, asciisz + 1)) == NULL) + dest->str = malloc(desc.bLength - 2); + if (dest->str == NULL) { return -ENOMEM; + } - for (i = 0; i < asciisz; i++) - (*buf)[i] = desc.wData[i * 2]; + dest->len = desc.bLength - 2; + memcpy(dest->str, desc.wData, dest->len); return 0; } -#define USB_STRING_MAX_LEN 255 +/* assumes dest buffer size >= len / 2 + 1 */ +static unsigned int usb_utf16ToAscii(char *dest, const char *src, unsigned int len) +{ + unsigned int asciilen = len / 2; + int i; + + if (len < 2) { + return 0; + } + for (i = 0; i < asciilen; i++) { + dest[i] = src[i * 2]; + } -static void usb_fallbackProductString(usb_dev_t *dev) + dest[asciilen] = 0; + + return asciilen; +} + + +#define USB_HID_UTF16_STR u"USB HID" +#define USB_HUB_ROOT_USTR u"USB Root Hub" +#define USB_HUB_SINGLE_TT_USTR u"USB Single TT Hub" +#define USB_HUB_OTHER_USTR u"USB Hub" +#define USB_MASS_STORAGE_USTR u"USB Mass Storage" +#define USB_UNKNOWN_DEV_USTR u"Unknown USB Device" + + +static int usb_fallbackProductString(usb_dev_t *dev) { - char product[USB_STRING_MAX_LEN] = { 0 }; + char *product; + unsigned int len; switch (dev->desc.bDeviceClass) { case USB_CLASS_HID: - strcpy(product, "USB HID"); + product = (char *)USB_HID_UTF16_STR; + len = sizeof(USB_HID_UTF16_STR); break; case USB_CLASS_HUB: switch (dev->desc.bDeviceProtocol) { case USB_HUB_PROTO_ROOT: - strcpy(product, "USB Root Hub"); + product = (char *)USB_HUB_ROOT_USTR; + len = sizeof(USB_HUB_ROOT_USTR); break; case USB_HUB_PROTO_SINGLE_TT: - strcpy(product, "USB Single TT Hub"); + product = (char *)USB_HUB_SINGLE_TT_USTR; + len = sizeof(USB_HUB_SINGLE_TT_USTR); break; default: - strcpy(product, "USB Hub"); + product = (char *)USB_HUB_OTHER_USTR; + len = sizeof(USB_HUB_OTHER_USTR); break; } break; case USB_CLASS_MASS_STORAGE: - strcpy(product, "USB Mass Storage"); + product = (char *)USB_MASS_STORAGE_USTR; + len = sizeof(USB_MASS_STORAGE_USTR); break; default: - strcpy(product, "Unknown USB Device"); + product = (char *)USB_UNKNOWN_DEV_USTR; + len = sizeof(USB_UNKNOWN_DEV_USTR); break; } - dev->product = calloc(sizeof(char), strnlen(product, USB_STRING_MAX_LEN) + 1); - strcpy(dev->product, product); + len -= 2; + + dev->product.str = malloc(len); + + if (dev->product.str == NULL) { + return -ENOMEM; + } + + memcpy(dev->product.str, product, len); + dev->product.len = len; + + return 0; } -static void usb_fallbackManufacturerString(usb_dev_t *dev) +#define USB_MANUFACTURER_USTR u"Generic" + + +static int usb_fallbackManufacturerString(usb_dev_t *dev) { - char manufacturer[] = "Generic"; + const char *manufacturer = (char *)USB_MANUFACTURER_USTR; + int len = sizeof(USB_MANUFACTURER_USTR) - 2; + + dev->manufacturer.str = malloc(len); + if (dev->manufacturer.str == NULL) { + return -ENOMEM; + } + + memcpy(dev->manufacturer.str, manufacturer, len); + dev->manufacturer.len = len; - dev->manufacturer = calloc(sizeof(char), strnlen(manufacturer, USB_STRING_MAX_LEN) + 1); - strcpy(dev->manufacturer, manufacturer); + return 0; } -static void usb_fallbackSerialNumberString(usb_dev_t *dev) +#define USB_SERIAL_NUMBER_USTR u"Unknown" + + +static int usb_fallbackSerialNumberString(usb_dev_t *dev) { - char serialNumber[] = "Unknown"; + const char *serialNumber = (char *)USB_SERIAL_NUMBER_USTR; + int len = sizeof(USB_SERIAL_NUMBER_USTR) - 2; - dev->serialNumber = calloc(sizeof(char), strnlen(serialNumber, USB_STRING_MAX_LEN) + 1); - strcpy(dev->serialNumber, serialNumber); + dev->serialNumber.str = malloc(len); + if (dev->serialNumber.str == NULL) { + return -ENOMEM; + } + + memcpy(dev->serialNumber.str, serialNumber, len); + dev->serialNumber.len = len; + + return 0; } @@ -475,7 +538,7 @@ static int usb_getAllStringDescs(usb_dev_t *dev) for (i = 0; i < dev->nifs; i++) { if (dev->ifs[i].desc->iInterface == 0) continue; - if (usb_getStringDesc(dev, &dev->ifs[i].str, dev->ifs[i].desc->iInterface) != 0) + if (usb_getStringDesc(dev, &dev->ifs[i].name, dev->ifs[i].desc->iInterface) != 0) return -ENOMEM; } @@ -487,6 +550,8 @@ static int usb_getAllStringDescs(usb_dev_t *dev) int usb_devEnumerate(usb_dev_t *dev) { + char manufacturerAscii[USB_STR_MAX / 2 + 1]; + char productAscii[USB_STR_MAX / 2 + 1]; int addr, iface; usb_event_insertion_t insertion = { 0 }; @@ -528,8 +593,11 @@ int usb_devEnumerate(usb_dev_t *dev) if (!usb_isRoothub(dev)) usb_devSetChild(dev->hub, dev->port, dev); + usb_utf16ToAscii(manufacturerAscii, dev->manufacturer.str, dev->manufacturer.len); + usb_utf16ToAscii(productAscii, dev->product.str, dev->product.len); + log_info("New device addr: %d locationID: %08x %s, %s\n", dev->address, dev->locationID, - dev->manufacturer, dev->product); + manufacturerAscii, productAscii); if (dev->desc.bDeviceClass == USB_CLASS_HUB) { if (hub_conf(dev) != 0) diff --git a/usb/dev.h b/usb/dev.h index e533941..4f030a8 100644 --- a/usb/dev.h +++ b/usb/dev.h @@ -23,11 +23,18 @@ enum usb_speed { usb_full_speed = 0, usb_low_speed, usb_high_speed }; + +typedef struct { + unsigned int len; + char *str; +} usb_lenStr_t; + + typedef struct { usb_interface_desc_t *desc; usb_endpoint_desc_t *eps; void *classDesc; - char *str; + usb_lenStr_t name; struct usb_drvpriv *driver; } usb_iface_t; @@ -39,9 +46,10 @@ typedef struct _usb_dev { enum usb_speed speed; usb_device_desc_t desc; usb_configuration_desc_t *conf; - char *manufacturer; - char *product; - char *serialNumber; + + usb_lenStr_t manufacturer; + usb_lenStr_t product; + usb_lenStr_t serialNumber; uint16_t langId; int address; From c6eb186b4d6d0eb3aae3f0d0b7657e078d21aee5 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 10 Apr 2025 15:54:20 +0200 Subject: [PATCH 22/25] dev: print vid:pid on device insertion JIRA: RTOS-1024 --- usb/dev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/usb/dev.c b/usb/dev.c index d911d02..be8e637 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -596,8 +596,9 @@ int usb_devEnumerate(usb_dev_t *dev) usb_utf16ToAscii(manufacturerAscii, dev->manufacturer.str, dev->manufacturer.len); usb_utf16ToAscii(productAscii, dev->product.str, dev->product.len); - log_info("New device addr: %d locationID: %08x %s, %s\n", dev->address, dev->locationID, - manufacturerAscii, productAscii); + log_info("New device: %04x:%04x %s, %s (%d, %08x)\n", + dev->desc.idVendor, dev->desc.idProduct, manufacturerAscii, productAscii, + dev->address, dev->locationID); if (dev->desc.bDeviceClass == USB_CLASS_HUB) { if (hub_conf(dev) != 0) From e858d51eb16f07ae0a61249d4685cd9af5ae4d2c Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 23 Apr 2025 11:49:15 +0200 Subject: [PATCH 23/25] usb/drv: fix drivers not being bound to all possible dev interfaces Multifunction (multi-interface) devices may be served by multiple drivers JIRA: RTOS-1024 --- usb/drv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/usb/drv.c b/usb/drv.c index 18535f5..b1087e9 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -366,7 +366,7 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) msg_t msg = { 0 }; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - int i, err; + int i, err, ndrvs = 0; msg.type = mtDevCtl; umsg->type = usb_msg_insertion; @@ -401,17 +401,18 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) break; default: log_error("unexpected driver type: %d\n", drv->type); + err = -1; break; } if (err == 0) { - return 0; + ndrvs++; } } /* TODO: Make a device orphaned */ } - return -1; + return ndrvs == 0 ? -1 : 0; } From 6643ceda52a7987148d5bc243db2971e6d2ca059 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 17 Apr 2025 16:07:17 +0200 Subject: [PATCH 24/25] usb: add device info retrieval API based on driver's device file oid The usbhost now also creates symlinks to these driver devices named `/dev/usb---if" that can be looked up on and resolved via `canonicalize_file_name(path)` to acquire the needed oid. JIRA: RTOS-1024 --- libusb/Makefile | 2 +- libusb/devinfo.c | 49 +++++++++++ libusb/include/usbdevinfo.h | 25 ++++++ libusb/include/usbdriver.h | 24 +++++- libusb/internal.c | 30 +++++++ libusb/procdriver.c | 21 +---- libusb/usbinternal.h | 24 ++++++ usb/dev.c | 168 ++++++++++++++++++++++++++++++++++-- usb/dev.h | 13 ++- usb/drv.c | 13 ++- usb/drv.h | 5 +- usb/usb.c | 3 + 12 files changed, 340 insertions(+), 37 deletions(-) create mode 100644 libusb/devinfo.c create mode 100644 libusb/include/usbdevinfo.h create mode 100644 libusb/internal.c create mode 100644 libusb/usbinternal.h diff --git a/libusb/Makefile b/libusb/Makefile index 55c618d..89f2430 100644 --- a/libusb/Makefile +++ b/libusb/Makefile @@ -6,7 +6,7 @@ NAME := libusb LOCAL_PATH := $(call my-dir) -LOCAL_SRCS := cdc_client.c hid_client.c driver.c procdriver.c +LOCAL_SRCS := cdc_client.c hid_client.c driver.c procdriver.c internal.c devinfo.c LOCAL_CFLAGS := -I$(LOCAL_PATH) include $(static-lib.mk) diff --git a/libusb/devinfo.c b/libusb/devinfo.c new file mode 100644 index 0000000..87a6031 --- /dev/null +++ b/libusb/devinfo.c @@ -0,0 +1,49 @@ +/* + * Phoenix-RTOS + * + * Libusb driver interface + * + * USB low-level information API for userspace applications + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + +#include + +#include + +#include "usbinternal.h" +#include "log.h" + + +int usb_devinfoGet(oid_t oid, usb_devinfo_desc_t *desc) +{ + int err; + oid_t hostOid; + msg_t msg = { 0 }; + usb_msg_t *imsg = (usb_msg_t *)msg.i.raw; + + usb_hostLookup(&hostOid); + + msg.type = mtDevCtl; + imsg->type = usb_msg_devdesc; + imsg->devdesc.oid = oid; + msg.o.data = desc; + msg.o.size = sizeof(usb_devinfo_desc_t); + + err = msgSend(hostOid.port, &msg); + if (err < 0) { + log_error("msgSend failed: %d\n", err); + return err; + } + + if (msg.o.err < 0) { + log_error("msg.o.err=%d\n", msg.o.err); + return msg.o.err; + } + + return 0; +} diff --git a/libusb/include/usbdevinfo.h b/libusb/include/usbdevinfo.h new file mode 100644 index 0000000..b99f528 --- /dev/null +++ b/libusb/include/usbdevinfo.h @@ -0,0 +1,25 @@ +/* + * Phoenix-RTOS + * + * Libusb driver interface + * + * USB low-level information API for userspace applications + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + + +#ifndef _USB_DEVINFO_H_ +#define _USB_DEVINFO_H_ + +#include +#include + + +int usb_devinfoGet(oid_t oid, usb_devinfo_desc_t *desc); + + +#endif diff --git a/libusb/include/usbdriver.h b/libusb/include/usbdriver.h index b2fe613..2165f95 100644 --- a/libusb/include/usbdriver.h +++ b/libusb/include/usbdriver.h @@ -121,6 +121,11 @@ typedef struct { } usb_completion_t; +typedef struct { + oid_t oid; +} usb_devdesc_t; + + typedef struct { enum { usb_msg_connect, usb_msg_insertion, @@ -128,7 +133,8 @@ typedef struct { usb_msg_urb, usb_msg_open, usb_msg_urbcmd, - usb_msg_completion } type; + usb_msg_completion, + usb_msg_devdesc } type; union { usb_connect_t connect; @@ -138,10 +144,21 @@ typedef struct { usb_devinfo_t insertion; usb_deletion_t deletion; usb_completion_t completion; + usb_devdesc_t devdesc; }; } usb_msg_t; +typedef struct { + usb_device_desc_t desc; + + struct { + unsigned int len; + char str[USB_STR_MAX]; + } manufacturer, product, serialNumber; +} __attribute__((packed)) usb_devinfo_desc_t; + + typedef struct { uint16_t vid; uint16_t pid; @@ -152,7 +169,10 @@ typedef struct { typedef struct { bool deviceCreated; /* Set to true by the insertion handler if a device file for the inserted device has been created */ - char devPath[32]; /* Path to device file */ + + /* oid and path to the device file */ + oid_t dev; + char devPath[32]; } usb_event_insertion_t; diff --git a/libusb/internal.c b/libusb/internal.c new file mode 100644 index 0000000..c103ac0 --- /dev/null +++ b/libusb/internal.c @@ -0,0 +1,30 @@ +/* + * Phoenix-RTOS + * + * libusb/internal.c + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + + +#include +#include + + +void usb_hostLookup(oid_t *oid) +{ + for (;;) { + if (lookup("devfs/usb", NULL, oid) >= 0) { + break; + } + + if (lookup("/dev/usb", NULL, oid) >= 0) { + break; + } + + usleep(1000000); + } +} diff --git a/libusb/procdriver.c b/libusb/procdriver.c index caaea36..8456d3c 100644 --- a/libusb/procdriver.c +++ b/libusb/procdriver.c @@ -19,6 +19,7 @@ #include #include +#include #include "log.h" @@ -46,26 +47,6 @@ static struct { } usbprocdrv_common; -static void usb_hostLookup(oid_t *oid) -{ - int ret; - - for (;;) { - ret = lookup("devfs/usb", NULL, oid); - if (ret >= 0) { - break; - } - - ret = lookup("/dev/usb", NULL, oid); - if (ret >= 0) { - break; - } - - usleep(1000000); - } -} - - static void usb_thread(void *arg) { usb_driver_t *drv = (usb_driver_t *)arg; diff --git a/libusb/usbinternal.h b/libusb/usbinternal.h new file mode 100644 index 0000000..4d45cf6 --- /dev/null +++ b/libusb/usbinternal.h @@ -0,0 +1,24 @@ +/* + * Phoenix-RTOS + * + * Libusb driver interface + * + * Internal header + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + +#ifndef _USB_INTERNAL_H_ +#define _USB_INTERNAL_H_ + + +#include + + +void usb_hostLookup(oid_t *oid); + + +#endif diff --git a/usb/dev.c b/usb/dev.c index be8e637..2dc77f5 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -17,8 +17,11 @@ #include #include #include +#include +#include #include #include +#include #include @@ -31,11 +34,24 @@ #define USBDEV_BUF_SIZE 0x200 + +typedef struct devOid { + struct devOid *prev, *next; + + /* iface-specific dev oid created by the dev's driver */ + oid_t oid; + + usb_dev_t *dev; +} usb_devOid_t; + + struct { handle_t lock; handle_t cond; char *ctrlBuf; char *setupBuf; + + usb_devOid_t *devOids; } usbdev_common; @@ -548,12 +564,66 @@ static int usb_getAllStringDescs(usb_dev_t *dev) } +#define USB_DEV_SYMLINK_FORMAT "/dev/usb-%04x-%04x-if%02d" + + +static void usb_devSymlinksCreate(usb_dev_t *dev, const char *devPath, int iface) +{ + char linkpath[32] = { 0 }; + int ret; + + sprintf(linkpath, USB_DEV_SYMLINK_FORMAT, dev->desc.idVendor, dev->desc.idProduct, iface); + + unlink(linkpath); + ret = symlink(devPath, linkpath); + + if (ret < 0) { + log_error("%s -> %s symlink error: %d", linkpath, devPath, errno); + } +} + + +static void usb_devSymlinksDestroy(usb_dev_t *dev, int iface) +{ + char linkpath[32] = { 0 }; + + sprintf(linkpath, USB_DEV_SYMLINK_FORMAT, dev->desc.idVendor, dev->desc.idProduct, iface); + unlink(linkpath); +} + + +static void usb_devOnDrvBindCb(usb_dev_t *dev, usb_event_insertion_t *event, int iface) +{ + usb_devOid_t *devOid; + + if (event->deviceCreated) { + devOid = calloc(1, sizeof(usb_devOid_t)); + + if (devOid == NULL) { + log_error("calloc failed"); + return; + } + + log_info("Dev oid bound to device with addr %d: port=%u, id=%u\n", + dev->address, event->dev.port, (uint32_t)event->dev.id); + + devOid->oid = event->dev; + devOid->dev = dev; + + mutexLock(usbdev_common.lock); + LIST_ADD(&usbdev_common.devOids, devOid); + mutexUnlock(usbdev_common.lock); + + usb_devSymlinksCreate(dev, event->devPath, iface); + } +} + + int usb_devEnumerate(usb_dev_t *dev) { char manufacturerAscii[USB_STR_MAX / 2 + 1]; char productAscii[USB_STR_MAX / 2 + 1]; - int addr, iface; - usb_event_insertion_t insertion = { 0 }; + int addr; if (usb_genLocationID(dev) < 0) { log_error("Fail to generate location ID\n"); @@ -604,16 +674,59 @@ int usb_devEnumerate(usb_dev_t *dev) if (hub_conf(dev) != 0) return -1; } - else if (usb_drvBind(dev, &insertion, &iface) != 0) { + else if (usb_drvBind(dev, usb_devOnDrvBindCb) != 0) { log_msg("Fail to match drivers for device\n"); /* TODO: make device orphaned */ + return -1; } - if (insertion.deviceCreated) { - log_info("Driver bound to device with addr %d: %s\n", dev->address, insertion.devPath); + return 0; +} + + +static usb_dev_t *_usb_devOidFind(oid_t oid) +{ + usb_devOid_t *curr = usbdev_common.devOids; + + if (curr != NULL) { + do { + if (curr->oid.port == oid.port && curr->oid.id == oid.id) { + return curr->dev; + } + curr = curr->next; + } while (curr != usbdev_common.devOids); } - return 0; + return NULL; +} + + +static void usb_devFreeOids(usb_dev_t *dev) +{ + usb_devOid_t *next, *curr = usbdev_common.devOids; + + bool end = false; + + mutexLock(usbdev_common.lock); + + if (curr != NULL) { + do { + next = curr->next; + + if (curr == next) { + end = true; + } + + if (curr->dev == dev) { + LIST_REMOVE(&usbdev_common.devOids, curr); + free(curr); + } + + curr = next; + } while (!end && curr != usbdev_common.devOids); + } + + mutexUnlock(usbdev_common.lock); } @@ -622,13 +735,18 @@ static void usb_devUnbind(usb_dev_t *dev) int i; for (i = 0; i < dev->nports; i++) { - if (dev->devs[i] != NULL) + if (dev->devs[i] != NULL) { usb_devUnbind(dev->devs[i]); + } } + usb_devFreeOids(dev); + for (i = 0; i < dev->nifs; i++) { - if (dev->ifs[i].driver) + if (dev->ifs[i].driver != NULL) { + usb_devSymlinksDestroy(dev, i); usb_drvUnbind(dev->ifs[i].driver, dev, i); + } } } @@ -663,6 +781,40 @@ usb_dev_t *usb_devFind(usb_dev_t *hub, int locationID) } +int usb_devFindDescFromOid(oid_t oid, usb_devinfo_desc_t *desc) +{ + usb_dev_t *dev; + + if (desc == NULL) { + return -EINVAL; + } + + mutexLock(usbdev_common.lock); + + dev = _usb_devOidFind(oid); + if (dev == NULL) { + mutexUnlock(usbdev_common.lock); + log_msg("device not found with oid.id=%u oid.port=%u \n", (uint32_t)oid.id, oid.port); + return -EINVAL; + } + + memcpy(&desc->desc, &dev->desc, sizeof(usb_device_desc_t)); + + memcpy(desc->product.str, dev->product.str, dev->product.len); + desc->product.len = dev->product.len; + + memcpy(desc->manufacturer.str, dev->manufacturer.str, dev->manufacturer.len); + desc->manufacturer.len = dev->manufacturer.len; + + memcpy(desc->serialNumber.str, dev->serialNumber.str, dev->serialNumber.len); + desc->serialNumber.len = dev->serialNumber.len; + + mutexUnlock(usbdev_common.lock); + + return 0; +} + + void usb_devDisconnected(usb_dev_t *dev, bool silent) { if (!silent) { diff --git a/usb/dev.h b/usb/dev.h index 4f030a8..5134992 100644 --- a/usb/dev.h +++ b/usb/dev.h @@ -21,7 +21,9 @@ #include "usbhost.h" -enum usb_speed { usb_full_speed = 0, usb_low_speed, usb_high_speed }; +enum usb_speed { usb_full_speed = 0, + usb_low_speed, + usb_high_speed }; typedef struct { @@ -40,6 +42,12 @@ typedef struct { } usb_iface_t; +typedef struct usb_dev_oid { + struct usb_dev_oid *next, *prev; + oid_t oid; +} usb_dev_oids_t; + + typedef struct _usb_dev { struct _usb_dev *next, *prev; @@ -97,4 +105,7 @@ int usb_isRoothub(usb_dev_t *dev); void usb_devSignal(void); +int usb_devFindDescFromOid(oid_t oid, usb_devinfo_desc_t *desc); + + #endif /* _USB_DEV_H_ */ diff --git a/usb/drv.c b/usb/drv.c index b1087e9..cb3d9eb 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -360,7 +360,7 @@ int usb_drvUnbind(usb_drvpriv_t *drv, usb_dev_t *dev, int iface) } -int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) +int usb_drvBind(usb_dev_t *dev, usb_drvOnBindCb_t onBindCb) { usb_drvpriv_t *drv; @@ -368,6 +368,8 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; int i, err, ndrvs = 0; + usb_event_insertion_t event = { 0 }; + msg.type = mtDevCtl; umsg->type = usb_msg_insertion; umsg->insertion.bus = dev->hcd->num; @@ -383,11 +385,10 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) if (drv != NULL) { dev->ifs[i].driver = drv; umsg->insertion.interface = i; - *iface = i; switch (drv->type) { case usb_drvType_intrn: - err = drv->driver.handlers.insertion(&drv->driver, &umsg->insertion, event); + err = drv->driver.handlers.insertion(&drv->driver, &umsg->insertion, &event); break; case usb_drvType_extrn: err = msgSend(drv->extrn.port, &msg); @@ -396,7 +397,7 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) } if (err == 0) { - memcpy(event, msg.o.raw, sizeof(usb_event_insertion_t)); + memcpy(&event, msg.o.raw, sizeof(usb_event_insertion_t)); } break; default: @@ -406,9 +407,13 @@ int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface) } if (err == 0) { + if (onBindCb != NULL) { + onBindCb(dev, &event, i); + } ndrvs++; } } + /* TODO: Make a device orphaned */ } diff --git a/usb/drv.h b/usb/drv.h index 29e9bf5..41afb73 100644 --- a/usb/drv.h +++ b/usb/drv.h @@ -24,6 +24,9 @@ #define PORT_INTERNAL (-1) +typedef void (*usb_drvOnBindCb_t)(usb_dev_t *dev, usb_event_insertion_t *event, int iface); + + typedef struct usb_drvpriv { struct usb_drvpriv *next, *prev; @@ -58,7 +61,7 @@ void usb_libDrvDestroy(usb_driver_t *drv); void usb_drvAdd(usb_drvpriv_t *drv); -int usb_drvBind(usb_dev_t *dev, usb_event_insertion_t *event, int *iface); +int usb_drvBind(usb_dev_t *dev, usb_drvOnBindCb_t onBindCb); int usb_drvUnbind(usb_drvpriv_t *drv, usb_dev_t *dev, int iface); diff --git a/usb/usb.c b/usb/usb.c index acd4ced..5143c48 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -331,6 +331,9 @@ static void usb_msgthr(void *arg) msg.o.err = usb_handleUrbcmd(&msg); break; #endif + case usb_msg_devdesc: + msg.o.err = usb_devFindDescFromOid(umsg->devdesc.oid, msg.o.data); + break; default: msg.o.err = -EINVAL; log_error("unsupported usb_msg type: %d\n", umsg->type); From 91853a686f4b7e34b60975865b70af215157b8ff Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 25 Apr 2025 17:37:35 +0200 Subject: [PATCH 25/25] usb/drv: reset msg before each msgSend Not resetting caused subsequent msgSend calls to send the modified and incorrect messages JIRA: RTOS-1024 --- usb/drv.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/usb/drv.c b/usb/drv.c index cb3d9eb..10a19e1 100644 --- a/usb/drv.c +++ b/usb/drv.c @@ -364,25 +364,26 @@ int usb_drvBind(usb_dev_t *dev, usb_drvOnBindCb_t onBindCb) { usb_drvpriv_t *drv; - msg_t msg = { 0 }; + msg_t msg; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; int i, err, ndrvs = 0; usb_event_insertion_t event = { 0 }; - msg.type = mtDevCtl; - umsg->type = usb_msg_insertion; - umsg->insertion.bus = dev->hcd->num; - umsg->insertion.dev = dev->address; - umsg->insertion.descriptor = dev->desc; - umsg->insertion.locationID = dev->locationID; - /* FIXME: drvAdd races with drvMatchIface in multi-driver scenario. * Devices may become orphaned forever if they get added by hcd before the driver * is connected */ for (i = 0; i < dev->nifs; i++) { drv = usb_drvMatchIface(dev, &dev->ifs[i]); if (drv != NULL) { + memset(&msg, 0, sizeof(msg)); + msg.type = mtDevCtl; + umsg->type = usb_msg_insertion; + umsg->insertion.bus = dev->hcd->num; + umsg->insertion.dev = dev->address; + umsg->insertion.descriptor = dev->desc; + umsg->insertion.locationID = dev->locationID; + dev->ifs[i].driver = drv; umsg->insertion.interface = i;