From 491b5936d5abba5030cceea35a4aa31c470e5782 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Apr 2019 01:30:01 +0700 Subject: [PATCH] usbd better support suspend/resume --- src/device/usbd.c | 64 +++++++++++++++++++++------------------ src/device/usbd_control.c | 1 + 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 7b87d1944..cdbd6db5b 100644 --- a/src/device/usbd.c +++ b/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: diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 24234f4d2..8460a11b0 100644 --- a/src/device/usbd_control.c +++ b/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); }