|
|
1.1 ! root 1: /* ! 2: * Linux host USB redirector ! 3: * ! 4: * Copyright (c) 2005 Fabrice Bellard ! 5: * ! 6: * Copyright (c) 2008 Max Krasnyansky ! 7: * Support for host device auto connect & disconnect ! 8: * Major rewrite to support fully async operation ! 9: * ! 10: * Copyright 2008 TJ <[email protected]> ! 11: * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition ! 12: * to the legacy /proc/bus/usb USB device discovery and handling ! 13: * ! 14: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 15: * of this software and associated documentation files (the "Software"), to deal ! 16: * in the Software without restriction, including without limitation the rights ! 17: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 18: * copies of the Software, and to permit persons to whom the Software is ! 19: * furnished to do so, subject to the following conditions: ! 20: * ! 21: * The above copyright notice and this permission notice shall be included in ! 22: * all copies or substantial portions of the Software. ! 23: * ! 24: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 25: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 26: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 27: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 28: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 29: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 30: * THE SOFTWARE. ! 31: */ ! 32: ! 33: #include "qemu-common.h" ! 34: #include "qemu-timer.h" ! 35: #include "monitor.h" ! 36: #include "sysemu.h" ! 37: #include "trace.h" ! 38: ! 39: #include <dirent.h> ! 40: #include <sys/ioctl.h> ! 41: ! 42: #include <linux/usbdevice_fs.h> ! 43: #include <linux/version.h> ! 44: #include "hw/usb.h" ! 45: #include "hw/usb/desc.h" ! 46: ! 47: /* We redefine it to avoid version problems */ ! 48: struct usb_ctrltransfer { ! 49: uint8_t bRequestType; ! 50: uint8_t bRequest; ! 51: uint16_t wValue; ! 52: uint16_t wIndex; ! 53: uint16_t wLength; ! 54: uint32_t timeout; ! 55: void *data; ! 56: }; ! 57: ! 58: typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port, ! 59: int class_id, int vendor_id, int product_id, ! 60: const char *product_name, int speed); ! 61: ! 62: //#define DEBUG ! 63: ! 64: #ifdef DEBUG ! 65: #define DPRINTF printf ! 66: #else ! 67: #define DPRINTF(...) ! 68: #endif ! 69: ! 70: #define PRODUCT_NAME_SZ 32 ! 71: #define MAX_PORTLEN 16 ! 72: ! 73: /* endpoint association data */ ! 74: #define ISO_FRAME_DESC_PER_URB 32 ! 75: ! 76: /* devio.c limits single requests to 16k */ ! 77: #define MAX_USBFS_BUFFER_SIZE 16384 ! 78: ! 79: typedef struct AsyncURB AsyncURB; ! 80: ! 81: struct endp_data { ! 82: uint8_t halted; ! 83: uint8_t iso_started; ! 84: AsyncURB *iso_urb; ! 85: int iso_urb_idx; ! 86: int iso_buffer_used; ! 87: int inflight; ! 88: }; ! 89: ! 90: struct USBAutoFilter { ! 91: uint32_t bus_num; ! 92: uint32_t addr; ! 93: char *port; ! 94: uint32_t vendor_id; ! 95: uint32_t product_id; ! 96: }; ! 97: ! 98: enum USBHostDeviceOptions { ! 99: USB_HOST_OPT_PIPELINE, ! 100: }; ! 101: ! 102: typedef struct USBHostDevice { ! 103: USBDevice dev; ! 104: int fd; ! 105: int hub_fd; ! 106: int hub_port; ! 107: ! 108: uint8_t descr[8192]; ! 109: int descr_len; ! 110: int closing; ! 111: uint32_t iso_urb_count; ! 112: uint32_t options; ! 113: Notifier exit; ! 114: ! 115: struct endp_data ep_in[USB_MAX_ENDPOINTS]; ! 116: struct endp_data ep_out[USB_MAX_ENDPOINTS]; ! 117: QLIST_HEAD(, AsyncURB) aurbs; ! 118: ! 119: /* Host side address */ ! 120: int bus_num; ! 121: int addr; ! 122: char port[MAX_PORTLEN]; ! 123: struct USBAutoFilter match; ! 124: int32_t bootindex; ! 125: int seen, errcount; ! 126: ! 127: QTAILQ_ENTRY(USBHostDevice) next; ! 128: } USBHostDevice; ! 129: ! 130: static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs); ! 131: ! 132: static int usb_host_close(USBHostDevice *dev); ! 133: static int parse_filter(const char *spec, struct USBAutoFilter *f); ! 134: static void usb_host_auto_check(void *unused); ! 135: static int usb_host_read_file(char *line, size_t line_size, ! 136: const char *device_file, const char *device_name); ! 137: static int usb_linux_update_endp_table(USBHostDevice *s); ! 138: ! 139: static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p) ! 140: { ! 141: static const int usbfs[] = { ! 142: [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL, ! 143: [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO, ! 144: [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK, ! 145: [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT, ! 146: }; ! 147: uint8_t type = p->ep->type; ! 148: assert(type < ARRAY_SIZE(usbfs)); ! 149: return usbfs[type]; ! 150: } ! 151: ! 152: static int usb_host_do_reset(USBHostDevice *dev) ! 153: { ! 154: struct timeval s, e; ! 155: uint32_t usecs; ! 156: int ret; ! 157: ! 158: gettimeofday(&s, NULL); ! 159: ret = ioctl(dev->fd, USBDEVFS_RESET); ! 160: gettimeofday(&e, NULL); ! 161: usecs = (e.tv_sec - s.tv_sec) * 1000000; ! 162: usecs += e.tv_usec - s.tv_usec; ! 163: if (usecs > 1000000) { ! 164: /* more than a second, something is fishy, broken usb device? */ ! 165: fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n", ! 166: dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000); ! 167: } ! 168: return ret; ! 169: } ! 170: ! 171: static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep) ! 172: { ! 173: struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out; ! 174: assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT); ! 175: assert(ep > 0 && ep <= USB_MAX_ENDPOINTS); ! 176: return eps + ep - 1; ! 177: } ! 178: ! 179: static int is_isoc(USBHostDevice *s, int pid, int ep) ! 180: { ! 181: return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC; ! 182: } ! 183: ! 184: static int is_valid(USBHostDevice *s, int pid, int ep) ! 185: { ! 186: return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID; ! 187: } ! 188: ! 189: static int is_halted(USBHostDevice *s, int pid, int ep) ! 190: { ! 191: return get_endp(s, pid, ep)->halted; ! 192: } ! 193: ! 194: static void clear_halt(USBHostDevice *s, int pid, int ep) ! 195: { ! 196: trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep); ! 197: get_endp(s, pid, ep)->halted = 0; ! 198: } ! 199: ! 200: static void set_halt(USBHostDevice *s, int pid, int ep) ! 201: { ! 202: if (ep != 0) { ! 203: trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep); ! 204: get_endp(s, pid, ep)->halted = 1; ! 205: } ! 206: } ! 207: ! 208: static int is_iso_started(USBHostDevice *s, int pid, int ep) ! 209: { ! 210: return get_endp(s, pid, ep)->iso_started; ! 211: } ! 212: ! 213: static void clear_iso_started(USBHostDevice *s, int pid, int ep) ! 214: { ! 215: trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep); ! 216: get_endp(s, pid, ep)->iso_started = 0; ! 217: } ! 218: ! 219: static void set_iso_started(USBHostDevice *s, int pid, int ep) ! 220: { ! 221: struct endp_data *e = get_endp(s, pid, ep); ! 222: ! 223: trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep); ! 224: if (!e->iso_started) { ! 225: e->iso_started = 1; ! 226: e->inflight = 0; ! 227: } ! 228: } ! 229: ! 230: static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value) ! 231: { ! 232: struct endp_data *e = get_endp(s, pid, ep); ! 233: ! 234: e->inflight += value; ! 235: return e->inflight; ! 236: } ! 237: ! 238: static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb) ! 239: { ! 240: get_endp(s, pid, ep)->iso_urb = iso_urb; ! 241: } ! 242: ! 243: static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep) ! 244: { ! 245: return get_endp(s, pid, ep)->iso_urb; ! 246: } ! 247: ! 248: static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i) ! 249: { ! 250: get_endp(s, pid, ep)->iso_urb_idx = i; ! 251: } ! 252: ! 253: static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep) ! 254: { ! 255: return get_endp(s, pid, ep)->iso_urb_idx; ! 256: } ! 257: ! 258: static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i) ! 259: { ! 260: get_endp(s, pid, ep)->iso_buffer_used = i; ! 261: } ! 262: ! 263: static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep) ! 264: { ! 265: return get_endp(s, pid, ep)->iso_buffer_used; ! 266: } ! 267: ! 268: /* ! 269: * Async URB state. ! 270: * We always allocate iso packet descriptors even for bulk transfers ! 271: * to simplify allocation and casts. ! 272: */ ! 273: struct AsyncURB ! 274: { ! 275: struct usbdevfs_urb urb; ! 276: struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB]; ! 277: USBHostDevice *hdev; ! 278: QLIST_ENTRY(AsyncURB) next; ! 279: ! 280: /* For regular async urbs */ ! 281: USBPacket *packet; ! 282: int more; /* large transfer, more urbs follow */ ! 283: ! 284: /* For buffered iso handling */ ! 285: int iso_frame_idx; /* -1 means in flight */ ! 286: }; ! 287: ! 288: static AsyncURB *async_alloc(USBHostDevice *s) ! 289: { ! 290: AsyncURB *aurb = g_malloc0(sizeof(AsyncURB)); ! 291: aurb->hdev = s; ! 292: QLIST_INSERT_HEAD(&s->aurbs, aurb, next); ! 293: return aurb; ! 294: } ! 295: ! 296: static void async_free(AsyncURB *aurb) ! 297: { ! 298: QLIST_REMOVE(aurb, next); ! 299: g_free(aurb); ! 300: } ! 301: ! 302: static void do_disconnect(USBHostDevice *s) ! 303: { ! 304: usb_host_close(s); ! 305: usb_host_auto_check(NULL); ! 306: } ! 307: ! 308: static void async_complete(void *opaque) ! 309: { ! 310: USBHostDevice *s = opaque; ! 311: AsyncURB *aurb; ! 312: int urbs = 0; ! 313: ! 314: while (1) { ! 315: USBPacket *p; ! 316: ! 317: int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb); ! 318: if (r < 0) { ! 319: if (errno == EAGAIN) { ! 320: if (urbs > 2) { ! 321: fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs); ! 322: } ! 323: return; ! 324: } ! 325: if (errno == ENODEV) { ! 326: if (!s->closing) { ! 327: trace_usb_host_disconnect(s->bus_num, s->addr); ! 328: do_disconnect(s); ! 329: } ! 330: return; ! 331: } ! 332: ! 333: perror("USBDEVFS_REAPURBNDELAY"); ! 334: return; ! 335: } ! 336: ! 337: DPRINTF("husb: async completed. aurb %p status %d alen %d\n", ! 338: aurb, aurb->urb.status, aurb->urb.actual_length); ! 339: ! 340: /* If this is a buffered iso urb mark it as complete and don't do ! 341: anything else (it is handled further in usb_host_handle_iso_data) */ ! 342: if (aurb->iso_frame_idx == -1) { ! 343: int inflight; ! 344: int pid = (aurb->urb.endpoint & USB_DIR_IN) ? ! 345: USB_TOKEN_IN : USB_TOKEN_OUT; ! 346: int ep = aurb->urb.endpoint & 0xf; ! 347: if (aurb->urb.status == -EPIPE) { ! 348: set_halt(s, pid, ep); ! 349: } ! 350: aurb->iso_frame_idx = 0; ! 351: urbs++; ! 352: inflight = change_iso_inflight(s, pid, ep, -1); ! 353: if (inflight == 0 && is_iso_started(s, pid, ep)) { ! 354: fprintf(stderr, "husb: out of buffers for iso stream\n"); ! 355: } ! 356: continue; ! 357: } ! 358: ! 359: p = aurb->packet; ! 360: trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status, ! 361: aurb->urb.actual_length, aurb->more); ! 362: ! 363: if (p) { ! 364: switch (aurb->urb.status) { ! 365: case 0: ! 366: p->result += aurb->urb.actual_length; ! 367: break; ! 368: ! 369: case -EPIPE: ! 370: set_halt(s, p->pid, p->ep->nr); ! 371: p->result = USB_RET_STALL; ! 372: break; ! 373: ! 374: case -EOVERFLOW: ! 375: p->result = USB_RET_BABBLE; ! 376: break; ! 377: ! 378: default: ! 379: p->result = USB_RET_IOERROR; ! 380: break; ! 381: } ! 382: ! 383: if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { ! 384: trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); ! 385: usb_generic_async_ctrl_complete(&s->dev, p); ! 386: } else if (!aurb->more) { ! 387: trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); ! 388: usb_packet_complete(&s->dev, p); ! 389: } ! 390: } ! 391: ! 392: async_free(aurb); ! 393: } ! 394: } ! 395: ! 396: static void usb_host_async_cancel(USBDevice *dev, USBPacket *p) ! 397: { ! 398: USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); ! 399: AsyncURB *aurb; ! 400: ! 401: trace_usb_host_req_canceled(s->bus_num, s->addr, p); ! 402: ! 403: QLIST_FOREACH(aurb, &s->aurbs, next) { ! 404: if (p != aurb->packet) { ! 405: continue; ! 406: } ! 407: ! 408: trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb); ! 409: ! 410: /* Mark it as dead (see async_complete above) */ ! 411: aurb->packet = NULL; ! 412: ! 413: int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb); ! 414: if (r < 0) { ! 415: DPRINTF("husb: async. discard urb failed errno %d\n", errno); ! 416: } ! 417: } ! 418: } ! 419: ! 420: static int usb_host_open_device(int bus, int addr) ! 421: { ! 422: const char *usbfs = NULL; ! 423: char filename[32]; ! 424: struct stat st; ! 425: int fd, rc; ! 426: ! 427: rc = stat("/dev/bus/usb", &st); ! 428: if (rc == 0 && S_ISDIR(st.st_mode)) { ! 429: /* udev-created device nodes available */ ! 430: usbfs = "/dev/bus/usb"; ! 431: } else { ! 432: /* fallback: usbfs mounted below /proc */ ! 433: usbfs = "/proc/bus/usb"; ! 434: } ! 435: ! 436: snprintf(filename, sizeof(filename), "%s/%03d/%03d", ! 437: usbfs, bus, addr); ! 438: fd = open(filename, O_RDWR | O_NONBLOCK); ! 439: if (fd < 0) { ! 440: fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno)); ! 441: } ! 442: return fd; ! 443: } ! 444: ! 445: static int usb_host_claim_port(USBHostDevice *s) ! 446: { ! 447: #ifdef USBDEVFS_CLAIM_PORT ! 448: char *h, hub_name[64], line[1024]; ! 449: int hub_addr, ret; ! 450: ! 451: snprintf(hub_name, sizeof(hub_name), "%d-%s", ! 452: s->match.bus_num, s->match.port); ! 453: ! 454: /* try strip off last ".$portnr" to get hub */ ! 455: h = strrchr(hub_name, '.'); ! 456: if (h != NULL) { ! 457: s->hub_port = atoi(h+1); ! 458: *h = '\0'; ! 459: } else { ! 460: /* no dot in there -> it is the root hub */ ! 461: snprintf(hub_name, sizeof(hub_name), "usb%d", ! 462: s->match.bus_num); ! 463: s->hub_port = atoi(s->match.port); ! 464: } ! 465: ! 466: if (!usb_host_read_file(line, sizeof(line), "devnum", ! 467: hub_name)) { ! 468: return -1; ! 469: } ! 470: if (sscanf(line, "%d", &hub_addr) != 1) { ! 471: return -1; ! 472: } ! 473: ! 474: s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr); ! 475: if (s->hub_fd < 0) { ! 476: return -1; ! 477: } ! 478: ! 479: ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port); ! 480: if (ret < 0) { ! 481: close(s->hub_fd); ! 482: s->hub_fd = -1; ! 483: return -1; ! 484: } ! 485: ! 486: trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port); ! 487: return 0; ! 488: #else ! 489: return -1; ! 490: #endif ! 491: } ! 492: ! 493: static void usb_host_release_port(USBHostDevice *s) ! 494: { ! 495: if (s->hub_fd == -1) { ! 496: return; ! 497: } ! 498: #ifdef USBDEVFS_RELEASE_PORT ! 499: ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port); ! 500: #endif ! 501: close(s->hub_fd); ! 502: s->hub_fd = -1; ! 503: } ! 504: ! 505: static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces) ! 506: { ! 507: /* earlier Linux 2.4 do not support that */ ! 508: #ifdef USBDEVFS_DISCONNECT ! 509: struct usbdevfs_ioctl ctrl; ! 510: int ret, interface; ! 511: ! 512: for (interface = 0; interface < nb_interfaces; interface++) { ! 513: ctrl.ioctl_code = USBDEVFS_DISCONNECT; ! 514: ctrl.ifno = interface; ! 515: ctrl.data = 0; ! 516: ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl); ! 517: if (ret < 0 && errno != ENODATA) { ! 518: perror("USBDEVFS_DISCONNECT"); ! 519: return -1; ! 520: } ! 521: } ! 522: #endif ! 523: return 0; ! 524: } ! 525: ! 526: static int usb_linux_get_num_interfaces(USBHostDevice *s) ! 527: { ! 528: char device_name[64], line[1024]; ! 529: int num_interfaces = 0; ! 530: ! 531: sprintf(device_name, "%d-%s", s->bus_num, s->port); ! 532: if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces", ! 533: device_name)) { ! 534: return -1; ! 535: } ! 536: if (sscanf(line, "%d", &num_interfaces) != 1) { ! 537: return -1; ! 538: } ! 539: return num_interfaces; ! 540: } ! 541: ! 542: static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) ! 543: { ! 544: const char *op = NULL; ! 545: int dev_descr_len, config_descr_len; ! 546: int interface, nb_interfaces; ! 547: int ret, i; ! 548: ! 549: for (i = 0; i < USB_MAX_INTERFACES; i++) { ! 550: dev->dev.altsetting[i] = 0; ! 551: } ! 552: ! 553: if (configuration == 0) { /* address state - ignore */ ! 554: dev->dev.ninterfaces = 0; ! 555: dev->dev.configuration = 0; ! 556: return 1; ! 557: } ! 558: ! 559: DPRINTF("husb: claiming interfaces. config %d\n", configuration); ! 560: ! 561: i = 0; ! 562: dev_descr_len = dev->descr[0]; ! 563: if (dev_descr_len > dev->descr_len) { ! 564: fprintf(stderr, "husb: update iface failed. descr too short\n"); ! 565: return 0; ! 566: } ! 567: ! 568: i += dev_descr_len; ! 569: while (i < dev->descr_len) { ! 570: DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n", ! 571: i, dev->descr_len, ! 572: dev->descr[i], dev->descr[i+1]); ! 573: ! 574: if (dev->descr[i+1] != USB_DT_CONFIG) { ! 575: i += dev->descr[i]; ! 576: continue; ! 577: } ! 578: config_descr_len = dev->descr[i]; ! 579: ! 580: DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration); ! 581: ! 582: if (configuration == dev->descr[i + 5]) { ! 583: configuration = dev->descr[i + 5]; ! 584: break; ! 585: } ! 586: ! 587: i += config_descr_len; ! 588: } ! 589: ! 590: if (i >= dev->descr_len) { ! 591: fprintf(stderr, ! 592: "husb: update iface failed. no matching configuration\n"); ! 593: return 0; ! 594: } ! 595: nb_interfaces = dev->descr[i + 4]; ! 596: ! 597: if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) { ! 598: goto fail; ! 599: } ! 600: ! 601: /* XXX: only grab if all interfaces are free */ ! 602: for (interface = 0; interface < nb_interfaces; interface++) { ! 603: op = "USBDEVFS_CLAIMINTERFACE"; ! 604: ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface); ! 605: if (ret < 0) { ! 606: goto fail; ! 607: } ! 608: } ! 609: ! 610: trace_usb_host_claim_interfaces(dev->bus_num, dev->addr, ! 611: nb_interfaces, configuration); ! 612: ! 613: dev->dev.ninterfaces = nb_interfaces; ! 614: dev->dev.configuration = configuration; ! 615: return 1; ! 616: ! 617: fail: ! 618: if (errno == ENODEV) { ! 619: do_disconnect(dev); ! 620: } ! 621: perror(op); ! 622: return 0; ! 623: } ! 624: ! 625: static int usb_host_release_interfaces(USBHostDevice *s) ! 626: { ! 627: int ret, i; ! 628: ! 629: trace_usb_host_release_interfaces(s->bus_num, s->addr); ! 630: ! 631: for (i = 0; i < s->dev.ninterfaces; i++) { ! 632: ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i); ! 633: if (ret < 0) { ! 634: perror("USBDEVFS_RELEASEINTERFACE"); ! 635: return 0; ! 636: } ! 637: } ! 638: return 1; ! 639: } ! 640: ! 641: static void usb_host_handle_reset(USBDevice *dev) ! 642: { ! 643: USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); ! 644: ! 645: trace_usb_host_reset(s->bus_num, s->addr); ! 646: ! 647: usb_host_do_reset(s);; ! 648: ! 649: usb_host_claim_interfaces(s, 0); ! 650: usb_linux_update_endp_table(s); ! 651: } ! 652: ! 653: static void usb_host_handle_destroy(USBDevice *dev) ! 654: { ! 655: USBHostDevice *s = (USBHostDevice *)dev; ! 656: ! 657: usb_host_release_port(s); ! 658: usb_host_close(s); ! 659: QTAILQ_REMOVE(&hostdevs, s, next); ! 660: qemu_remove_exit_notifier(&s->exit); ! 661: } ! 662: ! 663: /* iso data is special, we need to keep enough urbs in flight to make sure ! 664: that the controller never runs out of them, otherwise the device will ! 665: likely suffer a buffer underrun / overrun. */ ! 666: static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep) ! 667: { ! 668: AsyncURB *aurb; ! 669: int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep); ! 670: ! 671: aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb)); ! 672: for (i = 0; i < s->iso_urb_count; i++) { ! 673: aurb[i].urb.endpoint = ep; ! 674: aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len; ! 675: aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length); ! 676: aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO; ! 677: aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP; ! 678: aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB; ! 679: for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++) ! 680: aurb[i].urb.iso_frame_desc[j].length = len; ! 681: if (pid == USB_TOKEN_IN) { ! 682: aurb[i].urb.endpoint |= 0x80; ! 683: /* Mark as fully consumed (idle) */ ! 684: aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB; ! 685: } ! 686: } ! 687: set_iso_urb(s, pid, ep, aurb); ! 688: ! 689: return aurb; ! 690: } ! 691: ! 692: static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep) ! 693: { ! 694: AsyncURB *aurb; ! 695: int i, ret, killed = 0, free = 1; ! 696: ! 697: aurb = get_iso_urb(s, pid, ep); ! 698: if (!aurb) { ! 699: return; ! 700: } ! 701: ! 702: for (i = 0; i < s->iso_urb_count; i++) { ! 703: /* in flight? */ ! 704: if (aurb[i].iso_frame_idx == -1) { ! 705: ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]); ! 706: if (ret < 0) { ! 707: perror("USBDEVFS_DISCARDURB"); ! 708: free = 0; ! 709: continue; ! 710: } ! 711: killed++; ! 712: } ! 713: } ! 714: ! 715: /* Make sure any urbs we've killed are reaped before we free them */ ! 716: if (killed) { ! 717: async_complete(s); ! 718: } ! 719: ! 720: for (i = 0; i < s->iso_urb_count; i++) { ! 721: g_free(aurb[i].urb.buffer); ! 722: } ! 723: ! 724: if (free) ! 725: g_free(aurb); ! 726: else ! 727: printf("husb: leaking iso urbs because of discard failure\n"); ! 728: set_iso_urb(s, pid, ep, NULL); ! 729: set_iso_urb_idx(s, pid, ep, 0); ! 730: clear_iso_started(s, pid, ep); ! 731: } ! 732: ! 733: static int urb_status_to_usb_ret(int status) ! 734: { ! 735: switch (status) { ! 736: case -EPIPE: ! 737: return USB_RET_STALL; ! 738: case -EOVERFLOW: ! 739: return USB_RET_BABBLE; ! 740: default: ! 741: return USB_RET_IOERROR; ! 742: } ! 743: } ! 744: ! 745: static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) ! 746: { ! 747: AsyncURB *aurb; ! 748: int i, j, ret, max_packet_size, offset, len = 0; ! 749: uint8_t *buf; ! 750: ! 751: max_packet_size = p->ep->max_packet_size; ! 752: if (max_packet_size == 0) ! 753: return USB_RET_NAK; ! 754: ! 755: aurb = get_iso_urb(s, p->pid, p->ep->nr); ! 756: if (!aurb) { ! 757: aurb = usb_host_alloc_iso(s, p->pid, p->ep->nr); ! 758: } ! 759: ! 760: i = get_iso_urb_idx(s, p->pid, p->ep->nr); ! 761: j = aurb[i].iso_frame_idx; ! 762: if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) { ! 763: if (in) { ! 764: /* Check urb status */ ! 765: if (aurb[i].urb.status) { ! 766: len = urb_status_to_usb_ret(aurb[i].urb.status); ! 767: /* Move to the next urb */ ! 768: aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1; ! 769: /* Check frame status */ ! 770: } else if (aurb[i].urb.iso_frame_desc[j].status) { ! 771: len = urb_status_to_usb_ret( ! 772: aurb[i].urb.iso_frame_desc[j].status); ! 773: /* Check the frame fits */ ! 774: } else if (aurb[i].urb.iso_frame_desc[j].actual_length ! 775: > p->iov.size) { ! 776: printf("husb: received iso data is larger then packet\n"); ! 777: len = USB_RET_BABBLE; ! 778: /* All good copy data over */ ! 779: } else { ! 780: len = aurb[i].urb.iso_frame_desc[j].actual_length; ! 781: buf = aurb[i].urb.buffer + ! 782: j * aurb[i].urb.iso_frame_desc[0].length; ! 783: usb_packet_copy(p, buf, len); ! 784: } ! 785: } else { ! 786: len = p->iov.size; ! 787: offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->ep->nr); ! 788: ! 789: /* Check the frame fits */ ! 790: if (len > max_packet_size) { ! 791: printf("husb: send iso data is larger then max packet size\n"); ! 792: return USB_RET_NAK; ! 793: } ! 794: ! 795: /* All good copy data over */ ! 796: usb_packet_copy(p, aurb[i].urb.buffer + offset, len); ! 797: aurb[i].urb.iso_frame_desc[j].length = len; ! 798: offset += len; ! 799: set_iso_buffer_used(s, p->pid, p->ep->nr, offset); ! 800: ! 801: /* Start the stream once we have buffered enough data */ ! 802: if (!is_iso_started(s, p->pid, p->ep->nr) && i == 1 && j == 8) { ! 803: set_iso_started(s, p->pid, p->ep->nr); ! 804: } ! 805: } ! 806: aurb[i].iso_frame_idx++; ! 807: if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { ! 808: i = (i + 1) % s->iso_urb_count; ! 809: set_iso_urb_idx(s, p->pid, p->ep->nr, i); ! 810: } ! 811: } else { ! 812: if (in) { ! 813: set_iso_started(s, p->pid, p->ep->nr); ! 814: } else { ! 815: DPRINTF("hubs: iso out error no free buffer, dropping packet\n"); ! 816: } ! 817: } ! 818: ! 819: if (is_iso_started(s, p->pid, p->ep->nr)) { ! 820: /* (Re)-submit all fully consumed / filled urbs */ ! 821: for (i = 0; i < s->iso_urb_count; i++) { ! 822: if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { ! 823: ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]); ! 824: if (ret < 0) { ! 825: perror("USBDEVFS_SUBMITURB"); ! 826: if (!in || len == 0) { ! 827: switch(errno) { ! 828: case ETIMEDOUT: ! 829: len = USB_RET_NAK; ! 830: break; ! 831: case EPIPE: ! 832: default: ! 833: len = USB_RET_STALL; ! 834: } ! 835: } ! 836: break; ! 837: } ! 838: aurb[i].iso_frame_idx = -1; ! 839: change_iso_inflight(s, p->pid, p->ep->nr, 1); ! 840: } ! 841: } ! 842: } ! 843: ! 844: return len; ! 845: } ! 846: ! 847: static int usb_host_handle_data(USBDevice *dev, USBPacket *p) ! 848: { ! 849: USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); ! 850: struct usbdevfs_urb *urb; ! 851: AsyncURB *aurb; ! 852: int ret, rem, prem, v; ! 853: uint8_t *pbuf; ! 854: uint8_t ep; ! 855: ! 856: trace_usb_host_req_data(s->bus_num, s->addr, p, ! 857: p->pid == USB_TOKEN_IN, ! 858: p->ep->nr, p->iov.size); ! 859: ! 860: if (!is_valid(s, p->pid, p->ep->nr)) { ! 861: trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); ! 862: return USB_RET_NAK; ! 863: } ! 864: ! 865: if (p->pid == USB_TOKEN_IN) { ! 866: ep = p->ep->nr | 0x80; ! 867: } else { ! 868: ep = p->ep->nr; ! 869: } ! 870: ! 871: if (is_halted(s, p->pid, p->ep->nr)) { ! 872: unsigned int arg = ep; ! 873: ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg); ! 874: if (ret < 0) { ! 875: perror("USBDEVFS_CLEAR_HALT"); ! 876: trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); ! 877: return USB_RET_NAK; ! 878: } ! 879: clear_halt(s, p->pid, p->ep->nr); ! 880: } ! 881: ! 882: if (is_isoc(s, p->pid, p->ep->nr)) { ! 883: return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); ! 884: } ! 885: ! 886: v = 0; ! 887: prem = 0; ! 888: pbuf = NULL; ! 889: rem = p->iov.size; ! 890: do { ! 891: if (prem == 0 && rem > 0) { ! 892: assert(v < p->iov.niov); ! 893: prem = p->iov.iov[v].iov_len; ! 894: pbuf = p->iov.iov[v].iov_base; ! 895: assert(prem <= rem); ! 896: v++; ! 897: } ! 898: aurb = async_alloc(s); ! 899: aurb->packet = p; ! 900: ! 901: urb = &aurb->urb; ! 902: urb->endpoint = ep; ! 903: urb->type = usb_host_usbfs_type(s, p); ! 904: urb->usercontext = s; ! 905: urb->buffer = pbuf; ! 906: urb->buffer_length = prem; ! 907: ! 908: if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) { ! 909: urb->buffer_length = MAX_USBFS_BUFFER_SIZE; ! 910: } ! 911: pbuf += urb->buffer_length; ! 912: prem -= urb->buffer_length; ! 913: rem -= urb->buffer_length; ! 914: if (rem) { ! 915: aurb->more = 1; ! 916: } ! 917: ! 918: trace_usb_host_urb_submit(s->bus_num, s->addr, aurb, ! 919: urb->buffer_length, aurb->more); ! 920: ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); ! 921: ! 922: DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n", ! 923: urb->endpoint, urb->buffer_length, aurb->more, p, aurb); ! 924: ! 925: if (ret < 0) { ! 926: perror("USBDEVFS_SUBMITURB"); ! 927: async_free(aurb); ! 928: ! 929: switch(errno) { ! 930: case ETIMEDOUT: ! 931: trace_usb_host_req_complete(s->bus_num, s->addr, p, ! 932: USB_RET_NAK); ! 933: return USB_RET_NAK; ! 934: case EPIPE: ! 935: default: ! 936: trace_usb_host_req_complete(s->bus_num, s->addr, p, ! 937: USB_RET_STALL); ! 938: return USB_RET_STALL; ! 939: } ! 940: } ! 941: } while (rem > 0); ! 942: ! 943: return USB_RET_ASYNC; ! 944: } ! 945: ! 946: static int ctrl_error(void) ! 947: { ! 948: if (errno == ETIMEDOUT) { ! 949: return USB_RET_NAK; ! 950: } else { ! 951: return USB_RET_STALL; ! 952: } ! 953: } ! 954: ! 955: static int usb_host_set_address(USBHostDevice *s, int addr) ! 956: { ! 957: trace_usb_host_set_address(s->bus_num, s->addr, addr); ! 958: s->dev.addr = addr; ! 959: return 0; ! 960: } ! 961: ! 962: static int usb_host_set_config(USBHostDevice *s, int config) ! 963: { ! 964: int ret, first = 1; ! 965: ! 966: trace_usb_host_set_config(s->bus_num, s->addr, config); ! 967: ! 968: usb_host_release_interfaces(s); ! 969: ! 970: again: ! 971: ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config); ! 972: ! 973: DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno); ! 974: ! 975: if (ret < 0 && errno == EBUSY && first) { ! 976: /* happens if usb device is in use by host drivers */ ! 977: int count = usb_linux_get_num_interfaces(s); ! 978: if (count > 0) { ! 979: DPRINTF("husb: busy -> disconnecting %d interfaces\n", count); ! 980: usb_host_disconnect_ifaces(s, count); ! 981: first = 0; ! 982: goto again; ! 983: } ! 984: } ! 985: ! 986: if (ret < 0) { ! 987: return ctrl_error(); ! 988: } ! 989: usb_host_claim_interfaces(s, config); ! 990: usb_linux_update_endp_table(s); ! 991: return 0; ! 992: } ! 993: ! 994: static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) ! 995: { ! 996: struct usbdevfs_setinterface si; ! 997: int i, ret; ! 998: ! 999: trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt); ! 1000: ! 1001: for (i = 1; i <= USB_MAX_ENDPOINTS; i++) { ! 1002: if (is_isoc(s, USB_TOKEN_IN, i)) { ! 1003: usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i); ! 1004: } ! 1005: if (is_isoc(s, USB_TOKEN_OUT, i)) { ! 1006: usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i); ! 1007: } ! 1008: } ! 1009: ! 1010: if (iface >= USB_MAX_INTERFACES) { ! 1011: return USB_RET_STALL; ! 1012: } ! 1013: ! 1014: si.interface = iface; ! 1015: si.altsetting = alt; ! 1016: ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si); ! 1017: ! 1018: DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n", ! 1019: iface, alt, ret, errno); ! 1020: ! 1021: if (ret < 0) { ! 1022: return ctrl_error(); ! 1023: } ! 1024: ! 1025: s->dev.altsetting[iface] = alt; ! 1026: usb_linux_update_endp_table(s); ! 1027: return 0; ! 1028: } ! 1029: ! 1030: static int usb_host_handle_control(USBDevice *dev, USBPacket *p, ! 1031: int request, int value, int index, int length, uint8_t *data) ! 1032: { ! 1033: USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); ! 1034: struct usbdevfs_urb *urb; ! 1035: AsyncURB *aurb; ! 1036: int ret; ! 1037: ! 1038: /* ! 1039: * Process certain standard device requests. ! 1040: * These are infrequent and are processed synchronously. ! 1041: */ ! 1042: ! 1043: /* Note request is (bRequestType << 8) | bRequest */ ! 1044: trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); ! 1045: ! 1046: switch (request) { ! 1047: case DeviceOutRequest | USB_REQ_SET_ADDRESS: ! 1048: ret = usb_host_set_address(s, value); ! 1049: trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); ! 1050: return ret; ! 1051: ! 1052: case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ! 1053: ret = usb_host_set_config(s, value & 0xff); ! 1054: trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); ! 1055: return ret; ! 1056: ! 1057: case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ! 1058: ret = usb_host_set_interface(s, index, value); ! 1059: trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); ! 1060: return ret; ! 1061: ! 1062: case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ! 1063: if (value == 0) { /* clear halt */ ! 1064: int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; ! 1065: ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index); ! 1066: clear_halt(s, pid, index & 0x0f); ! 1067: trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0); ! 1068: return 0; ! 1069: } ! 1070: } ! 1071: ! 1072: /* The rest are asynchronous */ ! 1073: ! 1074: if (length > sizeof(dev->data_buf)) { ! 1075: fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", ! 1076: length, sizeof(dev->data_buf)); ! 1077: return USB_RET_STALL; ! 1078: } ! 1079: ! 1080: aurb = async_alloc(s); ! 1081: aurb->packet = p; ! 1082: ! 1083: /* ! 1084: * Setup ctrl transfer. ! 1085: * ! 1086: * s->ctrl is laid out such that data buffer immediately follows ! 1087: * 'req' struct which is exactly what usbdevfs expects. ! 1088: */ ! 1089: urb = &aurb->urb; ! 1090: ! 1091: urb->type = USBDEVFS_URB_TYPE_CONTROL; ! 1092: urb->endpoint = p->ep->nr; ! 1093: ! 1094: urb->buffer = &dev->setup_buf; ! 1095: urb->buffer_length = length + 8; ! 1096: ! 1097: urb->usercontext = s; ! 1098: ! 1099: trace_usb_host_urb_submit(s->bus_num, s->addr, aurb, ! 1100: urb->buffer_length, aurb->more); ! 1101: ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); ! 1102: ! 1103: DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb); ! 1104: ! 1105: if (ret < 0) { ! 1106: DPRINTF("husb: submit failed. errno %d\n", errno); ! 1107: async_free(aurb); ! 1108: ! 1109: switch(errno) { ! 1110: case ETIMEDOUT: ! 1111: return USB_RET_NAK; ! 1112: case EPIPE: ! 1113: default: ! 1114: return USB_RET_STALL; ! 1115: } ! 1116: } ! 1117: ! 1118: return USB_RET_ASYNC; ! 1119: } ! 1120: ! 1121: /* returns 1 on problem encountered or 0 for success */ ! 1122: static int usb_linux_update_endp_table(USBHostDevice *s) ! 1123: { ! 1124: static const char *tname[] = { ! 1125: [USB_ENDPOINT_XFER_CONTROL] = "control", ! 1126: [USB_ENDPOINT_XFER_ISOC] = "isoc", ! 1127: [USB_ENDPOINT_XFER_BULK] = "bulk", ! 1128: [USB_ENDPOINT_XFER_INT] = "int", ! 1129: }; ! 1130: uint8_t devep, type; ! 1131: uint16_t mps, v, p; ! 1132: int ep, pid; ! 1133: unsigned int i, configuration = -1, interface = -1, altsetting = -1; ! 1134: struct endp_data *epd; ! 1135: USBDescriptor *d; ! 1136: bool active = false; ! 1137: ! 1138: usb_ep_init(&s->dev); ! 1139: ! 1140: for (i = 0;; i += d->bLength) { ! 1141: if (i+2 >= s->descr_len) { ! 1142: break; ! 1143: } ! 1144: d = (void *)(s->descr + i); ! 1145: if (d->bLength < 2) { ! 1146: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1147: "descriptor too short"); ! 1148: goto error; ! 1149: } ! 1150: if (i + d->bLength > s->descr_len) { ! 1151: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1152: "descriptor too long"); ! 1153: goto error; ! 1154: } ! 1155: switch (d->bDescriptorType) { ! 1156: case 0: ! 1157: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1158: "invalid descriptor type"); ! 1159: goto error; ! 1160: case USB_DT_DEVICE: ! 1161: if (d->bLength < 0x12) { ! 1162: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1163: "device descriptor too short"); ! 1164: goto error; ! 1165: } ! 1166: v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo; ! 1167: p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo; ! 1168: trace_usb_host_parse_device(s->bus_num, s->addr, v, p); ! 1169: break; ! 1170: case USB_DT_CONFIG: ! 1171: if (d->bLength < 0x09) { ! 1172: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1173: "config descriptor too short"); ! 1174: goto error; ! 1175: } ! 1176: configuration = d->u.config.bConfigurationValue; ! 1177: active = (configuration == s->dev.configuration); ! 1178: trace_usb_host_parse_config(s->bus_num, s->addr, ! 1179: configuration, active); ! 1180: break; ! 1181: case USB_DT_INTERFACE: ! 1182: if (d->bLength < 0x09) { ! 1183: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1184: "interface descriptor too short"); ! 1185: goto error; ! 1186: } ! 1187: interface = d->u.interface.bInterfaceNumber; ! 1188: altsetting = d->u.interface.bAlternateSetting; ! 1189: active = (configuration == s->dev.configuration) && ! 1190: (altsetting == s->dev.altsetting[interface]); ! 1191: trace_usb_host_parse_interface(s->bus_num, s->addr, ! 1192: interface, altsetting, active); ! 1193: break; ! 1194: case USB_DT_ENDPOINT: ! 1195: if (d->bLength < 0x07) { ! 1196: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1197: "endpoint descriptor too short"); ! 1198: goto error; ! 1199: } ! 1200: devep = d->u.endpoint.bEndpointAddress; ! 1201: pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; ! 1202: ep = devep & 0xf; ! 1203: if (ep == 0) { ! 1204: trace_usb_host_parse_error(s->bus_num, s->addr, ! 1205: "invalid endpoint address"); ! 1206: goto error; ! 1207: } ! 1208: ! 1209: type = d->u.endpoint.bmAttributes & 0x3; ! 1210: mps = d->u.endpoint.wMaxPacketSize_lo | ! 1211: (d->u.endpoint.wMaxPacketSize_hi << 8); ! 1212: trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep, ! 1213: (devep & USB_DIR_IN) ? "in" : "out", ! 1214: tname[type], active); ! 1215: ! 1216: if (active) { ! 1217: usb_ep_set_max_packet_size(&s->dev, pid, ep, mps); ! 1218: assert(usb_ep_get_type(&s->dev, pid, ep) == ! 1219: USB_ENDPOINT_XFER_INVALID); ! 1220: usb_ep_set_type(&s->dev, pid, ep, type); ! 1221: usb_ep_set_ifnum(&s->dev, pid, ep, interface); ! 1222: if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) && ! 1223: (type == USB_ENDPOINT_XFER_BULK)) { ! 1224: usb_ep_set_pipeline(&s->dev, pid, ep, true); ! 1225: } ! 1226: ! 1227: epd = get_endp(s, pid, ep); ! 1228: epd->halted = 0; ! 1229: } ! 1230: ! 1231: break; ! 1232: default: ! 1233: trace_usb_host_parse_unknown(s->bus_num, s->addr, ! 1234: d->bLength, d->bDescriptorType); ! 1235: break; ! 1236: } ! 1237: } ! 1238: return 0; ! 1239: ! 1240: error: ! 1241: usb_ep_init(&s->dev); ! 1242: return 1; ! 1243: } ! 1244: ! 1245: /* ! 1246: * Check if we can safely redirect a usb2 device to a usb1 virtual controller, ! 1247: * this function assumes this is safe, if: ! 1248: * 1) There are no isoc endpoints ! 1249: * 2) There are no interrupt endpoints with a max_packet_size > 64 ! 1250: * Note bulk endpoints with a max_packet_size > 64 in theory also are not ! 1251: * usb1 compatible, but in practice this seems to work fine. ! 1252: */ ! 1253: static int usb_linux_full_speed_compat(USBHostDevice *dev) ! 1254: { ! 1255: int i, packet_size; ! 1256: ! 1257: /* ! 1258: * usb_linux_update_endp_table only registers info about ep in the current ! 1259: * interface altsettings, so we need to parse the descriptors again. ! 1260: */ ! 1261: for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) { ! 1262: if (dev->descr[i + 1] == USB_DT_ENDPOINT) { ! 1263: switch (dev->descr[i + 3] & 0x3) { ! 1264: case 0x00: /* CONTROL */ ! 1265: break; ! 1266: case 0x01: /* ISO */ ! 1267: return 0; ! 1268: case 0x02: /* BULK */ ! 1269: break; ! 1270: case 0x03: /* INTERRUPT */ ! 1271: packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8); ! 1272: if (packet_size > 64) ! 1273: return 0; ! 1274: break; ! 1275: } ! 1276: } ! 1277: } ! 1278: return 1; ! 1279: } ! 1280: ! 1281: static int usb_host_open(USBHostDevice *dev, int bus_num, ! 1282: int addr, const char *port, ! 1283: const char *prod_name, int speed) ! 1284: { ! 1285: int fd = -1, ret; ! 1286: ! 1287: trace_usb_host_open_started(bus_num, addr); ! 1288: ! 1289: if (dev->fd != -1) { ! 1290: goto fail; ! 1291: } ! 1292: ! 1293: fd = usb_host_open_device(bus_num, addr); ! 1294: if (fd < 0) { ! 1295: goto fail; ! 1296: } ! 1297: DPRINTF("husb: opened %s\n", buf); ! 1298: ! 1299: dev->bus_num = bus_num; ! 1300: dev->addr = addr; ! 1301: strcpy(dev->port, port); ! 1302: dev->fd = fd; ! 1303: ! 1304: /* read the device description */ ! 1305: dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); ! 1306: if (dev->descr_len <= 0) { ! 1307: perror("husb: reading device data failed"); ! 1308: goto fail; ! 1309: } ! 1310: ! 1311: #ifdef DEBUG ! 1312: { ! 1313: int x; ! 1314: printf("=== begin dumping device descriptor data ===\n"); ! 1315: for (x = 0; x < dev->descr_len; x++) { ! 1316: printf("%02x ", dev->descr[x]); ! 1317: } ! 1318: printf("\n=== end dumping device descriptor data ===\n"); ! 1319: } ! 1320: #endif ! 1321: ! 1322: ! 1323: /* start unconfigured -- we'll wait for the guest to set a configuration */ ! 1324: if (!usb_host_claim_interfaces(dev, 0)) { ! 1325: goto fail; ! 1326: } ! 1327: ! 1328: ret = usb_linux_update_endp_table(dev); ! 1329: if (ret) { ! 1330: goto fail; ! 1331: } ! 1332: ! 1333: if (speed == -1) { ! 1334: struct usbdevfs_connectinfo ci; ! 1335: ! 1336: ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); ! 1337: if (ret < 0) { ! 1338: perror("usb_host_device_open: USBDEVFS_CONNECTINFO"); ! 1339: goto fail; ! 1340: } ! 1341: ! 1342: if (ci.slow) { ! 1343: speed = USB_SPEED_LOW; ! 1344: } else { ! 1345: speed = USB_SPEED_HIGH; ! 1346: } ! 1347: } ! 1348: dev->dev.speed = speed; ! 1349: dev->dev.speedmask = (1 << speed); ! 1350: if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) { ! 1351: dev->dev.speedmask |= USB_SPEED_MASK_FULL; ! 1352: } ! 1353: ! 1354: trace_usb_host_open_success(bus_num, addr); ! 1355: ! 1356: if (!prod_name || prod_name[0] == '\0') { ! 1357: snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc), ! 1358: "host:%d.%d", bus_num, addr); ! 1359: } else { ! 1360: pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc), ! 1361: prod_name); ! 1362: } ! 1363: ! 1364: ret = usb_device_attach(&dev->dev); ! 1365: if (ret) { ! 1366: goto fail; ! 1367: } ! 1368: ! 1369: /* USB devio uses 'write' flag to check for async completions */ ! 1370: qemu_set_fd_handler(dev->fd, NULL, async_complete, dev); ! 1371: ! 1372: return 0; ! 1373: ! 1374: fail: ! 1375: trace_usb_host_open_failure(bus_num, addr); ! 1376: if (dev->fd != -1) { ! 1377: close(dev->fd); ! 1378: dev->fd = -1; ! 1379: } ! 1380: return -1; ! 1381: } ! 1382: ! 1383: static int usb_host_close(USBHostDevice *dev) ! 1384: { ! 1385: int i; ! 1386: ! 1387: if (dev->fd == -1) { ! 1388: return -1; ! 1389: } ! 1390: ! 1391: trace_usb_host_close(dev->bus_num, dev->addr); ! 1392: ! 1393: qemu_set_fd_handler(dev->fd, NULL, NULL, NULL); ! 1394: dev->closing = 1; ! 1395: for (i = 1; i <= USB_MAX_ENDPOINTS; i++) { ! 1396: if (is_isoc(dev, USB_TOKEN_IN, i)) { ! 1397: usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i); ! 1398: } ! 1399: if (is_isoc(dev, USB_TOKEN_OUT, i)) { ! 1400: usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i); ! 1401: } ! 1402: } ! 1403: async_complete(dev); ! 1404: dev->closing = 0; ! 1405: if (dev->dev.attached) { ! 1406: usb_device_detach(&dev->dev); ! 1407: } ! 1408: usb_host_do_reset(dev); ! 1409: close(dev->fd); ! 1410: dev->fd = -1; ! 1411: return 0; ! 1412: } ! 1413: ! 1414: static void usb_host_exit_notifier(struct Notifier *n, void *data) ! 1415: { ! 1416: USBHostDevice *s = container_of(n, USBHostDevice, exit); ! 1417: ! 1418: usb_host_release_port(s); ! 1419: if (s->fd != -1) { ! 1420: usb_host_do_reset(s);; ! 1421: } ! 1422: } ! 1423: ! 1424: static int usb_host_initfn(USBDevice *dev) ! 1425: { ! 1426: USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); ! 1427: ! 1428: dev->auto_attach = 0; ! 1429: s->fd = -1; ! 1430: s->hub_fd = -1; ! 1431: ! 1432: QTAILQ_INSERT_TAIL(&hostdevs, s, next); ! 1433: s->exit.notify = usb_host_exit_notifier; ! 1434: qemu_add_exit_notifier(&s->exit); ! 1435: usb_host_auto_check(NULL); ! 1436: ! 1437: if (s->match.bus_num != 0 && s->match.port != NULL) { ! 1438: usb_host_claim_port(s); ! 1439: } ! 1440: add_boot_device_path(s->bootindex, &dev->qdev, NULL); ! 1441: return 0; ! 1442: } ! 1443: ! 1444: static const VMStateDescription vmstate_usb_host = { ! 1445: .name = "usb-host", ! 1446: .unmigratable = 1, ! 1447: }; ! 1448: ! 1449: static Property usb_host_dev_properties[] = { ! 1450: DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0), ! 1451: DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0), ! 1452: DEFINE_PROP_STRING("hostport", USBHostDevice, match.port), ! 1453: DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0), ! 1454: DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0), ! 1455: DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), ! 1456: DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1), ! 1457: DEFINE_PROP_BIT("pipeline", USBHostDevice, options, ! 1458: USB_HOST_OPT_PIPELINE, true), ! 1459: DEFINE_PROP_END_OF_LIST(), ! 1460: }; ! 1461: ! 1462: static void usb_host_class_initfn(ObjectClass *klass, void *data) ! 1463: { ! 1464: DeviceClass *dc = DEVICE_CLASS(klass); ! 1465: USBDeviceClass *uc = USB_DEVICE_CLASS(klass); ! 1466: ! 1467: uc->init = usb_host_initfn; ! 1468: uc->product_desc = "USB Host Device"; ! 1469: uc->cancel_packet = usb_host_async_cancel; ! 1470: uc->handle_data = usb_host_handle_data; ! 1471: uc->handle_control = usb_host_handle_control; ! 1472: uc->handle_reset = usb_host_handle_reset; ! 1473: uc->handle_destroy = usb_host_handle_destroy; ! 1474: dc->vmsd = &vmstate_usb_host; ! 1475: dc->props = usb_host_dev_properties; ! 1476: } ! 1477: ! 1478: static TypeInfo usb_host_dev_info = { ! 1479: .name = "usb-host", ! 1480: .parent = TYPE_USB_DEVICE, ! 1481: .instance_size = sizeof(USBHostDevice), ! 1482: .class_init = usb_host_class_initfn, ! 1483: }; ! 1484: ! 1485: static void usb_host_register_types(void) ! 1486: { ! 1487: type_register_static(&usb_host_dev_info); ! 1488: usb_legacy_register("usb-host", "host", usb_host_device_open); ! 1489: } ! 1490: ! 1491: type_init(usb_host_register_types) ! 1492: ! 1493: USBDevice *usb_host_device_open(USBBus *bus, const char *devname) ! 1494: { ! 1495: struct USBAutoFilter filter; ! 1496: USBDevice *dev; ! 1497: char *p; ! 1498: ! 1499: dev = usb_create(bus, "usb-host"); ! 1500: ! 1501: if (strstr(devname, "auto:")) { ! 1502: if (parse_filter(devname, &filter) < 0) { ! 1503: goto fail; ! 1504: } ! 1505: } else { ! 1506: if ((p = strchr(devname, '.'))) { ! 1507: filter.bus_num = strtoul(devname, NULL, 0); ! 1508: filter.addr = strtoul(p + 1, NULL, 0); ! 1509: filter.vendor_id = 0; ! 1510: filter.product_id = 0; ! 1511: } else if ((p = strchr(devname, ':'))) { ! 1512: filter.bus_num = 0; ! 1513: filter.addr = 0; ! 1514: filter.vendor_id = strtoul(devname, NULL, 16); ! 1515: filter.product_id = strtoul(p + 1, NULL, 16); ! 1516: } else { ! 1517: goto fail; ! 1518: } ! 1519: } ! 1520: ! 1521: qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num); ! 1522: qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr); ! 1523: qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id); ! 1524: qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id); ! 1525: qdev_init_nofail(&dev->qdev); ! 1526: return dev; ! 1527: ! 1528: fail: ! 1529: qdev_free(&dev->qdev); ! 1530: return NULL; ! 1531: } ! 1532: ! 1533: int usb_host_device_close(const char *devname) ! 1534: { ! 1535: #if 0 ! 1536: char product_name[PRODUCT_NAME_SZ]; ! 1537: int bus_num, addr; ! 1538: USBHostDevice *s; ! 1539: ! 1540: if (strstr(devname, "auto:")) { ! 1541: return usb_host_auto_del(devname); ! 1542: } ! 1543: if (usb_host_find_device(&bus_num, &addr, product_name, ! 1544: sizeof(product_name), devname) < 0) { ! 1545: return -1; ! 1546: } ! 1547: s = hostdev_find(bus_num, addr); ! 1548: if (s) { ! 1549: usb_device_delete_addr(s->bus_num, s->dev.addr); ! 1550: return 0; ! 1551: } ! 1552: #endif ! 1553: ! 1554: return -1; ! 1555: } ! 1556: ! 1557: /* ! 1558: * Read sys file-system device file ! 1559: * ! 1560: * @line address of buffer to put file contents in ! 1561: * @line_size size of line ! 1562: * @device_file path to device file (printf format string) ! 1563: * @device_name device being opened (inserted into device_file) ! 1564: * ! 1565: * @return 0 failed, 1 succeeded ('line' contains data) ! 1566: */ ! 1567: static int usb_host_read_file(char *line, size_t line_size, ! 1568: const char *device_file, const char *device_name) ! 1569: { ! 1570: FILE *f; ! 1571: int ret = 0; ! 1572: char filename[PATH_MAX]; ! 1573: ! 1574: snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name, ! 1575: device_file); ! 1576: f = fopen(filename, "r"); ! 1577: if (f) { ! 1578: ret = fgets(line, line_size, f) != NULL; ! 1579: fclose(f); ! 1580: } ! 1581: ! 1582: return ret; ! 1583: } ! 1584: ! 1585: /* ! 1586: * Use /sys/bus/usb/devices/ directory to determine host's USB ! 1587: * devices. ! 1588: * ! 1589: * This code is based on Robert Schiele's original patches posted to ! 1590: * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950 ! 1591: */ ! 1592: static int usb_host_scan(void *opaque, USBScanFunc *func) ! 1593: { ! 1594: DIR *dir = NULL; ! 1595: char line[1024]; ! 1596: int bus_num, addr, speed, class_id, product_id, vendor_id; ! 1597: int ret = 0; ! 1598: char port[MAX_PORTLEN]; ! 1599: char product_name[512]; ! 1600: struct dirent *de; ! 1601: ! 1602: dir = opendir("/sys/bus/usb/devices"); ! 1603: if (!dir) { ! 1604: perror("husb: opendir /sys/bus/usb/devices"); ! 1605: fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n"); ! 1606: goto the_end; ! 1607: } ! 1608: ! 1609: while ((de = readdir(dir))) { ! 1610: if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) { ! 1611: if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) { ! 1612: continue; ! 1613: } ! 1614: ! 1615: if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) { ! 1616: goto the_end; ! 1617: } ! 1618: if (sscanf(line, "%d", &addr) != 1) { ! 1619: goto the_end; ! 1620: } ! 1621: if (!usb_host_read_file(line, sizeof(line), "bDeviceClass", ! 1622: de->d_name)) { ! 1623: goto the_end; ! 1624: } ! 1625: if (sscanf(line, "%x", &class_id) != 1) { ! 1626: goto the_end; ! 1627: } ! 1628: ! 1629: if (!usb_host_read_file(line, sizeof(line), "idVendor", ! 1630: de->d_name)) { ! 1631: goto the_end; ! 1632: } ! 1633: if (sscanf(line, "%x", &vendor_id) != 1) { ! 1634: goto the_end; ! 1635: } ! 1636: if (!usb_host_read_file(line, sizeof(line), "idProduct", ! 1637: de->d_name)) { ! 1638: goto the_end; ! 1639: } ! 1640: if (sscanf(line, "%x", &product_id) != 1) { ! 1641: goto the_end; ! 1642: } ! 1643: if (!usb_host_read_file(line, sizeof(line), "product", ! 1644: de->d_name)) { ! 1645: *product_name = 0; ! 1646: } else { ! 1647: if (strlen(line) > 0) { ! 1648: line[strlen(line) - 1] = '\0'; ! 1649: } ! 1650: pstrcpy(product_name, sizeof(product_name), line); ! 1651: } ! 1652: ! 1653: if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) { ! 1654: goto the_end; ! 1655: } ! 1656: if (!strcmp(line, "5000\n")) { ! 1657: speed = USB_SPEED_SUPER; ! 1658: } else if (!strcmp(line, "480\n")) { ! 1659: speed = USB_SPEED_HIGH; ! 1660: } else if (!strcmp(line, "1.5\n")) { ! 1661: speed = USB_SPEED_LOW; ! 1662: } else { ! 1663: speed = USB_SPEED_FULL; ! 1664: } ! 1665: ! 1666: ret = func(opaque, bus_num, addr, port, class_id, vendor_id, ! 1667: product_id, product_name, speed); ! 1668: if (ret) { ! 1669: goto the_end; ! 1670: } ! 1671: } ! 1672: } ! 1673: the_end: ! 1674: if (dir) { ! 1675: closedir(dir); ! 1676: } ! 1677: return ret; ! 1678: } ! 1679: ! 1680: static QEMUTimer *usb_auto_timer; ! 1681: ! 1682: static int usb_host_auto_scan(void *opaque, int bus_num, ! 1683: int addr, const char *port, ! 1684: int class_id, int vendor_id, int product_id, ! 1685: const char *product_name, int speed) ! 1686: { ! 1687: struct USBAutoFilter *f; ! 1688: struct USBHostDevice *s; ! 1689: ! 1690: /* Ignore hubs */ ! 1691: if (class_id == 9) ! 1692: return 0; ! 1693: ! 1694: QTAILQ_FOREACH(s, &hostdevs, next) { ! 1695: f = &s->match; ! 1696: ! 1697: if (f->bus_num > 0 && f->bus_num != bus_num) { ! 1698: continue; ! 1699: } ! 1700: if (f->addr > 0 && f->addr != addr) { ! 1701: continue; ! 1702: } ! 1703: if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) { ! 1704: continue; ! 1705: } ! 1706: ! 1707: if (f->vendor_id > 0 && f->vendor_id != vendor_id) { ! 1708: continue; ! 1709: } ! 1710: ! 1711: if (f->product_id > 0 && f->product_id != product_id) { ! 1712: continue; ! 1713: } ! 1714: /* We got a match */ ! 1715: s->seen++; ! 1716: if (s->errcount >= 3) { ! 1717: return 0; ! 1718: } ! 1719: ! 1720: /* Already attached ? */ ! 1721: if (s->fd != -1) { ! 1722: return 0; ! 1723: } ! 1724: DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr); ! 1725: ! 1726: if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) { ! 1727: s->errcount++; ! 1728: } ! 1729: break; ! 1730: } ! 1731: ! 1732: return 0; ! 1733: } ! 1734: ! 1735: static void usb_host_auto_check(void *unused) ! 1736: { ! 1737: struct USBHostDevice *s; ! 1738: int unconnected = 0; ! 1739: ! 1740: usb_host_scan(NULL, usb_host_auto_scan); ! 1741: ! 1742: QTAILQ_FOREACH(s, &hostdevs, next) { ! 1743: if (s->fd == -1) { ! 1744: unconnected++; ! 1745: } ! 1746: if (s->seen == 0) { ! 1747: s->errcount = 0; ! 1748: } ! 1749: s->seen = 0; ! 1750: } ! 1751: ! 1752: if (unconnected == 0) { ! 1753: /* nothing to watch */ ! 1754: if (usb_auto_timer) { ! 1755: qemu_del_timer(usb_auto_timer); ! 1756: trace_usb_host_auto_scan_disabled(); ! 1757: } ! 1758: return; ! 1759: } ! 1760: ! 1761: if (!usb_auto_timer) { ! 1762: usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL); ! 1763: if (!usb_auto_timer) { ! 1764: return; ! 1765: } ! 1766: trace_usb_host_auto_scan_enabled(); ! 1767: } ! 1768: qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000); ! 1769: } ! 1770: ! 1771: /* ! 1772: * Autoconnect filter ! 1773: * Format: ! 1774: * auto:bus:dev[:vid:pid] ! 1775: * auto:bus.dev[:vid:pid] ! 1776: * ! 1777: * bus - bus number (dec, * means any) ! 1778: * dev - device number (dec, * means any) ! 1779: * vid - vendor id (hex, * means any) ! 1780: * pid - product id (hex, * means any) ! 1781: * ! 1782: * See 'lsusb' output. ! 1783: */ ! 1784: static int parse_filter(const char *spec, struct USBAutoFilter *f) ! 1785: { ! 1786: enum { BUS, DEV, VID, PID, DONE }; ! 1787: const char *p = spec; ! 1788: int i; ! 1789: ! 1790: f->bus_num = 0; ! 1791: f->addr = 0; ! 1792: f->vendor_id = 0; ! 1793: f->product_id = 0; ! 1794: ! 1795: for (i = BUS; i < DONE; i++) { ! 1796: p = strpbrk(p, ":."); ! 1797: if (!p) { ! 1798: break; ! 1799: } ! 1800: p++; ! 1801: ! 1802: if (*p == '*') { ! 1803: continue; ! 1804: } ! 1805: switch(i) { ! 1806: case BUS: f->bus_num = strtol(p, NULL, 10); break; ! 1807: case DEV: f->addr = strtol(p, NULL, 10); break; ! 1808: case VID: f->vendor_id = strtol(p, NULL, 16); break; ! 1809: case PID: f->product_id = strtol(p, NULL, 16); break; ! 1810: } ! 1811: } ! 1812: ! 1813: if (i < DEV) { ! 1814: fprintf(stderr, "husb: invalid auto filter spec %s\n", spec); ! 1815: return -1; ! 1816: } ! 1817: ! 1818: return 0; ! 1819: } ! 1820: ! 1821: /**********************/ ! 1822: /* USB host device info */ ! 1823: ! 1824: struct usb_class_info { ! 1825: int class; ! 1826: const char *class_name; ! 1827: }; ! 1828: ! 1829: static const struct usb_class_info usb_class_info[] = { ! 1830: { USB_CLASS_AUDIO, "Audio"}, ! 1831: { USB_CLASS_COMM, "Communication"}, ! 1832: { USB_CLASS_HID, "HID"}, ! 1833: { USB_CLASS_HUB, "Hub" }, ! 1834: { USB_CLASS_PHYSICAL, "Physical" }, ! 1835: { USB_CLASS_PRINTER, "Printer" }, ! 1836: { USB_CLASS_MASS_STORAGE, "Storage" }, ! 1837: { USB_CLASS_CDC_DATA, "Data" }, ! 1838: { USB_CLASS_APP_SPEC, "Application Specific" }, ! 1839: { USB_CLASS_VENDOR_SPEC, "Vendor Specific" }, ! 1840: { USB_CLASS_STILL_IMAGE, "Still Image" }, ! 1841: { USB_CLASS_CSCID, "Smart Card" }, ! 1842: { USB_CLASS_CONTENT_SEC, "Content Security" }, ! 1843: { -1, NULL } ! 1844: }; ! 1845: ! 1846: static const char *usb_class_str(uint8_t class) ! 1847: { ! 1848: const struct usb_class_info *p; ! 1849: for(p = usb_class_info; p->class != -1; p++) { ! 1850: if (p->class == class) { ! 1851: break; ! 1852: } ! 1853: } ! 1854: return p->class_name; ! 1855: } ! 1856: ! 1857: static void usb_info_device(Monitor *mon, int bus_num, ! 1858: int addr, const char *port, ! 1859: int class_id, int vendor_id, int product_id, ! 1860: const char *product_name, ! 1861: int speed) ! 1862: { ! 1863: const char *class_str, *speed_str; ! 1864: ! 1865: switch(speed) { ! 1866: case USB_SPEED_LOW: ! 1867: speed_str = "1.5"; ! 1868: break; ! 1869: case USB_SPEED_FULL: ! 1870: speed_str = "12"; ! 1871: break; ! 1872: case USB_SPEED_HIGH: ! 1873: speed_str = "480"; ! 1874: break; ! 1875: case USB_SPEED_SUPER: ! 1876: speed_str = "5000"; ! 1877: break; ! 1878: default: ! 1879: speed_str = "?"; ! 1880: break; ! 1881: } ! 1882: ! 1883: monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n", ! 1884: bus_num, addr, port, speed_str); ! 1885: class_str = usb_class_str(class_id); ! 1886: if (class_str) { ! 1887: monitor_printf(mon, " %s:", class_str); ! 1888: } else { ! 1889: monitor_printf(mon, " Class %02x:", class_id); ! 1890: } ! 1891: monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id); ! 1892: if (product_name[0] != '\0') { ! 1893: monitor_printf(mon, ", %s", product_name); ! 1894: } ! 1895: monitor_printf(mon, "\n"); ! 1896: } ! 1897: ! 1898: static int usb_host_info_device(void *opaque, int bus_num, int addr, ! 1899: const char *path, int class_id, ! 1900: int vendor_id, int product_id, ! 1901: const char *product_name, ! 1902: int speed) ! 1903: { ! 1904: Monitor *mon = opaque; ! 1905: ! 1906: usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id, ! 1907: product_name, speed); ! 1908: return 0; ! 1909: } ! 1910: ! 1911: static void dec2str(int val, char *str, size_t size) ! 1912: { ! 1913: if (val == 0) { ! 1914: snprintf(str, size, "*"); ! 1915: } else { ! 1916: snprintf(str, size, "%d", val); ! 1917: } ! 1918: } ! 1919: ! 1920: static void hex2str(int val, char *str, size_t size) ! 1921: { ! 1922: if (val == 0) { ! 1923: snprintf(str, size, "*"); ! 1924: } else { ! 1925: snprintf(str, size, "%04x", val); ! 1926: } ! 1927: } ! 1928: ! 1929: void usb_host_info(Monitor *mon) ! 1930: { ! 1931: struct USBAutoFilter *f; ! 1932: struct USBHostDevice *s; ! 1933: ! 1934: usb_host_scan(mon, usb_host_info_device); ! 1935: ! 1936: if (QTAILQ_EMPTY(&hostdevs)) { ! 1937: return; ! 1938: } ! 1939: ! 1940: monitor_printf(mon, " Auto filters:\n"); ! 1941: QTAILQ_FOREACH(s, &hostdevs, next) { ! 1942: char bus[10], addr[10], vid[10], pid[10]; ! 1943: f = &s->match; ! 1944: dec2str(f->bus_num, bus, sizeof(bus)); ! 1945: dec2str(f->addr, addr, sizeof(addr)); ! 1946: hex2str(f->vendor_id, vid, sizeof(vid)); ! 1947: hex2str(f->product_id, pid, sizeof(pid)); ! 1948: monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n", ! 1949: bus, addr, f->port ? f->port : "*", vid, pid); ! 1950: } ! 1951: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.