Add typed request return value that indicates request is OK or requires endpoint STALL.

Changed vendor request to a lookup table, instead of an ever-growing switch statement.
This commit is contained in:
Jared Boone
2012-10-18 19:47:25 -07:00
parent e8b30f3489
commit 526a8e9e7a
5 changed files with 121 additions and 132 deletions

View File

@ -196,7 +196,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
sgpio_cpld_stream_enable(); sgpio_cpld_stream_enable();
} }
bool usb_vendor_request_set_transceiver_mode( usb_request_status_t usb_vendor_request_set_transceiver_mode(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -205,22 +205,22 @@ bool usb_vendor_request_set_transceiver_mode(
case 1: case 1:
set_transceiver_mode(TRANSCEIVER_MODE_RX); set_transceiver_mode(TRANSCEIVER_MODE_RX);
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return true; return USB_REQUEST_STATUS_OK;
case 2: case 2:
set_transceiver_mode(TRANSCEIVER_MODE_TX); set_transceiver_mode(TRANSCEIVER_MODE_TX);
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return true; return USB_REQUEST_STATUS_OK;
default: default:
return false; return USB_REQUEST_STATUS_STALL;
} }
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
bool usb_vendor_request_write_max2837( usb_request_status_t usb_vendor_request_write_max2837(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -229,16 +229,16 @@ bool usb_vendor_request_write_max2837(
if( endpoint->setup.value < 0x3ff ) { if( endpoint->setup.value < 0x3ff ) {
max2837_reg_write(endpoint->setup.index, endpoint->setup.value); max2837_reg_write(endpoint->setup.index, endpoint->setup.value);
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return true; return USB_REQUEST_STATUS_OK;
} }
} }
return false; return USB_REQUEST_STATUS_STALL;
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
bool usb_vendor_request_read_max2837( usb_request_status_t usb_vendor_request_read_max2837(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -249,15 +249,15 @@ bool usb_vendor_request_read_max2837(
endpoint->buffer[1] = value >> 8; endpoint->buffer[1] = value >> 8;
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2); usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2);
usb_endpoint_schedule_ack(endpoint->out); usb_endpoint_schedule_ack(endpoint->out);
return true; return USB_REQUEST_STATUS_OK;
} }
return false; return USB_REQUEST_STATUS_STALL;
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
bool usb_vendor_request_write_si5351c( usb_request_status_t usb_vendor_request_write_si5351c(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -266,16 +266,16 @@ bool usb_vendor_request_write_si5351c(
if( endpoint->setup.value < 256 ) { if( endpoint->setup.value < 256 ) {
si5351c_write_single(endpoint->setup.index, endpoint->setup.value); si5351c_write_single(endpoint->setup.index, endpoint->setup.value);
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return true; return USB_REQUEST_STATUS_OK;
} }
} }
return false; return USB_REQUEST_STATUS_STALL;
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
bool usb_vendor_request_read_si5351c( usb_request_status_t usb_vendor_request_read_si5351c(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -285,15 +285,15 @@ bool usb_vendor_request_read_si5351c(
endpoint->buffer[0] = value; endpoint->buffer[0] = value;
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1);
usb_endpoint_schedule_ack(endpoint->out); usb_endpoint_schedule_ack(endpoint->out);
return true; return USB_REQUEST_STATUS_OK;
} }
return false; return USB_REQUEST_STATUS_STALL;
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
bool usb_vendor_request_set_sample_rate( usb_request_status_t usb_vendor_request_set_sample_rate(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -301,15 +301,15 @@ bool usb_vendor_request_set_sample_rate(
const uint32_t sample_rate = (endpoint->setup.index << 16) | endpoint->setup.value; const uint32_t sample_rate = (endpoint->setup.index << 16) | endpoint->setup.value;
if( sample_rate_set(sample_rate) ) { if( sample_rate_set(sample_rate) ) {
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return true; return USB_REQUEST_STATUS_OK;
} }
return false; return USB_REQUEST_STATUS_STALL;
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
bool usb_vendor_request_set_baseband_filter_bandwidth( usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
@ -317,56 +317,42 @@ bool usb_vendor_request_set_baseband_filter_bandwidth(
const uint32_t bandwidth = (endpoint->setup.index << 16) | endpoint->setup.value; const uint32_t bandwidth = (endpoint->setup.index << 16) | endpoint->setup.value;
if( baseband_filter_bandwidth_set(bandwidth) ) { if( baseband_filter_bandwidth_set(bandwidth) ) {
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return true; return USB_REQUEST_STATUS_OK;
} }
return false; return USB_REQUEST_STATUS_STALL;
} else { } else {
return true; return USB_REQUEST_STATUS_OK;
} }
} }
void usb_vendor_request( static const usb_request_handler_fn vendor_request_handler[] = {
NULL,
usb_vendor_request_set_transceiver_mode,
usb_vendor_request_write_max2837,
usb_vendor_request_read_max2837,
usb_vendor_request_write_si5351c,
usb_vendor_request_read_si5351c,
usb_vendor_request_set_sample_rate,
usb_vendor_request_set_baseband_filter_bandwidth,
};
static const uint32_t vendor_request_handler_count =
sizeof(vendor_request_handler) / sizeof(vendor_request_handler[0]);
usb_request_status_t usb_vendor_request(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
bool success = false; usb_request_status_t status = USB_REQUEST_STATUS_STALL;
switch(endpoint->setup.request) { if( endpoint->setup.request < vendor_request_handler_count ) {
case 1: usb_request_handler_fn handler = vendor_request_handler[endpoint->setup.request];
success = usb_vendor_request_set_transceiver_mode(endpoint, stage); if( handler ) {
break; status = handler(endpoint, stage);
}
case 2:
success = usb_vendor_request_write_max2837(endpoint, stage);
break;
case 3:
success = usb_vendor_request_read_max2837(endpoint, stage);
break;
case 4:
success = usb_vendor_request_write_si5351c(endpoint, stage);
break;
case 5:
success = usb_vendor_request_read_si5351c(endpoint, stage);
break;
case 6:
success = usb_vendor_request_set_sample_rate(endpoint, stage);
break;
case 7:
success = usb_vendor_request_set_baseband_filter_bandwidth(endpoint, stage);
break;
default:
break;
} }
if( success != true ) { return status;
usb_endpoint_stall(endpoint);
}
} }
const usb_request_handlers_t usb_request_handlers = { const usb_request_handlers_t usb_request_handlers = {

View File

@ -28,6 +28,7 @@ static void usb_request(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
usb_request_handler_fn handler = 0; usb_request_handler_fn handler = 0;
switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) { switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) {
@ -49,8 +50,10 @@ static void usb_request(
} }
if( handler ) { if( handler ) {
handler(endpoint, stage); status = handler(endpoint, stage);
} else { }
if( status != USB_REQUEST_STATUS_OK ) {
// USB 2.0 section 9.2.7 "Request Error" // USB 2.0 section 9.2.7 "Request Error"
usb_endpoint_stall(endpoint); usb_endpoint_stall(endpoint);
} }

View File

@ -37,7 +37,12 @@ typedef enum {
USB_TRANSFER_STAGE_STATUS, USB_TRANSFER_STAGE_STATUS,
} usb_transfer_stage_t; } usb_transfer_stage_t;
typedef void (*usb_request_handler_fn)( typedef enum {
USB_REQUEST_STATUS_OK = 0,
USB_REQUEST_STATUS_STALL = 1,
} usb_request_status_t;
typedef usb_request_status_t (*usb_request_handler_fn)(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
); );

View File

@ -63,7 +63,7 @@ extern bool usb_set_configuration(
const uint_fast8_t configuration_number const uint_fast8_t configuration_number
); );
static void usb_send_descriptor( static usb_request_status_t usb_send_descriptor(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
uint8_t* const descriptor_data uint8_t* const descriptor_data
) { ) {
@ -77,113 +77,110 @@ static void usb_send_descriptor(
descriptor_data, descriptor_data,
(setup_length > descriptor_length) ? descriptor_length : setup_length (setup_length > descriptor_length) ? descriptor_length : setup_length
); );
usb_endpoint_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
} }
static void usb_send_descriptor_string( static usb_request_status_t usb_send_descriptor_string(
usb_endpoint_t* const endpoint usb_endpoint_t* const endpoint
) { ) {
uint_fast8_t index = endpoint->setup.value_l; uint_fast8_t index = endpoint->setup.value_l;
for( uint_fast8_t i=0; usb_descriptor_strings[i] != 0; i++ ) { for( uint_fast8_t i=0; usb_descriptor_strings[i] != 0; i++ ) {
if( i == index ) { if( i == index ) {
usb_send_descriptor(endpoint, usb_descriptor_strings[i]); return usb_send_descriptor(endpoint, usb_descriptor_strings[i]);
return;
} }
} }
usb_endpoint_stall(endpoint); return USB_REQUEST_STATUS_STALL;
} }
static void usb_standard_request_get_descriptor_setup( static usb_request_status_t usb_standard_request_get_descriptor_setup(
usb_endpoint_t* const endpoint usb_endpoint_t* const endpoint
) { ) {
switch( endpoint->setup.value_h ) { switch( endpoint->setup.value_h ) {
case USB_DESCRIPTOR_TYPE_DEVICE: case USB_DESCRIPTOR_TYPE_DEVICE:
usb_send_descriptor(endpoint, usb_descriptor_device); return usb_send_descriptor(endpoint, usb_descriptor_device);
break;
case USB_DESCRIPTOR_TYPE_CONFIGURATION: case USB_DESCRIPTOR_TYPE_CONFIGURATION:
// TODO: Duplicated code. Refactor. // TODO: Duplicated code. Refactor.
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) { if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed);
} else { } else {
usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed);
} }
break;
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
usb_send_descriptor(endpoint, usb_descriptor_device_qualifier); return usb_send_descriptor(endpoint, usb_descriptor_device_qualifier);
break;
case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION: case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
// TODO: Duplicated code. Refactor. // TODO: Duplicated code. Refactor.
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) { if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed);
} else { } else {
usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed);
} }
break;
case USB_DESCRIPTOR_TYPE_STRING: case USB_DESCRIPTOR_TYPE_STRING:
usb_send_descriptor_string(endpoint); return usb_send_descriptor_string(endpoint);
break;
case USB_DESCRIPTOR_TYPE_INTERFACE: case USB_DESCRIPTOR_TYPE_INTERFACE:
case USB_DESCRIPTOR_TYPE_ENDPOINT: case USB_DESCRIPTOR_TYPE_ENDPOINT:
default: default:
usb_endpoint_stall(endpoint); return USB_REQUEST_STATUS_STALL;
break;
} }
} }
static void usb_standard_request_get_descriptor( static usb_request_status_t usb_standard_request_get_descriptor(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
switch( stage ) { switch( stage ) {
case USB_TRANSFER_STAGE_SETUP: case USB_TRANSFER_STAGE_SETUP:
usb_standard_request_get_descriptor_setup(endpoint); return usb_standard_request_get_descriptor_setup(endpoint);
usb_endpoint_schedule_ack(endpoint->out);
break;
case USB_TRANSFER_STAGE_DATA: case USB_TRANSFER_STAGE_DATA:
break;
case USB_TRANSFER_STAGE_STATUS: case USB_TRANSFER_STAGE_STATUS:
break; return USB_REQUEST_STATUS_OK;
default:
return USB_REQUEST_STATUS_STALL;
} }
} }
/*********************************************************************/ /*********************************************************************/
static void usb_standard_request_set_address( static usb_request_status_t usb_standard_request_set_address_setup(
usb_endpoint_t* const endpoint
) {
usb_set_address_deferred(endpoint->device, endpoint->setup.value_l);
usb_endpoint_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
static usb_request_status_t usb_standard_request_set_address(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
switch( stage ) { switch( stage ) {
case USB_TRANSFER_STAGE_SETUP: case USB_TRANSFER_STAGE_SETUP:
usb_set_address_deferred(endpoint->device, endpoint->setup.value_l); return usb_standard_request_set_address_setup(endpoint);
usb_endpoint_schedule_ack(endpoint->in);
break;
case USB_TRANSFER_STAGE_DATA: case USB_TRANSFER_STAGE_DATA:
break;
case USB_TRANSFER_STAGE_STATUS: case USB_TRANSFER_STAGE_STATUS:
/* NOTE: Not necessary to set address here, as DEVICEADR.USBADRA bit /* NOTE: Not necessary to set address here, as DEVICEADR.USBADRA bit
* will cause controller to automatically perform set address * will cause controller to automatically perform set address
* operation on IN ACK. * operation on IN ACK.
*/ */
break; return USB_REQUEST_STATUS_OK;
default: default:
break; return USB_REQUEST_STATUS_STALL;
} }
} }
/*********************************************************************/ /*********************************************************************/
static void usb_standard_request_set_configuration_setup( static usb_request_status_t usb_standard_request_set_configuration_setup(
usb_endpoint_t* const endpoint usb_endpoint_t* const endpoint
) { ) {
const uint8_t usb_configuration = endpoint->setup.value_l; const uint8_t usb_configuration = endpoint->setup.value_l;
@ -193,32 +190,32 @@ static void usb_standard_request_set_configuration_setup(
usb_set_address_immediate(endpoint->device, 0); usb_set_address_immediate(endpoint->device, 0);
} }
usb_endpoint_schedule_ack(endpoint->in); usb_endpoint_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
} else { } else {
usb_endpoint_stall(endpoint); return USB_REQUEST_STATUS_STALL;
} }
} }
static void usb_standard_request_set_configuration( static usb_request_status_t usb_standard_request_set_configuration(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
switch( stage ) { switch( stage ) {
case USB_TRANSFER_STAGE_SETUP: case USB_TRANSFER_STAGE_SETUP:
usb_standard_request_set_configuration_setup(endpoint); return usb_standard_request_set_configuration_setup(endpoint);
break;
case USB_TRANSFER_STAGE_DATA: case USB_TRANSFER_STAGE_DATA:
break;
case USB_TRANSFER_STAGE_STATUS: case USB_TRANSFER_STAGE_STATUS:
break; return USB_REQUEST_STATUS_OK;
default:
return USB_REQUEST_STATUS_STALL;
} }
} }
/*********************************************************************/ /*********************************************************************/
static void usb_standard_request_get_configuration_setup( static usb_request_status_t usb_standard_request_get_configuration_setup(
usb_endpoint_t* const endpoint usb_endpoint_t* const endpoint
) { ) {
if( endpoint->setup.length == 1 ) { if( endpoint->setup.length == 1 ) {
@ -227,52 +224,50 @@ static void usb_standard_request_get_configuration_setup(
endpoint->buffer[0] = endpoint->device->configuration->number; endpoint->buffer[0] = endpoint->device->configuration->number;
} }
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1);
usb_endpoint_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
} else { } else {
usb_endpoint_stall(endpoint); return USB_REQUEST_STATUS_STALL;
} }
} }
static void usb_standard_request_get_configuration( static usb_request_status_t usb_standard_request_get_configuration(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
switch( stage ) { switch( stage ) {
case USB_TRANSFER_STAGE_SETUP: case USB_TRANSFER_STAGE_SETUP:
usb_standard_request_get_configuration_setup(endpoint); return usb_standard_request_get_configuration_setup(endpoint);
usb_endpoint_schedule_ack(endpoint->out);
break;
case USB_TRANSFER_STAGE_DATA: case USB_TRANSFER_STAGE_DATA:
break;
case USB_TRANSFER_STAGE_STATUS: case USB_TRANSFER_STAGE_STATUS:
break; return USB_REQUEST_STATUS_OK;
default:
return USB_REQUEST_STATUS_STALL;
} }
} }
/*********************************************************************/ /*********************************************************************/
void usb_standard_request( usb_request_status_t usb_standard_request(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
) { ) {
switch( endpoint->setup.request ) { switch( endpoint->setup.request ) {
case USB_STANDARD_REQUEST_GET_DESCRIPTOR: case USB_STANDARD_REQUEST_GET_DESCRIPTOR:
usb_standard_request_get_descriptor(endpoint, stage); return usb_standard_request_get_descriptor(endpoint, stage);
break;
case USB_STANDARD_REQUEST_SET_ADDRESS: case USB_STANDARD_REQUEST_SET_ADDRESS:
usb_standard_request_set_address(endpoint, stage); return usb_standard_request_set_address(endpoint, stage);
break;
case USB_STANDARD_REQUEST_SET_CONFIGURATION: case USB_STANDARD_REQUEST_SET_CONFIGURATION:
usb_standard_request_set_configuration(endpoint, stage); return usb_standard_request_set_configuration(endpoint, stage);
break;
case USB_STANDARD_REQUEST_GET_CONFIGURATION: case USB_STANDARD_REQUEST_GET_CONFIGURATION:
usb_standard_request_get_configuration(endpoint, stage); return usb_standard_request_get_configuration(endpoint, stage);
break;
default:
return USB_REQUEST_STATUS_STALL;
} }
} }

View File

@ -25,7 +25,7 @@
#include "usb_type.h" #include "usb_type.h"
#include "usb_request.h" #include "usb_request.h"
void usb_standard_request( usb_request_status_t usb_standard_request(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
); );