static int usb_host_open(USBHostDevice *dev, int bus_num, int addr, const char *port, const char *prod_name, int speed) { int fd = -1, ret; trace_usb_host_open_started(bus_num, addr); if (dev->fd != -1) { goto fail; } fd = usb_host_open_device(bus_num, addr); if (fd < 0) { goto fail; } DPRINTF("husb: opened %s\n", buf); dev->bus_num = bus_num; dev->addr = addr; strcpy(dev->port, port); dev->fd = fd; /* read the device description */ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); if (dev->descr_len <= 0) { perror("husb: reading device data failed"); goto fail; } #ifdef DEBUG { int x; printf("=== begin dumping device descriptor data ===\n"); for (x = 0; x < dev->descr_len; x++) { printf("%02x ", dev->descr[x]); } printf("\n=== end dumping device descriptor data ===\n"); } #endif /* start unconfigured -- we'll wait for the guest to set a configuration */ if (!usb_host_claim_interfaces(dev, 0)) { goto fail; } usb_ep_init(&dev->dev); usb_linux_update_endp_table(dev); if (speed == -1) { struct usbdevfs_connectinfo ci; ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); if (ret < 0) { perror("usb_host_device_open: USBDEVFS_CONNECTINFO"); goto fail; } if (ci.slow) { speed = USB_SPEED_LOW; } else { speed = USB_SPEED_HIGH; } } dev->dev.speed = speed; dev->dev.speedmask = (1 << speed); if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) { dev->dev.speedmask |= USB_SPEED_MASK_FULL; } trace_usb_host_open_success(bus_num, addr); if (!prod_name || prod_name[0] == '\0') { snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc), "host:%d.%d", bus_num, addr); } else { pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc), prod_name); } ret = usb_device_attach(&dev->dev); if (ret) { goto fail; } /* USB devio uses 'write' flag to check for async completions */ qemu_set_fd_handler(dev->fd, NULL, async_complete, dev); return 0; fail: trace_usb_host_open_failure(bus_num, addr); if (dev->fd != -1) { close(dev->fd); dev->fd = -1; } return -1; }