Эх сурвалжийг харах

add usbh_edpt_claim/release

implement USBH_EVENT_FUNC_CALL
hathach 5 жил өмнө
parent
commit
87b989e8b4

+ 1 - 1
src/device/dcd.h

@@ -77,7 +77,7 @@ typedef struct TU_ATTR_ALIGNED(4)
       uint32_t len;
     }xfer_complete;
 
-    // USBD_EVENT_FUNC_CALL
+    // FUNC_CALL
     struct {
       void (*func) (void*);
       void* param;

+ 11 - 0
src/host/hcd.h

@@ -45,6 +45,11 @@ typedef enum
   HCD_EVENT_DEVICE_ATTACH,
   HCD_EVENT_DEVICE_REMOVE,
   HCD_EVENT_XFER_COMPLETE,
+
+  // Not an HCD event, just a convenient way to defer ISR function
+  USBH_EVENT_FUNC_CALL,
+
+  HCD_EVENT_COUNT
 } hcd_eventid_t;
 
 typedef struct
@@ -67,6 +72,12 @@ typedef struct
       uint8_t result;
       uint32_t len;
     } xfer_complete;
+
+    // FUNC_CALL
+    struct {
+      void (*func) (void*);
+      void* param;
+    }func_call;
   };
 
 } hcd_event_t;

+ 72 - 3
src/host/usbh.c

@@ -169,6 +169,11 @@ bool tuh_init(void)
     dev->control.sem_hdl = osal_semaphore_create(&dev->control.sem_def);
     TU_ASSERT(dev->control.sem_hdl != NULL);
 
+#if CFG_TUSB_OS != OPT_OS_NONE
+    dev->mutex = osal_mutex_create(&dev->mutexdef);
+    TU_ASSERT(dev->mutex);
+#endif
+
     memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping
     memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping
   }
@@ -187,6 +192,8 @@ bool tuh_init(void)
 }
 
 //------------- USBH control transfer -------------//
+
+// TODO remove
 bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data)
 {
   usbh_device_t* dev = &_usbh_devices[dev_addr];
@@ -216,6 +223,58 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8
   return true;
 }
 
+bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
+{
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  usbh_device_t* dev = &_usbh_devices[dev_addr];
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  // pre-check to help reducing mutex lock
+  TU_VERIFY((dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0));
+  osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+#endif
+
+  // can only claim the endpoint if it is not busy and not claimed yet.
+  bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0);
+  if (ret)
+  {
+    dev->ep_status[epnum][dir].claimed = 1;
+  }
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  osal_mutex_unlock(dev->mutex);
+#endif
+
+  return ret;
+}
+
+bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
+{
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  usbh_device_t* dev = &_usbh_devices[dev_addr];
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+#endif
+
+  // can only release the endpoint if it is claimed and not busy
+  bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 1);
+  if (ret)
+  {
+    dev->ep_status[epnum][dir].claimed = 0;
+  }
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  osal_mutex_unlock(dev->mutex);
+#endif
+
+  return ret;
+}
+
 bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 {
   usbh_device_t* dev = &_usbh_devices[dev_addr];
@@ -402,6 +461,8 @@ void tuh_task(void)
     switch (event.event_id)
     {
       case HCD_EVENT_DEVICE_ATTACH:
+        // TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
+        // one device before enumerating another one.
         TU_LOG2("USBH DEVICE ATTACH\r\n");
         enum_new_device(&event);
       break;
@@ -443,6 +504,10 @@ void tuh_task(void)
       }
       break;
 
+      case USBH_EVENT_FUNC_CALL:
+        if ( event.func_call.func ) event.func_call.func(event.func_call.param);
+      break;
+
       default: break;
     }
   }
@@ -465,6 +530,8 @@ static uint8_t get_new_address(void)
 // is a lengthy process with a seires of control transfer to configure
 // newly attached device. Each step is handled by a function in this
 // section
+// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
+// one device before enumerating another one.
 //--------------------------------------------------------------------+
 
 static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
@@ -785,7 +852,7 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
     {
       tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
 
-      // Check if class is supportedVe
+      // Check if class is supported
       uint8_t drv_id;
       for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
       {
@@ -799,6 +866,8 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
       }
       else
       {
+        usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
+
         // Interface number must not be used already TODO alternate interface
         TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
         dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
@@ -813,8 +882,8 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
         {
           uint16_t itf_len = 0;
 
-          TU_LOG2("%s open\r\n", usbh_class_drivers[drv_id].name);
-          TU_ASSERT( usbh_class_drivers[drv_id].open(dev->rhport, dev_addr, desc_itf, &itf_len) );
+          TU_LOG2("%s open\r\n", driver->name);
+          TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) );
           TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) );
           p_desc += itf_len;
         }

+ 7 - 2
src/host/usbh.h

@@ -65,6 +65,7 @@ typedef struct {
 } usbh_class_driver_t;
 
 typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+
 //--------------------------------------------------------------------+
 // INTERNAL OBJECT & FUNCTION DECLARATION
 //--------------------------------------------------------------------+
@@ -106,11 +107,15 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr);
 // CLASS-USBH & INTERNAL API
 //--------------------------------------------------------------------+
 
-bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data);
 bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
-
 bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
 
+// Claim an endpoint before submitting a transfer.
+// If caller does not make any transfer, it must release endpoint for others.
+bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
+
+bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data); // TODO remove later
+
 #ifdef __cplusplus
  }
 #endif

+ 7 - 1
src/host/usbh_control.c

@@ -58,6 +58,8 @@ static usbh_control_xfer_t _ctrl_xfer;
 
 bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb)
 {
+  // TODO need to claim the endpoint first
+
   usbh_device_t* dev = &_usbh_devices[dev_addr];
   const uint8_t rhport = dev->rhport;
 
@@ -83,6 +85,10 @@ static void _xfer_complete(uint8_t dev_addr, xfer_result_t result)
 
 bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
 {
+  (void) ep_addr;
+  (void) xferred_bytes;
+
+
   usbh_device_t* dev = &_usbh_devices[dev_addr];
   const uint8_t rhport = dev->rhport;
 
@@ -106,7 +112,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu
           hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength);
           return true;
         }
-      __attribute__((fallthrough));
+        __attribute__((fallthrough));
 
       case STAGE_DATA:
         _ctrl_xfer.stage = STAGE_ACK;

+ 22 - 1
src/host/usbh_hcd.h

@@ -40,6 +40,10 @@
 #include "common/tusb_common.h"
 #include "osal/osal.h"
 
+#ifndef CFG_TUH_EP_MAX
+#define CFG_TUH_EP_MAX          9
+#endif
+
 //--------------------------------------------------------------------+
 // USBH-HCD common data structure
 //--------------------------------------------------------------------+
@@ -80,7 +84,24 @@ typedef struct {
   } control;
 
   uint8_t itf2drv[16];  // map interface number to driver (0xff is invalid)
-  uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid )
+  uint8_t ep2drv[CFG_TUH_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
+
+  struct TU_ATTR_PACKED
+  {
+    volatile bool busy    : 1;
+    volatile bool stalled : 1;
+    volatile bool claimed : 1;
+
+    // TODO merge ep2drv here, 4-bit should be sufficient
+  }ep_status[CFG_TUH_EP_MAX][2];
+
+
+// Mutex for claiming endpoint, only needed when using with preempted RTOS
+#if CFG_TUSB_OS != OPT_OS_NONE
+  osal_mutex_def_t mutexdef;
+  osal_mutex_t mutex;
+#endif
+
 } usbh_device_t;
 
 extern usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // including zero-address