usb: add hostdevice property to usb-host

The new property allows to specify usb host device name.  Uses standard
qemu_open(), so both file system path (/dev/bus/usb/$bus/$dev on linux)
and file descriptor passing can be used.

Requires libusb 1.0.23 or newer.  The hostdevice property is only
present in case qemu is compiled against a new enough library version,
so the presence of the property can be used for feature detection.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-Id: <20200605125952.13113-1-kraxel@redhat.com>
This commit is contained in:
Gerd Hoffmann 2020-06-05 14:59:52 +02:00
parent 5c24bce305
commit 9f815e83e9
2 changed files with 62 additions and 14 deletions

View File

@ -80,6 +80,7 @@ struct USBHostDevice {
/* properties */ /* properties */
struct USBAutoFilter match; struct USBAutoFilter match;
char *hostdevice;
int32_t bootindex; int32_t bootindex;
uint32_t iso_urb_count; uint32_t iso_urb_count;
uint32_t iso_urb_frames; uint32_t iso_urb_frames;
@ -97,6 +98,7 @@ struct USBHostDevice {
int addr; int addr;
char port[16]; char port[16];
int hostfd;
libusb_device *dev; libusb_device *dev;
libusb_device_handle *dh; libusb_device_handle *dh;
struct libusb_device_descriptor ddesc; struct libusb_device_descriptor ddesc;
@ -880,26 +882,45 @@ static void usb_host_ep_update(USBHostDevice *s)
libusb_free_config_descriptor(conf); libusb_free_config_descriptor(conf);
} }
static int usb_host_open(USBHostDevice *s, libusb_device *dev) static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd)
{ {
USBDevice *udev = USB_DEVICE(s); USBDevice *udev = USB_DEVICE(s);
int bus_num = libusb_get_bus_number(dev); int bus_num = 0;
int addr = libusb_get_device_address(dev); int addr = 0;
int rc; int rc;
Error *local_err = NULL; Error *local_err = NULL;
if (s->bh_postld_pending) { if (s->bh_postld_pending) {
return -1; return -1;
} }
trace_usb_host_open_started(bus_num, addr);
if (s->dh != NULL) { if (s->dh != NULL) {
goto fail; goto fail;
} }
rc = libusb_open(dev, &s->dh);
if (rc != 0) { if (dev) {
goto fail; bus_num = libusb_get_bus_number(dev);
addr = libusb_get_device_address(dev);
trace_usb_host_open_started(bus_num, addr);
rc = libusb_open(dev, &s->dh);
if (rc != 0) {
goto fail;
}
} else {
#if LIBUSB_API_VERSION >= 0x01000107
trace_usb_host_open_hostfd(hostfd);
rc = libusb_wrap_sys_device(ctx, hostfd, &s->dh);
if (rc != 0) {
goto fail;
}
s->hostfd = hostfd;
dev = libusb_get_device(s->dh);
bus_num = libusb_get_bus_number(dev);
addr = libusb_get_device_address(dev);
#else
g_assert_not_reached();
#endif
} }
s->dev = dev; s->dev = dev;
@ -988,6 +1009,11 @@ static int usb_host_close(USBHostDevice *s)
s->dh = NULL; s->dh = NULL;
s->dev = NULL; s->dev = NULL;
if (s->hostfd != -1) {
close(s->hostfd);
s->hostfd = -1;
}
usb_host_auto_check(NULL); usb_host_auto_check(NULL);
return 0; return 0;
} }
@ -1025,9 +1051,6 @@ static libusb_device *usb_host_find_ref(int bus, int addr)
libusb_device *ret = NULL; libusb_device *ret = NULL;
int i, n; int i, n;
if (usb_host_init() != 0) {
return NULL;
}
n = libusb_get_device_list(ctx, &devs); n = libusb_get_device_list(ctx, &devs);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (libusb_get_bus_number(devs[i]) == bus && if (libusb_get_bus_number(devs[i]) == bus &&
@ -1046,6 +1069,10 @@ static void usb_host_realize(USBDevice *udev, Error **errp)
libusb_device *ldev; libusb_device *ldev;
int rc; int rc;
if (usb_host_init() != 0) {
error_setg(errp, "failed to init libusb");
return;
}
if (s->match.vendor_id > 0xffff) { if (s->match.vendor_id > 0xffff) {
error_setg(errp, "vendorid out of range"); error_setg(errp, "vendorid out of range");
return; return;
@ -1064,7 +1091,24 @@ static void usb_host_realize(USBDevice *udev, Error **errp)
udev->auto_attach = 0; udev->auto_attach = 0;
QTAILQ_INIT(&s->requests); QTAILQ_INIT(&s->requests);
QTAILQ_INIT(&s->isorings); QTAILQ_INIT(&s->isorings);
s->hostfd = -1;
#if LIBUSB_API_VERSION >= 0x01000107
if (s->hostdevice) {
int fd;
s->needs_autoscan = false;
fd = qemu_open(s->hostdevice, O_RDWR);
if (fd < 0) {
error_setg_errno(errp, errno, "failed to open %s", s->hostdevice);
return;
}
rc = usb_host_open(s, NULL, fd);
if (rc < 0) {
error_setg(errp, "failed to open host usb device %s", s->hostdevice);
return;
}
} else
#endif
if (s->match.addr && s->match.bus_num && if (s->match.addr && s->match.bus_num &&
!s->match.vendor_id && !s->match.vendor_id &&
!s->match.product_id && !s->match.product_id &&
@ -1077,7 +1121,7 @@ static void usb_host_realize(USBDevice *udev, Error **errp)
s->match.bus_num, s->match.addr); s->match.bus_num, s->match.addr);
return; return;
} }
rc = usb_host_open(s, ldev); rc = usb_host_open(s, ldev, 0);
libusb_unref_device(ldev); libusb_unref_device(ldev);
if (rc < 0) { if (rc < 0) {
error_setg(errp, "failed to open host usb device %d:%d", error_setg(errp, "failed to open host usb device %d:%d",
@ -1605,6 +1649,9 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_STRING("hostport", USBHostDevice, match.port), DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
DEFINE_PROP_UINT32("vendorid", USBHostDevice, match.vendor_id, 0), DEFINE_PROP_UINT32("vendorid", USBHostDevice, match.vendor_id, 0),
DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0), DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
#if LIBUSB_API_VERSION >= 0x01000107
DEFINE_PROP_STRING("hostdevice", USBHostDevice, hostdevice),
#endif
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32), DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
DEFINE_PROP_BOOL("guest-reset", USBHostDevice, DEFINE_PROP_BOOL("guest-reset", USBHostDevice,
@ -1723,7 +1770,7 @@ static void usb_host_auto_check(void *unused)
if (s->dh != NULL) { if (s->dh != NULL) {
continue; continue;
} }
if (usb_host_open(s, devs[i]) < 0) { if (usb_host_open(s, devs[i], 0) < 0) {
s->errcount++; s->errcount++;
continue; continue;
} }

View File

@ -291,6 +291,7 @@ usb_mtp_file_monitor_event(int dev, const char *path, const char *s) "dev %d, pa
# host-libusb.c # host-libusb.c
usb_host_open_started(int bus, int addr) "dev %d:%d" usb_host_open_started(int bus, int addr) "dev %d:%d"
usb_host_open_hostfd(int hostfd) "hostfd %d"
usb_host_open_success(int bus, int addr) "dev %d:%d" usb_host_open_success(int bus, int addr) "dev %d:%d"
usb_host_open_failure(int bus, int addr) "dev %d:%d" usb_host_open_failure(int bus, int addr) "dev %d:%d"
usb_host_close(int bus, int addr) "dev %d:%d" usb_host_close(int bus, int addr) "dev %d:%d"