From 08b04cc5870bc78e653a9093d186999a5d263407 Mon Sep 17 00:00:00 2001 From: Frank Gevaerts Date: Sun, 19 Apr 2009 19:53:32 +0000 Subject: reorganise usb_core.c a bit, to make the code more readable and more maintainable (FS#10150 by Tomer Shalev)) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20748 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/usb_ch9.h | 18 ++ firmware/export/usb_core.h | 8 +- firmware/usbstack/usb_core.c | 519 +++++++++++++++++++++++-------------------- 3 files changed, 299 insertions(+), 246 deletions(-) diff --git a/firmware/export/usb_ch9.h b/firmware/export/usb_ch9.h index 560a737354..f05dbd3265 100644 --- a/firmware/export/usb_ch9.h +++ b/firmware/export/usb_ch9.h @@ -109,6 +109,24 @@ #define USB_REQ_GET_INTERFACE 0x0A #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) Hubs may also support a + * new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend. + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ +#define USB_DEVICE_BATTERY 2 /* (wireless) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ +#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ +#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + /** * struct usb_ctrlrequest - SETUP data for a USB device control request diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index ba2820b1ad..aac84756f5 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h @@ -42,16 +42,16 @@ struct usb_class_driver; void usb_core_init(void); void usb_core_exit(void); void usb_core_control_request(struct usb_ctrlrequest* req); -void usb_core_transfer_complete(int endpoint, int dir, int status, int length); +void usb_core_transfer_complete(int endpoint,int dir,int status,int length); void usb_core_bus_reset(void); bool usb_core_any_exclusive_storage(void); void usb_core_enable_driver(int driver,bool enabled); -bool usb_core_driver_enabled (int driver); +bool usb_core_driver_enabled(int driver); void usb_core_handle_transfer_completion( - struct usb_transfer_completion_event_data* event); + struct usb_transfer_completion_event_data* event); int usb_core_ack_control(struct usb_ctrlrequest* req); -int usb_core_request_endpoint(int dir, struct usb_class_driver *drv); +int usb_core_request_endpoint(int dir,struct usb_class_driver* drv); void usb_core_release_endpoint(int dir); #ifdef HAVE_HOTSWAP diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index f6373b8945..8c235723ad 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -167,7 +167,7 @@ static enum { DEFAULT, ADDRESS, CONFIGURED } usb_state; static int usb_core_num_interfaces; typedef void (*completion_handler_t)(int ep,int dir, int status, int length); -typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, unsigned char *dest); +typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, unsigned char* dest); static struct { @@ -435,13 +435,13 @@ static void usb_core_set_serial_function_id(void) usb_string_iSerial.wString[0] = hex[id]; } -int usb_core_request_endpoint(int dir, struct usb_class_driver *drv) +int usb_core_request_endpoint(int dir, struct usb_class_driver* drv) { int ret, ep; ret = usb_drv_request_endpoint(dir); - if (ret == -1) + if (ret==-1) return -1; ep = ret & 0x7f; @@ -494,270 +494,305 @@ static void allocate_interfaces_and_endpoints(void) usb_core_num_interfaces = interface; } -static void usb_core_control_request_handler(struct usb_ctrlrequest* req) +static void control_request_handler_drivers(struct usb_ctrlrequest* req) { int i; - if(usb_state == DEFAULT) { - set_serial_descriptor(); - usb_core_set_serial_function_id(); - - allocate_interfaces_and_endpoints(); + bool handled=false; + for(i=0;iwIndex) && + drivers[i].last_interface > (req->wIndex)) + { + handled = drivers[i].control_request(req, response_data); + if(handled) + break; + } } + if(!handled) { + /* nope. flag error */ + logf("bad req:desc %d:%d", req->bRequest, req->wValue>>8); + usb_drv_stall(EP_CONTROL, true,true); + usb_core_ack_control(req); + } +} - switch(req->bRequestType & 0x1f) { - case 0: /* Device */ - switch (req->bRequest) { - case USB_REQ_GET_CONFIGURATION: { - logf("usb_core: GET_CONFIG"); - if (usb_state == ADDRESS) - response_data[0] = 0; - else - response_data[0] = 1; - if(usb_drv_send(EP_CONTROL, response_data, 1)!= 0) - break; - usb_core_ack_control(req); - break; - } - case USB_REQ_SET_CONFIGURATION: { - logf("usb_core: SET_CONFIG"); - usb_drv_cancel_all_transfers(); - if (req->wValue) { - usb_state = CONFIGURED; - for(i=0;iwLength; + int index = req->wValue & 0xff; + + switch(req->wValue>>8) { /* type */ + case USB_DT_DEVICE: + ptr = &device_descriptor; + size = sizeof(struct usb_device_descriptor); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + case USB_DT_CONFIG: { + int i, max_packet_size; + + if(req->wValue>>8==USB_DT_CONFIG) { + max_packet_size=(usb_drv_port_speed() ? 512 : 64); + config_descriptor.bDescriptorType=USB_DT_CONFIG; } - case USB_REQ_SET_ADDRESS: { - unsigned char address = req->wValue; - logf("usb_core: SET_ADR %d", address); - if(usb_core_ack_control(req)!=0) - break; - usb_drv_cancel_all_transfers(); - usb_address = address; - usb_drv_set_address(usb_address); - usb_state = ADDRESS; - break; + else { + max_packet_size=(usb_drv_port_speed() ? 64 : 512); + config_descriptor.bDescriptorType = + USB_DT_OTHER_SPEED_CONFIG; } - case USB_REQ_GET_DESCRIPTOR: { - int index = req->wValue & 0xff; - int length = req->wLength; - int size; - const void* ptr = NULL; - logf("usb_core: GET_DESC %d", req->wValue >> 8); - - switch (req->wValue >> 8) { /* type */ - case USB_DT_DEVICE: - ptr = &device_descriptor; - size = sizeof(struct usb_device_descriptor); - break; - - case USB_DT_OTHER_SPEED_CONFIG: - case USB_DT_CONFIG: { - int max_packet_size; - - if(req->wValue >> 8 == USB_DT_CONFIG) { - if(usb_drv_port_speed()) - max_packet_size=512; - else - max_packet_size=64; - config_descriptor.bDescriptorType=USB_DT_CONFIG; - } - else { - if(usb_drv_port_speed()) - max_packet_size=64; - else - max_packet_size=512; - config_descriptor.bDescriptorType = - USB_DT_OTHER_SPEED_CONFIG; - } - size = sizeof(struct usb_config_descriptor); - - for(i=0;ibLength; - ptr = usb_strings[index]; - } - else { - logf("bad string id %d", index); - usb_drv_stall(EP_CONTROL, true,true); - } - break; - - case USB_DT_DEVICE_QUALIFIER: - ptr = &qualifier_descriptor; - size = sizeof (struct usb_qualifier_descriptor); - break; - - default: - logf("bad desc %d", req->wValue >> 8); - usb_drv_stall(EP_CONTROL, true,true); - break; - } + size = sizeof(struct usb_config_descriptor); - if (ptr) { - length = MIN(size, length); + for(i=0;iwValue == 2) { /* TEST_MODE */ - int mode=req->wIndex>>8; - usb_core_ack_control(req); - usb_drv_set_test_mode(mode); - } - break; - case USB_REQ_GET_STATUS: - response_data[0]= 0; - response_data[1]= 0; - if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) - break; - usb_core_ack_control(req); - break; - default: - break; + case USB_DT_STRING: + logf("STRING %d",index); + if ((unsigned)index < (sizeof(usb_strings)/ + sizeof(struct usb_string_descriptor*))) { + size = usb_strings[index]->bLength; + ptr = usb_strings[index]; + } + else { + logf("bad string id %d",index); + usb_drv_stall(EP_CONTROL,true,true); } break; - case 1: /* Interface */ - switch (req->bRequest) { - case USB_REQ_SET_INTERFACE: - logf("usb_core: SET_INTERFACE"); - usb_core_ack_control(req); - break; - case USB_REQ_GET_INTERFACE: - logf("usb_core: GET_INTERFACE"); - response_data[0] = 0; - if(usb_drv_send(EP_CONTROL, response_data, 1)!=0) - break; - usb_core_ack_control(req); - break; - case USB_REQ_CLEAR_FEATURE: - break; - case USB_REQ_SET_FEATURE: - break; - case USB_REQ_GET_STATUS: - response_data[0]= 0; - response_data[1]= 0; - if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) - break; + case USB_DT_DEVICE_QUALIFIER: + ptr = &qualifier_descriptor; + size = sizeof(struct usb_qualifier_descriptor); + break; + + default: + logf("ctrl desc."); + handled = false; + control_request_handler_drivers(req); + break; + } + + if (ptr) { + logf("data %d (%d)",size,length); + length = MIN(size,length); + + if (ptr != response_data) { + memcpy(response_data,ptr,length); + } + + if(usb_drv_send(EP_CONTROL,response_data,length)) + return; + } + if (handled) + usb_core_ack_control(req); +} + +static void request_handler_device(struct usb_ctrlrequest* req) +{ + int i; + + switch(req->bRequest) { + case USB_REQ_GET_CONFIGURATION: { + logf("usb_core: GET_CONFIG"); + response_data[0] = (usb_state == ADDRESS ? 0 : 1); + if(!usb_drv_send(EP_CONTROL, response_data, 1)) usb_core_ack_control(req); - break; - default: { - bool handled=false; + break; + } + case USB_REQ_SET_CONFIGURATION: { + logf("usb_core: SET_CONFIG"); + usb_drv_cancel_all_transfers(); + if(req->wValue) { + usb_state = CONFIGURED; for(i=0;iwIndex) && - drivers[i].last_interface > (req->wIndex)) - { - handled = drivers[i].control_request(req, response_data); - } - } - if(!handled) { - /* nope. flag error */ - logf("usb bad req %d", req->bRequest); - usb_drv_stall(EP_CONTROL, true,true); - usb_core_ack_control(req); + if(drivers[i].enabled && drivers[i].init_connection) + drivers[i].init_connection(); } - break; } + else { + usb_state = ADDRESS; + } + usb_core_ack_control(req); + break; } - break; - case 2: /* Endpoint */ - switch (req->bRequest) { - case USB_REQ_CLEAR_FEATURE: - if (req->wValue == 0 ) /* ENDPOINT_HALT */ - usb_drv_stall(req->wIndex & 0xf, false, - (req->wIndex & 0x80) !=0); - usb_core_ack_control(req); + case USB_REQ_SET_ADDRESS: { + unsigned char address = req->wValue; + logf("usb_core: SET_ADR %d", address); + if(usb_core_ack_control(req)) break; - case USB_REQ_SET_FEATURE: - if (req->wValue == 0 ) /* ENDPOINT_HALT */ - usb_drv_stall(req->wIndex & 0xf, true, - (req->wIndex & 0x80) !=0); - usb_core_ack_control(req); + usb_drv_cancel_all_transfers(); + usb_address = address; + usb_drv_set_address(usb_address); + usb_state = ADDRESS; + break; + } + case USB_REQ_GET_DESCRIPTOR: + logf("usb_core: GET_DESC %d", req->wValue>>8); + request_handler_device_get_descriptor(req); + break; + case USB_REQ_CLEAR_FEATURE: + break; + case USB_REQ_SET_FEATURE: + if(req->wValue==USB_DEVICE_TEST_MODE) { + int mode=req->wIndex>>8; + usb_core_ack_control(req); + usb_drv_set_test_mode(mode); + } + break; + case USB_REQ_GET_STATUS: + response_data[0]= 0; + response_data[1]= 0; + if(!usb_drv_send(EP_CONTROL, response_data, 2)) + usb_core_ack_control(req); + break; + default: + break; + } +} + +static void request_handler_interface_standard(struct usb_ctrlrequest* req) +{ + switch (req->bRequest) + { + case USB_REQ_SET_INTERFACE: + logf("usb_core: SET_INTERFACE"); + usb_core_ack_control(req); + break; + + case USB_REQ_GET_INTERFACE: + logf("usb_core: GET_INTERFACE"); + response_data[0]=0; + if(!usb_drv_send(EP_CONTROL,response_data,1)) + usb_core_ack_control(req); + break; + case USB_REQ_CLEAR_FEATURE: + break; + case USB_REQ_SET_FEATURE: + break; + case USB_REQ_GET_STATUS: + response_data[0]=0; + response_data[1]=0; + if(!usb_drv_send(EP_CONTROL, response_data, 2)) + usb_core_ack_control(req); + break; + default: + control_request_handler_drivers(req); + break; + } +} + +static void request_handler_interface(struct usb_ctrlrequest* req) +{ + switch(req->bRequestType & USB_TYPE_MASK) { + case USB_TYPE_STANDARD: + request_handler_interface_standard(req); + break; + case USB_TYPE_CLASS: + control_request_handler_drivers(req); + break; + case USB_TYPE_VENDOR: + break; + } +} + +static void request_handler_endpoint(struct usb_ctrlrequest* req) +{ + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + if (req->wValue==USB_ENDPOINT_HALT) { + usb_drv_stall(req->wIndex & 0xf, false, + (req->wIndex & USB_DIR_IN)!=0); + } + usb_core_ack_control(req); + break; + case USB_REQ_SET_FEATURE: + if (req->wValue==USB_ENDPOINT_HALT) { + usb_drv_stall(req->wIndex & 0xf,true, + (req->wIndex & USB_DIR_IN)!=0); + } + usb_core_ack_control(req); + break; + case USB_REQ_GET_STATUS: + response_data[0]=0; + response_data[1]=0; + logf("usb_core: GET_STATUS"); + if(req->wIndex>0) { + response_data[0]=usb_drv_stalled(req->wIndex & 0xf, + (req->wIndex & USB_DIR_IN)!=0); + } + if(!usb_drv_send(EP_CONTROL,response_data,2)) + usb_core_ack_control(req); + break; + default: { + bool handled; + control_handler_t control_handler; + + control_handler=ep_data[req->wIndex & 0xf].control_handler[0]; + if (!control_handler) break; - case USB_REQ_GET_STATUS: - response_data[0]= 0; - response_data[1]= 0; - logf("usb_core: GET_STATUS"); - if(req->wIndex>0) - response_data[0] = usb_drv_stalled(req->wIndex&0xf, - (req->wIndex&0x80)!=0); - if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) - break; + + handled=control_handler(req, response_data); + if (!handled) { + /* nope. flag error */ + logf("usb bad req %d",req->bRequest); + usb_drv_stall(EP_CONTROL,true,true); usb_core_ack_control(req); - break; - default: { - bool handled=false; - if(ep_data[req->wIndex & 0xf].control_handler[0] != NULL) { - handled = ep_data[req->wIndex & 0xf].control_handler[0](req, - response_data); - } - if(!handled) { - /* nope. flag error */ - logf("usb bad req %d", req->bRequest); - usb_drv_stall(EP_CONTROL, true,true); - usb_core_ack_control(req); - } - break; } + break; } } - logf("control handled"); +} + +/* Handling USB requests starts here */ +static void usb_core_control_request_handler(struct usb_ctrlrequest* req) +{ + if (usb_state==DEFAULT) { + set_serial_descriptor(); + usb_core_set_serial_function_id(); + + allocate_interfaces_and_endpoints(); + } + + switch(req->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + request_handler_device(req); + break; + case USB_RECIP_INTERFACE: + request_handler_interface(req); + break; + case USB_RECIP_ENDPOINT: + request_handler_endpoint(req); + break; + case USB_RECIP_OTHER: + logf("unsupported recipient"); + break; + } + //logf("control handled"); } /* called by usb_drv_int() */ void usb_core_bus_reset(void) { - usb_address = 0; - usb_state = DEFAULT; + usb_address=0; + usb_state=DEFAULT; } /* called by usb_drv_transfer_completed() */ -void usb_core_transfer_complete(int endpoint, int dir, int status,int length) +void usb_core_transfer_complete(int endpoint,int dir,int status,int length) { struct usb_transfer_completion_event_data *completion_event; @@ -767,7 +802,7 @@ void usb_core_transfer_complete(int endpoint, int dir, int status,int length) break; default: - completion_event = &ep_data[endpoint].completion_event; + completion_event=&ep_data[endpoint].completion_event; completion_event->endpoint=endpoint; completion_event->dir=dir; @@ -783,12 +818,12 @@ void usb_core_transfer_complete(int endpoint, int dir, int status,int length) /* called by usb_drv_int() */ void usb_core_control_request(struct usb_ctrlrequest* req) { - struct usb_transfer_completion_event_data *completion_event = + struct usb_transfer_completion_event_data* completion_event = &ep_data[0].completion_event; completion_event->endpoint=0; completion_event->dir=0; - completion_event->data=(void *)req; + completion_event->data=(void*)req; completion_event->status=0; completion_event->length=0; logf("ctrl received %ld",current_tick); @@ -798,14 +833,14 @@ void usb_core_control_request(struct usb_ctrlrequest* req) int usb_core_ack_control(struct usb_ctrlrequest* req) { if (req->bRequestType & USB_DIR_IN) - return usb_drv_recv(EP_CONTROL, NULL, 0); + return usb_drv_recv(EP_CONTROL,NULL,0); else - return usb_drv_send(EP_CONTROL, NULL, 0); + return usb_drv_send(EP_CONTROL,NULL,0); } #ifdef HAVE_USB_POWER unsigned short usb_allowed_current() { - return (usb_state == CONFIGURED) ? MAX(USB_MAX_CURRENT, 100) : 100; + return (usb_state==CONFIGURED) ? MAX(USB_MAX_CURRENT, 100) : 100; } #endif -- cgit v1.2.3