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

usbd better support suspend/resume

hathach 7 лет назад
Родитель
Сommit
491b5936d5
2 измененных файлов с 35 добавлено и 30 удалено
  1. 34 30
      src/device/usbd.c
  2. 1 0
      src/device/usbd_control.c

+ 34 - 30
src/device/usbd.c

@@ -262,18 +262,10 @@ void tud_task (void)
 
     if ( !osal_queue_receive(_usbd_q, &event) ) return;
 
-    // Skip event if device is not connected except BUS_RESET & UNPLUGGED & FUNC_CALL
-    if ( !(_usbd_dev.connected || event.event_id == DCD_EVENT_UNPLUGGED ||
-        event.event_id == DCD_EVENT_BUS_RESET || event.event_id == USBD_EVENT_FUNC_CALL) )
-    {
-      return;
-    }
-
     switch ( event.event_id )
     {
       case DCD_EVENT_BUS_RESET:
         usbd_reset(event.rhport);
-        _usbd_dev.connected = 1; // connected after bus reset
       break;
 
       case DCD_EVENT_UNPLUGGED:
@@ -284,6 +276,10 @@ void tud_task (void)
       break;
 
       case DCD_EVENT_SETUP_RECEIVED:
+        // Mark as connected after receiving 1st setup packet.
+        // But it is easier to set it every time instead of wasting time to check then set
+        _usbd_dev.connected = 1;
+
         // Process control request
         if ( !process_control_request(event.rhport, &event.setup_received) )
         {
@@ -294,27 +290,29 @@ void tud_task (void)
       break;
 
       case DCD_EVENT_XFER_COMPLETE:
-      {
-        // Invoke the class callback associated with the endpoint address
-        uint8_t const ep_addr = event.xfer_complete.ep_addr;
-
-        if ( 0 == tu_edpt_number(ep_addr) )
+        // Only handle xfer callback in ready state
+        // if (_usbd_dev.connected && !_usbd_dev.suspended)
         {
-          // control transfer DATA stage callback
-          usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
-        }
-        else
-        {
-          uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)];
-          TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,);
+          // Invoke the class callback associated with the endpoint address
+          uint8_t const ep_addr = event.xfer_complete.ep_addr;
 
-          usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+          if ( 0 == tu_edpt_number(ep_addr) )
+          {
+            // control transfer DATA stage callback
+            usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+          }
+          else
+          {
+            uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)];
+            TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,);
+
+            usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+          }
         }
-      }
       break;
 
       case DCD_EVENT_SUSPEND:
-        if (tud_suspend_cb) tud_suspend_cb( _usbd_dev.remote_wakeup_en );
+        if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
       break;
 
       case DCD_EVENT_RESUME:
@@ -641,16 +639,22 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
     break;
 
     case DCD_EVENT_SUSPEND:
-      // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the
-      // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume
-      // are submitted by DCD before the actual UNPLUGGED
-      _usbd_dev.suspended = 1;
-      osal_queue_send(_usbd_q, event, in_isr);
+      // NOTE: When plugging/unplugging device, the D+/D- state are unstable and can accidentally meet the
+      // SUSPEND condition ( Idle for 3ms ). Some MCUs such as samd don't distinguish suspend vs disconnect as well.
+      // We will skip handling SUSPEND/RESUME event if not currently connected
+      if ( _usbd_dev.connected )
+      {
+        _usbd_dev.suspended = 1;
+        osal_queue_send(_usbd_q, event, in_isr);
+      }
     break;
 
     case DCD_EVENT_RESUME:
-      _usbd_dev.suspended = 0;
-      osal_queue_send(_usbd_q, event, in_isr);
+      if ( _usbd_dev.connected )
+      {
+        _usbd_dev.suspended = 0;
+        osal_queue_send(_usbd_q, event, in_isr);
+      }
     break;
 
     case DCD_EVENT_SETUP_RECEIVED:

+ 1 - 0
src/device/usbd_control.c

@@ -114,6 +114,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
 
   if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT )
   {
+    TU_VERIFY(_control_state.buffer);
     memcpy(_control_state.buffer, _usbd_ctrl_buf, xferred_bytes);
   }