diff options
author | SeokYeon Hwang <syeon.hwang@samsung.com> | 2016-11-30 14:11:48 +0900 |
---|---|---|
committer | SeokYeon Hwang <syeon.hwang@samsung.com> | 2016-11-30 14:11:58 +0900 |
commit | 2371603ef207b015cc29728296b21cb1722d8ae6 (patch) | |
tree | 25cbb62daf29066fa874b9a4b8f754bc18187806 /hw/usb/host-libusb.c | |
parent | d5df306aedcc13cf5a2463ddf858c8d718a788d5 (diff) | |
parent | d4dcb59384ab4433702f015fdddda1eff8e3927f (diff) | |
download | qemu-2371603ef207b015cc29728296b21cb1722d8ae6.tar.gz qemu-2371603ef207b015cc29728296b21cb1722d8ae6.tar.bz2 qemu-2371603ef207b015cc29728296b21cb1722d8ae6.zip |
Merge branch 'develop_qemu_2.7' into develop
Change-Id: Ibae70e3c0d1d88632903f98be114f47af9ca7502
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
Diffstat (limited to 'hw/usb/host-libusb.c')
-rw-r--r-- | hw/usb/host-libusb.c | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 6458a94485..e94672c155 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -34,7 +34,9 @@ */ #include "qemu/osdep.h" +#ifndef CONFIG_WIN32 #include <poll.h> +#endif #include <libusb.h> #include "qapi/error.h" @@ -79,6 +81,7 @@ struct USBHostDevice { uint32_t iso_urb_frames; uint32_t options; uint32_t loglevel; + bool needs_autoscan; /* state */ QTAILQ_ENTRY(USBHostDevice) next; @@ -204,6 +207,8 @@ static const char *err_names[] = { static libusb_context *ctx; static uint32_t loglevel; +#ifndef CONFIG_WIN32 + static void usb_host_handle_fd(void *opaque) { struct timeval tv = { 0, 0 }; @@ -223,10 +228,14 @@ static void usb_host_del_fd(int fd, void *user_data) qemu_set_fd_handler(fd, NULL, NULL, NULL); } +#endif /* !CONFIG_WIN32 */ + static int usb_host_init(void) { +#ifndef CONFIG_WIN32 const struct libusb_pollfd **poll; - int i, rc; +#endif + int rc; if (ctx) { return 0; @@ -236,17 +245,21 @@ static int usb_host_init(void) return -1; } libusb_set_debug(ctx, loglevel); - +#ifdef CONFIG_WIN32 + /* FIXME: add support for Windows. */ +#else libusb_set_pollfd_notifiers(ctx, usb_host_add_fd, usb_host_del_fd, ctx); poll = libusb_get_pollfds(ctx); if (poll) { + int i; for (i = 0; poll[i] != NULL; i++) { usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx); } } free(poll); +#endif return 0; } @@ -346,7 +359,7 @@ static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p) return NULL; } -static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer) +static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer) { USBHostRequest *r = xfer->user_data; USBHostDevice *s = r->host; @@ -379,7 +392,7 @@ out: } } -static void usb_host_req_complete_data(struct libusb_transfer *xfer) +static void LIBUSB_CALL usb_host_req_complete_data(struct libusb_transfer *xfer) { USBHostRequest *r = xfer->user_data; USBHostDevice *s = r->host; @@ -435,7 +448,8 @@ static void usb_host_req_abort(USBHostRequest *r) /* ------------------------------------------------------------------------ */ -static void usb_host_req_complete_iso(struct libusb_transfer *transfer) +static void LIBUSB_CALL +usb_host_req_complete_iso(struct libusb_transfer *transfer) { USBHostIsoXfer *xfer = transfer->user_data; @@ -963,9 +977,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"); @@ -986,11 +1023,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) @@ -1008,7 +1067,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); } |