Jelajahi Sumber

init ohci for ehci

sakumisu 1 tahun lalu
induk
melakukan
808cd454a3

+ 4 - 1
SConscript

@@ -130,8 +130,11 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
         src += Glob('port/ehci/usb_hc_ehci.c')
         src += Glob('port/ehci/usb_glue_hpm.c')
     if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_AIC']):
+        path += [cwd + '/port/ehci']
+        path += [cwd + '/port/ohci']
         src += Glob('port/ehci/usb_hc_ehci.c')
         src += Glob('port/ehci/usb_glue_aic.c')
+        src += Glob('port/ohci/usb_hc_ohci.c')
     if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980']):
         src += Glob('port/ehci/usb_hc_ehci.c')
         src += Glob('port/ehci/usb_glue_nuc980.c')
@@ -198,7 +201,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
         src += Glob('demo/usb_host.c')
     
     if GetDepend('RT_USING_DFS'):
-        src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c')
+       src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c')
 
 group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
 

+ 1 - 2
cherryusb_config_template.h

@@ -160,10 +160,9 @@
 
 #define CONFIG_USB_EHCI_HCCR_OFFSET     (0x0)
 #define CONFIG_USB_EHCI_HCOR_OFFSET     (0x10)
+#define CONFIG_USB_OHCI_HCOR_OFFSET     (0x400)
 #define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
 // #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
 // #define CONFIG_USB_EHCI_CONFIGFLAG
-// #define CONFIG_USB_EHCI_PORT_POWER
-// #define CONFIG_USB_EHCI_PRINT_HW_PARAM
 
 #endif

+ 11 - 0
port/ehci/usb_ehci_priv.h

@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 #ifndef _USB_EHCI_PRIV_H
 #define _USB_EHCI_PRIV_H
 
@@ -47,6 +52,12 @@ struct ehci_itd_hw {
 struct ehci_hcd {
     bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM];
     bool ehci_itd_used[CONFIG_USB_EHCI_ITD_NUM];
+    bool ppc; /* Port Power Control */
+    bool has_tt;   /* if use tt instead of Companion Controller */
+    uint8_t n_cc;  /* Number of Companion Controller */
+    uint8_t n_pcc; /* Number of ports supported per companion host controller */
+    uint8_t n_ports;
+    uint8_t hccr_offset;
 };
 
 extern struct ehci_hcd g_ehci_hcd[CONFIG_USBHOST_MAX_BUS];

+ 9 - 1
port/ehci/usb_glue_aic.c

@@ -19,6 +19,13 @@ static void aic_ehci_isr(int vector, void *arg)
     USBH_IRQHandler(bus->hcd.hcd_id);
 }
 
+static void aic_ohci_isr(int vector, void *arg)
+{
+    struct usbh_bus *bus = (struct usbh_bus *)arg;
+    extern void OHCI_IRQHandler(uint8_t busid);
+    OHCI_IRQHandler(bus->hcd.hcd_id);
+}
+
 typedef struct aic_ehci_config {
     uint32_t base_addr;
     uint32_t clk_id;
@@ -107,6 +114,8 @@ void usb_hc_low_level_init(struct usbh_bus *bus)
     /* register interrupt callback */
     aicos_request_irq(config[i].irq_num, (irq_handler_t)aic_ehci_isr,
                       0, "usb_host_ehci", bus);
+    aicos_request_irq(config[i].irq_num + 1, (irq_handler_t)aic_ohci_isr,
+                      0, "usb_host_ohci", bus);
     aicos_irq_enable(config[i].irq_num);
 }
 
@@ -155,7 +164,6 @@ int usbh_init(void)
     usbh_initialize(bus_id, USB_HOST1_BASE);
     bus_id++;
 #endif
-
     return 0;
 }
 

+ 101 - 23
port/ehci/usb_hc_ehci.c

@@ -4,6 +4,9 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 #include "usb_ehci_priv.h"
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+#include "usb_ohci_priv.h"
+#endif
 
 #define EHCI_TUNE_CERR    3 /* 0-3 qtd retries; 0 == don't stop */
 #define EHCI_TUNE_RL_HS   4 /* nak throttle; see 4.9 */
@@ -770,11 +773,24 @@ int usb_hc_init(struct usbh_bus *bus)
 
     EHCI_HCOR->usbintr = 0;
     EHCI_HCOR->usbsts = EHCI_HCOR->usbsts;
-#ifdef CONFIG_USB_EHCI_PRINT_HW_PARAM
-    USB_LOG_INFO("EHCI HCIVERSION:%04x\r\n", (int)EHCI_HCCR->hciversion);
-    USB_LOG_INFO("EHCI HCSPARAMS:%06x\r\n", (int)EHCI_HCCR->hcsparams);
-    USB_LOG_INFO("EHCI HCCPARAMS:%04x\r\n", (int)EHCI_HCCR->hccparams);
-#endif
+
+    USB_LOG_INFO("EHCI HCIVERSION:0x%04x\r\n", (unsigned int)EHCI_HCCR->hciversion);
+    USB_LOG_INFO("EHCI HCSPARAMS:0x%06x\r\n", (unsigned int)EHCI_HCCR->hcsparams);
+    USB_LOG_INFO("EHCI HCCPARAMS:0x%04x\r\n", (unsigned int)EHCI_HCCR->hccparams);
+
+    g_ehci_hcd[bus->hcd.hcd_id].ppc = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_PPC) ? true : false;
+    g_ehci_hcd[bus->hcd.hcd_id].n_ports = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT;
+    g_ehci_hcd[bus->hcd.hcd_id].n_cc = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_NCC_MASK) >> EHCI_HCSPARAMS_NCC_SHIFT;
+    g_ehci_hcd[bus->hcd.hcd_id].n_pcc = (EHCI_HCCR->hcsparams & EHCI_HCSPARAMS_NPCC_MASK) >> EHCI_HCSPARAMS_NPCC_SHIFT;
+    g_ehci_hcd[bus->hcd.hcd_id].has_tt = g_ehci_hcd[bus->hcd.hcd_id].n_cc ? false : true;
+    g_ehci_hcd[bus->hcd.hcd_id].hccr_offset = EHCI_HCCR->caplength;
+
+    USB_LOG_INFO("EHCI ppc:%u, n_ports:%u, n_cc:%u, n_pcc:%u\r\n",
+                 g_ehci_hcd[bus->hcd.hcd_id].ppc,
+                 g_ehci_hcd[bus->hcd.hcd_id].n_ports,
+                 g_ehci_hcd[bus->hcd.hcd_id].n_cc,
+                 g_ehci_hcd[bus->hcd.hcd_id].n_pcc);
+
     /* Set the Current Asynchronous List Address. */
     EHCI_HCOR->asynclistaddr = EHCI_PTR2ADDR(&g_async_qh_head[bus->hcd.hcd_id]);
     /* Set the Periodic Frame List Base Address. */
@@ -809,13 +825,32 @@ int usb_hc_init(struct usbh_bus *bus)
             return -USB_ERR_TIMEOUT;
         }
     }
-#ifdef CONFIG_USB_EHCI_PORT_POWER
-    for (uint8_t port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) {
-        regval = EHCI_HCOR->portsc[port];
-        regval |= EHCI_PORTSC_PP;
-        EHCI_HCOR->portsc[port] = regval;
+
+    if (g_ehci_hcd[bus->hcd.hcd_id].ppc) {
+        for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_ports; port++) {
+            regval = EHCI_HCOR->portsc[port];
+            regval |= EHCI_PORTSC_PP;
+            EHCI_HCOR->portsc[port] = regval;
+        }
     }
+
+    if (g_ehci_hcd[bus->hcd.hcd_id].has_tt) {
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+        USB_LOG_INFO("EHCI uses tt for ls/fs device, so cannot enable this macro\r\n");
+        return -USB_ERR_INVAL;
 #endif
+    }
+
+    if (g_ehci_hcd[bus->hcd.hcd_id].has_tt) {
+        USB_LOG_INFO("EHCI uses tt for ls/fs device\r\n");
+    } else {
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+        USB_LOG_INFO("EHCI uses companion controller for ls/fs device\r\n");
+        ohci_init(bus);
+#else
+        USB_LOG_WRN("Do not enable companion controller, you should use a hub to support ls/fs device\r\n");
+#endif
+    }
 
     /* Enable EHCI interrupts. */
     EHCI_HCOR->usbintr = EHCI_USBIE_INT | EHCI_USBIE_ERR | EHCI_USBIE_PCD | EHCI_USBIE_FATAL | EHCI_USBIE_IAA;
@@ -845,13 +880,13 @@ int usb_hc_deinit(struct usbh_bus *bus)
         }
     }
 
-#ifdef CONFIG_USB_EHCI_PORT_POWER
-    for (uint8_t port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) {
-        regval = EHCI_HCOR->portsc[port];
-        regval &= ~EHCI_PORTSC_PP;
-        EHCI_HCOR->portsc[port] = regval;
+    if (g_ehci_hcd[bus->hcd.hcd_id].ppc) {
+        for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_ports; port++) {
+            regval = EHCI_HCOR->portsc[port];
+            regval &= ~EHCI_PORTSC_PP;
+            EHCI_HCOR->portsc[port] = regval;
+        }
     }
-#endif
 
 #ifdef CONFIG_USB_EHCI_CONFIGFLAG
     EHCI_HCOR->configflag = 0;
@@ -864,12 +899,22 @@ int usb_hc_deinit(struct usbh_bus *bus)
         usb_osal_sem_delete(qh->waitsem);
     }
 
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+    ohci_deinit(bus);
+#endif
+
     usb_hc_low_level_deinit(bus);
     return 0;
 }
 
 uint16_t usbh_get_frame_number(struct usbh_bus *bus)
 {
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+    if (EHCI_HCOR->portsc[0] & EHCI_PORTSC_OWNER) {
+        return ohci_get_frame_number(bus);
+    }
+#endif
+
     return (((EHCI_HCOR->frindex & EHCI_FRINDEX_MASK) >> 3) & 0x3ff);
 }
 
@@ -879,9 +924,25 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u
     uint8_t port;
     uint32_t temp, status;
 
-    nports = CONFIG_USBHOST_MAX_RHPORTS;
+    nports = g_ehci_hcd[bus->hcd.hcd_id].n_ports;
 
     port = setup->wIndex;
+
+    temp = EHCI_HCOR->portsc[port - 1];
+
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+    if (temp & EHCI_PORTSC_OWNER) {
+        return ohci_roothub_control(bus, setup, buf);
+    }
+
+    if ((temp & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE) {
+        EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_OWNER;
+
+        while (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_OWNER)) {
+        }
+        return ohci_roothub_control(bus, setup, buf);
+    }
+#endif
     if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
         switch (setup->bRequest) {
             case HUB_REQUEST_CLEAR_FEATURE:
@@ -942,9 +1003,7 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u
                     case HUB_PORT_FEATURE_C_SUSPEND:
                         break;
                     case HUB_PORT_FEATURE_POWER:
-#ifdef CONFIG_USB_EHCI_PORT_POWER
                         EHCI_HCOR->portsc[port - 1] &= ~EHCI_PORTSC_PP;
-#endif
                         break;
                     case HUB_PORT_FEATURE_C_CONNECTION:
                         EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_CSC;
@@ -982,12 +1041,19 @@ int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, u
                         }
                         break;
                     case HUB_PORT_FEATURE_POWER:
-#ifdef CONFIG_USB_EHCI_PORT_POWER
                         EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_PP;
-#endif
                         break;
                     case HUB_PORT_FEATURE_RESET:
                         usbh_reset_port(bus, port);
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+                        if (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_PE)) {
+                            EHCI_HCOR->portsc[port - 1] |= EHCI_PORTSC_OWNER;
+
+                            while (!(EHCI_HCOR->portsc[port - 1] & EHCI_PORTSC_OWNER)) {
+                            }
+                            return ohci_roothub_control(bus, setup, buf);
+                        }
+#endif
                         break;
 
                     default:
@@ -1067,6 +1133,12 @@ int usbh_submit_urb(struct usbh_urb *urb)
         hub = hub->parent->parent;
     }
 
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+    if (EHCI_HCOR->portsc[hport->port - 1] & EHCI_PORTSC_OWNER) {
+        return ohci_submit_urb(urb);
+    }
+#endif
+
     if (!urb->hport->connected || !(EHCI_HCOR->portsc[hport->port - 1] & EHCI_PORTSC_CCS)) {
         return -USB_ERR_NOTCONN;
     }
@@ -1138,12 +1210,18 @@ int usbh_kill_urb(struct usbh_urb *urb)
     struct usbh_bus *bus;
     size_t flags;
 
-    if (!urb || !urb->hcpriv || !urb->hport->bus) {
+    if (!urb || !urb->hport || !urb->hcpriv || !urb->hport->bus) {
         return -USB_ERR_INVAL;
     }
 
     bus = urb->hport->bus;
 
+#ifdef CONFIG_USB_EHCI_WITH_OHCI
+    if (EHCI_HCOR->portsc[urb->hport->port - 1] & EHCI_PORTSC_OWNER) {
+        return ohci_kill_urb(urb);
+    }
+#endif
+
     flags = usb_osal_enter_critical_section();
 
     EHCI_HCOR->usbcmd &= ~(EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
@@ -1245,7 +1323,7 @@ void USBH_IRQHandler(uint8_t busid)
     }
 
     if (usbsts & EHCI_USBSTS_PCD) {
-        for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) {
+        for (int port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_ports; port++) {
             uint32_t portsc = EHCI_HCOR->portsc[port];
 
             if (portsc & EHCI_PORTSC_CSC) {

+ 17 - 17
port/ehci/usb_hc_ehci.h

@@ -281,12 +281,12 @@
  */
 
 struct ehci_hccr {
-    uint8_t caplength;        /* 0x00: Capability Register Length */
-    uint8_t reserved;         /* 0x01: reserved */
-    uint16_t hciversion;      /* 0x02: Interface Version Number */
-    uint32_t hcsparams;       /* 0x04: Structural Parameters */
-    uint32_t hccparams;       /* 0x08: Capability Parameters */
-    uint8_t hcspportroute[8]; /* 0x0c: Companion Port Route Description */
+    volatile uint8_t caplength;        /* 0x00: Capability Register Length */
+    volatile uint8_t reserved;         /* 0x01: reserved */
+    volatile uint16_t hciversion;      /* 0x02: Interface Version Number */
+    volatile uint32_t hcsparams;       /* 0x04: Structural Parameters */
+    volatile uint32_t hccparams;       /* 0x08: Capability Parameters */
+    volatile uint8_t hcspportroute[8]; /* 0x0c: Companion Port Route Description */
 };
 
 /* Host Controller Operational Registers.
@@ -295,18 +295,18 @@ struct ehci_hccr {
  */
 
 struct ehci_hcor {
-    uint32_t usbcmd;           /* 0x00: USB Command */
-    uint32_t usbsts;           /* 0x04: USB Status */
-    uint32_t usbintr;          /* 0x08: USB Interrupt Enable */
-    uint32_t frindex;          /* 0x0c: USB Frame Index */
-    uint32_t ctrldssegment;    /* 0x10: 4G Segment Selector */
-    uint32_t periodiclistbase; /* 0x14: Frame List Base Address */
-    uint32_t asynclistaddr;    /* 0x18: Next Asynchronous List Address */
+    volatile uint32_t usbcmd;           /* 0x00: USB Command */
+    volatile uint32_t usbsts;           /* 0x04: USB Status */
+    volatile uint32_t usbintr;          /* 0x08: USB Interrupt Enable */
+    volatile uint32_t frindex;          /* 0x0c: USB Frame Index */
+    volatile uint32_t ctrldssegment;    /* 0x10: 4G Segment Selector */
+    volatile uint32_t periodiclistbase; /* 0x14: Frame List Base Address */
+    volatile uint32_t asynclistaddr;    /* 0x18: Next Asynchronous List Address */
 #ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
     uint32_t reserved[9];
 #endif
-    uint32_t configflag; /* 0x40: Configured Flag Register */
-    uint32_t portsc[15]; /* 0x44: Port Status/Control */
+    volatile uint32_t configflag; /* 0x40: Configured Flag Register */
+    volatile uint32_t portsc[15]; /* 0x44: Port Status/Control */
 };
 
 /* USB2 Debug Port Register Interface.
@@ -357,7 +357,7 @@ struct ehci_itd {
     uint32_t bpl[7];  /* 0x24-0x3c: Buffer Page Pointer List */
 };
 
-#define SIZEOF_EHCI_ITD_S (64) /* 16*sizeof(uint32_t) */
+#define SIZEOF_EHCI_ITD (64) /* 16*sizeof(uint32_t) */
 
 /* Split Transaction Isochronous Transfer Descriptor (siTD). Paragraph 3.4 */
 
@@ -370,6 +370,6 @@ struct ehci_sitd {
     uint32_t blp;    /* 0x18-0x1b: Back link pointer */
 };
 
-#define SIZEOF_EHCI_SITD_S (28) /* 7*sizeof(uint32_t) */
+#define SIZEOF_EHCI_SITD (28) /* 7*sizeof(uint32_t) */
 
 #endif /* USB_HC_EHCI_H */

+ 18 - 0
port/ohci/README.md

@@ -0,0 +1,18 @@
+# Note
+
+This OHCI is a companion controller of EHCI.
+
+## Support Chip List
+
+### AllwinnerTech
+
+- F133
+
+### Nuvoton
+
+- Nuvoton all series
+
+### Artinchip
+
+- d13x, d21x
+

+ 240 - 0
port/ohci/usb_hc_ohci.c

@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usb_ohci_priv.h"
+#include "usb_ehci_priv.h"
+
+int ohci_init(struct usbh_bus *bus)
+{
+    volatile uint32_t timeout = 0;
+    uint32_t regval;
+
+    USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision);
+
+    OHCI_HCOR->hccontrol = 0;
+    OHCI_HCOR->hccontrolheaded = 0;
+    OHCI_HCOR->hcbulkheaded = 0;
+
+    OHCI_HCOR->hccmdsts = OHCI_CMDST_HCR;
+    while (OHCI_HCOR->hccmdsts & OHCI_CMDST_HCR) {
+        usb_osal_msleep(1);
+        timeout++;
+        if (timeout > 100) {
+            return -USB_ERR_TIMEOUT;
+        }
+    }
+
+    /* Frame Interval / Periodic Start.
+    *
+    * At 12Mbps, there are 12000 bit time in each 1Msec frame.
+    */
+
+#define BITS_PER_FRAME     12000
+#define FI                 (BITS_PER_FRAME - 1)
+#define FSMPS              ((6 * (FI - 210)) / 7)
+#define DEFAULT_FMINTERVAL ((FSMPS << OHCI_FMINT_FSMPS_SHIFT) | FI)
+#define DEFAULT_PERSTART   (((9 * BITS_PER_FRAME) / 10) - 1)
+
+    OHCI_HCOR->hcfminterval = DEFAULT_FMINTERVAL;
+    OHCI_HCOR->hcperiodicstart = DEFAULT_PERSTART;
+
+    /* Put HC in operational state */
+    regval = OHCI_HCOR->hccontrol;
+    regval &= ~OHCI_CTRL_HCFS_MASK;
+    regval |= OHCI_CTRL_HCFS_OPER;
+    OHCI_HCOR->hccontrol = regval;
+
+    /* Set global power in HcRhStatus */
+    OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP;
+
+    /* Set HCCA base address */
+    OHCI_HCOR->hchcca = 0;
+
+    /* Clear pending interrupts */
+    regval = OHCI_HCOR->hcintsts;
+    OHCI_HCOR->hcintsts = regval;
+
+    for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_pcc; port++) {
+        regval = OHCI_HCOR->hcrhportsts[port];
+        regval |= OHCI_RHPORTST_PPS;
+        OHCI_HCOR->hcrhportsts[port] = regval;
+    }
+
+    /* Enable OHCI interrupts */
+    OHCI_HCOR->hcinten = OHCI_INT_SO | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_OC |
+                         OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
+
+    return 0;
+}
+
+int ohci_deinit(struct usbh_bus *bus)
+{
+    uint32_t regval;
+
+    /* Disable OHCI interrupts */
+    OHCI_HCOR->hcintdis = OHCI_INT_SO | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_OC |
+                          OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
+
+    for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_pcc; port++) {
+        regval = OHCI_HCOR->hcrhportsts[port];
+        regval &= ~OHCI_RHPORTST_PPS;
+        OHCI_HCOR->hcrhportsts[port] = regval;
+    }
+
+    return 0;
+}
+
+uint16_t ohci_get_frame_number(struct usbh_bus *bus)
+{
+    return OHCI_HCOR->hcfmnumber;
+}
+
+int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
+{
+    uint8_t nports;
+    uint8_t port;
+    uint32_t temp;
+
+    nports = g_ehci_hcd[bus->hcd.hcd_id].n_pcc;
+
+    port = setup->wIndex;
+    if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
+        switch (setup->bRequest) {
+            case HUB_REQUEST_CLEAR_FEATURE:
+                switch (setup->wValue) {
+                    case HUB_FEATURE_HUB_C_LOCALPOWER:
+                        break;
+                    case HUB_FEATURE_HUB_C_OVERCURRENT:
+                        break;
+                    default:
+                        return -USB_ERR_NOTSUPP;
+                }
+                break;
+            case HUB_REQUEST_SET_FEATURE:
+                switch (setup->wValue) {
+                    case HUB_FEATURE_HUB_C_LOCALPOWER:
+                        break;
+                    case HUB_FEATURE_HUB_C_OVERCURRENT:
+                        break;
+                    default:
+                        return -USB_ERR_NOTSUPP;
+                }
+                break;
+            case HUB_REQUEST_GET_DESCRIPTOR:
+                break;
+            case HUB_REQUEST_GET_STATUS:
+                memset(buf, 0, 4);
+                break;
+            default:
+                break;
+        }
+    } else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) {
+        switch (setup->bRequest) {
+            case HUB_REQUEST_CLEAR_FEATURE:
+                if (!port || port > nports) {
+                    return -USB_ERR_INVAL;
+                }
+
+                switch (setup->wValue) {
+                    case HUB_PORT_FEATURE_ENABLE:
+                        break;
+                    case HUB_PORT_FEATURE_SUSPEND:
+
+                    case HUB_PORT_FEATURE_C_SUSPEND:
+                        break;
+                    case HUB_PORT_FEATURE_POWER:
+                        break;
+                    case HUB_PORT_FEATURE_C_CONNECTION:
+                        OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_CSC;
+                        break;
+                    case HUB_PORT_FEATURE_C_ENABLE:
+                        OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PESC;
+                        break;
+                    case HUB_PORT_FEATURE_C_OVER_CURREN:
+                        OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_OCIC;
+                        break;
+                    case HUB_PORT_FEATURE_C_RESET:
+                        OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRSC;
+                        break;
+                    default:
+                        return -USB_ERR_NOTSUPP;
+                }
+                break;
+            case HUB_REQUEST_SET_FEATURE:
+                if (!port || port > nports) {
+                    return -USB_ERR_INVAL;
+                }
+
+                switch (setup->wValue) {
+                    case HUB_PORT_FEATURE_SUSPEND:
+                        break;
+                    case HUB_PORT_FEATURE_POWER:
+                        break;
+                    case HUB_PORT_FEATURE_RESET:
+                        OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRS;
+
+                        while (OHCI_HCOR->hcrhportsts[port - 1] & OHCI_RHPORTST_PRS) {
+                        }
+                        break;
+
+                    default:
+                        return -USB_ERR_NOTSUPP;
+                }
+                break;
+            case HUB_REQUEST_GET_STATUS:
+                if (!port || port > nports) {
+                    return -USB_ERR_INVAL;
+                }
+                temp = OHCI_HCOR->hcrhportsts[port - 1];
+
+                memcpy(buf, &temp, 4);
+                break;
+            default:
+                break;
+        }
+    }
+    return 0;
+}
+
+int ohci_submit_urb(struct usbh_urb *urb)
+{
+    return -USB_ERR_NOTSUPP;
+}
+
+int ohci_kill_urb(struct usbh_urb *urb)
+{
+    return -USB_ERR_NOTSUPP;
+}
+
+void OHCI_IRQHandler(uint8_t busid)
+{
+    uint32_t usbsts;
+    struct usbh_bus *bus;
+
+    bus = &g_usbhost_bus[busid];
+
+    usbsts = OHCI_HCOR->hcintsts & OHCI_HCOR->hcinten;
+    OHCI_HCOR->hcintsts = usbsts;
+
+    if (usbsts & OHCI_INT_RHSC) {
+        for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) {
+            uint32_t portsc = OHCI_HCOR->hcrhportsts[port];
+
+            if (portsc & OHCI_RHPORTST_CSC) {
+                if (OHCI_HCOR->hcrhsts & OHCI_RHSTATUS_DRWE) {
+                    /* If DRWE is set, Connect Status Change indicates a remote wake-up event */
+                } else {
+                    if (portsc & OHCI_RHPORTST_CCS) {
+                    } else {
+                    }
+                    bus->hcd.roothub.int_buffer[0] |= (1 << (port + 1));
+                    usbh_hub_thread_wakeup(&bus->hcd.roothub);
+                }
+            }
+        }
+    }
+    if (usbsts & OHCI_INT_WDH) {
+    }
+}

+ 484 - 0
port/ohci/usb_hc_ohci.h

@@ -0,0 +1,484 @@
+/****************************************************************************
+ * include/nuttx/usb/ohci.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_USB_OHCI_H
+#define __INCLUDE_NUTTX_USB_OHCI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+/* Control and status registers (section 7.1) */
+
+#define OHCI_HCIREV_OFFSET          0x0000 /* HcRevision: Version of HCI specification */
+#define OHCI_CTRL_OFFSET            0x0004 /* HcControl: HC control */
+#define OHCI_CMDST_OFFSET           0x0008 /* HcCommandStatus: HC command status */
+#define OHCI_INTST_OFFSET           0x000c /* HcInterruptStatus: HC interrupt status */
+#define OHCI_INTEN_OFFSET           0x0010 /* HcInterruptEnable: HC interrupt enable */
+#define OHCI_INTDIS_OFFSET          0x0014 /* HcInterruptDisable: HC interrupt disable */
+
+/* Memory pointer registers (section 7.2) */
+
+#define OHCI_HCCA_OFFSET            0x0018 /* HcHCCA: HC communication area */
+#define OHCI_PERED_OFFSET           0x001c /* HcPeriodCurrentED: Current isoc or int endpoint desc */
+#define OHCI_CTRLHEADED_OFFSET      0x0020 /* HcControlHeadED: First EP desc in the control list */
+#define OHCI_CTRLED_OFFSET          0x0024 /* HcControlCurrentED: Current EP desc in the control list */
+#define OHCI_BULKHEADED_OFFSET      0x0028 /* HcBulkHeadED: First EP desc in the bulk list */
+#define OHCI_BULKED_OFFSET          0x002c /* HcBulkCurrentED: Current EP desc in the bulk list */
+#define OHCI_DONEHEAD_OFFSET        0x0030 /* HcDoneHead: Last transfer desc added to DONE queue */
+
+/* Frame counter registers (section 7.3) */
+
+#define OHCI_FMINT_OFFSET           0x0034 /* HcFmInterval: Bit time interval that would not cause overrun */
+#define OHCI_FMREM_OFFSET           0x0038 /* HcFmRemaining: Bit time remaining in current frame */
+#define OHCI_FMNO_OFFSET            0x003c /* HcFmNumber: Frame number counter */
+#define OHCI_PERSTART_OFFSET        0x0040 /* HcPeriodicStart: Time to start processing periodic list */
+
+/* Root hub registers (section 7.4) */
+
+#define OHCI_LSTHRES_OFFSET         0x0044 /* HcLSThreshold: Commit to transfer threshold */
+#define OHCI_RHDESCA_OFFSET         0x0048 /* HcRhDescriptorA: Describes root hub (part A) */
+#define OHCI_RHDESCB_OFFSET         0x004c /* HcRhDescriptorB: Describes root hub (part B) */
+#define OHCI_RHSTATUS_OFFSET        0x0050 /* HcRhStatus: Root hub status */
+
+#define OHCI_MAX_RHPORT             15     /* Maximum number of OHCI root hub ports */
+
+#define OHCI_RHPORTST_OFFSET(n)     (0x0054 + (((n) - 1) << 2))
+#define OHCI_RHPORTST1_OFFSET       0x0054 /* HcRhPort1Status:  Root hub port status 1 */
+#define OHCI_RHPORTST2_OFFSET       0x0058 /* HcRhPort2Status:  Root hub port status 2 */
+#define OHCI_RHPORTST3_OFFSET       0x005c /* HcRhPort3Status:  Root hub port status 3 */
+#define OHCI_RHPORTST4_OFFSET       0x0060 /* HcRhPort4Status:  Root hub port status 4 */
+#define OHCI_RHPORTST5_OFFSET       0x0064 /* HcRhPort5Status:  Root hub port status 5 */
+#define OHCI_RHPORTST6_OFFSET       0x0068 /* HcRhPort6Status:  Root hub port status 6 */
+#define OHCI_RHPORTST7_OFFSET       0x006c /* HcRhPort7Status:  Root hub port status 7 */
+#define OHCI_RHPORTST8_OFFSET       0x0070 /* HcRhPort8Status:  Root hub port status 8 */
+#define OHCI_RHPORTST9_OFFSET       0x0074 /* HcRhPort9Status:  Root hub port status 9 */
+#define OHCI_RHPORTST10_OFFSET      0x0078 /* HcRhPort10Status: Root hub port status 10 */
+#define OHCI_RHPORTST11_OFFSET      0x007c /* HcRhPort11Status: Root hub port status 11 */
+#define OHCI_RHPORTST12_OFFSET      0x0080 /* HcRhPort12Status: Root hub port status 12 */
+#define OHCI_RHPORTST13_OFFSET      0x0084 /* HcRhPort13Status: Root hub port status 13 */
+#define OHCI_RHPORTST14_OFFSET      0x0088 /* HcRhPort14Status: Root hub port status 14 */
+#define OHCI_RHPORTST15_OFFSET      0x008c /* HcRhPort15Status: Root hub port status 15 */
+
+/* Register bit definitions *************************************************/
+
+/* HcRevision: Version of HCI specification (7.1.1) */
+
+#define OHCI_HCIREV_SHIFT           (0)       /* Bits 0-7: HCI spec version (BCD) */
+#define OHCI_HCIREV_MASK            (0xff << OHCI_HCIREV_SHIFT)
+
+/* HcControl: HC control (7.1.2) */
+
+#define OHCI_CTRL_CBSR              (3 << 0)  /* Bit 0:  Control/bulk service ratio */
+#define OHCI_CTRL_PLE               (1 << 2)  /* Bit 1:  Periodic list enable */
+#define OHCI_CTRL_IE                (1 << 3)  /* Bit 2:  Isochronous enable */
+#define OHCI_CTRL_CLE               (1 << 4)  /* Bit 3:  Control list enable */
+#define OHCI_CTRL_BLE               (1 << 5)  /* Bit 4:  Bulk list enable */
+#define OHCI_CTRL_HCFS_SHIFT        (6)       /* Bits 6-7: Host controller functional state */
+#define OHCI_CTRL_HCFS_MASK         (3 << OHCI_CTRL_HCFS_SHIFT)
+#  define OHCI_CTRL_HCFS_RESET      (0 << OHCI_CTRL_HCFS_SHIFT)
+#  define OHCI_CTRL_HCFS_RESUME     (1 << OHCI_CTRL_HCFS_SHIFT)
+#  define OHCI_CTRL_HCFS_OPER       (2 << OHCI_CTRL_HCFS_SHIFT)
+#  define OHCI_CTRL_HCFS_SUSPEND    (3 << OHCI_CTRL_HCFS_SHIFT)
+#define OHCI_CTRL_IR                (1 << 8)  /* Bit 8:  Interrupt routing */
+#define OHCI_CTRL_RWC               (1 << 9)  /* Bit 9:  Remote wakeup connected */
+#define OHCI_CTRL_RWE               (1 << 10) /* Bit 10: Remote wakeup enable */
+                                              /* Bits 11-31: Reserved */
+
+/* HcCommandStatus: HC command status (7.1.3) */
+
+#define OHCI_CMDST_HCR              (1 << 0)  /* Bit 0:  Host controller reset */
+#define OHCI_CMDST_CLF              (1 << 1)  /* Bit 1:  Control list filled */
+#define OHCI_CMDST_BLF              (1 << 2)  /* Bit 2:  Bulk list filled */
+#define OHCI_CMDST_OCR              (1 << 3)  /* Bit 3:  Ownership change request */
+                                              /* Bits 4-15: Reserved */
+#define OHCI_CMDST_SOC              (3 << 16) /* Bit 16: Scheduling overrun count */
+                                              /* Bits 17-31: Reserved */
+
+/* HcInterruptStatus: HC interrupt status (7.1.4),
+ * HcInterruptEnable: HC interrupt enable (7.1.5), and
+ * HcInterruptDisable: HC interrupt disable (7.1.6)
+ */
+
+#define OHCI_INT_SO                 (1 << 0)  /* Bit 0:  Scheduling overrun */
+#define OHCI_INT_WDH                (1 << 1)  /* Bit 1:  Writeback done head */
+#define OHCI_INT_SF                 (1 << 2)  /* Bit 2:  Start of frame */
+#define OHCI_INT_RD                 (1 << 3)  /* Bit 3:  Resume detected */
+#define OHCI_INT_UE                 (1 << 4)  /* Bit 4:  Unrecoverable error */
+#define OHCI_INT_FNO                (1 << 5)  /* Bit 5:  Frame number overflow */
+#define OHCI_INT_RHSC               (1 << 6)  /* Bit 6:  Root hub status change */
+                                              /* Bits 7-29: Reserved */
+#define OHCI_INT_OC                 (1 << 30) /* Bit 30: Ownership change */
+#define OHCI_INT_MIE                (1 << 31) /* Bit 31: Master interrupt enable
+                                               *         (Enable/disable only) */
+
+/* HcHCCA: HC communication area (7.2.1):
+ *
+ * 32-bits aligned to 256 byte boundary.
+ */
+
+/* HcPeriodCurrentED: Current isoc or int endpoint desc (7.2.2),
+ * HcControlHeadED: First EP desc in the control list (7.2.3),
+ * HcControlCurrentED: Current EP desc in the control list (7.2.4),
+ * HcBulkHeadED: First EP desc in the bulk list (7.2.5),
+ * HcBulkCurrentED: Current EP desc in the bulk list (7.2.6), and
+ * HcDoneHead: Last transfer desc added to DONE queue (7.2.7):
+ *
+ * All 32-bits aligned to an 8-byte boundary
+ */
+
+/* HcFmInterval: Bit time interval that would not cause overrun (7.3.1) */
+
+#define OHCI_FMINT_FI_SHIFT         (0)       /* Bits 0-13: Frame interval */
+#define OHCI_FMINT_FI_MASK          (0x3fff << OHCI_FMINT_FI_SHIFT)
+                                              /* Bits 14-15: Reserved */
+#define OHCI_FMINT_FSMPS_SHIFT      (16)      /* Bits 16-30: FS largest packet data */
+#define OHCI_FMINT_FSMPS_MASK       (0x7fff << OHCI_FMINT_FSMPS_SHIFT)
+#define OHCI_FMINT_FIT              (1 << 31) /* Bit 31: Frame interval toggle */
+
+/* HcFmRemaining: Bit time remaining in current frame (7.3.2) */
+
+#define OHCI_FMREM_FR_SHIFT         (0)       /* Bits 0-13: Frame remaining */
+#define OHCI_FMREM_FR_MASK          (0x3fff << OHCI_FMREM_FR_SHIFT)
+                                              /* Bits 16-30: Reserved */
+#define OHCI_FMINT_FRT              (1 << 31) /* Bit 31: Frame remaining toggle */
+
+/* HcFmNumber: Frame number counter (7.3.3) */
+
+#define OHCI_FMNO_FI_SHIFT          (0)       /* Bits 0-15: Frame number */
+#define OHCI_FMNO_FI_MASK           (0xffff << OHCI_FMINT_FI_SHIFT)
+                                              /* Bits 16-31: Reserved */
+
+/* HcPeriodicStart: Time to start processing periodic list (7.3.4) */
+
+#define OHCI_PERSTART_SHIFT         (0)       /* Bits 0-13: Periodic start */
+#define OHCI_PERSTART_MASK          (0x3fff << OHCI_PERSTART_SHIFT)
+                                              /* Bits 14-31: Reserved */
+
+/* HcLSThreshold: Commit to transfer threshold (7.3.5) */
+
+#define OHCI_LSTHRES_SHIFT          (0)       /* Bits 0-11: LS threshold */
+#define OHCI_LSTHRES_MASK           (0x0fff << OHCI_PERSTART_SHIFT)
+                                              /* Bits 12-31: Reserved */
+
+/* HcRhDescriptorN: Describes root hub (part A) (7.4.1) */
+
+#define OHCI_RHDESCA_NDP_SHIFT      (0)       /* Bits 0-7: Number downstream ports */
+#define OHCI_RHDESCA_NDP_MASK       (0xff << OHCI_RHDESCA_NDP_SHIFT)
+#define OHCI_RHDESCA_PSM            (1 << 8)  /* Bit 8:  Power switching mode */
+#define OHCI_RHDESCA_NPS            (1 << 9)  /* Bit 9:  No power switching */
+#define OHCI_RHDESCA_DT             (1 << 10) /* Bit 10: Device type */
+#define OHCI_RHDESCA_OCPM           (1 << 11) /* Bit 11: Over current protection mode */
+#define OHCI_RHDESCA_NOCP           (1 << 12) /* Bit 12: No over current protection */
+                                              /* Bits 13-23: Reserved */
+#define OHCI_RHDESCA_POTPGT_SHIFT   (24)      /* Bits 24-31: Power on to power good time */
+#define OHCI_RHDESCA_POTPGT_MASK    (0xff << OHCI_RHDESCA_POTPGT_SHIFT)
+
+/* HcRhDescriptorB: Describes root hub (part B) (7.4.2) */
+
+#define OHCI_RHDESCB_DR_SHIFT      (0)        /* Bits 0-15: Device removable */
+#define OHCI_RHDESCB_DR_MASK       (0xffff << OHCI_RHDESCB_DR_SHIFT)
+#  define OHCI_RHDESCB_ATTACHED(n) (1 << (OHCI_RHDESCB_DR_SHIFT+(n)))
+#define OHCI_RHDESCB_PPCM_SHIFT    (16)       /* Bits 16-31: Port power control mask */
+#define OHCI_RHDESCB_PPCM_MASK     (0xffff << OHCI_RHDESCB_PPCM_SHIFT)
+#  define OHCI_RHDESCB_POWERED(n)  (1 << (OHCI_RHDESCB_DR_SHIFT+(n)))
+
+/* HcRhStatus: Root hub status (7.4.3) */
+
+#define OHCI_RHSTATUS_LPS          (1 << 0)   /* Bit 0:  Local power status (read)*/
+#define OHCI_RHSTATUS_CGP          (1 << 0)   /* Bit 0:  Clear global power (write)*/
+#define OHCI_RHSTATUS_OCI          (1 << 1)   /* Bit 1:  Over current indicator */
+                                              /* Bits 2-14: Reserved */
+#define OHCI_RHSTATUS_DRWE         (1 << 15)  /* Bit 15: Device remote wakeup enable */
+#define OHCI_RHSTATUS_LPSC         (1 << 16)  /* Bit 16: Local power status change (read) */
+#define OHCI_RHSTATUS_SGP          (1 << 16)  /* Bit 16: Set global power (write) */
+#define OHCI_RHSTATUS_OCIC         (1 << 17)  /* Bit 17: Overcurrent indicator change */
+                                              /* Bits 18-30: Reserved */
+#define OHCI_RHSTATUS_CRWE         (1 << 31)  /* Bit 31: Clear remote wakeup enable */
+
+/* HcRhPortStatus: Root hub port status (7.4.4) */
+
+#define OHCI_RHPORTST_CCS          (1 << 0)   /* Bit 0:  Current connect status */
+#define OHCI_RHPORTST_PES          (1 << 1)   /* Bit 1:  Port enable status */
+#define OHCI_RHPORTST_PSS          (1 << 2)   /* Bit 2:  Port suspend status */
+#define OHCI_RHPORTST_POCI         (1 << 3)   /* Bit 3:  Port over current indicator */
+#define OHCI_RHPORTST_PRS          (1 << 4)   /* Bit 4:  Port reset status */
+                                              /* Bits 5-7: Reserved */
+#define OHCI_RHPORTST_PPS          (1 << 8)   /* Bit 8:  Port power status */
+#define OHCI_RHPORTST_LSDA         (1 << 9)   /* Bit 9:  Low speed device attached */
+                                              /* Bits 10-15: Reserved */
+#define OHCI_RHPORTST_CSC          (1 << 16)  /* Bit 16: Connect status change */
+#define OHCI_RHPORTST_PESC         (1 << 17)  /* Bit 17: Port enable status change */
+#define OHCI_RHPORTST_PSSC         (1 << 18)  /* Bit 18: Port suspend status change */
+#define OHCI_RHPORTST_OCIC         (1 << 19)  /* Bit 19: Port over current indicator change */
+#define OHCI_RHPORTST_PRSC         (1 << 20)  /* Bit 20: Port reset status change */
+                                              /* Bits 21-31: Reserved */
+
+/* Transfer Descriptors *****************************************************/
+
+/* Endpoint Descriptor Offsets (4.2.1) */
+
+#define ED_CONTROL_OFFSET          (0x00)     /* ED status/control bits */
+#define ED_TAILP_OFFSET            (0x04)     /* TD Queue Tail Pointer (TailP) */
+#define ED_HEADP_OFFSET            (0x08)     /* TD Queue Head Pointer (HeadP) */
+#define ED_NEXTED_OFFSET           (0x0c)     /* Next Endpoint Descriptor (NextED) */
+
+/* Endpoint Descriptor Bit Definitions (4.2.2) */
+
+#define ED_CONTROL_FA_SHIFT        (0)        /* Bits 0-6: Function Address */
+#define ED_CONTROL_FA_MASK         (0x7f << ED_CONTROL_FA_SHIFT)
+#define ED_CONTROL_EN_SHIFT        (7)        /* Bits 7-10: Endpoint number */
+#define ED_CONTROL_EN_MASK         (15 << ED_CONTROL_EN_SHIFT)
+#define ED_CONTROL_D_SHIFT         (11)       /* Bits 11-12: Direction */
+#define ED_CONTROL_D_MASK          (3 << ED_CONTROL_D_SHIFT)
+#  define ED_CONTROL_D_TD1         (0 << ED_CONTROL_D_SHIFT) /* Get direction from TD */
+#  define ED_CONTROL_D_OUT         (1 << ED_CONTROL_D_SHIFT) /* OUT */
+#  define ED_CONTROL_D_IN          (2 << ED_CONTROL_D_SHIFT) /* IN */
+#  define ED_CONTROL_D_TD2         (3 << ED_CONTROL_D_SHIFT) /* Get direction from TD */
+
+#define ED_CONTROL_S               (1 << 13)  /* Bit 13: Speed (low) */
+#define ED_CONTROL_K               (1 << 14)  /* Bit 14: Skip */
+#define ED_CONTROL_F               (1 << 15)  /* Bit 15: Format (isochronous) */
+#define ED_CONTROL_MPS_SHIFT       (16)       /* Bits 16-26: Maximum packet size */
+#define ED_CONTROL_MPS_MASK        (0x7ff << ED_CONTROL_MPS_SHIFT)
+
+#define ED_HEADP_ADDR_SHIFT        (0)
+#define ED_HEADP_ADDR_MASK         0xfffffff0
+#define ED_HEADP_H                 (1 << 0)  /* Bit 0: Halted */
+#define ED_HEADP_C                 (1 << 1)  /* Bit 1: Toggle carry */
+
+/* General Transfer Descriptor Offsets (4.3.1) */
+
+#define GTD_STATUS_OFFSET          (0x00)     /* TD status bits */
+#define GTD_CBP_OFFSET             (0x04)     /* Current Buffer Pointer (CBP) */
+#define GTD_NEXTTD_OFFSET          (0x08)     /* Next TD (NextTD) */
+#define GTD_BE_OFFSET              (0x0c)     /* Buffer End (BE) */
+
+/* General Transfer Descriptor Bit Definitions */
+
+                                              /* Bits 0-17: Reserved */
+
+#define GTD_STATUS_R               (1 << 18)  /* Bit 18: Buffer rounding */
+#define GTD_STATUS_DP_SHIFT        (19)       /* Bits 19-20: Direction/PID */
+#define GTD_STATUS_DP_MASK         (3 << GTD_STATUS_DP_SHIFT)
+#  define GTD_STATUS_DP_SETUP      (0 << GTD_STATUS_DP_SHIFT) /* To endpoint */
+#  define GTD_STATUS_DP_OUT        (1 << GTD_STATUS_DP_SHIFT) /* To endpoint */
+#  define GTD_STATUS_DP_IN         (2 << GTD_STATUS_DP_SHIFT) /* From endpoint */
+
+#define GTD_STATUS_DI_SHIFT        (21)      /* Bits 21-23: Delay input */
+#define GTD_STATUS_DI_MASK         (7 << GTD_STATUS_DI_SHIFT)
+#define GTD_STATUS_T_SHIFT         (24)      /* Bits 24-25: Data Toggle */
+#define GTD_STATUS_T_MASK          (3 << GTD_STATUS_T_SHIFT)
+#  define GTD_STATUS_T_TOGGLE      (0 << GTD_STATUS_T_SHIFT)
+#  define GTD_STATUS_T_DATA0       (2 << GTD_STATUS_T_SHIFT)
+#  define GTD_STATUS_T_DATA1       (3 << GTD_STATUS_T_SHIFT)
+#define GTD_STATUS_EC_SHIFT        (26)      /* Bits 26-27: Error count */
+#define GTD_STATUS_EC_MASK         (3 << GTD_STATUS_EC_SHIFT)
+#define GTD_STATUS_CC_SHIFT        (28)      /* Bits 28-31: Condition code */
+#define GTD_STATUS_CC_MASK         (15 << GTD_STATUS_CC_SHIFT)
+
+/* Isochronous Transfer Descriptor Offsets (4.3.2) */
+
+#define ITD_STATUS_OFFSET          (0x00)    /* TD status bits */
+#define ITD_BP0_OFFSET             (0x04)    /* Buffer page 0 (BP0) */
+#define ITD_NEXTTD_OFFSET          (0x08)    /* Next TD (NextTD) */
+#define ITD_BE_OFFSET              (0x0c)    /* Buffer End (BE) */
+
+#define ITD_NPSW                   (8)
+#define ITD_PSW0_OFFSET            (0x10)    /* Offset0/PSW0 */
+#define ITD_PSW1_OFFSET            (0x12)    /* Offset1/PSW1 */
+#define ITD_PSW2_OFFSET            (0x14)    /* Offset2/PSW2 */
+#define ITD_PSW3_OFFSET            (0x16)    /* Offset3/PSW3 */
+#define ITD_PSW4_OFFSET            (0x18)    /* Offset4/PSW4 */
+#define ITD_PSW5_OFFSET            (0x1a)    /* Offset5/PSW5 */
+#define ITD_PSW6_OFFSET            (0x1c)    /* Offset6/PSW6 */
+#define ITD_PSW7_OFFSET            (0x1e)    /* Offset7/PSW7 */
+
+/* Condition codes (Table 4-7) */
+
+#define TD_CC_NOERROR              0x00
+#define TD_CC_CRC                  0x01
+#define TD_CC_BITSTUFFING          0x02
+#define TD_CC_DATATOGGLEMISMATCH   0x03
+#define TD_CC_STALL                0x04
+#define TD_CC_DEVNOTRESPONDING     0x05
+#define TD_CC_PIDCHECKFAILURE      0x06
+#define TD_CC_UNEXPECTEDPID        0x07
+#define TD_CC_DATAOVERRUN          0x08
+#define TD_CC_DATAUNDERRUN         0x09
+#define TD_CC_BUFFEROVERRUN        0x0c
+#define TD_CC_BUFFERUNDERRUN       0x0d
+#define TD_CC_NOTACCESSED          0x0f
+
+#define TD_CC_USER                 0x10      /* For use by OHCI drivers */
+
+/* Host Controller Communications Area Format (4.4.1) ***********************/
+
+/* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */
+
+#define HCCA_INTTBL_OFFSET         (0x00)
+#define HCCA_INTTBL_WSIZE          (32)
+#define HCCA_INTTBL_BSIZE          (HCCA_INTTBL_WSIZE * 4)
+
+/* HccaFrameNumber: Current frame number */
+
+#define HCCA_FMNO_OFFSET           (0x80)
+#define HCCA_FMNO_BSIZE            (2)
+
+/* HccaPad1: Zero when frame no. updated */
+
+#define HCCA_PAD1_OFFSET           (0x82)
+#define HCCA_PAD1_BSIZE            (2)
+
+/* HccaDoneHead: When the HC reaches the end of a frame and its deferred
+ * interrupt register is 0, it writes the current value of its HcDoneHead to
+ * this location and generates an interrupt.
+ *
+ * The LSB of HCCADoneHead may be set to 1 to indicate that an unmasked
+ * HcInterruptStatus was set when HccaDoneHead was written.
+ */
+
+#define HCCA_DONEHEAD_OFFSET       (0x84)
+#define HCCA_DONEHEAD_BSIZE        (4)
+
+#define HCCA_DONEHEAD_MASK         0xfffffffe
+#define HCCA_DONEHEAD_INTSTA       (1 << 0)
+
+/* 0x88: 116 bytes reserved */
+
+#define HCCA_RESERVED_OFFSET       (0x88)
+#define HCCA_RESERVED_BSIZE        (116)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct ohci_hcor
+{
+    volatile uint32_t hcrevision;           /* 0x00 */
+    volatile uint32_t hccontrol;            /* 0x04 */
+    volatile uint32_t hccmdsts;             /* 0x08 */
+    volatile uint32_t hcintsts;             /* 0x0c */
+    volatile uint32_t hcinten;              /* 0x10 */
+    volatile uint32_t hcintdis;             /* 0x14 */
+    volatile uint32_t hchcca;               /* 0x18 */
+    volatile uint32_t hcperiodcurrented;    /* 0x1c */
+    volatile uint32_t hccontrolheaded;      /* 0x20 */
+    volatile uint32_t hccontrolcurrented;   /* 0x24 */
+    volatile uint32_t hcbulkheaded;         /* 0x28 */
+    volatile uint32_t hcbulkcurrented;      /* 0x2c */
+    volatile uint32_t hcdonehead;           /* 0x30 */
+    volatile uint32_t hcfminterval;         /* 0x34 */
+    volatile uint32_t hcfmremaining;        /* 0x38 */
+    volatile uint32_t hcfmnumber;           /* 0x3c */
+    volatile uint32_t hcperiodicstart;      /* 0x40 */
+    volatile uint32_t hclsthreshold;        /* 0x44 */
+    volatile uint32_t hcrhdescriptora;      /* 0x48 */
+    volatile uint32_t hcrhdescriptorb;      /* 0x4c */
+    volatile uint32_t hcrhsts;              /* 0x50 */
+    volatile uint32_t hcrhportsts[15];      /* 0x54 */
+};
+
+/* Endpoint Descriptor Offsets (4.2.1) */
+
+struct ohci_ed_s
+{
+  volatile  uint32_t ctrl;         /* ED status/control bits */
+  volatile  uint32_t tailp;        /* TD Queue Tail Pointer (TailP) */
+  volatile  uint32_t headp;        /* TD Queue Head Pointer (HeadP) */
+  volatile  uint32_t nexted;       /* Next Endpoint Descriptor (NextED) */
+};
+
+/* General Transfer Descriptor (4.3.1) */
+
+struct ohci_gtd_s
+{
+  volatile uint32_t ctrl;          /* TD status/control bits */
+  volatile uint32_t cbp;           /* Current Buffer Pointer (CBP) */
+  volatile uint32_t nexttd;        /* Next TD (NextTD) */
+  volatile uint32_t be;            /* Buffer End (BE) */
+};
+
+/* Isochronous Transfer Descriptor Offsets (4.3.2) */
+
+struct ohci_itd_s
+{
+  volatile uint32_t ctrl;          /* TD status/control bits */
+  volatile uint32_t bp0;           /* Buffer page 0 (BP0 */
+  volatile uint32_t nexttd;        /* Next TD (NextTD) */
+  volatile uint32_t be;            /* Buffer End (BE) */
+  volatile uint16_t psw[ITD_NPSW]; /* Offset/PSW */
+};
+
+/* Host Controller Communications Area Format (4.4.1) */
+
+struct ohci_hcca_s
+{
+  /* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */
+
+  volatile uint32_t inttbl[HCCA_INTTBL_WSIZE];
+
+  /* HccaFrameNumber: Current frame number and
+   * HccaPad1: Zero when frame no. updated
+   */
+
+  volatile uint16_t fmno;
+  volatile uint16_t pad1;
+
+  /* HccaDoneHead: When the HC reaches the end of a frame and its deferred
+   * interrupt register is 0, it writes the current value of its HcDoneHead
+   * to this location and generates an interrupt.
+   */
+
+  volatile uint32_t donehead;
+  volatile uint8_t  reserved[HCCA_RESERVED_BSIZE];
+  volatile uint32_t extra;
+} __attribute__((aligned(256)));
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_USB_OHCI_H */

+ 24 - 0
port/ohci/usb_ohci_priv.h

@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef _USB_OHCI_PRIV_H
+#define _USB_OHCI_PRIV_H
+
+#include "usbh_core.h"
+#include "usbh_hub.h"
+#include "usb_hc_ohci.h"
+
+#define OHCI_HCOR ((struct ohci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_OHCI_HCOR_OFFSET))
+
+int ohci_init(struct usbh_bus *bus);
+int ohci_deinit(struct usbh_bus *bus);
+uint16_t ohci_get_frame_number(struct usbh_bus *bus);
+int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf);
+int ohci_submit_urb(struct usbh_urb *urb);
+int ohci_kill_urb(struct usbh_urb *urb);
+
+void OHCI_IRQHandler(uint8_t busid);
+
+#endif