mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-10 08:03:04 -04:00
usb: refactor control request handling
this commit is a combination of the following changes, which significantly refactors usb core and class drivers. 1. unify usb buffers of each class driver to reduce iram usage currently, many class drivers allocate their own buffer to receive control out data, which is a waste of iram. share one common buffer for that usage to address the issue. 2. simplify control request handling by implicitly receiving write request data packets change 1 above fixed the data destination. therefore, having the core receive the data allows us to reduce the class driver's work and simplifies the api. 3. enhance usb core's control request handling and unify the legacy driver api in order to implement change 2, both the legacy and new driver apis should be supported. so that, using the designware driver as a reference, the new driver api functionality is move into usb core. this simplifies the usb device drivers by requiring them to implement only the functionalities equivalent to the legacy api. tested with ipodvideo(arc) and erosqnative(designware) Change-Id: I3627daa90278751f599e2108ec150ec3f8f6c524
This commit is contained in:
parent
64b1f09e06
commit
2291aa24f2
23 changed files with 441 additions and 825 deletions
|
|
@ -307,9 +307,6 @@ static struct usb_class_driver_ep_allocation ep_allocs[2] = {
|
|||
#define EP_ISO_OUT (ep_allocs[0].ep)
|
||||
#define EP_ISO_FEEDBACK_IN (ep_allocs[1].ep)
|
||||
|
||||
/* small buffer used for control transfers */
|
||||
static unsigned char usb_buffer[128] USB_DEVBSS_ATTR;
|
||||
|
||||
/* number of buffers: 2 is double-buffering (one for usb, one for playback),
|
||||
* 3 is triple-buffering (one for usb, one for playback, one for queuing), ... */
|
||||
|
||||
|
|
@ -833,8 +830,10 @@ int32_t usb_audio_get_samples_rx_perframe(void)
|
|||
return samples_received_report;
|
||||
}
|
||||
|
||||
static bool usb_audio_as_ctrldata_endpoint_request(struct usb_ctrlrequest* req, void *reqdata)
|
||||
static bool usb_audio_as_ctrldata_endpoint_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
(void)reqdata_size; /* should check this? */
|
||||
|
||||
/* only support sampling frequency */
|
||||
if(req->wValue != (USB_AS_EP_CS_SAMPLING_FREQ_CTL << 8))
|
||||
{
|
||||
|
|
@ -848,40 +847,26 @@ static bool usb_audio_as_ctrldata_endpoint_request(struct usb_ctrlrequest* req,
|
|||
if(req->wLength != 3)
|
||||
{
|
||||
logf("usbaudio: bad length for SET_CUR");
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
logf("usbaudio: SET_CUR sampling freq");
|
||||
|
||||
if (reqdata) { /* control write, second pass */
|
||||
set_playback_sampling_frequency(decode3(reqdata));
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return true;
|
||||
} else { /* control write, first pass */
|
||||
bool error = false;
|
||||
set_playback_sampling_frequency(decode3(reqdata));
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
|
||||
if (req->wLength != 3)
|
||||
error = true;
|
||||
/* ... other validation? */
|
||||
|
||||
if (error)
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
else
|
||||
usb_drv_control_response(USB_CONTROL_RECEIVE, usb_buffer, 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
case USB_AC_GET_CUR:
|
||||
if(req->wLength != 3)
|
||||
{
|
||||
logf("usbaudio: bad length for GET_CUR");
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
logf("usbaudio: GET_CUR sampling freq");
|
||||
encode3(usb_buffer, usb_audio_get_playback_sampling_frequency());
|
||||
usb_drv_control_response(USB_CONTROL_ACK, usb_buffer, req->wLength);
|
||||
encode3(reqdata, usb_audio_get_playback_sampling_frequency());
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 3);
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -892,12 +877,12 @@ static bool usb_audio_as_ctrldata_endpoint_request(struct usb_ctrlrequest* req,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool usb_audio_endpoint_request(struct usb_ctrlrequest* req, void *reqdata)
|
||||
static bool usb_audio_endpoint_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
int ep = req->wIndex & 0xff;
|
||||
|
||||
if(ep == EP_ISO_OUT)
|
||||
return usb_audio_as_ctrldata_endpoint_request(req, reqdata);
|
||||
return usb_audio_as_ctrldata_endpoint_request(req, reqdata, reqdata_size);
|
||||
else
|
||||
{
|
||||
logf("usbaudio: unhandled ep req (ep=%d)", ep);
|
||||
|
|
@ -1029,8 +1014,10 @@ int usb_audio_get_cur_volume(void)
|
|||
return usb_audio_volume_to_db(vol, sound_numdecimals(SOUND_VOLUME));
|
||||
}
|
||||
|
||||
static bool usb_audio_set_get_feature_unit(struct usb_ctrlrequest* req, void *reqdata)
|
||||
static bool usb_audio_set_get_feature_unit(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
(void)reqdata_size; /* should check this? */
|
||||
|
||||
int channel = req->wValue & 0xff;
|
||||
int selector = req->wValue >> 8;
|
||||
uint8_t cmd = (req->bRequest & ~USB_AC_GET_REQ);
|
||||
|
|
@ -1066,7 +1053,7 @@ static bool usb_audio_set_get_feature_unit(struct usb_ctrlrequest* req, void *re
|
|||
if(!handled)
|
||||
{
|
||||
logf("usbaudio: unhandled get control 0x%x selector 0x%x of feature unit", cmd, selector);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1077,9 +1064,9 @@ static bool usb_audio_set_get_feature_unit(struct usb_ctrlrequest* req, void *re
|
|||
}
|
||||
|
||||
for(i = 0; i < req->wLength; i++)
|
||||
usb_buffer[i] = (value >> (8 * i)) & 0xff;
|
||||
reqdata[i] = (value >> (8 * i)) & 0xff;
|
||||
|
||||
usb_drv_control_response(USB_CONTROL_ACK, usb_buffer, req->wLength);
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, req->wLength);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
@ -1091,68 +1078,47 @@ static bool usb_audio_set_get_feature_unit(struct usb_ctrlrequest* req, void *re
|
|||
return false;
|
||||
}
|
||||
|
||||
if (reqdata) {
|
||||
for(i = 0; i < req->wLength; i++)
|
||||
value = value | (reqdata[i] << (i * 8));
|
||||
|
||||
for(i = 0; i < req->wLength; i++)
|
||||
value = value | (usb_buffer[i] << (i * 8));
|
||||
switch(selector)
|
||||
{
|
||||
case USB_AC_FU_MUTE:
|
||||
handled = (req->wLength == 1) && feature_unit_set_mute(value, cmd);
|
||||
break;
|
||||
case USB_AC_VOLUME_CONTROL:
|
||||
handled = (req->wLength == 2) && feature_unit_set_volume(value, cmd);
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
logf("usbaudio: unhandled control selector of feature unit (0x%x)", selector);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(selector)
|
||||
{
|
||||
case USB_AC_FU_MUTE:
|
||||
handled = (req->wLength == 1) && feature_unit_set_mute(value, cmd);
|
||||
break;
|
||||
case USB_AC_VOLUME_CONTROL:
|
||||
handled = (req->wLength == 2) && feature_unit_set_volume(value, cmd);
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
logf("usbaudio: unhandled control selector of feature unit (0x%x)", selector);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!handled)
|
||||
{
|
||||
logf("usbaudio: unhandled set control 0x%x selector 0x%x of feature unit", cmd, selector);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return true;
|
||||
if(!handled) {
|
||||
logf("usbaudio: unhandled set control 0x%x selector 0x%x of feature unit", cmd, selector);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
} else {
|
||||
/*
|
||||
* should handle the following (req->wValue >> 8):
|
||||
* USB_AC_FU_MUTE
|
||||
* USB_AC_VOLUME_CONTROL
|
||||
*/
|
||||
|
||||
bool error = false;
|
||||
|
||||
if (error)
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
else
|
||||
usb_drv_control_response(USB_CONTROL_RECEIVE, usb_buffer, 3);
|
||||
|
||||
return true;
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool usb_audio_ac_set_get_request(struct usb_ctrlrequest* req, void *reqdata)
|
||||
static bool usb_audio_ac_set_get_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
switch(req->wIndex >> 8)
|
||||
{
|
||||
case AC_PLAYBACK_FEATURE_ID:
|
||||
return usb_audio_set_get_feature_unit(req, reqdata);
|
||||
return usb_audio_set_get_feature_unit(req, reqdata, reqdata_size);
|
||||
default:
|
||||
logf("usbaudio: unhandled set/get on entity %d", req->wIndex >> 8);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool usb_audio_interface_request(struct usb_ctrlrequest* req, void *reqdata)
|
||||
static bool usb_audio_interface_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
int intf = req->wIndex & 0xff;
|
||||
|
||||
|
|
@ -1163,7 +1129,7 @@ static bool usb_audio_interface_request(struct usb_ctrlrequest* req, void *reqda
|
|||
case USB_AC_SET_CUR: case USB_AC_SET_MIN: case USB_AC_SET_MAX: case USB_AC_SET_RES:
|
||||
case USB_AC_SET_MEM: case USB_AC_GET_CUR: case USB_AC_GET_MIN: case USB_AC_GET_MAX:
|
||||
case USB_AC_GET_RES: case USB_AC_GET_MEM:
|
||||
return usb_audio_ac_set_get_request(req, reqdata);
|
||||
return usb_audio_ac_set_get_request(req, reqdata, reqdata_size);
|
||||
default:
|
||||
logf("usbaudio: unhandled ac intf req 0x%x", req->bRequest);
|
||||
return false;
|
||||
|
|
@ -1182,17 +1148,14 @@ static bool usb_audio_interface_request(struct usb_ctrlrequest* req, void *reqda
|
|||
*
|
||||
* Return true if this driver handles the request, false otherwise.
|
||||
*/
|
||||
static bool usb_audio_control_request(struct usb_ctrlrequest* req, void *reqdata, unsigned char* dest)
|
||||
static bool usb_audio_control_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
(void) reqdata;
|
||||
(void) dest;
|
||||
|
||||
switch(req->bRequestType & USB_RECIP_MASK)
|
||||
{
|
||||
case USB_RECIP_ENDPOINT:
|
||||
return usb_audio_endpoint_request(req, reqdata);
|
||||
return usb_audio_endpoint_request(req, reqdata, reqdata_size);
|
||||
case USB_RECIP_INTERFACE:
|
||||
return usb_audio_interface_request(req, reqdata);
|
||||
return usb_audio_interface_request(req, reqdata, reqdata_size);
|
||||
default:
|
||||
logf("usbaudio: unhandled req type 0x%x", req->bRequestType);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ struct usb_class_driver {
|
|||
able to handle it, it should ack the request, and return true. Otherwise
|
||||
it should return false.
|
||||
Optional function */
|
||||
bool (*control_request)(struct usb_ctrlrequest* req, void* reqdata, unsigned char *dest);
|
||||
bool (*control_request)(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size);
|
||||
|
||||
#ifdef HAVE_HOTSWAP
|
||||
/* Tells the driver that a hotswappable disk/card was inserted or
|
||||
|
|
|
|||
|
|
@ -184,10 +184,71 @@ static int usb_no_host_callback(struct timeout *tmo)
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct usb_ctrlrequest handling_request;
|
||||
static struct usb_ctrlrequest pending_request;
|
||||
static volatile bool have_pending_request;
|
||||
|
||||
/* control endpoint typical state flow
|
||||
* READY -setup_received(IN, wLength==0)->
|
||||
* HANDLING_TX_CONTROL -control_response(size==0)->
|
||||
* EXPECT_TX_STATUS_COMP -transfer_complete(OUT)->
|
||||
* READY
|
||||
* -setup_received(IN, wLength>0)->
|
||||
* HANDLING_TX_CONTROL -control_response(size>0)->
|
||||
* EXPECT_TX_DATA_STATUS_COMP
|
||||
* -transfer_complete(OUT)->
|
||||
* EXPECT_TX_DATA_COMP -transfer_complete(IN)->
|
||||
* READY
|
||||
* -transfer_complete(IN)->
|
||||
* EXPECT_TX_STATUS_COMP -transfer_complete(OUT)->
|
||||
* READY
|
||||
* -setup_received(OUT, wLength==0)->
|
||||
* HANDLING_RX_CONTROL -control_response(size==0)->
|
||||
* EXPECT_RX_STATUS_COMP -transfer_complete(IN)->
|
||||
* READY
|
||||
* -setup_received(OUT, wLength>0)->
|
||||
* HANDLING_RX_CONTROL ->
|
||||
* EXPECT_RX_DATA_COMP -transfer_complete(OUT)->
|
||||
* HANDLING_TX_CONTROL -control_response(size==0)->
|
||||
* EXPECT_RX_STATUS_COMP -transfer_complete()->
|
||||
* READY
|
||||
* */
|
||||
enum {
|
||||
EP0_READY, /* waiting for new setup packet */
|
||||
/* IN request */
|
||||
EP0_HANDLING_TX_CONTROL, /* control in received, usb thread is processing it */
|
||||
EP0_EXPECT_TX_DATA_STATUS_COMP, /* sending control in data phase */
|
||||
EP0_EXPECT_TX_DATA_COMP, /* status packet received earlier than tx completion */
|
||||
EP0_EXPECT_TX_STATUS_COMP, /* receiving status */
|
||||
/* OUT request */
|
||||
EP0_HANDLING_RX_CONTROL, /* control out received, usb thread is processing it */
|
||||
EP0_EXPECT_RX_DATA_COMP, /* receiving control out data phase */
|
||||
EP0_EXPECT_RX_STATUS_COMP, /* sending status */
|
||||
};
|
||||
static volatile int ep0_state;
|
||||
|
||||
#define TRACE_EP0_STATE 0
|
||||
#if TRACE_EP0_STATE == 1
|
||||
#define set_ep0_state(new) \
|
||||
{ \
|
||||
logf("usb_core:%d ep0_state %d -> %d", __LINE__, ep0_state, new); \
|
||||
ep0_state = new; \
|
||||
}
|
||||
#else
|
||||
#define set_ep0_state(new) {ep0_state = new;}
|
||||
#endif
|
||||
|
||||
struct usb_transfer_completion_event_data
|
||||
{
|
||||
struct usb_ctrlrequest* req;
|
||||
unsigned char ep;
|
||||
int status;
|
||||
int length;
|
||||
};
|
||||
|
||||
typedef void (*completion_handler_t)(int ep, int dir, int status, int length);
|
||||
typedef bool (*fast_completion_handler_t)(int ep, int dir, int status, int length);
|
||||
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata,
|
||||
unsigned char* dest);
|
||||
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size);
|
||||
|
||||
static struct
|
||||
{
|
||||
|
|
@ -232,18 +293,8 @@ static struct usb_class_driver* drivers[USB_NUM_DRIVERS] =
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef USB_LEGACY_CONTROL_API
|
||||
static struct usb_ctrlrequest buffered_request;
|
||||
static struct usb_ctrlrequest* volatile active_request = NULL;
|
||||
static volatile unsigned int num_active_requests = 0;
|
||||
static void* volatile control_write_data = NULL;
|
||||
static volatile bool control_write_data_done = false;
|
||||
#endif
|
||||
|
||||
static int usb_core_do_set_config(uint8_t new_config);
|
||||
static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void* reqdata);
|
||||
|
||||
static unsigned char response_data[256] USB_DEVBSS_ATTR;
|
||||
static void usb_core_control_request_handler(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size);
|
||||
|
||||
#define is_active(driver) ((driver)->enabled && !(driver)->error && (driver)->config == usb_config)
|
||||
#define has_if(driver, interface) ((interface) >= (driver)->first_interface && (interface) < (driver)->last_interface)
|
||||
|
|
@ -441,27 +492,24 @@ void usb_core_exit(void)
|
|||
logf("usb_core_exit() finished");
|
||||
}
|
||||
|
||||
/* for sending/receiving control data */
|
||||
static uint8_t usb_control_data[256] USB_DEVBSS_ATTR;
|
||||
|
||||
void usb_core_handle_transfer_completion(
|
||||
struct usb_transfer_completion_event_data* event)
|
||||
{
|
||||
completion_handler_t handler;
|
||||
int ep = event->endpoint;
|
||||
int num = EP_NUM(event->ep);
|
||||
int dir = EP_DIR(event->ep);
|
||||
|
||||
switch(ep) {
|
||||
case EP_CONTROL:
|
||||
logf("ctrl handled %ld req=0x%x",
|
||||
current_tick,
|
||||
((struct usb_ctrlrequest*)event->data[0])->bRequest);
|
||||
|
||||
usb_core_control_request_handler(
|
||||
(struct usb_ctrlrequest*)event->data[0], event->data[1]);
|
||||
break;
|
||||
default:
|
||||
handler = ep_data[ep].completion_handler[EP_DIR(event->dir)];
|
||||
if(handler != NULL)
|
||||
handler(ep, event->dir, event->status, event->length);
|
||||
break;
|
||||
if(num == EP_CONTROL) {
|
||||
logf("ctrl handled %ld req=0x%x", current_tick,event->req->bRequest);
|
||||
usb_core_control_request_handler(event->req, usb_control_data, sizeof(usb_control_data));
|
||||
return;
|
||||
}
|
||||
|
||||
completion_handler_t handler = ep_data[num].completion_handler[dir];
|
||||
if(handler != NULL)
|
||||
handler(num, dir == DIR_IN ? USB_DIR_IN : USB_DIR_OUT, event->status, event->length);
|
||||
}
|
||||
|
||||
void usb_core_enable_driver(int driver, bool enabled)
|
||||
|
|
@ -676,8 +724,7 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void control_request_handler_drivers(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void control_request_handler_drivers(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
int i, interface = req->wIndex & 0xff;
|
||||
bool handled = false;
|
||||
|
|
@ -694,7 +741,7 @@ static void control_request_handler_drivers(struct usb_ctrlrequest* req, void* r
|
|||
if(req->bRequest == USB_REQ_SET_INTERFACE) {
|
||||
logf("usb_core: SET INTERFACE 0x%x 0x%x", req->wValue, req->wIndex);
|
||||
if(driver->set_interface && driver->set_interface(req->wIndex, req->wValue) >= 0) {
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
|
|
@ -706,26 +753,26 @@ static void control_request_handler_drivers(struct usb_ctrlrequest* req, void* r
|
|||
alt = driver->get_interface(req->wIndex);
|
||||
|
||||
if(alt >= 0 && alt < 255) {
|
||||
response_data[0] = alt;
|
||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, 1);
|
||||
reqdata[0] = alt;
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 1);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handled = driver->control_request(req, reqdata, response_data);
|
||||
handled = driver->control_request(req, reqdata, reqdata_size);
|
||||
break; /* no other driver can handle it because it's interface specific */
|
||||
}
|
||||
if(!handled) {
|
||||
/* nope. flag error */
|
||||
logf("bad req 0x%x:0x%x:0x%x:0x%x:0x%x", req->bRequestType,req->bRequest,
|
||||
req->wValue, req->wIndex, req->wLength);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
int size;
|
||||
const void* ptr = NULL;
|
||||
|
|
@ -769,16 +816,16 @@ static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, v
|
|||
|
||||
for(i = 0; i < USB_NUM_DRIVERS; i++) {
|
||||
if(drivers[i]->enabled && drivers[i]->config == index + 1 && drivers[i]->get_config_descriptor) {
|
||||
size += drivers[i]->get_config_descriptor(&response_data[size], max_packet_size);
|
||||
size += drivers[i]->get_config_descriptor(reqdata + size, max_packet_size);
|
||||
}
|
||||
}
|
||||
|
||||
config_descriptor.bNumInterfaces = config_states[index].num_interfaces;
|
||||
config_descriptor.bConfigurationValue = index + 1;
|
||||
config_descriptor.wTotalLength = (uint16_t)size;
|
||||
memcpy(&response_data[0], &config_descriptor, sizeof(struct usb_config_descriptor));
|
||||
memcpy(reqdata, &config_descriptor, sizeof(struct usb_config_descriptor));
|
||||
|
||||
ptr = response_data;
|
||||
ptr = reqdata;
|
||||
} break;
|
||||
case USB_DT_STRING:
|
||||
logf("STRING %d", index);
|
||||
|
|
@ -807,7 +854,7 @@ static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, v
|
|||
|
||||
default:
|
||||
logf("ctrl desc.");
|
||||
control_request_handler_drivers(req, reqdata);
|
||||
control_request_handler_drivers(req, reqdata, reqdata_size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -815,12 +862,12 @@ static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, v
|
|||
logf("data %d (%d)", size, length);
|
||||
length = MIN(size, length);
|
||||
|
||||
if (ptr != response_data)
|
||||
memcpy(response_data, ptr, length);
|
||||
if (ptr != reqdata)
|
||||
memcpy(reqdata, ptr, length);
|
||||
|
||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, length);
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, length);
|
||||
} else {
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -916,22 +963,22 @@ static void usb_core_do_clear_feature(int recip, int recip_nr, int feature)
|
|||
}
|
||||
}
|
||||
|
||||
static void request_handler_device(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_device(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
unsigned address;
|
||||
|
||||
switch(req->bRequest) {
|
||||
case USB_REQ_GET_CONFIGURATION:
|
||||
logf("usb_core: GET_CONFIG");
|
||||
response_data[0] = usb_config;
|
||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, 1);
|
||||
reqdata[0] = usb_config;
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 1);
|
||||
break;
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
usb_drv_cancel_all_transfers();
|
||||
if(usb_core_do_set_config(req->wValue) == 0) {
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
} else {
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
}
|
||||
break;
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
|
|
@ -939,85 +986,85 @@ static void request_handler_device(struct usb_ctrlrequest* req, void* reqdata)
|
|||
* should just handle it themselves. We don't care beyond
|
||||
* knowing if we've been assigned an address yet, or not. */
|
||||
address = req->wValue;
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_drv_cancel_all_transfers();
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_drv_set_address(address);
|
||||
usb_core_do_set_addr(address);
|
||||
break;
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
logf("usb_core: GET_DESC %d", req->wValue >> 8);
|
||||
request_handler_device_get_descriptor(req, reqdata);
|
||||
request_handler_device_get_descriptor(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE:
|
||||
if(req->wValue==USB_DEVICE_TEST_MODE) {
|
||||
int mode = req->wIndex >> 8;
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_drv_set_test_mode(mode);
|
||||
} else {
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
response_data[0] = 0;
|
||||
response_data[1] = 0;
|
||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, 2);
|
||||
reqdata[0] = 0;
|
||||
reqdata[1] = 0;
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 2);
|
||||
break;
|
||||
#ifdef USB_ENABLE_IAP
|
||||
case USB_REQ_APPLE_SET_AVAIL_CURRENT:
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
logf("bad req:desc %d:%d", req->bRequest, req->wValue);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void request_handler_interface_standard(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_interface_standard(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
switch (req->bRequest)
|
||||
{
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
logf("usb_core: SET_INTERFACE");
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
control_request_handler_drivers(req, reqdata);
|
||||
control_request_handler_drivers(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
response_data[0] = 0;
|
||||
response_data[1] = 0;
|
||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, 2);
|
||||
reqdata[0] = 0;
|
||||
reqdata[1] = 0;
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 2);
|
||||
break;
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
case USB_REQ_SET_FEATURE:
|
||||
/* TODO: These used to be ignored (erroneously).
|
||||
* Should they be passed to the drivers instead? */
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
control_request_handler_drivers(req, reqdata);
|
||||
control_request_handler_drivers(req, reqdata, reqdata_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void request_handler_interface(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_interface(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
switch(req->bRequestType & USB_TYPE_MASK) {
|
||||
case USB_TYPE_STANDARD:
|
||||
request_handler_interface_standard(req, reqdata);
|
||||
request_handler_interface_standard(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_TYPE_CLASS:
|
||||
control_request_handler_drivers(req, reqdata);
|
||||
control_request_handler_drivers(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_TYPE_VENDOR:
|
||||
default:
|
||||
logf("bad req:desc %d", req->bRequest);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void request_handler_endpoint_drivers(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_endpoint_drivers(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
bool handled = false;
|
||||
control_handler_t control_handler = NULL;
|
||||
|
|
@ -1027,67 +1074,67 @@ static void request_handler_endpoint_drivers(struct usb_ctrlrequest* req, void*
|
|||
ep_data[EP_NUM(req->wIndex)].control_handler[EP_DIR(req->wIndex)];
|
||||
|
||||
if(control_handler)
|
||||
handled = control_handler(req, reqdata, response_data);
|
||||
handled = control_handler(req, reqdata, reqdata_size);
|
||||
|
||||
if(!handled) {
|
||||
/* nope. flag error */
|
||||
logf("bad req 0x%x:0x%x:0x%x:0x%x:0x%x", req->bRequestType,req->bRequest,
|
||||
req->wValue, req->wIndex, req->wLength);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void request_handler_endpoint_standard(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_endpoint_standard(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
usb_core_do_clear_feature(USB_RECIP_ENDPOINT,
|
||||
req->wIndex,
|
||||
req->wValue);
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE:
|
||||
logf("usb_core: SET FEATURE (%d)", req->wValue);
|
||||
if(req->wValue == USB_ENDPOINT_HALT)
|
||||
usb_drv_stall(EP_NUM(req->wIndex), true, EP_DIR(req->wIndex));
|
||||
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
response_data[0] = 0;
|
||||
response_data[1] = 0;
|
||||
reqdata[0] = 0;
|
||||
reqdata[1] = 0;
|
||||
logf("usb_core: GET_STATUS");
|
||||
if(req->wIndex > 0)
|
||||
response_data[0] = usb_drv_stalled(EP_NUM(req->wIndex),
|
||||
EP_DIR(req->wIndex));
|
||||
reqdata[0] = usb_drv_stalled(EP_NUM(req->wIndex),
|
||||
EP_DIR(req->wIndex));
|
||||
|
||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, 2);
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 2);
|
||||
break;
|
||||
default:
|
||||
request_handler_endpoint_drivers(req, reqdata);
|
||||
request_handler_endpoint_drivers(req, reqdata, reqdata_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void request_handler_endpoint(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void request_handler_endpoint(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
switch(req->bRequestType & USB_TYPE_MASK) {
|
||||
case USB_TYPE_STANDARD:
|
||||
request_handler_endpoint_standard(req, reqdata);
|
||||
request_handler_endpoint_standard(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_TYPE_CLASS:
|
||||
request_handler_endpoint_drivers(req, reqdata);
|
||||
request_handler_endpoint_drivers(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_TYPE_VENDOR:
|
||||
default:
|
||||
logf("bad req:desc %d", req->bRequest);
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handling USB requests starts here */
|
||||
static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void* reqdata)
|
||||
static void usb_core_control_request_handler(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
#ifdef HAVE_USB_CHARGING_ENABLE
|
||||
timeout_cancel(&usb_no_host_timeout);
|
||||
|
|
@ -1105,17 +1152,17 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void*
|
|||
|
||||
switch(req->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_DEVICE:
|
||||
request_handler_device(req, reqdata);
|
||||
request_handler_device(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
request_handler_interface(req, reqdata);
|
||||
request_handler_interface(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_RECIP_ENDPOINT:
|
||||
request_handler_endpoint(req, reqdata);
|
||||
request_handler_endpoint(req, reqdata, reqdata_size);
|
||||
break;
|
||||
default:
|
||||
logf("unsupported recipient");
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1123,10 +1170,9 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void*
|
|||
static void do_bus_reset(void) {
|
||||
usb_address = 0;
|
||||
usb_state = DEFAULT;
|
||||
#ifdef USB_LEGACY_CONTROL_API
|
||||
num_active_requests = 0;
|
||||
#endif
|
||||
bus_reset_pending = false;
|
||||
set_ep0_state(EP0_READY);
|
||||
have_pending_request = false;
|
||||
}
|
||||
|
||||
/* called by usb_drv_int() */
|
||||
|
|
@ -1145,9 +1191,51 @@ void usb_core_bus_reset(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void signal_xfer_complete(int ep, struct usb_ctrlrequest* req, int status, int length) {
|
||||
struct usb_transfer_completion_event_data* completion_event =
|
||||
&ep_data[EP_NUM(ep)].completion_event[EP_DIR(ep)];
|
||||
|
||||
completion_event->req = req;
|
||||
completion_event->ep = ep;
|
||||
completion_event->status = status;
|
||||
completion_event->length = length;
|
||||
usb_signal_transfer_completion(completion_event);
|
||||
}
|
||||
|
||||
static void process_setup_request(struct usb_ctrlrequest* req) {
|
||||
set_ep0_state(req->bRequestType & USB_DIR_IN ? EP0_HANDLING_TX_CONTROL : EP0_HANDLING_RX_CONTROL);
|
||||
|
||||
if(ep0_state == EP0_HANDLING_TX_CONTROL || req->wLength == 0) {
|
||||
signal_xfer_complete(EP_CONTROL | USB_DIR_IN, req, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start control out data phase without usb thread interaction */
|
||||
if(req->wLength > sizeof(usb_control_data)) {
|
||||
logf("usb_core: control write too large %u > %u", req->wLength, sizeof(usb_control_data));
|
||||
usb_drv_stall(EP_CONTROL, true, false);
|
||||
return;
|
||||
}
|
||||
set_ep0_state(EP0_EXPECT_RX_DATA_COMP);
|
||||
usb_drv_recv_nonblocking(EP_CONTROL, usb_control_data, req->wLength);
|
||||
return;
|
||||
}
|
||||
|
||||
static bool check_for_new_setup(void) {
|
||||
int oldlevel = disable_irq_save();
|
||||
if(!have_pending_request) {
|
||||
restore_irq(oldlevel);
|
||||
return false;
|
||||
}
|
||||
have_pending_request = false;
|
||||
handling_request = pending_request;
|
||||
process_setup_request(&handling_request);
|
||||
restore_irq(oldlevel);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
#ifdef USB_BATCH_NON_NATIVE
|
||||
/* batch api */
|
||||
if(batch_ep != 0 && (endpoint | dir) == batch_ep) {
|
||||
|
|
@ -1158,37 +1246,52 @@ void usb_core_transfer_complete(int endpoint, int dir, int status, int length)
|
|||
|
||||
/* Fast notification */
|
||||
fast_completion_handler_t handler = ep_data[endpoint].fast_completion_handler[EP_DIR(dir)];
|
||||
if(handler != NULL && handler(endpoint, dir, status, length))
|
||||
if(handler != NULL && handler(endpoint, dir, status, length)) {
|
||||
return; /* do not dispatch to the queue if handled */
|
||||
|
||||
void* data0 = NULL;
|
||||
void* data1 = NULL;
|
||||
|
||||
#ifdef USB_LEGACY_CONTROL_API
|
||||
if(endpoint == EP_CONTROL) {
|
||||
bool cwdd = control_write_data_done;
|
||||
struct usb_ctrlrequest* req = active_request;
|
||||
|
||||
if(dir == USB_DIR_OUT && req && cwdd) {
|
||||
data0 = req;
|
||||
data1 = control_write_data;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct usb_transfer_completion_event_data* completion_event =
|
||||
&ep_data[endpoint].completion_event[EP_DIR(dir)];
|
||||
/* Non-control packet handling */
|
||||
if(endpoint != EP_CONTROL) {
|
||||
signal_xfer_complete(endpoint | dir, NULL, status, length);
|
||||
return;
|
||||
}
|
||||
|
||||
completion_event->endpoint = endpoint;
|
||||
completion_event->dir = dir;
|
||||
completion_event->data[0] = data0;
|
||||
completion_event->data[1] = data1;
|
||||
completion_event->status = status;
|
||||
completion_event->length = length;
|
||||
/* Control packet handling */
|
||||
switch(dir | ep0_state) {
|
||||
/* EXPECT_TX_DATA_STATUS_COMP -(status comp)-> EXPECT_TX_DATA_COMP -(data comp)-> READY
|
||||
* -(data comp)-> EXPECT_TX_STATUS_COMP -(status comp)-> READY */
|
||||
case USB_DIR_OUT | EP0_EXPECT_TX_DATA_STATUS_COMP:
|
||||
logf("usb_core: control-in done success=%d", status == 0 && length == 0);
|
||||
set_ep0_state(EP0_EXPECT_TX_DATA_COMP);
|
||||
break;
|
||||
case USB_DIR_IN | EP0_EXPECT_TX_DATA_STATUS_COMP:
|
||||
set_ep0_state(EP0_EXPECT_TX_STATUS_COMP);
|
||||
break;
|
||||
case USB_DIR_OUT | EP0_EXPECT_TX_STATUS_COMP:
|
||||
logf("usb_core: control-in done success=%d", status == 0 && length == 0);
|
||||
set_ep0_state(EP0_READY);
|
||||
break;
|
||||
case USB_DIR_IN | EP0_EXPECT_TX_DATA_COMP:
|
||||
set_ep0_state(EP0_READY);
|
||||
break;
|
||||
/* EXPECT_RX_DATA_COMP -(data comp)-> HANDLING_RX_CONTROL [-(send status)-> EXPECT_RX_STATUS_COMP] -(status comp)-> READY
|
||||
* ^ done in control_response() */
|
||||
case USB_DIR_OUT | EP0_EXPECT_RX_DATA_COMP:
|
||||
set_ep0_state(EP0_HANDLING_RX_CONTROL);
|
||||
signal_xfer_complete(EP_CONTROL | USB_DIR_OUT, &handling_request, status, length);
|
||||
break;
|
||||
case USB_DIR_IN | EP0_EXPECT_RX_STATUS_COMP:
|
||||
logf("usb_core: control-out done success=%d", status == 0 && length == 0);
|
||||
set_ep0_state(EP0_READY);
|
||||
break;
|
||||
default:
|
||||
panicf("unhandled endpoint xfer completion ep0_state=%d dir=%d", ep0_state, dir);
|
||||
break;
|
||||
}
|
||||
|
||||
usb_signal_transfer_completion(completion_event);
|
||||
if(ep0_state == EP0_READY) {
|
||||
check_for_new_setup();
|
||||
}
|
||||
}
|
||||
|
||||
void usb_core_handle_notify(long id, intptr_t data)
|
||||
|
|
@ -1227,153 +1330,68 @@ void usb_core_handle_notify(long id, intptr_t data)
|
|||
}
|
||||
}
|
||||
|
||||
void usb_core_control_request(struct usb_ctrlrequest* req, void* reqdata)
|
||||
{
|
||||
struct usb_transfer_completion_event_data* completion_event =
|
||||
&ep_data[EP_CONTROL].completion_event[EP_DIR(USB_DIR_IN)];
|
||||
|
||||
completion_event->endpoint = EP_CONTROL;
|
||||
completion_event->dir = 0;
|
||||
completion_event->data[0] = (void*)req;
|
||||
completion_event->data[1] = reqdata;
|
||||
completion_event->status = 0;
|
||||
completion_event->length = 0;
|
||||
logf("ctrl received %ld, req=0x%x", current_tick, req->bRequest);
|
||||
usb_signal_transfer_completion(completion_event);
|
||||
}
|
||||
|
||||
void usb_core_control_complete(int status)
|
||||
{
|
||||
/* We currently don't use this, it's here to make the API look good ;)
|
||||
* It makes sense to #define it away on normal builds.
|
||||
*/
|
||||
(void)status;
|
||||
logf("ctrl complete %ld, %d", current_tick, status);
|
||||
}
|
||||
|
||||
#ifdef USB_LEGACY_CONTROL_API
|
||||
/* Only needed if the driver does not support the new API yet */
|
||||
void usb_core_legacy_control_request(struct usb_ctrlrequest* req)
|
||||
{
|
||||
/* Only submit non-overlapping requests */
|
||||
if (num_active_requests++ == 0)
|
||||
{
|
||||
buffered_request = *req;
|
||||
active_request = &buffered_request;
|
||||
control_write_data = NULL;
|
||||
control_write_data_done = false;
|
||||
|
||||
usb_core_control_request(req, NULL);
|
||||
void usb_core_setup_received(struct usb_ctrlrequest* req) {
|
||||
if(bus_reset_pending) {
|
||||
logf("usb_core: bus resetting tick=%lu", current_tick);
|
||||
return;
|
||||
}
|
||||
if(ep0_state != EP0_READY) {
|
||||
logf("usb_core: control pending tick=%lu", current_tick);
|
||||
pending_request = *req;
|
||||
have_pending_request = true;
|
||||
return;
|
||||
}
|
||||
handling_request = *req;
|
||||
process_setup_request(&handling_request);
|
||||
}
|
||||
|
||||
void usb_drv_control_response(enum usb_control_response resp,
|
||||
void* data, int length)
|
||||
{
|
||||
struct usb_ctrlrequest* req = active_request;
|
||||
unsigned int num_active = num_active_requests--;
|
||||
void usb_core_control_response(enum usb_control_response response, const void* data, size_t size) {
|
||||
logf("usb_core: response ack=%d size=%u ep0_state=%d tick=%lu", response, size, ep0_state, current_tick);
|
||||
|
||||
/*
|
||||
* There should have been a prior request submission, at least.
|
||||
* FIXME: It seems the iPod video can get here and ignoring it
|
||||
* allows the connection to succeed??
|
||||
*/
|
||||
if (num_active == 0)
|
||||
{
|
||||
//panicf("null ctrl req");
|
||||
if((ep0_state == EP0_HANDLING_TX_CONTROL || ep0_state == EP0_HANDLING_RX_CONTROL) && check_for_new_setup()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This can happen because an active request was already pending when
|
||||
* the driver submitted a new one in usb_core_legacy_control_request().
|
||||
* This could mean two things: (a) a driver bug; or (b) the host sent
|
||||
* another request because we were too slow in handling an earlier one.
|
||||
*
|
||||
* The USB spec requires we respond to the latest request and drop any
|
||||
* earlier ones, but that's not easy to do with the current design of
|
||||
* the USB stack. Thus, the host will be expecting a response for the
|
||||
* latest request, but this response is for the _earliest_ request.
|
||||
*
|
||||
* Play it safe and return a STALL. At this point we've recovered from
|
||||
* the error on our end and will be ready to handle the next request.
|
||||
*/
|
||||
if (num_active > 1)
|
||||
{
|
||||
active_request = NULL;
|
||||
num_active_requests = 0;
|
||||
if(response == USB_CONTROL_STALL) {
|
||||
set_ep0_state(EP0_READY);
|
||||
usb_drv_stall(EP_CONTROL, true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if(req->wLength == 0)
|
||||
{
|
||||
active_request = NULL;
|
||||
|
||||
/* No-data request */
|
||||
if(resp == USB_CONTROL_ACK)
|
||||
usb_drv_send(EP_CONTROL, data, length);
|
||||
else if(resp == USB_CONTROL_STALL)
|
||||
usb_drv_stall(EP_CONTROL, true, true);
|
||||
else
|
||||
panicf("RECEIVE on non-data req");
|
||||
}
|
||||
else if(req->bRequestType & USB_DIR_IN)
|
||||
{
|
||||
/* Control read request */
|
||||
if(resp == USB_CONTROL_ACK)
|
||||
{
|
||||
active_request = NULL;
|
||||
switch(ep0_state) {
|
||||
case EP0_HANDLING_TX_CONTROL:
|
||||
if(size == 0) {
|
||||
/* non-data control-in */
|
||||
set_ep0_state(EP0_EXPECT_TX_STATUS_COMP);
|
||||
usb_drv_recv_nonblocking(EP_CONTROL, NULL, 0);
|
||||
usb_drv_send(EP_CONTROL, data, length);
|
||||
} else {
|
||||
/* control-in data phase */
|
||||
set_ep0_state(EP0_EXPECT_TX_DATA_STATUS_COMP);
|
||||
/* prepare for a status packet before sending data.
|
||||
* note that it is driver and host-dependent that which completion
|
||||
* of the following two commands is notified first. */
|
||||
usb_drv_recv_nonblocking(EP_CONTROL, NULL, 0);
|
||||
/* send data packets */
|
||||
usb_drv_send_nonblocking(EP_CONTROL, (void*)data, size);
|
||||
}
|
||||
else if(resp == USB_CONTROL_STALL)
|
||||
{
|
||||
active_request = NULL;
|
||||
usb_drv_stall(EP_CONTROL, true, true);
|
||||
break;
|
||||
case EP0_HANDLING_RX_CONTROL:
|
||||
if(size == 0) {
|
||||
/* non-data control-out */
|
||||
set_ep0_state(EP0_EXPECT_RX_STATUS_COMP);
|
||||
/* send status packet*/
|
||||
usb_drv_send_nonblocking(EP_CONTROL, NULL, 0);
|
||||
} else {
|
||||
/* control-out data phase */
|
||||
/* should not happen, we've received it internally */
|
||||
logf("usb_core: receiving control data by class drivers is not allowed");
|
||||
}
|
||||
else
|
||||
{
|
||||
panicf("RECEIVE on ctrl read req");
|
||||
}
|
||||
}
|
||||
else if(!control_write_data_done)
|
||||
{
|
||||
/* Control write request, data phase */
|
||||
if(resp == USB_CONTROL_RECEIVE)
|
||||
{
|
||||
control_write_data = data;
|
||||
control_write_data_done = true;
|
||||
usb_drv_recv_nonblocking(EP_CONTROL, data, length);
|
||||
}
|
||||
else if(resp == USB_CONTROL_STALL)
|
||||
{
|
||||
/* We should stall the OUT endpoint here, but the old code did
|
||||
* not do so and some drivers may not handle it correctly. */
|
||||
active_request = NULL;
|
||||
usb_drv_stall(EP_CONTROL, true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
panicf("ACK on ctrl write data");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
active_request = NULL;
|
||||
control_write_data = NULL;
|
||||
control_write_data_done = false;
|
||||
|
||||
/* Control write request, status phase */
|
||||
if(resp == USB_CONTROL_ACK)
|
||||
usb_drv_send(EP_CONTROL, NULL, 0);
|
||||
else if(resp == USB_CONTROL_STALL)
|
||||
usb_drv_stall(EP_CONTROL, true, true);
|
||||
else
|
||||
panicf("RECEIVE on ctrl write status");
|
||||
break;
|
||||
default:
|
||||
panicf("usb_core: invalid control response ep_state=%d", ep0_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usb_core_notify_set_address(uint8_t addr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -594,9 +594,11 @@ static void usb_hid_transfer_complete(int ep, int dir, int status, int length)
|
|||
* In order to allow sending info to the DAP, the Set Report mechanism can be
|
||||
* used by defining vendor specific output reports and send them from the host
|
||||
* to the DAP using the host's custom driver */
|
||||
static int usb_hid_set_report(struct usb_ctrlrequest *req, void *reqdata)
|
||||
static int usb_hid_set_report(struct usb_ctrlrequest *req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
static unsigned char buf[64] USB_DEVBSS_ATTR __attribute__((aligned(32)));
|
||||
(void)reqdata;
|
||||
(void)reqdata_size;
|
||||
|
||||
int length;
|
||||
|
||||
if ((req->wValue >> 8) != USB_HID_REPORT_TYPE_OUTPUT)
|
||||
|
|
@ -621,28 +623,22 @@ static int usb_hid_set_report(struct usb_ctrlrequest *req, void *reqdata)
|
|||
return 4;
|
||||
}
|
||||
|
||||
if(!reqdata) {
|
||||
memset(buf, 0, length);
|
||||
usb_drv_control_response(USB_CONTROL_RECEIVE, buf, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LOGF_ENABLE
|
||||
if (buf[1] & 0x01)
|
||||
if (reqdata[1] & 0x01)
|
||||
logf("Num Lock enabled");
|
||||
if (buf[1] & 0x02)
|
||||
if (reqdata[1] & 0x02)
|
||||
logf("Caps Lock enabled");
|
||||
if (buf[1] & 0x04)
|
||||
if (reqdata[1] & 0x04)
|
||||
logf("Scroll Lock enabled");
|
||||
if (buf[1] & 0x08)
|
||||
if (reqdata[1] & 0x08)
|
||||
logf("Compose enabled");
|
||||
if (buf[1] & 0x10)
|
||||
if (reqdata[1] & 0x10)
|
||||
logf("Kana enabled");
|
||||
#endif
|
||||
|
||||
/* Defining other LEDs and setting them from the USB host (OS) can be used
|
||||
* to send messages to the DAP */
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -674,15 +670,14 @@ static int usb_hid_get_report(struct usb_ctrlrequest *req, unsigned char* dest)
|
|||
|
||||
dest[0] = 0;
|
||||
dest[1] = battery_level();
|
||||
usb_drv_control_response(USB_CONTROL_ACK, dest, 2);
|
||||
usb_core_control_response(USB_CONTROL_ACK, dest, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called by usb_core_control_request() */
|
||||
static bool usb_hid_control_request(struct usb_ctrlrequest *req, void *reqdata, unsigned char *dest)
|
||||
static bool usb_hid_control_request(struct usb_ctrlrequest *req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
(void)reqdata;
|
||||
|
||||
unsigned char* dest = reqdata;
|
||||
unsigned char *orig_dest = dest;
|
||||
switch (req->bRequestType & USB_TYPE_MASK)
|
||||
{
|
||||
|
|
@ -706,7 +701,7 @@ static bool usb_hid_control_request(struct usb_ctrlrequest *req, void *reqdata,
|
|||
|
||||
if (dest != orig_dest)
|
||||
{
|
||||
usb_drv_control_response(USB_CONTROL_ACK, orig_dest, dest - orig_dest);
|
||||
usb_core_control_response(USB_CONTROL_ACK, orig_dest, dest - orig_dest);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
@ -723,13 +718,13 @@ static bool usb_hid_control_request(struct usb_ctrlrequest *req, void *reqdata,
|
|||
switch (req->bRequest)
|
||||
{
|
||||
case USB_HID_SET_REPORT:
|
||||
rc = usb_hid_set_report(req, reqdata);
|
||||
rc = usb_hid_set_report(req, reqdata, reqdata_size);
|
||||
break;
|
||||
case USB_HID_GET_REPORT:
|
||||
rc = usb_hid_get_report(req, dest);
|
||||
break;
|
||||
case USB_HID_SET_IDLE:
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return true;
|
||||
default:
|
||||
/* all other requests are errors */
|
||||
|
|
|
|||
|
|
@ -481,39 +481,19 @@ static bool usb_iap_fast_transfer_complete(int ep, int dir, int status, int leng
|
|||
return (ep | dir) == AS_EP_IN;
|
||||
}
|
||||
|
||||
static unsigned char ctrl_buf[256] USB_DEVBSS_ATTR;
|
||||
|
||||
static void respond_zero(struct usb_ctrlrequest* req) {
|
||||
if(req->wLength > sizeof(ctrl_buf)) {
|
||||
ERROR("required data too long %u > %u", req->wLength, sizeof(ctrl_buf));
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
static void respond_zero(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size) {
|
||||
if(req->wLength > reqdata_size) {
|
||||
ERROR("required data too long %u > %u", req->wLength, reqdata_size);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
} else {
|
||||
memset(ctrl_buf, 0, req->wLength);
|
||||
usb_drv_control_response(USB_CONTROL_ACK, ctrl_buf, req->wLength);
|
||||
memset(reqdata, 0, req->wLength);
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, req->wLength);
|
||||
}
|
||||
}
|
||||
|
||||
/* returns true when ctrl_buf has received data */
|
||||
static bool receive_data(struct usb_ctrlrequest* req, void* reqdata) {
|
||||
if(reqdata == NULL) {
|
||||
/* setup */
|
||||
if(req->wLength > sizeof(ctrl_buf)) {
|
||||
ERROR("parameter too long");
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
} else {
|
||||
usb_drv_control_response(USB_CONTROL_RECEIVE, ctrl_buf, req->wLength);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
/* data */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool control_request_if_std(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest) {
|
||||
(void)reqdata;
|
||||
|
||||
unsigned char* const orig_dest = dest;
|
||||
static bool control_request_if_std(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size) {
|
||||
const void* src = NULL;
|
||||
size_t size;
|
||||
switch(req->bRequest) {
|
||||
case USB_REQ_GET_DESCRIPTOR: {
|
||||
const uint8_t desc_type = req->wValue >> 8;
|
||||
|
|
@ -522,18 +502,28 @@ static bool control_request_if_std(struct usb_ctrlrequest* req, void* reqdata, u
|
|||
(void)desc_index;
|
||||
switch(desc_type) {
|
||||
case USB_DT_HID:
|
||||
PACK_DATA(&dest, ipod_hid_hid_desc);
|
||||
src = &ipod_hid_hid_desc;
|
||||
size = sizeof(ipod_hid_hid_desc);
|
||||
break;
|
||||
case USB_DT_REPORT:
|
||||
if(usb_drv_port_speed()) {
|
||||
PACK_DATA(&dest, ipod_hid_report_hs);
|
||||
src = &ipod_hid_report_hs;
|
||||
size = sizeof(ipod_hid_report_hs);
|
||||
} else {
|
||||
PACK_DATA(&dest, ipod_hid_report_fs);
|
||||
src = &ipod_hid_report_fs;
|
||||
size = sizeof(ipod_hid_report_fs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(dest != orig_dest) {
|
||||
usb_drv_control_response(USB_CONTROL_ACK, orig_dest, MIN(dest - orig_dest, req->wLength));
|
||||
if(src != NULL) {
|
||||
if(size > reqdata_size) {
|
||||
LOG("descriptor size too large");
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
} else {
|
||||
size = MIN(size, req->wLength);
|
||||
memcpy(reqdata, src, size);
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
|
|
@ -541,19 +531,14 @@ static bool control_request_if_std(struct usb_ctrlrequest* req, void* reqdata, u
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool control_request_if_class(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest) {
|
||||
(void)dest;
|
||||
|
||||
static bool control_request_if_class(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size) {
|
||||
const uint8_t recip_interface = req->wIndex & 0xff;
|
||||
if(recip_interface == hid.interface) {
|
||||
switch(req->bRequest) {
|
||||
case USB_HID_GET_REPORT:
|
||||
respond_zero(req);
|
||||
respond_zero(req, reqdata, reqdata_size);
|
||||
return true;
|
||||
case USB_HID_SET_REPORT: {
|
||||
if(!receive_data(req, reqdata)) {
|
||||
return true;
|
||||
}
|
||||
#if DEBUG_DUMP_RX == 1
|
||||
logf("==== acc: %u bytes ====", req->wLength);
|
||||
iap_platform_dump_hex(reqdata, req->wLength);
|
||||
|
|
@ -564,20 +549,18 @@ static bool control_request_if_class(struct usb_ctrlrequest* req, void* reqdata,
|
|||
_iap_release_ctx();
|
||||
|
||||
check_act(ret, return false);
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
case USB_HID_SET_IDLE:
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool control_request_if_endpoint(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest) {
|
||||
(void)dest;
|
||||
|
||||
static bool control_request_if_endpoint(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size) {
|
||||
LOG("ctrl to endpoint %x (stream=%x, hid=%x)", req->wIndex, AS_EP_IN, HID_EP_IN);
|
||||
if(req->wIndex == AS_EP_IN) {
|
||||
const uint8_t recip_entity = req->wIndex >> 8;
|
||||
|
|
@ -585,45 +568,42 @@ static bool control_request_if_endpoint(struct usb_ctrlrequest* req, void* reqda
|
|||
(void)recip_entity;
|
||||
switch(req->bRequest) {
|
||||
case USB_AC_SET_CUR:
|
||||
if(!receive_data(req, reqdata)) {
|
||||
return true;
|
||||
}
|
||||
LOG("audio ctrl to stream endpoint entity=0x%02X request=0x%02X length=%u", recip_entity, req->bRequest, req->wLength);
|
||||
switch(control_selector) {
|
||||
case USB_AS_EP_CS_SAMPLING_FREQ_CTL:
|
||||
check_act(req->wLength == 3, goto stall);
|
||||
stream.sample_rate = ctrl_buf[0] | (ctrl_buf[1] << 8) | (ctrl_buf[2] << 16);
|
||||
stream.sample_rate = reqdata[0] | (reqdata[1] << 8) | (reqdata[2] << 16);
|
||||
LOG("audio stream sampling rate %lu", stream.sample_rate);
|
||||
check_act(iap_audio_set_sampr(stream.sample_rate), goto stall);
|
||||
break;
|
||||
}
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
return true;
|
||||
case USB_AC_GET_CUR:
|
||||
switch(control_selector) {
|
||||
case USB_AS_EP_CS_SAMPLING_FREQ_CTL:
|
||||
check_act(req->wLength == 3, goto stall);
|
||||
ctrl_buf[2] = (stream.sample_rate >> 16) & 0xff;
|
||||
ctrl_buf[1] = (stream.sample_rate >> 8) & 0xff;
|
||||
ctrl_buf[0] = (stream.sample_rate & 0xff);
|
||||
usb_drv_control_response(USB_CONTROL_ACK, ctrl_buf, req->wLength);
|
||||
reqdata[2] = (stream.sample_rate >> 16) & 0xff;
|
||||
reqdata[1] = (stream.sample_rate >> 8) & 0xff;
|
||||
reqdata[0] = (stream.sample_rate & 0xff);
|
||||
usb_core_control_response(USB_CONTROL_ACK, reqdata, 3);
|
||||
return true;
|
||||
}
|
||||
/* fallthrough */
|
||||
case USB_AC_GET_MIN:
|
||||
case USB_AC_GET_MAX:
|
||||
case USB_AC_GET_RES:
|
||||
respond_zero(req);
|
||||
respond_zero(req, reqdata, reqdata_size);
|
||||
return true;
|
||||
stall:
|
||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool usb_iap_control_request(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest) {
|
||||
static bool usb_iap_control_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size) {
|
||||
const uint8_t req_recipient = req->bRequestType & USB_RECIP_MASK;
|
||||
const uint8_t req_type = req->bRequestType & USB_TYPE_MASK;
|
||||
#if 0
|
||||
|
|
@ -631,11 +611,11 @@ static bool usb_iap_control_request(struct usb_ctrlrequest* req, void* reqdata,
|
|||
LOG("recip=%x type=%x", req_recipient, req_type);
|
||||
#endif
|
||||
if(req_recipient == USB_RECIP_INTERFACE && req_type == USB_TYPE_STANDARD) {
|
||||
return control_request_if_std(req, reqdata, dest);
|
||||
return control_request_if_std(req, reqdata, reqdata_size);
|
||||
} else if(req_recipient == USB_RECIP_INTERFACE && req_type == USB_TYPE_CLASS) {
|
||||
return control_request_if_class(req, reqdata, dest);
|
||||
return control_request_if_class(req, reqdata, reqdata_size);
|
||||
} else if(req_recipient == USB_RECIP_ENDPOINT && req_type == USB_TYPE_CLASS) {
|
||||
return control_request_if_endpoint(req, reqdata, dest);
|
||||
return control_request_if_endpoint(req, reqdata, reqdata_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ union line_coding_buffer
|
|||
unsigned char raw[64];
|
||||
};
|
||||
|
||||
static union line_coding_buffer line_coding USB_DEVBSS_ATTR;
|
||||
static union line_coding_buffer line_coding;
|
||||
|
||||
/* send_buffer: local ring buffer.
|
||||
* transit_buffer: used to store aligned data that will be sent by the USB
|
||||
|
|
@ -270,12 +270,11 @@ static int usb_serial_get_config_descriptor(unsigned char *dest, int max_packet_
|
|||
}
|
||||
|
||||
/* called by usb_core_control_request() */
|
||||
static bool usb_serial_control_request(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest)
|
||||
static bool usb_serial_control_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
bool handled = false;
|
||||
(void)reqdata_size; /* should check this? */
|
||||
|
||||
(void)dest;
|
||||
(void)reqdata;
|
||||
bool handled = false;
|
||||
|
||||
if (req->wIndex != control_interface)
|
||||
{
|
||||
|
|
@ -289,16 +288,7 @@ static bool usb_serial_control_request(struct usb_ctrlrequest* req, void* reqdat
|
|||
if (req->wLength == sizeof(struct cdc_line_coding))
|
||||
{
|
||||
/* Receive line coding into local copy */
|
||||
if (!reqdata)
|
||||
{
|
||||
usb_drv_control_response(USB_CONTROL_RECEIVE, line_coding.raw,
|
||||
sizeof(struct cdc_line_coding));
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
}
|
||||
|
||||
memcpy(line_coding.raw, reqdata, sizeof(struct cdc_line_coding));
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -307,7 +297,7 @@ static bool usb_serial_control_request(struct usb_ctrlrequest* req, void* reqdat
|
|||
if (req->wLength == 0)
|
||||
{
|
||||
/* wValue holds Control Signal Bitmap that is simply ignored here */
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -319,7 +309,7 @@ static bool usb_serial_control_request(struct usb_ctrlrequest* req, void* reqdat
|
|||
if (req->wLength == sizeof(struct cdc_line_coding))
|
||||
{
|
||||
/* Send back line coding so host is happy */
|
||||
usb_drv_control_response(USB_CONTROL_ACK, line_coding.raw,
|
||||
usb_core_control_response(USB_CONTROL_ACK, line_coding.raw,
|
||||
sizeof(struct cdc_line_coding));
|
||||
handled = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -695,12 +695,12 @@ static void usb_storage_send_smart(uint8_t cmd)
|
|||
#endif /* STORAGE_ATA */
|
||||
|
||||
/* called by usb_core_control_request() */
|
||||
static bool usb_storage_control_request(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest)
|
||||
static bool usb_storage_control_request(struct usb_ctrlrequest* req, uint8_t* reqdata, size_t reqdata_size)
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
(void)dest;
|
||||
(void)reqdata;
|
||||
(void)reqdata_size;
|
||||
|
||||
bool handled = false;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_BULK_GET_MAX_LUN: {
|
||||
|
|
@ -709,7 +709,7 @@ static bool usb_storage_control_request(struct usb_ctrlrequest* req, void* reqda
|
|||
if(skip_first) (*tb.max_lun) --;
|
||||
#endif
|
||||
logf("ums: getmaxlun");
|
||||
usb_drv_control_response(USB_CONTROL_ACK, tb.max_lun, 1);
|
||||
usb_core_control_response(USB_CONTROL_ACK, tb.max_lun, 1);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -724,7 +724,7 @@ static bool usb_storage_control_request(struct usb_ctrlrequest* req, void* reqda
|
|||
usb_drv_reset_endpoint(EP_IN, false);
|
||||
usb_drv_reset_endpoint(EP_OUT, true);
|
||||
#endif
|
||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
usb_core_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue