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,