12b2325ffSGerd Hoffmann /* 22b2325ffSGerd Hoffmann * Linux host USB redirector 32b2325ffSGerd Hoffmann * 42b2325ffSGerd Hoffmann * Copyright (c) 2005 Fabrice Bellard 52b2325ffSGerd Hoffmann * 62b2325ffSGerd Hoffmann * Copyright (c) 2008 Max Krasnyansky 72b2325ffSGerd Hoffmann * Support for host device auto connect & disconnect 82b2325ffSGerd Hoffmann * Major rewrite to support fully async operation 92b2325ffSGerd Hoffmann * 102b2325ffSGerd Hoffmann * Copyright 2008 TJ <linux@tjworld.net> 112b2325ffSGerd Hoffmann * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition 122b2325ffSGerd Hoffmann * to the legacy /proc/bus/usb USB device discovery and handling 132b2325ffSGerd Hoffmann * 142b2325ffSGerd Hoffmann * (c) 2012 Gerd Hoffmann <kraxel@redhat.com> 152b2325ffSGerd Hoffmann * Completely rewritten to use libusb instead of usbfs ioctls. 162b2325ffSGerd Hoffmann * 172b2325ffSGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy 182b2325ffSGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal 192b2325ffSGerd Hoffmann * in the Software without restriction, including without limitation the rights 202b2325ffSGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 212b2325ffSGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is 222b2325ffSGerd Hoffmann * furnished to do so, subject to the following conditions: 232b2325ffSGerd Hoffmann * 242b2325ffSGerd Hoffmann * The above copyright notice and this permission notice shall be included in 252b2325ffSGerd Hoffmann * all copies or substantial portions of the Software. 262b2325ffSGerd Hoffmann * 272b2325ffSGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 282b2325ffSGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 292b2325ffSGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 302b2325ffSGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 312b2325ffSGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 322b2325ffSGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 332b2325ffSGerd Hoffmann * THE SOFTWARE. 342b2325ffSGerd Hoffmann */ 352b2325ffSGerd Hoffmann 362b2325ffSGerd Hoffmann #include <poll.h> 372b2325ffSGerd Hoffmann #include <libusb.h> 382b2325ffSGerd Hoffmann 392b2325ffSGerd Hoffmann #include "qemu-common.h" 402b2325ffSGerd Hoffmann #include "monitor/monitor.h" 412b2325ffSGerd Hoffmann #include "sysemu/sysemu.h" 422b2325ffSGerd Hoffmann #include "trace.h" 432b2325ffSGerd Hoffmann 442b2325ffSGerd Hoffmann #include "hw/usb.h" 452b2325ffSGerd Hoffmann 462b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 472b2325ffSGerd Hoffmann 482b2325ffSGerd Hoffmann #define TYPE_USB_HOST_DEVICE "usb-host" 492b2325ffSGerd Hoffmann #define USB_HOST_DEVICE(obj) \ 502b2325ffSGerd Hoffmann OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE) 512b2325ffSGerd Hoffmann 522b2325ffSGerd Hoffmann typedef struct USBHostDevice USBHostDevice; 532b2325ffSGerd Hoffmann typedef struct USBHostRequest USBHostRequest; 542b2325ffSGerd Hoffmann typedef struct USBHostIsoXfer USBHostIsoXfer; 552b2325ffSGerd Hoffmann typedef struct USBHostIsoRing USBHostIsoRing; 562b2325ffSGerd Hoffmann 572b2325ffSGerd Hoffmann struct USBAutoFilter { 582b2325ffSGerd Hoffmann uint32_t bus_num; 592b2325ffSGerd Hoffmann uint32_t addr; 602b2325ffSGerd Hoffmann char *port; 612b2325ffSGerd Hoffmann uint32_t vendor_id; 622b2325ffSGerd Hoffmann uint32_t product_id; 632b2325ffSGerd Hoffmann }; 642b2325ffSGerd Hoffmann 652b2325ffSGerd Hoffmann enum USBHostDeviceOptions { 662b2325ffSGerd Hoffmann USB_HOST_OPT_PIPELINE, 672b2325ffSGerd Hoffmann }; 682b2325ffSGerd Hoffmann 692b2325ffSGerd Hoffmann struct USBHostDevice { 702b2325ffSGerd Hoffmann USBDevice parent_obj; 712b2325ffSGerd Hoffmann 722b2325ffSGerd Hoffmann /* properties */ 732b2325ffSGerd Hoffmann struct USBAutoFilter match; 742b2325ffSGerd Hoffmann int32_t bootindex; 752b2325ffSGerd Hoffmann uint32_t iso_urb_count; 762b2325ffSGerd Hoffmann uint32_t iso_urb_frames; 772b2325ffSGerd Hoffmann uint32_t options; 782b2325ffSGerd Hoffmann uint32_t loglevel; 792b2325ffSGerd Hoffmann 802b2325ffSGerd Hoffmann /* state */ 812b2325ffSGerd Hoffmann QTAILQ_ENTRY(USBHostDevice) next; 822b2325ffSGerd Hoffmann int seen, errcount; 832b2325ffSGerd Hoffmann int bus_num; 842b2325ffSGerd Hoffmann int addr; 852b2325ffSGerd Hoffmann char port[16]; 862b2325ffSGerd Hoffmann 872b2325ffSGerd Hoffmann libusb_device *dev; 882b2325ffSGerd Hoffmann libusb_device_handle *dh; 892b2325ffSGerd Hoffmann struct libusb_device_descriptor ddesc; 902b2325ffSGerd Hoffmann 912b2325ffSGerd Hoffmann struct { 922b2325ffSGerd Hoffmann bool detached; 932b2325ffSGerd Hoffmann bool claimed; 942b2325ffSGerd Hoffmann } ifs[USB_MAX_INTERFACES]; 952b2325ffSGerd Hoffmann 962b2325ffSGerd Hoffmann /* callbacks & friends */ 9795efb20cSGerd Hoffmann QEMUBH *bh_nodev; 9895efb20cSGerd Hoffmann QEMUBH *bh_postld; 992b2325ffSGerd Hoffmann Notifier exit; 1002b2325ffSGerd Hoffmann 1012b2325ffSGerd Hoffmann /* request queues */ 1022b2325ffSGerd Hoffmann QTAILQ_HEAD(, USBHostRequest) requests; 1032b2325ffSGerd Hoffmann QTAILQ_HEAD(, USBHostIsoRing) isorings; 1042b2325ffSGerd Hoffmann }; 1052b2325ffSGerd Hoffmann 1062b2325ffSGerd Hoffmann struct USBHostRequest { 1072b2325ffSGerd Hoffmann USBHostDevice *host; 1082b2325ffSGerd Hoffmann USBPacket *p; 1092b2325ffSGerd Hoffmann bool in; 1102b2325ffSGerd Hoffmann struct libusb_transfer *xfer; 1112b2325ffSGerd Hoffmann unsigned char *buffer; 1122b2325ffSGerd Hoffmann unsigned char *cbuf; 1132b2325ffSGerd Hoffmann unsigned int clen; 114b88a3e01SGerd Hoffmann bool usb3ep0quirk; 1152b2325ffSGerd Hoffmann QTAILQ_ENTRY(USBHostRequest) next; 1162b2325ffSGerd Hoffmann }; 1172b2325ffSGerd Hoffmann 1182b2325ffSGerd Hoffmann struct USBHostIsoXfer { 1192b2325ffSGerd Hoffmann USBHostIsoRing *ring; 1202b2325ffSGerd Hoffmann struct libusb_transfer *xfer; 1212b2325ffSGerd Hoffmann bool copy_complete; 1222b2325ffSGerd Hoffmann unsigned int packet; 1232b2325ffSGerd Hoffmann QTAILQ_ENTRY(USBHostIsoXfer) next; 1242b2325ffSGerd Hoffmann }; 1252b2325ffSGerd Hoffmann 1262b2325ffSGerd Hoffmann struct USBHostIsoRing { 1272b2325ffSGerd Hoffmann USBHostDevice *host; 1282b2325ffSGerd Hoffmann USBEndpoint *ep; 1292b2325ffSGerd Hoffmann QTAILQ_HEAD(, USBHostIsoXfer) unused; 1302b2325ffSGerd Hoffmann QTAILQ_HEAD(, USBHostIsoXfer) inflight; 1312b2325ffSGerd Hoffmann QTAILQ_HEAD(, USBHostIsoXfer) copy; 1322b2325ffSGerd Hoffmann QTAILQ_ENTRY(USBHostIsoRing) next; 1332b2325ffSGerd Hoffmann }; 1342b2325ffSGerd Hoffmann 1352b2325ffSGerd Hoffmann static QTAILQ_HEAD(, USBHostDevice) hostdevs = 1362b2325ffSGerd Hoffmann QTAILQ_HEAD_INITIALIZER(hostdevs); 1372b2325ffSGerd Hoffmann 1382b2325ffSGerd Hoffmann static void usb_host_auto_check(void *unused); 1392b2325ffSGerd Hoffmann static void usb_host_release_interfaces(USBHostDevice *s); 1402b2325ffSGerd Hoffmann static void usb_host_nodev(USBHostDevice *s); 141f34d5c75SHans de Goede static void usb_host_detach_kernel(USBHostDevice *s); 1422b2325ffSGerd Hoffmann static void usb_host_attach_kernel(USBHostDevice *s); 1432b2325ffSGerd Hoffmann 1442b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 1452b2325ffSGerd Hoffmann 1461e03e407SChris Johns #ifndef LIBUSB_LOG_LEVEL_WARNING /* older libusb didn't define these */ 1471e03e407SChris Johns #define LIBUSB_LOG_LEVEL_WARNING 2 1481e03e407SChris Johns #endif 1491e03e407SChris Johns 1501e03e407SChris Johns /* ------------------------------------------------------------------------ */ 1511e03e407SChris Johns 1522b2325ffSGerd Hoffmann #define CONTROL_TIMEOUT 10000 /* 10 sec */ 1532b2325ffSGerd Hoffmann #define BULK_TIMEOUT 0 /* unlimited */ 1542b2325ffSGerd Hoffmann #define INTR_TIMEOUT 0 /* unlimited */ 1552b2325ffSGerd Hoffmann 156322fd1f4SGerd Hoffmann #if LIBUSBX_API_VERSION >= 0x01000103 157322fd1f4SGerd Hoffmann # define HAVE_STREAMS 1 158322fd1f4SGerd Hoffmann #endif 159322fd1f4SGerd Hoffmann 1602b2325ffSGerd Hoffmann static const char *speed_name[] = { 1612b2325ffSGerd Hoffmann [LIBUSB_SPEED_UNKNOWN] = "?", 1622b2325ffSGerd Hoffmann [LIBUSB_SPEED_LOW] = "1.5", 1632b2325ffSGerd Hoffmann [LIBUSB_SPEED_FULL] = "12", 1642b2325ffSGerd Hoffmann [LIBUSB_SPEED_HIGH] = "480", 1652b2325ffSGerd Hoffmann [LIBUSB_SPEED_SUPER] = "5000", 1662b2325ffSGerd Hoffmann }; 1672b2325ffSGerd Hoffmann 1682b2325ffSGerd Hoffmann static const unsigned int speed_map[] = { 1692b2325ffSGerd Hoffmann [LIBUSB_SPEED_LOW] = USB_SPEED_LOW, 1702b2325ffSGerd Hoffmann [LIBUSB_SPEED_FULL] = USB_SPEED_FULL, 1712b2325ffSGerd Hoffmann [LIBUSB_SPEED_HIGH] = USB_SPEED_HIGH, 1722b2325ffSGerd Hoffmann [LIBUSB_SPEED_SUPER] = USB_SPEED_SUPER, 1732b2325ffSGerd Hoffmann }; 1742b2325ffSGerd Hoffmann 1752b2325ffSGerd Hoffmann static const unsigned int status_map[] = { 1762b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_COMPLETED] = USB_RET_SUCCESS, 1772b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_ERROR] = USB_RET_IOERROR, 1782b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_TIMED_OUT] = USB_RET_IOERROR, 1792b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_CANCELLED] = USB_RET_IOERROR, 1802b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_STALL] = USB_RET_STALL, 1812b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_NO_DEVICE] = USB_RET_NODEV, 1822b2325ffSGerd Hoffmann [LIBUSB_TRANSFER_OVERFLOW] = USB_RET_BABBLE, 1832b2325ffSGerd Hoffmann }; 1842b2325ffSGerd Hoffmann 1852b2325ffSGerd Hoffmann static const char *err_names[] = { 1862b2325ffSGerd Hoffmann [-LIBUSB_ERROR_IO] = "IO", 1872b2325ffSGerd Hoffmann [-LIBUSB_ERROR_INVALID_PARAM] = "INVALID_PARAM", 1882b2325ffSGerd Hoffmann [-LIBUSB_ERROR_ACCESS] = "ACCESS", 1892b2325ffSGerd Hoffmann [-LIBUSB_ERROR_NO_DEVICE] = "NO_DEVICE", 1902b2325ffSGerd Hoffmann [-LIBUSB_ERROR_NOT_FOUND] = "NOT_FOUND", 1912b2325ffSGerd Hoffmann [-LIBUSB_ERROR_BUSY] = "BUSY", 1922b2325ffSGerd Hoffmann [-LIBUSB_ERROR_TIMEOUT] = "TIMEOUT", 1932b2325ffSGerd Hoffmann [-LIBUSB_ERROR_OVERFLOW] = "OVERFLOW", 1942b2325ffSGerd Hoffmann [-LIBUSB_ERROR_PIPE] = "PIPE", 1952b2325ffSGerd Hoffmann [-LIBUSB_ERROR_INTERRUPTED] = "INTERRUPTED", 1962b2325ffSGerd Hoffmann [-LIBUSB_ERROR_NO_MEM] = "NO_MEM", 1972b2325ffSGerd Hoffmann [-LIBUSB_ERROR_NOT_SUPPORTED] = "NOT_SUPPORTED", 1982b2325ffSGerd Hoffmann [-LIBUSB_ERROR_OTHER] = "OTHER", 1992b2325ffSGerd Hoffmann }; 2002b2325ffSGerd Hoffmann 2012b2325ffSGerd Hoffmann static libusb_context *ctx; 2022b2325ffSGerd Hoffmann static uint32_t loglevel; 2032b2325ffSGerd Hoffmann 2042b2325ffSGerd Hoffmann static void usb_host_handle_fd(void *opaque) 2052b2325ffSGerd Hoffmann { 2062b2325ffSGerd Hoffmann struct timeval tv = { 0, 0 }; 2072b2325ffSGerd Hoffmann libusb_handle_events_timeout(ctx, &tv); 2082b2325ffSGerd Hoffmann } 2092b2325ffSGerd Hoffmann 2102b2325ffSGerd Hoffmann static void usb_host_add_fd(int fd, short events, void *user_data) 2112b2325ffSGerd Hoffmann { 2122b2325ffSGerd Hoffmann qemu_set_fd_handler(fd, 2132b2325ffSGerd Hoffmann (events & POLLIN) ? usb_host_handle_fd : NULL, 2142b2325ffSGerd Hoffmann (events & POLLOUT) ? usb_host_handle_fd : NULL, 2152b2325ffSGerd Hoffmann ctx); 2162b2325ffSGerd Hoffmann } 2172b2325ffSGerd Hoffmann 2182b2325ffSGerd Hoffmann static void usb_host_del_fd(int fd, void *user_data) 2192b2325ffSGerd Hoffmann { 2202b2325ffSGerd Hoffmann qemu_set_fd_handler(fd, NULL, NULL, NULL); 2212b2325ffSGerd Hoffmann } 2222b2325ffSGerd Hoffmann 2232b2325ffSGerd Hoffmann static int usb_host_init(void) 2242b2325ffSGerd Hoffmann { 2252b2325ffSGerd Hoffmann const struct libusb_pollfd **poll; 2262b2325ffSGerd Hoffmann int i, rc; 2272b2325ffSGerd Hoffmann 2282b2325ffSGerd Hoffmann if (ctx) { 2292b2325ffSGerd Hoffmann return 0; 2302b2325ffSGerd Hoffmann } 2312b2325ffSGerd Hoffmann rc = libusb_init(&ctx); 2322b2325ffSGerd Hoffmann if (rc != 0) { 2332b2325ffSGerd Hoffmann return -1; 2342b2325ffSGerd Hoffmann } 2352b2325ffSGerd Hoffmann libusb_set_debug(ctx, loglevel); 2362b2325ffSGerd Hoffmann 2372b2325ffSGerd Hoffmann libusb_set_pollfd_notifiers(ctx, usb_host_add_fd, 2382b2325ffSGerd Hoffmann usb_host_del_fd, 2392b2325ffSGerd Hoffmann ctx); 2402b2325ffSGerd Hoffmann poll = libusb_get_pollfds(ctx); 2412b2325ffSGerd Hoffmann if (poll) { 2422b2325ffSGerd Hoffmann for (i = 0; poll[i] != NULL; i++) { 2432b2325ffSGerd Hoffmann usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx); 2442b2325ffSGerd Hoffmann } 2452b2325ffSGerd Hoffmann } 2462b2325ffSGerd Hoffmann free(poll); 2472b2325ffSGerd Hoffmann return 0; 2482b2325ffSGerd Hoffmann } 2492b2325ffSGerd Hoffmann 2502b2325ffSGerd Hoffmann static int usb_host_get_port(libusb_device *dev, char *port, size_t len) 2512b2325ffSGerd Hoffmann { 2522b2325ffSGerd Hoffmann uint8_t path[7]; 2532b2325ffSGerd Hoffmann size_t off; 2542b2325ffSGerd Hoffmann int rc, i; 2552b2325ffSGerd Hoffmann 256bc45de8cSHans de Goede #if LIBUSBX_API_VERSION >= 0x01000102 257bc45de8cSHans de Goede rc = libusb_get_port_numbers(dev, path, 7); 258bc45de8cSHans de Goede #else 2592b2325ffSGerd Hoffmann rc = libusb_get_port_path(ctx, dev, path, 7); 260bc45de8cSHans de Goede #endif 2612b2325ffSGerd Hoffmann if (rc < 0) { 2622b2325ffSGerd Hoffmann return 0; 2632b2325ffSGerd Hoffmann } 2642b2325ffSGerd Hoffmann off = snprintf(port, len, "%d", path[0]); 2652b2325ffSGerd Hoffmann for (i = 1; i < rc; i++) { 2662b2325ffSGerd Hoffmann off += snprintf(port+off, len-off, ".%d", path[i]); 2672b2325ffSGerd Hoffmann } 2682b2325ffSGerd Hoffmann return off; 2692b2325ffSGerd Hoffmann } 2702b2325ffSGerd Hoffmann 2712b2325ffSGerd Hoffmann static void usb_host_libusb_error(const char *func, int rc) 2722b2325ffSGerd Hoffmann { 2732b2325ffSGerd Hoffmann const char *errname; 2742b2325ffSGerd Hoffmann 2752b2325ffSGerd Hoffmann if (rc >= 0) { 2762b2325ffSGerd Hoffmann return; 2772b2325ffSGerd Hoffmann } 2782b2325ffSGerd Hoffmann 2792b2325ffSGerd Hoffmann if (-rc < ARRAY_SIZE(err_names) && err_names[-rc]) { 2802b2325ffSGerd Hoffmann errname = err_names[-rc]; 2812b2325ffSGerd Hoffmann } else { 2822b2325ffSGerd Hoffmann errname = "?"; 2832b2325ffSGerd Hoffmann } 2842e6a0dd1SGonglei error_report("%s: %d [%s]", func, rc, errname); 2852b2325ffSGerd Hoffmann } 2862b2325ffSGerd Hoffmann 2872b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 2882b2325ffSGerd Hoffmann 2892b2325ffSGerd Hoffmann static bool usb_host_use_combining(USBEndpoint *ep) 2902b2325ffSGerd Hoffmann { 2912b2325ffSGerd Hoffmann int type; 2922b2325ffSGerd Hoffmann 2932b2325ffSGerd Hoffmann if (!ep->pipeline) { 2942b2325ffSGerd Hoffmann return false; 2952b2325ffSGerd Hoffmann } 2962b2325ffSGerd Hoffmann if (ep->pid != USB_TOKEN_IN) { 2972b2325ffSGerd Hoffmann return false; 2982b2325ffSGerd Hoffmann } 2992b2325ffSGerd Hoffmann type = usb_ep_get_type(ep->dev, ep->pid, ep->nr); 3002b2325ffSGerd Hoffmann if (type != USB_ENDPOINT_XFER_BULK) { 3012b2325ffSGerd Hoffmann return false; 3022b2325ffSGerd Hoffmann } 3032b2325ffSGerd Hoffmann return true; 3042b2325ffSGerd Hoffmann } 3052b2325ffSGerd Hoffmann 3062b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 3072b2325ffSGerd Hoffmann 3082b2325ffSGerd Hoffmann static USBHostRequest *usb_host_req_alloc(USBHostDevice *s, USBPacket *p, 3092b2325ffSGerd Hoffmann bool in, size_t bufsize) 3102b2325ffSGerd Hoffmann { 3112b2325ffSGerd Hoffmann USBHostRequest *r = g_new0(USBHostRequest, 1); 3122b2325ffSGerd Hoffmann 3132b2325ffSGerd Hoffmann r->host = s; 3142b2325ffSGerd Hoffmann r->p = p; 3152b2325ffSGerd Hoffmann r->in = in; 3162b2325ffSGerd Hoffmann r->xfer = libusb_alloc_transfer(0); 3172b2325ffSGerd Hoffmann if (bufsize) { 3182b2325ffSGerd Hoffmann r->buffer = g_malloc(bufsize); 3192b2325ffSGerd Hoffmann } 3202b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&s->requests, r, next); 3212b2325ffSGerd Hoffmann return r; 3222b2325ffSGerd Hoffmann } 3232b2325ffSGerd Hoffmann 3242b2325ffSGerd Hoffmann static void usb_host_req_free(USBHostRequest *r) 3252b2325ffSGerd Hoffmann { 3262b2325ffSGerd Hoffmann if (r->host) { 3272b2325ffSGerd Hoffmann QTAILQ_REMOVE(&r->host->requests, r, next); 3282b2325ffSGerd Hoffmann } 3292b2325ffSGerd Hoffmann libusb_free_transfer(r->xfer); 3302b2325ffSGerd Hoffmann g_free(r->buffer); 3312b2325ffSGerd Hoffmann g_free(r); 3322b2325ffSGerd Hoffmann } 3332b2325ffSGerd Hoffmann 3342b2325ffSGerd Hoffmann static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p) 3352b2325ffSGerd Hoffmann { 3362b2325ffSGerd Hoffmann USBHostRequest *r; 3372b2325ffSGerd Hoffmann 3382b2325ffSGerd Hoffmann QTAILQ_FOREACH(r, &s->requests, next) { 3392b2325ffSGerd Hoffmann if (r->p == p) { 3402b2325ffSGerd Hoffmann return r; 3412b2325ffSGerd Hoffmann } 3422b2325ffSGerd Hoffmann } 3432b2325ffSGerd Hoffmann return NULL; 3442b2325ffSGerd Hoffmann } 3452b2325ffSGerd Hoffmann 3462b2325ffSGerd Hoffmann static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer) 3472b2325ffSGerd Hoffmann { 3482b2325ffSGerd Hoffmann USBHostRequest *r = xfer->user_data; 3492b2325ffSGerd Hoffmann USBHostDevice *s = r->host; 3502b2325ffSGerd Hoffmann bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE); 3512b2325ffSGerd Hoffmann 3522b2325ffSGerd Hoffmann if (r->p == NULL) { 3532b2325ffSGerd Hoffmann goto out; /* request was canceled */ 3542b2325ffSGerd Hoffmann } 3552b2325ffSGerd Hoffmann 3562b2325ffSGerd Hoffmann r->p->status = status_map[xfer->status]; 3572b2325ffSGerd Hoffmann r->p->actual_length = xfer->actual_length; 3582b2325ffSGerd Hoffmann if (r->in && xfer->actual_length) { 3592b2325ffSGerd Hoffmann memcpy(r->cbuf, r->buffer + 8, xfer->actual_length); 360b88a3e01SGerd Hoffmann 361b88a3e01SGerd Hoffmann /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices 362b88a3e01SGerd Hoffmann * to work redirected to a not superspeed capable hcd */ 363b88a3e01SGerd Hoffmann if (r->usb3ep0quirk && xfer->actual_length >= 18 && 364b88a3e01SGerd Hoffmann r->cbuf[7] == 9) { 365b88a3e01SGerd Hoffmann r->cbuf[7] = 64; 366b88a3e01SGerd Hoffmann } 3672b2325ffSGerd Hoffmann } 3682b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, r->p, 3692b2325ffSGerd Hoffmann r->p->status, r->p->actual_length); 3702b2325ffSGerd Hoffmann usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p); 3712b2325ffSGerd Hoffmann 3722b2325ffSGerd Hoffmann out: 3732b2325ffSGerd Hoffmann usb_host_req_free(r); 3742b2325ffSGerd Hoffmann if (disconnect) { 3752b2325ffSGerd Hoffmann usb_host_nodev(s); 3762b2325ffSGerd Hoffmann } 3772b2325ffSGerd Hoffmann } 3782b2325ffSGerd Hoffmann 3792b2325ffSGerd Hoffmann static void usb_host_req_complete_data(struct libusb_transfer *xfer) 3802b2325ffSGerd Hoffmann { 3812b2325ffSGerd Hoffmann USBHostRequest *r = xfer->user_data; 3822b2325ffSGerd Hoffmann USBHostDevice *s = r->host; 3832b2325ffSGerd Hoffmann bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE); 3842b2325ffSGerd Hoffmann 3852b2325ffSGerd Hoffmann if (r->p == NULL) { 3862b2325ffSGerd Hoffmann goto out; /* request was canceled */ 3872b2325ffSGerd Hoffmann } 3882b2325ffSGerd Hoffmann 3892b2325ffSGerd Hoffmann r->p->status = status_map[xfer->status]; 3902b2325ffSGerd Hoffmann if (r->in && xfer->actual_length) { 3912b2325ffSGerd Hoffmann usb_packet_copy(r->p, r->buffer, xfer->actual_length); 3922b2325ffSGerd Hoffmann } 3932b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, r->p, 3942b2325ffSGerd Hoffmann r->p->status, r->p->actual_length); 3952b2325ffSGerd Hoffmann if (usb_host_use_combining(r->p->ep)) { 3962b2325ffSGerd Hoffmann usb_combined_input_packet_complete(USB_DEVICE(s), r->p); 3972b2325ffSGerd Hoffmann } else { 3982b2325ffSGerd Hoffmann usb_packet_complete(USB_DEVICE(s), r->p); 3992b2325ffSGerd Hoffmann } 4002b2325ffSGerd Hoffmann 4012b2325ffSGerd Hoffmann out: 4022b2325ffSGerd Hoffmann usb_host_req_free(r); 4032b2325ffSGerd Hoffmann if (disconnect) { 4042b2325ffSGerd Hoffmann usb_host_nodev(s); 4052b2325ffSGerd Hoffmann } 4062b2325ffSGerd Hoffmann } 4072b2325ffSGerd Hoffmann 4082b2325ffSGerd Hoffmann static void usb_host_req_abort(USBHostRequest *r) 4092b2325ffSGerd Hoffmann { 4102b2325ffSGerd Hoffmann USBHostDevice *s = r->host; 41145ec2671SEd Maste bool inflight = (r->p && r->p->state == USB_PACKET_ASYNC); 4122b2325ffSGerd Hoffmann 4132b2325ffSGerd Hoffmann if (inflight) { 4142b2325ffSGerd Hoffmann r->p->status = USB_RET_NODEV; 4152b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, r->p, 4162b2325ffSGerd Hoffmann r->p->status, r->p->actual_length); 4172b2325ffSGerd Hoffmann if (r->p->ep->nr == 0) { 4182b2325ffSGerd Hoffmann usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p); 4192b2325ffSGerd Hoffmann } else { 4202b2325ffSGerd Hoffmann usb_packet_complete(USB_DEVICE(s), r->p); 4212b2325ffSGerd Hoffmann } 4222b2325ffSGerd Hoffmann r->p = NULL; 4232b2325ffSGerd Hoffmann } 4242b2325ffSGerd Hoffmann 4252b2325ffSGerd Hoffmann QTAILQ_REMOVE(&r->host->requests, r, next); 4262b2325ffSGerd Hoffmann r->host = NULL; 4272b2325ffSGerd Hoffmann 4282b2325ffSGerd Hoffmann if (inflight) { 4292b2325ffSGerd Hoffmann libusb_cancel_transfer(r->xfer); 4302b2325ffSGerd Hoffmann } 4312b2325ffSGerd Hoffmann } 4322b2325ffSGerd Hoffmann 4332b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 4342b2325ffSGerd Hoffmann 4352b2325ffSGerd Hoffmann static void usb_host_req_complete_iso(struct libusb_transfer *transfer) 4362b2325ffSGerd Hoffmann { 4372b2325ffSGerd Hoffmann USBHostIsoXfer *xfer = transfer->user_data; 4382b2325ffSGerd Hoffmann 4392b2325ffSGerd Hoffmann if (!xfer) { 4402b2325ffSGerd Hoffmann /* USBHostIsoXfer released while inflight */ 4412b2325ffSGerd Hoffmann g_free(transfer->buffer); 4422b2325ffSGerd Hoffmann libusb_free_transfer(transfer); 4432b2325ffSGerd Hoffmann return; 4442b2325ffSGerd Hoffmann } 4452b2325ffSGerd Hoffmann 4462b2325ffSGerd Hoffmann QTAILQ_REMOVE(&xfer->ring->inflight, xfer, next); 4472b2325ffSGerd Hoffmann if (QTAILQ_EMPTY(&xfer->ring->inflight)) { 4482b2325ffSGerd Hoffmann USBHostDevice *s = xfer->ring->host; 4492b2325ffSGerd Hoffmann trace_usb_host_iso_stop(s->bus_num, s->addr, xfer->ring->ep->nr); 4502b2325ffSGerd Hoffmann } 4512b2325ffSGerd Hoffmann if (xfer->ring->ep->pid == USB_TOKEN_IN) { 4522b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&xfer->ring->copy, xfer, next); 4532b2325ffSGerd Hoffmann } else { 4542b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&xfer->ring->unused, xfer, next); 4552b2325ffSGerd Hoffmann } 4562b2325ffSGerd Hoffmann } 4572b2325ffSGerd Hoffmann 4582b2325ffSGerd Hoffmann static USBHostIsoRing *usb_host_iso_alloc(USBHostDevice *s, USBEndpoint *ep) 4592b2325ffSGerd Hoffmann { 4602b2325ffSGerd Hoffmann USBHostIsoRing *ring = g_new0(USBHostIsoRing, 1); 4612b2325ffSGerd Hoffmann USBHostIsoXfer *xfer; 4622b2325ffSGerd Hoffmann /* FIXME: check interval (for now assume one xfer per frame) */ 4632b2325ffSGerd Hoffmann int packets = s->iso_urb_frames; 4642b2325ffSGerd Hoffmann int i; 4652b2325ffSGerd Hoffmann 4662b2325ffSGerd Hoffmann ring->host = s; 4672b2325ffSGerd Hoffmann ring->ep = ep; 4682b2325ffSGerd Hoffmann QTAILQ_INIT(&ring->unused); 4692b2325ffSGerd Hoffmann QTAILQ_INIT(&ring->inflight); 4702b2325ffSGerd Hoffmann QTAILQ_INIT(&ring->copy); 4712b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&s->isorings, ring, next); 4722b2325ffSGerd Hoffmann 4732b2325ffSGerd Hoffmann for (i = 0; i < s->iso_urb_count; i++) { 4742b2325ffSGerd Hoffmann xfer = g_new0(USBHostIsoXfer, 1); 4752b2325ffSGerd Hoffmann xfer->ring = ring; 4762b2325ffSGerd Hoffmann xfer->xfer = libusb_alloc_transfer(packets); 4772b2325ffSGerd Hoffmann xfer->xfer->dev_handle = s->dh; 4782b2325ffSGerd Hoffmann xfer->xfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; 4792b2325ffSGerd Hoffmann 4802b2325ffSGerd Hoffmann xfer->xfer->endpoint = ring->ep->nr; 4812b2325ffSGerd Hoffmann if (ring->ep->pid == USB_TOKEN_IN) { 4822b2325ffSGerd Hoffmann xfer->xfer->endpoint |= USB_DIR_IN; 4832b2325ffSGerd Hoffmann } 4842b2325ffSGerd Hoffmann xfer->xfer->callback = usb_host_req_complete_iso; 4852b2325ffSGerd Hoffmann xfer->xfer->user_data = xfer; 4862b2325ffSGerd Hoffmann 4872b2325ffSGerd Hoffmann xfer->xfer->num_iso_packets = packets; 4882b2325ffSGerd Hoffmann xfer->xfer->length = ring->ep->max_packet_size * packets; 4892b2325ffSGerd Hoffmann xfer->xfer->buffer = g_malloc0(xfer->xfer->length); 4902b2325ffSGerd Hoffmann 4912b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); 4922b2325ffSGerd Hoffmann } 4932b2325ffSGerd Hoffmann 4942b2325ffSGerd Hoffmann return ring; 4952b2325ffSGerd Hoffmann } 4962b2325ffSGerd Hoffmann 4972b2325ffSGerd Hoffmann static USBHostIsoRing *usb_host_iso_find(USBHostDevice *s, USBEndpoint *ep) 4982b2325ffSGerd Hoffmann { 4992b2325ffSGerd Hoffmann USBHostIsoRing *ring; 5002b2325ffSGerd Hoffmann 5012b2325ffSGerd Hoffmann QTAILQ_FOREACH(ring, &s->isorings, next) { 5022b2325ffSGerd Hoffmann if (ring->ep == ep) { 5032b2325ffSGerd Hoffmann return ring; 5042b2325ffSGerd Hoffmann } 5052b2325ffSGerd Hoffmann } 5062b2325ffSGerd Hoffmann return NULL; 5072b2325ffSGerd Hoffmann } 5082b2325ffSGerd Hoffmann 5092b2325ffSGerd Hoffmann static void usb_host_iso_reset_xfer(USBHostIsoXfer *xfer) 5102b2325ffSGerd Hoffmann { 5112b2325ffSGerd Hoffmann libusb_set_iso_packet_lengths(xfer->xfer, 5122b2325ffSGerd Hoffmann xfer->ring->ep->max_packet_size); 5132b2325ffSGerd Hoffmann xfer->packet = 0; 5142b2325ffSGerd Hoffmann xfer->copy_complete = false; 5152b2325ffSGerd Hoffmann } 5162b2325ffSGerd Hoffmann 5172b2325ffSGerd Hoffmann static void usb_host_iso_free_xfer(USBHostIsoXfer *xfer, bool inflight) 5182b2325ffSGerd Hoffmann { 5192b2325ffSGerd Hoffmann if (inflight) { 5202b2325ffSGerd Hoffmann xfer->xfer->user_data = NULL; 5212b2325ffSGerd Hoffmann } else { 5222b2325ffSGerd Hoffmann g_free(xfer->xfer->buffer); 5232b2325ffSGerd Hoffmann libusb_free_transfer(xfer->xfer); 5242b2325ffSGerd Hoffmann } 5252b2325ffSGerd Hoffmann g_free(xfer); 5262b2325ffSGerd Hoffmann } 5272b2325ffSGerd Hoffmann 5282b2325ffSGerd Hoffmann static void usb_host_iso_free(USBHostIsoRing *ring) 5292b2325ffSGerd Hoffmann { 5302b2325ffSGerd Hoffmann USBHostIsoXfer *xfer; 5312b2325ffSGerd Hoffmann 5322b2325ffSGerd Hoffmann while ((xfer = QTAILQ_FIRST(&ring->inflight)) != NULL) { 5332b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->inflight, xfer, next); 5342b2325ffSGerd Hoffmann usb_host_iso_free_xfer(xfer, true); 5352b2325ffSGerd Hoffmann } 5362b2325ffSGerd Hoffmann while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) { 5372b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->unused, xfer, next); 5382b2325ffSGerd Hoffmann usb_host_iso_free_xfer(xfer, false); 5392b2325ffSGerd Hoffmann } 5402b2325ffSGerd Hoffmann while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL) { 5412b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->copy, xfer, next); 5422b2325ffSGerd Hoffmann usb_host_iso_free_xfer(xfer, false); 5432b2325ffSGerd Hoffmann } 5442b2325ffSGerd Hoffmann 5452b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->host->isorings, ring, next); 5462b2325ffSGerd Hoffmann g_free(ring); 5472b2325ffSGerd Hoffmann } 5482b2325ffSGerd Hoffmann 5492b2325ffSGerd Hoffmann static void usb_host_iso_free_all(USBHostDevice *s) 5502b2325ffSGerd Hoffmann { 5512b2325ffSGerd Hoffmann USBHostIsoRing *ring; 5522b2325ffSGerd Hoffmann 5532b2325ffSGerd Hoffmann while ((ring = QTAILQ_FIRST(&s->isorings)) != NULL) { 5542b2325ffSGerd Hoffmann usb_host_iso_free(ring); 5552b2325ffSGerd Hoffmann } 5562b2325ffSGerd Hoffmann } 5572b2325ffSGerd Hoffmann 5582b2325ffSGerd Hoffmann static bool usb_host_iso_data_copy(USBHostIsoXfer *xfer, USBPacket *p) 5592b2325ffSGerd Hoffmann { 5602b2325ffSGerd Hoffmann unsigned int psize; 5612b2325ffSGerd Hoffmann unsigned char *buf; 5622b2325ffSGerd Hoffmann 5632b2325ffSGerd Hoffmann buf = libusb_get_iso_packet_buffer_simple(xfer->xfer, xfer->packet); 5642b2325ffSGerd Hoffmann if (p->pid == USB_TOKEN_OUT) { 5652b2325ffSGerd Hoffmann psize = p->iov.size; 5662b2325ffSGerd Hoffmann if (psize > xfer->ring->ep->max_packet_size) { 5672b2325ffSGerd Hoffmann /* should not happen (guest bug) */ 5682b2325ffSGerd Hoffmann psize = xfer->ring->ep->max_packet_size; 5692b2325ffSGerd Hoffmann } 5702b2325ffSGerd Hoffmann xfer->xfer->iso_packet_desc[xfer->packet].length = psize; 5712b2325ffSGerd Hoffmann } else { 5722b2325ffSGerd Hoffmann psize = xfer->xfer->iso_packet_desc[xfer->packet].actual_length; 5732b2325ffSGerd Hoffmann if (psize > p->iov.size) { 5742b2325ffSGerd Hoffmann /* should not happen (guest bug) */ 5752b2325ffSGerd Hoffmann psize = p->iov.size; 5762b2325ffSGerd Hoffmann } 5772b2325ffSGerd Hoffmann } 5782b2325ffSGerd Hoffmann usb_packet_copy(p, buf, psize); 5792b2325ffSGerd Hoffmann xfer->packet++; 5802b2325ffSGerd Hoffmann xfer->copy_complete = (xfer->packet == xfer->xfer->num_iso_packets); 5812b2325ffSGerd Hoffmann return xfer->copy_complete; 5822b2325ffSGerd Hoffmann } 5832b2325ffSGerd Hoffmann 5842b2325ffSGerd Hoffmann static void usb_host_iso_data_in(USBHostDevice *s, USBPacket *p) 5852b2325ffSGerd Hoffmann { 5862b2325ffSGerd Hoffmann USBHostIsoRing *ring; 5872b2325ffSGerd Hoffmann USBHostIsoXfer *xfer; 5882b2325ffSGerd Hoffmann bool disconnect = false; 5892b2325ffSGerd Hoffmann int rc; 5902b2325ffSGerd Hoffmann 5912b2325ffSGerd Hoffmann ring = usb_host_iso_find(s, p->ep); 5922b2325ffSGerd Hoffmann if (ring == NULL) { 5932b2325ffSGerd Hoffmann ring = usb_host_iso_alloc(s, p->ep); 5942b2325ffSGerd Hoffmann } 5952b2325ffSGerd Hoffmann 5962b2325ffSGerd Hoffmann /* copy data to guest */ 5972b2325ffSGerd Hoffmann xfer = QTAILQ_FIRST(&ring->copy); 5982b2325ffSGerd Hoffmann if (xfer != NULL) { 5992b2325ffSGerd Hoffmann if (usb_host_iso_data_copy(xfer, p)) { 6002b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->copy, xfer, next); 6012b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); 6022b2325ffSGerd Hoffmann } 6032b2325ffSGerd Hoffmann } 6042b2325ffSGerd Hoffmann 6052b2325ffSGerd Hoffmann /* submit empty bufs to host */ 6062b2325ffSGerd Hoffmann while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) { 6072b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->unused, xfer, next); 6082b2325ffSGerd Hoffmann usb_host_iso_reset_xfer(xfer); 6092b2325ffSGerd Hoffmann rc = libusb_submit_transfer(xfer->xfer); 6102b2325ffSGerd Hoffmann if (rc != 0) { 6112b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_submit_transfer [iso]", rc); 6122b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); 6132b2325ffSGerd Hoffmann if (rc == LIBUSB_ERROR_NO_DEVICE) { 6142b2325ffSGerd Hoffmann disconnect = true; 6152b2325ffSGerd Hoffmann } 6162b2325ffSGerd Hoffmann break; 6172b2325ffSGerd Hoffmann } 6182b2325ffSGerd Hoffmann if (QTAILQ_EMPTY(&ring->inflight)) { 6192b2325ffSGerd Hoffmann trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr); 6202b2325ffSGerd Hoffmann } 6212b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next); 6222b2325ffSGerd Hoffmann } 6232b2325ffSGerd Hoffmann 6242b2325ffSGerd Hoffmann if (disconnect) { 6252b2325ffSGerd Hoffmann usb_host_nodev(s); 6262b2325ffSGerd Hoffmann } 6272b2325ffSGerd Hoffmann } 6282b2325ffSGerd Hoffmann 6292b2325ffSGerd Hoffmann static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p) 6302b2325ffSGerd Hoffmann { 6312b2325ffSGerd Hoffmann USBHostIsoRing *ring; 6322b2325ffSGerd Hoffmann USBHostIsoXfer *xfer; 6332b2325ffSGerd Hoffmann bool disconnect = false; 6342b2325ffSGerd Hoffmann int rc, filled = 0; 6352b2325ffSGerd Hoffmann 6362b2325ffSGerd Hoffmann ring = usb_host_iso_find(s, p->ep); 6372b2325ffSGerd Hoffmann if (ring == NULL) { 6382b2325ffSGerd Hoffmann ring = usb_host_iso_alloc(s, p->ep); 6392b2325ffSGerd Hoffmann } 6402b2325ffSGerd Hoffmann 6412b2325ffSGerd Hoffmann /* copy data from guest */ 6422b2325ffSGerd Hoffmann xfer = QTAILQ_FIRST(&ring->copy); 6432b2325ffSGerd Hoffmann while (xfer != NULL && xfer->copy_complete) { 6442b2325ffSGerd Hoffmann filled++; 6452b2325ffSGerd Hoffmann xfer = QTAILQ_NEXT(xfer, next); 6462b2325ffSGerd Hoffmann } 6472b2325ffSGerd Hoffmann if (xfer == NULL) { 6482b2325ffSGerd Hoffmann xfer = QTAILQ_FIRST(&ring->unused); 6492b2325ffSGerd Hoffmann if (xfer == NULL) { 6502b2325ffSGerd Hoffmann trace_usb_host_iso_out_of_bufs(s->bus_num, s->addr, p->ep->nr); 6512b2325ffSGerd Hoffmann return; 6522b2325ffSGerd Hoffmann } 6532b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->unused, xfer, next); 6542b2325ffSGerd Hoffmann usb_host_iso_reset_xfer(xfer); 6552b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->copy, xfer, next); 6562b2325ffSGerd Hoffmann } 6572b2325ffSGerd Hoffmann usb_host_iso_data_copy(xfer, p); 6582b2325ffSGerd Hoffmann 6592b2325ffSGerd Hoffmann if (QTAILQ_EMPTY(&ring->inflight)) { 6602b2325ffSGerd Hoffmann /* wait until half of our buffers are filled 6612b2325ffSGerd Hoffmann before kicking the iso out stream */ 6622b2325ffSGerd Hoffmann if (filled*2 < s->iso_urb_count) { 6632b2325ffSGerd Hoffmann return; 6642b2325ffSGerd Hoffmann } 6652b2325ffSGerd Hoffmann } 6662b2325ffSGerd Hoffmann 6672b2325ffSGerd Hoffmann /* submit filled bufs to host */ 6682b2325ffSGerd Hoffmann while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL && 6692b2325ffSGerd Hoffmann xfer->copy_complete) { 6702b2325ffSGerd Hoffmann QTAILQ_REMOVE(&ring->copy, xfer, next); 6712b2325ffSGerd Hoffmann rc = libusb_submit_transfer(xfer->xfer); 6722b2325ffSGerd Hoffmann if (rc != 0) { 6732b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_submit_transfer [iso]", rc); 6742b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); 6752b2325ffSGerd Hoffmann if (rc == LIBUSB_ERROR_NO_DEVICE) { 6762b2325ffSGerd Hoffmann disconnect = true; 6772b2325ffSGerd Hoffmann } 6782b2325ffSGerd Hoffmann break; 6792b2325ffSGerd Hoffmann } 6802b2325ffSGerd Hoffmann if (QTAILQ_EMPTY(&ring->inflight)) { 6812b2325ffSGerd Hoffmann trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr); 6822b2325ffSGerd Hoffmann } 6832b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next); 6842b2325ffSGerd Hoffmann } 6852b2325ffSGerd Hoffmann 6862b2325ffSGerd Hoffmann if (disconnect) { 6872b2325ffSGerd Hoffmann usb_host_nodev(s); 6882b2325ffSGerd Hoffmann } 6892b2325ffSGerd Hoffmann } 6902b2325ffSGerd Hoffmann 6912b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 6922b2325ffSGerd Hoffmann 693b88a3e01SGerd Hoffmann static void usb_host_speed_compat(USBHostDevice *s) 694c3268cc1SGerd Hoffmann { 695b88a3e01SGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 696c3268cc1SGerd Hoffmann struct libusb_config_descriptor *conf; 697c3268cc1SGerd Hoffmann const struct libusb_interface_descriptor *intf; 698c3268cc1SGerd Hoffmann const struct libusb_endpoint_descriptor *endp; 699322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 700b88a3e01SGerd Hoffmann struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp; 701b88a3e01SGerd Hoffmann #endif 702b88a3e01SGerd Hoffmann bool compat_high = true; 703b88a3e01SGerd Hoffmann bool compat_full = true; 704c3268cc1SGerd Hoffmann uint8_t type; 705c3268cc1SGerd Hoffmann int rc, c, i, a, e; 706c3268cc1SGerd Hoffmann 707c3268cc1SGerd Hoffmann for (c = 0;; c++) { 708c3268cc1SGerd Hoffmann rc = libusb_get_config_descriptor(s->dev, c, &conf); 709c3268cc1SGerd Hoffmann if (rc != 0) { 710c3268cc1SGerd Hoffmann break; 711c3268cc1SGerd Hoffmann } 712c3268cc1SGerd Hoffmann for (i = 0; i < conf->bNumInterfaces; i++) { 713c3268cc1SGerd Hoffmann for (a = 0; a < conf->interface[i].num_altsetting; a++) { 714c3268cc1SGerd Hoffmann intf = &conf->interface[i].altsetting[a]; 715c3268cc1SGerd Hoffmann for (e = 0; e < intf->bNumEndpoints; e++) { 716c3268cc1SGerd Hoffmann endp = &intf->endpoint[e]; 717c3268cc1SGerd Hoffmann type = endp->bmAttributes & 0x3; 718c3268cc1SGerd Hoffmann switch (type) { 719c3268cc1SGerd Hoffmann case 0x01: /* ISO */ 720b88a3e01SGerd Hoffmann compat_full = false; 721b88a3e01SGerd Hoffmann compat_high = false; 722b88a3e01SGerd Hoffmann break; 723b88a3e01SGerd Hoffmann case 0x02: /* BULK */ 724322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 725b88a3e01SGerd Hoffmann rc = libusb_get_ss_endpoint_companion_descriptor 726b88a3e01SGerd Hoffmann (ctx, endp, &endp_ss_comp); 727b88a3e01SGerd Hoffmann if (rc == LIBUSB_SUCCESS) { 728b88a3e01SGerd Hoffmann libusb_free_ss_endpoint_companion_descriptor 729b88a3e01SGerd Hoffmann (endp_ss_comp); 730b88a3e01SGerd Hoffmann compat_full = false; 731b88a3e01SGerd Hoffmann compat_high = false; 732b88a3e01SGerd Hoffmann } 733b88a3e01SGerd Hoffmann #endif 734b88a3e01SGerd Hoffmann break; 735c3268cc1SGerd Hoffmann case 0x03: /* INTERRUPT */ 736c3268cc1SGerd Hoffmann if (endp->wMaxPacketSize > 64) { 737b88a3e01SGerd Hoffmann compat_full = false; 738b88a3e01SGerd Hoffmann } 739b88a3e01SGerd Hoffmann if (endp->wMaxPacketSize > 1024) { 740b88a3e01SGerd Hoffmann compat_high = false; 741c3268cc1SGerd Hoffmann } 742c3268cc1SGerd Hoffmann break; 743c3268cc1SGerd Hoffmann } 744c3268cc1SGerd Hoffmann } 745c3268cc1SGerd Hoffmann } 746c3268cc1SGerd Hoffmann } 747c3268cc1SGerd Hoffmann libusb_free_config_descriptor(conf); 748c3268cc1SGerd Hoffmann } 749b88a3e01SGerd Hoffmann 750b88a3e01SGerd Hoffmann udev->speedmask = (1 << udev->speed); 751b88a3e01SGerd Hoffmann if (udev->speed == USB_SPEED_SUPER && compat_high) { 752*79ae25afSGerd Hoffmann udev->speedmask |= USB_SPEED_MASK_HIGH; 753b88a3e01SGerd Hoffmann } 754b88a3e01SGerd Hoffmann if (udev->speed == USB_SPEED_SUPER && compat_full) { 755*79ae25afSGerd Hoffmann udev->speedmask |= USB_SPEED_MASK_FULL; 756b88a3e01SGerd Hoffmann } 757b88a3e01SGerd Hoffmann if (udev->speed == USB_SPEED_HIGH && compat_full) { 758*79ae25afSGerd Hoffmann udev->speedmask |= USB_SPEED_MASK_FULL; 759b88a3e01SGerd Hoffmann } 760c3268cc1SGerd Hoffmann } 761c3268cc1SGerd Hoffmann 7622b2325ffSGerd Hoffmann static void usb_host_ep_update(USBHostDevice *s) 7632b2325ffSGerd Hoffmann { 7642b2325ffSGerd Hoffmann static const char *tname[] = { 7652b2325ffSGerd Hoffmann [USB_ENDPOINT_XFER_CONTROL] = "control", 7662b2325ffSGerd Hoffmann [USB_ENDPOINT_XFER_ISOC] = "isoc", 7672b2325ffSGerd Hoffmann [USB_ENDPOINT_XFER_BULK] = "bulk", 7682b2325ffSGerd Hoffmann [USB_ENDPOINT_XFER_INT] = "int", 7692b2325ffSGerd Hoffmann }; 7702b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 7712b2325ffSGerd Hoffmann struct libusb_config_descriptor *conf; 7722b2325ffSGerd Hoffmann const struct libusb_interface_descriptor *intf; 7732b2325ffSGerd Hoffmann const struct libusb_endpoint_descriptor *endp; 774322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 775b664b80fSHans de Goede struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp; 776b664b80fSHans de Goede #endif 7772b2325ffSGerd Hoffmann uint8_t devep, type; 7782b2325ffSGerd Hoffmann int pid, ep; 7792b2325ffSGerd Hoffmann int rc, i, e; 7802b2325ffSGerd Hoffmann 7812b2325ffSGerd Hoffmann usb_ep_reset(udev); 7822b2325ffSGerd Hoffmann rc = libusb_get_active_config_descriptor(s->dev, &conf); 7832b2325ffSGerd Hoffmann if (rc != 0) { 7842b2325ffSGerd Hoffmann return; 7852b2325ffSGerd Hoffmann } 7862b2325ffSGerd Hoffmann trace_usb_host_parse_config(s->bus_num, s->addr, 7872b2325ffSGerd Hoffmann conf->bConfigurationValue, true); 7882b2325ffSGerd Hoffmann 7892b2325ffSGerd Hoffmann for (i = 0; i < conf->bNumInterfaces; i++) { 7902b2325ffSGerd Hoffmann assert(udev->altsetting[i] < conf->interface[i].num_altsetting); 7912b2325ffSGerd Hoffmann intf = &conf->interface[i].altsetting[udev->altsetting[i]]; 7922b2325ffSGerd Hoffmann trace_usb_host_parse_interface(s->bus_num, s->addr, 7932b2325ffSGerd Hoffmann intf->bInterfaceNumber, 7942b2325ffSGerd Hoffmann intf->bAlternateSetting, true); 7952b2325ffSGerd Hoffmann for (e = 0; e < intf->bNumEndpoints; e++) { 7962b2325ffSGerd Hoffmann endp = &intf->endpoint[e]; 7972b2325ffSGerd Hoffmann 7982b2325ffSGerd Hoffmann devep = endp->bEndpointAddress; 7992b2325ffSGerd Hoffmann pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; 8002b2325ffSGerd Hoffmann ep = devep & 0xf; 8012b2325ffSGerd Hoffmann type = endp->bmAttributes & 0x3; 8022b2325ffSGerd Hoffmann 8032b2325ffSGerd Hoffmann if (ep == 0) { 8042b2325ffSGerd Hoffmann trace_usb_host_parse_error(s->bus_num, s->addr, 8052b2325ffSGerd Hoffmann "invalid endpoint address"); 8062b2325ffSGerd Hoffmann return; 8072b2325ffSGerd Hoffmann } 8082b2325ffSGerd Hoffmann if (usb_ep_get_type(udev, pid, ep) != USB_ENDPOINT_XFER_INVALID) { 8092b2325ffSGerd Hoffmann trace_usb_host_parse_error(s->bus_num, s->addr, 8102b2325ffSGerd Hoffmann "duplicate endpoint address"); 8112b2325ffSGerd Hoffmann return; 8122b2325ffSGerd Hoffmann } 8132b2325ffSGerd Hoffmann 8142b2325ffSGerd Hoffmann trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep, 8152b2325ffSGerd Hoffmann (devep & USB_DIR_IN) ? "in" : "out", 8162b2325ffSGerd Hoffmann tname[type], true); 8172b2325ffSGerd Hoffmann usb_ep_set_max_packet_size(udev, pid, ep, 8182b2325ffSGerd Hoffmann endp->wMaxPacketSize); 8192b2325ffSGerd Hoffmann usb_ep_set_type(udev, pid, ep, type); 8202b2325ffSGerd Hoffmann usb_ep_set_ifnum(udev, pid, ep, i); 8212b2325ffSGerd Hoffmann usb_ep_set_halted(udev, pid, ep, 0); 822322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 823b664b80fSHans de Goede if (type == LIBUSB_TRANSFER_TYPE_BULK && 824b664b80fSHans de Goede libusb_get_ss_endpoint_companion_descriptor(ctx, endp, 825b664b80fSHans de Goede &endp_ss_comp) == LIBUSB_SUCCESS) { 826b664b80fSHans de Goede usb_ep_set_max_streams(udev, pid, ep, 827b664b80fSHans de Goede endp_ss_comp->bmAttributes); 828b664b80fSHans de Goede libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp); 829b664b80fSHans de Goede } 830b664b80fSHans de Goede #endif 8312b2325ffSGerd Hoffmann } 8322b2325ffSGerd Hoffmann } 8332b2325ffSGerd Hoffmann 8342b2325ffSGerd Hoffmann libusb_free_config_descriptor(conf); 8352b2325ffSGerd Hoffmann } 8362b2325ffSGerd Hoffmann 8372b2325ffSGerd Hoffmann static int usb_host_open(USBHostDevice *s, libusb_device *dev) 8382b2325ffSGerd Hoffmann { 8392b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 8402b2325ffSGerd Hoffmann int bus_num = libusb_get_bus_number(dev); 8412b2325ffSGerd Hoffmann int addr = libusb_get_device_address(dev); 8422b2325ffSGerd Hoffmann int rc; 8437d553f27SGonglei Error *local_err = NULL; 8442b2325ffSGerd Hoffmann 8452b2325ffSGerd Hoffmann trace_usb_host_open_started(bus_num, addr); 8462b2325ffSGerd Hoffmann 8472b2325ffSGerd Hoffmann if (s->dh != NULL) { 8482b2325ffSGerd Hoffmann goto fail; 8492b2325ffSGerd Hoffmann } 8502b2325ffSGerd Hoffmann rc = libusb_open(dev, &s->dh); 8512b2325ffSGerd Hoffmann if (rc != 0) { 8522b2325ffSGerd Hoffmann goto fail; 8532b2325ffSGerd Hoffmann } 8542b2325ffSGerd Hoffmann 8552b2325ffSGerd Hoffmann s->dev = dev; 8562b2325ffSGerd Hoffmann s->bus_num = bus_num; 8572b2325ffSGerd Hoffmann s->addr = addr; 858f34d5c75SHans de Goede 859f34d5c75SHans de Goede usb_host_detach_kernel(s); 860f34d5c75SHans de Goede 861f34d5c75SHans de Goede libusb_get_device_descriptor(dev, &s->ddesc); 8622b2325ffSGerd Hoffmann usb_host_get_port(s->dev, s->port, sizeof(s->port)); 8632b2325ffSGerd Hoffmann 8642b2325ffSGerd Hoffmann usb_ep_init(udev); 8652b2325ffSGerd Hoffmann usb_host_ep_update(s); 8662b2325ffSGerd Hoffmann 8672b2325ffSGerd Hoffmann udev->speed = speed_map[libusb_get_device_speed(dev)]; 868b88a3e01SGerd Hoffmann usb_host_speed_compat(s); 8692b2325ffSGerd Hoffmann 8702b2325ffSGerd Hoffmann if (s->ddesc.iProduct) { 8712b2325ffSGerd Hoffmann libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct, 8722b2325ffSGerd Hoffmann (unsigned char *)udev->product_desc, 8732b2325ffSGerd Hoffmann sizeof(udev->product_desc)); 8742b2325ffSGerd Hoffmann } else { 8752b2325ffSGerd Hoffmann snprintf(udev->product_desc, sizeof(udev->product_desc), 8762b2325ffSGerd Hoffmann "host:%d.%d", bus_num, addr); 8772b2325ffSGerd Hoffmann } 8782b2325ffSGerd Hoffmann 8797d553f27SGonglei usb_device_attach(udev, &local_err); 8807d553f27SGonglei if (local_err) { 8817d553f27SGonglei error_report("%s", error_get_pretty(local_err)); 8827d553f27SGonglei error_free(local_err); 8832b2325ffSGerd Hoffmann goto fail; 8842b2325ffSGerd Hoffmann } 8852b2325ffSGerd Hoffmann 8862b2325ffSGerd Hoffmann trace_usb_host_open_success(bus_num, addr); 8872b2325ffSGerd Hoffmann return 0; 8882b2325ffSGerd Hoffmann 8892b2325ffSGerd Hoffmann fail: 8902b2325ffSGerd Hoffmann trace_usb_host_open_failure(bus_num, addr); 8912b2325ffSGerd Hoffmann if (s->dh != NULL) { 8922b2325ffSGerd Hoffmann libusb_close(s->dh); 8932b2325ffSGerd Hoffmann s->dh = NULL; 8942b2325ffSGerd Hoffmann s->dev = NULL; 8952b2325ffSGerd Hoffmann } 8962b2325ffSGerd Hoffmann return -1; 8972b2325ffSGerd Hoffmann } 8982b2325ffSGerd Hoffmann 8992b2325ffSGerd Hoffmann static void usb_host_abort_xfers(USBHostDevice *s) 9002b2325ffSGerd Hoffmann { 9012b2325ffSGerd Hoffmann USBHostRequest *r, *rtmp; 9022b2325ffSGerd Hoffmann 9032b2325ffSGerd Hoffmann QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) { 9042b2325ffSGerd Hoffmann usb_host_req_abort(r); 9052b2325ffSGerd Hoffmann } 9062b2325ffSGerd Hoffmann } 9072b2325ffSGerd Hoffmann 9082b2325ffSGerd Hoffmann static int usb_host_close(USBHostDevice *s) 9092b2325ffSGerd Hoffmann { 9102b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 9112b2325ffSGerd Hoffmann 9122b2325ffSGerd Hoffmann if (s->dh == NULL) { 9132b2325ffSGerd Hoffmann return -1; 9142b2325ffSGerd Hoffmann } 9152b2325ffSGerd Hoffmann 9162b2325ffSGerd Hoffmann trace_usb_host_close(s->bus_num, s->addr); 9172b2325ffSGerd Hoffmann 9182b2325ffSGerd Hoffmann usb_host_abort_xfers(s); 9192b2325ffSGerd Hoffmann usb_host_iso_free_all(s); 9202b2325ffSGerd Hoffmann 9212b2325ffSGerd Hoffmann if (udev->attached) { 9222b2325ffSGerd Hoffmann usb_device_detach(udev); 9232b2325ffSGerd Hoffmann } 9242b2325ffSGerd Hoffmann 9252b2325ffSGerd Hoffmann usb_host_release_interfaces(s); 9262b2325ffSGerd Hoffmann libusb_reset_device(s->dh); 9272b2325ffSGerd Hoffmann usb_host_attach_kernel(s); 9282b2325ffSGerd Hoffmann libusb_close(s->dh); 9292b2325ffSGerd Hoffmann s->dh = NULL; 9302b2325ffSGerd Hoffmann s->dev = NULL; 9312b2325ffSGerd Hoffmann 9322b2325ffSGerd Hoffmann usb_host_auto_check(NULL); 9332b2325ffSGerd Hoffmann return 0; 9342b2325ffSGerd Hoffmann } 9352b2325ffSGerd Hoffmann 9362b2325ffSGerd Hoffmann static void usb_host_nodev_bh(void *opaque) 9372b2325ffSGerd Hoffmann { 9382b2325ffSGerd Hoffmann USBHostDevice *s = opaque; 9392b2325ffSGerd Hoffmann usb_host_close(s); 9402b2325ffSGerd Hoffmann } 9412b2325ffSGerd Hoffmann 9422b2325ffSGerd Hoffmann static void usb_host_nodev(USBHostDevice *s) 9432b2325ffSGerd Hoffmann { 94495efb20cSGerd Hoffmann if (!s->bh_nodev) { 94595efb20cSGerd Hoffmann s->bh_nodev = qemu_bh_new(usb_host_nodev_bh, s); 9462b2325ffSGerd Hoffmann } 94795efb20cSGerd Hoffmann qemu_bh_schedule(s->bh_nodev); 9482b2325ffSGerd Hoffmann } 9492b2325ffSGerd Hoffmann 9502b2325ffSGerd Hoffmann static void usb_host_exit_notifier(struct Notifier *n, void *data) 9512b2325ffSGerd Hoffmann { 9522b2325ffSGerd Hoffmann USBHostDevice *s = container_of(n, USBHostDevice, exit); 9532b2325ffSGerd Hoffmann 9542b2325ffSGerd Hoffmann if (s->dh) { 9552b2325ffSGerd Hoffmann usb_host_release_interfaces(s); 9562b2325ffSGerd Hoffmann usb_host_attach_kernel(s); 9572b2325ffSGerd Hoffmann } 9582b2325ffSGerd Hoffmann } 9592b2325ffSGerd Hoffmann 9602aa76dc1SGonglei static void usb_host_realize(USBDevice *udev, Error **errp) 9612b2325ffSGerd Hoffmann { 9622b2325ffSGerd Hoffmann USBHostDevice *s = USB_HOST_DEVICE(udev); 9632b2325ffSGerd Hoffmann 964f3cda6e0SGerd Hoffmann if (s->match.vendor_id > 0xffff) { 9652aa76dc1SGonglei error_setg(errp, "vendorid out of range"); 9662aa76dc1SGonglei return; 967f3cda6e0SGerd Hoffmann } 968f3cda6e0SGerd Hoffmann if (s->match.product_id > 0xffff) { 9692aa76dc1SGonglei error_setg(errp, "productid out of range"); 9702aa76dc1SGonglei return; 971f3cda6e0SGerd Hoffmann } 972f3cda6e0SGerd Hoffmann if (s->match.addr > 127) { 9732aa76dc1SGonglei error_setg(errp, "hostaddr out of range"); 9742aa76dc1SGonglei return; 975f3cda6e0SGerd Hoffmann } 976f3cda6e0SGerd Hoffmann 9772b2325ffSGerd Hoffmann loglevel = s->loglevel; 978628e5485SGerd Hoffmann udev->flags |= (1 << USB_DEV_FLAG_IS_HOST); 9792b2325ffSGerd Hoffmann udev->auto_attach = 0; 9802b2325ffSGerd Hoffmann QTAILQ_INIT(&s->requests); 9812b2325ffSGerd Hoffmann QTAILQ_INIT(&s->isorings); 9822b2325ffSGerd Hoffmann 9832b2325ffSGerd Hoffmann s->exit.notify = usb_host_exit_notifier; 9842b2325ffSGerd Hoffmann qemu_add_exit_notifier(&s->exit); 9852b2325ffSGerd Hoffmann 9862b2325ffSGerd Hoffmann QTAILQ_INSERT_TAIL(&hostdevs, s, next); 9872b2325ffSGerd Hoffmann usb_host_auto_check(NULL); 9882b2325ffSGerd Hoffmann } 9892b2325ffSGerd Hoffmann 990e6adae52SGonglei static void usb_host_instance_init(Object *obj) 991e6adae52SGonglei { 992e6adae52SGonglei USBDevice *udev = USB_DEVICE(obj); 993e6adae52SGonglei USBHostDevice *s = USB_HOST_DEVICE(udev); 994e6adae52SGonglei 995e6adae52SGonglei device_add_bootindex_property(obj, &s->bootindex, 996e6adae52SGonglei "bootindex", NULL, 997e6adae52SGonglei &udev->qdev, NULL); 998e6adae52SGonglei } 999e6adae52SGonglei 10002b2325ffSGerd Hoffmann static void usb_host_handle_destroy(USBDevice *udev) 10012b2325ffSGerd Hoffmann { 10022b2325ffSGerd Hoffmann USBHostDevice *s = USB_HOST_DEVICE(udev); 10032b2325ffSGerd Hoffmann 10042b2325ffSGerd Hoffmann qemu_remove_exit_notifier(&s->exit); 10052b2325ffSGerd Hoffmann QTAILQ_REMOVE(&hostdevs, s, next); 10062b2325ffSGerd Hoffmann usb_host_close(s); 10072b2325ffSGerd Hoffmann } 10082b2325ffSGerd Hoffmann 10092b2325ffSGerd Hoffmann static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p) 10102b2325ffSGerd Hoffmann { 10112b2325ffSGerd Hoffmann USBHostDevice *s = USB_HOST_DEVICE(udev); 10122b2325ffSGerd Hoffmann USBHostRequest *r; 10132b2325ffSGerd Hoffmann 10142b2325ffSGerd Hoffmann if (p->combined) { 10152b2325ffSGerd Hoffmann usb_combined_packet_cancel(udev, p); 10162b2325ffSGerd Hoffmann return; 10172b2325ffSGerd Hoffmann } 10182b2325ffSGerd Hoffmann 10192b2325ffSGerd Hoffmann trace_usb_host_req_canceled(s->bus_num, s->addr, p); 10202b2325ffSGerd Hoffmann 10212b2325ffSGerd Hoffmann r = usb_host_req_find(s, p); 10222b2325ffSGerd Hoffmann if (r && r->p) { 10232b2325ffSGerd Hoffmann r->p = NULL; /* mark as dead */ 10242b2325ffSGerd Hoffmann libusb_cancel_transfer(r->xfer); 10252b2325ffSGerd Hoffmann } 10262b2325ffSGerd Hoffmann } 10272b2325ffSGerd Hoffmann 10282b2325ffSGerd Hoffmann static void usb_host_detach_kernel(USBHostDevice *s) 10292b2325ffSGerd Hoffmann { 10302b2325ffSGerd Hoffmann struct libusb_config_descriptor *conf; 10312b2325ffSGerd Hoffmann int rc, i; 10322b2325ffSGerd Hoffmann 10332b2325ffSGerd Hoffmann rc = libusb_get_active_config_descriptor(s->dev, &conf); 10342b2325ffSGerd Hoffmann if (rc != 0) { 10352b2325ffSGerd Hoffmann return; 10362b2325ffSGerd Hoffmann } 10372b2325ffSGerd Hoffmann for (i = 0; i < conf->bNumInterfaces; i++) { 10382b2325ffSGerd Hoffmann rc = libusb_kernel_driver_active(s->dh, i); 10392b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_kernel_driver_active", rc); 10402b2325ffSGerd Hoffmann if (rc != 1) { 10412b2325ffSGerd Hoffmann continue; 10422b2325ffSGerd Hoffmann } 10432b2325ffSGerd Hoffmann trace_usb_host_detach_kernel(s->bus_num, s->addr, i); 10442b2325ffSGerd Hoffmann rc = libusb_detach_kernel_driver(s->dh, i); 10452b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_detach_kernel_driver", rc); 10462b2325ffSGerd Hoffmann s->ifs[i].detached = true; 10472b2325ffSGerd Hoffmann } 10482b2325ffSGerd Hoffmann libusb_free_config_descriptor(conf); 10492b2325ffSGerd Hoffmann } 10502b2325ffSGerd Hoffmann 10512b2325ffSGerd Hoffmann static void usb_host_attach_kernel(USBHostDevice *s) 10522b2325ffSGerd Hoffmann { 10532b2325ffSGerd Hoffmann struct libusb_config_descriptor *conf; 10542b2325ffSGerd Hoffmann int rc, i; 10552b2325ffSGerd Hoffmann 10562b2325ffSGerd Hoffmann rc = libusb_get_active_config_descriptor(s->dev, &conf); 10572b2325ffSGerd Hoffmann if (rc != 0) { 10582b2325ffSGerd Hoffmann return; 10592b2325ffSGerd Hoffmann } 10602b2325ffSGerd Hoffmann for (i = 0; i < conf->bNumInterfaces; i++) { 10612b2325ffSGerd Hoffmann if (!s->ifs[i].detached) { 10622b2325ffSGerd Hoffmann continue; 10632b2325ffSGerd Hoffmann } 10642b2325ffSGerd Hoffmann trace_usb_host_attach_kernel(s->bus_num, s->addr, i); 10652b2325ffSGerd Hoffmann libusb_attach_kernel_driver(s->dh, i); 10662b2325ffSGerd Hoffmann s->ifs[i].detached = false; 10672b2325ffSGerd Hoffmann } 10682b2325ffSGerd Hoffmann libusb_free_config_descriptor(conf); 10692b2325ffSGerd Hoffmann } 10702b2325ffSGerd Hoffmann 10712b2325ffSGerd Hoffmann static int usb_host_claim_interfaces(USBHostDevice *s, int configuration) 10722b2325ffSGerd Hoffmann { 10732b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 10742b2325ffSGerd Hoffmann struct libusb_config_descriptor *conf; 10752b2325ffSGerd Hoffmann int rc, i; 10762b2325ffSGerd Hoffmann 10772b2325ffSGerd Hoffmann for (i = 0; i < USB_MAX_INTERFACES; i++) { 10782b2325ffSGerd Hoffmann udev->altsetting[i] = 0; 10792b2325ffSGerd Hoffmann } 10802b2325ffSGerd Hoffmann udev->ninterfaces = 0; 10812b2325ffSGerd Hoffmann udev->configuration = 0; 10822b2325ffSGerd Hoffmann 10832b2325ffSGerd Hoffmann usb_host_detach_kernel(s); 10842b2325ffSGerd Hoffmann 10852b2325ffSGerd Hoffmann rc = libusb_get_active_config_descriptor(s->dev, &conf); 10862b2325ffSGerd Hoffmann if (rc != 0) { 10871294ca79SHans de Goede if (rc == LIBUSB_ERROR_NOT_FOUND) { 10881294ca79SHans de Goede /* address state - ignore */ 10891294ca79SHans de Goede return USB_RET_SUCCESS; 10901294ca79SHans de Goede } 10912b2325ffSGerd Hoffmann return USB_RET_STALL; 10922b2325ffSGerd Hoffmann } 10932b2325ffSGerd Hoffmann 10942b2325ffSGerd Hoffmann for (i = 0; i < conf->bNumInterfaces; i++) { 10952b2325ffSGerd Hoffmann trace_usb_host_claim_interface(s->bus_num, s->addr, configuration, i); 10962b2325ffSGerd Hoffmann rc = libusb_claim_interface(s->dh, i); 10972b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_claim_interface", rc); 10982b2325ffSGerd Hoffmann if (rc != 0) { 10992b2325ffSGerd Hoffmann return USB_RET_STALL; 11002b2325ffSGerd Hoffmann } 11012b2325ffSGerd Hoffmann s->ifs[i].claimed = true; 11022b2325ffSGerd Hoffmann } 11032b2325ffSGerd Hoffmann 11042b2325ffSGerd Hoffmann udev->ninterfaces = conf->bNumInterfaces; 11052b2325ffSGerd Hoffmann udev->configuration = configuration; 11062b2325ffSGerd Hoffmann 11072b2325ffSGerd Hoffmann libusb_free_config_descriptor(conf); 11082b2325ffSGerd Hoffmann return USB_RET_SUCCESS; 11092b2325ffSGerd Hoffmann } 11102b2325ffSGerd Hoffmann 11112b2325ffSGerd Hoffmann static void usb_host_release_interfaces(USBHostDevice *s) 11122b2325ffSGerd Hoffmann { 11132b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 11142b2325ffSGerd Hoffmann int i, rc; 11152b2325ffSGerd Hoffmann 11162b2325ffSGerd Hoffmann for (i = 0; i < udev->ninterfaces; i++) { 11172b2325ffSGerd Hoffmann if (!s->ifs[i].claimed) { 11182b2325ffSGerd Hoffmann continue; 11192b2325ffSGerd Hoffmann } 11202b2325ffSGerd Hoffmann trace_usb_host_release_interface(s->bus_num, s->addr, i); 11212b2325ffSGerd Hoffmann rc = libusb_release_interface(s->dh, i); 11222b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_release_interface", rc); 11232b2325ffSGerd Hoffmann s->ifs[i].claimed = false; 11242b2325ffSGerd Hoffmann } 11252b2325ffSGerd Hoffmann } 11262b2325ffSGerd Hoffmann 11272b2325ffSGerd Hoffmann static void usb_host_set_address(USBHostDevice *s, int addr) 11282b2325ffSGerd Hoffmann { 11292b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 11302b2325ffSGerd Hoffmann 11312b2325ffSGerd Hoffmann trace_usb_host_set_address(s->bus_num, s->addr, addr); 11322b2325ffSGerd Hoffmann udev->addr = addr; 11332b2325ffSGerd Hoffmann } 11342b2325ffSGerd Hoffmann 11352b2325ffSGerd Hoffmann static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p) 11362b2325ffSGerd Hoffmann { 11372b2325ffSGerd Hoffmann int rc; 11382b2325ffSGerd Hoffmann 11392b2325ffSGerd Hoffmann trace_usb_host_set_config(s->bus_num, s->addr, config); 11402b2325ffSGerd Hoffmann 11412b2325ffSGerd Hoffmann usb_host_release_interfaces(s); 11422b2325ffSGerd Hoffmann rc = libusb_set_configuration(s->dh, config); 11432b2325ffSGerd Hoffmann if (rc != 0) { 11442b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_set_configuration", rc); 11452b2325ffSGerd Hoffmann p->status = USB_RET_STALL; 11462b2325ffSGerd Hoffmann if (rc == LIBUSB_ERROR_NO_DEVICE) { 11472b2325ffSGerd Hoffmann usb_host_nodev(s); 11482b2325ffSGerd Hoffmann } 11492b2325ffSGerd Hoffmann return; 11502b2325ffSGerd Hoffmann } 11512b2325ffSGerd Hoffmann p->status = usb_host_claim_interfaces(s, config); 11522b2325ffSGerd Hoffmann if (p->status != USB_RET_SUCCESS) { 11532b2325ffSGerd Hoffmann return; 11542b2325ffSGerd Hoffmann } 11552b2325ffSGerd Hoffmann usb_host_ep_update(s); 11562b2325ffSGerd Hoffmann } 11572b2325ffSGerd Hoffmann 11582b2325ffSGerd Hoffmann static void usb_host_set_interface(USBHostDevice *s, int iface, int alt, 11592b2325ffSGerd Hoffmann USBPacket *p) 11602b2325ffSGerd Hoffmann { 11612b2325ffSGerd Hoffmann USBDevice *udev = USB_DEVICE(s); 11622b2325ffSGerd Hoffmann int rc; 11632b2325ffSGerd Hoffmann 11642b2325ffSGerd Hoffmann trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt); 11652b2325ffSGerd Hoffmann 11662b2325ffSGerd Hoffmann usb_host_iso_free_all(s); 11672b2325ffSGerd Hoffmann 11682b2325ffSGerd Hoffmann if (iface >= USB_MAX_INTERFACES) { 11692b2325ffSGerd Hoffmann p->status = USB_RET_STALL; 11702b2325ffSGerd Hoffmann return; 11712b2325ffSGerd Hoffmann } 11722b2325ffSGerd Hoffmann 11732b2325ffSGerd Hoffmann rc = libusb_set_interface_alt_setting(s->dh, iface, alt); 11742b2325ffSGerd Hoffmann if (rc != 0) { 11752b2325ffSGerd Hoffmann usb_host_libusb_error("libusb_set_interface_alt_setting", rc); 11762b2325ffSGerd Hoffmann p->status = USB_RET_STALL; 11772b2325ffSGerd Hoffmann if (rc == LIBUSB_ERROR_NO_DEVICE) { 11782b2325ffSGerd Hoffmann usb_host_nodev(s); 11792b2325ffSGerd Hoffmann } 11802b2325ffSGerd Hoffmann return; 11812b2325ffSGerd Hoffmann } 11822b2325ffSGerd Hoffmann 11832b2325ffSGerd Hoffmann udev->altsetting[iface] = alt; 11842b2325ffSGerd Hoffmann usb_host_ep_update(s); 11852b2325ffSGerd Hoffmann } 11862b2325ffSGerd Hoffmann 11872b2325ffSGerd Hoffmann static void usb_host_handle_control(USBDevice *udev, USBPacket *p, 11882b2325ffSGerd Hoffmann int request, int value, int index, 11892b2325ffSGerd Hoffmann int length, uint8_t *data) 11902b2325ffSGerd Hoffmann { 11912b2325ffSGerd Hoffmann USBHostDevice *s = USB_HOST_DEVICE(udev); 11922b2325ffSGerd Hoffmann USBHostRequest *r; 11932b2325ffSGerd Hoffmann int rc; 11942b2325ffSGerd Hoffmann 11952b2325ffSGerd Hoffmann trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); 11962b2325ffSGerd Hoffmann 11972b2325ffSGerd Hoffmann if (s->dh == NULL) { 11982b2325ffSGerd Hoffmann p->status = USB_RET_NODEV; 11992b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12002b2325ffSGerd Hoffmann return; 12012b2325ffSGerd Hoffmann } 12022b2325ffSGerd Hoffmann 12032b2325ffSGerd Hoffmann switch (request) { 12042b2325ffSGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_ADDRESS: 12052b2325ffSGerd Hoffmann usb_host_set_address(s, value); 12062b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12072b2325ffSGerd Hoffmann return; 12082b2325ffSGerd Hoffmann 12092b2325ffSGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: 12102b2325ffSGerd Hoffmann usb_host_set_config(s, value & 0xff, p); 12112b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12122b2325ffSGerd Hoffmann return; 12132b2325ffSGerd Hoffmann 12142b2325ffSGerd Hoffmann case InterfaceOutRequest | USB_REQ_SET_INTERFACE: 12152b2325ffSGerd Hoffmann usb_host_set_interface(s, index, value, p); 12162b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12172b2325ffSGerd Hoffmann return; 12182b2325ffSGerd Hoffmann 12192b2325ffSGerd Hoffmann case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: 12202b2325ffSGerd Hoffmann if (value == 0) { /* clear halt */ 12212b2325ffSGerd Hoffmann int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; 12222b2325ffSGerd Hoffmann libusb_clear_halt(s->dh, index); 12232b2325ffSGerd Hoffmann usb_ep_set_halted(udev, pid, index & 0x0f, 0); 12242b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12252b2325ffSGerd Hoffmann return; 12262b2325ffSGerd Hoffmann } 12272b2325ffSGerd Hoffmann } 12282b2325ffSGerd Hoffmann 12292b2325ffSGerd Hoffmann r = usb_host_req_alloc(s, p, (request >> 8) & USB_DIR_IN, length + 8); 12302b2325ffSGerd Hoffmann r->cbuf = data; 12312b2325ffSGerd Hoffmann r->clen = length; 12322b2325ffSGerd Hoffmann memcpy(r->buffer, udev->setup_buf, 8); 12332b2325ffSGerd Hoffmann if (!r->in) { 12342b2325ffSGerd Hoffmann memcpy(r->buffer + 8, r->cbuf, r->clen); 12352b2325ffSGerd Hoffmann } 12362b2325ffSGerd Hoffmann 1237b88a3e01SGerd Hoffmann /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices 1238b88a3e01SGerd Hoffmann * to work redirected to a not superspeed capable hcd */ 1239b88a3e01SGerd Hoffmann if (udev->speed == USB_SPEED_SUPER && 1240b88a3e01SGerd Hoffmann !((udev->port->speedmask & USB_SPEED_MASK_SUPER)) && 1241b88a3e01SGerd Hoffmann request == 0x8006 && value == 0x100 && index == 0) { 1242b88a3e01SGerd Hoffmann r->usb3ep0quirk = true; 1243b88a3e01SGerd Hoffmann } 1244b88a3e01SGerd Hoffmann 12452b2325ffSGerd Hoffmann libusb_fill_control_transfer(r->xfer, s->dh, r->buffer, 12462b2325ffSGerd Hoffmann usb_host_req_complete_ctrl, r, 12472b2325ffSGerd Hoffmann CONTROL_TIMEOUT); 12482b2325ffSGerd Hoffmann rc = libusb_submit_transfer(r->xfer); 12492b2325ffSGerd Hoffmann if (rc != 0) { 12502b2325ffSGerd Hoffmann p->status = USB_RET_NODEV; 12512b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, p, 12522b2325ffSGerd Hoffmann p->status, p->actual_length); 12532b2325ffSGerd Hoffmann if (rc == LIBUSB_ERROR_NO_DEVICE) { 12542b2325ffSGerd Hoffmann usb_host_nodev(s); 12552b2325ffSGerd Hoffmann } 12562b2325ffSGerd Hoffmann return; 12572b2325ffSGerd Hoffmann } 12582b2325ffSGerd Hoffmann 12592b2325ffSGerd Hoffmann p->status = USB_RET_ASYNC; 12602b2325ffSGerd Hoffmann } 12612b2325ffSGerd Hoffmann 12622b2325ffSGerd Hoffmann static void usb_host_handle_data(USBDevice *udev, USBPacket *p) 12632b2325ffSGerd Hoffmann { 12642b2325ffSGerd Hoffmann USBHostDevice *s = USB_HOST_DEVICE(udev); 12652b2325ffSGerd Hoffmann USBHostRequest *r; 12662b2325ffSGerd Hoffmann size_t size; 12672b2325ffSGerd Hoffmann int ep, rc; 12682b2325ffSGerd Hoffmann 12692b2325ffSGerd Hoffmann if (usb_host_use_combining(p->ep) && p->state == USB_PACKET_SETUP) { 12702b2325ffSGerd Hoffmann p->status = USB_RET_ADD_TO_QUEUE; 12712b2325ffSGerd Hoffmann return; 12722b2325ffSGerd Hoffmann } 12732b2325ffSGerd Hoffmann 12742b2325ffSGerd Hoffmann trace_usb_host_req_data(s->bus_num, s->addr, p, 12752b2325ffSGerd Hoffmann p->pid == USB_TOKEN_IN, 12762b2325ffSGerd Hoffmann p->ep->nr, p->iov.size); 12772b2325ffSGerd Hoffmann 12782b2325ffSGerd Hoffmann if (s->dh == NULL) { 12792b2325ffSGerd Hoffmann p->status = USB_RET_NODEV; 12802b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12812b2325ffSGerd Hoffmann return; 12822b2325ffSGerd Hoffmann } 12832b2325ffSGerd Hoffmann if (p->ep->halted) { 12842b2325ffSGerd Hoffmann p->status = USB_RET_STALL; 12852b2325ffSGerd Hoffmann trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); 12862b2325ffSGerd Hoffmann return; 12872b2325ffSGerd Hoffmann } 12882b2325ffSGerd Hoffmann 12892b2325ffSGerd Hoffmann switch (usb_ep_get_type(udev, p->pid, p->ep->nr)) { 12902b2325ffSGerd Hoffmann case USB_ENDPOINT_XFER_BULK: 12912b2325ffSGerd Hoffmann size = usb_packet_size(p); 12922b2325ffSGerd Hoffmann r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, size); 12932b2325ffSGerd Hoffmann if (!r->in) { 12942b2325ffSGerd Hoffmann usb_packet_copy(p, r->buffer, size); 12952b2325ffSGerd Hoffmann } 12962b2325ffSGerd Hoffmann ep = p->ep->nr | (r->in ? USB_DIR_IN : 0); 12978d1bd3c9SHans de Goede if (p->stream) { 1298322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 12998d1bd3c9SHans de Goede libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream, 13008d1bd3c9SHans de Goede r->buffer, size, 13018d1bd3c9SHans de Goede usb_host_req_complete_data, r, 13028d1bd3c9SHans de Goede BULK_TIMEOUT); 13038d1bd3c9SHans de Goede #else 13048d1bd3c9SHans de Goede usb_host_req_free(r); 13058d1bd3c9SHans de Goede p->status = USB_RET_STALL; 13068d1bd3c9SHans de Goede return; 13078d1bd3c9SHans de Goede #endif 13088d1bd3c9SHans de Goede } else { 13092b2325ffSGerd Hoffmann libusb_fill_bulk_transfer(r->xfer, s->dh, ep, 13102b2325ffSGerd Hoffmann r->buffer, size, 13112b2325ffSGerd Hoffmann usb_host_req_complete_data, r, 13122b2325ffSGerd Hoffmann BULK_TIMEOUT); 13138d1bd3c9SHans de Goede } 13142b2325ffSGerd Hoffmann break; 13152b2325ffSGerd Hoffmann case USB_ENDPOINT_XFER_INT: 13162b2325ffSGerd Hoffmann r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size); 13172b2325ffSGerd Hoffmann if (!r->in) { 13182b2325ffSGerd Hoffmann usb_packet_copy(p, r->buffer, p->iov.size); 13192b2325ffSGerd Hoffmann } 13202b2325ffSGerd Hoffmann ep = p->ep->nr | (r->in ? USB_DIR_IN : 0); 13212b2325ffSGerd Hoffmann libusb_fill_interrupt_transfer(r->xfer, s->dh, ep, 13222b2325ffSGerd Hoffmann r->buffer, p->iov.size, 13232b2325ffSGerd Hoffmann usb_host_req_complete_data, r, 13242b2325ffSGerd Hoffmann INTR_TIMEOUT); 13252b2325ffSGerd Hoffmann break; 13262b2325ffSGerd Hoffmann case USB_ENDPOINT_XFER_ISOC: 13272b2325ffSGerd Hoffmann if (p->pid == USB_TOKEN_IN) { 13282b2325ffSGerd Hoffmann usb_host_iso_data_in(s, p); 13292b2325ffSGerd Hoffmann } else { 13302b2325ffSGerd Hoffmann usb_host_iso_data_out(s, p); 13312b2325ffSGerd Hoffmann } 13322b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, p, 13332b2325ffSGerd Hoffmann p->status, p->actual_length); 13342b2325ffSGerd Hoffmann return; 13352b2325ffSGerd Hoffmann default: 13362b2325ffSGerd Hoffmann p->status = USB_RET_STALL; 13372b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, p, 13382b2325ffSGerd Hoffmann p->status, p->actual_length); 13392b2325ffSGerd Hoffmann return; 13402b2325ffSGerd Hoffmann } 13412b2325ffSGerd Hoffmann 13422b2325ffSGerd Hoffmann rc = libusb_submit_transfer(r->xfer); 13432b2325ffSGerd Hoffmann if (rc != 0) { 13442b2325ffSGerd Hoffmann p->status = USB_RET_NODEV; 13452b2325ffSGerd Hoffmann trace_usb_host_req_complete(s->bus_num, s->addr, p, 13462b2325ffSGerd Hoffmann p->status, p->actual_length); 13472b2325ffSGerd Hoffmann if (rc == LIBUSB_ERROR_NO_DEVICE) { 13482b2325ffSGerd Hoffmann usb_host_nodev(s); 13492b2325ffSGerd Hoffmann } 13502b2325ffSGerd Hoffmann return; 13512b2325ffSGerd Hoffmann } 13522b2325ffSGerd Hoffmann 13532b2325ffSGerd Hoffmann p->status = USB_RET_ASYNC; 13542b2325ffSGerd Hoffmann } 13552b2325ffSGerd Hoffmann 13562b2325ffSGerd Hoffmann static void usb_host_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) 13572b2325ffSGerd Hoffmann { 13582b2325ffSGerd Hoffmann if (usb_host_use_combining(ep)) { 13592b2325ffSGerd Hoffmann usb_ep_combine_input_packets(ep); 13602b2325ffSGerd Hoffmann } 13612b2325ffSGerd Hoffmann } 13622b2325ffSGerd Hoffmann 13632b2325ffSGerd Hoffmann static void usb_host_handle_reset(USBDevice *udev) 13642b2325ffSGerd Hoffmann { 13652b2325ffSGerd Hoffmann USBHostDevice *s = USB_HOST_DEVICE(udev); 13665af35d7fSHans de Goede int rc; 13672b2325ffSGerd Hoffmann 13682b2325ffSGerd Hoffmann trace_usb_host_reset(s->bus_num, s->addr); 13692b2325ffSGerd Hoffmann 13705af35d7fSHans de Goede rc = libusb_reset_device(s->dh); 13715af35d7fSHans de Goede if (rc != 0) { 13725af35d7fSHans de Goede usb_host_nodev(s); 13732b2325ffSGerd Hoffmann } 13742b2325ffSGerd Hoffmann } 13752b2325ffSGerd Hoffmann 137656a9f180SHans de Goede static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps, 137756a9f180SHans de Goede int nr_eps, int streams) 137856a9f180SHans de Goede { 1379322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 138056a9f180SHans de Goede USBHostDevice *s = USB_HOST_DEVICE(udev); 138156a9f180SHans de Goede unsigned char endpoints[30]; 138256a9f180SHans de Goede int i, rc; 138356a9f180SHans de Goede 138456a9f180SHans de Goede for (i = 0; i < nr_eps; i++) { 138556a9f180SHans de Goede endpoints[i] = eps[i]->nr; 138656a9f180SHans de Goede if (eps[i]->pid == USB_TOKEN_IN) { 138756a9f180SHans de Goede endpoints[i] |= 0x80; 138856a9f180SHans de Goede } 138956a9f180SHans de Goede } 139056a9f180SHans de Goede rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps); 139156a9f180SHans de Goede if (rc < 0) { 139256a9f180SHans de Goede usb_host_libusb_error("libusb_alloc_streams", rc); 139356a9f180SHans de Goede } else if (rc != streams) { 13942e6a0dd1SGonglei error_report("libusb_alloc_streams: got less streams " 13952e6a0dd1SGonglei "then requested %d < %d", rc, streams); 139656a9f180SHans de Goede } 139756a9f180SHans de Goede 139856a9f180SHans de Goede return (rc == streams) ? 0 : -1; 139956a9f180SHans de Goede #else 14002e6a0dd1SGonglei error_report("libusb_alloc_streams: error not implemented"); 140156a9f180SHans de Goede return -1; 140256a9f180SHans de Goede #endif 140356a9f180SHans de Goede } 140456a9f180SHans de Goede 140556a9f180SHans de Goede static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps, 140656a9f180SHans de Goede int nr_eps) 140756a9f180SHans de Goede { 1408322fd1f4SGerd Hoffmann #ifdef HAVE_STREAMS 140956a9f180SHans de Goede USBHostDevice *s = USB_HOST_DEVICE(udev); 141056a9f180SHans de Goede unsigned char endpoints[30]; 141156a9f180SHans de Goede int i; 141256a9f180SHans de Goede 141356a9f180SHans de Goede for (i = 0; i < nr_eps; i++) { 141456a9f180SHans de Goede endpoints[i] = eps[i]->nr; 141556a9f180SHans de Goede if (eps[i]->pid == USB_TOKEN_IN) { 141656a9f180SHans de Goede endpoints[i] |= 0x80; 141756a9f180SHans de Goede } 141856a9f180SHans de Goede } 141956a9f180SHans de Goede libusb_free_streams(s->dh, endpoints, nr_eps); 142056a9f180SHans de Goede #endif 142156a9f180SHans de Goede } 142256a9f180SHans de Goede 142395efb20cSGerd Hoffmann /* 142495efb20cSGerd Hoffmann * This is *NOT* about restoring state. We have absolutely no idea 142595efb20cSGerd Hoffmann * what state the host device is in at the moment and whenever it is 142695efb20cSGerd Hoffmann * still present in the first place. Attemping to contine where we 142795efb20cSGerd Hoffmann * left off is impossible. 142895efb20cSGerd Hoffmann * 142995efb20cSGerd Hoffmann * What we are going to to to here is emulate a surprise removal of 143095efb20cSGerd Hoffmann * the usb device passed through, then kick host scan so the device 143195efb20cSGerd Hoffmann * will get re-attached (and re-initialized by the guest) in case it 143295efb20cSGerd Hoffmann * is still present. 143395efb20cSGerd Hoffmann * 143495efb20cSGerd Hoffmann * As the device removal will change the state of other devices (usb 143595efb20cSGerd Hoffmann * host controller, most likely interrupt controller too) we have to 143695efb20cSGerd Hoffmann * wait with it until *all* vmstate is loaded. Thus post_load just 143795efb20cSGerd Hoffmann * kicks a bottom half which then does the actual work. 143895efb20cSGerd Hoffmann */ 143995efb20cSGerd Hoffmann static void usb_host_post_load_bh(void *opaque) 144095efb20cSGerd Hoffmann { 144195efb20cSGerd Hoffmann USBHostDevice *dev = opaque; 144295efb20cSGerd Hoffmann USBDevice *udev = USB_DEVICE(dev); 144395efb20cSGerd Hoffmann 144495efb20cSGerd Hoffmann if (dev->dh != NULL) { 144595efb20cSGerd Hoffmann usb_host_close(dev); 144695efb20cSGerd Hoffmann } 144795efb20cSGerd Hoffmann if (udev->attached) { 144895efb20cSGerd Hoffmann usb_device_detach(udev); 144995efb20cSGerd Hoffmann } 145095efb20cSGerd Hoffmann usb_host_auto_check(NULL); 145195efb20cSGerd Hoffmann } 145295efb20cSGerd Hoffmann 145395efb20cSGerd Hoffmann static int usb_host_post_load(void *opaque, int version_id) 145495efb20cSGerd Hoffmann { 145595efb20cSGerd Hoffmann USBHostDevice *dev = opaque; 145695efb20cSGerd Hoffmann 145795efb20cSGerd Hoffmann if (!dev->bh_postld) { 145895efb20cSGerd Hoffmann dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev); 145995efb20cSGerd Hoffmann } 146095efb20cSGerd Hoffmann qemu_bh_schedule(dev->bh_postld); 146195efb20cSGerd Hoffmann return 0; 146295efb20cSGerd Hoffmann } 146395efb20cSGerd Hoffmann 14642b2325ffSGerd Hoffmann static const VMStateDescription vmstate_usb_host = { 14652b2325ffSGerd Hoffmann .name = "usb-host", 146695efb20cSGerd Hoffmann .version_id = 1, 146795efb20cSGerd Hoffmann .minimum_version_id = 1, 146895efb20cSGerd Hoffmann .post_load = usb_host_post_load, 14692b2325ffSGerd Hoffmann .fields = (VMStateField[]) { 14702b2325ffSGerd Hoffmann VMSTATE_USB_DEVICE(parent_obj, USBHostDevice), 14712b2325ffSGerd Hoffmann VMSTATE_END_OF_LIST() 14722b2325ffSGerd Hoffmann } 14732b2325ffSGerd Hoffmann }; 14742b2325ffSGerd Hoffmann 14752b2325ffSGerd Hoffmann static Property usb_host_dev_properties[] = { 14762b2325ffSGerd Hoffmann DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0), 14772b2325ffSGerd Hoffmann DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0), 14782b2325ffSGerd Hoffmann DEFINE_PROP_STRING("hostport", USBHostDevice, match.port), 1479c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32("vendorid", USBHostDevice, match.vendor_id, 0), 1480c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0), 14812b2325ffSGerd Hoffmann DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), 14822b2325ffSGerd Hoffmann DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32), 14832b2325ffSGerd Hoffmann DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel, 14842b2325ffSGerd Hoffmann LIBUSB_LOG_LEVEL_WARNING), 14852b2325ffSGerd Hoffmann DEFINE_PROP_BIT("pipeline", USBHostDevice, options, 14862b2325ffSGerd Hoffmann USB_HOST_OPT_PIPELINE, true), 14872b2325ffSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 14882b2325ffSGerd Hoffmann }; 14892b2325ffSGerd Hoffmann 14902b2325ffSGerd Hoffmann static void usb_host_class_initfn(ObjectClass *klass, void *data) 14912b2325ffSGerd Hoffmann { 14922b2325ffSGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 14932b2325ffSGerd Hoffmann USBDeviceClass *uc = USB_DEVICE_CLASS(klass); 14942b2325ffSGerd Hoffmann 14952aa76dc1SGonglei uc->realize = usb_host_realize; 14962b2325ffSGerd Hoffmann uc->product_desc = "USB Host Device"; 14972b2325ffSGerd Hoffmann uc->cancel_packet = usb_host_cancel_packet; 14982b2325ffSGerd Hoffmann uc->handle_data = usb_host_handle_data; 14992b2325ffSGerd Hoffmann uc->handle_control = usb_host_handle_control; 15002b2325ffSGerd Hoffmann uc->handle_reset = usb_host_handle_reset; 15012b2325ffSGerd Hoffmann uc->handle_destroy = usb_host_handle_destroy; 15022b2325ffSGerd Hoffmann uc->flush_ep_queue = usb_host_flush_ep_queue; 150356a9f180SHans de Goede uc->alloc_streams = usb_host_alloc_streams; 150456a9f180SHans de Goede uc->free_streams = usb_host_free_streams; 15052b2325ffSGerd Hoffmann dc->vmsd = &vmstate_usb_host; 15062b2325ffSGerd Hoffmann dc->props = usb_host_dev_properties; 1507125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 15082b2325ffSGerd Hoffmann } 15092b2325ffSGerd Hoffmann 15102b2325ffSGerd Hoffmann static TypeInfo usb_host_dev_info = { 15112b2325ffSGerd Hoffmann .name = TYPE_USB_HOST_DEVICE, 15122b2325ffSGerd Hoffmann .parent = TYPE_USB_DEVICE, 15132b2325ffSGerd Hoffmann .instance_size = sizeof(USBHostDevice), 15142b2325ffSGerd Hoffmann .class_init = usb_host_class_initfn, 1515e6adae52SGonglei .instance_init = usb_host_instance_init, 15162b2325ffSGerd Hoffmann }; 15172b2325ffSGerd Hoffmann 15182b2325ffSGerd Hoffmann static void usb_host_register_types(void) 15192b2325ffSGerd Hoffmann { 15202b2325ffSGerd Hoffmann type_register_static(&usb_host_dev_info); 15212b2325ffSGerd Hoffmann } 15222b2325ffSGerd Hoffmann 15232b2325ffSGerd Hoffmann type_init(usb_host_register_types) 15242b2325ffSGerd Hoffmann 15252b2325ffSGerd Hoffmann /* ------------------------------------------------------------------------ */ 15262b2325ffSGerd Hoffmann 15272b2325ffSGerd Hoffmann static QEMUTimer *usb_auto_timer; 15282b2325ffSGerd Hoffmann static VMChangeStateEntry *usb_vmstate; 15292b2325ffSGerd Hoffmann 15302b2325ffSGerd Hoffmann static void usb_host_vm_state(void *unused, int running, RunState state) 15312b2325ffSGerd Hoffmann { 15322b2325ffSGerd Hoffmann if (running) { 15332b2325ffSGerd Hoffmann usb_host_auto_check(unused); 15342b2325ffSGerd Hoffmann } 15352b2325ffSGerd Hoffmann } 15362b2325ffSGerd Hoffmann 15372b2325ffSGerd Hoffmann static void usb_host_auto_check(void *unused) 15382b2325ffSGerd Hoffmann { 15392b2325ffSGerd Hoffmann struct USBHostDevice *s; 15402b2325ffSGerd Hoffmann struct USBAutoFilter *f; 15413ce21445SJincheng Miao libusb_device **devs = NULL; 15422b2325ffSGerd Hoffmann struct libusb_device_descriptor ddesc; 15432b2325ffSGerd Hoffmann int unconnected = 0; 15442b2325ffSGerd Hoffmann int i, n; 15452b2325ffSGerd Hoffmann 15462b2325ffSGerd Hoffmann if (usb_host_init() != 0) { 15472b2325ffSGerd Hoffmann return; 15482b2325ffSGerd Hoffmann } 15492b2325ffSGerd Hoffmann 15502b2325ffSGerd Hoffmann if (runstate_is_running()) { 15512b2325ffSGerd Hoffmann n = libusb_get_device_list(ctx, &devs); 15522b2325ffSGerd Hoffmann for (i = 0; i < n; i++) { 15532b2325ffSGerd Hoffmann if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) { 15542b2325ffSGerd Hoffmann continue; 15552b2325ffSGerd Hoffmann } 15562b2325ffSGerd Hoffmann if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) { 15572b2325ffSGerd Hoffmann continue; 15582b2325ffSGerd Hoffmann } 15592b2325ffSGerd Hoffmann QTAILQ_FOREACH(s, &hostdevs, next) { 15602b2325ffSGerd Hoffmann f = &s->match; 15612b2325ffSGerd Hoffmann if (f->bus_num > 0 && 15622b2325ffSGerd Hoffmann f->bus_num != libusb_get_bus_number(devs[i])) { 15632b2325ffSGerd Hoffmann continue; 15642b2325ffSGerd Hoffmann } 15652b2325ffSGerd Hoffmann if (f->addr > 0 && 15662b2325ffSGerd Hoffmann f->addr != libusb_get_device_address(devs[i])) { 15672b2325ffSGerd Hoffmann continue; 15682b2325ffSGerd Hoffmann } 15692b2325ffSGerd Hoffmann if (f->port != NULL) { 15702b2325ffSGerd Hoffmann char port[16] = "-"; 15712b2325ffSGerd Hoffmann usb_host_get_port(devs[i], port, sizeof(port)); 15722b2325ffSGerd Hoffmann if (strcmp(f->port, port) != 0) { 15732b2325ffSGerd Hoffmann continue; 15742b2325ffSGerd Hoffmann } 15752b2325ffSGerd Hoffmann } 15762b2325ffSGerd Hoffmann if (f->vendor_id > 0 && 15772b2325ffSGerd Hoffmann f->vendor_id != ddesc.idVendor) { 15782b2325ffSGerd Hoffmann continue; 15792b2325ffSGerd Hoffmann } 15802b2325ffSGerd Hoffmann if (f->product_id > 0 && 15812b2325ffSGerd Hoffmann f->product_id != ddesc.idProduct) { 15822b2325ffSGerd Hoffmann continue; 15832b2325ffSGerd Hoffmann } 15842b2325ffSGerd Hoffmann 15852b2325ffSGerd Hoffmann /* We got a match */ 15862b2325ffSGerd Hoffmann s->seen++; 15872b2325ffSGerd Hoffmann if (s->errcount >= 3) { 15882b2325ffSGerd Hoffmann continue; 15892b2325ffSGerd Hoffmann } 15902b2325ffSGerd Hoffmann if (s->dh != NULL) { 15912b2325ffSGerd Hoffmann continue; 15922b2325ffSGerd Hoffmann } 15932b2325ffSGerd Hoffmann if (usb_host_open(s, devs[i]) < 0) { 15942b2325ffSGerd Hoffmann s->errcount++; 15952b2325ffSGerd Hoffmann continue; 15962b2325ffSGerd Hoffmann } 15972b2325ffSGerd Hoffmann break; 15982b2325ffSGerd Hoffmann } 15992b2325ffSGerd Hoffmann } 16002b2325ffSGerd Hoffmann libusb_free_device_list(devs, 1); 16012b2325ffSGerd Hoffmann 16022b2325ffSGerd Hoffmann QTAILQ_FOREACH(s, &hostdevs, next) { 16032b2325ffSGerd Hoffmann if (s->dh == NULL) { 16042b2325ffSGerd Hoffmann unconnected++; 16052b2325ffSGerd Hoffmann } 16062b2325ffSGerd Hoffmann if (s->seen == 0) { 16072b2325ffSGerd Hoffmann if (s->dh) { 16082b2325ffSGerd Hoffmann usb_host_close(s); 16092b2325ffSGerd Hoffmann } 16102b2325ffSGerd Hoffmann s->errcount = 0; 16112b2325ffSGerd Hoffmann } 16122b2325ffSGerd Hoffmann s->seen = 0; 16132b2325ffSGerd Hoffmann } 16142b2325ffSGerd Hoffmann 16152b2325ffSGerd Hoffmann #if 0 16162b2325ffSGerd Hoffmann if (unconnected == 0) { 16172b2325ffSGerd Hoffmann /* nothing to watch */ 16182b2325ffSGerd Hoffmann if (usb_auto_timer) { 1619bc72ad67SAlex Bligh timer_del(usb_auto_timer); 16202b2325ffSGerd Hoffmann trace_usb_host_auto_scan_disabled(); 16212b2325ffSGerd Hoffmann } 16222b2325ffSGerd Hoffmann return; 16232b2325ffSGerd Hoffmann } 16242b2325ffSGerd Hoffmann #endif 16252b2325ffSGerd Hoffmann } 16262b2325ffSGerd Hoffmann 16272b2325ffSGerd Hoffmann if (!usb_vmstate) { 16282b2325ffSGerd Hoffmann usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); 16292b2325ffSGerd Hoffmann } 16302b2325ffSGerd Hoffmann if (!usb_auto_timer) { 1631bc72ad67SAlex Bligh usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL); 16322b2325ffSGerd Hoffmann if (!usb_auto_timer) { 16332b2325ffSGerd Hoffmann return; 16342b2325ffSGerd Hoffmann } 16352b2325ffSGerd Hoffmann trace_usb_host_auto_scan_enabled(); 16362b2325ffSGerd Hoffmann } 1637bc72ad67SAlex Bligh timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000); 16382b2325ffSGerd Hoffmann } 16392b2325ffSGerd Hoffmann 16402b2325ffSGerd Hoffmann void usb_host_info(Monitor *mon, const QDict *qdict) 16412b2325ffSGerd Hoffmann { 16423ce21445SJincheng Miao libusb_device **devs = NULL; 16432b2325ffSGerd Hoffmann struct libusb_device_descriptor ddesc; 16442b2325ffSGerd Hoffmann char port[16]; 16452b2325ffSGerd Hoffmann int i, n; 16462b2325ffSGerd Hoffmann 16472b2325ffSGerd Hoffmann if (usb_host_init() != 0) { 16482b2325ffSGerd Hoffmann return; 16492b2325ffSGerd Hoffmann } 16502b2325ffSGerd Hoffmann 16512b2325ffSGerd Hoffmann n = libusb_get_device_list(ctx, &devs); 16522b2325ffSGerd Hoffmann for (i = 0; i < n; i++) { 16532b2325ffSGerd Hoffmann if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) { 16542b2325ffSGerd Hoffmann continue; 16552b2325ffSGerd Hoffmann } 16562b2325ffSGerd Hoffmann if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) { 16572b2325ffSGerd Hoffmann continue; 16582b2325ffSGerd Hoffmann } 16592b2325ffSGerd Hoffmann usb_host_get_port(devs[i], port, sizeof(port)); 16602b2325ffSGerd Hoffmann monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n", 16612b2325ffSGerd Hoffmann libusb_get_bus_number(devs[i]), 16622b2325ffSGerd Hoffmann libusb_get_device_address(devs[i]), 16632b2325ffSGerd Hoffmann port, 16642b2325ffSGerd Hoffmann speed_name[libusb_get_device_speed(devs[i])]); 16652b2325ffSGerd Hoffmann monitor_printf(mon, " Class %02x:", ddesc.bDeviceClass); 16662b2325ffSGerd Hoffmann monitor_printf(mon, " USB device %04x:%04x", 16672b2325ffSGerd Hoffmann ddesc.idVendor, ddesc.idProduct); 16682b2325ffSGerd Hoffmann if (ddesc.iProduct) { 16692b2325ffSGerd Hoffmann libusb_device_handle *handle; 16702b2325ffSGerd Hoffmann if (libusb_open(devs[i], &handle) == 0) { 16712b2325ffSGerd Hoffmann unsigned char name[64] = ""; 16722b2325ffSGerd Hoffmann libusb_get_string_descriptor_ascii(handle, 16732b2325ffSGerd Hoffmann ddesc.iProduct, 16742b2325ffSGerd Hoffmann name, sizeof(name)); 16752b2325ffSGerd Hoffmann libusb_close(handle); 16762b2325ffSGerd Hoffmann monitor_printf(mon, ", %s", name); 16772b2325ffSGerd Hoffmann } 16782b2325ffSGerd Hoffmann } 16792b2325ffSGerd Hoffmann monitor_printf(mon, "\n"); 16802b2325ffSGerd Hoffmann } 16812b2325ffSGerd Hoffmann libusb_free_device_list(devs, 1); 16822b2325ffSGerd Hoffmann } 1683