diff options
author | Peter Maydell | 2016-06-13 16:15:03 +0200 |
---|---|---|
committer | Peter Maydell | 2016-06-13 16:15:03 +0200 |
commit | 2c96c379ac7a22424c25d65b73e81b860f902868 (patch) | |
tree | cba7cba9fcf3464ebff66430a70ba5f2ada4bbdc /hw/usb/host-libusb.c | |
parent | Merge remote-tracking branch 'remotes/berrange/tags/qcrypto-next-2016-06-13-v... (diff) | |
parent | vl: Eliminate usb_enabled() (diff) | |
download | qemu-2c96c379ac7a22424c25d65b73e81b860f902868.tar.gz qemu-2c96c379ac7a22424c25d65b73e81b860f902868.tar.xz qemu-2c96c379ac7a22424c25d65b73e81b860f902868.zip |
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20160613-1' into staging
usb: misc fixes.
# gpg: Signature made Mon 13 Jun 2016 14:09:15 BST
# gpg: using RSA key 0x4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138
* remotes/kraxel/tags/pull-usb-20160613-1:
vl: Eliminate usb_enabled()
pxa2xx: Unconditionally enable USB controller
hw/usb/dev-network.c: Use ldl_le_p() and stl_le_p()
usb-host: add special case for bus+addr
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/usb/host-libusb.c')
-rw-r--r-- | hw/usb/host-libusb.c | 56 |
1 files changed, 52 insertions, 4 deletions
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 8b774f4939..da59c294bb 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -81,6 +81,7 @@ struct USBHostDevice { uint32_t iso_urb_frames; uint32_t options; uint32_t loglevel; + bool needs_autoscan; /* state */ QTAILQ_ENTRY(USBHostDevice) next; @@ -974,9 +975,32 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data) } } +static libusb_device *usb_host_find_ref(int bus, int addr) +{ + libusb_device **devs = NULL; + libusb_device *ret = NULL; + int i, n; + + if (usb_host_init() != 0) { + return NULL; + } + n = libusb_get_device_list(ctx, &devs); + for (i = 0; i < n; i++) { + if (libusb_get_bus_number(devs[i]) == bus && + libusb_get_device_address(devs[i]) == addr) { + ret = libusb_ref_device(devs[i]); + break; + } + } + libusb_free_device_list(devs, 1); + return ret; +} + static void usb_host_realize(USBDevice *udev, Error **errp) { USBHostDevice *s = USB_HOST_DEVICE(udev); + libusb_device *ldev; + int rc; if (s->match.vendor_id > 0xffff) { error_setg(errp, "vendorid out of range"); @@ -997,11 +1021,33 @@ static void usb_host_realize(USBDevice *udev, Error **errp) QTAILQ_INIT(&s->requests); QTAILQ_INIT(&s->isorings); + if (s->match.addr && s->match.bus_num && + !s->match.vendor_id && + !s->match.product_id && + !s->match.port) { + s->needs_autoscan = false; + ldev = usb_host_find_ref(s->match.bus_num, + s->match.addr); + if (!ldev) { + error_setg(errp, "failed to find host usb device %d:%d", + s->match.bus_num, s->match.addr); + return; + } + rc = usb_host_open(s, ldev); + libusb_unref_device(ldev); + if (rc < 0) { + error_setg(errp, "failed to open host usb device %d:%d", + s->match.bus_num, s->match.addr); + return; + } + } else { + s->needs_autoscan = true; + QTAILQ_INSERT_TAIL(&hostdevs, s, next); + usb_host_auto_check(NULL); + } + s->exit.notify = usb_host_exit_notifier; qemu_add_exit_notifier(&s->exit); - - QTAILQ_INSERT_TAIL(&hostdevs, s, next); - usb_host_auto_check(NULL); } static void usb_host_instance_init(Object *obj) @@ -1019,7 +1065,9 @@ static void usb_host_handle_destroy(USBDevice *udev) USBHostDevice *s = USB_HOST_DEVICE(udev); qemu_remove_exit_notifier(&s->exit); - QTAILQ_REMOVE(&hostdevs, s, next); + if (s->needs_autoscan) { + QTAILQ_REMOVE(&hostdevs, s, next); + } usb_host_close(s); } |