diff --git a/firmware/common/usb.c b/firmware/common/usb.c index f8e4bd8c..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; @@ -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..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 ); @@ -70,6 +74,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..b3386f71 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,39 @@ 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( + usb_endpoint_from_address(endpoint->setup.index) + ); + usb_transfer_schedule_ack(endpoint->in); + 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 +421,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,