mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
usb_host: handle control URBs asynchronously
In the Genode C API and the DDE Linux USB host driver, turn control URBs into asynchronously handled ones. Fix genodelabs/genode#4535
This commit is contained in:
parent
1ca2265fd4
commit
0b5ad90bde
@ -48,15 +48,7 @@ static int usb_drv_probe(struct usb_interface *interface,
|
|||||||
return -ENODEV; }
|
return -ENODEV; }
|
||||||
|
|
||||||
|
|
||||||
static void usb_drv_disconnect(struct usb_interface *iface)
|
static void usb_drv_disconnect(struct usb_interface *iface) { }
|
||||||
{
|
|
||||||
struct usb_iface_urbs * urbs = usb_get_intfdata(iface);
|
|
||||||
if (urbs) {
|
|
||||||
urbs->in_delete = 1;
|
|
||||||
usb_kill_anchored_urbs(&urbs->submitted);
|
|
||||||
kfree(urbs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct usb_driver usb_drv = {
|
static struct usb_driver usb_drv = {
|
||||||
@ -213,12 +205,7 @@ static struct task_struct * usb_rpc_task;
|
|||||||
|
|
||||||
static int claim_iface(struct usb_interface * iface)
|
static int claim_iface(struct usb_interface * iface)
|
||||||
{
|
{
|
||||||
struct usb_iface_urbs *urbs = (struct usb_iface_urbs*)
|
return usb_driver_claim_interface(&usb_drv, iface, NULL);
|
||||||
kmalloc(sizeof(struct usb_iface_urbs), GFP_KERNEL);
|
|
||||||
init_usb_anchor(&urbs->submitted);
|
|
||||||
urbs->in_delete = 0;
|
|
||||||
return usb_driver_claim_interface(&usb_drv, iface, urbs);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,8 +253,13 @@ static int usb_rpc_call(void * data)
|
|||||||
release_iface(iface);
|
release_iface(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_rpc_args.call == RELEASE_ALL)
|
if (usb_rpc_args.call == RELEASE_ALL) {
|
||||||
|
struct usb_iface_urbs * urbs = dev_get_drvdata(&udev->dev);
|
||||||
|
urbs->in_delete = 1;
|
||||||
|
usb_kill_anchored_urbs(&urbs->submitted);
|
||||||
|
urbs->in_delete = 0;
|
||||||
usb_reset_device(udev);
|
usb_reset_device(udev);
|
||||||
|
}
|
||||||
|
|
||||||
usb_rpc_args.ret = ret;
|
usb_rpc_args.ret = ret;
|
||||||
}
|
}
|
||||||
@ -337,39 +329,6 @@ struct genode_usb_rpc_callbacks lx_emul_usb_rpc_callbacks = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static genode_usb_request_ret_t
|
|
||||||
handle_ctrl_request(struct genode_usb_request_control * req,
|
|
||||||
void * buf, unsigned long size, void * data)
|
|
||||||
{
|
|
||||||
struct usb_device * udev = (struct usb_device *) data;
|
|
||||||
|
|
||||||
int pipe = (req->request_type & 0x80)
|
|
||||||
? usb_rcvctrlpipe(udev, 0) : usb_sndctrlpipe(udev, 0);
|
|
||||||
|
|
||||||
int err = usb_control_msg(udev, pipe, req->request, req->request_type,
|
|
||||||
req->value, req->index, buf, size, req->timeout);
|
|
||||||
|
|
||||||
if (err >= 0) {
|
|
||||||
req->actual_size = err;
|
|
||||||
return NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
req->actual_size = 0;
|
|
||||||
|
|
||||||
switch (err) {
|
|
||||||
case -ENOENT: return INTERFACE_OR_ENDPOINT_ERROR;
|
|
||||||
case -ENODEV: return NO_DEVICE_ERROR;
|
|
||||||
case -ESHUTDOWN: return NO_DEVICE_ERROR;
|
|
||||||
case -EPROTO: return PROTOCOL_ERROR;
|
|
||||||
case -EILSEQ: return PROTOCOL_ERROR;
|
|
||||||
case -EPIPE: return STALL_ERROR;
|
|
||||||
case -ETIMEDOUT: return TIMEOUT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UNKNOWN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static genode_usb_request_ret_t
|
static genode_usb_request_ret_t
|
||||||
handle_string_request(struct genode_usb_request_string * req,
|
handle_string_request(struct genode_usb_request_string * req,
|
||||||
void * buf, unsigned long size, void * data)
|
void * buf, unsigned long size, void * data)
|
||||||
@ -426,26 +385,53 @@ handle_flush_request(unsigned char ep, void * data)
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Timer_state { TIMER_OFF, TIMER_ACTIVE, TIMER_TRIGGERED };
|
||||||
|
|
||||||
|
struct usb_urb_context
|
||||||
|
{
|
||||||
|
genode_usb_session_handle_t session;
|
||||||
|
genode_usb_request_handle_t request;
|
||||||
|
struct urb * urb;
|
||||||
|
struct timer_list timeo;
|
||||||
|
enum Timer_state timer_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static genode_usb_request_ret_t
|
static genode_usb_request_ret_t
|
||||||
handle_transfer_response(struct genode_usb_request_transfer * req,
|
handle_transfer_response(struct genode_usb_request_urb req,
|
||||||
void * data)
|
void * data)
|
||||||
{
|
{
|
||||||
struct urb * urb = (struct urb *) data;
|
struct usb_urb_context * context = (struct usb_urb_context *) data;
|
||||||
|
struct urb * urb = context->urb;
|
||||||
|
struct genode_usb_request_control * ctrl =
|
||||||
|
genode_usb_get_request_control(&req);
|
||||||
|
struct genode_usb_request_transfer * transfer =
|
||||||
|
genode_usb_get_request_transfer(&req);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (urb->status == 0) {
|
if (urb->status == 0) {
|
||||||
req->actual_size = urb->actual_length;
|
if (ctrl)
|
||||||
|
ctrl->actual_size = urb->actual_length;
|
||||||
|
if (transfer) {
|
||||||
|
transfer->actual_size = urb->actual_length;
|
||||||
|
|
||||||
if (usb_pipein(urb->pipe))
|
if (usb_pipein(urb->pipe))
|
||||||
for (i = 0; i < urb->number_of_packets; i++)
|
for (i = 0; i < urb->number_of_packets; i++)
|
||||||
req->actual_packet_size[i] = urb->iso_frame_desc[i].actual_length;
|
transfer->actual_packet_size[i] =
|
||||||
|
urb->iso_frame_desc[i].actual_length;
|
||||||
|
}
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctrl)
|
||||||
|
ctrl->actual_size = 0;
|
||||||
|
|
||||||
|
if (context->timer_state == TIMER_TRIGGERED)
|
||||||
|
return TIMEOUT_ERROR;
|
||||||
|
|
||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
|
case -ENOENT: return INTERFACE_OR_ENDPOINT_ERROR;
|
||||||
|
case -ENODEV: return NO_DEVICE_ERROR;
|
||||||
case -ESHUTDOWN: return NO_DEVICE_ERROR;
|
case -ESHUTDOWN: return NO_DEVICE_ERROR;
|
||||||
case -EPROTO: return PROTOCOL_ERROR;
|
case -EPROTO: return PROTOCOL_ERROR;
|
||||||
case -EILSEQ: return PROTOCOL_ERROR;
|
case -EILSEQ: return PROTOCOL_ERROR;
|
||||||
@ -455,55 +441,83 @@ handle_transfer_response(struct genode_usb_request_transfer * req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct usb_interface * usb_get_iface_from_urb(struct urb * urb)
|
static void usb_free_complete_urb(struct urb * urb)
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
if (!urb)
|
||||||
struct usb_host_endpoint * ep = usb_pipe_endpoint(urb->dev, urb->pipe);
|
return;
|
||||||
|
if (urb->setup_packet)
|
||||||
if (!ep || !urb->dev || !urb->dev->actconfig)
|
kfree(urb->setup_packet);
|
||||||
return NULL;
|
if (urb->context) {
|
||||||
|
struct usb_urb_context * context =
|
||||||
for (i = 0; i < urb->dev->actconfig->desc.bNumInterfaces; i++) {
|
(struct usb_urb_context *) urb->context;
|
||||||
struct usb_interface * iface = urb->dev->actconfig->interface[i];
|
if (context->timer_state != TIMER_OFF)
|
||||||
if (!iface || !iface->cur_altsetting)
|
del_timer_sync(&context->timeo);
|
||||||
continue;
|
kfree(context);
|
||||||
for (j = 0; j < iface->cur_altsetting->desc.bNumEndpoints; j++) {
|
|
||||||
if (&iface->cur_altsetting->endpoint[j] != ep)
|
|
||||||
continue;
|
|
||||||
return iface;
|
|
||||||
}
|
}
|
||||||
}
|
usb_free_urb(urb);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void async_complete(struct urb *urb)
|
static void async_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct usb_interface * iface;
|
struct usb_iface_urbs * urbs = dev_get_drvdata(&urb->dev->dev);
|
||||||
struct usb_iface_urbs * urbs = NULL;
|
|
||||||
|
|
||||||
unsigned long handle = (unsigned long)urb->context;
|
struct usb_urb_context * context =
|
||||||
genode_usb_session_handle_t session =
|
(struct usb_urb_context*) urb->context;
|
||||||
(genode_usb_session_handle_t) (handle >> 16);
|
|
||||||
genode_usb_request_handle_t request =
|
|
||||||
(genode_usb_request_handle_t) (handle & 0xffff);
|
|
||||||
|
|
||||||
genode_usb_ack_request(session, request,
|
genode_usb_ack_request(context->session, context->request,
|
||||||
handle_transfer_response, (void*)urb);
|
handle_transfer_response, (void*)context);
|
||||||
|
|
||||||
iface = usb_get_iface_from_urb(urb);
|
|
||||||
if (iface)
|
|
||||||
urbs = usb_get_intfdata(iface);
|
|
||||||
if (!urbs || !urbs->in_delete) {
|
if (!urbs || !urbs->in_delete) {
|
||||||
usb_free_urb(urb);
|
usb_free_complete_urb(urb);
|
||||||
lx_user_handle_io();
|
lx_user_handle_io();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void urb_timeout(struct timer_list *t)
|
||||||
|
{
|
||||||
|
struct usb_urb_context * context = from_timer(context, t, timeo);
|
||||||
|
context->timer_state = TIMER_TRIGGERED;
|
||||||
|
usb_kill_urb(context->urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int fill_ctrl_urb(struct usb_device * udev,
|
||||||
|
struct genode_usb_request_control * req,
|
||||||
|
void * handle,
|
||||||
|
void * buf,
|
||||||
|
unsigned long size,
|
||||||
|
int read,
|
||||||
|
struct urb ** urb)
|
||||||
|
{
|
||||||
|
int pipe = read ? usb_rcvctrlpipe(udev, 0) : usb_sndctrlpipe(udev, 0);
|
||||||
|
struct usb_ctrlrequest * ucr =
|
||||||
|
kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
|
||||||
|
|
||||||
|
*urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!ucr || !*urb) {
|
||||||
|
if (ucr) kfree(ucr);
|
||||||
|
if (*urb) usb_free_urb(*urb);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ucr->bRequestType = req->request_type;
|
||||||
|
ucr->bRequest = req->request;
|
||||||
|
ucr->wValue = cpu_to_le16(req->value);
|
||||||
|
ucr->wIndex = cpu_to_le16(req->index);
|
||||||
|
ucr->wLength = cpu_to_le16(size);
|
||||||
|
|
||||||
|
usb_fill_control_urb(*urb, udev, pipe, (unsigned char*)ucr, buf, size,
|
||||||
|
async_complete, handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int fill_bulk_urb(struct usb_device * udev,
|
static int fill_bulk_urb(struct usb_device * udev,
|
||||||
struct genode_usb_request_transfer * req,
|
struct genode_usb_request_transfer * req,
|
||||||
unsigned long handle,
|
void * handle,
|
||||||
void * buf,
|
void * buf,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
int read,
|
int read,
|
||||||
@ -516,15 +530,14 @@ static int fill_bulk_urb(struct usb_device * udev,
|
|||||||
if (!*urb)
|
if (!*urb)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
usb_fill_bulk_urb(*urb, udev, pipe, buf, size,
|
usb_fill_bulk_urb(*urb, udev, pipe, buf, size, async_complete, handle);
|
||||||
async_complete, (void*)handle);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int fill_irq_urb(struct usb_device * udev,
|
static int fill_irq_urb(struct usb_device * udev,
|
||||||
struct genode_usb_request_transfer * req,
|
struct genode_usb_request_transfer * req,
|
||||||
unsigned long handle,
|
void * handle,
|
||||||
void * buf,
|
void * buf,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
int read,
|
int read,
|
||||||
@ -551,14 +564,14 @@ static int fill_irq_urb(struct usb_device * udev,
|
|||||||
polling_interval = req->polling_interval;
|
polling_interval = req->polling_interval;
|
||||||
|
|
||||||
usb_fill_int_urb(*urb, udev, pipe, buf, size,
|
usb_fill_int_urb(*urb, udev, pipe, buf, size,
|
||||||
async_complete, (void*)handle, polling_interval);
|
async_complete, handle, polling_interval);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int fill_isoc_urb(struct usb_device * udev,
|
static int fill_isoc_urb(struct usb_device * udev,
|
||||||
struct genode_usb_request_transfer * req,
|
struct genode_usb_request_transfer * req,
|
||||||
unsigned long handle,
|
void * handle,
|
||||||
void * buf,
|
void * buf,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
int read,
|
int read,
|
||||||
@ -584,7 +597,7 @@ static int fill_isoc_urb(struct usb_device * udev,
|
|||||||
(*urb)->transfer_buffer_length = size;
|
(*urb)->transfer_buffer_length = size;
|
||||||
(*urb)->number_of_packets = req->number_of_packets;
|
(*urb)->number_of_packets = req->number_of_packets;
|
||||||
(*urb)->interval = 1 << min(15, ep->desc.bInterval - 1);
|
(*urb)->interval = 1 << min(15, ep->desc.bInterval - 1);
|
||||||
(*urb)->context = (void *)handle;
|
(*urb)->context = handle;
|
||||||
(*urb)->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT);
|
(*urb)->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT);
|
||||||
(*urb)->complete = async_complete;
|
(*urb)->complete = async_complete;
|
||||||
|
|
||||||
@ -599,54 +612,71 @@ static int fill_isoc_urb(struct usb_device * udev,
|
|||||||
|
|
||||||
|
|
||||||
static genode_usb_request_ret_t
|
static genode_usb_request_ret_t
|
||||||
handle_transfer_request(struct genode_usb_request_transfer * req,
|
handle_urb_request(struct genode_usb_request_urb req,
|
||||||
genode_usb_transfer_type_t type,
|
|
||||||
genode_usb_session_handle_t session_handle,
|
genode_usb_session_handle_t session_handle,
|
||||||
genode_usb_request_handle_t request_handle,
|
genode_usb_request_handle_t request_handle,
|
||||||
void * buf, unsigned long size, void * data)
|
void * buf, unsigned long size, void * data)
|
||||||
{
|
{
|
||||||
struct usb_device * udev = (struct usb_device *) data;
|
struct usb_device * udev = (struct usb_device *) data;
|
||||||
|
struct usb_iface_urbs * urbs = dev_get_drvdata(&udev->dev);
|
||||||
|
struct genode_usb_request_control * ctrl =
|
||||||
|
genode_usb_get_request_control(&req);
|
||||||
|
struct genode_usb_request_transfer * transfer =
|
||||||
|
genode_usb_get_request_transfer(&req);
|
||||||
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int read = (req->ep & 0x80);
|
int read = transfer ? (transfer->ep & 0x80) : 0;
|
||||||
unsigned long handle = session_handle << 16 | request_handle;
|
|
||||||
struct urb * urb;
|
struct urb * urb;
|
||||||
|
|
||||||
switch (type) {
|
struct usb_urb_context * context =
|
||||||
|
kmalloc(sizeof(struct usb_urb_context), GFP_NOIO);
|
||||||
|
if (!context)
|
||||||
|
return MEMORY_ERROR;
|
||||||
|
|
||||||
|
context->session = session_handle;
|
||||||
|
context->request = request_handle;
|
||||||
|
|
||||||
|
switch (req.type) {
|
||||||
|
case CTRL:
|
||||||
|
err = fill_ctrl_urb(udev, ctrl, context, buf, size,
|
||||||
|
(ctrl->request_type & 0x80), &urb);
|
||||||
|
break;
|
||||||
case BULK:
|
case BULK:
|
||||||
err = fill_bulk_urb(udev, req, handle, buf, size, read, &urb);
|
err = fill_bulk_urb(udev, transfer, context, buf, size, read, &urb);
|
||||||
break;
|
break;
|
||||||
case IRQ:
|
case IRQ:
|
||||||
err = fill_irq_urb(udev, req, handle, buf, size, read, &urb);
|
err = fill_irq_urb(udev, transfer, context, buf, size, read, &urb);
|
||||||
break;
|
break;
|
||||||
case ISOC:
|
case ISOC:
|
||||||
err = fill_isoc_urb(udev, req, handle, buf, size, read, &urb);
|
err = fill_isoc_urb(udev, transfer, context, buf, size, read, &urb);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk("Unknown USB transfer request!\n");
|
printk("Unknown USB transfer request!\n");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!err) {
|
if (err)
|
||||||
struct usb_iface_urbs * urbs;
|
goto free_context;
|
||||||
struct usb_interface * iface = usb_get_iface_from_urb(urb);
|
|
||||||
if (!iface) {
|
|
||||||
usb_free_urb(urb);
|
|
||||||
return NO_DEVICE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!usb_interface_claimed(iface))
|
context->urb = urb;
|
||||||
claim_iface(iface);
|
|
||||||
urbs = usb_get_intfdata(iface);
|
|
||||||
usb_anchor_urb(urb, &urbs->submitted);
|
usb_anchor_urb(urb, &urbs->submitted);
|
||||||
|
|
||||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||||
|
if (err)
|
||||||
|
goto free_urb;
|
||||||
|
|
||||||
if (!err)
|
if (ctrl && ctrl->timeout) {
|
||||||
return NO_ERROR;
|
context->timer_state = TIMER_ACTIVE;
|
||||||
|
timer_setup(&context->timeo, urb_timeout, 0);
|
||||||
usb_free_urb(urb);
|
mod_timer(&context->timeo, jiffies + msecs_to_jiffies(ctrl->timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_urb:
|
||||||
|
usb_unanchor_urb(urb);
|
||||||
|
usb_free_complete_urb(urb);
|
||||||
|
free_context:
|
||||||
|
kfree(context);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case -ENOENT: return INTERFACE_OR_ENDPOINT_ERROR;
|
case -ENOENT: return INTERFACE_OR_ENDPOINT_ERROR;
|
||||||
case -ENODEV: return NO_DEVICE_ERROR;
|
case -ENODEV: return NO_DEVICE_ERROR;
|
||||||
@ -659,8 +689,7 @@ handle_transfer_request(struct genode_usb_request_transfer * req,
|
|||||||
|
|
||||||
|
|
||||||
static struct genode_usb_request_callbacks request_callbacks = {
|
static struct genode_usb_request_callbacks request_callbacks = {
|
||||||
.control_fn = handle_ctrl_request,
|
.urb_fn = handle_urb_request,
|
||||||
.transfer_fn = handle_transfer_request,
|
|
||||||
.string_fn = handle_string_request,
|
.string_fn = handle_string_request,
|
||||||
.altsetting_fn = handle_altsetting_request,
|
.altsetting_fn = handle_altsetting_request,
|
||||||
.config_fn = handle_config_request,
|
.config_fn = handle_config_request,
|
||||||
@ -744,6 +773,12 @@ static int raw_notify(struct notifier_block *nb, unsigned long action, void *dat
|
|||||||
*/
|
*/
|
||||||
unsigned long class;
|
unsigned long class;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
struct usb_iface_urbs *urbs = (struct usb_iface_urbs*)
|
||||||
|
kmalloc(sizeof(struct usb_iface_urbs), GFP_KERNEL);
|
||||||
|
init_usb_anchor(&urbs->submitted);
|
||||||
|
urbs->in_delete = 0;
|
||||||
|
dev_set_drvdata(&udev->dev, urbs);
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
|
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
|
||||||
struct usb_interface * iface = udev->actconfig->interface[i];
|
struct usb_interface * iface = udev->actconfig->interface[i];
|
||||||
@ -764,7 +799,14 @@ static int raw_notify(struct notifier_block *nb, unsigned long action, void *dat
|
|||||||
|
|
||||||
case USB_DEVICE_REMOVE:
|
case USB_DEVICE_REMOVE:
|
||||||
{
|
{
|
||||||
|
struct usb_iface_urbs * urbs = dev_get_drvdata(&udev->dev);
|
||||||
|
urbs->in_delete = 1;
|
||||||
|
usb_kill_anchored_urbs(&urbs->submitted);
|
||||||
|
kfree(urbs);
|
||||||
|
|
||||||
|
|
||||||
genode_usb_discontinue_device(udev->bus->busnum, udev->devnum);
|
genode_usb_discontinue_device(udev->bus->busnum, udev->devnum);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,8 +148,6 @@ struct genode_usb_request_control
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum Iso { MAX_PACKETS = 32 };
|
enum Iso { MAX_PACKETS = 32 };
|
||||||
enum Transfer { BULK, IRQ, ISOC };
|
|
||||||
typedef enum Transfer genode_usb_transfer_type_t;
|
|
||||||
|
|
||||||
struct genode_usb_request_transfer
|
struct genode_usb_request_transfer
|
||||||
{
|
{
|
||||||
@ -161,6 +159,27 @@ struct genode_usb_request_transfer
|
|||||||
unsigned long actual_packet_size[MAX_PACKETS];
|
unsigned long actual_packet_size[MAX_PACKETS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Urb_type { CTRL, BULK, IRQ, ISOC };
|
||||||
|
typedef enum Urb_type genode_usb_urb_t;
|
||||||
|
|
||||||
|
struct genode_usb_request_urb
|
||||||
|
{
|
||||||
|
genode_usb_urb_t type;
|
||||||
|
void * req;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct genode_usb_request_control *
|
||||||
|
genode_usb_get_request_control(struct genode_usb_request_urb * urb)
|
||||||
|
{
|
||||||
|
return (urb->type == CTRL) ? (struct genode_usb_request_control*)urb->req : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct genode_usb_request_transfer *
|
||||||
|
genode_usb_get_request_transfer(struct genode_usb_request_urb * urb)
|
||||||
|
{
|
||||||
|
return (urb->type != CTRL) ? (struct genode_usb_request_transfer*)urb->req : 0;
|
||||||
|
}
|
||||||
|
|
||||||
enum Request_return_error {
|
enum Request_return_error {
|
||||||
NO_ERROR,
|
NO_ERROR,
|
||||||
INTERFACE_OR_ENDPOINT_ERROR,
|
INTERFACE_OR_ENDPOINT_ERROR,
|
||||||
@ -174,15 +193,8 @@ enum Request_return_error {
|
|||||||
};
|
};
|
||||||
typedef enum Request_return_error genode_usb_request_ret_t;
|
typedef enum Request_return_error genode_usb_request_ret_t;
|
||||||
|
|
||||||
typedef genode_usb_request_ret_t (*genode_usb_req_ctrl_t)
|
typedef genode_usb_request_ret_t (*genode_usb_req_urb_t)
|
||||||
(struct genode_usb_request_control * req,
|
(struct genode_usb_request_urb req,
|
||||||
void * payload,
|
|
||||||
unsigned long payload_size,
|
|
||||||
void * opaque_data);
|
|
||||||
|
|
||||||
typedef genode_usb_request_ret_t (*genode_usb_req_transfer_t)
|
|
||||||
(struct genode_usb_request_transfer * req,
|
|
||||||
genode_usb_transfer_type_t type,
|
|
||||||
genode_usb_session_handle_t session_handle,
|
genode_usb_session_handle_t session_handle,
|
||||||
genode_usb_request_handle_t request_handle,
|
genode_usb_request_handle_t request_handle,
|
||||||
void * payload,
|
void * payload,
|
||||||
@ -205,12 +217,11 @@ typedef genode_usb_request_ret_t (*genode_usb_req_flush_t)
|
|||||||
(unsigned char ep, void * opaque_data);
|
(unsigned char ep, void * opaque_data);
|
||||||
|
|
||||||
typedef genode_usb_request_ret_t (*genode_usb_response_t)
|
typedef genode_usb_request_ret_t (*genode_usb_response_t)
|
||||||
(struct genode_usb_request_transfer * req,
|
(struct genode_usb_request_urb req,
|
||||||
void * opaque_data);
|
void * opaque_data);
|
||||||
|
|
||||||
struct genode_usb_request_callbacks {
|
struct genode_usb_request_callbacks {
|
||||||
genode_usb_req_ctrl_t control_fn;
|
genode_usb_req_urb_t urb_fn;
|
||||||
genode_usb_req_transfer_t transfer_fn;
|
|
||||||
genode_usb_req_string_t string_fn;
|
genode_usb_req_string_t string_fn;
|
||||||
genode_usb_req_altsetting_t altsetting_fn;
|
genode_usb_req_altsetting_t altsetting_fn;
|
||||||
genode_usb_req_config_t config_fn;
|
genode_usb_req_config_t config_fn;
|
||||||
|
@ -450,23 +450,20 @@ bool genode_usb_session::request(genode_usb_request_callbacks & req, void * data
|
|||||||
addr, p.size(), data), p);
|
addr, p.size(), data), p);
|
||||||
break;
|
break;
|
||||||
case Packet_descriptor::CTRL:
|
case Packet_descriptor::CTRL:
|
||||||
_ack(req.control_fn((genode_usb_request_control*)&p.control,
|
packets[idx].construct(p);
|
||||||
addr, p.size(), data), p);
|
req.urb_fn({ CTRL, &p.control }, _id, idx, addr, p.size(), data);
|
||||||
break;
|
break;
|
||||||
case Packet_descriptor::BULK:
|
case Packet_descriptor::BULK:
|
||||||
packets[idx].construct(p);
|
packets[idx].construct(p);
|
||||||
req.transfer_fn((genode_usb_request_transfer*)&p.transfer, BULK,
|
req.urb_fn({ BULK, &p.transfer }, _id, idx, addr, p.size(), data);
|
||||||
_id, idx, addr, p.size(), data);
|
|
||||||
break;
|
break;
|
||||||
case Packet_descriptor::IRQ:
|
case Packet_descriptor::IRQ:
|
||||||
packets[idx].construct(p);
|
packets[idx].construct(p);
|
||||||
req.transfer_fn((genode_usb_request_transfer*)&p.transfer, IRQ,
|
req.urb_fn({ IRQ, &p.transfer }, _id, idx, addr, p.size(), data);
|
||||||
_id, idx, addr, p.size(), data);
|
|
||||||
break;
|
break;
|
||||||
case Packet_descriptor::ISOC:
|
case Packet_descriptor::ISOC:
|
||||||
packets[idx].construct(p);
|
packets[idx].construct(p);
|
||||||
req.transfer_fn((genode_usb_request_transfer*)&p.transfer, ISOC,
|
req.urb_fn({ ISOC, &p.transfer }, _id, idx, addr, p.size(), data);
|
||||||
_id, idx, addr, p.size(), data);
|
|
||||||
break;
|
break;
|
||||||
case Packet_descriptor::ALT_SETTING:
|
case Packet_descriptor::ALT_SETTING:
|
||||||
_ack(req.altsetting_fn(p.interface.number,
|
_ack(req.altsetting_fn(p.interface.number,
|
||||||
@ -491,9 +488,25 @@ void genode_usb_session::handle_response(genode_usb_request_handle_t id,
|
|||||||
genode_usb_response_t callback,
|
genode_usb_response_t callback,
|
||||||
void * callback_data)
|
void * callback_data)
|
||||||
{
|
{
|
||||||
Usb::Packet_descriptor p = *packets[id];
|
using Packet_descriptor = Usb::Packet_descriptor;
|
||||||
_ack(callback((genode_usb_request_transfer*)&p.transfer,
|
|
||||||
callback_data), p);
|
Packet_descriptor p = *packets[id];
|
||||||
|
switch (p.type) {
|
||||||
|
case Packet_descriptor::CTRL:
|
||||||
|
_ack(callback({ CTRL, &p.control }, callback_data), p);
|
||||||
|
break;
|
||||||
|
case Packet_descriptor::BULK:
|
||||||
|
_ack(callback({ BULK, &p.transfer }, callback_data), p);
|
||||||
|
break;
|
||||||
|
case Packet_descriptor::IRQ:
|
||||||
|
_ack(callback({ IRQ, &p.transfer }, callback_data), p);
|
||||||
|
break;
|
||||||
|
case Packet_descriptor::ISOC:
|
||||||
|
_ack(callback({ ISOC, &p.transfer }, callback_data), p);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Invalid packet descriptor for asynchronous response");
|
||||||
|
};
|
||||||
packets[id].destruct();
|
packets[id].destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user