diff --git a/repos/dde_linux/patches/usb_message.patch b/repos/dde_linux/patches/usb_message.patch deleted file mode 100644 index 5536291942..0000000000 --- a/repos/dde_linux/patches/usb_message.patch +++ /dev/null @@ -1,19 +0,0 @@ -+++ src/linux/drivers/usb/core/message.c -@@ -869,7 +869,7 @@ - } - } - --static int usb_string_sub(struct usb_device *dev, unsigned int langid, -+int usb_string_sub(struct usb_device *dev, unsigned int langid, - unsigned int index, unsigned char *buf) - { - int rc; -@@ -906,7 +906,7 @@ - return rc; - } - --static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) -+int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) - { - int err; - diff --git a/repos/dde_linux/ports/linux.hash b/repos/dde_linux/ports/linux.hash index 01a1096471..e0eba16af2 100644 --- a/repos/dde_linux/ports/linux.hash +++ b/repos/dde_linux/ports/linux.hash @@ -1 +1 @@ -0c5bbb2cab108531df25b2c92610ce92c57abc87 +6d981ad90be7e1fc9eb1dfd8513698d4e2a37a45 diff --git a/repos/dde_linux/ports/linux.port b/repos/dde_linux/ports/linux.port index 1ba4e0ea53..309e35c417 100644 --- a/repos/dde_linux/ports/linux.port +++ b/repos/dde_linux/ports/linux.port @@ -12,7 +12,6 @@ DIR(linux) := src/linux PATCH_FILES := i915_irq.patch i915_fb_resize.patch \ iwlwifi_enable_irq_before_pnvm.patch \ iwlwifi_limit_rx_bufs.patch \ - usb_message.patch \ workqueue_deadlock.patch PATCHES += $(addprefix patches/,$(PATCH_FILES)) diff --git a/repos/dde_linux/src/include/lx_emul/init.h b/repos/dde_linux/src/include/lx_emul/init.h index a18c8ca3fd..6a3a535ef9 100644 --- a/repos/dde_linux/src/include/lx_emul/init.h +++ b/repos/dde_linux/src/include/lx_emul/init.h @@ -24,7 +24,7 @@ void lx_emul_register_initcall(int (*initcall)(void), const char * name); void lx_emul_start_kernel(void * dtb); -void lx_emul_execute_kernel_until(int (*condition)(void)); +void lx_emul_execute_kernel_until(int (*condition)(void*), void * args); void lx_emul_setup_arch(void * dtb); diff --git a/repos/dde_linux/src/include/lx_emul/usb.h b/repos/dde_linux/src/include/lx_emul/usb.h index 38d9245ed6..fe3936d90d 100644 --- a/repos/dde_linux/src/include/lx_emul/usb.h +++ b/repos/dde_linux/src/include/lx_emul/usb.h @@ -20,6 +20,9 @@ extern "C" { extern struct genode_usb_rpc_callbacks lx_emul_usb_rpc_callbacks; +struct file_operations; +void lx_emul_usb_register_devio(const struct file_operations * fops); + #ifdef __cplusplus } #endif diff --git a/repos/dde_linux/src/lib/lx_emul/init.cc b/repos/dde_linux/src/lib/lx_emul/init.cc index 44eac5569b..92dc85e743 100644 --- a/repos/dde_linux/src/lib/lx_emul/init.cc +++ b/repos/dde_linux/src/lib/lx_emul/init.cc @@ -63,11 +63,11 @@ extern "C" void lx_emul_start_kernel(void * dtb) } -extern "C" void lx_emul_execute_kernel_until(int (*condition)(void)) +extern "C" void lx_emul_execute_kernel_until(int (*condition)(void*), void * args) { Lx_kit::env().scheduler.schedule(); - while (!condition()) { + while (!condition(args)) { Lx_kit::env().env.ep().wait_and_dispatch_one_io_signal(); } } diff --git a/repos/dde_linux/src/lib/lx_emul/usb.c b/repos/dde_linux/src/lib/lx_emul/usb.c index abc2d94e40..ce253594e4 100644 --- a/repos/dde_linux/src/lib/lx_emul/usb.c +++ b/repos/dde_linux/src/lib/lx_emul/usb.c @@ -20,14 +20,18 @@ #include #include #include +#include #include #include +#include #include #include #include +static struct file_operations * usbdev_file_operations = NULL; + struct usb_interface; struct usb_find_request { @@ -37,12 +41,6 @@ struct usb_find_request { }; -struct usb_iface_urbs { - struct usb_anchor submitted; - int in_delete; -}; - - static int usb_drv_probe(struct usb_interface *interface, const struct usb_device_id *id) { return -ENODEV; } @@ -188,93 +186,149 @@ static int endpoint_descriptor(genode_usb_bus_num_t bus, } +static inline void * +usercontext_from_handle(genode_usb_session_handle_t session_handle, + genode_usb_request_handle_t request_handle) +{ + return (void*)(((unsigned long)session_handle << 16) | request_handle); +} + + +static inline void +handle_from_usercontext(void * usercontext, + genode_usb_session_handle_t * session_handle, + genode_usb_request_handle_t * request_handle) +{ + *session_handle = (genode_usb_session_handle_t)((unsigned long)usercontext >> 16); + *request_handle = (genode_usb_request_handle_t)((unsigned long)usercontext & 0xffff); +} + + +static genode_usb_request_ret_t +handle_return_code(struct genode_usb_request_urb req, + struct genode_usb_buffer payload, + void *data) +{ + switch (*(int*)data) { + case 0: return NO_ERROR; + case -ENOENT: return INTERFACE_OR_ENDPOINT_ERROR; + case -ENOMEM: return MEMORY_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; + default: return UNKNOWN_ERROR; + }; +}; + + typedef enum usb_rpc_call_type { + NOTHING, CLAIM, RELEASE_IF, RELEASE_ALL } usb_rpc_call_type_t; + struct usb_rpc_call_args { - genode_usb_bus_num_t bus; - genode_usb_dev_num_t dev; unsigned iface_num; usb_rpc_call_type_t call; int ret; }; -static struct usb_rpc_call_args usb_rpc_args; -static struct task_struct * usb_rpc_task; - - -static int claim_iface(struct usb_interface * iface) +struct usb_per_dev_data { - return usb_driver_claim_interface(&usb_drv, iface, NULL); -} + struct inode inode; + struct file file; + struct usb_rpc_call_args rpc; + struct usb_device *dev; + struct task_struct *task; + struct list_head urblist; +}; -static void release_iface(struct usb_interface * iface) +struct usb_urb_in_flight { - usb_driver_release_interface(&usb_drv, iface); -} + struct list_head le; + struct usbdevfs_urb urb; +}; -static int usb_rpc_call(void * data) +static int poll_usb_device(void * args); +static struct file * open_usb_dev(struct usb_device * udev) { - struct usb_device * udev; - struct usb_interface * iface; - unsigned i, num; - int ret; + struct usb_per_dev_data * data = dev_get_drvdata(&udev->dev); - for (;;) { - lx_emul_task_schedule(true); - - udev = find_usb_device(usb_rpc_args.bus, usb_rpc_args.dev); - if (!udev) { - usb_rpc_args.ret = -1; - continue; - } - - if (usb_rpc_args.call == RELEASE_ALL) { - i = 0; - num = (udev->actconfig) ? udev->actconfig->desc.bNumInterfaces : 0; - } else { - i = usb_rpc_args.iface_num; - num = i + 1; - } - - ret = 0; - for (; i < num; i++) { - iface = usb_ifnum_to_if(udev, i); - if (!iface) { - ret = -2; - continue; - } - - if (usb_rpc_args.call == CLAIM) - ret = claim_iface(iface); - else - release_iface(iface); - } - - 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; - if (udev->actconfig) - ret = usb_reset_configuration(udev); - } - - usb_rpc_args.ret = ret; + if (!data) { + int pid; + data = kmalloc(sizeof(struct usb_per_dev_data), GFP_KERNEL); + data->inode.i_rdev = udev->dev.devt; + data->file.f_inode = &data->inode; + data->file.f_mode = FMODE_WRITE; + usbdev_file_operations->open(&data->inode, &data->file); + data->dev = udev; + pid = kernel_thread(poll_usb_device, data, CLONE_FS | CLONE_FILES); + data->task = find_task_by_pid_ns(pid, NULL); + INIT_LIST_HEAD(&data->urblist); + dev_set_drvdata(&udev->dev, data); } + + return &data->file; +} + + +static void release_device(struct usb_per_dev_data * data, int reset) +{ + genode_usb_session_handle_t session; + genode_usb_request_handle_t request; + struct usb_urb_in_flight *iter, *next; + int ret = -ENODEV; + + list_for_each_entry_safe(iter, next, &data->urblist, le) { + usbdev_file_operations->unlocked_ioctl(&data->file, + USBDEVFS_DISCARDURB, + (unsigned long)&iter->urb); + handle_from_usercontext(iter->urb.usercontext, &session, &request); + genode_usb_ack_request(session, request, handle_return_code, &ret); + list_del(&iter->le); + kfree(iter); + } + usbdev_file_operations->release(&data->inode, &data->file); + if (reset) + usbdev_file_operations->unlocked_ioctl(&data->file, USBDEVFS_RESET, 0); +} + + +static int claim_iface(struct usb_device *udev, unsigned int ifnum) +{ + struct file * file = open_usb_dev(udev); + return usbdev_file_operations->unlocked_ioctl(file, USBDEVFS_CLAIMINTERFACE, + (unsigned long)&ifnum); +} + + +static int release_iface(struct usb_device *udev, unsigned int ifnum) +{ + struct usb_per_dev_data * data = dev_get_drvdata(&udev->dev); + + if (!data) + return -ENODEV; + + if (data) + usbdev_file_operations->unlocked_ioctl(&data->file, + USBDEVFS_RELEASEINTERFACE, + (unsigned long)&ifnum); return 0; } -static int usb_rpc_finished(void) +static int usb_rpc_finished(void *d) { - return (usb_rpc_args.ret <= 0); + struct usb_per_dev_data * data = (struct usb_per_dev_data*)d; + return (data->rpc.ret <= 0); } @@ -282,14 +336,25 @@ static int claim(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned iface_num) { - usb_rpc_args.ret = 1; - usb_rpc_args.call = CLAIM; - usb_rpc_args.bus = bus; - usb_rpc_args.dev = dev; - usb_rpc_args.iface_num = iface_num; - lx_emul_task_unblock(usb_rpc_task); - lx_emul_execute_kernel_until(&usb_rpc_finished); - return usb_rpc_args.ret; + struct usb_device * udev = find_usb_device(bus, dev); + struct usb_per_dev_data * data = udev ? dev_get_drvdata(&udev->dev) : NULL; + + /* + * As long as 'claim' is a rpc-call, and the usb device wasn't opened yet, + * we cannot open the device here, this has to be done from a Linux task. + * So just ignore it here, it will be claimed implicitely by the devio + * usb layer later. + */ + if (!data) + return 0; + + data = dev_get_drvdata(&udev->dev); + data->rpc.ret = 1; + data->rpc.call = CLAIM; + data->rpc.iface_num = iface_num; + lx_emul_task_unblock(data->task); + lx_emul_execute_kernel_until(&usb_rpc_finished, data); + return data->rpc.ret; } @@ -297,26 +362,34 @@ static int release(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned iface_num) { - usb_rpc_args.ret = 1; - usb_rpc_args.call = RELEASE_IF; - usb_rpc_args.bus = bus; - usb_rpc_args.dev = dev; - usb_rpc_args.iface_num = iface_num; - lx_emul_task_unblock(usb_rpc_task); - lx_emul_execute_kernel_until(&usb_rpc_finished); - return usb_rpc_args.ret; + struct usb_device * udev = find_usb_device(bus, dev); + struct usb_per_dev_data * data = udev ? dev_get_drvdata(&udev->dev) : NULL; + + if (!data) + return -1; + + data->rpc.ret = 1; + data->rpc.call = RELEASE_IF; + data->rpc.iface_num = iface_num; + lx_emul_task_unblock(data->task); + lx_emul_execute_kernel_until(&usb_rpc_finished, data); + return data->rpc.ret; } static void release_all(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev) { - usb_rpc_args.ret = 1; - usb_rpc_args.call = RELEASE_ALL; - usb_rpc_args.bus = bus; - usb_rpc_args.dev = dev; - lx_emul_task_unblock(usb_rpc_task); - lx_emul_execute_kernel_until(&usb_rpc_finished); + struct usb_device * udev = find_usb_device(bus, dev); + struct usb_per_dev_data * data = udev ? dev_get_drvdata(&udev->dev) : NULL; + + if (!data) + return; + + data->rpc.ret = 1; + data->rpc.call = RELEASE_ALL; + lx_emul_task_unblock(data->task); + lx_emul_execute_kernel_until(&usb_rpc_finished, data); } @@ -335,71 +408,36 @@ struct genode_usb_rpc_callbacks lx_emul_usb_rpc_callbacks = { static genode_usb_request_ret_t -handle_return_code(struct genode_usb_request_urb req, struct genode_usb_buffer payload, void * data) +handle_transfer_response(struct genode_usb_request_urb req, + struct genode_usb_buffer payload, + void * data) { - return (genode_usb_request_ret_t)data; -}; + struct usbdevfs_urb * urb = ((struct usbdevfs_urb *)data); + struct genode_usb_request_control * ctrl = + genode_usb_get_request_control(&req); + struct genode_usb_request_transfer * transfer = + genode_usb_get_request_transfer(&req); + if (urb->status < 0) + return handle_return_code(req, payload, &urb->status); -extern int usb_get_langid(struct usb_device *dev, unsigned char *tbuf); -extern int usb_string_sub(struct usb_device *dev, unsigned int langid, int index, unsigned char *tbuf); + if (ctrl) ctrl->actual_size = urb->actual_length; + if (transfer) transfer->actual_size = urb->actual_length; -/** - * usb_string_utf16 - returns the string descriptor - * @dev: the device whose string descriptor is being retrieved - * @index: the number of the descriptor - * @buf: where to put the string - * @size: how big is "buf"? - * - * Context: task context, might sleep. - * - * This returns the UTF-16LE encoded strings returned by devices, from - * usb_get_string_descriptor(). Note that this function - * chooses strings in the first language supported by the device. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Return: length of the string (>= 0) or usb_control_msg status (< 0). - */ -static int usb_string_utf16(struct usb_device *dev, int index, char *buf, size_t size) -{ - unsigned char *tbuf; - int err; - size_t len; - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - if (size <= 2 || buf == NULL) - return -EINVAL; - buf[0] = 0; - if (index <= 0 || index >= 256) - return -EINVAL; - tbuf = kmalloc(256, GFP_NOIO); - if (!tbuf) - return -ENOMEM; + if (req.type == ISOC) { + int i; + struct genode_usb_isoc_transfer *isoc = + (struct genode_usb_isoc_transfer *)payload.addr; + if (!isoc) + return PACKET_INVALID_ERROR; - err = usb_get_langid(dev, tbuf); - if (err < 0) - goto errout; + for (i = 0; i < urb->number_of_packets; i++) { + isoc->actual_packet_size[i] = + urb->iso_frame_desc[i].actual_length; + } + } - err = usb_string_sub(dev, dev->string_langid, index, tbuf); - if (err < 0) - goto errout; - - len = min(size-2, (size_t)err); - memcpy(buf, tbuf+2, len); - - buf[len] = 0; - buf[len+1] = 0; - err = len + 2; - - if (tbuf[1] != USB_DT_STRING) - dev_dbg(&dev->dev, - "wrong descriptor type %02x for string %d (\"%s\")\n", - tbuf[1], index, buf); - - errout: - kfree(tbuf); - return err; + return NO_ERROR; } @@ -411,23 +449,21 @@ handle_string_request(struct genode_usb_request_string * req, void * data) { struct usb_device * udev = (struct usb_device *) data; - genode_usb_request_ret_t ret = UNKNOWN_ERROR; - int length = 0; + struct file * file = open_usb_dev(udev); - if (!payload.size || !payload.addr) - return; - - length = usb_string_utf16(udev, req->index, payload.addr, payload.size); - if (length < 0) { - printk("Could not read string descriptor index: %u\n", req->index); - req->length = 0; - } else { - /* returned length is in bytes (char) */ - req->length = length / 2; - ret = NO_ERROR; - } - - genode_usb_ack_request(session, request, handle_return_code, (void*)ret); + struct usbdevfs_ctrltransfer ctrl = { + .bRequestType = USB_DIR_IN, + .bRequest = USB_REQ_GET_DESCRIPTOR, + .wValue = (USB_DT_STRING << 8) + req->index, + .wIndex = udev->string_langid, + .wLength = payload.size, + .timeout = USB_CTRL_GET_TIMEOUT, + .data = payload.addr, + }; + int ret = + usbdev_file_operations->unlocked_ioctl(file, USBDEVFS_CONTROL, + (unsigned long)&ctrl); + genode_usb_ack_request(session, request, handle_return_code, &ret); } @@ -439,15 +475,17 @@ handle_altsetting_request(unsigned iface, void * data) { struct usb_device * udev = (struct usb_device *) data; - genode_usb_request_ret_t ret = NO_ERROR; + struct file * file = open_usb_dev(udev); - if (usb_set_interface(udev, iface, alt_setting)) { - ret = UNKNOWN_ERROR; - printk("Alt setting request (iface=%u alt_setting=%u) failed\n", - iface, alt_setting); - } + struct usbdevfs_setinterface setintf = { + .interface = iface, + .altsetting = alt_setting + }; - genode_usb_ack_request(session, request, handle_return_code, (void*)ret); + int ret = + usbdev_file_operations->unlocked_ioctl(file, USBDEVFS_SETINTERFACE, + (unsigned long)&setintf); + genode_usb_ack_request(session, request, handle_return_code, &ret); } @@ -458,18 +496,14 @@ handle_config_request(unsigned cfg_idx, void * data) { struct usb_device * udev = (struct usb_device *) data; - genode_usb_request_ret_t ret = NO_ERROR; + struct file * file = open_usb_dev(udev); - /* - * Skip SET_CONFIGURATION requests if the device already has the - * selected config as active config. This workaround prevents issues - * with Linux guests in vbox and SDC-reader passthrough. - */ - if (!(udev && udev->actconfig && - udev->actconfig->desc.bConfigurationValue == cfg_idx)) - ret = (usb_set_configuration(udev, cfg_idx)) ? UNKNOWN_ERROR : NO_ERROR; - - genode_usb_ack_request(session, request, handle_return_code, (void*)ret); + int u = cfg_idx; + int ret = + usbdev_file_operations->unlocked_ioctl(file, + USBDEVFS_SETCONFIGURATION, + (unsigned long)&u); + genode_usb_ack_request(session, request, handle_return_code, &ret); } @@ -480,259 +514,13 @@ handle_flush_request(unsigned char ep, void * data) { struct usb_device * udev = (struct usb_device *) data; - struct usb_host_endpoint * endpoint = - ep & USB_DIR_IN ? udev->ep_in[ep & 0xf] - : udev->ep_out[ep & 0xf]; - genode_usb_request_ret_t ret = NO_ERROR; - - if (!endpoint) - ret = INTERFACE_OR_ENDPOINT_ERROR; - else - usb_hcd_flush_endpoint(udev, endpoint); - - genode_usb_ack_request(session, request, handle_return_code, (void*)ret); -} - -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 -handle_transfer_response(struct genode_usb_request_urb req, - struct genode_usb_buffer payload, - void * 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; - - /* handle failure first */ - if (urb->status) { - if (ctrl) - ctrl->actual_size = 0; - - if (context->timer_state == TIMER_TRIGGERED) - return TIMEOUT_ERROR; - - switch (urb->status) { - 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; - }; - return UNKNOWN_ERROR; - } - - if (ctrl) - ctrl->actual_size = urb->actual_length; - if (transfer) { - transfer->actual_size = urb->actual_length; - - if (usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe)) { - struct genode_usb_isoc_transfer *isoc = - (struct genode_usb_isoc_transfer *)payload.addr; - for (i = 0; i < isoc->number_of_packets; i++) - isoc->actual_packet_size[i] = - urb->iso_frame_desc[i].actual_length; - } - } - return NO_ERROR; -} - - -static void usb_free_complete_urb(struct urb * urb) -{ - if (!urb) - return; - if (urb->setup_packet) - kfree(urb->setup_packet); - if (urb->context) { - struct usb_urb_context * context = - (struct usb_urb_context *) urb->context; - if (context->timer_state != TIMER_OFF) - del_timer_sync(&context->timeo); - kfree(context); - } - usb_free_urb(urb); -} - - -static void async_complete(struct urb *urb) -{ - struct usb_iface_urbs * urbs = dev_get_drvdata(&urb->dev->dev); - - struct usb_urb_context * context = - (struct usb_urb_context*) urb->context; - - genode_usb_ack_request(context->session, context->request, - handle_transfer_response, (void*)context); - - if (!urbs || !urbs->in_delete) { - usb_free_complete_urb(urb); - 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_unlink_urb(context->urb); -} - - -static int fill_ctrl_urb(struct usb_device * udev, - struct genode_usb_request_control * req, - void * handle, - struct genode_usb_buffer buf, - 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); - - if (buf.size && !buf.addr) - return PACKET_INVALID_ERROR; - - *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(buf.size); - - usb_fill_control_urb(*urb, udev, pipe, (unsigned char*)ucr, buf.addr, buf.size, - async_complete, handle); - return 0; -} - - -static int fill_bulk_urb(struct usb_device * udev, - struct genode_usb_request_transfer * req, - void * handle, - struct genode_usb_buffer buf, - int read, - struct urb ** urb) -{ - int pipe = (read) - ? usb_rcvbulkpipe(udev, req->ep) : usb_sndbulkpipe(udev, req->ep); - - if (!buf.addr) - return PACKET_INVALID_ERROR; - - *urb = usb_alloc_urb(0, GFP_KERNEL); - if (!*urb) - return -ENOMEM; - - usb_fill_bulk_urb(*urb, udev, pipe, buf.addr, buf.size, async_complete, handle); - return 0; -} - - -static int fill_irq_urb(struct usb_device * udev, - struct genode_usb_request_transfer * req, - void * handle, - struct genode_usb_buffer buf, - int read, - struct urb ** urb) -{ - int polling_interval; - int pipe = (read) - ? usb_rcvintpipe(udev, req->ep) : usb_sndintpipe(udev, req->ep); - - if (buf.size && !buf.addr) - return PACKET_INVALID_ERROR; - - *urb = usb_alloc_urb(0, GFP_KERNEL); - if (!*urb) - return -ENOMEM; - - if (req->polling_interval == -1) { - - struct usb_host_endpoint *ep = (req->ep & USB_DIR_IN) ? - udev->ep_in[req->ep & 0xf] : udev->ep_out[req->ep & 0xf]; - - if (!ep) - return -ENOENT; - - polling_interval = ep->desc.bInterval; - } else - polling_interval = req->polling_interval; - - usb_fill_int_urb(*urb, udev, pipe, buf.addr, buf.size, - async_complete, handle, polling_interval); - return 0; -} - - -static int fill_isoc_urb(struct usb_device * udev, - struct genode_usb_request_transfer * req, - void * handle, - struct genode_usb_buffer buf, - int read, - struct urb ** urb) -{ - int i; - unsigned offset = 0; - int pipe = (read) - ? usb_rcvisocpipe(udev, req->ep) : usb_sndisocpipe(udev, req->ep); - struct usb_host_endpoint * ep = - req->ep & USB_DIR_IN ? udev->ep_in[req->ep & 0xf] - : udev->ep_out[req->ep & 0xf]; - - struct genode_usb_isoc_transfer *isoc = (struct genode_usb_isoc_transfer *)buf.addr; - - if (!buf.addr || isoc->number_of_packets > MAX_PACKETS) - return PACKET_INVALID_ERROR; - if (!ep) - return -ENOENT; - - *urb = usb_alloc_urb(isoc->number_of_packets, GFP_KERNEL); - if (!*urb) - return -ENOMEM; - - (*urb)->dev = udev; - (*urb)->pipe = pipe; - (*urb)->start_frame = -1; - (*urb)->stream_id = 0; - (*urb)->transfer_buffer = isoc->data; - (*urb)->transfer_buffer_length = buf.size - sizeof(*isoc); - (*urb)->number_of_packets = isoc->number_of_packets; - (*urb)->interval = 1 << min(15, ep->desc.bInterval - 1); - (*urb)->context = handle; - (*urb)->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT); - (*urb)->complete = async_complete; - - for (i = 0; i < isoc->number_of_packets; i++) { - (*urb)->iso_frame_desc[i].offset = offset; - (*urb)->iso_frame_desc[i].length = isoc->packet_size[i]; - offset += isoc->packet_size[i]; - } - - return 0; + struct file * file = open_usb_dev(udev); + unsigned int e = ep; + int ret = + usbdev_file_operations->unlocked_ioctl(file, + USBDEVFS_RESETEP, + (unsigned long)&e); + genode_usb_ack_request(session, request, handle_return_code, &ret); } @@ -740,83 +528,87 @@ static void handle_urb_request(struct genode_usb_request_urb req, genode_usb_session_handle_t session_handle, genode_usb_request_handle_t request_handle, - struct genode_usb_buffer payload, void * data) + struct genode_usb_buffer payload, void * args) { - 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); - genode_usb_request_ret_t ret = UNKNOWN_ERROR; - - int err = 0; - int read = transfer ? (transfer->ep & 0x80) : 0; - struct urb * urb; - - struct usb_urb_context * context = - kmalloc(sizeof(struct usb_urb_context), GFP_NOIO); - if (!context) { - ret = MEMORY_ERROR; - goto error; - } - - context->session = session_handle; - context->request = request_handle; + struct usb_device * udev = (struct usb_device *) args; + struct usb_per_dev_data * data = dev_get_drvdata(&udev->dev); + struct file * file = &data->file; switch (req.type) { case CTRL: - err = fill_ctrl_urb(udev, ctrl, context, payload, - (ctrl->request_type & 0x80), &urb); - break; - case BULK: - err = fill_bulk_urb(udev, transfer, context, payload, read, &urb); - break; + { + struct usbdevfs_urb urb; + struct genode_usb_request_control * urc = + genode_usb_get_request_control(&req); + struct usbdevfs_ctrltransfer ctrl = { + .bRequestType = urc->request_type, + .bRequest = urc->request, + .wValue = urc->value, + .wIndex = urc->index, + .wLength = payload.size, + .timeout = urc->timeout, + .data = payload.addr, + }; + urb.actual_length = + usbdev_file_operations->unlocked_ioctl(file, USBDEVFS_CONTROL, + (unsigned long)&ctrl); + urb.status = urb.actual_length < 0 ? urb.actual_length : 0; + genode_usb_ack_request(session_handle, request_handle, + handle_transfer_response, &urb); + break; + } case IRQ: - err = fill_irq_urb(udev, transfer, context, payload, read, &urb); - break; + case BULK: + { + struct genode_usb_request_transfer * urt = + genode_usb_get_request_transfer(&req); + struct usb_urb_in_flight * u = + kmalloc(sizeof(struct usb_urb_in_flight), GFP_KERNEL); + u->urb.type = req.type == IRQ ? USBDEVFS_URB_TYPE_INTERRUPT + : USBDEVFS_URB_TYPE_BULK, + u->urb.endpoint = urt->ep; + u->urb.buffer_length = payload.size; + u->urb.buffer = payload.addr; + u->urb.usercontext = usercontext_from_handle(session_handle, + request_handle); + u->urb.signr = 1; + INIT_LIST_HEAD(&u->le); + list_add_tail(&u->le, &data->urblist); + usbdev_file_operations->unlocked_ioctl(file, USBDEVFS_SUBMITURB, + (unsigned long)&u->urb); + break; + } case ISOC: - err = fill_isoc_urb(udev, transfer, context, payload, read, &urb); - break; - default: - printk("Unknown USB transfer request!\n"); - err = PACKET_INVALID_ERROR; + { + int i; + struct genode_usb_request_transfer * urt = + genode_usb_get_request_transfer(&req); + struct genode_usb_isoc_transfer *isoc = + (struct genode_usb_isoc_transfer *)payload.addr; + unsigned num_packets = isoc ? isoc->number_of_packets : 0; + struct usb_urb_in_flight * u = + kmalloc(sizeof(struct usb_urb_in_flight) + + sizeof(struct usbdevfs_iso_packet_desc)*num_packets, + GFP_KERNEL); + u->urb.type = USBDEVFS_URB_TYPE_ISO, + u->urb.endpoint = urt->ep; + u->urb.buffer_length = payload.size - + sizeof(struct genode_usb_isoc_transfer); + u->urb.buffer = isoc ? isoc->data : NULL;; + u->urb.usercontext = usercontext_from_handle(session_handle, + request_handle); + u->urb.signr = 1; + u->urb.number_of_packets = num_packets; + INIT_LIST_HEAD(&u->le); + list_add_tail(&u->le, &data->urblist); + for (i = 0; i < num_packets; i++) + u->urb.iso_frame_desc[i].length = isoc ? isoc->packet_size[i] : 0; + usbdev_file_operations->unlocked_ioctl(file, USBDEVFS_SUBMITURB, + (unsigned long)&u->urb); + break; + } + case NONE: ; }; - - if (err) - goto free_context; - - context->urb = urb; - usb_anchor_urb(urb, &urbs->submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) - goto free_urb; - - if (ctrl && ctrl->timeout) { - context->timer_state = TIMER_ACTIVE; - timer_setup(&context->timeo, urb_timeout, 0); - mod_timer(&context->timeo, jiffies + msecs_to_jiffies(ctrl->timeout)); - } - - return; - - free_urb: - usb_unanchor_urb(urb); - usb_free_complete_urb(urb); - free_context: - kfree(context); - switch (err) { - case -ENOENT: ret = INTERFACE_OR_ENDPOINT_ERROR; break; - case -ENODEV: ret = NO_DEVICE_ERROR; break; - case -ESHUTDOWN: ret = NO_DEVICE_ERROR; break; - case -ENOSPC: ret = STALL_ERROR; break; - case -ENOMEM: ret = MEMORY_ERROR; break; - - case PACKET_INVALID_ERROR: ret = PACKET_INVALID_ERROR; break; - } - error: - genode_usb_ack_request(context->session, context->request, - handle_return_code, (void*)ret); } @@ -829,33 +621,113 @@ static struct genode_usb_request_callbacks request_callbacks = { }; -static int poll_usb_device(struct usb_device *udev, void * data) +static inline void handle_rpc(struct usb_per_dev_data * data) { - genode_usb_session_handle_t session = - genode_usb_session_by_bus_dev(udev->bus->busnum, udev->devnum); - int * work_done = (int *) data; + switch(data->rpc.call) { + case CLAIM: + if (data->dev) claim_iface(data->dev, data->rpc.iface_num); + break; + case RELEASE_IF: + if (data->dev) release_iface(data->dev, data->rpc.iface_num); + break; + case RELEASE_ALL: + data->dev = NULL; + break; + case NOTHING: ; + }; + + data->rpc.call = NOTHING; + data->rpc.ret = 0; +} + + +static inline int check_for_urb(struct usb_device * udev) +{ + genode_usb_session_handle_t session; + + if (!udev) + return 0; + + session = genode_usb_session_by_bus_dev(udev->bus->busnum, + udev->devnum); if (!session) return 0; + return genode_usb_request_by_session(session, &request_callbacks, + (void*)udev); +} + + +static inline int check_for_urb_done(struct file * file) +{ + genode_usb_session_handle_t session_handle; + genode_usb_request_handle_t request_handle; + struct usb_urb_in_flight * u; + struct usbdevfs_urb * urb = NULL; + int ret = usbdev_file_operations->unlocked_ioctl(file, + USBDEVFS_REAPURBNDELAY, + (unsigned long)&urb); + if (ret < 0) + return 0; + + handle_from_usercontext(urb->usercontext, &session_handle, &request_handle); + genode_usb_ack_request(session_handle, request_handle, + handle_transfer_response, urb); + u = container_of(urb, struct usb_urb_in_flight, urb); + list_del(&u->le); + kfree(u); + return 1; +} + + +static int poll_usb_device(void * args) +{ + struct usb_per_dev_data * data = (struct usb_per_dev_data*)args; + genode_usb_bus_num_t bus = data->dev->bus->busnum; + genode_usb_dev_num_t dev = data->dev->devnum; + for (;;) { - if (!genode_usb_request_by_session(session, &request_callbacks, - (void*)udev)) - break; - *work_done = true; + handle_rpc(data); + while (check_for_urb(data->dev)) ; + while (check_for_urb_done(&data->file)) ; + if (!data->dev) { + struct usb_device * udev = find_usb_device(bus, dev); + release_device(data, udev ? 1 : 0); + if (!udev) genode_usb_discontinue_device(bus, dev); + else dev_set_drvdata(&udev->dev, NULL); + kfree(data); + do_exit(0); + } + lx_emul_task_schedule(true); } return 0; } -static int usb_poll_sessions(void * data) +static int wake_up_udev_task(struct usb_device *udev, void * args) +{ + struct usb_per_dev_data * data = dev_get_drvdata(&udev->dev); + + if (!genode_usb_session_by_bus_dev(udev->bus->busnum, udev->devnum)) + return 0; + + if (!data) { + open_usb_dev(udev); + data = dev_get_drvdata(&udev->dev); + } + + lx_emul_task_unblock(data->task); + return 0; +} + + +static int usb_poll_empty_sessions(void * data) { for (;;) { - int work_done = false; - usb_for_each_dev(&work_done, poll_usb_device); - if (work_done) - continue; + usb_for_each_dev(NULL, wake_up_udev_task); + lx_emul_task_schedule(false); genode_usb_handle_empty_sessions(); lx_emul_task_schedule(true); } @@ -869,17 +741,15 @@ static struct task_struct * lx_user_task = NULL; void lx_user_handle_io(void) { - if (lx_user_task) - lx_emul_task_unblock(lx_user_task); + if (lx_user_task) lx_emul_task_unblock(lx_user_task); } void lx_user_init(void) { - int pid = kernel_thread(usb_poll_sessions, NULL, CLONE_FS | CLONE_FILES); - lx_user_task = find_task_by_pid_ns(pid, NULL);; - pid = kernel_thread(usb_rpc_call, NULL, CLONE_FS | CLONE_FILES); - usb_rpc_task = find_task_by_pid_ns(pid, NULL); + int pid = kernel_thread(usb_poll_empty_sessions, NULL, + CLONE_FS | CLONE_FILES); + lx_user_task = find_task_by_pid_ns(pid, NULL); } @@ -903,17 +773,8 @@ static int raw_notify(struct notifier_block *nb, unsigned long action, void *dat * solution only to assist the implementation of access-control * policies. */ - unsigned long class; - unsigned i, num; - 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); - - - class = 0; - num = (udev->actconfig) ? + unsigned long class = 0; + unsigned i, num = (udev->actconfig) ? udev->actconfig->desc.bNumInterfaces : 0; for (i = 0; i < num; i++) { struct usb_interface * iface = @@ -935,25 +796,16 @@ static int raw_notify(struct notifier_block *nb, unsigned long action, void *dat 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); - + struct usb_per_dev_data * data = dev_get_drvdata(&udev->dev); + if (data) { + data->dev = NULL; + lx_emul_task_unblock(data->task); + } break; } + } - case USB_BUS_ADD: - break; - - case USB_BUS_REMOVE: - break; - } - - return NOTIFY_OK; + return NOTIFY_OK; } @@ -979,3 +831,19 @@ static int usbnet_init(void) * an additional one */ module_init(usbnet_init); + + +void lx_emul_usb_register_devio(const struct file_operations * fops) +{ + usbdev_file_operations = fops; +} + + +#include + +int kill_pid_usb_asyncio(int sig, int errno, sigval_t addr, struct pid * pid, + const struct cred * cred) +{ + lx_user_handle_io(); + return 0; +} diff --git a/repos/pc/src/drivers/framebuffer/intel/pc/dummies.c b/repos/pc/src/drivers/framebuffer/intel/pc/dummies.c index 332cbf55b9..f79da0fe68 100644 --- a/repos/pc/src/drivers/framebuffer/intel/pc/dummies.c +++ b/repos/pc/src/drivers/framebuffer/intel/pc/dummies.c @@ -758,3 +758,11 @@ void software_node_notify_remove(struct device * dev) { lx_emul_trace(__func__); } + + +#include + +void cdev_init(struct cdev * cdev,const struct file_operations * fops) +{ + lx_emul_trace(__func__); +} diff --git a/repos/pc/src/drivers/usb_host/pc/dummies.c b/repos/pc/src/drivers/usb_host/pc/dummies.c index 4b2ee7b816..c062c31b36 100644 --- a/repos/pc/src/drivers/usb_host/pc/dummies.c +++ b/repos/pc/src/drivers/usb_host/pc/dummies.c @@ -214,3 +214,30 @@ void net_ns_init(void) { lx_emul_trace(__func__); } + + +#include + +struct timespec64 current_time(struct inode * inode) +{ + struct timespec64 ret = { 0 }; + lx_emul_trace(__func__); + return ret; +} + + +#include + +void put_pid(struct pid * pid) +{ + lx_emul_trace(__func__); +} + + +#include + +void __put_cred(struct cred * cred) +{ + lx_emul_trace(__func__); +} + diff --git a/repos/pc/src/drivers/usb_host/pc/generated_dummies.c b/repos/pc/src/drivers/usb_host/pc/generated_dummies.c index 3d7aabd801..fc4d27b411 100644 --- a/repos/pc/src/drivers/usb_host/pc/generated_dummies.c +++ b/repos/pc/src/drivers/usb_host/pc/generated_dummies.c @@ -36,14 +36,6 @@ void __printk_safe_exit(void) } -#include - -void __put_cred(struct cred * cred) -{ - lx_emul_trace_and_stop(__func__); -} - - #include void __put_task_struct(struct task_struct * tsk) @@ -68,22 +60,6 @@ void __unregister_chrdev(unsigned int major,unsigned int baseminor,unsigned int } -#include - -unsigned long _copy_from_user(void * to,const void __user * from,unsigned long n) -{ - lx_emul_trace_and_stop(__func__); -} - - -#include - -unsigned long _copy_to_user(void __user * to,const void * from,unsigned long n) -{ - lx_emul_trace_and_stop(__func__); -} - - #include int _printk_deferred(const char * fmt,...) @@ -131,14 +107,6 @@ const struct cpumask * cpu_clustergroup_mask(int cpu) } -#include - -struct timespec64 current_time(struct inode * inode) -{ - lx_emul_trace_and_stop(__func__); -} - - #include int device_create_managed_software_node(struct device * dev,const struct property_entry * properties,const struct software_node * parent) @@ -303,14 +271,6 @@ void kill_anon_super(struct super_block * sb) } -#include - -int kill_pid_usb_asyncio(int sig,int errno,sigval_t addr,struct pid * pid,const struct cred * cred) -{ - lx_emul_trace_and_stop(__func__); -} - - #include void * kmem_cache_alloc_lru(struct kmem_cache * cachep,struct list_lru * lru,gfp_t flags) @@ -428,14 +388,6 @@ int proc_douintvec(struct ctl_table * table,int write,void * buffer,size_t * len } -#include - -void put_pid(struct pid * pid) -{ - lx_emul_trace_and_stop(__func__); -} - - #include void refcount_warn_saturate(refcount_t * r,enum refcount_saturation_type t) diff --git a/repos/pc/src/drivers/usb_host/pc/lx_emul.c b/repos/pc/src/drivers/usb_host/pc/lx_emul.c index 3471080d94..a6f49aae89 100644 --- a/repos/pc/src/drivers/usb_host/pc/lx_emul.c +++ b/repos/pc/src/drivers/usb_host/pc/lx_emul.c @@ -108,3 +108,30 @@ int pci_irq_vector(struct pci_dev *dev, unsigned int nr) void pci_free_irq_vectors(struct pci_dev *dev) { } + + +#include +#include + +void cdev_init(struct cdev * cdev, const struct file_operations * fops) +{ + lx_emul_usb_register_devio(fops); +} + + +#include + +unsigned long _copy_from_user(void * to,const void __user * from,unsigned long n) +{ + memcpy(to, from, n); + return 0; +} + + +#include + +unsigned long _copy_to_user(void __user * to,const void * from,unsigned long n) +{ + memcpy(to, from, n); + return 0; +} diff --git a/repos/pc/src/lib/pc/lx_emul/common_dummies.c b/repos/pc/src/lib/pc/lx_emul/common_dummies.c index 104a60ec4c..f3c01076a4 100644 --- a/repos/pc/src/lib/pc/lx_emul/common_dummies.c +++ b/repos/pc/src/lib/pc/lx_emul/common_dummies.c @@ -194,14 +194,6 @@ void register_irq_proc(unsigned int irq,struct irq_desc * desc) } -#include - -void cdev_init(struct cdev * cdev,const struct file_operations * fops) -{ - lx_emul_trace(__func__); -} - - int cdev_add(struct cdev * p,dev_t dev,unsigned count) { lx_emul_trace(__func__); diff --git a/repos/pc/src/lib/wifi/dummies.c b/repos/pc/src/lib/wifi/dummies.c index 9eda8ff892..43d90ca827 100644 --- a/repos/pc/src/lib/wifi/dummies.c +++ b/repos/pc/src/lib/wifi/dummies.c @@ -530,3 +530,11 @@ int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, lx_emul_trace_and_stop(__func__); return 0; } + + +#include + +void cdev_init(struct cdev * cdev,const struct file_operations * fops) +{ + lx_emul_trace(__func__); +}