diff options
-rw-r--r-- | usb-linux.c | 140 |
1 files changed, 77 insertions, 63 deletions
diff --git a/usb-linux.c b/usb-linux.c index 2075c4c67a..ff1a29c663 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -411,6 +411,80 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p) } } +static int usb_host_claim_port(USBHostDevice *s) +{ +#ifdef USBDEVFS_CLAIM_PORT + char *h, hub_name[64], line[1024]; + int hub_addr, portnr, ret; + + snprintf(hub_name, sizeof(hub_name), "%d-%s", + s->match.bus_num, s->match.port); + + /* try strip off last ".$portnr" to get hub */ + h = strrchr(hub_name, '.'); + if (h != NULL) { + portnr = atoi(h+1); + *h = '\0'; + } else { + /* no dot in there -> it is the root hub */ + snprintf(hub_name, sizeof(hub_name), "usb%d", + s->match.bus_num); + portnr = atoi(s->match.port); + } + + if (!usb_host_read_file(line, sizeof(line), "devnum", + hub_name)) { + return -1; + } + if (sscanf(line, "%d", &hub_addr) != 1) { + return -1; + } + + if (!usb_host_device_path) { + return -1; + } + snprintf(line, sizeof(line), "%s/%03d/%03d", + usb_host_device_path, s->match.bus_num, hub_addr); + s->hub_fd = open(line, O_RDWR | O_NONBLOCK); + if (s->hub_fd < 0) { + return -1; + } + + ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr); + if (ret < 0) { + close(s->hub_fd); + s->hub_fd = -1; + return -1; + } + + trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr); + return 0; +#else + return -1; +#endif +} + +static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces) +{ + /* earlier Linux 2.4 do not support that */ +#ifdef USBDEVFS_DISCONNECT + struct usbdevfs_ioctl ctrl; + int ret, interface; + + for (interface = 0; interface < nb_interfaces; interface++) { + ctrl.ioctl_code = USBDEVFS_DISCONNECT; + ctrl.ifno = interface; + ctrl.data = 0; + ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl); + if (ret < 0 && errno != ENODATA) { + perror("USBDEVFS_DISCONNECT"); + return -1; + } + } +#endif + return 0; +} + static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) { const char *op = NULL; @@ -462,22 +536,9 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) } nb_interfaces = dev->descr[i + 4]; -#ifdef USBDEVFS_DISCONNECT - /* earlier Linux 2.4 do not support that */ - { - struct usbdevfs_ioctl ctrl; - for (interface = 0; interface < nb_interfaces; interface++) { - ctrl.ioctl_code = USBDEVFS_DISCONNECT; - ctrl.ifno = interface; - ctrl.data = 0; - op = "USBDEVFS_DISCONNECT"; - ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl); - if (ret < 0 && errno != ENODATA) { - goto fail; - } - } + if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) { + goto fail; } -#endif /* XXX: only grab if all interfaces are free */ for (interface = 0; interface < nb_interfaces; interface++) { @@ -1301,56 +1362,9 @@ static int usb_host_initfn(USBDevice *dev) qemu_add_exit_notifier(&s->exit); usb_host_auto_check(NULL); -#ifdef USBDEVFS_CLAIM_PORT if (s->match.bus_num != 0 && s->match.port != NULL) { - char *h, hub_name[64], line[1024]; - int hub_addr, portnr, ret; - - snprintf(hub_name, sizeof(hub_name), "%d-%s", - s->match.bus_num, s->match.port); - - /* try strip off last ".$portnr" to get hub */ - h = strrchr(hub_name, '.'); - if (h != NULL) { - portnr = atoi(h+1); - *h = '\0'; - } else { - /* no dot in there -> it is the root hub */ - snprintf(hub_name, sizeof(hub_name), "usb%d", - s->match.bus_num); - portnr = atoi(s->match.port); - } - - if (!usb_host_read_file(line, sizeof(line), "devnum", - hub_name)) { - goto out; - } - if (sscanf(line, "%d", &hub_addr) != 1) { - goto out; - } - - if (!usb_host_device_path) { - goto out; - } - snprintf(line, sizeof(line), "%s/%03d/%03d", - usb_host_device_path, s->match.bus_num, hub_addr); - s->hub_fd = open(line, O_RDWR | O_NONBLOCK); - if (s->hub_fd < 0) { - goto out; - } - - ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr); - if (ret < 0) { - close(s->hub_fd); - s->hub_fd = -1; - goto out; - } - - trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr); + usb_host_claim_port(s); } -out: -#endif - return 0; } |