forked from len0rd/rockbox
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
This commit is contained in:
parent
b71aad65f5
commit
08b04cc587
3 changed files with 311 additions and 258 deletions
|
@ -109,6 +109,24 @@
|
||||||
#define USB_REQ_GET_INTERFACE 0x0A
|
#define USB_REQ_GET_INTERFACE 0x0A
|
||||||
#define USB_REQ_SET_INTERFACE 0x0B
|
#define USB_REQ_SET_INTERFACE 0x0B
|
||||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
#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
|
* struct usb_ctrlrequest - SETUP data for a USB device control request
|
||||||
|
|
|
@ -494,66 +494,36 @@ static void allocate_interfaces_and_endpoints(void)
|
||||||
usb_core_num_interfaces = interface;
|
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;
|
int i;
|
||||||
if(usb_state == DEFAULT) {
|
bool handled=false;
|
||||||
set_serial_descriptor();
|
|
||||||
usb_core_set_serial_function_id();
|
|
||||||
|
|
||||||
allocate_interfaces_and_endpoints();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;i<USB_NUM_DRIVERS;i++) {
|
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||||
if(drivers[i].enabled &&
|
if(drivers[i].enabled &&
|
||||||
drivers[i].init_connection!=NULL)
|
drivers[i].control_request &&
|
||||||
|
drivers[i].first_interface <= (req->wIndex) &&
|
||||||
|
drivers[i].last_interface > (req->wIndex))
|
||||||
{
|
{
|
||||||
drivers[i].init_connection();
|
handled = drivers[i].control_request(req, response_data);
|
||||||
|
if(handled)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if(!handled) {
|
||||||
else {
|
/* nope. flag error */
|
||||||
usb_state = ADDRESS;
|
logf("bad req:desc %d:%d", req->bRequest, req->wValue>>8);
|
||||||
}
|
usb_drv_stall(EP_CONTROL, true,true);
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
case USB_REQ_GET_DESCRIPTOR: {
|
|
||||||
int index = req->wValue & 0xff;
|
static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req)
|
||||||
int length = req->wLength;
|
{
|
||||||
int size;
|
int size;
|
||||||
|
bool handled = true;
|
||||||
const void* ptr = NULL;
|
const void* ptr = NULL;
|
||||||
logf("usb_core: GET_DESC %d", req->wValue >> 8);
|
int length = req->wLength;
|
||||||
|
int index = req->wValue & 0xff;
|
||||||
|
|
||||||
switch(req->wValue>>8) { /* type */
|
switch(req->wValue>>8) { /* type */
|
||||||
case USB_DT_DEVICE:
|
case USB_DT_DEVICE:
|
||||||
|
@ -563,36 +533,26 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
|
|
||||||
case USB_DT_OTHER_SPEED_CONFIG:
|
case USB_DT_OTHER_SPEED_CONFIG:
|
||||||
case USB_DT_CONFIG: {
|
case USB_DT_CONFIG: {
|
||||||
int max_packet_size;
|
int i, max_packet_size;
|
||||||
|
|
||||||
if(req->wValue>>8==USB_DT_CONFIG) {
|
if(req->wValue>>8==USB_DT_CONFIG) {
|
||||||
if(usb_drv_port_speed())
|
max_packet_size=(usb_drv_port_speed() ? 512 : 64);
|
||||||
max_packet_size=512;
|
|
||||||
else
|
|
||||||
max_packet_size=64;
|
|
||||||
config_descriptor.bDescriptorType=USB_DT_CONFIG;
|
config_descriptor.bDescriptorType=USB_DT_CONFIG;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(usb_drv_port_speed())
|
max_packet_size=(usb_drv_port_speed() ? 64 : 512);
|
||||||
max_packet_size=64;
|
|
||||||
else
|
|
||||||
max_packet_size=512;
|
|
||||||
config_descriptor.bDescriptorType =
|
config_descriptor.bDescriptorType =
|
||||||
USB_DT_OTHER_SPEED_CONFIG;
|
USB_DT_OTHER_SPEED_CONFIG;
|
||||||
}
|
}
|
||||||
size = sizeof(struct usb_config_descriptor);
|
size = sizeof(struct usb_config_descriptor);
|
||||||
|
|
||||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||||
if(drivers[i].enabled &&
|
if(drivers[i].enabled && drivers[i].get_config_descriptor) {
|
||||||
drivers[i].get_config_descriptor)
|
|
||||||
{
|
|
||||||
size+=drivers[i].get_config_descriptor(
|
size+=drivers[i].get_config_descriptor(
|
||||||
&response_data[size],
|
&response_data[size],max_packet_size);
|
||||||
max_packet_size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config_descriptor.bNumInterfaces =
|
config_descriptor.bNumInterfaces = usb_core_num_interfaces;
|
||||||
usb_core_num_interfaces;
|
|
||||||
config_descriptor.wTotalLength = size;
|
config_descriptor.wTotalLength = size;
|
||||||
memcpy(&response_data[0],&config_descriptor,
|
memcpy(&response_data[0],&config_descriptor,
|
||||||
sizeof(struct usb_config_descriptor));
|
sizeof(struct usb_config_descriptor));
|
||||||
|
@ -604,8 +564,7 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
case USB_DT_STRING:
|
case USB_DT_STRING:
|
||||||
logf("STRING %d",index);
|
logf("STRING %d",index);
|
||||||
if ((unsigned)index < (sizeof(usb_strings)/
|
if ((unsigned)index < (sizeof(usb_strings)/
|
||||||
sizeof(struct usb_string_descriptor*)))
|
sizeof(struct usb_string_descriptor*))) {
|
||||||
{
|
|
||||||
size = usb_strings[index]->bLength;
|
size = usb_strings[index]->bLength;
|
||||||
ptr = usb_strings[index];
|
ptr = usb_strings[index];
|
||||||
}
|
}
|
||||||
|
@ -621,28 +580,74 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logf("bad desc %d", req->wValue >> 8);
|
logf("ctrl desc.");
|
||||||
usb_drv_stall(EP_CONTROL, true,true);
|
handled = false;
|
||||||
|
control_request_handler_drivers(req);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
|
logf("data %d (%d)",size,length);
|
||||||
length = MIN(size,length);
|
length = MIN(size,length);
|
||||||
|
|
||||||
if (ptr != response_data) {
|
if (ptr != response_data) {
|
||||||
memcpy(response_data,ptr,length);
|
memcpy(response_data,ptr,length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(usb_drv_send(EP_CONTROL, response_data, length)!=0)
|
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;
|
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;i<USB_NUM_DRIVERS;i++) {
|
||||||
|
if(drivers[i].enabled && drivers[i].init_connection)
|
||||||
|
drivers[i].init_connection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
usb_state = ADDRESS;
|
||||||
|
}
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
} /* USB_REQ_GET_DESCRIPTOR */
|
}
|
||||||
|
case USB_REQ_SET_ADDRESS: {
|
||||||
|
unsigned char address = req->wValue;
|
||||||
|
logf("usb_core: SET_ADR %d", address);
|
||||||
|
if(usb_core_ack_control(req))
|
||||||
|
break;
|
||||||
|
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:
|
case USB_REQ_CLEAR_FEATURE:
|
||||||
break;
|
break;
|
||||||
case USB_REQ_SET_FEATURE:
|
case USB_REQ_SET_FEATURE:
|
||||||
if(req->wValue == 2) { /* TEST_MODE */
|
if(req->wValue==USB_DEVICE_TEST_MODE) {
|
||||||
int mode=req->wIndex>>8;
|
int mode=req->wIndex>>8;
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
usb_drv_set_test_mode(mode);
|
usb_drv_set_test_mode(mode);
|
||||||
|
@ -651,16 +656,18 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
case USB_REQ_GET_STATUS:
|
case USB_REQ_GET_STATUS:
|
||||||
response_data[0]= 0;
|
response_data[0]= 0;
|
||||||
response_data[1]= 0;
|
response_data[1]= 0;
|
||||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
if(!usb_drv_send(EP_CONTROL, response_data, 2))
|
||||||
break;
|
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case 1: /* Interface */
|
|
||||||
switch (req->bRequest) {
|
static void request_handler_interface_standard(struct usb_ctrlrequest* req)
|
||||||
|
{
|
||||||
|
switch (req->bRequest)
|
||||||
|
{
|
||||||
case USB_REQ_SET_INTERFACE:
|
case USB_REQ_SET_INTERFACE:
|
||||||
logf("usb_core: SET_INTERFACE");
|
logf("usb_core: SET_INTERFACE");
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
|
@ -669,8 +676,7 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
case USB_REQ_GET_INTERFACE:
|
case USB_REQ_GET_INTERFACE:
|
||||||
logf("usb_core: GET_INTERFACE");
|
logf("usb_core: GET_INTERFACE");
|
||||||
response_data[0]=0;
|
response_data[0]=0;
|
||||||
if(usb_drv_send(EP_CONTROL, response_data, 1)!=0)
|
if(!usb_drv_send(EP_CONTROL,response_data,1))
|
||||||
break;
|
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
case USB_REQ_CLEAR_FEATURE:
|
case USB_REQ_CLEAR_FEATURE:
|
||||||
|
@ -680,62 +686,66 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
case USB_REQ_GET_STATUS:
|
case USB_REQ_GET_STATUS:
|
||||||
response_data[0]=0;
|
response_data[0]=0;
|
||||||
response_data[1]=0;
|
response_data[1]=0;
|
||||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
if(!usb_drv_send(EP_CONTROL, response_data, 2))
|
||||||
break;
|
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
default: {
|
default:
|
||||||
bool handled=false;
|
control_request_handler_drivers(req);
|
||||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
break;
|
||||||
if(drivers[i].enabled &&
|
}
|
||||||
drivers[i].control_request &&
|
}
|
||||||
drivers[i].first_interface <= (req->wIndex) &&
|
|
||||||
drivers[i].last_interface > (req->wIndex))
|
static void request_handler_interface(struct usb_ctrlrequest* req)
|
||||||
{
|
{
|
||||||
handled = drivers[i].control_request(req, response_data);
|
switch(req->bRequestType & USB_TYPE_MASK) {
|
||||||
}
|
case USB_TYPE_STANDARD:
|
||||||
}
|
request_handler_interface_standard(req);
|
||||||
if(!handled) {
|
break;
|
||||||
/* nope. flag error */
|
case USB_TYPE_CLASS:
|
||||||
logf("usb bad req %d", req->bRequest);
|
control_request_handler_drivers(req);
|
||||||
usb_drv_stall(EP_CONTROL, true,true);
|
break;
|
||||||
usb_core_ack_control(req);
|
case USB_TYPE_VENDOR:
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 2: /* Endpoint */
|
static void request_handler_endpoint(struct usb_ctrlrequest* req)
|
||||||
|
{
|
||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
case USB_REQ_CLEAR_FEATURE:
|
case USB_REQ_CLEAR_FEATURE:
|
||||||
if (req->wValue == 0 ) /* ENDPOINT_HALT */
|
if (req->wValue==USB_ENDPOINT_HALT) {
|
||||||
usb_drv_stall(req->wIndex & 0xf, false,
|
usb_drv_stall(req->wIndex & 0xf, false,
|
||||||
(req->wIndex & 0x80) !=0);
|
(req->wIndex & USB_DIR_IN)!=0);
|
||||||
|
}
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
case USB_REQ_SET_FEATURE:
|
case USB_REQ_SET_FEATURE:
|
||||||
if (req->wValue == 0 ) /* ENDPOINT_HALT */
|
if (req->wValue==USB_ENDPOINT_HALT) {
|
||||||
usb_drv_stall(req->wIndex & 0xf,true,
|
usb_drv_stall(req->wIndex & 0xf,true,
|
||||||
(req->wIndex & 0x80) !=0);
|
(req->wIndex & USB_DIR_IN)!=0);
|
||||||
|
}
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
case USB_REQ_GET_STATUS:
|
case USB_REQ_GET_STATUS:
|
||||||
response_data[0]=0;
|
response_data[0]=0;
|
||||||
response_data[1]=0;
|
response_data[1]=0;
|
||||||
logf("usb_core: GET_STATUS");
|
logf("usb_core: GET_STATUS");
|
||||||
if(req->wIndex>0)
|
if(req->wIndex>0) {
|
||||||
response_data[0]=usb_drv_stalled(req->wIndex & 0xf,
|
response_data[0]=usb_drv_stalled(req->wIndex & 0xf,
|
||||||
(req->wIndex&0x80)!=0);
|
(req->wIndex & USB_DIR_IN)!=0);
|
||||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
}
|
||||||
break;
|
if(!usb_drv_send(EP_CONTROL,response_data,2))
|
||||||
usb_core_ack_control(req);
|
usb_core_ack_control(req);
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
bool handled=false;
|
bool handled;
|
||||||
if(ep_data[req->wIndex & 0xf].control_handler[0] != NULL) {
|
control_handler_t control_handler;
|
||||||
handled = ep_data[req->wIndex & 0xf].control_handler[0](req,
|
|
||||||
response_data);
|
control_handler=ep_data[req->wIndex & 0xf].control_handler[0];
|
||||||
}
|
if (!control_handler)
|
||||||
|
break;
|
||||||
|
|
||||||
|
handled=control_handler(req, response_data);
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
/* nope. flag error */
|
/* nope. flag error */
|
||||||
logf("usb bad req %d",req->bRequest);
|
logf("usb bad req %d",req->bRequest);
|
||||||
|
@ -746,7 +756,32 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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() */
|
/* called by usb_drv_int() */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue