diff --git a/src/device/usbd.c b/src/device/usbd.c index f6b00563d..d871a53d4 100644 --- a/src/device/usbd.c +++ b/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 _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 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" return invoke_class_control(rhport, driver, p_request); } + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { // 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) ); - 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 ) { case TUSB_REQ_GET_STATUS: @@ -730,40 +740,39 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; 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: - 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; // Unknown/Unsupported request 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; diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 8ed0ad1c0..d15380199 100644 --- a/src/device/usbd_control.c +++ b/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 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 @@ -101,9 +96,7 @@ static bool _data_stage_xact(uint8_t rhport) 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. @@ -140,9 +133,6 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo // USBD API //--------------------------------------------------------------------+ -//--------------------------------------------------------------------+ -// Prototypes -//--------------------------------------------------------------------+ void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); 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); } -// TODO may find a better way +// Set complete callback void usbd_control_set_complete_callback( usbd_control_xfer_cb_t 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) { _ctrl_xfer.request = (*request);