From 750a4fe080109b54b8be181277dc4c6b1a285f5c Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 20 Nov 2024 16:24:30 +0100 Subject: [PATCH 01/29] usb/ehci: adapt to hcd_info_t struct change JIRA: RTOS-937 (cherry picked from commit 66691353fa02d0c9e40c55f9fe58034edcef1e63) --- usb/ehci/phy-imx6ull.c | 20 ++++++++++---------- usb/ehci/phy-imxrt106x.c | 18 +++++++++--------- usb/ehci/phy-imxrt117x.c | 16 ++++++++++------ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/usb/ehci/phy-imx6ull.c b/usb/ehci/phy-imx6ull.c index 011d2b3f9..fb8abc4d0 100644 --- a/usb/ehci/phy-imx6ull.c +++ b/usb/ehci/phy-imx6ull.c @@ -33,13 +33,13 @@ enum { phy_pwd, phy_pwd_set, phy_pwd_clr, phy_pwd_tog, phy_tx, phy_tx_set, /* NOTE: This should be obtained using device tree */ static const hcd_info_t imx6ull_info[] = { - { - .type = "ehci", + { .type = "ehci", .hcdaddr = 0x02184200, - .phyaddr = 0x020ca000, - .clk = pctl_clk_usboh3, - .irq = 74 - } + .phy = { + .addr = 0x020ca000, + .clk = pctl_clk_usboh3, + }, + .irq = 74 } }; @@ -88,7 +88,7 @@ void phy_initClock(hcd_t *hcd) .action = pctl_set, .type = pctl_devclock, .devclock = { - .dev = hcd->info->clk, + .dev = hcd->info->phy.clk, .state = 3, } }; @@ -103,7 +103,7 @@ void phy_disableClock(hcd_t *hcd) .action = pctl_set, .type = pctl_devclock, .devclock = { - .dev = hcd->info->clk, + .dev = hcd->info->phy.clk, .state = 0, } }; @@ -123,8 +123,8 @@ int phy_init(hcd_t *hcd) { off_t offs; - offs = hcd->info->phyaddr % _PAGE_SIZE; - hcd->phybase = mmap(NULL, _PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, hcd->info->phyaddr - offs); + offs = hcd->info->phy.addr % _PAGE_SIZE; + hcd->phybase = mmap(NULL, _PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, hcd->info->phy.addr - offs); if (hcd->phybase == MAP_FAILED) return -ENOMEM; hcd->phybase += (offs / sizeof(int)); diff --git a/usb/ehci/phy-imxrt106x.c b/usb/ehci/phy-imxrt106x.c index dec0ec339..67fbc68c9 100644 --- a/usb/ehci/phy-imxrt106x.c +++ b/usb/ehci/phy-imxrt106x.c @@ -32,13 +32,13 @@ enum { phy_pwd, phy_pwd_set, phy_pwd_clr, phy_pwd_tog, phy_tx, phy_tx_set, /* NOTE: This should be later implemented using device tree */ static const hcd_info_t imxrt_info[] = { - { - .type = "ehci", + { .type = "ehci", .hcdaddr = 0x402e0200, - .phyaddr = 0x400da000, - .clk = pctl_clk_usboh3, - .irq = 128 - } + .phy = { + .addr = 0x400da000, + .clk = pctl_clk_usboh3, + }, + .irq = 128 } }; @@ -104,10 +104,10 @@ void phy_enableHighSpeedDisconnect(hcd_t *hcd, int enable) int phy_init(hcd_t *hcd) { /* No mmapping, since we are on NOMMU architecture */ - hcd->phybase = (volatile int *)hcd->info->phyaddr; - hcd->base = (volatile int *)hcd->info->hcdaddr; + hcd->phybase = (volatile uint32_t *)hcd->info->phy.addr; + hcd->base = (volatile uint32_t *)hcd->info->hcdaddr; - setClock(hcd->info->clk, clk_state_run); + setClock(hcd->info->phy.clk, clk_state_run); phy_reset(hcd); phy_config(hcd); diff --git a/usb/ehci/phy-imxrt117x.c b/usb/ehci/phy-imxrt117x.c index 9b6ebcdf7..f1698e283 100644 --- a/usb/ehci/phy-imxrt117x.c +++ b/usb/ehci/phy-imxrt117x.c @@ -40,8 +40,10 @@ static const hcd_info_t imxrt_info[] = { { .type = "ehci", .hcdaddr = 0x40430000, - .phyaddr = 0x40434000, - .clk = pctl_lpcg_usb, + .phy = { + .addr = 0x40434000, + .clk = pctl_lpcg_usb, + }, .irq = usb_otg1_irq, }, #endif @@ -49,8 +51,10 @@ static const hcd_info_t imxrt_info[] = { { .type = "ehci", .hcdaddr = 0x4042c000, - .phyaddr = 0x40438000, - .clk = pctl_lpcg_usb, + .phy = { + .addr = 0x40438000, + .clk = pctl_lpcg_usb, + }, .irq = usb_otg2_irq, } #endif @@ -165,13 +169,13 @@ int phy_init(hcd_t *hcd) return -ENODEV; } - res = setClock(hcd->info->clk, 1); + res = setClock(hcd->info->phy.clk, 1); if (res < 0) { return res; } /* NOMMU architecture, mmap not needed */ - hcd->phybase = (void *)hcd->info->phyaddr; + hcd->phybase = (void *)hcd->info->phy.addr; hcd->base = (void *)hcd->info->hcdaddr; phy_start(hcd); From b5cacd3659b06c1f0e616aca71e0b6b3bc5e03a4 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 20 Nov 2024 17:27:58 +0100 Subject: [PATCH 02/29] usb/ehci: adapt ehci to work on ia32 JIRA: RTOS-937 (cherry picked from commit ae48f3764b4ec10b852a7d0929e53900f61036c8) --- _targets/Makefile.ia32-generic | 2 +- usb/ehci/Makefile | 5 + usb/ehci/ehci-hub.c | 22 +++-- usb/ehci/ehci.c | 83 ++++++++++++---- usb/ehci/ehci.h | 30 +++++- usb/ehci/phy-generic.c | 175 +++++++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+), 32 deletions(-) create mode 100644 usb/ehci/phy-generic.c diff --git a/_targets/Makefile.ia32-generic b/_targets/Makefile.ia32-generic index b939c8ce9..579f8d7a6 100644 --- a/_targets/Makefile.ia32-generic +++ b/_targets/Makefile.ia32-generic @@ -6,4 +6,4 @@ # Copyright 2019 Phoenix Systems # -DEFAULT_COMPONENTS := pc-tty uart16550 pc-ata +DEFAULT_COMPONENTS := pc-tty uart16550 pc-ata libusbehci umass diff --git a/usb/ehci/Makefile b/usb/ehci/Makefile index 8fe36da3c..044ca23de 100644 --- a/usb/ehci/Makefile +++ b/usb/ehci/Makefile @@ -6,6 +6,11 @@ # FIXME: rename usb host component NAME := libusbehci +# TODO use TARGET_FAMILY-TARGET_SUBFAMILY LOCAL_SRCS := ehci.c ehci-hub.c phy-$(TARGET_SUBFAMILY).c +ifneq (,$(findstring imx,$(TARGET_SUBFAMILY))) + LOCAL_CFLAGS += -DEHCI_IMX +endif + include $(static-lib.mk) diff --git a/usb/ehci/ehci-hub.c b/usb/ehci/ehci-hub.c index df8f5cc6d..ca8235d79 100644 --- a/usb/ehci/ehci-hub.c +++ b/usb/ehci/ehci-hub.c @@ -87,17 +87,23 @@ static const struct { static void ehci_resetPort(hcd_t *hcd, int port) { ehci_t *ehci = (ehci_t *)hcd->priv; - volatile int *reg = (hcd->base + portsc1) + (port - 1); + volatile int *reg = (ehci->opbase + portsc1) + (port - 1); *reg &= ~PORTSC_ENA; *reg |= PORTSC_PR; + +#ifdef EHCI_IMX /* - * This is imx deviation. According to ehci documentation + * imx deviation: According to ehci documentation * it is up to software to set the PR bit 0 after waiting 20ms */ while (*reg & PORTSC_PR) ; usleep(20 * 1000); +#else + usleep(20 * 1000); + *reg &= ~PORTSC_PR; +#endif ehci->portResetChange = 1 << port; @@ -118,7 +124,7 @@ static int ehci_getPortStatus(usb_dev_t *hub, int port, usb_port_status_t *statu status->wPortChange = 0; status->wPortStatus = 0; - val = *(hcd->base + portsc1 + port - 1); + val = *(ehci->opbase + portsc1 + port - 1); if (val & PORTSC_CCS) status->wPortStatus |= USB_PORT_STAT_CONNECTION; @@ -192,7 +198,7 @@ static int ehci_clearPortFeature(usb_dev_t *hub, int port, uint16_t wValue) { hcd_t *hcd = hub->hcd; ehci_t *ehci = (ehci_t *)hcd->priv; - volatile int *portsc = hcd->base + portsc1 + port - 1; + volatile int *portsc = ehci->opbase + portsc1 + port - 1; uint32_t val = *portsc; if (port > hub->nports) @@ -285,6 +291,7 @@ static int ehci_getStringDesc(usb_dev_t *hub, int index, char *buf, size_t size) static int ehci_getDesc(usb_dev_t *hub, int type, int index, char *buf, size_t size) { hcd_t *hcd = hub->hcd; + ehci_t *ehci = (ehci_t *)hcd->priv; usb_hub_desc_t *hdesc; int bytes = 0; @@ -309,7 +316,7 @@ static int ehci_getDesc(usb_dev_t *hub, int type, int index, char *buf, size_t s hdesc->wHubCharacteristics = 0x1; hdesc->bPwrOn2PwrGood = 10; hdesc->bHubContrCurrent = 10; - hdesc->bNbrPorts = *(hcd->base + hcsparams) & 0xf; + hdesc->bNbrPorts = *(ehci->base + hcsparams) & 0xf; hdesc->variable[0] = 0; /* Device not removable */ hdesc->variable[1] = 0xff; /* PortPwrCtrlMask */ break; @@ -340,12 +347,13 @@ int ehci_roothubReq(usb_dev_t *hub, usb_transfer_t *t) { usb_setup_packet_t *setup = t->setup; int ret; + ehci_t *ehci = (ehci_t *)hub->hcd->priv; /* It will be finished, when a port status changes */ if (t->type == usb_transfer_interrupt) { /* Enable Port Status Changed interrupt if this is a first call */ - if ((*(hub->hcd->base + usbintr) & USBSTS_PCI) == 0) - *(hub->hcd->base + usbintr) |= USBSTS_PCI; + if ((*(ehci->opbase + usbintr) & USBSTS_PCI) == 0) + *(ehci->opbase + usbintr) |= USBSTS_PCI; return 0; } diff --git a/usb/ehci/ehci.c b/usb/ehci/ehci.c index a947f67c6..dafcd3c57 100644 --- a/usb/ehci/ehci.c +++ b/usb/ehci/ehci.c @@ -36,7 +36,11 @@ #include "ehci.h" +#ifdef EHCI_IMX #define EHCI_PERIODIC_SIZE 128 +#else +#define EHCI_PERIODIC_SIZE 1024 +#endif #ifndef EHCI_PRIO #define EHCI_PRIO 2 @@ -45,7 +49,11 @@ static inline void ehci_memDmb(void) { - asm volatile ("dmb" ::: "memory"); +#ifdef EHCI_IMX + asm volatile("dmb" ::: "memory"); +#else + __sync_synchronize(); +#endif } @@ -53,19 +61,21 @@ static void ehci_startAsync(hcd_t *hcd) { ehci_t *ehci = (ehci_t *)hcd->priv; - *(hcd->base + asynclistaddr) = va2pa((void *)ehci->asyncList->hw); - *(hcd->base + usbcmd) |= USBCMD_ASE; + *(ehci->opbase + asynclistaddr) = va2pa((void *)ehci->asyncList->hw); + *(ehci->opbase + usbcmd) |= USBCMD_ASE; ehci_memDmb(); - while ((*(hcd->base + usbsts) & USBSTS_AS) == 0) + while ((*(ehci->opbase + usbsts) & USBSTS_AS) == 0) ; } static void ehci_stopAsync(hcd_t *hcd) { - *(hcd->base + usbcmd) &= ~USBCMD_ASE; + ehci_t *ehci = (ehci_t *)hcd->priv; + + *(ehci->opbase + usbcmd) &= ~USBCMD_ASE; ehci_memDmb(); - while ((*(hcd->base + usbsts) & USBSTS_AS) != 0) + while ((*(ehci->opbase + usbsts) & USBSTS_AS) != 0) ; } @@ -494,19 +504,19 @@ static int ehci_irqHandler(unsigned int n, void *data) ehci_t *ehci = (ehci_t *)hcd->priv; uint32_t currentStatus; - currentStatus = *(hcd->base + usbsts); + currentStatus = *(ehci->opbase + usbsts); do { - *(hcd->base + usbsts) = currentStatus & EHCI_INTRMASK; + *(ehci->opbase + usbsts) = currentStatus & EHCI_INTRMASK; ehci->status |= currentStatus; /* For edge triggered interrupts to prevent losing interrupts, * poll the usbsts register until it is stable */ - currentStatus = *(hcd->base + usbsts); + currentStatus = *(ehci->opbase + usbsts); } while ((currentStatus & EHCI_INTRMASK) != 0); if (ehci->status & USBSTS_PCI) - ehci->portsc = *(hcd->base + portsc1); + ehci->portsc = *(ehci->opbase + portsc1); return -!(ehci->status & EHCI_INTRMASK); } @@ -600,8 +610,9 @@ static void ehci_irqThread(void *arg) mutexUnlock(hcd->transLock); } - if (ehci->status & USBSTS_PCI) + if (ehci->status & USBSTS_PCI) { ehci_portStatusChanged(hcd); + } } } @@ -677,7 +688,7 @@ static int ehci_transferEnqueue(hcd_t *hcd, usb_transfer_t *t, usb_pipe_t *pipe) /* Data stage */ if ((t->type == usb_transfer_control && t->size > 0) || t->type == usb_transfer_bulk || - t->type == usb_transfer_interrupt) { + t->type == usb_transfer_interrupt) { if (ehci_qtdAdd(hcd->priv, &qtds, token, pipe->maxPacketLen, t->buffer, t->size, 1) < 0) { ehci_qtdsPut(hcd->priv, &qtds); t->hcdpriv = NULL; @@ -844,27 +855,57 @@ static int ehci_init(hcd_t *hcd) ehci_free(ehci); return -ENOMEM; } + interrupt(hcd->info->irq, ehci_irqHandler, hcd, ehci->irqCond, &ehci->irqHandle); + if (((addr_t)hcd->base & (0x20 - 1)) != 0) { + fprintf(stderr, "ehci: USBBASE not aligned to 32 bits\n"); + ehci_free(ehci); + return -EINVAL; + } + + /* Set USBBASE */ + ehci->base = hcd->base; + +#ifdef EHCI_IMX + /* imx deviation: Here we don't distinguish between base/opbase addresses, as + * the distance between operational register base and USBBASE is a known + * constant accounted for in the register enum already. */ + ehci->opbase = ehci->base; +#else + /* In general, EHCI states that the operational register base has address: + * USBBASE + CAPLENGTH */ + ehci->opbase = (volatile int *)((char *)ehci->base + *(uint8_t *)(ehci->base + caplength)); +#endif + /* Reset controller */ - *(hcd->base + usbcmd) |= 2; - while (*(hcd->base + usbcmd) & 2) + *(ehci->opbase + usbcmd) |= USBCMD_HCRESET; + while ((*(ehci->opbase + usbcmd) & USBCMD_HCRESET) != 0) ; - /* Set host mode */ - *(hcd->base + usbmode) |= 3; +#ifdef EHCI_IMX + /* imx deviation: Set host mode */ + *(ehci->opbase + usbmode) |= 3; +#endif /* Enable interrupts */ - *(hcd->base + usbintr) = USBSTS_UI | USBSTS_UEI; + *(ehci->opbase + usbintr) = USBSTS_UI | USBSTS_UEI; /* Set periodic frame list */ - *(hcd->base + periodiclistbase) = va2pa(ehci->periodicList); + *(ehci->opbase + periodiclistbase) = va2pa(ehci->periodicList); + +#ifdef EHCI_IMX + /* imx deviation: Set frame list size (128 bytes) */ + *(ehci->opbase + usbcmd) |= (3 << 2); +#endif - /* Set interrupts threshold, frame list size - 128 bytes, turn controller on */ - *(hcd->base + usbcmd) |= (1 << 4) | (3 << 2) | 1; + /* Enable periodic scheduling, turn the controller on */ + *(ehci->opbase + usbcmd) |= USBCMD_PSE | USBCMD_RUN; + while ((*(ehci->opbase + usbsts) & (USBSTS_HCH)) != 0) + ; /* Route all ports to this host controller */ - *(hcd->base + configflag) = 1; + *(ehci->opbase + configflag) = 1; ehci_startAsync(hcd); diff --git a/usb/ehci/ehci.h b/usb/ehci/ehci.h index e8dd87ad8..ff99f035b 100644 --- a/usb/ehci/ehci.h +++ b/usb/ehci/ehci.h @@ -31,8 +31,11 @@ #define EHCI_INTRMASK (USBSTS_PCI | USBSTS_UEI | USBSTS_UI) -#define USBCMD_ASE (1 << 5) -#define USBCMD_IAA (1 << 6) +#define USBCMD_RUN (1 << 0) +#define USBCMD_HCRESET (1 << 1) +#define USBCMD_PSE (1 << 4) +#define USBCMD_ASE (1 << 5) +#define USBCMD_IAA (1 << 6) #define PORTSC_PTS_1 (3 << 30) #define PORTSC_STS (1 << 29) @@ -116,6 +119,9 @@ #define EHCI_MAX_QTD_POOL 20 #define EHCI_MAX_QH_POOL 10 + +/* clang-format off */ +#ifdef EHCI_IMX enum { /* identification regs */ id = 0x0, hwgeneral, hwhost, hwdevice, hwtxbuf, hwrxbuf, @@ -136,10 +142,24 @@ enum { endptctrl2, endptctrl3, endptctrl4, endptctrl5, endptctrl6, endptctrl7, }; - enum { usb_otg1_ctrl = 0x200, usb_otg2_ctrl, usb_otg1_phy_ctrl = usb_otg2_ctrl + 5, usb_otg2_phy_ctrl }; enum { ehci_item_itd = 0, ehci_item_qh, ehci_item_sitd, ehci_item_fstn }; +#else +enum { + /* capability regs */ + caplength = 0x0, hciversion = 0x0, hcsparams, hccparams, + hcspportroute1, hcspportroute2 /* hcspportroute is a 64-bit register */ +}; + +enum { + /* operational regs */ + usbcmd = 0x0, usbsts, usbintr, frindex, ctrldssegment, + periodiclistbase = 0x5, asynclistaddr, + configflag = 0x10, portsc1 +}; +#endif +/* clang-format on */ struct qtd { @@ -184,6 +204,7 @@ typedef struct _ehci_qh { typedef struct { char stack[1024] __attribute__((aligned(8))); + uint32_t *periodicList; ehci_qh_t *asyncList; ehci_qh_t **periodicNodes; @@ -197,6 +218,9 @@ typedef struct { volatile unsigned portResetChange; volatile unsigned status; volatile unsigned portsc; + + volatile int *base; + volatile int *opbase; } ehci_t; diff --git a/usb/ehci/phy-generic.c b/usb/ehci/phy-generic.c new file mode 100644 index 000000000..c52c9a2fe --- /dev/null +++ b/usb/ehci/phy-generic.c @@ -0,0 +1,175 @@ +/* + * Phoenix-RTOS + * + * EHCI USB Physical Layer for ia32 + * + * Copyright 2024 Phoenix Systems + * Author: Adam Greloch + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define EHCI_MAP_SIZE (0x1000) + +#define EHCI_HCD_CLASS (0x0c03) /* Serial bus controller / USB controller */ +#define EHCI_HCD_PROGIF (0x20) /* EHCI */ + +#define EHCI_HCCPARAMS_EECP (0x8) + + +int hcd_getInfo(const hcd_info_t **info) +{ + platformctl_t pctl; + int i, err; + + hcd_info_t *hcd_info = NULL; + + pctl.action = pctl_get; + pctl.type = pctl_pci; + pctl.pci.id.cl = EHCI_HCD_CLASS; + pctl.pci.id.progif = EHCI_HCD_PROGIF; + pctl.pci.dev.bus = 0; + pctl.pci.dev.dev = 0; + pctl.pci.dev.func = 0; + pctl.pci.caps = NULL; + + i = 0; + for (;;) { + pctl.pci.id.vendor = PCI_VENDOR_INTEL; + pctl.pci.id.device = PCI_ANY; + pctl.pci.id.subvendor = PCI_ANY; + pctl.pci.id.subdevice = PCI_ANY; + + err = platformctl(&pctl); + + if (err == -ENODEV) { + break; + } + + if (err < 0) { + fprintf(stderr, "phy: pctl_get failed\n"); + return err; + } + + if (pctl.pci.dev.progif != EHCI_HCD_PROGIF) { + pctl.pci.dev.func++; + continue; + } + + hcd_info = realloc(hcd_info, sizeof(hcd_info_t) * (i + 1)); + if (hcd_info == NULL) { + return -ENOMEM; + } + memset((void *)(hcd_info + i), 0, sizeof(hcd_info_t)); + + sprintf(hcd_info[i].type, "ehci"); + hcd_info[i].hcdaddr = pctl.pci.dev.resources[0].base; + hcd_info[i].irq = pctl.pci.dev.irq; + hcd_info[i].pci_devId.bus = pctl.pci.dev.bus; + hcd_info[i].pci_devId.dev = pctl.pci.dev.dev; + hcd_info[i].pci_devId.func = pctl.pci.dev.func; + + i++; + pctl.pci.dev.func++; + } + + *info = hcd_info; + + return i; +} + + +static void phy_config(hcd_t *hcd) +{ + platformctl_t pctl; + int err; + uint8_t eecp; + short bus = hcd->info->pci_devId.bus; + short dev = hcd->info->pci_devId.dev; + short func = hcd->info->pci_devId.func; + + pctl.action = pctl_set; + pctl.type = pctl_pcicfg; + pctl.pcicfg.dev.bus = bus; + pctl.pcicfg.dev.dev = dev; + pctl.pcicfg.dev.func = func; + pctl.pcicfg.cfg = pci_cfg_busmaster; + pctl.pcicfg.enable = 1; + + err = platformctl(&pctl); + if (err < 0) { + fprintf(stderr, "phy: setting busmaster failed: %d\n", err); + } + + pctl.pcicfg.cfg = pci_cfg_memoryspace; + pctl.pcicfg.enable = 1; + + err = platformctl(&pctl); + if (err < 0) { + fprintf(stderr, "phy: setting memoryspace failed: %d\n", err); + } + + pctl.pcicfg.cfg = pci_cfg_interruptdisable; + pctl.pcicfg.enable = 0; + + err = platformctl(&pctl); + if (err < 0) { + fprintf(stderr, "phy: enabling interrupts failed: %d\n", err); + } + + eecp = (*(uint32_t *)((char *)hcd->base + EHCI_HCCPARAMS_EECP) >> 8) & 0xFF; + + if (eecp >= 0x40) { + /* Take ownership of the controller from BIOS */ + pctl.action = pctl_set; + pctl.type = pctl_usbownership; + pctl.usbownership.dev.bus = bus; + pctl.usbownership.dev.dev = dev; + pctl.usbownership.dev.func = func; + pctl.usbownership.osOwned = 1; + pctl.usbownership.eecp = eecp; + + err = platformctl(&pctl); + if (err < 0) { + fprintf(stderr, "phy: taking controller ownership from BIOS failed: %d\n", err); + } + } +} + + +void phy_enableHighSpeedDisconnect(hcd_t *hcd, int enable) +{ +} + + +int phy_init(hcd_t *hcd) +{ + off_t offs; + + hcd->phybase = NULL; + + offs = hcd->info->hcdaddr % _PAGE_SIZE; + hcd->base = mmap(NULL, EHCI_MAP_SIZE, PROT_WRITE | PROT_READ, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, hcd->info->hcdaddr - offs); + if (hcd->base == MAP_FAILED) { + return -ENOMEM; + } + hcd->base += (offs / sizeof(int)); + + phy_config(hcd); + + return 0; +} From b7c83fb01c7208ca63fb382f709dbbbeaa7dca4b Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Mon, 28 Oct 2024 10:07:12 +0100 Subject: [PATCH 03/29] usb/ehci: rename per-subfamily phy src to per-family-subfamily JIRA: RTOS-937 (cherry picked from commit ff920258bf559803d6e4f18eafcdeb62d6e3f88e) --- usb/ehci/Makefile | 5 ++--- usb/ehci/{phy-imx6ull.c => phy-armv7a7-imx6ull.c} | 0 usb/ehci/{phy-imxrt106x.c => phy-armv7m7-imxrt106x.c} | 0 usb/ehci/{phy-imxrt117x.c => phy-armv7m7-imxrt117x.c} | 0 usb/ehci/{phy-generic.c => phy-ia32-generic.c} | 0 5 files changed, 2 insertions(+), 3 deletions(-) rename usb/ehci/{phy-imx6ull.c => phy-armv7a7-imx6ull.c} (100%) rename usb/ehci/{phy-imxrt106x.c => phy-armv7m7-imxrt106x.c} (100%) rename usb/ehci/{phy-imxrt117x.c => phy-armv7m7-imxrt117x.c} (100%) rename usb/ehci/{phy-generic.c => phy-ia32-generic.c} (100%) diff --git a/usb/ehci/Makefile b/usb/ehci/Makefile index 044ca23de..50875c6bc 100644 --- a/usb/ehci/Makefile +++ b/usb/ehci/Makefile @@ -1,13 +1,12 @@ # -# Makefile for Phoenix-RTOS imx6ull-ehci +# Makefile for Phoenix-RTOS ehci # # Copyright 2018, 2019 Phoenix Systems # # FIXME: rename usb host component NAME := libusbehci -# TODO use TARGET_FAMILY-TARGET_SUBFAMILY -LOCAL_SRCS := ehci.c ehci-hub.c phy-$(TARGET_SUBFAMILY).c +LOCAL_SRCS := ehci.c ehci-hub.c phy-$(TARGET_FAMILY)-$(TARGET_SUBFAMILY).c ifneq (,$(findstring imx,$(TARGET_SUBFAMILY))) LOCAL_CFLAGS += -DEHCI_IMX diff --git a/usb/ehci/phy-imx6ull.c b/usb/ehci/phy-armv7a7-imx6ull.c similarity index 100% rename from usb/ehci/phy-imx6ull.c rename to usb/ehci/phy-armv7a7-imx6ull.c diff --git a/usb/ehci/phy-imxrt106x.c b/usb/ehci/phy-armv7m7-imxrt106x.c similarity index 100% rename from usb/ehci/phy-imxrt106x.c rename to usb/ehci/phy-armv7m7-imxrt106x.c diff --git a/usb/ehci/phy-imxrt117x.c b/usb/ehci/phy-armv7m7-imxrt117x.c similarity index 100% rename from usb/ehci/phy-imxrt117x.c rename to usb/ehci/phy-armv7m7-imxrt117x.c diff --git a/usb/ehci/phy-generic.c b/usb/ehci/phy-ia32-generic.c similarity index 100% rename from usb/ehci/phy-generic.c rename to usb/ehci/phy-ia32-generic.c From d62a69ba63c646291ab4f8fe3fc510325ce67868 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 20 Dec 2024 12:25:08 +0100 Subject: [PATCH 04/29] usb/ehci: adapt hcd driver to ia32 hw The root hub is now declared with bDeviceProtocol 0 instead of 1 to differentiate between root hubs and real TT layer 2 hubs in the usb stack JIRA: RTOS-937 (cherry picked from commit 2dc30475a4813f4cd58b035486bdd8eb493a954a) --- usb/ehci/ehci-hub.c | 55 +++++++++--- usb/ehci/ehci.c | 173 +++++++++++++++++++++++++++++------- usb/ehci/ehci.h | 35 ++++++-- usb/ehci/phy-ia32-generic.c | 4 + 4 files changed, 216 insertions(+), 51 deletions(-) diff --git a/usb/ehci/ehci-hub.c b/usb/ehci/ehci-hub.c index ca8235d79..2f34ce70d 100644 --- a/usb/ehci/ehci-hub.c +++ b/usb/ehci/ehci-hub.c @@ -3,8 +3,8 @@ * * ehci root hub implementation * - * Copyright 2021 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -39,7 +39,12 @@ static const struct { .bcdUSB = 0x0200, .bDeviceClass = USB_CLASS_HUB, .bDeviceSubClass = 0, +#ifdef EHCI_IMX + /* imx deviation: the controller has an embedded TT */ .bDeviceProtocol = 1, /* Single TT */ +#else + .bDeviceProtocol = 0, /* Root hub */ +#endif .bMaxPacketSize0 = 64, .idVendor = 0x0, .idProduct = 0x0, @@ -87,10 +92,14 @@ static const struct { static void ehci_resetPort(hcd_t *hcd, int port) { ehci_t *ehci = (ehci_t *)hcd->priv; - volatile int *reg = (ehci->opbase + portsc1) + (port - 1); + volatile uint32_t *reg = (ehci->opbase + portsc1) + (port - 1); + uint32_t tmp; + + log_debug("resetting port %d", port); - *reg &= ~PORTSC_ENA; - *reg |= PORTSC_PR; + tmp = *reg; + tmp &= ~(PORTSC_ENA | PORTSC_PR); + *reg = tmp | PORTSC_PR; #ifdef EHCI_IMX /* @@ -101,8 +110,25 @@ static void ehci_resetPort(hcd_t *hcd, int port) ; usleep(20 * 1000); #else + /* Wait for reset to complete */ + usleep(50 * 1000); + + /* Stop the reset sequence */ + *reg = tmp; + + /* Wait until reset sequence stops */ + while ((*reg & PORTSC_PR) != 0) + ; + usleep(20 * 1000); - *reg &= ~PORTSC_PR; + + tmp = *reg; + + log_debug("port %d reset done, status after reset=%x", port, tmp); + + if ((tmp & PORTSC_ENA) == 0) { + log_debug("device on port %d is not a highspeed device", port); + } #endif ehci->portResetChange = 1 << port; @@ -116,7 +142,7 @@ static int ehci_getPortStatus(usb_dev_t *hub, int port, usb_port_status_t *statu { hcd_t *hcd = hub->hcd; ehci_t *ehci = (ehci_t *)hcd->priv; - int val; + uint32_t val; if (port > hub->nports) return -1; @@ -158,10 +184,15 @@ static int ehci_getPortStatus(usb_dev_t *hub, int port, usb_port_status_t *statu if (ehci->portResetChange & (1 << port)) status->wPortChange |= USB_PORT_STAT_C_RESET; +#ifdef EHCI_IMX if ((val & PORTSC_PSPD) >> 26 == 1) status->wPortStatus |= USB_PORT_STAT_LOW_SPEED; else if ((val & PORTSC_PSPD) >> 26 == 2) status->wPortStatus |= USB_PORT_STAT_HIGH_SPEED; +#else + /* TODO handle low/full speed devices on ia32 */ + status->wPortStatus |= USB_PORT_STAT_HIGH_SPEED; +#endif /* TODO: set indicator */ @@ -198,7 +229,7 @@ static int ehci_clearPortFeature(usb_dev_t *hub, int port, uint16_t wValue) { hcd_t *hcd = hub->hcd; ehci_t *ehci = (ehci_t *)hcd->priv; - volatile int *portsc = ehci->opbase + portsc1 + port - 1; + volatile uint32_t *portsc = (ehci->opbase + portsc1) + (port - 1); uint32_t val = *portsc; if (port > hub->nports) @@ -329,16 +360,18 @@ static int ehci_getDesc(usb_dev_t *hub, int type, int index, char *buf, size_t s uint32_t ehci_getHubStatus(usb_dev_t *hub) { hcd_t *hcd = hub->hcd; - uint32_t status = 0; - int i, val; + uint32_t status = 0, val; + int i; ehci_t *ehci = (ehci_t *)hcd->priv; for (i = 0; i < hub->nports; i++) { - val = ehci->portsc; + val = *(ehci->opbase + portsc1 + i); + log_debug("(INT%d) port %d portsc: %x", hcd->info->irq, i + 1, val); if (val & (PORTSC_CSC | PORTSC_PEC | PORTSC_OCC)) status |= 1 << (i + 1); } + log_debug("(INT%d): status: %x", hcd->info->irq, status); return status; } diff --git a/usb/ehci/ehci.c b/usb/ehci/ehci.c index dafcd3c57..1033d9e4e 100644 --- a/usb/ehci/ehci.c +++ b/usb/ehci/ehci.c @@ -5,9 +5,9 @@ * * ehci/ehci.c * - * Copyright 2018, 2021 Phoenix Systems + * Copyright 2018, 2021, 2024 Phoenix Systems * Copyright 2007 Pawel Pisarczyk - * Author: Jan Sikorski, Maciej Purski + * Author: Jan Sikorski, Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -170,6 +171,34 @@ static void ehci_qtdsPut(ehci_t *ehci, ehci_qtd_t **head) } +static void +ehci_qtdDump(ehci_qtd_t *qtd, bool dump_bufs) +{ +#if EHCI_DEBUG_QTD + uint32_t s; + + s = qtd->hw->token; + fprintf(stderr, "sts=0x%08x: tog=%d sz=0x%x ioc=%d", + s, s >> 31, (s >> 16) & 0x7fff, + (s >> 15) & 0b1); + fprintf(stderr, " cerr=%d pid=%d %s%s%s%s%s%s%s%s\n", + (s >> 10) & 0b11, (s >> 8) & 0b11, + (s & QTD_ACTIVE) ? "ACTIVE" : "NOT_ACTIVE", + (s & QTD_HALTED) ? "-HALTED" : "", + (s & QTD_BUFERR) ? "-BUFERR" : "", + (s & QTD_BABBLE) ? "-BABBLE" : "", + (s & QTD_XACT) ? "-XACT" : "", + (s & QTD_MISSED_UFRAME) ? "-MISSED" : "", + (s & QTD_SPLIT) ? "-SPLIT" : "", + (s & QTD_PING) ? "-PING" : ""); + + for (s = 0; dump_bufs && s < EHCI_QH_NBUFS; s++) { + fprintf(stderr, " buf[%d]=0x%08x buf_hi[%d]=0x%08x\n", s, qtd->hw->buf[s], s, qtd->hw->buf_hi[s]); + } +#endif +} + + static ehci_qtd_t *ehci_qtdAlloc(ehci_t *ehci, int pid, size_t maxpacksz, char *data, size_t *size, int datax) { ehci_qtd_t *qtd; @@ -195,21 +224,30 @@ static ehci_qtd_t *ehci_qtdAlloc(ehci_t *ehci, int pid, size_t maxpacksz, char * if (data != NULL) { qtd->hw->buf[0] = (uintptr_t)va2pa(data); + qtd->hw->buf_hi[0] = 0; + offs = min(EHCI_PAGE_SIZE - QTD_OFFSET(qtd->hw->buf[0]), *size); bytes += offs; data += offs; - for (i = 1; i < 5 && bytes != *size; i++) { + for (i = 1; i < EHCI_QH_NBUFS && bytes != *size; i++) { qtd->hw->buf[i] = va2pa(data) & ~0xfff; + qtd->hw->buf_hi[i] = 0; + offs = min(*size - bytes, EHCI_PAGE_SIZE); /* If the data does not fit one qtd, don't leave a trailing short packet */ - if (i == 4 && bytes + offs < *size) + if (i == EHCI_QH_NBUFS - 1 && bytes + offs < *size) offs = (((bytes + offs) / maxpacksz) * maxpacksz) - bytes; bytes += offs; data += offs; } + for (; i < EHCI_QH_NBUFS; i++) { + qtd->hw->buf[i] = 0; + qtd->hw->buf_hi[i] = 0; + } + qtd->hw->token |= bytes << 16; *size -= bytes; } @@ -258,6 +296,7 @@ static void ehci_qhPut(ehci_t *ehci, ehci_qh_t *qh) static ehci_qh_t *ehci_qhAlloc(ehci_t *ehci) { ehci_qh_t *qh; + int i; if ((qh = ehci_qhGet(ehci)) == NULL) { if ((qh = malloc(sizeof(ehci_qh_t))) == NULL) @@ -284,6 +323,11 @@ static ehci_qh_t *ehci_qhAlloc(ehci_t *ehci) qh->phase = 0; qh->lastQtd = NULL; + for (i = 0; i < EHCI_QH_NBUFS; i++) { + qh->hw->buf[i] = 0; + qh->hw->buf_hi[i] = 0; + } + return qh; } @@ -506,7 +550,7 @@ static int ehci_irqHandler(unsigned int n, void *data) currentStatus = *(ehci->opbase + usbsts); do { - *(ehci->opbase + usbsts) = currentStatus & EHCI_INTRMASK; + *(ehci->opbase + usbsts) = currentStatus & (EHCI_INTRMASK | USBSTS_FRI); ehci->status |= currentStatus; @@ -515,9 +559,6 @@ static int ehci_irqHandler(unsigned int n, void *data) currentStatus = *(ehci->opbase + usbsts); } while ((currentStatus & EHCI_INTRMASK) != 0); - if (ehci->status & USBSTS_PCI) - ehci->portsc = *(ehci->opbase + portsc1); - return -!(ehci->status & EHCI_INTRMASK); } @@ -530,8 +571,10 @@ static int ehci_qtdsCheck(hcd_t *hcd, usb_transfer_t *t, int *status) *status = 0; do { - if (qtds->hw->token & (QTD_XACT | QTD_BABBLE | QTD_BUFERR)) + ehci_qtdDump(qtds, false); + if (qtds->hw->token & (QTD_XACT | QTD_BABBLE | QTD_BUFERR | QTD_HALTED)) { error++; + } qtds = qtds->next; } while (qtds != t->hcdpriv); @@ -595,6 +638,29 @@ static void ehci_portStatusChanged(hcd_t *hcd) } +#if EHCI_DEBUG_IRQ +static void ehci_printIrq(hcd_t *hcd) +{ + ehci_t *ehci = (ehci_t *)hcd->priv; + static char buf[30]; + size_t i = 0; + + i += sprintf(buf, "INT%d: ", hcd->info->irq); + +#define append_to_buf(interrupt) \ + if (ehci->status & (interrupt)) { \ + i += sprintf(buf + i, #interrupt " "); \ + } + append_to_buf(USBSTS_UI); + append_to_buf(USBSTS_UEI); + append_to_buf(USBSTS_SEI); + append_to_buf(USBSTS_PCI); + + log_debug("%s", buf); +} +#endif + + static void ehci_irqThread(void *arg) { hcd_t *hcd = (hcd_t *)arg; @@ -604,13 +670,29 @@ static void ehci_irqThread(void *arg) for (;;) { condWait(ehci->irqCond, ehci->irqLock, 0); +#if EHCI_DEBUG_IRQ + ehci_printIrq(hcd); +#endif + + /* The irqThread must clear the handler interrupt status, + since otherwise it would handle ghost interrupts + on every interrupt (irqHandler never clears ehci->status) */ + if (ehci->status & USBSTS_SEI) { + ehci->status &= ~USBSTS_SEI; + log_error("host system error, controller halted"); + /* TODO cleanup/reset after death */ + continue; + } + if (ehci->status & (USBSTS_UI | USBSTS_UEI)) { + ehci->status &= ~(USBSTS_UI | USBSTS_UEI); mutexLock(hcd->transLock); ehci_transUpdate(hcd); mutexUnlock(hcd->transLock); } if (ehci->status & USBSTS_PCI) { + ehci->status &= ~USBSTS_PCI; ehci_portStatusChanged(hcd); } } @@ -627,7 +709,7 @@ static int ehci_qtdAdd(ehci_t *ehci, ehci_qtd_t **list, int token, size_t maxpac return -ENOMEM; LIST_ADD(list, tmp); - dt = !dt; + dt = 1 - dt; } while (remaining > 0); return 0; @@ -786,21 +868,21 @@ static int ehci_init(hcd_t *hcd) { ehci_t *ehci; ehci_qh_t *qh; - int i; + int i, ret; if ((ehci = calloc(1, sizeof(ehci_t))) == NULL) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); return -ENOMEM; } if ((ehci->periodicList = usb_allocAligned(EHCI_PERIODIC_SIZE * sizeof(uint32_t), EHCI_PERIODIC_ALIGN)) == NULL) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } if ((ehci->periodicNodes = calloc(EHCI_PERIODIC_SIZE, sizeof(ehci_qh_t *))) == NULL) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } @@ -808,31 +890,31 @@ static int ehci_init(hcd_t *hcd) hcd->priv = ehci; if (phy_init(hcd) != 0) { - fprintf(stderr, "ehci: Phy init failed!\n"); + log_error("Phy init failed!"); ehci_free(ehci); return -EINVAL; } if (condCreate(&ehci->irqCond) < 0) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } if (mutexCreate(&ehci->irqLock) < 0) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } if (mutexCreate(&ehci->asyncLock) < 0) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } if (mutexCreate(&ehci->periodicLock) < 0) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } @@ -840,7 +922,7 @@ static int ehci_init(hcd_t *hcd) /* Initialize Async List with a dummy qh to optimize * accesses and make them safer */ if ((qh = ehci_qhAlloc(ehci)) == NULL) { - fprintf(stderr, "ehci: Out of memory!\n"); + log_error("Out of memory!"); ehci_free(ehci); return -ENOMEM; } @@ -851,15 +933,8 @@ static int ehci_init(hcd_t *hcd) for (i = 0; i < EHCI_PERIODIC_SIZE; ++i) ehci->periodicList[i] = QH_PTR_INVALID; - if (beginthread(ehci_irqThread, EHCI_PRIO, ehci->stack, sizeof(ehci->stack), hcd) != 0) { - ehci_free(ehci); - return -ENOMEM; - } - - interrupt(hcd->info->irq, ehci_irqHandler, hcd, ehci->irqCond, &ehci->irqHandle); - if (((addr_t)hcd->base & (0x20 - 1)) != 0) { - fprintf(stderr, "ehci: USBBASE not aligned to 32 bits\n"); + log_error("USBBASE not aligned to 32 bits"); ehci_free(ehci); return -EINVAL; } @@ -875,7 +950,28 @@ static int ehci_init(hcd_t *hcd) #else /* In general, EHCI states that the operational register base has address: * USBBASE + CAPLENGTH */ - ehci->opbase = (volatile int *)((char *)ehci->base + *(uint8_t *)(ehci->base + caplength)); + ehci->opbase = (volatile uint32_t *)((char *)ehci->base + *(uint8_t *)(ehci->base + caplength)); +#endif + + log_debug("attaching handler to irq=%d", hcd->info->irq); + ret = interrupt(hcd->info->irq, ehci_irqHandler, hcd, ehci->irqCond, &ehci->irqHandle); + + if (ret < 0) { + log_error("failed to set interrupt handler"); + return ret; + } + + if (beginthread(ehci_irqThread, EHCI_PRIO, ehci->stack, sizeof(ehci->stack), hcd) != 0) { + ehci_free(ehci); + return -ENOMEM; + } + +#ifndef EHCI_IMX + /* Hangs controller on imx */ + *(ehci->opbase + usbcmd) &= ~(USBCMD_RUN | USBCMD_IAA); + + while ((*(ehci->opbase + usbsts) & USBSTS_HCH) == 0) + ; #endif /* Reset controller */ @@ -886,29 +982,40 @@ static int ehci_init(hcd_t *hcd) #ifdef EHCI_IMX /* imx deviation: Set host mode */ *(ehci->opbase + usbmode) |= 3; +#else + if ((*(ehci->base + hccparams) & HCCPARAMS_64BIT_ADDRS) != 0) { + *(ehci->opbase + ctrldssegment) = 0; + } #endif /* Enable interrupts */ - *(ehci->opbase + usbintr) = USBSTS_UI | USBSTS_UEI; + *(ehci->opbase + usbintr) = USBSTS_UI | USBSTS_UEI | USBSTS_SEI; /* Set periodic frame list */ *(ehci->opbase + periodiclistbase) = va2pa(ehci->periodicList); #ifdef EHCI_IMX - /* imx deviation: Set frame list size (128 bytes) */ + /* imx deviation: Set frame list size (128 elements) */ *(ehci->opbase + usbcmd) |= (3 << 2); #endif - /* Enable periodic scheduling, turn the controller on */ - *(ehci->opbase + usbcmd) |= USBCMD_PSE | USBCMD_RUN; + /* Turn the controller on, enable periodic scheduling */ + *(ehci->opbase + usbcmd) &= ~(USBCMD_LRESET | USBCMD_ASE); + + *(ehci->opbase + usbcmd) |= (USBCMD_PSE | USBCMD_RUN); while ((*(ehci->opbase + usbsts) & (USBSTS_HCH)) != 0) ; /* Route all ports to this host controller */ *(ehci->opbase + configflag) = 1; + /* Allow for the hardware to catch up */ + usleep(50 * 1000); + ehci_startAsync(hcd); + log_debug("hc initialized"); + return 0; } diff --git a/usb/ehci/ehci.h b/usb/ehci/ehci.h index ff99f035b..06203adcb 100644 --- a/usb/ehci/ehci.h +++ b/usb/ehci/ehci.h @@ -3,8 +3,8 @@ * * USB EHCI host controller * - * Copyright 2021 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -14,6 +14,18 @@ #ifndef _USB_EHCI_H_ #define _USB_EHCI_H_ +#define EHCI_DEBUG 0 +#define EHCI_DEBUG_IRQ 0 +#define EHCI_DEBUG_QTD 0 + +#define LOG_TAG "ehci: " + +/* clang-format off */ +#define log_msg(fmt, ...) do { fprintf(stderr, LOG_TAG fmt "\n", ##__VA_ARGS__); } while (0) +#define log_error(fmt, ...) do { log_msg("error: " fmt, ##__VA_ARGS__); } while (0) +#define log_debug(fmt, ...) do { if (EHCI_DEBUG != 0) log_msg(fmt, ##__VA_ARGS__); } while (0) +/* clang-format on */ + #define USBSTS_AS (1 << 15) #define USBSTS_PS (1 << 14) #define USBSTS_RCL (1 << 13) @@ -29,13 +41,14 @@ #define USBSTS_UEI (1 << 1) #define USBSTS_UI (1 << 0) -#define EHCI_INTRMASK (USBSTS_PCI | USBSTS_UEI | USBSTS_UI) +#define EHCI_INTRMASK (USBSTS_SEI | USBSTS_PCI | USBSTS_UEI | USBSTS_UI) #define USBCMD_RUN (1 << 0) #define USBCMD_HCRESET (1 << 1) #define USBCMD_PSE (1 << 4) #define USBCMD_ASE (1 << 5) #define USBCMD_IAA (1 << 6) +#define USBCMD_LRESET (1 << 7) #define PORTSC_PTS_1 (3 << 30) #define PORTSC_STS (1 << 29) @@ -111,6 +124,8 @@ /* 'change' bits cleared by writing 1 */ #define PORTSC_CBITS (PORTSC_CSC | PORTSC_PEC | PORTSC_OCC) +#define HCCPARAMS_64BIT_ADDRS (1 << 0) + #define EHCI_PAGE_SIZE 4096 #define EHCI_PERIODIC_ALIGN 4096 @@ -161,15 +176,21 @@ enum { #endif /* clang-format on */ +/* TODO: buf_hi is required only on ia32 if hcd is capable of 64-bit addressing + * Shrink it on smaller targets to save memory? */ struct qtd { uint32_t next; uint32_t altnext; uint32_t token; uint32_t buf[5]; + uint32_t buf_hi[5]; }; +#define EHCI_QH_NBUFS 5 + + struct qh { uint32_t horizontal; uint32_t info[2]; @@ -179,7 +200,8 @@ struct qh { uint32_t nextQtd; uint32_t altnextQtd; uint32_t token; - uint32_t buf[5]; + uint32_t buf[EHCI_QH_NBUFS]; + uint32_t buf_hi[EHCI_QH_NBUFS]; }; @@ -217,10 +239,9 @@ typedef struct { handle_t irqCond, irqHandle, irqLock, asyncLock, periodicLock; volatile unsigned portResetChange; volatile unsigned status; - volatile unsigned portsc; - volatile int *base; - volatile int *opbase; + volatile uint32_t *base; + volatile uint32_t *opbase; } ehci_t; diff --git a/usb/ehci/phy-ia32-generic.c b/usb/ehci/phy-ia32-generic.c index c52c9a2fe..2d4ab92ce 100644 --- a/usb/ehci/phy-ia32-generic.c +++ b/usb/ehci/phy-ia32-generic.c @@ -78,7 +78,11 @@ int hcd_getInfo(const hcd_info_t **info) sprintf(hcd_info[i].type, "ehci"); hcd_info[i].hcdaddr = pctl.pci.dev.resources[0].base; + + /* TODO do ACPI _PRT lookup instead */ + fprintf(stderr, "phy: choosing default irq from pci\n"); hcd_info[i].irq = pctl.pci.dev.irq; + hcd_info[i].pci_devId.bus = pctl.pci.dev.bus; hcd_info[i].pci_devId.dev = pctl.pci.dev.dev; hcd_info[i].pci_devId.func = pctl.pci.dev.func; From 912cca67b3c1f6ba55d4656e72550dd44fce9ceb Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 18 Oct 2024 09:39:48 +0200 Subject: [PATCH 05/29] storage/umass: implement ext2 mounting JIRA: RTOS-970 (cherry picked from commit c299eb80da744666de2b5bfe59f6f91794bb9955) --- storage/umass/Makefile | 5 + storage/umass/umass.c | 571 +++++++++++++++++++++++++++++++++++------ 2 files changed, 492 insertions(+), 84 deletions(-) diff --git a/storage/umass/Makefile b/storage/umass/Makefile index 9e8c90608..d6d4ae253 100644 --- a/storage/umass/Makefile +++ b/storage/umass/Makefile @@ -8,4 +8,9 @@ NAME := umass LOCAL_SRCS := umass.c LIBS := libusb +ifeq ($(TARGET_FAMILY),ia32) + LIBS += libext2 + CFLAGS += -DUMASS_MOUNT_EXT2 +endif + include $(binary.mk) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index acb67d102..0d29688b1 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -3,8 +3,8 @@ * * USB Mass Storage class 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. * @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -26,13 +26,21 @@ #include #include #include +#include + +#include + +#ifdef UMASS_MOUNT_EXT2 +#include +#endif #include #include #include "../pc-ata/mbr.h" -#define UMASS_N_MSG_THREADS 1 +#define UMASS_N_MSG_THREADS 2 +#define UMASS_N_POOL_THREADS 4 #define UMASS_SECTOR_SIZE 512 @@ -42,6 +50,12 @@ #define CBW_SIG 0x43425355 #define CSW_SIG 0x53425355 +/* clang-format off */ +#define LOG(str_, ...) do { printf("umass: " str_ "\n", ##__VA_ARGS__); } while (0) +#define LOG_ERROR(str_, ...) LOG(__FILE__ ":%d error: " str_, __LINE__, ##__VA_ARGS__) +#define TRACE(str_, ...) do { if (0) LOG(__FILE__ ":%d TRACE: " str_, __LINE__, ##__VA_ARGS__); } while (0) +/* clang-format on */ + typedef struct { uint32_t sig; @@ -73,31 +87,94 @@ typedef struct { } __attribute__((packed)) scsi_cdb10_t; +/* Device access callbacks */ +static ssize_t umass_read(id_t id, off_t offs, char *buf, size_t len); +static ssize_t umass_write(id_t id, off_t offs, const char *buf, size_t len); + + +/* Thread types */ +static void umass_fsthr(void *arg); +static void umass_poolthr(void *arg); +static void umass_msgthr(void *arg); + + +/* Filesystem callbacks types */ +typedef int (*fs_handler_t)(void *, msg_t *); +typedef int (*fs_unmount_t)(void *); +typedef int (*fs_mount_t)(oid_t *, unsigned int, typeof(umass_read) *, typeof(umass_write) *, void **); + + +typedef struct { + rbnode_t node; /* RBTree node */ + char name[16]; /* Filesystem name */ + uint8_t type; /* Compatible partition type */ + fs_handler_t handler; /* Message handler callback */ + fs_unmount_t unmount; /* Unmount callback */ + fs_mount_t mount; /* Mount callback */ +} umass_fs_t; + + +typedef struct _umass_part_t { + /* Partition data */ + unsigned int idx; /* Partition index */ + unsigned int port; /* Partition port */ + uint32_t start; /* Partition start */ + uint32_t sectors; /* Number of sectors */ + + /* Filesystem data */ + umass_fs_t *fs; /* Mounted filesystem */ + void *fdata; /* Mounted filesystem data */ + + /* Partition filesystem thread stack */ + char fsstack[4 * _PAGE_SIZE] __attribute__((aligned(8))); +} umass_part_t; + + +typedef struct _umass_req_t { + msg_t msg; /* Request msg */ + msg_rid_t rid; /* Request receiving context */ + umass_part_t *part; /* Request receiver partition */ + struct _umass_req_t *prev, *next; /* Doubly linked list */ +} umass_req_t; + + typedef struct umass_dev { + idnode_t node; /* Device ID */ + char buffer[8 * UMASS_SECTOR_SIZE]; - struct umass_dev *prev, *next; usb_devinfo_t instance; char path[32]; int pipeCtrl; int pipeIn; int pipeOut; - int id; int fileId; int tag; unsigned port; - uint32_t partOffset; - uint32_t partSize; handle_t lock; + + umass_part_t part; /* TODO extend for more partitions */ } umass_dev_t; static struct { - umass_dev_t *devices; - char stack[UMASS_N_MSG_THREADS][1024] __attribute__((aligned(8))); + idtree_t devices; + umass_dev_t device; + unsigned drvport; unsigned msgport; handle_t lock; - int lastId; + rbtree_t fss; /* Registered filesystems */ + + umass_req_t *rqueue; /* Requests FIFO queue */ + handle_t rlock, rcond; /* Requests synchronization */ + + bool mount_root; + + /* Message threads stacks */ + char mstacks[UMASS_N_MSG_THREADS][2 * _PAGE_SIZE] __attribute__((aligned(8))); + + /* Pool threads stacks */ + char pstacks[UMASS_N_POOL_THREADS][4 * _PAGE_SIZE] __attribute__((aligned(8))); } umass_common; @@ -107,7 +184,36 @@ static const usb_device_id_t filters[] = { }; -static int umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, size_t dlen, int dir) +#ifdef UMASS_MOUNT_EXT2 +static int umass_registerfs(const char *name, uint8_t type, fs_mount_t mount, fs_unmount_t unmount, fs_handler_t handler) +{ + umass_fs_t *fs; + + if ((fs = (umass_fs_t *)malloc(sizeof(umass_fs_t))) == NULL) + return -ENOMEM; + + strcpy(fs->name, name); + fs->type = type; + fs->mount = mount; + fs->unmount = unmount; + fs->handler = handler; + lib_rbInsert(&umass_common.fss, &fs->node); + + return EOK; +} +#endif + + +static int umass_cmpfs(rbnode_t *node1, rbnode_t *node2) +{ + umass_fs_t *fs1 = lib_treeof(umass_fs_t, node, node1); + umass_fs_t *fs2 = lib_treeof(umass_fs_t, node, node2); + + return strcmp(fs1->name, fs2->name); +} + + +static int _umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, size_t dlen, int dir) { umass_cbw_t cbw = { 0 }; umass_csw_t csw = { 0 }; @@ -145,7 +251,7 @@ static int umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, return -EIO; } - /* Transferred finished, check transfer correctness */ + /* Transfer finished, check transfer correctness */ if (csw.sig != CSW_SIG || csw.tag != cbw.tag || csw.status != 0) { fprintf(stderr, "umass_transmit: transfer incorrect\n"); return -EIO; @@ -155,7 +261,7 @@ static int umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, } -static int umass_check(umass_dev_t *dev) +static int _umass_check(umass_dev_t *dev) { scsi_cdb10_t readcmd = { .opcode = 0x28, @@ -164,13 +270,13 @@ static int umass_check(umass_dev_t *dev) char testcmd[6] = { 0 }; mbr_t *mbr; - if (umass_transmit(dev, testcmd, sizeof(testcmd), NULL, 0, usb_dir_in) < 0) { + if (_umass_transmit(dev, testcmd, sizeof(testcmd), NULL, 0, usb_dir_in) < 0) { fprintf(stderr, "umass_transmit failed\n"); return -1; } /* Read MBR */ - if (umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, UMASS_SECTOR_SIZE, usb_dir_in) < 0) { + if (_umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, UMASS_SECTOR_SIZE, usb_dir_in) < 0) { fprintf(stderr, "umass_transmit 2 failed\n"); return -1; } @@ -180,39 +286,78 @@ static int umass_check(umass_dev_t *dev) return -1; /* Read only the first partition */ - dev->partOffset = mbr->pent[0].start; - dev->partSize = mbr->pent[0].sectors; + /* TODO read the rest of them*/ + dev->part.start = mbr->pent[0].start; + dev->part.sectors = mbr->pent[0].sectors; + dev->part.fs = NULL; + dev->part.fdata = NULL; + dev->part.idx = 0; return 0; } -static int umass_read(umass_dev_t *dev, off_t offs, char *buf, size_t len) +static umass_fs_t *umass_getfs(const char *name) +{ + umass_fs_t fs; + + strcpy(fs.name, name); + + return lib_treeof(umass_fs_t, node, lib_rbFind(&umass_common.fss, &fs.node)); +} + + +/* TODO: handle mounting other filesystems than ext2 */ +#if 0 +static umass_fs_t *umass_findfs(uint8_t type) +{ + rbnode_t *node; + umass_fs_t *fs; + + for (node = lib_rbMinimum(umass_common.fss.root); node != NULL; node = lib_rbNext(node)) { + fs = lib_treeof(umass_fs_t, node, node); + + if (fs->type == type) + return fs; + } + + return NULL; +} +#endif + + +static int umass_readFromDev(umass_dev_t *dev, off_t offs, char *buf, size_t len) { scsi_cdb10_t readcmd = { .opcode = 0x28 }; int ret; - if ((offs % UMASS_SECTOR_SIZE) || (len % UMASS_SECTOR_SIZE)) + if ((offs % UMASS_SECTOR_SIZE) || (len % UMASS_SECTOR_SIZE)) { return -EINVAL; + } - if (offs + len > dev->partSize * UMASS_SECTOR_SIZE) + if (offs + len > dev->part.sectors * UMASS_SECTOR_SIZE) { return -EINVAL; + } len = min(len, sizeof(dev->buffer)); - readcmd.lba = htonl(offs / UMASS_SECTOR_SIZE + dev->partOffset); + readcmd.lba = htonl(offs / UMASS_SECTOR_SIZE + dev->part.start); readcmd.length = htons((uint16_t)(len / UMASS_SECTOR_SIZE)); mutexLock(dev->lock); - if ((ret = umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, len, usb_dir_in)) > 0) - memcpy(buf, dev->buffer, ret); + ret = _umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, len, usb_dir_in); + if (ret > 0) + memcpy(buf, dev->buffer, len); + else if (len > 0) { + printf("read transmit failed for offs: %lld\n", offs); + } mutexUnlock(dev->lock); return ret; } -static int umass_write(umass_dev_t *dev, off_t offs, const char *buf, size_t len) +static int umass_writeToDev(umass_dev_t *dev, off_t offs, const char *buf, size_t len) { scsi_cdb10_t writecmd = { .opcode = 0x2a }; int ret; @@ -220,18 +365,21 @@ static int umass_write(umass_dev_t *dev, off_t offs, const char *buf, size_t len if ((offs % UMASS_SECTOR_SIZE) || (len % UMASS_SECTOR_SIZE)) return -EINVAL; - if (offs + len > dev->partSize * UMASS_SECTOR_SIZE) + if (offs + len > dev->part.sectors * UMASS_SECTOR_SIZE) return -EINVAL; len = min(len, sizeof(dev->buffer)); - writecmd.lba = htonl(offs / UMASS_SECTOR_SIZE + dev->partOffset); + writecmd.lba = htonl(offs / UMASS_SECTOR_SIZE + dev->part.start); writecmd.length = htons((uint16_t)(len / UMASS_SECTOR_SIZE)); mutexLock(dev->lock); memcpy(dev->buffer, buf, len); - ret = umass_transmit(dev, &writecmd, sizeof(writecmd), dev->buffer, len, usb_dir_out); + ret = _umass_transmit(dev, &writecmd, sizeof(writecmd), dev->buffer, len, usb_dir_out); mutexUnlock(dev->lock); + if (ret < 0) { + fprintf(stderr, "write transmit failed for offs: %lld\n", offs); + } return ret; } @@ -242,25 +390,148 @@ static int umass_getattr(umass_dev_t *dev, int type, long long int *attr) if (type != atSize) return -EINVAL; - *attr = dev->partSize * UMASS_SECTOR_SIZE; + *attr = dev->part.sectors * UMASS_SECTOR_SIZE; return EOK; } -static umass_dev_t *umass_devFind(int id) +static umass_dev_t *_umass_devFind(id_t id) { - umass_dev_t *tmp = umass_common.devices; + return lib_treeof(umass_dev_t, node, idtree_find(&umass_common.devices, id)); +} + - if (tmp != NULL) { - do { - if (tmp->fileId == id) - return tmp; - tmp = tmp->next; - } while (tmp != umass_common.devices); +static ssize_t umass_read(id_t id, off_t offs, char *buf, size_t len) +{ + mutexLock(umass_common.lock); + umass_dev_t *dev = _umass_devFind(id); + mutexUnlock(umass_common.lock); + if (dev == NULL) { + return -ENODEV; } + return umass_readFromDev(dev, offs, buf, len); +} - return NULL; + +static ssize_t umass_write(id_t id, off_t offs, const char *buf, size_t len) +{ + mutexLock(umass_common.lock); + umass_dev_t *dev = _umass_devFind(id); + mutexUnlock(umass_common.lock); + if (dev == NULL) { + return -ENODEV; + } + return umass_writeToDev(dev, offs, buf, len); +} + + +static int umass_mountFromDev(umass_dev_t *dev, const char *name, oid_t *oid) +{ + umass_fs_t *fs; + int err; + + if (dev == NULL) { + return -ENODEV; + } + + if (dev->part.fs != NULL) + return -EEXIST; + + if ((dev->part.fs = fs = umass_getfs(name)) == NULL) + return -ENOENT; + + if (portCreate(&dev->part.port) != 0) { + fprintf(stderr, "umass: Can't create partition port!\n"); + return 1; + } + + oid->port = dev->part.port; + oid->id = dev->fileId; + + if ((err = fs->mount(oid, UMASS_SECTOR_SIZE, umass_read, umass_write, &dev->part.fdata)) < 0) + return err; + oid->id = err; + + if ((err = beginthread(umass_fsthr, 4, dev->part.fsstack, sizeof(dev->part.fsstack), &dev->part)) < 0) { + dev->part.fs->unmount(dev->part.fdata); + dev->part.fs = NULL; + dev->part.fdata = NULL; + return err; + } + + return EOK; +} + + +static int umass_mount(id_t id, const char *name, oid_t *oid) +{ + umass_dev_t *dev; + + mutexLock(umass_common.lock); + dev = _umass_devFind(id); + mutexUnlock(umass_common.lock); + + return umass_mountFromDev(dev, name, oid); +} + + +static void umass_fsthr(void *arg) +{ + umass_part_t *part = (umass_part_t *)arg; + umass_req_t *req; + int umount = 0; + + for (;;) { + if ((req = (umass_req_t *)malloc(sizeof(umass_req_t))) == NULL) + continue; + + req->part = part; + while (msgRecv(req->part->port, &req->msg, &req->rid) < 0) + ; + + if (req->msg.type == mtUmount) + umount = 1; + + mutexLock(umass_common.rlock); + + LIST_ADD(&umass_common.rqueue, req); + + mutexUnlock(umass_common.rlock); + condSignal(umass_common.rcond); + + if (umount) + endthread(); + } +} + + +static void umass_poolthr(void *arg) +{ + umass_req_t *req; + + for (;;) { + mutexLock(umass_common.rlock); + + while (umass_common.rqueue == NULL) + condWait(umass_common.rcond, umass_common.rlock, 0); + req = umass_common.rqueue->prev; + LIST_REMOVE(&umass_common.rqueue, req); + + mutexUnlock(umass_common.rlock); + + if (req->msg.type == mtUmount) { + req->part->fs->unmount(req->part->fdata); + req->part->fs = NULL; + req->part->fdata = NULL; + } + else { + req->part->fs->handler(req->part->fdata, &req->msg); + } + + msgRespond(req->part->port, &req->msg, req->rid); + free(req); + } } @@ -269,6 +540,8 @@ static void umass_msgthr(void *arg) umass_dev_t *dev; msg_rid_t rid; msg_t msg; + mount_i_msg_t *imnt; + mount_o_msg_t *omnt; for (;;) { if (msgRecv(umass_common.msgport, &msg, &rid) < 0) @@ -282,7 +555,7 @@ static void umass_msgthr(void *arg) } mutexLock(umass_common.lock); - dev = umass_devFind(msg.oid.id); + dev = _umass_devFind(msg.oid.id); mutexUnlock(umass_common.lock); if (dev == NULL) { @@ -297,12 +570,18 @@ static void umass_msgthr(void *arg) msg.o.err = EOK; break; + case mtMount: + imnt = (mount_i_msg_t *)msg.i.raw; + omnt = (mount_o_msg_t *)msg.o.raw; + msg.o.err = umass_mount(msg.oid.id, imnt->fstype, &omnt->oid); + break; + case mtRead: - msg.o.err = umass_read(dev, msg.i.io.offs, msg.o.data, msg.o.size); + msg.o.err = umass_readFromDev(dev, msg.i.io.offs, msg.o.data, msg.o.size); break; case mtWrite: - msg.o.err = umass_write(dev, msg.i.io.offs, msg.i.data, msg.i.size); + msg.o.err = umass_writeToDev(dev, msg.i.io.offs, msg.i.data, msg.i.size); break; case mtGetAttr: @@ -324,33 +603,62 @@ static void umass_msgthr(void *arg) static umass_dev_t *umass_devAlloc(void) { umass_dev_t *dev; + int rv; - if ((dev = malloc(sizeof(umass_dev_t))) == NULL) { + dev = malloc(sizeof(umass_dev_t)); + if (dev == NULL) { fprintf(stderr, "umass: Not enough memory\n"); return NULL; } - /* Get next device number */ - if (umass_common.devices == NULL) - dev->id = 0; - else - dev->id = umass_common.devices->prev->id + 1; + rv = mutexCreate(&dev->lock); + if (rv < 0) { + free(dev); + return NULL; + } - dev->fileId = umass_common.lastId++; + idtree_alloc(&umass_common.devices, &dev->node); + dev->fileId = idtree_id(&dev->node); - if (mutexCreate(&dev->lock)) { + rv = snprintf(dev->path, sizeof(dev->path), "/dev/umass%d", dev->fileId); + if (rv < 0) { + resourceDestroy(dev->lock); free(dev); return NULL; } - snprintf(dev->path, sizeof(dev->path), "/dev/umass%d", dev->id); - return dev; } -static int umass_handleInsertion(usb_devinfo_t *insertion) +static int umass_mountRoot(umass_dev_t *dev) +{ +#ifdef UMASS_MOUNT_EXT2 + int err; + oid_t roid; + + err = umass_mountFromDev(dev, LIBEXT2_NAME, &roid); + if (err < 0) { + return err; + } + + err = portRegister(roid.port, "/", &roid); + if (err < 0) { + return err; + } + + umass_common.mount_root = false; /* don't try to mount root again */ + + return EOK; +#else + return -ENOSYS; +#endif +} + + +static int _umass_handleInsertion(usb_devinfo_t *insertion) { + int err; umass_dev_t *dev; oid_t oid; @@ -385,7 +693,7 @@ static int umass_handleInsertion(usb_devinfo_t *insertion) } dev->tag = 0; - if (umass_check(dev)) { + if (_umass_check(dev)) { fprintf(stderr, "umass: umass_check failed\n"); free(dev); return -EINVAL; @@ -393,85 +701,164 @@ static int umass_handleInsertion(usb_devinfo_t *insertion) oid.port = umass_common.msgport; oid.id = dev->fileId; - if (create_dev(&oid, dev->path) != 0) { + err = create_dev(&oid, dev->path); + if (err != 0) { free(dev); fprintf(stderr, "usb: Can't create dev!\n"); return -EINVAL; } - LIST_ADD(&umass_common.devices, dev); - fprintf(stderr, "umass: New USB Mass Storage device: %s sectors: %d\n", dev->path, dev->partSize); + printf("umass: New USB Mass Storage device: %s sectors: %d\n", dev->path, dev->part.sectors); return 0; } -static int umass_handleDeletion(usb_deletion_t *del) +static int _umass_handleDeletion(usb_deletion_t *del) { - umass_dev_t *next, *dev = umass_common.devices; - int cont = 1; + umass_dev_t *dev; + rbnode_t *node, *next; - if (dev == NULL) - return 0; + node = lib_rbMinimum(umass_common.devices.root); + while (node != NULL) { + next = lib_rbNext(node); - do { - next = dev->next; + dev = lib_treeof(umass_dev_t, node, lib_treeof(idnode_t, linkage, node)); if (dev->instance.bus == del->bus && dev->instance.dev == del->dev && dev->instance.interface == del->interface) { - if (dev == next) - cont = 0; resourceDestroy(dev->lock); remove(dev->path); - LIST_REMOVE(&umass_common.devices, dev); fprintf(stderr, "umass: Device removed: %s\n", dev->path); free(dev); - if (!cont) - break; } - dev = next; - } while (dev != umass_common.devices); + + node = next; + } return 0; } +static void umass_signalExit(int sig) +{ + exit(EXIT_SUCCESS); +} + + int main(int argc, char *argv[]) { + rbnode_t *node; + umass_dev_t *dev; int ret, i; + pid_t pid; msg_t msg; usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; + char c; + bool root_mount_pending = false; + + umass_common.mount_root = false; + + /* Wait for console */ + while (write(1, "", 0) < 0) + usleep(50000); + + if (argc > 1) { + /* Process command line options */ + while ((c = getopt(argc, argv, "r")) != -1) { + switch (c) { + case 'r': + umass_common.mount_root = true; + break; + default: + return EOK; + } + } + } + + /* Set parent exit handler */ + signal(SIGUSR1, umass_signalExit); + + /* Daemonize server */ + if ((pid = fork()) < 0) { + fprintf(stderr, "umass: failed to daemonize server\n"); + exit(EXIT_FAILURE); + } + else if (pid > 0) { + /* Parent waits to be killed by the child after finished server initialization */ + sleep(10); + fprintf(stderr, "umass: failed to successfully initialize server\n"); + exit(EXIT_FAILURE); + } + + /* Set child exit handler */ + signal(SIGUSR1, umass_signalExit); + + if (setsid() < 0) { + fprintf(stderr, "umass: failed to create new session\n"); + exit(EXIT_FAILURE); + } + + if ((ret = mutexCreate(&umass_common.rlock)) < 0) { + fprintf(stderr, "umass: failed to create server requests mutex\n"); + return ret; + } + + if ((ret = condCreate(&umass_common.rcond)) < 0) { + fprintf(stderr, "umass: failed to create server requests condition variable\n"); + return ret; + } + + umass_common.rqueue = NULL; + idtree_init(&umass_common.devices); + lib_rbInit(&umass_common.fss, umass_cmpfs, NULL); + +#ifdef UMASS_MOUNT_EXT2 + /* Register filesystems */ + if (umass_registerfs(LIBEXT2_NAME, LIBEXT2_TYPE, LIBEXT2_MOUNT, LIBEXT2_UNMOUNT, LIBEXT2_HANDLER) < 0) + fprintf(stderr, "umass: failed to register ext2 filesystem\n"); +#endif /* Port for communication with the USB stack */ if (portCreate(&umass_common.drvport) != 0) { - fprintf(stderr, "umass: Can't create port!\n"); + fprintf(stderr, "umass: Can't create driver port!\n"); return 1; } /* Port for communication with driver clients */ if (portCreate(&umass_common.msgport) != 0) { - fprintf(stderr, "umass: Can't create port!\n"); + fprintf(stderr, "umass: Can't create message port!\n"); return 1; } - if ((usb_connect(filters, sizeof(filters) / sizeof(filters[0]), umass_common.drvport)) < 0) { - fprintf(stderr, "umass: Fail to connect to usb host!\n"); - return 1; - } - - if (mutexCreate(&umass_common.lock)) { + if (mutexCreate(&umass_common.lock) < 0) { fprintf(stderr, "umass: Can't create mutex!\n"); return 1; } - umass_common.lastId = 1; - - for (i = 0; i < UMASS_N_MSG_THREADS; i++) { - if ((ret = beginthread(umass_msgthr, 4, umass_common.stack[i], sizeof(umass_common.stack[i]), NULL)) != 0) { + /* Run message threads */ + for (i = 0; i < sizeof(umass_common.mstacks) / sizeof(umass_common.mstacks[0]); i++) { + if ((ret = beginthread(umass_msgthr, 4, umass_common.mstacks[i], sizeof(umass_common.mstacks[i]), NULL)) != 0) { fprintf(stderr, "umass: fail to beginthread ret: %d\n", ret); return 1; } } + /* Run pool threads */ + for (i = 0; i < sizeof(umass_common.pstacks) / sizeof(umass_common.pstacks[0]); i++) { + if ((ret = beginthread(umass_poolthr, 4, umass_common.pstacks[i], sizeof(umass_common.pstacks[i]), NULL)) < 0) { + fprintf(stderr, "umass: failed to start pool thread %d\n", i); + return ret; + } + } + + /* Finished server initialization - kill parent */ + kill(getppid(), SIGUSR1); + + if ((usb_connect(filters, sizeof(filters) / sizeof(filters[0]), umass_common.drvport)) < 0) { + fprintf(stderr, "umass: Fail to connect to usb host!\n"); + return 1; + } + for (;;) { ret = usb_eventsWait(umass_common.drvport, &msg); if (ret != 0) @@ -479,17 +866,33 @@ int main(int argc, char *argv[]) mutexLock(umass_common.lock); switch (umsg->type) { case usb_msg_insertion: - if (umass_handleInsertion(&umsg->insertion) != 0) + if (_umass_handleInsertion(&umsg->insertion) == 0) { + if (umass_common.mount_root) { + root_mount_pending = true; + node = lib_rbMinimum(umass_common.devices.root); + dev = lib_treeof(umass_dev_t, node, lib_treeof(idnode_t, linkage, node)); + } + } + else { fprintf(stderr, "umass: Failed to initialize device!\n"); + } break; case usb_msg_deletion: - umass_handleDeletion(&umsg->deletion); + _umass_handleDeletion(&umsg->deletion); break; default: fprintf(stderr, "umass: Error when receiving event from host\n"); break; } mutexUnlock(umass_common.lock); + + if (root_mount_pending) { + ret = umass_mountRoot(dev); + if (ret < 0) { + fprintf(stderr, "umass: failed to mount root partition\n"); + } + root_mount_pending = false; + } } return 0; From d918ee628109dc255fdbfeab7c5454fb65719a08 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 6 Nov 2024 18:39:43 +0100 Subject: [PATCH 06/29] storage/umass: use new procDrvRun API JIRA: RTOS-970 (cherry picked from commit 2dd11e3af43875f78f8e965618a5419d3c7e6209) --- storage/umass/umass.c | 262 ++++++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 139 deletions(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 0d29688b1..0065e75f9 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -153,6 +152,8 @@ typedef struct umass_dev { handle_t lock; umass_part_t part; /* TODO extend for more partitions */ + + usb_driver_t *drv; } umass_dev_t; @@ -160,7 +161,6 @@ static struct { idtree_t devices; umass_dev_t device; - unsigned drvport; unsigned msgport; handle_t lock; rbtree_t fss; /* Registered filesystems */ @@ -232,21 +232,21 @@ static int _umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, cbw.clen = clen; memcpy(cbw.cmd, cmd, clen); - if ((ret = usb_transferBulk(dev->pipeOut, &cbw, sizeof(cbw), usb_dir_out)) != sizeof(cbw)) { + if ((ret = usb_transferBulk(dev->drv, dev->pipeOut, &cbw, sizeof(cbw), usb_dir_out)) != sizeof(cbw)) { fprintf(stderr, "umass_transmit: usb_transferBulk OUT failed\n"); return -EIO; } /* Optional data transfer */ if (dlen > 0) { - if ((ret = usb_transferBulk(dataPipe, data, dlen, dir)) < 0) { + if ((ret = usb_transferBulk(dev->drv, dataPipe, data, dlen, dir)) < 0) { fprintf(stderr, "umass_transmit: umass_transmit data transfer failed\n"); return ret; } bytes = ret; } - if ((ret = usb_transferBulk(dev->pipeIn, &csw, sizeof(csw), usb_dir_in)) != sizeof(csw)) { + if ((ret = usb_transferBulk(dev->drv, dev->pipeIn, &csw, sizeof(csw), usb_dir_in)) != sizeof(csw)) { fprintf(stderr, "umass_transmit: usb_transferBulk IN transfer failed\n"); return -EIO; } @@ -647,8 +647,6 @@ static int umass_mountRoot(umass_dev_t *dev) return err; } - umass_common.mount_root = false; /* don't try to mount root again */ - return EOK; #else return -ENOSYS; @@ -656,37 +654,40 @@ static int umass_mountRoot(umass_dev_t *dev) } -static int _umass_handleInsertion(usb_devinfo_t *insertion) +static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) { int err; umass_dev_t *dev; oid_t oid; + mutexLock(umass_common.lock); + if ((dev = umass_devAlloc()) == NULL) { fprintf(stderr, "umass: devAlloc failed\n"); return -ENOMEM; } + dev->drv = drv; dev->instance = *insertion; - if ((dev->pipeCtrl = usb_open(insertion, usb_transfer_control, 0)) < 0) { + if ((dev->pipeCtrl = usb_open(drv, insertion, usb_transfer_control, 0)) < 0) { free(dev); fprintf(stderr, "umass: usb_open failed\n"); return -EINVAL; } - if (usb_setConfiguration(dev->pipeCtrl, 1) != 0) { + if (usb_setConfiguration(drv, dev->pipeCtrl, 1) != 0) { free(dev); fprintf(stderr, "umass: setConfiguration failed\n"); return -EINVAL; } - if ((dev->pipeIn = usb_open(insertion, usb_transfer_bulk, usb_dir_in)) < 0) { + if ((dev->pipeIn = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_in)) < 0) { fprintf(stderr, "umass: pipe open failed \n"); free(dev); return -EINVAL; } - if ((dev->pipeOut = usb_open(insertion, usb_transfer_bulk, usb_dir_out)) < 0) { + if ((dev->pipeOut = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_out)) < 0) { fprintf(stderr, "umass: pipe open failed\n"); free(dev); return -EINVAL; @@ -710,15 +711,28 @@ static int _umass_handleInsertion(usb_devinfo_t *insertion) printf("umass: New USB Mass Storage device: %s sectors: %d\n", dev->path, dev->part.sectors); + mutexUnlock(umass_common.lock); + + if (umass_common.mount_root) { + err = umass_mountRoot(dev); + if (err < 0) { + fprintf(stderr, "umass: failed to mount root partition\n"); + return err; + } + umass_common.mount_root = false; /* don't try to mount root again */ + } + return 0; } -static int _umass_handleDeletion(usb_deletion_t *del) +static int umass_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) { umass_dev_t *dev; rbnode_t *node, *next; + mutexLock(umass_common.lock); + node = lib_rbMinimum(umass_common.devices.root); while (node != NULL) { next = lib_rbNext(node); @@ -735,165 +749,135 @@ static int _umass_handleDeletion(usb_deletion_t *del) node = next; } + mutexUnlock(umass_common.lock); + return 0; } -static void umass_signalExit(int sig) +static int umass_handleCompletion(usb_driver_t *drv, usb_completion_t *c, const char *data, size_t len) { - exit(EXIT_SUCCESS); + return EOK; } -int main(int argc, char *argv[]) +static usb_handlers_t umass_handlers = { + .insertion = umass_handleInsertion, + .deletion = umass_handleDeletion, + .completion = umass_handleCompletion, +}; + + +static int umass_init(usb_driver_t *drv) { - rbnode_t *node; - umass_dev_t *dev; int ret, i; - pid_t pid; - msg_t msg; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - char c; - bool root_mount_pending = false; - umass_common.mount_root = false; + do { + ret = mutexCreate(&umass_common.rlock); + if (ret < 0) { + fprintf(stderr, "umass: failed to create server requests mutex\n"); + break; + } - /* Wait for console */ - while (write(1, "", 0) < 0) - usleep(50000); + ret = condCreate(&umass_common.rcond); + if (ret < 0) { + fprintf(stderr, "umass: failed to create server requests condition variable\n"); + break; + } - if (argc > 1) { - /* Process command line options */ - while ((c = getopt(argc, argv, "r")) != -1) { - switch (c) { - case 'r': - umass_common.mount_root = true; - break; - default: - return EOK; - } + umass_common.rqueue = NULL; + idtree_init(&umass_common.devices); + lib_rbInit(&umass_common.fss, umass_cmpfs, NULL); + +#ifdef UMASS_MOUNT_EXT2 + /* Register filesystems */ + ret = umass_registerfs(LIBEXT2_NAME, LIBEXT2_TYPE, LIBEXT2_MOUNT, LIBEXT2_UNMOUNT, LIBEXT2_HANDLER); + if (ret < 0) { + fprintf(stderr, "umass: failed to register ext2 filesystem\n"); + break; } - } +#endif - /* Set parent exit handler */ - signal(SIGUSR1, umass_signalExit); + /* Port for communication with driver clients */ + ret = portCreate(&umass_common.msgport); + if (ret != 0) { + fprintf(stderr, "umass: Can't create message port!\n"); + break; + } - /* Daemonize server */ - if ((pid = fork()) < 0) { - fprintf(stderr, "umass: failed to daemonize server\n"); - exit(EXIT_FAILURE); - } - else if (pid > 0) { - /* Parent waits to be killed by the child after finished server initialization */ - sleep(10); - fprintf(stderr, "umass: failed to successfully initialize server\n"); - exit(EXIT_FAILURE); - } + ret = mutexCreate(&umass_common.lock); + if (ret < 0) { + fprintf(stderr, "umass: Can't create mutex!\n"); + break; + } - /* Set child exit handler */ - signal(SIGUSR1, umass_signalExit); + /* Run message threads */ + for (i = 0; i < sizeof(umass_common.mstacks) / sizeof(umass_common.mstacks[0]); i++) { + if ((ret = beginthread(umass_msgthr, 4, umass_common.mstacks[i], sizeof(umass_common.mstacks[i]), NULL)) != 0) { + fprintf(stderr, "umass: fail to beginthread ret: %d\n", ret); + break; + } + } - if (setsid() < 0) { - fprintf(stderr, "umass: failed to create new session\n"); - exit(EXIT_FAILURE); - } + /* Run pool threads */ + for (i = 0; i < sizeof(umass_common.pstacks) / sizeof(umass_common.pstacks[0]); i++) { + ret = beginthread(umass_poolthr, 4, umass_common.pstacks[i], sizeof(umass_common.pstacks[i]), NULL); + if (ret < 0) { + fprintf(stderr, "umass: failed to start pool thread %d\n", i); + break; + } + } - if ((ret = mutexCreate(&umass_common.rlock)) < 0) { - fprintf(stderr, "umass: failed to create server requests mutex\n"); - return ret; - } + ret = EOK; + } while (0); - if ((ret = condCreate(&umass_common.rcond)) < 0) { - fprintf(stderr, "umass: failed to create server requests condition variable\n"); - return ret; - } + return ret; +} - umass_common.rqueue = NULL; - idtree_init(&umass_common.devices); - lib_rbInit(&umass_common.fss, umass_cmpfs, NULL); -#ifdef UMASS_MOUNT_EXT2 - /* Register filesystems */ - if (umass_registerfs(LIBEXT2_NAME, LIBEXT2_TYPE, LIBEXT2_MOUNT, LIBEXT2_UNMOUNT, LIBEXT2_HANDLER) < 0) - fprintf(stderr, "umass: failed to register ext2 filesystem\n"); -#endif +int umass_destroy(usb_driver_t *drv) +{ + return EOK; +} - /* Port for communication with the USB stack */ - if (portCreate(&umass_common.drvport) != 0) { - fprintf(stderr, "umass: Can't create driver port!\n"); - return 1; - } - /* Port for communication with driver clients */ - if (portCreate(&umass_common.msgport) != 0) { - fprintf(stderr, "umass: Can't create message port!\n"); - return 1; - } +static usb_driverOps_t umass_ops = { + .init = umass_init, + .destroy = umass_destroy, +}; - if (mutexCreate(&umass_common.lock) < 0) { - fprintf(stderr, "umass: Can't create mutex!\n"); - return 1; - } - /* Run message threads */ - for (i = 0; i < sizeof(umass_common.mstacks) / sizeof(umass_common.mstacks[0]); i++) { - if ((ret = beginthread(umass_msgthr, 4, umass_common.mstacks[i], sizeof(umass_common.mstacks[i]), NULL)) != 0) { - fprintf(stderr, "umass: fail to beginthread ret: %d\n", ret); - return 1; - } - } +usb_driver_t umass_driver = { + .handlers = &umass_handlers, + .ops = &umass_ops, + .filters = filters, + .nfilters = sizeof(filters) / sizeof(filters[0]), + .priv = (uintptr_t *)&umass_common, +}; - /* Run pool threads */ - for (i = 0; i < sizeof(umass_common.pstacks) / sizeof(umass_common.pstacks[0]); i++) { - if ((ret = beginthread(umass_poolthr, 4, umass_common.pstacks[i], sizeof(umass_common.pstacks[i]), NULL)) < 0) { - fprintf(stderr, "umass: failed to start pool thread %d\n", i); - return ret; - } - } - /* Finished server initialization - kill parent */ - kill(getppid(), SIGUSR1); +int main(int argc, char *argv[]) +{ + char c; - if ((usb_connect(filters, sizeof(filters) / sizeof(filters[0]), umass_common.drvport)) < 0) { - fprintf(stderr, "umass: Fail to connect to usb host!\n"); - return 1; - } + umass_common.mount_root = false; - for (;;) { - ret = usb_eventsWait(umass_common.drvport, &msg); - if (ret != 0) - return 1; - mutexLock(umass_common.lock); - switch (umsg->type) { - case usb_msg_insertion: - if (_umass_handleInsertion(&umsg->insertion) == 0) { - if (umass_common.mount_root) { - root_mount_pending = true; - node = lib_rbMinimum(umass_common.devices.root); - dev = lib_treeof(umass_dev_t, node, lib_treeof(idnode_t, linkage, node)); - } - } - else { - fprintf(stderr, "umass: Failed to initialize device!\n"); - } - break; - case usb_msg_deletion: - _umass_handleDeletion(&umsg->deletion); - break; - default: - fprintf(stderr, "umass: Error when receiving event from host\n"); - break; - } - mutexUnlock(umass_common.lock); + /* Wait for console */ + while (write(1, "", 0) < 0) + usleep(50000); - if (root_mount_pending) { - ret = umass_mountRoot(dev); - if (ret < 0) { - fprintf(stderr, "umass: failed to mount root partition\n"); + if (argc > 1) { + /* Process command line options */ + while ((c = getopt(argc, argv, "r")) != -1) { + switch (c) { + case 'r': + umass_common.mount_root = true; + break; + default: + return EOK; } - root_mount_pending = false; } } - return 0; + return usb_procDrvRun(&umass_driver, true); } From 82cb3c531f79c24cf1aa7f282e9fe286ff0ab937 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 13 Nov 2024 19:11:22 +0100 Subject: [PATCH 07/29] storage/umass: refactor to compile driver as static-lib JIRA: RTOS-970 (cherry picked from commit 82b923470513dd17f014e4725dbba5bff8bd13c4) --- _targets/Makefile.ia32-generic | 2 +- storage/umass/Makefile | 19 ++++++---- storage/umass/srv.c | 69 ++++++++++++++++++++++++++++++++++ storage/umass/umass.c | 65 +++++++++++--------------------- storage/umass/umass.h | 30 +++++++++++++++ 5 files changed, 134 insertions(+), 51 deletions(-) create mode 100644 storage/umass/srv.c create mode 100644 storage/umass/umass.h diff --git a/_targets/Makefile.ia32-generic b/_targets/Makefile.ia32-generic index 579f8d7a6..1c24047e8 100644 --- a/_targets/Makefile.ia32-generic +++ b/_targets/Makefile.ia32-generic @@ -6,4 +6,4 @@ # Copyright 2019 Phoenix Systems # -DEFAULT_COMPONENTS := pc-tty uart16550 pc-ata libusbehci umass +DEFAULT_COMPONENTS := pc-tty uart16550 pc-ata libusbehci umass libusbdrv-umass diff --git a/storage/umass/Makefile b/storage/umass/Makefile index d6d4ae253..e0166e4ec 100644 --- a/storage/umass/Makefile +++ b/storage/umass/Makefile @@ -1,16 +1,21 @@ # # Makefile for Phoenix-RTOS USB Mass Storage driver # -# Copyright 2020 Phoenix Systems +# Copyright 2020, 2024 Phoenix Systems # -NAME := umass -LOCAL_SRCS := umass.c -LIBS := libusb - ifeq ($(TARGET_FAMILY),ia32) - LIBS += libext2 - CFLAGS += -DUMASS_MOUNT_EXT2 + UMASS_LIBS := libext2 + UMASS_CFLAGS := -DUMASS_MOUNT_EXT2 endif +NAME := libusbdrv-umass +LOCAL_SRCS := umass.c +LOCAL_CFLAGS += $(UMASS_CFLAGS) +include $(static-lib.mk) + +NAME := umass +LOCAL_SRCS := umass.c srv.c +LIBS := libusb $(UMASS_LIBS) +LOCAL_CFLAGS += $(UMASS_CFLAGS) include $(binary.mk) diff --git a/storage/umass/srv.c b/storage/umass/srv.c new file mode 100644 index 000000000..ffec4d456 --- /dev/null +++ b/storage/umass/srv.c @@ -0,0 +1,69 @@ +/* + * Phoenix-RTOS + * + * USB Mass Storage class driver + * + * Device driver server + * + * Copyright 2024 Phoenix Systems + * Author: Adam Greloch + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "umass.h" +#include + + +static void printHelp(const char *name) +{ + fprintf(stderr, + "Usage: %s [opts]\n" + " -r Mount as rootfs\n" + " -h Print this help\n", + name); +} + + +int main(int argc, char *argv[]) +{ + int ret; + char c; + umass_args_t umass_args = { .mount_root = false }; + usb_driver_t *driver = usb_registeredDriverPop(); + + if (driver == NULL) { + fprintf(stderr, "umass: no driver registered!"); + return 1; + } + + /* Wait for console */ + while (write(1, "", 0) < 0) { + usleep(50000); + } + + if (argc > 1) { + /* Process command line options */ + for (;;) { + c = getopt(argc, argv, "hr"); + if (c == -1) { + break; + } + switch (c) { + case 'r': + umass_args.mount_root = true; + break; + case 'h': + default: + printHelp(argv[0]); + return 0; + } + } + } + + ret = usb_driverProcRun(driver, &umass_args); + + return ret == 0 ? 0 : 1; +} diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 0065e75f9..591bac2f1 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -25,7 +25,6 @@ #include #include #include -#include #include @@ -37,6 +36,7 @@ #include #include "../pc-ata/mbr.h" +#include "umass.h" #define UMASS_N_MSG_THREADS 2 #define UMASS_N_POOL_THREADS 4 @@ -761,17 +761,18 @@ static int umass_handleCompletion(usb_driver_t *drv, usb_completion_t *c, const } -static usb_handlers_t umass_handlers = { - .insertion = umass_handleInsertion, - .deletion = umass_handleDeletion, - .completion = umass_handleCompletion, -}; - - -static int umass_init(usb_driver_t *drv) +static int umass_init(usb_driver_t *drv, void *args) { + umass_args_t *umass_args = (umass_args_t *)args; int ret, i; + if (umass_args != NULL) { + umass_common.mount_root = umass_args->mount_root; + } + else { + umass_common.mount_root = true; + } + do { ret = mutexCreate(&umass_common.rlock); if (ret < 0) { @@ -835,49 +836,27 @@ static int umass_init(usb_driver_t *drv) } -int umass_destroy(usb_driver_t *drv) +static int umass_destroy(usb_driver_t *drv) { return EOK; } -static usb_driverOps_t umass_ops = { - .init = umass_init, - .destroy = umass_destroy, -}; - - -usb_driver_t umass_driver = { - .handlers = &umass_handlers, - .ops = &umass_ops, +static usb_driver_t umass_driver = { + .name = "umass", + .handlers = { + .insertion = umass_handleInsertion, + .deletion = umass_handleDeletion, + .completion = umass_handleCompletion, + }, + .ops = { .init = umass_init, .destroy = umass_destroy }, .filters = filters, .nfilters = sizeof(filters) / sizeof(filters[0]), - .priv = (uintptr_t *)&umass_common, + .priv = (void *)&umass_common, }; -int main(int argc, char *argv[]) +__attribute__((constructor)) static void umass_register(void) { - char c; - - umass_common.mount_root = false; - - /* Wait for console */ - while (write(1, "", 0) < 0) - usleep(50000); - - if (argc > 1) { - /* Process command line options */ - while ((c = getopt(argc, argv, "r")) != -1) { - switch (c) { - case 'r': - umass_common.mount_root = true; - break; - default: - return EOK; - } - } - } - - return usb_procDrvRun(&umass_driver, true); + usb_driverRegister(&umass_driver); } diff --git a/storage/umass/umass.h b/storage/umass/umass.h new file mode 100644 index 000000000..14e953681 --- /dev/null +++ b/storage/umass/umass.h @@ -0,0 +1,30 @@ +/* + * Phoenix-RTOS + * + * USB Mass Storage class driver + * + * Common header + * + * Copyright 2024 Phoenix Systems + * Author: Adam Greloch + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _UMASS_H_ +#define _UMASS_H_ + +#include +#include + +#include + + +typedef struct { + bool mount_root; +} umass_args_t; + + +#endif From c8992455fd2c0baca1e10bc69515fdccae47caf0 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Mon, 2 Dec 2024 14:38:20 +0100 Subject: [PATCH 08/29] storage/umass: misra JIRA: RTOS-970 (cherry picked from commit fedd5cba25785feaaa9cd019de7c55d78f8f0705) --- storage/umass/umass.c | 93 ++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 591bac2f1..2d157ddd0 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -187,10 +187,10 @@ static const usb_device_id_t filters[] = { #ifdef UMASS_MOUNT_EXT2 static int umass_registerfs(const char *name, uint8_t type, fs_mount_t mount, fs_unmount_t unmount, fs_handler_t handler) { - umass_fs_t *fs; - - if ((fs = (umass_fs_t *)malloc(sizeof(umass_fs_t))) == NULL) + umass_fs_t *fs = malloc(sizeof(umass_fs_t)); + if (fs == NULL) { return -ENOMEM; + } strcpy(fs->name, name); fs->type = type; @@ -232,21 +232,24 @@ static int _umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, cbw.clen = clen; memcpy(cbw.cmd, cmd, clen); - if ((ret = usb_transferBulk(dev->drv, dev->pipeOut, &cbw, sizeof(cbw), usb_dir_out)) != sizeof(cbw)) { + ret = usb_transferBulk(dev->drv, dev->pipeOut, &cbw, sizeof(cbw), usb_dir_out); + if (ret != sizeof(cbw)) { fprintf(stderr, "umass_transmit: usb_transferBulk OUT failed\n"); return -EIO; } /* Optional data transfer */ if (dlen > 0) { - if ((ret = usb_transferBulk(dev->drv, dataPipe, data, dlen, dir)) < 0) { + ret = usb_transferBulk(dev->drv, dataPipe, data, dlen, dir); + if (ret < 0) { fprintf(stderr, "umass_transmit: umass_transmit data transfer failed\n"); return ret; } bytes = ret; } - if ((ret = usb_transferBulk(dev->drv, dev->pipeIn, &csw, sizeof(csw), usb_dir_in)) != sizeof(csw)) { + ret = usb_transferBulk(dev->drv, dev->pipeIn, &csw, sizeof(csw), usb_dir_in); + if (ret != sizeof(csw)) { fprintf(stderr, "umass_transmit: usb_transferBulk IN transfer failed\n"); return -EIO; } @@ -269,14 +272,17 @@ static int _umass_check(umass_dev_t *dev) }; char testcmd[6] = { 0 }; mbr_t *mbr; + int ret; - if (_umass_transmit(dev, testcmd, sizeof(testcmd), NULL, 0, usb_dir_in) < 0) { + ret = _umass_transmit(dev, testcmd, sizeof(testcmd), NULL, 0, usb_dir_in); + if (ret < 0) { fprintf(stderr, "umass_transmit failed\n"); return -1; } /* Read MBR */ - if (_umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, UMASS_SECTOR_SIZE, usb_dir_in) < 0) { + ret = _umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, UMASS_SECTOR_SIZE, usb_dir_in); + if (ret < 0) { fprintf(stderr, "umass_transmit 2 failed\n"); return -1; } @@ -286,7 +292,6 @@ static int _umass_check(umass_dev_t *dev) return -1; /* Read only the first partition */ - /* TODO read the rest of them*/ dev->part.start = mbr->pent[0].start; dev->part.sectors = mbr->pent[0].sectors; dev->part.fs = NULL; @@ -317,8 +322,9 @@ static umass_fs_t *umass_findfs(uint8_t type) for (node = lib_rbMinimum(umass_common.fss.root); node != NULL; node = lib_rbNext(node)) { fs = lib_treeof(umass_fs_t, node, node); - if (fs->type == type) + if (fs->type == type) { return fs; + } } return NULL; @@ -346,8 +352,9 @@ static int umass_readFromDev(umass_dev_t *dev, off_t offs, char *buf, size_t len mutexLock(dev->lock); ret = _umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, len, usb_dir_in); - if (ret > 0) + if (ret > 0) { memcpy(buf, dev->buffer, len); + } else if (len > 0) { printf("read transmit failed for offs: %lld\n", offs); } @@ -362,11 +369,13 @@ static int umass_writeToDev(umass_dev_t *dev, off_t offs, const char *buf, size_ scsi_cdb10_t writecmd = { .opcode = 0x2a }; int ret; - if ((offs % UMASS_SECTOR_SIZE) || (len % UMASS_SECTOR_SIZE)) + if ((offs % UMASS_SECTOR_SIZE) || (len % UMASS_SECTOR_SIZE)) { return -EINVAL; + } - if (offs + len > dev->part.sectors * UMASS_SECTOR_SIZE) + if (offs + len > dev->part.sectors * UMASS_SECTOR_SIZE) { return -EINVAL; + } len = min(len, sizeof(dev->buffer)); @@ -435,13 +444,18 @@ static int umass_mountFromDev(umass_dev_t *dev, const char *name, oid_t *oid) return -ENODEV; } - if (dev->part.fs != NULL) + if (dev->part.fs != NULL) { return -EEXIST; + } - if ((dev->part.fs = fs = umass_getfs(name)) == NULL) + fs = umass_getfs(name); + if (fs == NULL) { return -ENOENT; + } + dev->part.fs = fs; - if (portCreate(&dev->part.port) != 0) { + err = portCreate(&dev->part.port); + if (err != 0) { fprintf(stderr, "umass: Can't create partition port!\n"); return 1; } @@ -449,11 +463,14 @@ static int umass_mountFromDev(umass_dev_t *dev, const char *name, oid_t *oid) oid->port = dev->part.port; oid->id = dev->fileId; - if ((err = fs->mount(oid, UMASS_SECTOR_SIZE, umass_read, umass_write, &dev->part.fdata)) < 0) + err = fs->mount(oid, UMASS_SECTOR_SIZE, umass_read, umass_write, &dev->part.fdata); + if (err < 0) { return err; + } oid->id = err; - if ((err = beginthread(umass_fsthr, 4, dev->part.fsstack, sizeof(dev->part.fsstack), &dev->part)) < 0) { + err = beginthread(umass_fsthr, 4, dev->part.fsstack, sizeof(dev->part.fsstack), &dev->part); + if (err < 0) { dev->part.fs->unmount(dev->part.fdata); dev->part.fs = NULL; dev->part.fdata = NULL; @@ -480,18 +497,24 @@ static void umass_fsthr(void *arg) { umass_part_t *part = (umass_part_t *)arg; umass_req_t *req; - int umount = 0; + int umount = 0, ret; for (;;) { - if ((req = (umass_req_t *)malloc(sizeof(umass_req_t))) == NULL) + req = (umass_req_t *)malloc(sizeof(umass_req_t)); + if (req == NULL) { continue; + } req->part = part; - while (msgRecv(req->part->port, &req->msg, &req->rid) < 0) - ; - if (req->msg.type == mtUmount) + ret = -1; + while (ret < 0) { + ret = msgRecv(req->part->port, &req->msg, &req->rid); + } + + if (req->msg.type == mtUmount) { umount = 1; + } mutexLock(umass_common.rlock); @@ -500,8 +523,9 @@ static void umass_fsthr(void *arg) mutexUnlock(umass_common.rlock); condSignal(umass_common.rcond); - if (umount) + if (umount != 0) { endthread(); + } } } @@ -513,8 +537,9 @@ static void umass_poolthr(void *arg) for (;;) { mutexLock(umass_common.rlock); - while (umass_common.rqueue == NULL) + while (umass_common.rqueue == NULL) { condWait(umass_common.rcond, umass_common.rlock, 0); + } req = umass_common.rqueue->prev; LIST_REMOVE(&umass_common.rqueue, req); @@ -669,32 +694,37 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) dev->drv = drv; dev->instance = *insertion; - if ((dev->pipeCtrl = usb_open(drv, insertion, usb_transfer_control, 0)) < 0) { + dev->pipeCtrl = usb_open(drv, insertion, usb_transfer_control, 0); + if (dev->pipeCtrl < 0) { free(dev); fprintf(stderr, "umass: usb_open failed\n"); return -EINVAL; } - if (usb_setConfiguration(drv, dev->pipeCtrl, 1) != 0) { + err = usb_setConfiguration(drv, dev->pipeCtrl, 1); + if (err != 0) { free(dev); fprintf(stderr, "umass: setConfiguration failed\n"); return -EINVAL; } - if ((dev->pipeIn = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_in)) < 0) { + dev->pipeIn = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_in); + if (dev->pipeIn < 0) { fprintf(stderr, "umass: pipe open failed \n"); free(dev); return -EINVAL; } - if ((dev->pipeOut = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_out)) < 0) { + dev->pipeOut = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_out); + if (dev->pipeOut < 0) { fprintf(stderr, "umass: pipe open failed\n"); free(dev); return -EINVAL; } dev->tag = 0; - if (_umass_check(dev)) { + err = _umass_check(dev); + if (err != 0) { fprintf(stderr, "umass: umass_check failed\n"); free(dev); return -EINVAL; @@ -814,7 +844,8 @@ static int umass_init(usb_driver_t *drv, void *args) /* Run message threads */ for (i = 0; i < sizeof(umass_common.mstacks) / sizeof(umass_common.mstacks[0]); i++) { - if ((ret = beginthread(umass_msgthr, 4, umass_common.mstacks[i], sizeof(umass_common.mstacks[i]), NULL)) != 0) { + ret = beginthread(umass_msgthr, 4, umass_common.mstacks[i], sizeof(umass_common.mstacks[i]), NULL); + if (ret != 0) { fprintf(stderr, "umass: fail to beginthread ret: %d\n", ret); break; } From 866d409ab0f0ecfa0ec4d09e1cc0a8ad8cd6b544 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 29 Nov 2024 12:58:26 +0100 Subject: [PATCH 09/29] tty/usbacm: adapt to new usb API JIRA: RTOS-970 (cherry picked from commit 8a8e5724e7d0dc6b1648761cee0aa706f0558d5f) --- tty/usbacm/Makefile | 9 +- tty/usbacm/srv.c | 34 +++++++ tty/usbacm/usbacm.c | 240 +++++++++++++++++++++++--------------------- 3 files changed, 165 insertions(+), 118 deletions(-) create mode 100644 tty/usbacm/srv.c diff --git a/tty/usbacm/Makefile b/tty/usbacm/Makefile index ed8118d52..21f9efd4e 100644 --- a/tty/usbacm/Makefile +++ b/tty/usbacm/Makefile @@ -1,11 +1,14 @@ # # Makefile for Phoenix-RTOS USB CDC ACM driver # -# Copyright 2021 Phoenix Systems +# Copyright 2021, 2024 Phoenix Systems # -NAME := usbacm +NAME := libusbdrv-usbacm LOCAL_SRCS := usbacm.c -LIBS := libusb +include $(static-lib.mk) +NAME := usbacm +LOCAL_SRCS := usbacm.c srv.c +LIBS := libusb include $(binary.mk) diff --git a/tty/usbacm/srv.c b/tty/usbacm/srv.c new file mode 100644 index 000000000..db707ac94 --- /dev/null +++ b/tty/usbacm/srv.c @@ -0,0 +1,34 @@ +/* + * Phoenix-RTOS + * + * USB CDC ACM driver + * + * Device driver server + * + * Copyright 2024 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + + +#include +#include + + +int main(int argc, char *argv[]) +{ + int ret; + usb_driver_t *driver = usb_registeredDriverPop(); + if (driver == NULL) { + fprintf(stderr, "usbacm: no driver registered!"); + return 1; + } + + ret = usb_driverProcRun(driver, NULL); + if (ret < 0) { + fprintf(stderr, "usbacm: failed to start server: %d\n", ret); + } + + return ret == 0 ? 0 : 1; +} diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 5b315c00e..ac3bd73ad 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -3,8 +3,8 @@ * * USB CDC ACM driver * - * Copyright 2021, 2022 Phoenix Systems - * Author: Maciej Purski + * Copyright 2021, 2022, 2024 Phoenix Systems + * Author: Maciej Purski, Adam Greloch * * %LICENSE% */ @@ -36,12 +36,8 @@ #define USBACM_N_MSG_THREADS 2 #endif -#ifndef USBACM_N_UMSG_THREADS -#define USBACM_N_UMSG_THREADS 2 -#endif - #ifndef RX_FIFO_SIZE -#define RX_FIFO_SIZE 8192 +#define RX_FIFO_SIZE 8192 #endif #ifndef USBACM_N_URBS @@ -94,17 +90,18 @@ typedef struct _usbacm_dev { handle_t rxCond; int rxState; + usb_driver_t *drv; } usbacm_dev_t; static struct { char msgstack[USBACM_N_MSG_THREADS][1024] __attribute__((aligned(8))); - char ustack[USBACM_N_UMSG_THREADS - 1][2048] __attribute__((aligned(8))); usbacm_dev_t *devices; unsigned drvport; unsigned msgport; handle_t lock; int lastId; + usbacm_dev_t *devicesToFree; } usbacm_common; @@ -150,7 +147,7 @@ static int _usbacm_rxStop(usbacm_dev_t *dev) setup.wLength = 0; dev->rxState = RxStopped; - return usb_transferAsync(dev->pipeCtrl, dev->urbctrl, 0, &setup); + return usb_transferAsync(dev->drv, dev->pipeCtrl, dev->urbctrl, 0, &setup); } @@ -260,14 +257,14 @@ static void usbacm_put(usbacm_dev_t *dev) } -static void usbacm_handleCompletion(usb_completion_t *c, const char *data, size_t len) +static int usbacm_handleCompletion(usb_driver_t *drv, usb_completion_t *c, const char *data, size_t len) { usbacm_dev_t *dev; size_t bytes; dev = usbacm_getByPipe(c->pipeid); if (dev == NULL) { - return; + return -1; } TRACE("handleCompletion: c->err=%d, len=%u, rxbuflen=%u", c->err, len, dev->rxbuflen); @@ -281,12 +278,12 @@ static void usbacm_handleCompletion(usb_completion_t *c, const char *data, size_ } mutexUnlock(dev->rxLock); usbacm_put(dev); - return; + return -1; } if (c->pipeid != dev->pipeBulkIN) { usbacm_put(dev); - return; + return -1; } if (dev->flags & O_NONBLOCK) { @@ -309,10 +306,12 @@ static void usbacm_handleCompletion(usb_completion_t *c, const char *data, size_ } if (dev->rxState == RxRunning) { - usb_transferAsync(dev->pipeBulkIN, c->urbid, USBACM_BULK_SZ, NULL); + usb_transferAsync(drv, dev->pipeBulkIN, c->urbid, USBACM_BULK_SZ, NULL); } usbacm_put(dev); + + return 0; } @@ -320,7 +319,7 @@ static void usbacm_handleCompletion(usb_completion_t *c, const char *data, size_ static int _usbacm_rxStart(usbacm_dev_t *dev) { usb_setup_packet_t setup; - int i; + int i, ret; setup.bmRequestType = REQUEST_DIR_HOST2DEV | REQUEST_TYPE_CLASS | REQUEST_RECIPIENT_INTERFACE; setup.bRequest = USB_CDC_REQ_SET_CONTROL_LINE_STATE; @@ -328,12 +327,14 @@ static int _usbacm_rxStart(usbacm_dev_t *dev) setup.wValue = 3; setup.wLength = 0; - if (usb_transferAsync(dev->pipeCtrl, dev->urbctrl, 0, &setup) < 0) { + ret = usb_transferAsync(dev->drv, dev->pipeCtrl, dev->urbctrl, 0, &setup); + if (ret < 0) { return -EIO; } for (i = 0; i < USBACM_N_URBS; i++) { - if (usb_transferAsync(dev->pipeBulkIN, dev->urbs[i], USBACM_BULK_SZ, NULL) < 0) { + ret = usb_transferAsync(dev->drv, dev->pipeBulkIN, dev->urbs[i], USBACM_BULK_SZ, NULL); + if (ret < 0) { return -EIO; } } @@ -400,7 +401,9 @@ static int usbacm_write(usbacm_dev_t *dev, const char *data, size_t len) int ret = 0; TRACE("write: len=%u, flags=%u", len, dev->flags); - if ((ret = usb_transferBulk(dev->pipeBulkOUT, (void *)data, len, usb_dir_out)) <= 0) { + + ret = usb_transferBulk(dev->drv, dev->pipeBulkOUT, (void *)data, len, usb_dir_out); + if (ret <= 0) { fprintf(stderr, "usbacm: write failed\n"); ret = -EIO; } @@ -436,20 +439,20 @@ static int _usbacm_urbsAlloc(usbacm_dev_t *dev) { int i, j; - dev->urbctrl = usb_urbAlloc(dev->pipeCtrl, NULL, usb_dir_out, 0, usb_transfer_control); + dev->urbctrl = usb_urbAlloc(dev->drv, dev->pipeCtrl, NULL, usb_dir_out, 0, usb_transfer_control); if (dev->urbctrl < 0) { return -1; } for (i = 0; i < USBACM_N_URBS; i++) { - dev->urbs[i] = usb_urbAlloc(dev->pipeBulkIN, NULL, usb_dir_in, USBACM_BULK_SZ, usb_transfer_bulk); + dev->urbs[i] = usb_urbAlloc(dev->drv, dev->pipeBulkIN, NULL, usb_dir_in, USBACM_BULK_SZ, usb_transfer_bulk); if (dev->urbs[i] < 0) { for (j = i - 1; j >= 0; j--) { - usb_urbFree(dev->pipeBulkIN, dev->urbs[j]); + usb_urbFree(dev->drv, dev->pipeBulkIN, dev->urbs[j]); dev->urbs[j] = 0; } - usb_urbFree(dev->pipeCtrl, dev->urbctrl); + usb_urbFree(dev->drv, dev->pipeCtrl, dev->urbctrl); return -1; } } @@ -497,7 +500,7 @@ static void _usbacm_close(usbacm_dev_t *dev) TRACE("close: flags=%u", dev->flags); for (i = 0; i < USBACM_N_URBS; i++) { - usb_urbFree(dev->pipeBulkIN, dev->urbs[i]); + usb_urbFree(dev->drv, dev->pipeBulkIN, dev->urbs[i]); } if (dev->flags & O_NONBLOCK) { @@ -506,7 +509,7 @@ static void _usbacm_close(usbacm_dev_t *dev) mutexUnlock(dev->rxLock); } - usb_urbFree(dev->pipeCtrl, dev->urbctrl); + usb_urbFree(dev->drv, dev->pipeCtrl, dev->urbctrl); dev->flags = 0; dev->clientpid = 0; @@ -629,69 +632,87 @@ static void usbacm_msgthr(void *arg) } -static int usbacm_handleInsertion(usb_devinfo_t *insertion) +static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) { usbacm_dev_t *dev; const usb_modeswitch_t *mode; oid_t oid; + int err; TRACE("handleInsertion"); - if ((mode = usb_modeswitchFind(insertion->descriptor.idVendor, + mode = usb_modeswitchFind(insertion->descriptor.idVendor, insertion->descriptor.idProduct, - modeswitch, sizeof(modeswitch) / sizeof(modeswitch[0]))) != NULL) { - return usb_modeswitchHandle(insertion, mode); + modeswitch, sizeof(modeswitch) / sizeof(modeswitch[0])); + if (mode != NULL) { + return usb_modeswitchHandle(drv, insertion, mode); } if ((dev = usbacm_devAlloc()) == NULL) return -ENOMEM; dev->instance = *insertion; + dev->drv = drv; - if ((dev->pipeCtrl = usb_open(insertion, usb_transfer_control, 0)) < 0) { - fprintf(stderr, "usbacm: Fail to open control pipe\n"); - free(dev); - return -EINVAL; - } + do { + dev->pipeCtrl = usb_open(drv, insertion, usb_transfer_control, 0); + if (dev->pipeCtrl < 0) { + fprintf(stderr, "usbacm: Fail to open control pipe\n"); + err = -EINVAL; + break; + } - if (usb_setConfiguration(dev->pipeCtrl, 1) != 0) { - fprintf(stderr, "usbacm: Fail to set configuration\n"); - free(dev); - return -EINVAL; - } + err = usb_setConfiguration(drv, dev->pipeCtrl, 1); + if (err != 0) { + fprintf(stderr, "usbacm: Fail to set configuration\n"); + err = -EINVAL; + break; + } - if ((dev->pipeBulkIN = usb_open(insertion, usb_transfer_bulk, usb_dir_in)) < 0) { - free(dev); - return -EINVAL; - } + dev->pipeBulkIN = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_in); + if (dev->pipeBulkIN < 0) { + err = -EINVAL; + break; + } - if ((dev->pipeBulkOUT = usb_open(insertion, usb_transfer_bulk, usb_dir_out)) < 0) { - free(dev); - return -EINVAL; - } + dev->pipeBulkOUT = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_out); + if (dev->pipeBulkOUT < 0) { + err = -EINVAL; + break; + } - /* Interrupt pipe is optional */ - dev->pipeIntIN = usb_open(insertion, usb_transfer_interrupt, usb_dir_in); + /* Interrupt pipe is optional */ + dev->pipeIntIN = usb_open(drv, insertion, usb_transfer_interrupt, usb_dir_in); - if (mutexCreate(&dev->rxLock) != 0) { - free(dev); - return -ENOMEM; - } + err = mutexCreate(&dev->rxLock); + if (err != 0) { + err = -ENOMEM; + break; + } - if (condCreate(&dev->rxCond) != 0) { - resourceDestroy(dev->rxLock); - free(dev); - return -ENOMEM; - } + condCreate(&dev->rxCond); + if (err != 0) { + resourceDestroy(dev->rxLock); + err = -ENOMEM; + break; + } + + oid.port = usbacm_common.msgport; + oid.id = dev->fileId; - oid.port = usbacm_common.msgport; - oid.id = dev->fileId; - if (create_dev(&oid, dev->path) != 0) { - resourceDestroy(dev->rxCond); - resourceDestroy(dev->rxLock); + err = create_dev(&oid, dev->path); + if (err != 0) { + resourceDestroy(dev->rxCond); + resourceDestroy(dev->rxLock); + fprintf(stderr, "usbacm: Can't create dev: %s\n", dev->path); + err = -EINVAL; + break; + } + } while (0); + + if (err < 0) { free(dev); - fprintf(stderr, "usbacm: Can't create dev!\n"); - return -EINVAL; + return err; } dev->rfcnt = 1; @@ -705,7 +726,7 @@ static int usbacm_handleInsertion(usb_devinfo_t *insertion) } -static int _usbacm_handleDeletion(usb_deletion_t *del, usbacm_dev_t **devicesToFree) +static int usbacm_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) { usbacm_dev_t *next, *dev = usbacm_common.devices; int cont = 1; @@ -715,6 +736,8 @@ static int _usbacm_handleDeletion(usb_deletion_t *del, usbacm_dev_t **devicesToF TRACE("handleDeletion"); + mutexLock(usbacm_common.lock); + do { next = dev->next; if (dev->instance.bus == del->bus && dev->instance.dev == del->dev && @@ -729,7 +752,7 @@ static int _usbacm_handleDeletion(usb_deletion_t *del, usbacm_dev_t **devicesToF mutexUnlock(dev->rxLock); if (_usbacm_put(dev) == 0) { - LIST_ADD(devicesToFree, dev); + LIST_ADD(&usbacm_common.devicesToFree, dev); } if (!cont) break; @@ -737,48 +760,21 @@ static int _usbacm_handleDeletion(usb_deletion_t *del, usbacm_dev_t **devicesToF dev = next; } while (dev != usbacm_common.devices); - return 0; -} - - -static void usbthr(void *arg) -{ - msg_t msg; - usb_msg_t *umsg = (usb_msg_t *)msg.i.raw; - msg_rid_t rid; - usbacm_dev_t *devicesToFree = NULL; - - for (;;) { - if (msgRecv(usbacm_common.drvport, &msg, &rid) < 0) - continue; + mutexUnlock(usbacm_common.lock); - switch (umsg->type) { - case usb_msg_insertion: - usbacm_handleInsertion(&umsg->insertion); - break; - case usb_msg_deletion: - mutexLock(usbacm_common.lock); - _usbacm_handleDeletion(&umsg->deletion, &devicesToFree); - mutexUnlock(usbacm_common.lock); - usbacm_freeAll(&devicesToFree); - break; - case usb_msg_completion: - usbacm_handleCompletion(&umsg->completion, msg.i.data, msg.i.size); - break; - default: - fprintf(stderr, "usbacm: Error when receiving event from host\n"); - break; - } + usbacm_freeAll(&usbacm_common.devicesToFree); - msgRespond(usbacm_common.drvport, &msg, rid); - } + return 0; } -int main(int argc, char *argv[]) + +static int usbacm_init(usb_driver_t *drv, void *args) { int ret; int i; + usbacm_common.devicesToFree = NULL; + /* Port for communication with the USB stack */ if (portCreate(&usbacm_common.drvport) != 0) { fprintf(stderr, "usbacm: Can't create port!\n"); @@ -796,11 +792,6 @@ int main(int argc, char *argv[]) return 1; } - if ((usb_connect(filters, sizeof(filters) / sizeof(filters[0]), usbacm_common.drvport)) < 0) { - fprintf(stderr, "usbacm: Fail to connect to usb host!\n"); - return 1; - } - usbacm_common.lastId = 1; for (i = 0; i < USBACM_N_MSG_THREADS; i++) { @@ -811,16 +802,35 @@ int main(int argc, char *argv[]) } } - for (i = 0; i < USBACM_N_UMSG_THREADS - 1; i++) { - ret = beginthread(usbthr, USBACM_UMSG_PRIO, usbacm_common.ustack[i], sizeof(usbacm_common.ustack[i]), NULL); - if (ret < 0) { - fprintf(stderr, "usbacm: fail to beginthread ret: %d\n", ret); - return 1; - } - } + return 0; +} - priority(USBACM_UMSG_PRIO); - usbthr(NULL); - return 0; +static int usbacm_destroy(usb_driver_t *drv) +{ + /* TODO */ + return EOK; +} + + +static usb_driver_t usbacm_driver = { + .name = "usbacm", + .handlers = { + .insertion = usbacm_handleInsertion, + .deletion = usbacm_handleDeletion, + .completion = usbacm_handleCompletion, + }, + .ops = { + .init = usbacm_init, + .destroy = usbacm_destroy, + }, + .filters = filters, + .nfilters = sizeof(filters) / sizeof(filters[0]), + .priv = (void *)&usbacm_common, +}; + + +__attribute__((constructor)) static void usbacm_register(void) +{ + usb_driverRegister(&usbacm_driver); } From 86dc3427c395aee2cefb409c68d263cdf6639e58 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 29 Nov 2024 12:58:58 +0100 Subject: [PATCH 10/29] tty/usbacm: fix device insertion/deletion race conditions This fixes race conditions happening when there are multiple usb insertion/deletion/completion threads. Access to usbacm_common.devices struct was not guarded, which lead i.e. to multiple concurrent attempts of /dev/usbacm0 creation during insertion and possible double-free on destruction, since usbacm_freeAll was also called outside of critical section JIRA: RTOS-970 (cherry picked from commit 871c77b329db3c707ebdf0f36a0c787e36aa9ab0) --- tty/usbacm/usbacm.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index ac3bd73ad..3979cdaa8 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -421,6 +421,7 @@ static usbacm_dev_t *usbacm_devAlloc(void) return NULL; } + mutexLock(usbacm_common.lock); /* Get next device number */ if (usbacm_common.devices == NULL) dev->id = 0; @@ -428,6 +429,12 @@ static usbacm_dev_t *usbacm_devAlloc(void) dev->id = usbacm_common.devices->prev->id + 1; dev->fileId = usbacm_common.lastId++; + dev->rfcnt = 1; + + /* add this device prematurely to devices list, to mitigate race condition on + * multiple concurrent insertions */ + LIST_ADD(&usbacm_common.devices, dev); + mutexUnlock(usbacm_common.lock); snprintf(dev->path, sizeof(dev->path), "/dev/usbacm%u", dev->id); @@ -711,15 +718,14 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) } while (0); if (err < 0) { + mutexLock(usbacm_common.lock); + /* remove the device from list, as it has been added there in devAlloc */ + LIST_REMOVE(&usbacm_common.devices, dev); + mutexUnlock(usbacm_common.lock); free(dev); return err; } - dev->rfcnt = 1; - mutexLock(usbacm_common.lock); - LIST_ADD(&usbacm_common.devices, dev); - mutexUnlock(usbacm_common.lock); - fprintf(stdout, "usbacm: New device: %s\n", dev->path); return 0; @@ -760,10 +766,10 @@ static int usbacm_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) dev = next; } while (dev != usbacm_common.devices); - mutexUnlock(usbacm_common.lock); - usbacm_freeAll(&usbacm_common.devicesToFree); + mutexUnlock(usbacm_common.lock); + return 0; } From 0cd6d62faee71b0b6d206000a6b4a3c96514908b Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Mon, 18 Nov 2024 13:10:04 +0100 Subject: [PATCH 11/29] _targets/imx*: build usb drivers in lib versions JIRA: RTOS-970 (cherry picked from commit 9cdf1e172bbe3b6c6752e62181a35fadd7070b6e) --- _targets/Makefile.armv7a7-imx6ull | 2 +- _targets/Makefile.armv7m7-imxrt106x | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/_targets/Makefile.armv7a7-imx6ull b/_targets/Makefile.armv7a7-imx6ull index d081a2f62..cfff821b5 100644 --- a/_targets/Makefile.armv7a7-imx6ull +++ b/_targets/Makefile.armv7a7-imx6ull @@ -13,5 +13,5 @@ DEFAULT_COMPONENTS += libusbclient cdc-demo DEFAULT_COMPONENTS += imx6ull-uart imx6ull-otp DEFAULT_COMPONENTS += imx6ull-wdg imx6ull-i2c imx6ull-sdio -DEFAULT_COMPONENTS += libusbehci umass usbacm +DEFAULT_COMPONENTS += libusbehci umass libusbdrv-umass usbacm libusbdrv-usbacm DEFAULT_COMPONENTS += libsensors sensors diff --git a/_targets/Makefile.armv7m7-imxrt106x b/_targets/Makefile.armv7m7-imxrt106x index 064898c2c..3b64b28c3 100644 --- a/_targets/Makefile.armv7m7-imxrt106x +++ b/_targets/Makefile.armv7m7-imxrt106x @@ -9,9 +9,9 @@ DEFAULT_COMPONENTS := imxrt-multi ifneq (, $(findstring 117, $(TARGET))) - DEFAULT_COMPONENTS += libusbclient imxrt-flash cdc-demo imxrt117x-otp libusbehci umass usbacm + DEFAULT_COMPONENTS += libusbclient imxrt-flash cdc-demo imxrt117x-otp libusbehci umass libusbdrv-umass usbacm libusbdrv-usbacm else ifneq (, $(findstring 105, $(TARGET))) # placeholder else ifneq (, $(findstring 106, $(TARGET))) - DEFAULT_COMPONENTS += libusbclient imxrt-flash cdc-demo libimxrt-edma libusbehci umass usbacm + DEFAULT_COMPONENTS += libusbclient imxrt-flash cdc-demo libimxrt-edma libusbehci umass libusbdrv-umass usbacm libusbdrv-usbacm endif From 4370ca468a501e5e8a46a55c1313bcae7d696501 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 10 Jan 2025 16:46:22 +0100 Subject: [PATCH 12/29] storage/umass: handle quirky usb sticks Some real world sticks always fail few first commands but if REQUEST SENSE is done immediately afterwards, they will later work with no errors. Some others fail the first few READ commands, but recover after few retries. JIRA: RTOS-970 (cherry picked from commit 594cb684ae3aef13834956fa83f0948e93be533c) --- storage/umass/scsi.h | 63 +++++++++++ storage/umass/umass.c | 245 ++++++++++++++++++++++++++++++++---------- 2 files changed, 252 insertions(+), 56 deletions(-) create mode 100644 storage/umass/scsi.h diff --git a/storage/umass/scsi.h b/storage/umass/scsi.h new file mode 100644 index 000000000..99cd28b26 --- /dev/null +++ b/storage/umass/scsi.h @@ -0,0 +1,63 @@ +/* + * Phoenix-RTOS + * + * USB Mass Storage class driver + * + * SCSI transparent command set definitions header + * + * Copyright 2024 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + + +#ifndef _SCSI_H_ +#define _SCSI_H_ + +#include + + +/* Opcodes */ +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_INQUIRY 0x12 + + +typedef struct { + uint8_t opcode; + uint8_t action_misc0; /* [8:3] action, [3:0] misc0 */ + uint32_t lba; + uint8_t misc1; + uint16_t length; + uint8_t control; +} __attribute__((packed)) scsi_cdb10_t; + + +typedef struct { + uint8_t opcode; + uint8_t misc0[3]; + uint8_t length; + uint8_t control; +} __attribute__((packed)) scsi_cdb6_t; + + +typedef struct { + uint8_t errorcode; + uint8_t segnum; + uint8_t misc0_sensekey; /* [8:4] misc0, [4:0] sensekey */ + uint8_t misc[17]; +} __attribute__((packed)) scsi_sense_t; + + +typedef struct { + uint8_t qualifier_devicetype; /* [8:5] qualifier, [5:0] devicetype */ + uint8_t misc0; + uint8_t version; + uint8_t misc1[5]; + char vendorid[8]; + char productid[16]; + uint8_t misc[4]; +} __attribute__((packed)) scsi_inquiry_t; + + +#endif diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 2d157ddd0..ce31ccd69 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -28,6 +28,8 @@ #include +#define UMASS_DEBUG 0 + #ifdef UMASS_MOUNT_EXT2 #include #endif @@ -37,10 +39,14 @@ #include "../pc-ata/mbr.h" #include "umass.h" +#include "scsi.h" #define UMASS_N_MSG_THREADS 2 #define UMASS_N_POOL_THREADS 4 +#define UMASS_TRANSMIT_RETRIES 3 +#define UMASS_INIT_RETRIES 10 + #define UMASS_SECTOR_SIZE 512 #define UMASS_WRITE 0 @@ -49,10 +55,14 @@ #define CBW_SIG 0x43425355 #define CSW_SIG 0x53425355 +#define USB_SUBCLASS_SCSI 0x06 +#define USB_PROTOCOL_BULK 0x50 + /* clang-format off */ #define LOG(str_, ...) do { printf("umass: " str_ "\n", ##__VA_ARGS__); } while (0) -#define LOG_ERROR(str_, ...) LOG(__FILE__ ":%d error: " str_, __LINE__, ##__VA_ARGS__) -#define TRACE(str_, ...) do { if (0) LOG(__FILE__ ":%d TRACE: " str_, __LINE__, ##__VA_ARGS__); } while (0) +#define LOG_ERROR(str_, ...) LOG("error: " str_, ##__VA_ARGS__) +#define TRACE(str_, ...) do { if (0) LOG("trace (%d): " str_, __LINE__, ##__VA_ARGS__); } while (0) +#define DEBUG(str_, ...) do { if (UMASS_DEBUG) LOG("debug: " str_, ##__VA_ARGS__); } while (0) /* clang-format on */ @@ -75,17 +85,6 @@ typedef struct { } __attribute__((packed)) umass_csw_t; -typedef struct { - uint8_t opcode; - uint8_t action : 5; - uint8_t misc0 : 3; - uint32_t lba; - uint8_t misc1; - uint16_t length; - uint8_t control; -} __attribute__((packed)) scsi_cdb10_t; - - /* Device access callbacks */ static ssize_t umass_read(id_t id, off_t offs, char *buf, size_t len); static ssize_t umass_write(id_t id, off_t offs, const char *buf, size_t len); @@ -179,8 +178,7 @@ static struct { static const usb_device_id_t filters[] = { - /* USB Mass Storage class */ - { USBDRV_ANY, USBDRV_ANY, USB_CLASS_MASS_STORAGE, USBDRV_ANY, USBDRV_ANY }, + { USBDRV_ANY, USBDRV_ANY, USB_CLASS_MASS_STORAGE, USB_SUBCLASS_SCSI, USB_PROTOCOL_BULK }, }; @@ -213,54 +211,182 @@ static int umass_cmpfs(rbnode_t *node1, rbnode_t *node2) } +static int umass_scsiRequestSense(umass_dev_t *dev, char *odata); + + static int _umass_transmit(umass_dev_t *dev, void *cmd, size_t clen, char *data, size_t dlen, int dir) { + scsi_sense_t *sense; umass_cbw_t cbw = { 0 }; umass_csw_t csw = { 0 }; - int ret = 0, bytes = 0; + int ret = -1, bytes = 0; int dataPipe; + int i; if (clen > 16) return -1; - dataPipe = (dir == usb_dir_out) ? dev->pipeOut : dev->pipeIn; - cbw.sig = CBW_SIG; - cbw.tag = dev->tag++; - cbw.dlen = dlen; - cbw.flags = (dir == usb_dir_out) ? UMASS_WRITE : UMASS_READ; - cbw.lun = 0; - cbw.clen = clen; - memcpy(cbw.cmd, cmd, clen); - - ret = usb_transferBulk(dev->drv, dev->pipeOut, &cbw, sizeof(cbw), usb_dir_out); - if (ret != sizeof(cbw)) { - fprintf(stderr, "umass_transmit: usb_transferBulk OUT failed\n"); - return -EIO; - } + for (i = 0; ret < 0 && i < UMASS_TRANSMIT_RETRIES; i++) { + dataPipe = (dir == usb_dir_out) ? dev->pipeOut : dev->pipeIn; + cbw.sig = CBW_SIG; + cbw.tag = dev->tag++; + cbw.dlen = dlen; + cbw.flags = (dir == usb_dir_out) ? UMASS_WRITE : UMASS_READ; + cbw.lun = 0; + cbw.clen = clen; + memcpy(cbw.cmd, cmd, clen); + + ret = usb_transferBulk(dev->drv, dev->pipeOut, &cbw, sizeof(cbw), usb_dir_out); + if (ret != sizeof(cbw)) { + fprintf(stderr, "umass_transmit: usb_transferBulk OUT failed\n"); + return -EIO; + } - /* Optional data transfer */ - if (dlen > 0) { - ret = usb_transferBulk(dev->drv, dataPipe, data, dlen, dir); - if (ret < 0) { - fprintf(stderr, "umass_transmit: umass_transmit data transfer failed\n"); - return ret; + /* Optional data transfer */ + if (dlen > 0) { + ret = usb_transferBulk(dev->drv, dataPipe, data, dlen, dir); + if (ret < 0) { + fprintf(stderr, "umass_transmit: umass_transmit data transfer failed\n"); + return ret; + } + bytes = ret; + } + + ret = usb_transferBulk(dev->drv, dev->pipeIn, &csw, sizeof(csw), usb_dir_in); + if (ret != sizeof(csw)) { + fprintf(stderr, "umass_transmit: usb_transferBulk IN transfer failed\n"); + return -EIO; + } + + /* Transfer finished, check transfer correctness */ + if (csw.sig != CSW_SIG || csw.tag != cbw.tag || csw.status != 0) { + if (csw.status == 1) { + ret = umass_scsiRequestSense(dev, dev->buffer); + if (ret < 0) { + DEBUG("REQUEST SENSE failed: %d", ret); + } + else { + sense = (scsi_sense_t *)dev->buffer; + DEBUG("REQUEST SENSE code=0x%x, sense key code=0x%x", sense->errorcode, (sense->misc0_sensekey & 0xf)); + } + + /* Retry transfer */ + ret = -1; + bytes = 0; + continue; + } + else { + DEBUG("transfer incorrect.\n csw.sig=0x%x, csw.tag=0x%x, cbw.tag=0x%x, csw.status=%d\n", csw.sig, csw.tag, + cbw.tag, csw.status); + return -EIO; + } } - bytes = ret; } - ret = usb_transferBulk(dev->drv, dev->pipeIn, &csw, sizeof(csw), usb_dir_in); - if (ret != sizeof(csw)) { - fprintf(stderr, "umass_transmit: usb_transferBulk IN transfer failed\n"); + return bytes; +} + + +/* Left commented out: can be useful when handling devices of other types than direct-access + * (non-zero "Peripheral Device Type" in INQUIRY) */ +#if 0 +static int umass_getMaxLUN(umass_dev_t *dev, int ifaceNum, int *maxlun) +{ + usb_setup_packet_t setup = (usb_setup_packet_t) { + .bmRequestType = REQUEST_DIR_DEV2HOST | REQUEST_TYPE_CLASS | REQUEST_RECIPIENT_INTERFACE, + .bRequest = 0xFE, /* Get Max LUN */ + .wValue = 0, + .wIndex = ifaceNum, + .wLength = 1, + }; + int ret; + + ret = usb_transferControl(dev->drv, dev->pipeCtrl, &setup, maxlun, 1, usb_dir_in); + if (ret < 0) { + LOG("get max LUN failed"); + dev->maxlun = 0; return -EIO; } - /* Transfer finished, check transfer correctness */ - if (csw.sig != CSW_SIG || csw.tag != cbw.tag || csw.status != 0) { - fprintf(stderr, "umass_transmit: transfer incorrect\n"); - return -EIO; + return 0; +} +#endif + + +static int umass_scsiTest(umass_dev_t *dev) +{ + char testCmd[6] = { 0 }; + int ret; + + ret = _umass_transmit(dev, testCmd, sizeof(testCmd), NULL, 0, usb_dir_in); + + return ret == 0 ? 0 : -EIO; +} + + +static int umass_scsiRequestSense(umass_dev_t *dev, char *odata) +{ + uint8_t len = sizeof(scsi_sense_t); + int ret; + scsi_cdb6_t requestSenseCmd = { + .opcode = SCSI_REQUEST_SENSE, + .length = htons(len), + }; + + ret = _umass_transmit(dev, &requestSenseCmd, sizeof(requestSenseCmd), (char *)odata, len, usb_dir_in); + + return ret == sizeof(scsi_sense_t) ? 0 : -EIO; +} + + +static int umass_scsiInquiry(umass_dev_t *dev, char *odata) +{ + uint8_t len = sizeof(scsi_inquiry_t); + int ret; + scsi_cdb6_t inquiryCmd = { + .opcode = SCSI_INQUIRY, + .length = htons(len), + }; + + ret = _umass_transmit(dev, &inquiryCmd, sizeof(inquiryCmd), odata, len, usb_dir_in); + + return ret == sizeof(scsi_inquiry_t) ? 0 : -EIO; +} + + +static int _umass_scsiInit(umass_dev_t *dev) +{ + int ret; + int i, ok; + scsi_inquiry_t *inquiry; + + for (i = 0, ok = 0; ok < 2 && i < UMASS_INIT_RETRIES; i++) { + ok = 0; + + ret = umass_scsiTest(dev); + if (ret == 0) { + DEBUG("TEST UNIT READY succeeded"); + ok++; + } + + /* Some real world are said to not work without doing INQUIRY first */ + ret = umass_scsiInquiry(dev, dev->buffer); + if (ret == 0) { + inquiry = (scsi_inquiry_t *)dev->buffer; + + DEBUG("INQUIRY succeeded\n" + " device type=%x vendorid=%s\n" + " productid=%s", + (inquiry->qualifier_devicetype & 0x1f), inquiry->vendorid, inquiry->productid); + + ok++; + } + else { + DEBUG("INQUIRY failed, ret=%d", ret); + } } - return bytes; + return ok == 2 ? 0 : -1; } @@ -270,26 +396,21 @@ static int _umass_check(umass_dev_t *dev) .opcode = 0x28, .length = htons(0x1) }; - char testcmd[6] = { 0 }; mbr_t *mbr; int ret; - ret = _umass_transmit(dev, testcmd, sizeof(testcmd), NULL, 0, usb_dir_in); - if (ret < 0) { - fprintf(stderr, "umass_transmit failed\n"); - return -1; - } - /* Read MBR */ ret = _umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, UMASS_SECTOR_SIZE, usb_dir_in); if (ret < 0) { - fprintf(stderr, "umass_transmit 2 failed\n"); + LOG_ERROR("reading MBR failed"); return -1; } mbr = (mbr_t *)dev->buffer; - if (mbr->magic != MBR_MAGIC) + if (mbr->magic != MBR_MAGIC) { + LOG_ERROR("bad MBR magic: 0x%x", mbr->magic); return -1; + } /* Read only the first partition */ dev->part.start = mbr->pent[0].start; @@ -298,6 +419,8 @@ static int _umass_check(umass_dev_t *dev) dev->part.fdata = NULL; dev->part.idx = 0; + DEBUG("part.start=0x%x, part.sectors=0x%x", dev->part.start, dev->part.sectors); + return 0; } @@ -684,6 +807,9 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) int err; umass_dev_t *dev; oid_t oid; + int ret; + + fprintf(stderr, "umass: pending insertion\n"); mutexLock(umass_common.lock); @@ -723,8 +849,15 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) } dev->tag = 0; - err = _umass_check(dev); - if (err != 0) { + ret = _umass_scsiInit(dev); + if (ret < 0) { + fprintf(stderr, "umass: device didn't initialize properly after scsi init sequence\n"); + free(dev); + return -EINVAL; + } + + ret = _umass_check(dev); + if (ret < 0) { fprintf(stderr, "umass: umass_check failed\n"); free(dev); return -EINVAL; From 39e405a753b2cb0b106eafb6617ee48564dd67f2 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 27 Mar 2025 17:56:02 +0100 Subject: [PATCH 13/29] umass: adapt to events API JIRA: RTOS-1024 (cherry picked from commit f160d1a03f8bdde0fb70bcd02f2187c58d83af4a) --- storage/umass/umass.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index ce31ccd69..06a4c5701 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -802,7 +802,7 @@ static int umass_mountRoot(umass_dev_t *dev) } -static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) +static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, usb_event_insertion_t *event) { int err; umass_dev_t *dev; @@ -874,6 +874,10 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) printf("umass: New USB Mass Storage device: %s sectors: %d\n", dev->path, dev->part.sectors); + event->deviceCreated = true; + event->dev = oid; + strncpy(event->devPath, dev->path, sizeof(event->devPath)); + mutexUnlock(umass_common.lock); if (umass_common.mount_root) { From 21b10c9d1f5b397140ad924c51470f3f22931edc Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 18 Apr 2025 14:16:27 +0200 Subject: [PATCH 14/29] usbacm: adapt to events API JIRA: RTOS-1024 (cherry picked from commit b5f6620b5b602cd74dda7e25ddd2818fe8753bee) --- tty/usbacm/usbacm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 3979cdaa8..2895f6f80 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -639,7 +639,7 @@ static void usbacm_msgthr(void *arg) } -static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) +static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, usb_event_insertion_t *event) { usbacm_dev_t *dev; const usb_modeswitch_t *mode; @@ -728,6 +728,10 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion) fprintf(stdout, "usbacm: New device: %s\n", dev->path); + event->deviceCreated = true; + event->dev = oid; + strncpy(event->devPath, dev->path, sizeof(event->devPath)); + return 0; } From 8636b2264c9e899e8693fe10705537632c6a7d96 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 18 Apr 2025 14:18:15 +0200 Subject: [PATCH 15/29] usbacm: set line coding on device insertion JIRA: RTOS-1024 (cherry picked from commit c144b16f65390380a004a41c1d40618c2b7a4bf1) --- tty/usbacm/usbacm.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 2895f6f80..fa45728ef 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -52,6 +52,10 @@ #define USBACM_UMSG_PRIO 3 #endif +#ifndef USBACM_SET_LINE_DEFAULT_RATE +#define USBACM_SET_LINE_DEFAULT_RATE 57600 +#endif + #define USBACM_BULK_SZ 2048 /* clang-format off */ @@ -91,6 +95,8 @@ typedef struct _usbacm_dev { int rxState; usb_driver_t *drv; + + usb_cdc_line_coding_t line; } usbacm_dev_t; @@ -257,6 +263,20 @@ static void usbacm_put(usbacm_dev_t *dev) } +static int usbacm_setLine(usbacm_dev_t *dev) +{ + usb_setup_packet_t setup = { + .bmRequestType = REQUEST_DIR_HOST2DEV | REQUEST_TYPE_CLASS | REQUEST_RECIPIENT_INTERFACE, + .bRequest = 0x20, /* SET_LINE_CODING */ + .wValue = 0, + .wIndex = 0, + .wLength = sizeof(usb_cdc_line_coding_t), + }; + + return usb_transferControl(dev->drv, dev->pipeCtrl, &setup, &dev->line, sizeof(usb_cdc_line_coding_t), usb_dir_out); +} + + static int usbacm_handleCompletion(usb_driver_t *drv, usb_completion_t *c, const char *data, size_t len) { usbacm_dev_t *dev; @@ -704,6 +724,18 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u break; } + dev->line.dwDTERate = USBACM_SET_LINE_DEFAULT_RATE; + dev->line.bCharFormat = 0; + dev->line.bParityType = 0; + dev->line.bDataBits = 8; + + /* Some broken devices won't function without doing the set line cmd first */ + err = usbacm_setLine(dev); + if (err < 0) { + fprintf(stderr, "usbacm: Set line to speed %d failed/unsupported: %d\n", dev->line.dwDTERate, err); + /* Continue as this is optional: device may reject the setting/not support the set line cmd */ + } + oid.port = usbacm_common.msgport; oid.id = dev->fileId; From 3e421fb31300df5beaa4df11a4a9db6d397dca8d Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 25 Apr 2025 16:03:11 +0200 Subject: [PATCH 16/29] umass: fix incorrect error handling and a resulting deadlock on device insertion Mutex was still locked when returning after error from umass_handleInsertion JIRA: RTOS-1024 (cherry picked from commit 6fd2aaa097291dcfc453b94bae9c2e3df09d9c0a) --- storage/umass/umass.c | 140 ++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 65 deletions(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 06a4c5701..c1e5506a1 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -748,7 +748,15 @@ static void umass_msgthr(void *arg) } -static umass_dev_t *umass_devAlloc(void) +static void _umass_devFree(umass_dev_t *dev) +{ + idtree_remove(&umass_common.devices, &dev->node); + resourceDestroy(dev->lock); + free(dev); +} + + +static umass_dev_t *_umass_devAlloc(void) { umass_dev_t *dev; int rv; @@ -770,8 +778,7 @@ static umass_dev_t *umass_devAlloc(void) rv = snprintf(dev->path, sizeof(dev->path), "/dev/umass%d", dev->fileId); if (rv < 0) { - resourceDestroy(dev->lock); - free(dev); + _umass_devFree(dev); return NULL; } @@ -807,80 +814,84 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, us int err; umass_dev_t *dev; oid_t oid; - int ret; - - fprintf(stderr, "umass: pending insertion\n"); mutexLock(umass_common.lock); - if ((dev = umass_devAlloc()) == NULL) { - fprintf(stderr, "umass: devAlloc failed\n"); - return -ENOMEM; - } + do { + dev = _umass_devAlloc(); + if (dev == NULL) { + fprintf(stderr, "umass: devAlloc failed\n"); + err = -ENOMEM; + break; + } - dev->drv = drv; - dev->instance = *insertion; - dev->pipeCtrl = usb_open(drv, insertion, usb_transfer_control, 0); - if (dev->pipeCtrl < 0) { - free(dev); - fprintf(stderr, "umass: usb_open failed\n"); - return -EINVAL; - } + dev->drv = drv; + dev->instance = *insertion; + dev->pipeCtrl = usb_open(drv, insertion, usb_transfer_control, 0); + if (dev->pipeCtrl < 0) { + fprintf(stderr, "umass: usb_open failed\n"); + _umass_devFree(dev); + err = -EINVAL; + break; + } - err = usb_setConfiguration(drv, dev->pipeCtrl, 1); - if (err != 0) { - free(dev); - fprintf(stderr, "umass: setConfiguration failed\n"); - return -EINVAL; - } + err = usb_setConfiguration(drv, dev->pipeCtrl, 1); + if (err != 0) { + fprintf(stderr, "umass: setConfiguration failed\n"); + _umass_devFree(dev); + break; + } - dev->pipeIn = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_in); - if (dev->pipeIn < 0) { - fprintf(stderr, "umass: pipe open failed \n"); - free(dev); - return -EINVAL; - } + dev->pipeIn = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_in); + if (dev->pipeIn < 0) { + fprintf(stderr, "umass: pipe open failed \n"); + _umass_devFree(dev); + err = -EINVAL; + break; + } - dev->pipeOut = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_out); - if (dev->pipeOut < 0) { - fprintf(stderr, "umass: pipe open failed\n"); - free(dev); - return -EINVAL; - } - dev->tag = 0; + dev->pipeOut = usb_open(drv, insertion, usb_transfer_bulk, usb_dir_out); + if (dev->pipeOut < 0) { + fprintf(stderr, "umass: pipe open failed\n"); + _umass_devFree(dev); + err = -EINVAL; + break; + } + dev->tag = 0; - ret = _umass_scsiInit(dev); - if (ret < 0) { - fprintf(stderr, "umass: device didn't initialize properly after scsi init sequence\n"); - free(dev); - return -EINVAL; - } + err = _umass_scsiInit(dev); + if (err < 0) { + fprintf(stderr, "umass: device didn't initialize properly after scsi init sequence\n"); + _umass_devFree(dev); + break; + } - ret = _umass_check(dev); - if (ret < 0) { - fprintf(stderr, "umass: umass_check failed\n"); - free(dev); - return -EINVAL; - } + err = _umass_check(dev); + if (err < 0) { + fprintf(stderr, "umass: umass_check failed\n"); + _umass_devFree(dev); + break; + } - oid.port = umass_common.msgport; - oid.id = dev->fileId; - err = create_dev(&oid, dev->path); - if (err != 0) { - free(dev); - fprintf(stderr, "usb: Can't create dev!\n"); - return -EINVAL; - } + oid.port = umass_common.msgport; + oid.id = dev->fileId; + err = create_dev(&oid, dev->path); + if (err != 0) { + fprintf(stderr, "usb: Can't create dev!\n"); + _umass_devFree(dev); + break; + } - printf("umass: New USB Mass Storage device: %s sectors: %d\n", dev->path, dev->part.sectors); + printf("umass: New USB Mass Storage device: %s sectors: %d\n", dev->path, dev->part.sectors); - event->deviceCreated = true; - event->dev = oid; - strncpy(event->devPath, dev->path, sizeof(event->devPath)); + event->deviceCreated = true; + event->dev = oid; + strncpy(event->devPath, dev->path, sizeof(event->devPath)); + } while (0); mutexUnlock(umass_common.lock); - if (umass_common.mount_root) { + if (err == 0 && umass_common.mount_root) { err = umass_mountRoot(dev); if (err < 0) { fprintf(stderr, "umass: failed to mount root partition\n"); @@ -889,7 +900,7 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, us umass_common.mount_root = false; /* don't try to mount root again */ } - return 0; + return err; } @@ -907,10 +918,9 @@ static int umass_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) dev = lib_treeof(umass_dev_t, node, lib_treeof(idnode_t, linkage, node)); if (dev->instance.bus == del->bus && dev->instance.dev == del->dev && dev->instance.interface == del->interface) { - resourceDestroy(dev->lock); remove(dev->path); fprintf(stderr, "umass: Device removed: %s\n", dev->path); - free(dev); + _umass_devFree(dev); } node = next; From 903ed0e1c8b54e2fcb3d46e46ddc04c1144bb108 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 25 Apr 2025 16:05:08 +0200 Subject: [PATCH 17/29] usbacm: check condCreate return value JIRA: RTOS-1024 (cherry picked from commit ae3e1954ca359cde4da48085a66e7ff4ea768162) --- tty/usbacm/usbacm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index fa45728ef..3e41486c7 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -717,7 +717,7 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u break; } - condCreate(&dev->rxCond); + err = condCreate(&dev->rxCond); if (err != 0) { resourceDestroy(dev->rxLock); err = -ENOMEM; From b23e7caf4f328c070a4cfa346ca891184910a0d8 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Tue, 29 Apr 2025 14:03:09 +0200 Subject: [PATCH 18/29] umass: fix snprintf not being checked for truncation JIRA: RTOS-1024 (cherry picked from commit 0631265995ef78a76dd00ff3902509dc07ffe1c7) --- storage/umass/umass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index c1e5506a1..503c6ea32 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -777,7 +777,7 @@ static umass_dev_t *_umass_devAlloc(void) dev->fileId = idtree_id(&dev->node); rv = snprintf(dev->path, sizeof(dev->path), "/dev/umass%d", dev->fileId); - if (rv < 0) { + if (rv < 0 || rv >= sizeof(dev->path)) { _umass_devFree(dev); return NULL; } From fe39c3a998d5d66b2323de4d0ac70d8bd5aa3d23 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 11:05:11 +0200 Subject: [PATCH 19/29] usbacm: remove unused drvport, rename usbacm_freeAll to _usbacm_freeAll JIRA: RTOS-970 (cherry picked from commit caa8ba16053bcf209842343b5c5f5aa702fb8677) --- tty/usbacm/usbacm.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 3e41486c7..69b87fa0a 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -103,7 +103,6 @@ typedef struct _usbacm_dev { static struct { char msgstack[USBACM_N_MSG_THREADS][1024] __attribute__((aligned(8))); usbacm_dev_t *devices; - unsigned drvport; unsigned msgport; handle_t lock; int lastId; @@ -224,7 +223,7 @@ static void usbacm_free(usbacm_dev_t *dev) } -static void usbacm_freeAll(usbacm_dev_t **devices) +static void _usbacm_freeAll(usbacm_dev_t **devices) { usbacm_dev_t *next, *dev = *devices; @@ -802,7 +801,7 @@ static int usbacm_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) dev = next; } while (dev != usbacm_common.devices); - usbacm_freeAll(&usbacm_common.devicesToFree); + _usbacm_freeAll(&usbacm_common.devicesToFree); mutexUnlock(usbacm_common.lock); @@ -817,12 +816,6 @@ static int usbacm_init(usb_driver_t *drv, void *args) usbacm_common.devicesToFree = NULL; - /* Port for communication with the USB stack */ - if (portCreate(&usbacm_common.drvport) != 0) { - fprintf(stderr, "usbacm: Can't create port!\n"); - return 1; - } - /* Port for communication with driver clients */ if (portCreate(&usbacm_common.msgport) != 0) { fprintf(stderr, "usbacm: Can't create port!\n"); From 2314fe634385385997a7e430a638ca35d5177979 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 11:06:33 +0200 Subject: [PATCH 20/29] usbacm: use idtree for device id allocation JIRA: RTOS-970 (cherry picked from commit c3c46a71bd72175a1656c4efe195342256970fce) --- tty/usbacm/usbacm.c | 134 +++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 84 deletions(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 69b87fa0a..7f2385791 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,8 @@ enum { RxStopped = 0, RxRunning = 1, RxDisconnected = -1 }; /* clang-format on */ typedef struct _usbacm_dev { - struct _usbacm_dev *prev, *next; + idnode_t node; /* node.id is oid.id and ACM id (/dev/usbacm[ID]) */ + usb_devinfo_t instance; /* USB HOST related */ @@ -77,8 +79,6 @@ typedef struct _usbacm_dev { int urbctrl; char path[32]; - unsigned int id; /* ACM id (/dev/usbacm[ID]) */ - int fileId; /* oid.id */ /* opened file state */ int flags; @@ -102,11 +102,9 @@ typedef struct _usbacm_dev { static struct { char msgstack[USBACM_N_MSG_THREADS][1024] __attribute__((aligned(8))); - usbacm_dev_t *devices; + idtree_t devices; unsigned msgport; handle_t lock; - int lastId; - usbacm_dev_t *devicesToFree; } usbacm_common; @@ -170,18 +168,16 @@ static void usbacm_fifoPush(usbacm_dev_t *dev, const char *data, size_t size) static usbacm_dev_t *usbacm_getByPipe(int pipe) { usbacm_dev_t *tmp, *dev = NULL; + rbnode_t *node; mutexLock(usbacm_common.lock); - tmp = usbacm_common.devices; - if (tmp != NULL) { - do { - if (tmp->pipeBulkIN == pipe || tmp->pipeBulkOUT == pipe || tmp->pipeIntIN == pipe) { - dev = tmp; - dev->rfcnt++; - break; - } - tmp = tmp->next; - } while (tmp != usbacm_common.devices); + for (node = lib_rbMinimum(usbacm_common.devices.root); node != NULL; node = lib_rbNext(node)) { + tmp = lib_treeof(usbacm_dev_t, node, lib_treeof(idnode_t, linkage, node)); + if (tmp->pipeBulkIN == pipe || tmp->pipeBulkOUT == pipe || tmp->pipeIntIN == pipe) { + dev = tmp; + dev->rfcnt++; + break; + } } mutexUnlock(usbacm_common.lock); @@ -191,19 +187,12 @@ static usbacm_dev_t *usbacm_getByPipe(int pipe) static usbacm_dev_t *usbacm_get(int id) { - usbacm_dev_t *tmp, *dev = NULL; + usbacm_dev_t *dev; mutexLock(usbacm_common.lock); - tmp = usbacm_common.devices; - if (tmp != NULL) { - do { - if (tmp->fileId == id) { - dev = tmp; - dev->rfcnt++; - break; - } - tmp = tmp->next; - } while (tmp != usbacm_common.devices); + dev = lib_treeof(usbacm_dev_t, node, idtree_find(&usbacm_common.devices, id)); + if (dev != NULL) { + dev->rfcnt++; } mutexUnlock(usbacm_common.lock); @@ -223,26 +212,10 @@ static void usbacm_free(usbacm_dev_t *dev) } -static void _usbacm_freeAll(usbacm_dev_t **devices) -{ - usbacm_dev_t *next, *dev = *devices; - - if (dev != NULL) { - do { - next = dev->next; - usbacm_free(dev); - dev = next; - } while (dev != *devices); - } - - *devices = NULL; -} - - static int _usbacm_put(usbacm_dev_t *dev) { if (--dev->rfcnt == 0) { - LIST_REMOVE(&usbacm_common.devices, dev); + idtree_remove(&usbacm_common.devices, &dev->node); } return dev->rfcnt; } @@ -431,32 +404,23 @@ static int usbacm_write(usbacm_dev_t *dev, const char *data, size_t len) } -static usbacm_dev_t *usbacm_devAlloc(void) +static usbacm_dev_t *_usbacm_devAlloc(void) { usbacm_dev_t *dev; - if ((dev = calloc(1, sizeof(usbacm_dev_t))) == NULL) { + dev = calloc(1, sizeof(usbacm_dev_t)); + if (dev == NULL) { fprintf(stderr, "usbacm: Not enough memory\n"); return NULL; } - mutexLock(usbacm_common.lock); - /* Get next device number */ - if (usbacm_common.devices == NULL) - dev->id = 0; - else - dev->id = usbacm_common.devices->prev->id + 1; + if (idtree_alloc(&usbacm_common.devices, &dev->node) != 0) { + free(dev); + return NULL; + } - dev->fileId = usbacm_common.lastId++; dev->rfcnt = 1; - /* add this device prematurely to devices list, to mitigate race condition on - * multiple concurrent insertions */ - LIST_ADD(&usbacm_common.devices, dev); - mutexUnlock(usbacm_common.lock); - - snprintf(dev->path, sizeof(dev->path), "/dev/usbacm%u", dev->id); - return dev; } @@ -674,8 +638,13 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u return usb_modeswitchHandle(drv, insertion, mode); } - if ((dev = usbacm_devAlloc()) == NULL) + mutexLock(usbacm_common.lock); + + dev = _usbacm_devAlloc(); + if (dev == NULL) { + mutexUnlock(usbacm_common.lock); return -ENOMEM; + } dev->instance = *insertion; dev->drv = drv; @@ -736,7 +705,9 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u } oid.port = usbacm_common.msgport; - oid.id = dev->fileId; + oid.id = idtree_id(&dev->node); + + snprintf(dev->path, sizeof(dev->path), "/dev/usbacm%zu", oid.id); err = create_dev(&oid, dev->path); if (err != 0) { @@ -749,10 +720,12 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u } while (0); if (err < 0) { - mutexLock(usbacm_common.lock); - /* remove the device from list, as it has been added there in devAlloc */ - LIST_REMOVE(&usbacm_common.devices, dev); - mutexUnlock(usbacm_common.lock); + _usbacm_put(dev); + } + + mutexUnlock(usbacm_common.lock); + + if (err < 0) { free(dev); return err; } @@ -769,22 +742,20 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u static int usbacm_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) { - usbacm_dev_t *next, *dev = usbacm_common.devices; - int cont = 1; - - if (dev == NULL) - return 0; + rbnode_t *node, *next; + usbacm_dev_t *dev; TRACE("handleDeletion"); mutexLock(usbacm_common.lock); - do { - next = dev->next; + node = lib_rbMinimum(usbacm_common.devices.root); + while (node != NULL) { + next = lib_rbNext(node); + dev = lib_treeof(usbacm_dev_t, node, lib_treeof(idnode_t, linkage, node)); + if (dev->instance.bus == del->bus && dev->instance.dev == del->dev && dev->instance.interface == del->interface) { - if (dev == next) - cont = 0; /* close pending transfers, reject new ones */ mutexLock(dev->rxLock); @@ -793,15 +764,12 @@ static int usbacm_handleDeletion(usb_driver_t *drv, usb_deletion_t *del) mutexUnlock(dev->rxLock); if (_usbacm_put(dev) == 0) { - LIST_ADD(&usbacm_common.devicesToFree, dev); + usbacm_free(dev); } - if (!cont) - break; } - dev = next; - } while (dev != usbacm_common.devices); - _usbacm_freeAll(&usbacm_common.devicesToFree); + node = next; + } mutexUnlock(usbacm_common.lock); @@ -814,8 +782,6 @@ static int usbacm_init(usb_driver_t *drv, void *args) int ret; int i; - usbacm_common.devicesToFree = NULL; - /* Port for communication with driver clients */ if (portCreate(&usbacm_common.msgport) != 0) { fprintf(stderr, "usbacm: Can't create port!\n"); @@ -827,7 +793,7 @@ static int usbacm_init(usb_driver_t *drv, void *args) return 1; } - usbacm_common.lastId = 1; + idtree_init(&usbacm_common.devices); for (i = 0; i < USBACM_N_MSG_THREADS; i++) { ret = beginthread(usbacm_msgthr, USBACM_MSG_PRIO, usbacm_common.msgstack[i], sizeof(usbacm_common.msgstack[i]), NULL); From da9949f21324ef6752f304c192f54c02274f38ef Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 11:09:52 +0200 Subject: [PATCH 21/29] umass: decrease number of worker threads and make it configurable JIRA: RTOS-970 (cherry picked from commit 3b4ef64a7ef6415c966d6b19d0701cce2e3ab2b7) --- storage/umass/umass.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 503c6ea32..d0b7374be 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -28,6 +28,8 @@ #include +#include + #define UMASS_DEBUG 0 #ifdef UMASS_MOUNT_EXT2 @@ -41,8 +43,13 @@ #include "umass.h" #include "scsi.h" -#define UMASS_N_MSG_THREADS 2 -#define UMASS_N_POOL_THREADS 4 +#ifndef UMASS_N_MSG_THREADS +#define UMASS_N_MSG_THREADS 2 +#endif + +#ifndef UMASS_N_POOL_THREADS +#define UMASS_N_POOL_THREADS 2 +#endif #define UMASS_TRANSMIT_RETRIES 3 #define UMASS_INIT_RETRIES 10 From c4ac24a5e146a549265148ca102ca683a1e1758e Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 11:12:24 +0200 Subject: [PATCH 22/29] umass/srv: wait for rootfs instead of console JIRA: RTOS-970 (cherry picked from commit 53d5c1a5da9ea2ca731158310634c4ee0e17e001) --- storage/umass/srv.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/storage/umass/srv.c b/storage/umass/srv.c index ffec4d456..2c0a11bdf 100644 --- a/storage/umass/srv.c +++ b/storage/umass/srv.c @@ -31,6 +31,7 @@ int main(int argc, char *argv[]) { int ret; char c; + oid_t oid; umass_args_t umass_args = { .mount_root = false }; usb_driver_t *driver = usb_registeredDriverPop(); @@ -39,11 +40,6 @@ int main(int argc, char *argv[]) return 1; } - /* Wait for console */ - while (write(1, "", 0) < 0) { - usleep(50000); - } - if (argc > 1) { /* Process command line options */ for (;;) { @@ -63,6 +59,13 @@ int main(int argc, char *argv[]) } } + if (!umass_args.mount_root) { + /* Wait for root filesystem if not responsible for mounting it */ + while (lookup("/", NULL, &oid) < 0) { + usleep(10000); + } + } + ret = usb_driverProcRun(driver, &umass_args); return ret == 0 ? 0 : 1; From 238bec00a3fab0ea5062a5c065f7c1ad72c35c75 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 12:26:43 +0200 Subject: [PATCH 23/29] umass: fix umass_mountFromDev error paths JIRA: RTOS-970 (cherry picked from commit 2c5dc168202eb494d3284bfd224a6a604a70e9cc) --- storage/umass/umass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index d0b7374be..fc3c40201 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -595,6 +595,7 @@ static int umass_mountFromDev(umass_dev_t *dev, const char *name, oid_t *oid) err = fs->mount(oid, UMASS_SECTOR_SIZE, umass_read, umass_write, &dev->part.fdata); if (err < 0) { + portDestroy(dev->part.port); return err; } oid->id = err; @@ -604,6 +605,7 @@ static int umass_mountFromDev(umass_dev_t *dev, const char *name, oid_t *oid) dev->part.fs->unmount(dev->part.fdata); dev->part.fs = NULL; dev->part.fdata = NULL; + portDestroy(dev->part.port); return err; } @@ -650,8 +652,8 @@ static void umass_fsthr(void *arg) LIST_ADD(&umass_common.rqueue, req); - mutexUnlock(umass_common.rlock); condSignal(umass_common.rcond); + mutexUnlock(umass_common.rlock); if (umount != 0) { endthread(); From c410748f9d1de91f93f140c5356c2797e39b4026 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 11:26:56 +0200 Subject: [PATCH 24/29] umass: remove intermediate buffer JIRA: RTOS-970 (cherry picked from commit 7e1b9a5939de7c0194c2d2f1424f84e7c27f3ed2) --- storage/umass/umass.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index fc3c40201..b1f20f1e2 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -481,14 +481,12 @@ static int umass_readFromDev(umass_dev_t *dev, off_t offs, char *buf, size_t len readcmd.length = htons((uint16_t)(len / UMASS_SECTOR_SIZE)); mutexLock(dev->lock); - ret = _umass_transmit(dev, &readcmd, sizeof(readcmd), dev->buffer, len, usb_dir_in); - if (ret > 0) { - memcpy(buf, dev->buffer, len); - } - else if (len > 0) { + ret = _umass_transmit(dev, &readcmd, sizeof(readcmd), buf, len, usb_dir_in); + mutexUnlock(dev->lock); + + if (ret <= 0 && len > 0) { printf("read transmit failed for offs: %lld\n", offs); } - mutexUnlock(dev->lock); return ret; } @@ -513,8 +511,7 @@ static int umass_writeToDev(umass_dev_t *dev, off_t offs, const char *buf, size_ writecmd.length = htons((uint16_t)(len / UMASS_SECTOR_SIZE)); mutexLock(dev->lock); - memcpy(dev->buffer, buf, len); - ret = _umass_transmit(dev, &writecmd, sizeof(writecmd), dev->buffer, len, usb_dir_out); + ret = _umass_transmit(dev, &writecmd, sizeof(writecmd), (char *)buf, len, usb_dir_out); mutexUnlock(dev->lock); if (ret < 0) { fprintf(stderr, "write transmit failed for offs: %lld\n", offs); @@ -632,7 +629,8 @@ static void umass_fsthr(void *arg) int umount = 0, ret; for (;;) { - req = (umass_req_t *)malloc(sizeof(umass_req_t)); + /* TODO: use static requests buffer? */ + req = malloc(sizeof(umass_req_t)); if (req == NULL) { continue; } From f020e89669781d8d2a1c9baedf4f50d8dcf21fb8 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 12:47:14 +0200 Subject: [PATCH 25/29] umass: use strncpy JIRA: RTOS-970 (cherry picked from commit 1b340e358fd3c8a728802f18b6ab6d8c5c801b98) --- storage/umass/umass.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index b1f20f1e2..05fd84c97 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -197,7 +197,8 @@ static int umass_registerfs(const char *name, uint8_t type, fs_mount_t mount, fs return -ENOMEM; } - strcpy(fs->name, name); + strncpy(fs->name, name, sizeof(fs->name)); + fs->name[sizeof(fs->name) - 1] = '\0'; fs->type = type; fs->mount = mount; fs->unmount = unmount; @@ -436,7 +437,8 @@ static umass_fs_t *umass_getfs(const char *name) { umass_fs_t fs; - strcpy(fs.name, name); + strncpy(fs.name, name, sizeof(fs.name)); + fs.name[sizeof(fs.name) - 1] = '\0'; return lib_treeof(umass_fs_t, node, lib_rbFind(&umass_common.fss, &fs.node)); } @@ -894,6 +896,7 @@ static int umass_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, us event->deviceCreated = true; event->dev = oid; strncpy(event->devPath, dev->path, sizeof(event->devPath)); + event->devPath[sizeof(event->devPath) - 1] = '\0'; } while (0); mutexUnlock(umass_common.lock); From acd436bcd20a76fe32df6b30860a5ce455e7738b Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 6 Jun 2025 12:53:17 +0200 Subject: [PATCH 26/29] umass: access requests in FIFO order There is no clear benefit from LIFO processing JIRA: RTOS-970 (cherry picked from commit 073b881951e19ac8ae391a719f4bf4efc30dded3) --- storage/umass/umass.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/storage/umass/umass.c b/storage/umass/umass.c index 05fd84c97..a8efc4236 100644 --- a/storage/umass/umass.c +++ b/storage/umass/umass.c @@ -672,7 +672,12 @@ static void umass_poolthr(void *arg) while (umass_common.rqueue == NULL) { condWait(umass_common.rcond, umass_common.rlock, 0); } - req = umass_common.rqueue->prev; + + /* + * FIFO - assumes LIST_ADD/REMOVE set the queue pointer to the + * element added first + */ + req = umass_common.rqueue; LIST_REMOVE(&umass_common.rqueue, req); mutexUnlock(umass_common.rlock); From f84e1bbc42f79bcb146d7ed8fa8c6b14605b0145 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 18 Jun 2025 10:47:56 +0200 Subject: [PATCH 27/29] usbacm: fix use-after-free due to incorrect idtree_alloc error value check idtree_alloc returns node id on success JIRA: RTOS-970 (cherry picked from commit 13b60c47d8188e91629801f8a21056ab846cabf0) --- tty/usbacm/usbacm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 7f2385791..1b24a2a07 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -414,7 +414,7 @@ static usbacm_dev_t *_usbacm_devAlloc(void) return NULL; } - if (idtree_alloc(&usbacm_common.devices, &dev->node) != 0) { + if (idtree_alloc(&usbacm_common.devices, &dev->node) < 0) { free(dev); return NULL; } From 55db5c392640fd47186e054bd9bda006be6d54d8 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 18 Jun 2025 10:50:18 +0200 Subject: [PATCH 28/29] usbacm: update the dev refcnt on failure JIRA: RTOS-970 (cherry picked from commit c69cb7e52451f586ddc025d019bfa0b13c47af7a) --- tty/usbacm/usbacm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index 1b24a2a07..ec2e69e21 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -566,6 +566,7 @@ static void usbacm_msgthr(void *arg) /* A device can be opened only by one process */ /* FIXME: allow mtClose with different PID (files closing on process exit have invalid PID value as of 2023-10-23) */ if (((msg.type != mtOpen) && (msg.type != mtClose)) && (msg.pid != dev->clientpid)) { + usbacm_put(dev); msg.o.err = -EBUSY; msgRespond(usbacm_common.msgport, &msg, rid); continue; From 178e75c313362a4611e076f8e1cc725beb3cac3e Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Wed, 18 Jun 2025 10:52:01 +0200 Subject: [PATCH 29/29] usbacm: suppress snprintf format warning type of oid.id is sized differently depending on target JIRA: RTOS-970 (cherry picked from commit 1f9cdcbef99becd8694602ec80404095c7139100) --- tty/usbacm/usbacm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty/usbacm/usbacm.c b/tty/usbacm/usbacm.c index ec2e69e21..7bccb52d9 100644 --- a/tty/usbacm/usbacm.c +++ b/tty/usbacm/usbacm.c @@ -708,7 +708,7 @@ static int usbacm_handleInsertion(usb_driver_t *drv, usb_devinfo_t *insertion, u oid.port = usbacm_common.msgport; oid.id = idtree_id(&dev->node); - snprintf(dev->path, sizeof(dev->path), "/dev/usbacm%zu", oid.id); + snprintf(dev->path, sizeof(dev->path), "/dev/usbacm%d", idtree_id(&dev->node)); err = create_dev(&oid, dev->path); if (err != 0) {