Просмотр исходного кода

Merge pull request #646 from hathach/detect-clear-set-ep-status-from-class

remove the requirement of std SET/CLEAR_FEATURE must not return zlp status
Ha Thach 5 лет назад
Родитель
Сommit
89fcaf1efd
2 измененных файлов с 46 добавлено и 47 удалено
  1. 42 33
      src/device/usbd.c
  2. 4 14
      src/device/usbd_control.c

+ 42 - 33
src/device/usbd.c

@@ -485,6 +485,12 @@ void tud_task (void)
         // But it is easier to set it every time instead of wasting time to check then set
         // But it is easier to set it every time instead of wasting time to check then set
         _usbd_dev.connected = 1;
         _usbd_dev.connected = 1;
 
 
+        // mark both in & out control as free
+        _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false;
+        _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0;
+        _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false;
+        _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0;
+
         // Process control request
         // Process control request
         if ( !process_control_request(event.rhport, &event.setup_received) )
         if ( !process_control_request(event.rhport, &event.setup_received) )
         {
         {
@@ -605,6 +611,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
         // forward to class driver: "non-STD request to Interface"
         // forward to class driver: "non-STD request to Interface"
         return invoke_class_control(rhport, driver, p_request);
         return invoke_class_control(rhport, driver, p_request);
       }
       }
+
       if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
       if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
       {
       {
         // Non standard request is not supported
         // Non standard request is not supported
@@ -712,14 +719,17 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
 
 
       TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
       TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
 
 
-      bool ret = false;
+      usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]);
 
 
-      // Handle STD request to endpoint
-      if ( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
+      if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
       {
       {
-        // force return true for standard request
-        ret = true;
-
+        // Forward class request to its driver
+        TU_VERIFY(driver);
+        return invoke_class_control(rhport, driver, p_request);
+      }
+      else
+      {
+        // Handle STD request to endpoint
         switch ( p_request->bRequest )
         switch ( p_request->bRequest )
         {
         {
           case TUSB_REQ_GET_STATUS:
           case TUSB_REQ_GET_STATUS:
@@ -730,40 +740,39 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
           break;
           break;
 
 
           case TUSB_REQ_CLEAR_FEATURE:
           case TUSB_REQ_CLEAR_FEATURE:
-            if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) usbd_edpt_clear_stall(rhport, ep_addr);
-            tud_control_status(rhport, p_request);
-          break;
-
           case TUSB_REQ_SET_FEATURE:
           case TUSB_REQ_SET_FEATURE:
-            if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) usbd_edpt_stall(rhport, ep_addr);
-            tud_control_status(rhport, p_request);
+          {
+            if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
+            {
+              if ( TUSB_REQ_CLEAR_FEATURE ==  p_request->bRequest )
+              {
+                usbd_edpt_clear_stall(rhport, ep_addr);
+              }else
+              {
+                usbd_edpt_stall(rhport, ep_addr);
+              }
+            }
+
+            if (driver)
+            {
+              // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request
+              // We will also forward std request targeted endpoint to class drivers as well
+
+              // STD request must always be ACKed regardless of driver returned value
+              // Also clear complete callback if driver set since it can also stall the request.
+              (void) invoke_class_control(rhport, driver, p_request);
+              usbd_control_set_complete_callback(NULL);
+
+              // skip ZLP status if driver already did that
+              if ( !_usbd_dev.ep_status[0][TUSB_DIR_IN].busy ) tud_control_status(rhport, p_request);
+            }
+          }
           break;
           break;
 
 
           // Unknown/Unsupported request
           // Unknown/Unsupported request
           default: TU_BREAKPOINT(); return false;
           default: TU_BREAKPOINT(); return false;
         }
         }
       }
       }
-
-      usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]);
-
-      if (driver)
-      {
-        // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request
-        // We will forward all request targeted endpoint to class drivers after
-        // - For class-type requests: driver is fully responsible to reply to host
-        // - For std-type requests  : driver init/re-init internal variable/buffer only, and
-        //                            must not call tud_control_status(), driver's return value will have no effect.
-        //                            EP state has already affected (stalled/cleared)
-        if ( invoke_class_control(rhport, driver, p_request) ) ret = true;
-      }
-
-      if ( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
-      {
-        // Set complete callback = NULL since it can also stall the request.
-        usbd_control_set_complete_callback(NULL);
-      }
-
-      return ret;
     }
     }
     break;
     break;
 
 

+ 4 - 14
src/device/usbd_control.c

@@ -67,12 +67,7 @@ static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t con
 {
 {
   // Opposite to endpoint in Data Phase
   // Opposite to endpoint in Data Phase
   uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
   uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
-
-  TU_LOG2("  Queue EP %02X with zlp Status\r\n", ep_addr);
-
-  // status direction is reversed to one in the setup packet
-  // Note: Status must always be DATA1
-  return dcd_edpt_xfer(rhport, ep_addr, NULL, 0);
+  return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
 }
 }
 
 
 // Status phase
 // Status phase
@@ -101,9 +96,7 @@ static bool _data_stage_xact(uint8_t rhport)
     if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len);
     if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len);
   }
   }
 
 
-  TU_LOG2("  Queue EP %02X with %u bytes\r\n", ep_addr, xact_len);
-
-  return dcd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len);
+  return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len);
 }
 }
 
 
 // Transmit data to/from the control endpoint.
 // Transmit data to/from the control endpoint.
@@ -140,9 +133,6 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo
 // USBD API
 // USBD API
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
 
 
-//--------------------------------------------------------------------+
-// Prototypes
-//--------------------------------------------------------------------+
 void usbd_control_reset(void);
 void usbd_control_reset(void);
 void usbd_control_set_request(tusb_control_request_t const *request);
 void usbd_control_set_request(tusb_control_request_t const *request);
 void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp );
 void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp );
@@ -153,13 +143,13 @@ void usbd_control_reset(void)
   tu_varclr(&_ctrl_xfer);
   tu_varclr(&_ctrl_xfer);
 }
 }
 
 
-// TODO may find a better way
+// Set complete callback
 void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp )
 void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp )
 {
 {
   _ctrl_xfer.complete_cb = fp;
   _ctrl_xfer.complete_cb = fp;
 }
 }
 
 
-// useful for dcd_set_address where DCD is responsible for status response
+// for dcd_set_address where DCD is responsible for status response
 void usbd_control_set_request(tusb_control_request_t const *request)
 void usbd_control_set_request(tusb_control_request_t const *request)
 {
 {
   _ctrl_xfer.request       = (*request);
   _ctrl_xfer.request       = (*request);