Merge remote-tracking branch 'kraxel/usb.16' into staging

This commit is contained in:
Anthony Liguori 2011-06-15 09:03:22 -05:00
commit f897235e0a
12 changed files with 1023 additions and 579 deletions

View file

@ -31,6 +31,91 @@ a complete example:
This attaches a usb tablet to the UHCI adapter and a usb mass storage
device to the EHCI adapter.
More USB tips & tricks
======================
Recently the usb pass through driver (also known as usb-host) and the
qemu usb subsystem gained a few capabilities which are available only
via qdev properties, i,e. when using '-device'.
physical port addressing
------------------------
First you can (for all usb devices) specify the physical port where
the device will show up in the guest. This can be done using the
"port" property. UHCI has two root ports (1,2). EHCI has four root
ports (1-4), the emulated (1.1) USB hub has eight ports.
Plugging a tablet into UHCI port 1 works like this:
-device usb-tablet,bus=usb.0,port=1
Plugging a hub into UHCI port 2 works like this:
-device usb-hub,bus=usb.0,port=2
Plugging a virtual usb stick into port 4 of the hub just plugged works
this way:
-device usb-storage,bus=usb.0,port=2.4,drive=...
You can do basically the same in the monitor using the device_add
command. If you want to unplug devices too you should specify some
unique id which you can use to refer to the device ...
(qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
(qemu) device_del my-tablet
... when unplugging it with device_del.
USB pass through hints
----------------------
The usb-host driver has a bunch of properties to specify the device
which should be passed to the guest:
hostbus=<nr> -- Specifies the bus number the device must be attached
to.
hostaddr=<nr> -- Specifies the device address the device got
assigned by the guest os.
hostport=<str> -- Specifies the physical port the device is attached
to.
vendorid=<hexnr> -- Specifies the vendor ID of the device.
productid=<hexnr> -- Specifies the product ID of the device.
In theory you can combine all these properties as you like. In
practice only a few combinations are useful:
(1) vendorid+productid -- match for a specific device, pass it to
the guest when it shows up somewhere in the host.
(2) hostbus+hostport -- match for a specific physical port in the
host, any device which is plugged in there gets passed to the
guest.
(3) hostbus+hostaddr -- most useful for ad-hoc pass through as the
hostaddr isn't stable, the next time you plug in the device it
gets a new one ...
Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by
EHCI. That means a device plugged into the very same physical port
may show up on different busses depending on the speed. The port I'm
using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
for 1.1 devices. Passing through any device plugged into that port
and also assign them to the correct bus can be done this way:
qemu -M pc ${otheroptions} \
-usb \
-device usb-ehci,id=ehci \
-device usb-host,bus=usb.0,hostbus=3,hostport=1 \
-device usb-host,bus=ehci.0,hostbus=1,hostport=1
enjoy,
Gerd

View file

@ -247,10 +247,18 @@ static void softusb_attach(USBPort *port)
{
}
static void softusb_device_destroy(USBBus *bus, USBDevice *dev)
{
}
static USBPortOps softusb_ops = {
.attach = softusb_attach,
};
static USBBusOps softusb_bus_ops = {
.device_destroy = softusb_device_destroy,
};
static void milkymist_softusb_reset(DeviceState *d)
{
MilkymistSoftUsbState *s =
@ -294,7 +302,7 @@ static int milkymist_softusb_init(SysBusDevice *dev)
qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
/* create our usb bus */
usb_bus_new(&s->usbbus, NULL);
usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
/* our two ports */
usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,

View file

@ -39,9 +39,10 @@ const VMStateDescription vmstate_usb_device = {
}
};
void usb_bus_new(USBBus *bus, DeviceState *host)
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
{
qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
bus->ops = ops;
bus->busnr = next_usb_bus++;
bus->qbus.allow_hotplug = 1; /* Yes, we can */
QTAILQ_INIT(&bus->free);
@ -81,8 +82,12 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int usb_qdev_exit(DeviceState *qdev)
{
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
USBBus *bus = usb_bus_from_device(dev);
usb_device_detach(dev);
if (dev->attached) {
usb_device_detach(dev);
}
bus->ops->device_destroy(bus, dev);
if (dev->info->handle_destroy) {
dev->info->handle_destroy(dev);
}
@ -270,6 +275,7 @@ static const char *usb_speed(unsigned int speed)
[ USB_SPEED_LOW ] = "1.5",
[ USB_SPEED_FULL ] = "12",
[ USB_SPEED_HIGH ] = "480",
[ USB_SPEED_SUPER ] = "5000",
};
if (speed >= ARRAY_SIZE(txt))
return "?";

File diff suppressed because it is too large Load diff

View file

@ -142,7 +142,6 @@ static const USBDescIface desc_iface_tablet = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0x01, /* boot */
.bInterfaceProtocol = 0x02,
.ndesc = 1,
.descs = (USBDescOther[]) {
@ -782,13 +781,13 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
goto fail;
break;
case GET_PROTOCOL:
if (s->kind != USB_KEYBOARD)
if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
goto fail;
ret = 1;
data[0] = s->protocol;
break;
case SET_PROTOCOL:
if (s->kind != USB_KEYBOARD)
if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
goto fail;
ret = 0;
s->protocol = value;

View file

@ -262,6 +262,7 @@
static void musb_attach(USBPort *port);
static void musb_detach(USBPort *port);
static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
static void musb_device_destroy(USBBus *bus, USBDevice *dev);
static USBPortOps musb_port_ops = {
.attach = musb_attach,
@ -269,6 +270,10 @@ static USBPortOps musb_port_ops = {
.complete = musb_schedule_cb,
};
static USBBusOps musb_bus_ops = {
.device_destroy = musb_device_destroy,
};
typedef struct MUSBPacket MUSBPacket;
typedef struct MUSBEndPoint MUSBEndPoint;
@ -361,7 +366,7 @@ struct MUSBState *musb_init(qemu_irq *irqs)
s->ep[i].epnum = i;
}
usb_bus_new(&s->bus, NULL /* FIXME */);
usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_port_location(&s->port, NULL, 1);
@ -778,6 +783,22 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
musb_rx_intr_set(s, epnum, 1);
}
static void musb_device_destroy(USBBus *bus, USBDevice *dev)
{
MUSBState *s = container_of(bus, MUSBState, bus);
int ep, dir;
for (ep = 0; ep < 16; ep++) {
for (dir = 0; dir < 2; dir++) {
if (s->ep[ep].packey[dir].p.owner != dev) {
continue;
}
usb_cancel_packet(&s->ep[ep].packey[dir].p);
/* status updates needed here? */
}
}
}
static void musb_tx_rdy(MUSBState *s, int epnum)
{
MUSBEndPoint *ep = s->ep + epnum;

View file

@ -367,6 +367,22 @@ static void ohci_detach(USBPort *port1)
ohci_set_interrupt(s, OHCI_INTR_RHSC);
}
static void ohci_wakeup(USBDevice *dev)
{
USBBus *bus = usb_bus_from_device(dev);
OHCIState *s = container_of(bus, OHCIState, bus);
int portnum = dev->port->index;
OHCIPort *port = &s->rhport[portnum];
if (port->ctrl & OHCI_PORT_PSS) {
DPRINTF("usb-ohci: port %d: wakeup\n", portnum);
port->ctrl |= OHCI_PORT_PSSC;
port->ctrl &= ~OHCI_PORT_PSS;
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
ohci_set_interrupt(s, OHCI_INTR_RD);
}
}
}
/* Reset the controller */
static void ohci_reset(void *opaque)
{
@ -1575,6 +1591,10 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
ohci->hcca = val & OHCI_HCCA_MASK;
break;
case 7: /* HcPeriodCurrentED */
/* Ignore writes to this read-only register, Linux does them */
break;
case 8: /* HcControlHeadED */
ohci->ctrl_head = val & OHCI_EDPTR_MASK;
break;
@ -1644,6 +1664,16 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
}
}
static void ohci_device_destroy(USBBus *bus, USBDevice *dev)
{
OHCIState *ohci = container_of(bus, OHCIState, bus);
if (ohci->async_td && ohci->usb_packet.owner == dev) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
}
/* Only dword reads are defined on OHCI register space */
static CPUReadMemoryFunc * const ohci_readfn[3]={
ohci_mem_read,
@ -1661,9 +1691,14 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
.detach = ohci_detach,
.wakeup = ohci_wakeup,
.complete = ohci_async_complete_packet,
};
static USBBusOps ohci_bus_ops = {
.device_destroy = ohci_device_destroy,
};
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
int num_ports, uint32_t localmem_base)
{
@ -1691,7 +1726,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->name = dev->info->name;
usb_bus_new(&ohci->bus, dev);
usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
ohci->num_ports = num_ports;
for (i = 0; i < num_ports; i++) {
usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,

View file

@ -234,6 +234,19 @@ static void uhci_async_validate_end(UHCIState *s)
}
}
static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
{
UHCIAsync *curr, *n;
QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
if (curr->packet.owner != dev) {
continue;
}
uhci_async_unlink(s, curr);
uhci_async_cancel(s, curr);
}
}
static void uhci_async_cancel_all(UHCIState *s)
{
UHCIAsync *curr, *n;
@ -411,6 +424,8 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
case 0x00:
if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
/* start frame processing */
s->expire_time = qemu_get_clock_ns(vm_clock) +
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
s->status &= ~UHCI_STS_HCHALTED;
} else if (!(val & UHCI_CMD_RS)) {
@ -1081,6 +1096,13 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
static void uhci_device_destroy(USBBus *bus, USBDevice *dev)
{
UHCIState *s = container_of(bus, UHCIState, bus);
uhci_async_cancel_device(s, dev);
}
static USBPortOps uhci_port_ops = {
.attach = uhci_attach,
.detach = uhci_detach,
@ -1088,6 +1110,10 @@ static USBPortOps uhci_port_ops = {
.complete = uhci_async_complete,
};
static USBBusOps uhci_bus_ops = {
.device_destroy = uhci_device_destroy,
};
static int usb_uhci_common_initfn(UHCIState *s)
{
uint8_t *pci_conf = s->dev.config;
@ -1098,17 +1124,15 @@ static int usb_uhci_common_initfn(UHCIState *s)
pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
/* TODO: reset value should be 0. */
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
usb_bus_new(&s->bus, &s->dev.qdev);
usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_port_location(&s->ports[i].port, NULL, i+1);
}
s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
s->expire_time = qemu_get_clock_ns(vm_clock) +
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
s->num_ports_vmstate = NB_PORTS;
QTAILQ_INIT(&s->async_pending);

View file

@ -26,6 +26,12 @@
#include "qdev.h"
#include "qemu-queue.h"
/* Constants related to the USB / PCI interaction */
#define USB_SBRN 0x60 /* Serial Bus Release Number Register */
#define USB_RELEASE_1 0x10 /* USB 1.0 */
#define USB_RELEASE_2 0x20 /* USB 2.0 */
#define USB_RELEASE_3 0x30 /* USB 3.0 */
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
@ -132,6 +138,7 @@
#define USB_ENDPOINT_XFER_INT 3
typedef struct USBBus USBBus;
typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
typedef struct USBDeviceInfo USBDeviceInfo;
@ -323,6 +330,7 @@ void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
struct USBBus {
BusState qbus;
USBBusOps *ops;
int busnr;
int nfree;
int nused;
@ -331,7 +339,11 @@ struct USBBus {
QTAILQ_ENTRY(USBBus) next;
};
void usb_bus_new(USBBus *bus, DeviceState *host);
struct USBBusOps {
void (*device_destroy)(USBBus *bus, USBDevice *dev);
};
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
USBBus *usb_bus_find(int busnr);
void usb_qdev_register(USBDeviceInfo *info);
void usb_qdev_register_many(USBDeviceInfo *info);

View file

@ -194,6 +194,26 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g
disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
# hw/usb-ehci.c
disable usb_ehci_reset(void) "=== RESET ==="
disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
disable usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
disable usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x"
disable usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ %08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
disable usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ %08x - c %d, h %d, dtc %d, i %d"
disable usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t next, uint32_t altnext) "q %p - QTD @ %08x: next %08x altnext %08x"
disable usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
disable usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
disable usb_ehci_itd(uint32_t addr, uint32_t next, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
disable usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
disable usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"

View file

@ -115,7 +115,7 @@ typedef struct USBHostDevice {
USBDevice dev;
int fd;
uint8_t descr[1024];
uint8_t descr[8192];
int descr_len;
int configuration;
int ninterfaces;
@ -267,6 +267,14 @@ static void async_free(AsyncURB *aurb)
qemu_free(aurb);
}
static void do_disconnect(USBHostDevice *s)
{
printf("husb: device %d.%d disconnected\n",
s->bus_num, s->addr);
usb_host_close(s);
usb_host_auto_check(NULL);
}
static void async_complete(void *opaque)
{
USBHostDevice *s = opaque;
@ -281,10 +289,7 @@ static void async_complete(void *opaque)
return;
}
if (errno == ENODEV && !s->closing) {
printf("husb: device %d.%d disconnected\n",
s->bus_num, s->addr);
usb_host_close(s);
usb_host_auto_check(NULL);
do_disconnect(s);
return;
}
@ -358,6 +363,7 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
{
const char *op = NULL;
int dev_descr_len, config_descr_len;
int interface, nb_interfaces;
int ret, i;
@ -370,7 +376,8 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
i = 0;
dev_descr_len = dev->descr[0];
if (dev_descr_len > dev->descr_len) {
goto fail;
fprintf(stderr, "husb: update iface failed. descr too short\n");
return 0;
}
i += dev_descr_len;
@ -398,7 +405,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
if (i >= dev->descr_len) {
fprintf(stderr,
"husb: update iface failed. no matching configuration\n");
goto fail;
return 0;
}
nb_interfaces = dev->descr[i + 4];
@ -410,9 +417,9 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
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) {
perror("USBDEVFS_DISCONNECT");
goto fail;
}
}
@ -421,6 +428,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
/* XXX: only grab if all interfaces are free */
for (interface = 0; interface < nb_interfaces; interface++) {
op = "USBDEVFS_CLAIMINTERFACE";
ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
if (ret < 0) {
if (errno == EBUSY) {
@ -428,8 +436,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
} else {
perror("husb: failed to claim interface");
}
fail:
return 0;
goto fail;
}
}
@ -439,6 +446,13 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
dev->ninterfaces = nb_interfaces;
dev->configuration = configuration;
return 1;
fail:
if (errno == ENODEV) {
do_disconnect(dev);
}
perror(op);
return 0;
}
static int usb_host_release_interfaces(USBHostDevice *s)
@ -1015,6 +1029,11 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
devep = descriptors[i + 2];
if ((devep & 0x0f) == 0) {
fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
return 1;
}
switch (descriptors[i + 3] & 0x3) {
case 0x00:
type = USBDEVFS_URB_TYPE_CONTROL;
@ -1043,10 +1062,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
static int usb_host_open(USBHostDevice *dev, int bus_num,
int addr, char *port, const char *prod_name)
int addr, char *port, const char *prod_name, int speed)
{
int fd = -1, ret;
struct usbdevfs_connectinfo ci;
char buf[1024];
if (dev->fd != -1) {
@ -1101,24 +1119,29 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
goto fail;
}
ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
if (ret < 0) {
perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
goto fail;
}
printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
ret = usb_linux_update_endp_table(dev);
if (ret) {
goto fail;
}
if (ci.slow) {
dev->dev.speed = USB_SPEED_LOW;
} else {
dev->dev.speed = USB_SPEED_HIGH;
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;
printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
if (!prod_name || prod_name[0] == '\0') {
snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
@ -1135,9 +1158,9 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
return 0;
fail:
dev->fd = -1;
if (fd != -1) {
close(fd);
if (dev->fd != -1) {
close(dev->fd);
dev->fd = -1;
}
return -1;
}
@ -1146,7 +1169,7 @@ static int usb_host_close(USBHostDevice *dev)
{
int i;
if (dev->fd == -1) {
if (dev->fd == -1 || !dev->dev.attached) {
return -1;
}
@ -1332,7 +1355,8 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
}
device_count = 0;
bus_num = addr = speed = class_id = product_id = vendor_id = 0;
bus_num = addr = class_id = product_id = vendor_id = 0;
speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
for(;;) {
if (fgets(line, sizeof(line), f) == NULL) {
break;
@ -1360,7 +1384,9 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
goto fail;
}
if (!strcmp(buf, "480")) {
if (!strcmp(buf, "5000")) {
speed = USB_SPEED_SUPER;
} else if (!strcmp(buf, "480")) {
speed = USB_SPEED_HIGH;
} else if (!strcmp(buf, "1.5")) {
speed = USB_SPEED_LOW;
@ -1504,7 +1530,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
goto the_end;
}
if (!strcmp(line, "480\n")) {
if (!strcmp(line, "5000\n")) {
speed = USB_SPEED_SUPER;
} else if (!strcmp(line, "480\n")) {
speed = USB_SPEED_HIGH;
} else if (!strcmp(line, "1.5\n")) {
speed = USB_SPEED_LOW;
@ -1642,7 +1670,8 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
}
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
usb_host_open(s, bus_num, addr, port, product_name);
usb_host_open(s, bus_num, addr, port, product_name, speed);
break;
}
return 0;
@ -1781,6 +1810,9 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
case USB_SPEED_HIGH:
speed_str = "480";
break;
case USB_SPEED_SUPER:
speed_str = "5000";
break;
default:
speed_str = "?";
break;

6
vl.c
View file

@ -925,9 +925,13 @@ static int usb_device_add(const char *devname)
goto done;
/* the other ones */
#ifndef CONFIG_LINUX
/* only the linux version is qdev-ified, usb-bsd still needs this */
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(p);
} else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
} else
#endif
if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
dev = usb_bt_init(devname[2] ? hci_init(p) :
bt_new_hci(qemu_find_bt_vlan(0)));
} else {