remove the requirement of std SET/CLEAR_FEATURE must not return zlp status

This commit is contained in:
hathach 2021-02-11 11:22:02 +07:00
parent ba11bb2b80
commit 49bc97b0ca
2 changed files with 46 additions and 47 deletions

View File

@ -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 // Forward class request to its driver
ret = true; 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;

View File

@ -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;
return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
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);
} }
// 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 usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len);
return dcd_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);