Prechádzať zdrojové kódy

psc thread use event instead,add timeout for transfer

jzlv 3 rokov pred
rodič
commit
c44a26d69f

+ 18 - 19
class/msc/usbh_msc.c

@@ -32,7 +32,7 @@ static uint32_t g_devinuse = 0;
  * Name: usbh_msc_devno_alloc
  *
  * Description:
- *   Allocate a unique /dev/ttyACM[n] minor number in the range 0-31.
+ *   Allocate a unique /dev/sd[n] minor number in the range 0-31.
  *
  ****************************************************************************/
 
@@ -144,10 +144,10 @@ static inline int usbh_msc_scsi_testunitready(struct usbh_msc *msc_class)
 
     usbh_msc_cbw_dump(cbw);
     /* Send the CBW */
-    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
     if (nbytes >= 0) {
         /* Receive the CSW */
-        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
         if (nbytes >= 0) {
             usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
         }
@@ -173,13 +173,13 @@ static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
 
     usbh_msc_cbw_dump(cbw);
     /* Send the CBW */
-    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
     if (nbytes >= 0) {
         /* Receive the sense data response */
-        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
+        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF, CONFIG_USBHOST_MSC_TIMEOUT);
         if (nbytes >= 0) {
             /* Receive the CSW */
-            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
             if (nbytes >= 0) {
                 usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
             }
@@ -206,13 +206,13 @@ static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
 
     usbh_msc_cbw_dump(cbw);
     /* Send the CBW */
-    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
     if (nbytes >= 0) {
         /* Receive the sense data response */
-        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_INQUIRY_SIZEOF);
+        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_INQUIRY_SIZEOF, CONFIG_USBHOST_MSC_TIMEOUT);
         if (nbytes >= 0) {
             /* Receive the CSW */
-            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
             if (nbytes >= 0) {
                 usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
             }
@@ -238,16 +238,16 @@ static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
 
     usbh_msc_cbw_dump(cbw);
     /* Send the CBW */
-    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
     if (nbytes >= 0) {
         /* Receive the sense data response */
-        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_READCAPACITY10_SIZEOF);
+        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_READCAPACITY10_SIZEOF, CONFIG_USBHOST_MSC_TIMEOUT);
         if (nbytes >= 0) {
             /* Save the capacity information */
             msc_class->blocknum = GET_BE32(&msc_class->tx_buffer[0]) + 1;
             msc_class->blocksize = GET_BE32(&msc_class->tx_buffer[4]);
             /* Receive the CSW */
-            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
             if (nbytes >= 0) {
                 usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
             }
@@ -275,13 +275,13 @@ int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, con
 
     usbh_msc_cbw_dump(cbw);
     /* Send the CBW */
-    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
     if (nbytes >= 0) {
         /* Send the user data */
-        nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)buffer, msc_class->blocksize * nsectors);
+        nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)buffer, msc_class->blocksize * nsectors, CONFIG_USBHOST_MSC_TIMEOUT);
         if (nbytes >= 0) {
             /* Receive the CSW */
-            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
             if (nbytes >= 0) {
                 usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
             }
@@ -310,13 +310,13 @@ int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, cons
 
     usbh_msc_cbw_dump(cbw);
     /* Send the CBW */
-    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW);
+    nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
     if (nbytes >= 0) {
         /* Receive the user data */
-        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, (uint8_t *)buffer, msc_class->blocksize * nsectors);
+        nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, (uint8_t *)buffer, msc_class->blocksize * nsectors, CONFIG_USBHOST_MSC_TIMEOUT);
         if (nbytes >= 0) {
             /* Receive the CSW */
-            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW);
+            nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
             if (nbytes >= 0) {
                 usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
             }
@@ -338,7 +338,6 @@ int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
     }
 
     memset(msc_class, 0, sizeof(struct usbh_msc));
-    msc_class->hport = hport;
 
     usbh_msc_devno_alloc(msc_class);
     snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, msc_class->sdchar);

+ 13 - 2
common/usb_hc.h

@@ -66,6 +66,15 @@ struct usbh_endpoint_cfg {
  */
 int usb_hc_init(void);
 
+/**
+ * @brief get port connect status
+ *
+ * @param port
+ * @return true
+ * @return false
+ */
+bool usbh_get_port_connect_status(const uint8_t port);
+
 /**
  * @brief reset roothub port
  *
@@ -130,6 +139,7 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint
  * @param ep The IN or OUT endpoint descriptor for the device endpoint on which to perform the transfer.
  * @param buffer A buffer containing the data to be sent (OUT endpoint) or received (IN endpoint).
  * @param buflen The length of the data to be sent or received.
+ * @param timeout Timeout for transfer, unit is ms.
  * @return On success, a non-negative value is returned that indicates the number
  *   of bytes successfully transferred.  On a failure, a negated errno value
  *   is returned that indicates the nature of the failure:
@@ -141,7 +151,7 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint
  *     EPIPE  - Overrun errors
  *
  */
-int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen);
+int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
 
 /**
  * @brief  Process a request to handle a transfer descriptor.  This method will
@@ -151,6 +161,7 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen);
  * @param ep The IN or OUT endpoint descriptor for the device endpoint on which to perform the transfer.
  * @param buffer A buffer containing the data to be sent (OUT endpoint) or received (IN endpoint).
  * @param buflen The length of the data to be sent or received.
+ * @param timeout Timeout for transfer, unit is ms.
  * @return On success, a non-negative value is returned that indicates the number
  *   of bytes successfully transferred.  On a failure, a negated errno value
  *   is returned that indicates the nature of the failure:
@@ -162,7 +173,7 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen);
  *     EPIPE  - Overrun errors
  *
  */
-int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen);
+int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
 
 /**
  * @brief Process a request to handle a transfer asynchronously.  This method

+ 44 - 57
core/usbh_core.c

@@ -57,8 +57,7 @@ struct usbh_roothubport_priv {
 struct usbh_core_priv {
     struct usbh_roothubport_priv rhport[CONFIG_USBHOST_RHPORTS];
     volatile struct usbh_hubport *active_hport; /* Used to pass external hub port events */
-    volatile bool pscwait;                      /* TRUE: Thread is waiting for port status change event */
-    usb_osal_sem_t pscsem;                      /* Semaphore to wait for a port event */
+    usb_osal_event_t pscevent;                  /* Semaphore to wait for a port event */
 } usbh_core_cfg;
 
 static inline struct usbh_roothubport_priv *usbh_find_roothub_port(struct usbh_hubport *hport)
@@ -671,23 +670,46 @@ errout:
 static int usbh_portchange_wait(struct usbh_hubport **hport)
 {
     struct usbh_hubport *connport = NULL;
+    uint32_t recved_event;
     uint32_t flags;
     int ret;
 
     /* Loop until a change in connection state is detected */
     while (1) {
-        /* Check for a change in the connection state on any root hub port */
+        ret = usb_osal_event_recv(usbh_core_cfg.pscevent, USBH_EVENT_CONNECTED | USBH_EVENT_DISCONNECTED, &recved_event);
+        if (ret < 0) {
+            continue;
+        }
         flags = usb_osal_enter_critical_section();
         for (uint8_t port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
+            /* Check for a change in the connection state on any root hub port */
             connport = &usbh_core_cfg.rhport[port - 1].hport;
-
             if (connport->port_change) {
                 connport->port_change = false;
-                *hport = connport;
-                usb_osal_leave_critical_section(flags);
-                return 0;
+                /* debounce for port,in order to keep port connect status stability*/
+                usb_osal_msleep(25);
+                if (recved_event & USBH_EVENT_CONNECTED) {
+                    if (usbh_get_port_connect_status(port)) {
+                        if (!connport->connected) {
+                            connport->connected = true;
+                            *hport = connport;
+                            usb_osal_leave_critical_section(flags);
+                            return 0;
+                        }
+                    }
+                } else if (recved_event & USBH_EVENT_DISCONNECTED) {
+                    if (!usbh_get_port_connect_status(port)) {
+                        if (connport->connected) {
+                            connport->connected = false;
+                            *hport = connport;
+                            usb_osal_leave_critical_section(flags);
+                            return 0;
+                        }
+                    }
+                }
             }
         }
+#ifdef CONFIG_USBHOST_HUB
         /* Is a device connected to an external hub? */
         if (usbh_core_cfg.active_hport) {
             connport = (struct usbh_hubport *)usbh_core_cfg.active_hport;
@@ -696,13 +718,8 @@ static int usbh_portchange_wait(struct usbh_hubport **hport)
             usb_osal_leave_critical_section(flags);
             return 0;
         }
-        /* No changes on any port. Wait for a connection/disconnection event and check again */
-        usbh_core_cfg.pscwait = true;
+#endif
         usb_osal_leave_critical_section(flags);
-        ret = usb_osal_sem_take(usbh_core_cfg.pscsem);
-        if (ret < 0) {
-            return ret;
-        }
     }
 }
 
@@ -762,15 +779,9 @@ void usbh_external_hport_connect(struct usbh_hubport *hport)
 
     hport->connected = true;
     usbh_core_cfg.active_hport = hport;
-
-    if (usbh_core_cfg.pscwait) {
-        usbh_core_cfg.pscwait = false;
-        usb_osal_leave_critical_section(flags);
-        usb_osal_sem_give(usbh_core_cfg.pscsem);
-        return;
-    }
-
     usb_osal_leave_critical_section(flags);
+
+    usb_osal_event_send(usbh_core_cfg.pscevent, USBH_EVENT_CONNECTED);
 }
 
 void usbh_external_hport_disconnect(struct usbh_hubport *hport)
@@ -778,45 +789,18 @@ void usbh_external_hport_disconnect(struct usbh_hubport *hport)
     uint32_t flags;
 
     flags = usb_osal_enter_critical_section();
+
     hport->connected = false;
     usbh_core_cfg.active_hport = hport;
 
-    if (usbh_core_cfg.pscwait) {
-        usbh_core_cfg.pscwait = false;
-        usb_osal_leave_critical_section(flags);
-        usb_osal_sem_give(usbh_core_cfg.pscsem);
-        return;
-    }
-
     usb_osal_leave_critical_section(flags);
+    usb_osal_event_send(usbh_core_cfg.pscevent, USBH_EVENT_DISCONNECTED);
 }
 
 void usbh_event_notify_handler(uint8_t event, uint8_t rhport)
 {
-    switch (event) {
-        case USBH_EVENT_ATTACHED:
-            if (!usbh_core_cfg.rhport[rhport - 1].hport.connected) {
-                usbh_core_cfg.rhport[rhport - 1].hport.connected = true;
-                usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
-                if (usbh_core_cfg.pscwait) {
-                    usbh_core_cfg.pscwait = false;
-                    usb_osal_sem_give(usbh_core_cfg.pscsem);
-                }
-            }
-            break;
-        case USBH_EVENT_REMOVED:
-            if (usbh_core_cfg.rhport[rhport - 1].hport.connected) {
-                usbh_core_cfg.rhport[rhport - 1].hport.connected = false;
-                usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
-                if (usbh_core_cfg.pscwait) {
-                    usbh_core_cfg.pscwait = false;
-                    usb_osal_sem_give(usbh_core_cfg.pscsem);
-                }
-            }
-            break;
-        default:
-            break;
-    }
+    usbh_core_cfg.rhport[rhport - 1].hport.port_change = true;
+    usb_osal_event_send(usbh_core_cfg.pscevent, event);
 }
 
 int usbh_initialize(void)
@@ -824,11 +808,11 @@ int usbh_initialize(void)
     usb_osal_thread_t usb_thread;
 
     memset(&usbh_core_cfg, 0, sizeof(struct usbh_core_priv));
-
+#ifdef CONFIG_USBHOST_HUB
     usbh_workq_initialize();
-
-    usbh_core_cfg.pscsem = usb_osal_sem_create(0);
-    if (usbh_core_cfg.pscsem == NULL) {
+#endif
+    usbh_core_cfg.pscevent = usb_osal_event_create();
+    if (usbh_core_cfg.pscevent == NULL) {
         return -1;
     }
 
@@ -880,6 +864,7 @@ int lsusb(int argc, char **argv)
                 }
             }
         }
+#ifdef CONFIG_USBHOST_HUB
         usb_slist_for_each(hub_list, &hub_class_head)
         {
             usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
@@ -897,6 +882,7 @@ int lsusb(int argc, char **argv)
                 }
             }
         }
+#endif
     } else if (strcmp(argv[1], "-v") == 0) {
         for (port = USBH_HUB_PORT_START_INDEX; port <= CONFIG_USBHOST_RHPORTS; port++) {
             if (usbh_core_cfg.rhport[port - 1].hport.connected) {
@@ -905,7 +891,7 @@ int lsusb(int argc, char **argv)
                 usbh_print_hubport_info(&usbh_core_cfg.rhport[port - 1].hport);
             }
         }
-
+#ifdef CONFIG_USBHOST_HUB
         usb_slist_for_each(hub_list, &hub_class_head)
         {
             usbh_hub_t *hub_class = usb_slist_entry(hub_list, struct usbh_hub, list);
@@ -918,6 +904,7 @@ int lsusb(int argc, char **argv)
                 }
             }
         }
+#endif
     }
 
     return 0;

+ 5 - 2
core/usbh_core.h

@@ -27,8 +27,10 @@
 #include "usb_def.h"
 #include "usb_hc.h"
 #include "usb_osal.h"
+#ifdef CONFIG_USBHOST_HUB
 #include "usb_workq.h"
 #include "usbh_hub.h"
+#endif
 #include "usb_config.h"
 
 #ifdef __cplusplus
@@ -49,11 +51,12 @@ extern "C" {
 #define CLASS_DISCONNECT(hport, i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
 
 enum usbh_event_type {
-    USBH_EVENT_ATTACHED,
-    USBH_EVENT_REMOVED,
+    USBH_EVENT_CONNECTED = (1 << 0),
+    USBH_EVENT_DISCONNECTED = (1 << 1),
 };
 
 struct usbh_class_info {
+    uint8_t match_flags;
     uint8_t class;    /* Base device class code */
     uint8_t subclass; /* Sub-class, depends on base class. Eg. */
     uint8_t protocol; /* Protocol, depends on base class. Eg. */

+ 5 - 7
demo/usb_host.c

@@ -30,7 +30,7 @@ int cdc_acm_test(void)
     }
 
     memset(cdc_buffer, 0, 512);
-    ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512);
+    ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512, 3000);
     if (ret < 0) {
         printf("bulk in error\r\n");
         return ret;
@@ -43,7 +43,7 @@ int cdc_acm_test(void)
     const uint8_t data1[10] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x08, 0x14 };
 
     memcpy(cdc_buffer, data1, 8);
-    ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkout, cdc_buffer, 8);
+    ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkout, cdc_buffer, 8, 3000);
     if (ret < 0) {
         printf("bulk out error\r\n");
         return ret;
@@ -53,7 +53,7 @@ int cdc_acm_test(void)
 #if 0
     usbh_ep_bulk_async_transfer(cdc_acm_class->bulkin, cdc_buffer, 512, usbh_cdc_acm_callback, cdc_acm_class);
 #else
-    ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512);
+    ret = usbh_ep_bulk_transfer(cdc_acm_class->bulkin, cdc_buffer, 512, 3000);
     if (ret < 0) {
         printf("bulk in error\r\n");
         return ret;
@@ -68,7 +68,6 @@ int cdc_acm_test(void)
 #endif
 }
 
-
 #include "ff.h"
 
 int msc_test(void)
@@ -130,14 +129,13 @@ int msc_test(void)
         /*unmount*/
         f_mount(NULL, "2:", 1);
     } else {
-        printf("open error:%d\r\n",res_sd);
+        printf("open error:%d\r\n", res_sd);
     }
     usb_iofree(ReadBuffer);
 #endif
     return ret;
 }
 
-
 uint8_t hid_buffer[128];
 
 void usbh_hid_callback(void *arg, int nbytes)
@@ -167,7 +165,7 @@ int hid_test(void)
         return ret;
     }
 #else
-    ret = usbh_ep_intr_transfer(hid_class->intin, hid_buffer, 128);
+    ret = usbh_ep_intr_transfer(hid_class->intin, hid_buffer, 128, 1000);
     if (ret < 0) {
         return ret;
     }

+ 8 - 5
osal/usb_osal.h

@@ -25,11 +25,10 @@
 
 #include <stdint.h>
 
-#define USB_OSAL_MS2TICK(ms)
-
 typedef void *usb_osal_thread_t;
 typedef void *usb_osal_sem_t;
 typedef void *usb_osal_mutex_t;
+typedef void *usb_osal_event_t;
 typedef void (*usb_thread_entry_t)(void *argument);
 
 usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args);
@@ -39,7 +38,7 @@ void usb_osal_thread_resume(usb_osal_thread_t thread);
 
 usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count);
 void usb_osal_sem_delete(usb_osal_sem_t sem);
-int usb_osal_sem_take(usb_osal_sem_t sem);
+int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout);
 int usb_osal_sem_give(usb_osal_sem_t sem);
 
 usb_osal_mutex_t usb_osal_mutex_create(void);
@@ -47,11 +46,15 @@ void usb_osal_mutex_delete(usb_osal_mutex_t mutex);
 int usb_osal_mutex_take(usb_osal_mutex_t mutex);
 int usb_osal_mutex_give(usb_osal_mutex_t mutex);
 
+usb_osal_event_t usb_osal_event_create(void);
+void usb_osal_event_delete(usb_osal_event_t event);
+int usb_osal_event_recv(usb_osal_event_t event, uint32_t set, uint32_t *recved);
+int usb_osal_event_send(usb_osal_event_t event, uint32_t set);
+
 uint32_t usb_osal_enter_critical_section(void);
 void usb_osal_leave_critical_section(uint32_t flag);
 
 void usb_osal_msleep(uint32_t delay);
 
-uint32_t usb_osal_get_tick(void);
+#endif
 
-#endif

+ 33 - 8
osal/usb_osal_freertos.c

@@ -23,6 +23,8 @@
 #include "usb_osal.h"
 #include <FreeRTOS.h>
 #include "semphr.h"
+#include "timers.h"
+#include "event_groups.h"
 
 usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args)
 {
@@ -52,9 +54,9 @@ void usb_osal_sem_delete(usb_osal_sem_t sem)
     vSemaphoreDelete((SemaphoreHandle_t)sem);
 }
 
-int usb_osal_sem_take(usb_osal_sem_t sem)
+int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
 {
-    return (xSemaphoreTake((SemaphoreHandle_t)sem, portMAX_DELAY) == pdPASS) ? 0 : -1;
+    return (xSemaphoreTake((SemaphoreHandle_t)sem, pdMS_TO_TICKS(timeout)) == pdPASS) ? 0 : -1;
 }
 
 int usb_osal_sem_give(usb_osal_sem_t sem)
@@ -101,6 +103,34 @@ int usb_osal_mutex_give(usb_osal_mutex_t mutex)
     return (xSemaphoreGive((SemaphoreHandle_t)mutex) == pdPASS) ? 0 : -1;
 }
 
+usb_osal_event_t usb_osal_event_create(void)
+{
+    return (usb_osal_event_t)xEventGroupCreate();
+}
+
+void usb_osal_event_delete(usb_osal_event_t event)
+{
+    vEventGroupDelete((EventGroupHandle_t)event);
+}
+
+int usb_osal_event_recv(usb_osal_event_t event, uint32_t set, uint32_t *recved)
+{
+    *recved = xEventGroupWaitBits((EventGroupHandle_t)event, set, pdTRUE, pdFALSE, portMAX_DELAY);
+    return 0;
+}
+
+int usb_osal_event_send(usb_osal_event_t event, uint32_t set)
+{
+    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+    int ret;
+
+    ret = xEventGroupSetBitsFromISR((EventGroupHandle_t)event, set, &xHigherPriorityTaskWoken);
+    if (ret == pdPASS) {
+        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+    }
+    return (ret == pdPASS) ? 0 : -1;
+}
+
 uint32_t usb_osal_enter_critical_section(void)
 {
     taskENTER_CRITICAL();
@@ -115,9 +145,4 @@ void usb_osal_leave_critical_section(uint32_t flag)
 void usb_osal_msleep(uint32_t delay)
 {
     vTaskDelay(pdMS_TO_TICKS(delay));
-}
-
-uint32_t usb_osal_get_tick(void)
-{
-    return xTaskGetTickCount();
-}
+}

+ 30 - 6
osal/usb_osal_rtthread.c

@@ -51,9 +51,9 @@ void usb_osal_sem_delete(usb_osal_sem_t sem)
     rt_sem_delete((rt_sem_t)sem);
 }
 
-int usb_osal_sem_take(usb_osal_sem_t sem)
+int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
 {
-    return (int)rt_sem_take((rt_sem_t)sem, RT_WAITING_FOREVER);
+    return (int)rt_sem_take((rt_sem_t)sem, rt_tick_from_millisecond(timeout));
 }
 
 int usb_osal_sem_give(usb_osal_sem_t sem)
@@ -66,6 +66,11 @@ usb_osal_mutex_t usb_osal_mutex_create(void)
     return (usb_osal_mutex_t)rt_mutex_create("usbh_mutex", RT_IPC_FLAG_FIFO);
 }
 
+void usb_osal_mutex_delete(usb_osal_mutex_t mutex)
+{
+    rt_mutex_delete((rt_mutex_t)mutex);
+}
+
 int usb_osal_mutex_take(usb_osal_mutex_t mutex)
 {
     return (int)rt_mutex_take((rt_mutex_t)mutex, RT_WAITING_FOREVER);
@@ -76,18 +81,37 @@ int usb_osal_mutex_give(usb_osal_mutex_t mutex)
     return (int)rt_mutex_release((rt_mutex_t)mutex);
 }
 
+usb_osal_event_t usb_osal_event_create(void)
+{
+    return (usb_osal_event_t)rt_event_create("psc_event", RT_IPC_FLAG_FIFO);
+}
+
+void usb_osal_event_delete(usb_osal_event_t event)
+{
+    rt_event_delete((rt_event_t)event);
+}
+
+int usb_osal_event_recv(usb_osal_event_t event, uint32_t set, uint32_t *recved)
+{
+    rt_event_recv((rt_event_t)event, set, RT_EVENT_FLAG_OR, RT_WAITING_FOREVER, recved);
+}
+
+int usb_osal_event_send(usb_osal_event_t event, uint32_t set)
+{
+    rt_event_send((rt_event_t)event, set);
+}
+
 uint32_t usb_osal_enter_critical_section(void)
 {
-    rt_enter_critical();
-    return 1;
+    return rt_hw_interrupt_disable();
 }
 
 void usb_osal_leave_critical_section(uint32_t flag)
 {
-    rt_exit_critical();
+    rt_hw_interrupt_enable(flag);
 }
 
 void usb_osal_msleep(uint32_t delay)
 {
-    rt_thread_mdelay(delay);
+    rt_thread_mdelay(rt_tick_from_millisecond(delay));
 }

+ 24 - 2
osal/usb_workq.c

@@ -1,3 +1,25 @@
+/**
+ * @file usb_workq.c
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * 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.
+ *
+ */
 #include "usb_list.h"
 #include "usb_osal.h"
 #include "usb_workq.h"
@@ -29,7 +51,7 @@ static void usbh_hpwork_thread(void *argument)
     int ret;
     struct usb_workqueue *queue = (struct usb_workqueue *)argument;
     while (1) {
-        ret = usb_osal_sem_take(queue->sem);
+        ret = usb_osal_sem_take(queue->sem, 0xffffffff);
         if (ret < 0) {
             continue;
         }
@@ -52,7 +74,7 @@ static void usbh_lpwork_thread(void *argument)
     int ret;
     struct usb_workqueue *queue = (struct usb_workqueue *)argument;
     while (1) {
-        ret = usb_osal_sem_take(queue->sem);
+        ret = usb_osal_sem_take(queue->sem, 0xffffffff);
         if (ret < 0) {
             continue;
         }

+ 22 - 0
osal/usb_workq.h

@@ -1,3 +1,25 @@
+/**
+ * @file usb_workq.h
+ * @brief
+ *
+ * Copyright (c) 2022 sakumisu
+ *
+ * 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 _USB_WORKQUEUE_H
 #define _USB_WORKQUEUE_H
 

+ 109 - 125
port/ehci/usb_ehci.c

@@ -127,28 +127,22 @@ struct usb_ehci_epinfo_s {
     uint16_t speed     : 2;  /* See USB_*_SPEED definitions in ehci.h */
     int result;              /* The result of the transfer */
     uint32_t xfrd;           /* On completion, will hold the number of bytes transferred */
-
-    usb_osal_sem_t iocsem; /* Semaphore used to wait for transfer completion */
+    bool inuse;
+    usb_osal_sem_t iocsem;    /* Semaphore used to wait for transfer completion */
+    usb_osal_mutex_t exclsem; /* Support mutually exclusive access */
 #ifdef CONFIG_USBHOST_ASYNCH
     usbh_asynch_callback_t callback; /* Transfer complete callback */
     void *arg;                       /* Argument that accompanies the callback */
 #endif
     struct usbh_hubport *hport;
-    usb_slist_t list;
 };
 
 /* This structure retains the overall state of the USB host controller */
 
 struct usb_ehci_s {
-    volatile bool connected;  /* Connected to device */
-    usb_osal_mutex_t exclsem; /* Support mutually exclusive access */
-    struct usb_work work;
-
     struct usb_ehci_list_s *qhfree;  /* List of free Queue Head (QH) structures */
     struct usb_ehci_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */
-
-    struct usb_ehci_epinfo_s ep0[CONFIG_USBHOST_RHPORTS]; /* EP0 endpoint info */
-    usb_slist_t epinfo_list;
+    struct usb_ehci_epinfo_s chan[CONFIG_USBHOST_PIPE_NUM];
 };
 
 /****************************************************************************
@@ -303,6 +297,32 @@ static inline uint32_t usb_ehci_getreg(volatile uint32_t *regaddr)
     return *regaddr;
 }
 
+static int usb_ehci_chan_alloc(struct usb_ehci_s *priv)
+{
+    int chidx;
+
+    /* Search the table of channels */
+
+    for (chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) {
+        /* Is this channel available? */
+        if (!priv->chan[chidx].inuse) {
+            /* Yes... make it "in use" and return the index */
+
+            priv->chan[chidx].inuse = true;
+            return chidx;
+        }
+    }
+
+    /* All of the channels are "in-use" */
+
+    return -EBUSY;
+}
+
+static void usb_ehci_chan_free(struct usb_ehci_epinfo_s *chan)
+{
+    /* Mark the channel available */
+    chan->inuse = false;
+}
 /****************************************************************************
  * Name: usb_ehci_qh_alloc
  *
@@ -1287,7 +1307,7 @@ static int usb_ehci_ioc_setup(struct usb_ehci_epinfo_s *epinfo)
     /* Is the device still connected? */
 
     flags = usb_osal_enter_critical_section();
-    if (g_ehci.connected) {
+    if (epinfo->hport->connected) {
         /* Then set iocwait to indicate that we expect to be informed when
         * either (1) the device is disconnected, or (2) the transfer
         * completed.
@@ -1341,7 +1361,7 @@ static int usb_ehci_ioc_async_setup(struct usb_ehci_epinfo_s *epinfo, usbh_async
     /* Is the device still connected? */
 
     flags = usb_osal_enter_critical_section();
-    if (g_ehci.connected) {
+    if (epinfo->hport->connected) {
         /* Then set iocwait to indicate that we expect to be informed when
         * either (1) the device is disconnected, or (2) the transfer
         * completed.
@@ -1437,34 +1457,21 @@ static void usb_ehci_asynch_completion(struct usb_ehci_epinfo_s *epinfo)
  *
  ****************************************************************************/
 
-static int usb_ehci_transfer_wait(struct usb_ehci_epinfo_s *epinfo)
+static int usb_ehci_transfer_wait(struct usb_ehci_epinfo_s *epinfo, uint32_t timeout)
 {
     int ret = 0;
-    int ret2;
-
-    /* Release the EHCI semaphore while we wait.  Other threads need the
-    * opportunity to access the EHCI resources while we wait. */
-
-    usb_osal_mutex_give(g_ehci.exclsem);
 
     /* Wait for the IOC completion event */
     if (epinfo->iocwait) {
-        ret = usb_osal_sem_take(epinfo->iocsem);
-        if (ret == 0) {
-            ret = epinfo->result;
+        ret = usb_osal_sem_take(epinfo->iocsem, timeout);
+        if (ret < 0) {
+            return ret;
         }
     }
 
-    /* Re-acquire the EHCI semaphore. The caller expects to be holding this upon return.*/
-    ret2 = usb_osal_mutex_take(g_ehci.exclsem);
-    if (ret2 < 0) {
-        ret = ret2;
-    }
-
-    /* Did epinfo->result or usb_osal_mutex_take() report an error? */
+    ret = epinfo->result;
 
     if (ret < 0) {
-        epinfo->iocwait = false;
         return ret;
     }
 
@@ -1831,30 +1838,18 @@ static inline void usb_ehci_portsc_bottomhalf(void)
 
         /* Handle port connection status change (CSC) events */
         if ((portsc & EHCI_PORTSC_CSC) != 0) {
-            /* Debounce */
-            usb_osal_msleep(25);
-            /* Check current connect status*/
-            portsc = usb_ehci_getreg(&HCOR->portsc[rhpndx]);
             if ((portsc & EHCI_PORTSC_CCS) == EHCI_PORTSC_CCS) {
                 /* Connected ... Did we just become connected? */
-                if (!g_ehci.connected) {
-                    g_ehci.connected = 1;
-                    usbh_event_notify_handler(USBH_EVENT_ATTACHED, 1);
-                }
+                usbh_event_notify_handler(USBH_EVENT_CONNECTED, 1);
             } else {
-                if (g_ehci.connected) {
-                    g_ehci.connected = 0;
-                    usb_slist_t *i;
-                    usb_slist_for_each(i, &g_ehci.epinfo_list)
-                    {
-                        struct usb_ehci_epinfo_s *epinfo = usb_slist_entry(i, struct usb_ehci_epinfo_s, list);
-                        if (epinfo->iocwait) {
-                            epinfo->iocwait = false;
-                            usb_osal_sem_give(epinfo->iocsem);
-                        }
+                for (uint8_t chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) {
+                    struct usb_ehci_epinfo_s *epinfo = &g_ehci.chan[chidx];
+                    if (epinfo->iocwait) {
+                        epinfo->iocwait = false;
+                        usb_osal_sem_give(epinfo->iocsem);
                     }
-                    usbh_event_notify_handler(USBH_EVENT_REMOVED, 1);
                 }
+                usbh_event_notify_handler(USBH_EVENT_DISCONNECTED, 1);
             }
         }
 
@@ -2035,12 +2030,9 @@ int usb_hc_init(void)
     uintptr_t physaddr1;
     uintptr_t physaddr2;
 
-    g_ehci.connected = 0;
     g_ehci.qhfree = NULL;
     g_ehci.qtdfree = NULL;
 
-    usb_slist_init(&g_ehci.epinfo_list);
-
     /* Initialize the list of free Queue Head (QH) structures */
 
     for (uint8_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) {
@@ -2106,8 +2098,6 @@ int usb_hc_init(void)
     usb_ehci_dcache_clean((uintptr_t)&g_intrhead.hw, sizeof(struct usb_ehci_qh_s));
     usb_ehci_dcache_clean((uintptr_t)g_framelist, FRAME_LIST_SIZE * sizeof(uint32_t));
 
-    g_ehci.exclsem = usb_osal_mutex_create();
-
     usb_hc_low_level_init();
     /* Host Controller Initialization. Paragraph 4.1 */
 
@@ -2194,6 +2184,17 @@ int usb_hc_init(void)
     return ret;
 }
 
+bool usbh_get_port_connect_status(const uint8_t port)
+{
+    uint32_t portsc;
+    portsc = usb_ehci_getreg(&HCOR->portsc[port - 1]);
+    if ((portsc & EHCI_PORTSC_CCS) == EHCI_PORTSC_CCS) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 int usbh_reset_port(const uint8_t port)
 {
     uint32_t timeout = 0;
@@ -2249,7 +2250,7 @@ int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uin
 
     DEBUGASSERT(epinfo != NULL && ep_mps < 2048);
 
-    ret = usb_osal_mutex_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
@@ -2258,7 +2259,7 @@ int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uin
     epinfo->speed = speed;
     epinfo->maxpacket = ep_mps;
 
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
 
     return ret;
 }
@@ -2267,24 +2268,18 @@ int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg)
 {
     struct usb_ehci_epinfo_s *epinfo;
     struct usbh_hubport *hport;
+    int chidx;
 
     DEBUGASSERT(ep_cfg != NULL && ep_cfg->hport != NULL);
 
     hport = ep_cfg->hport;
 
-    /* new roothub ep info */
-    if (((ep_cfg->ep_type & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_CONTROL) && (hport->parent == NULL)) {
-        memset(&g_ehci.ep0, 0, sizeof(struct usb_ehci_epinfo_s));
-        epinfo = &g_ehci.ep0[hport->port - 1];
-    } else {
-        /* new exteranl hub ep info */
-        epinfo = usb_malloc(sizeof(struct usb_ehci_epinfo_s));
-        memset(epinfo, 0, sizeof(struct usb_ehci_epinfo_s));
-        if (epinfo == NULL) {
-            return -1;
-        }
-    }
+    chidx = usb_ehci_chan_alloc(&g_ehci);
+
+    epinfo = &g_ehci.chan[chidx];
+    memset(epinfo, 0, sizeof(struct usb_ehci_epinfo_s));
 
+    epinfo->inuse = true;
     epinfo->epno = ep_cfg->ep_addr & 0x7f;
     epinfo->dirin = (ep_cfg->ep_addr & 0x80) ? 1 : 0;
     epinfo->devaddr = hport->dev_addr;
@@ -2297,9 +2292,9 @@ int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg)
     epinfo->hport = hport;
 
     epinfo->iocsem = usb_osal_sem_create(0);
-    usb_slist_add_tail(&g_ehci.epinfo_list, &epinfo->list);
+    epinfo->exclsem = usb_osal_mutex_create();
 
-    *ep = epinfo;
+    *ep = (usbh_epinfo_t)epinfo;
 
     return 0;
 }
@@ -2309,8 +2304,8 @@ int usbh_ep_free(usbh_epinfo_t ep)
     struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep;
 
     usb_osal_sem_delete(epinfo->iocsem);
-    usb_slist_remove(&g_ehci.epinfo_list, &epinfo->list);
-    usb_free(epinfo);
+    usb_osal_mutex_delete(epinfo->exclsem);
+    usb_ehci_chan_free(epinfo);
 
     return 0;
 }
@@ -2330,7 +2325,7 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint
 
     DEBUGASSERT(setup || buffer);
 
-    ret = usb_osal_mutex_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
@@ -2347,18 +2342,22 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint
     }
 
     /* And wait for the transfer to complete */
-    nbytes = usb_ehci_transfer_wait(epinfo);
-    usb_osal_mutex_give(g_ehci.exclsem);
-    return nbytes >= 0 ? 0 : (int)nbytes;
+    nbytes = usb_ehci_transfer_wait(epinfo, CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT);
+    if (nbytes < 0) {
+        goto errout_with_iocwait;
+    }
+
+    usb_osal_mutex_give(epinfo->exclsem);
+    return nbytes;
 
 errout_with_iocwait:
     epinfo->iocwait = false;
 errout_with_sem:
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return ret;
 }
 
-int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen)
+int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
 {
     int nbytes;
     int ret;
@@ -2367,7 +2366,7 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen)
 
     DEBUGASSERT(epinfo && buffer && buflen > 0);
 
-    ret = usb_osal_mutex_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
@@ -2383,18 +2382,21 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen)
     }
 
     /* And wait for the transfer to complete */
-    nbytes = usb_ehci_transfer_wait(epinfo);
-    usb_osal_mutex_give(g_ehci.exclsem);
+    nbytes = usb_ehci_transfer_wait(epinfo, timeout);
+    if (nbytes < 0) {
+        goto errout_with_iocwait;
+    }
+    usb_osal_mutex_give(epinfo->exclsem);
     return nbytes;
 
 errout_with_iocwait:
     epinfo->iocwait = false;
 errout_with_sem:
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return ret;
 }
 
-int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen)
+int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
 {
     int nbytes;
     int ret;
@@ -2403,14 +2405,13 @@ int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen)
 
     DEBUGASSERT(epinfo && buffer && buflen > 0);
 
-    ret = usb_osal_mutex_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
 
     ret = usb_ehci_ioc_setup(epinfo);
-
-    if (ret != 0) {
+    if (ret < 0) {
         goto errout_with_sem;
     }
 
@@ -2420,14 +2421,17 @@ int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen)
     }
 
     /* And wait for the transfer to complete */
-    nbytes = usb_ehci_transfer_wait(epinfo);
-    usb_osal_mutex_give(g_ehci.exclsem);
+    nbytes = usb_ehci_transfer_wait(epinfo, timeout);
+    if (nbytes < 0) {
+        goto errout_with_iocwait;
+    }
+    usb_osal_mutex_give(epinfo->exclsem);
     return nbytes;
 
 errout_with_iocwait:
     epinfo->iocwait = false;
 errout_with_sem:
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return ret;
 }
 #ifdef CONFIG_USBHOST_ASYNCH
@@ -2439,7 +2443,7 @@ int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl
 
     DEBUGASSERT(epinfo && buffer && buflen > 0);
 
-    ret = usb_osal_mutex_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
@@ -2457,14 +2461,14 @@ int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl
     }
 
     /* The transfer is in progress */
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return 0;
 
 errout_with_callback:
     epinfo->callback = NULL;
     epinfo->arg = NULL;
 errout_with_sem:
-    usb_osal_mutex_give(&g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return ret;
 }
 
@@ -2476,7 +2480,7 @@ int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl
 
     DEBUGASSERT(epinfo && buffer && buflen > 0);
 
-    ret = usb_osal_mutex_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
@@ -2494,14 +2498,14 @@ int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl
     }
 
     /* The transfer is in progress */
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return 0;
 
 errout_with_callback:
     epinfo->callback = NULL;
     epinfo->arg = NULL;
 errout_with_sem:
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return ret;
 }
 #endif
@@ -2548,7 +2552,7 @@ int usb_ep_cancel(usbh_epinfo_t ep)
    * interrupt level.
    */
 
-    ret = usb_osal_sem_take(g_ehci.exclsem);
+    ret = usb_osal_mutex_take(epinfo->exclsem);
     if (ret < 0) {
         return ret;
     }
@@ -2688,21 +2692,14 @@ exit_terminate:
 #endif
 
 errout_with_sem:
-    usb_osal_mutex_give(g_ehci.exclsem);
+    usb_osal_mutex_give(epinfo->exclsem);
     return ret;
 }
 
 static void usb_ehci_bottomhalf(void *arg)
 {
     uint32_t pending = (uint32_t)arg;
-    /* We need to have exclusive access to the EHCI data structures.  Waiting
-    * here is not a good thing to do on the worker thread, but there is no
-    * real option (other than to reschedule and delay).
-    */
 
-    usb_osal_mutex_take(g_ehci.exclsem);
-
-    /* Handle all unmasked interrupt sources */
     /* USB Interrupt (USBINT)
     *
     *  "The Host Controller sets this bit to 1 on the completion of a USB
@@ -2785,14 +2782,6 @@ static void usb_ehci_bottomhalf(void *arg)
 
     if ((pending & EHCI_INT_AAINT) != 0) {
     }
-    /* Re-enable relevant EHCI interrupts.  Interrupts should still be enabled
-    * at the level of the interrupt controller.
-    */
-
-    usb_ehci_putreg(EHCI_HANDLED_INTS, &HCOR->usbintr);
-
-    /* We are done with the EHCI structures */
-    usb_osal_mutex_give(g_ehci.exclsem);
 }
 
 void usb_ehci_interrupt(void)
@@ -2810,23 +2799,18 @@ void usb_ehci_interrupt(void)
     pending = usbsts & regval;
 
     if (pending != 0) {
-        /* Schedule interrupt handling work for the high priority worker
-        * thread so that we are not pressed for time and so that we can
-        * interrupt with other USB threads gracefully.
-        *
-        * The worker should be available now because we implement a handshake
-        * by controlling the EHCI interrupts.
-        */
-
-        usb_workqueue_submit(&g_hpworkq, &g_ehci.work, usb_ehci_bottomhalf, (void *)pending, 0);
-        /* Disable further EHCI interrupts so that we do not overrun the work
-        * queue.
-        */
+        /* Disable further EHCI interrupts so that we do not overrun the work queue.*/
         usb_ehci_putreg(0, &HCOR->usbintr);
-
         /* Clear all pending status bits by writing the value of the pending
         * interrupt bits back to the status register.
         */
         usb_ehci_putreg(usbsts & EHCI_INT_ALLINTS, &HCOR->usbsts);
+
+        usb_ehci_bottomhalf((void *)pending);
+
+        /* Re-enable relevant EHCI interrupts.  Interrupts should still be enabled
+        * at the level of the interrupt controller.
+        */
+        usb_ehci_putreg(EHCI_HANDLED_INTS, &HCOR->usbintr);
     }
 }

+ 15 - 3
usb_config.h

@@ -12,12 +12,24 @@
 #define CONFIG_USBHOST_EHPORTS 4
 #endif
 
+#ifndef CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USBHOST_PIPE_NUM 10
+#endif
+
 #ifndef CONFIG_USBHOST_INTF_NUM
 #define CONFIG_USBHOST_INTF_NUM 6
 #endif
 
 #ifndef CONFIG_USBHOST_EP_NUM
-#define CONFIG_USBHOST_EP_NUM 2
+#define CONFIG_USBHOST_EP_NUM 4
+#endif
+
+#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
+#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 5000
+#endif
+
+#ifndef CONFIG_USBHOST_MSC_TIMEOUT
+#define CONFIG_USBHOST_MSC_TIMEOUT 5000
 #endif
 
 #ifndef CONFIG_USBHOST_HPWORKQ_PRIO
@@ -38,7 +50,7 @@
 #define CONFIG_USBHOST_PSC_PRIO 4
 #endif
 #ifndef CONFIG_USBHOST_PSC_STACKSIZE
-#define CONFIG_USBHOST_PSC_STACKSIZE 2048
+#define CONFIG_USBHOST_PSC_STACKSIZE 4096
 #endif
 
 #ifndef CONFIG_USBHOST_DEV_NAMELEN
@@ -54,7 +66,7 @@
 #define CONFIG_USB_EHCI_QH_NUM    (10)
 #define CONFIG_USB_EHCI_QTD_NUM   (10)
 // #define CONFIG_USB_EHCI_INFO_ENABLE
-// #define CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE
+#define CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE
 // #define CONFIG_USB_EHCI_CONFIGFLAG
 
 #endif