From 84898a0bcb7b04f123f78057deac1d61997cbd76 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Tue, 29 Mar 2022 13:47:41 +0100 Subject: [PATCH 1/3] Implement USB CLEAR_FEATURE request for ENDPOINT_HALT. From USB 2.0, section 9.4.5: "For endpoints using data toggle, regardless of whether an endpoint has the Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the data toggle being reinitialized to DATA0." --- firmware/common/usb.c | 11 +++++++++ firmware/common/usb.h | 4 ++++ firmware/common/usb_standard_request.c | 33 +++++++++++++++++++++++++- firmware/common/usb_type.h | 4 ++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/firmware/common/usb.c b/firmware/common/usb.c index f8e4bd8c..0a36af42 100644 --- a/firmware/common/usb.c +++ b/firmware/common/usb.c @@ -302,6 +302,17 @@ void usb_endpoint_stall( // TODO: Also need to reset data toggle in both directions? } +void usb_endpoint_reset_data_toggle( + const usb_endpoint_t* const endpoint +) { + const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address); + if( usb_endpoint_is_in(endpoint->address) ) { + USB0_ENDPTCTRL(endpoint_number) |= USB0_ENDPTCTRL_TXR; + } else { + USB0_ENDPTCTRL(endpoint_number) |= USB0_ENDPTCTRL_RXR; + } +} + static void usb_controller_run() { USB0_USBCMD_D |= USB0_USBCMD_D_RS; } diff --git a/firmware/common/usb.h b/firmware/common/usb.h index aa21beb2..dcc2d876 100644 --- a/firmware/common/usb.h +++ b/firmware/common/usb.h @@ -70,6 +70,10 @@ void usb_endpoint_disable( const usb_endpoint_t* const endpoint ); +void usb_endpoint_reset_data_toggle( + const usb_endpoint_t* const endpoint +); + void usb_endpoint_flush( const usb_endpoint_t* const endpoint ); diff --git a/firmware/common/usb_standard_request.c b/firmware/common/usb_standard_request.c index 51d2ca29..7444368b 100644 --- a/firmware/common/usb_standard_request.c +++ b/firmware/common/usb_standard_request.c @@ -333,7 +333,6 @@ static usb_request_status_t usb_standard_request_get_configuration( } } - static usb_request_status_t usb_standard_request_get_status_setup( usb_endpoint_t* const endpoint ) { @@ -367,6 +366,35 @@ static usb_request_status_t usb_standard_request_get_status( } } +static usb_request_status_t usb_standard_request_clear_feature_setup( + usb_endpoint_t* const endpoint) +{ + switch (endpoint->setup.value) { + case USB_FEATURE_SELECTOR_ENDPOINT_HALT: + usb_endpoint_reset_data_toggle(endpoint); + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; + } +} + +static usb_request_status_t usb_standard_request_clear_feature( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) +{ + switch (stage) { + case USB_TRANSFER_STAGE_SETUP: + return usb_standard_request_clear_feature_setup(endpoint); + + case USB_TRANSFER_STAGE_DATA: + case USB_TRANSFER_STAGE_STATUS: + return USB_REQUEST_STATUS_OK; + + default: + return USB_REQUEST_STATUS_STALL; + } +} + /*********************************************************************/ usb_request_status_t usb_standard_request( @@ -389,6 +417,9 @@ usb_request_status_t usb_standard_request( case USB_STANDARD_REQUEST_GET_CONFIGURATION: return usb_standard_request_get_configuration(endpoint, stage); + case USB_STANDARD_REQUEST_CLEAR_FEATURE: + return usb_standard_request_clear_feature(endpoint, stage); + default: return USB_REQUEST_STATUS_STALL; } diff --git a/firmware/common/usb_type.h b/firmware/common/usb_type.h index 2a1b7cd1..3063b09d 100644 --- a/firmware/common/usb_type.h +++ b/firmware/common/usb_type.h @@ -70,6 +70,10 @@ typedef enum { USB_STANDARD_REQUEST_SYNCH_FRAME = 12, } usb_standard_request_t; +typedef enum { + USB_FEATURE_SELECTOR_ENDPOINT_HALT = 0, +} usb_feature_selector_t; + typedef enum { USB_SETUP_REQUEST_TYPE_shift = 5, USB_SETUP_REQUEST_TYPE_mask = 3 << USB_SETUP_REQUEST_TYPE_shift, From 2fba08cf422e64a21bd729043c8d536454a85d01 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Tue, 29 Mar 2022 23:40:08 +0100 Subject: [PATCH 2/3] Reset endpoint specified in request, not the one it arrived on. --- firmware/common/usb.c | 2 +- firmware/common/usb.h | 4 ++++ firmware/common/usb_standard_request.c | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/firmware/common/usb.c b/firmware/common/usb.c index 0a36af42..6cbb3296 100644 --- a/firmware/common/usb.c +++ b/firmware/common/usb.c @@ -44,7 +44,7 @@ usb_queue_head_t* usb_queue_head( return &usb_qh[USB_QH_INDEX(endpoint_address)]; } -static usb_endpoint_t* usb_endpoint_from_address( +usb_endpoint_t* usb_endpoint_from_address( const uint_fast8_t endpoint_address ) { return (usb_endpoint_t*)usb_queue_head(endpoint_address)->_reserved_0; diff --git a/firmware/common/usb.h b/firmware/common/usb.h index dcc2d876..69190517 100644 --- a/firmware/common/usb.h +++ b/firmware/common/usb.h @@ -58,6 +58,10 @@ void usb_set_address_deferred( const uint_fast8_t address ); +usb_endpoint_t* usb_endpoint_from_address( + const uint_fast8_t endpoint_address +); + void usb_endpoint_init( const usb_endpoint_t* const endpoint ); diff --git a/firmware/common/usb_standard_request.c b/firmware/common/usb_standard_request.c index 7444368b..b9e1e9fd 100644 --- a/firmware/common/usb_standard_request.c +++ b/firmware/common/usb_standard_request.c @@ -369,9 +369,12 @@ static usb_request_status_t usb_standard_request_get_status( static usb_request_status_t usb_standard_request_clear_feature_setup( usb_endpoint_t* const endpoint) { + switch (endpoint->setup.value) { case USB_FEATURE_SELECTOR_ENDPOINT_HALT: - usb_endpoint_reset_data_toggle(endpoint); + usb_endpoint_reset_data_toggle( + usb_endpoint_from_address(endpoint->setup.index) + ); return USB_REQUEST_STATUS_OK; default: return USB_REQUEST_STATUS_STALL; From 077095451a212bd0ebaf9fa7df4b8f6c566b19df Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Wed, 30 Mar 2022 00:34:32 +0100 Subject: [PATCH 3/3] Schedule ACK after CLEAR_FEATURE / ENDPOINT_HALT request. --- firmware/common/usb_standard_request.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/common/usb_standard_request.c b/firmware/common/usb_standard_request.c index b9e1e9fd..b3386f71 100644 --- a/firmware/common/usb_standard_request.c +++ b/firmware/common/usb_standard_request.c @@ -375,6 +375,7 @@ static usb_request_status_t usb_standard_request_clear_feature_setup( usb_endpoint_reset_data_toggle( usb_endpoint_from_address(endpoint->setup.index) ); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; default: return USB_REQUEST_STATUS_STALL;