aboutsummaryrefslogtreecommitdiff
path: root/hw/usb-bus.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2009-09-25 21:42:39 +0200
committerAnthony Liguori <aliguori@us.ibm.com>2009-10-05 09:32:48 -0500
commita8e662b5477a7e3659c7fc2d83db50c42b201c1d (patch)
tree12dcfa0a4ef0960eec14ff44b772c8e0a5e80061 /hw/usb-bus.c
parente3936fa574d9fbe241acdc76b5195b048567537e (diff)
usb: hook unplug into qdev, cleanups + fixes.
Hook into DeviceInfo->exit(). handle_destroy() must not free the state struct, this is handled by the new usb_qdev_exit() function now. qdev_free(usb_device) works now. Fix usb hub to qdev_free() all connected devices on unplug. Unplugging a usb hub works now. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/usb-bus.c')
-rw-r--r--hw/usb-bus.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 2cac1e85b7..d0b59dd4dd 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -50,10 +50,22 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
return rc;
}
+static int usb_qdev_exit(DeviceState *qdev)
+{
+ USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+
+ usb_device_detach(dev);
+ if (dev->info->handle_destroy) {
+ dev->info->handle_destroy(dev);
+ }
+ return 0;
+}
+
void usb_qdev_register(USBDeviceInfo *info)
{
info->qdev.bus_info = &usb_bus_info;
info->qdev.init = usb_qdev_init;
+ info->qdev.exit = usb_qdev_exit;
qdev_register(&info->qdev);
}
@@ -101,6 +113,14 @@ void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
bus->nfree++;
}
+void usb_unregister_port(USBBus *bus, USBPort *port)
+{
+ if (port->dev)
+ qdev_free(&port->dev->qdev);
+ QTAILQ_REMOVE(&bus->free, port, next);
+ bus->nfree--;
+}
+
static void do_attach(USBDevice *dev)
{
USBBus *bus = usb_bus_from_device(dev);
@@ -136,6 +156,34 @@ int usb_device_attach(USBDevice *dev)
return 0;
}
+int usb_device_detach(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ USBPort *port;
+
+ if (!dev->attached) {
+ fprintf(stderr, "Warning: tried to detach unattached usb device %s\n",
+ dev->devname);
+ return -1;
+ }
+ dev->attached--;
+
+ QTAILQ_FOREACH(port, &bus->used, next) {
+ if (port->dev == dev)
+ break;
+ }
+ assert(port != NULL);
+
+ QTAILQ_REMOVE(&bus->used, port, next);
+ bus->nused--;
+
+ usb_attach(port, NULL);
+
+ QTAILQ_INSERT_TAIL(&bus->free, port, next);
+ bus->nfree++;
+ return 0;
+}
+
int usb_device_delete_addr(int busnr, int addr)
{
USBBus *bus;
@@ -152,16 +200,9 @@ int usb_device_delete_addr(int busnr, int addr)
}
if (!port)
return -1;
-
dev = port->dev;
- QTAILQ_REMOVE(&bus->used, port, next);
- bus->nused--;
-
- usb_attach(port, NULL);
- dev->info->handle_destroy(dev);
- QTAILQ_INSERT_TAIL(&bus->free, port, next);
- bus->nfree++;
+ qdev_free(&dev->qdev);
return 0;
}