aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb-bt.c3
-rw-r--r--hw/usb-bus.c29
-rw-r--r--hw/usb-ehci.c58
-rw-r--r--hw/usb-hub.c22
-rw-r--r--usb-linux.c25
5 files changed, 98 insertions, 39 deletions
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 529fa3355d..f30eec1ea2 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -528,6 +528,9 @@ USBDevice *usb_bt_init(HCIInfo *hci)
if (!hci)
return NULL;
dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle");
+ if (!dev) {
+ return NULL;
+ }
s = DO_UPCAST(struct USBBtState, dev, dev);
s->dev.opaque = s;
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 93f640d370..8cafb76fff 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -9,6 +9,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
static char *usb_get_dev_path(DeviceState *dev);
static char *usb_get_fw_dev_path(DeviceState *qdev);
+static int usb_qdev_exit(DeviceState *qdev);
static struct BusInfo usb_bus_info = {
.name = "USB",
@@ -75,12 +76,23 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
dev->auto_attach = 1;
QLIST_INIT(&dev->strings);
rc = usb_claim_port(dev);
- if (rc == 0) {
- rc = dev->info->init(dev);
+ if (rc != 0) {
+ goto err;
}
- if (rc == 0 && dev->auto_attach) {
+ rc = dev->info->init(dev);
+ if (rc != 0) {
+ goto err;
+ }
+ if (dev->auto_attach) {
rc = usb_device_attach(dev);
+ if (rc != 0) {
+ goto err;
+ }
}
+ return 0;
+
+err:
+ usb_qdev_exit(qdev);
return rc;
}
@@ -139,10 +151,17 @@ USBDevice *usb_create(USBBus *bus, const char *name)
USBDevice *usb_create_simple(USBBus *bus, const char *name)
{
USBDevice *dev = usb_create(bus, name);
+ int rc;
+
if (!dev) {
- hw_error("Failed to create USB device '%s'\n", name);
+ error_report("Failed to create USB device '%s'\n", name);
+ return NULL;
+ }
+ rc = qdev_init(&dev->qdev);
+ if (rc < 0) {
+ error_report("Failed to initialize USB device '%s'\n", name);
+ return NULL;
}
- qdev_init_nofail(&dev->qdev);
return dev;
}
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 3eea94d09e..a946e1d1fd 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -437,37 +437,39 @@ struct EHCIState {
} while(0)
static const char *ehci_state_names[] = {
- [ EST_INACTIVE ] = "INACTIVE",
- [ EST_ACTIVE ] = "ACTIVE",
- [ EST_EXECUTING ] = "EXECUTING",
- [ EST_SLEEPING ] = "SLEEPING",
- [ EST_WAITLISTHEAD ] = "WAITLISTHEAD",
- [ EST_FETCHENTRY ] = "FETCH ENTRY",
- [ EST_FETCHQH ] = "FETCH QH",
- [ EST_FETCHITD ] = "FETCH ITD",
- [ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE",
- [ EST_FETCHQTD ] = "FETCH QTD",
- [ EST_EXECUTE ] = "EXECUTE",
- [ EST_WRITEBACK ] = "WRITEBACK",
- [ EST_HORIZONTALQH ] = "HORIZONTALQH",
+ [EST_INACTIVE] = "INACTIVE",
+ [EST_ACTIVE] = "ACTIVE",
+ [EST_EXECUTING] = "EXECUTING",
+ [EST_SLEEPING] = "SLEEPING",
+ [EST_WAITLISTHEAD] = "WAITLISTHEAD",
+ [EST_FETCHENTRY] = "FETCH ENTRY",
+ [EST_FETCHQH] = "FETCH QH",
+ [EST_FETCHITD] = "FETCH ITD",
+ [EST_ADVANCEQUEUE] = "ADVANCEQUEUE",
+ [EST_FETCHQTD] = "FETCH QTD",
+ [EST_EXECUTE] = "EXECUTE",
+ [EST_WRITEBACK] = "WRITEBACK",
+ [EST_HORIZONTALQH] = "HORIZONTALQH",
};
static const char *ehci_mmio_names[] = {
- [ CAPLENGTH ] = "CAPLENGTH",
- [ HCIVERSION ] = "HCIVERSION",
- [ HCSPARAMS ] = "HCSPARAMS",
- [ HCCPARAMS ] = "HCCPARAMS",
- [ USBCMD ] = "USBCMD",
- [ USBSTS ] = "USBSTS",
- [ USBINTR ] = "USBINTR",
- [ FRINDEX ] = "FRINDEX",
- [ PERIODICLISTBASE ] = "P-LIST BASE",
- [ ASYNCLISTADDR ] = "A-LIST ADDR",
- [ PORTSC_BEGIN ] = "PORTSC #0",
- [ PORTSC_BEGIN + 4] = "PORTSC #1",
- [ PORTSC_BEGIN + 8] = "PORTSC #2",
- [ PORTSC_BEGIN + 12] = "PORTSC #3",
- [ CONFIGFLAG ] = "CONFIGFLAG",
+ [CAPLENGTH] = "CAPLENGTH",
+ [HCIVERSION] = "HCIVERSION",
+ [HCSPARAMS] = "HCSPARAMS",
+ [HCCPARAMS] = "HCCPARAMS",
+ [USBCMD] = "USBCMD",
+ [USBSTS] = "USBSTS",
+ [USBINTR] = "USBINTR",
+ [FRINDEX] = "FRINDEX",
+ [PERIODICLISTBASE] = "P-LIST BASE",
+ [ASYNCLISTADDR] = "A-LIST ADDR",
+ [PORTSC_BEGIN] = "PORTSC #0",
+ [PORTSC_BEGIN + 4] = "PORTSC #1",
+ [PORTSC_BEGIN + 8] = "PORTSC #2",
+ [PORTSC_BEGIN + 12] = "PORTSC #3",
+ [PORTSC_BEGIN + 16] = "PORTSC #4",
+ [PORTSC_BEGIN + 20] = "PORTSC #5",
+ [CONFIGFLAG] = "CONFIGFLAG",
};
static const char *nr2str(const char **n, size_t len, uint32_t nr)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 3eb0f1aa0a..e1959372e7 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -171,6 +171,8 @@ static void usb_hub_detach(USBPort *port1)
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
+ usb_wakeup(&s->dev);
+
/* Let upstream know the device on this port is gone */
s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@@ -220,7 +222,22 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
static void usb_hub_handle_reset(USBDevice *dev)
{
- /* XXX: do it */
+ USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+ USBHubPort *port;
+ int i;
+
+ for (i = 0; i < NUM_PORTS; i++) {
+ port = s->ports + i;
+ port->wPortStatus = PORT_STAT_POWER;
+ port->wPortChange = 0;
+ if (port->port.dev && port->port.dev->attached) {
+ port->wPortStatus |= PORT_STAT_CONNECTION;
+ port->wPortChange |= PORT_STAT_C_CONNECTION;
+ if (port->port.dev->speed == USB_SPEED_LOW) {
+ port->wPortStatus |= PORT_STAT_LOW_SPEED;
+ }
+ }
+ }
}
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
@@ -495,9 +512,8 @@ static int usb_hub_initfn(USBDevice *dev)
&port->port, s, i, &usb_hub_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_port_location(&port->port, dev->port, i+1);
- port->wPortStatus = PORT_STAT_POWER;
- port->wPortChange = 0;
}
+ usb_hub_handle_reset(dev);
return 0;
}
diff --git a/usb-linux.c b/usb-linux.c
index d4426ea730..ab4c6930ca 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -148,6 +148,25 @@ static int usb_host_read_file(char *line, size_t line_size,
const char *device_file, const char *device_name);
static int usb_linux_update_endp_table(USBHostDevice *s);
+static int usb_host_do_reset(USBHostDevice *dev)
+{
+ struct timeval s, e;
+ uint32_t usecs;
+ int ret;
+
+ gettimeofday(&s, NULL);
+ ret = ioctl(dev->fd, USBDEVFS_RESET);
+ gettimeofday(&e, NULL);
+ usecs = (e.tv_sec - s.tv_sec) * 1000000;
+ usecs += e.tv_usec - s.tv_usec;
+ if (usecs > 1000000) {
+ /* more than a second, something is fishy, broken usb device? */
+ fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
+ dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
+ }
+ return ret;
+}
+
static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
{
struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
@@ -606,7 +625,7 @@ static void usb_host_handle_reset(USBDevice *dev)
trace_usb_host_reset(s->bus_num, s->addr);
- ioctl(s->fd, USBDEVFS_RESET);
+ usb_host_do_reset(s);;
usb_host_claim_interfaces(s, 0);
usb_linux_update_endp_table(s);
@@ -1370,7 +1389,7 @@ static int usb_host_close(USBHostDevice *dev)
if (dev->dev.attached) {
usb_device_detach(&dev->dev);
}
- ioctl(dev->fd, USBDEVFS_RESET);
+ usb_host_do_reset(dev);
close(dev->fd);
dev->fd = -1;
return 0;
@@ -1381,7 +1400,7 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
USBHostDevice *s = container_of(n, USBHostDevice, exit);
if (s->fd != -1) {
- ioctl(s->fd, USBDEVFS_RESET);
+ usb_host_do_reset(s);;
}
}