aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-10-06 10:34:05 +0200
committerAvi Kivity <avi@redhat.com>2009-10-06 10:34:05 +0200
commitac7e70d61b19ae6971d98424b248b137fbc96272 (patch)
tree58f5ea42056064ecde22b561716307dd96b03886
parentMerge commit 'e3936fa574d9fbe241acdc76b5195b048567537e' into upstream-merge (diff)
parentpci: windup acpi-based hotplug (diff)
downloadqemu-kvm-ac7e70d61b19ae6971d98424b248b137fbc96272.tar.gz
qemu-kvm-ac7e70d61b19ae6971d98424b248b137fbc96272.tar.bz2
qemu-kvm-ac7e70d61b19ae6971d98424b248b137fbc96272.zip
Merge commit '3f84865ade594a2ec1ef613ab5fd11949f3d49de' into upstream-merge
* commit '3f84865ade594a2ec1ef613ab5fd11949f3d49de': pci: windup acpi-based hotplug pci: hotplug windup scsi: hotplug windup usb: hotplug windup qdev hotplug: infrastructure and monitor commands. switch qemu-config to qemu_error usb: hook unplug into qdev, cleanups + fixes. Conflicts: hw/acpi.c hw/pc.c hw/pc.h hw/pci-hotplug.c sysemu.h Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--hw/acpi.c41
-rw-r--r--hw/pc.c3
-rw-r--r--hw/pc.h2
-rw-r--r--hw/pci-hotplug.c17
-rw-r--r--hw/pci.c25
-rw-r--r--hw/pci.h2
-rw-r--r--hw/qdev.c79
-rw-r--r--hw/qdev.h12
-rw-r--r--hw/scsi-bus.c2
-rw-r--r--hw/usb-bt.c1
-rw-r--r--hw/usb-bus.c59
-rw-r--r--hw/usb-hid.c1
-rw-r--r--hw/usb-hub.c6
-rw-r--r--hw/usb-msd.c3
-rw-r--r--hw/usb-serial.c1
-rw-r--r--hw/usb-wacom.c1
-rw-r--r--hw/usb.h2
-rw-r--r--qemu-config.c9
-rw-r--r--qemu-monitor.hx20
-rw-r--r--sysemu.h5
-rw-r--r--vl.c2
21 files changed, 227 insertions, 66 deletions
diff --git a/hw/acpi.c b/hw/acpi.c
index 70953a735..d67316891 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -713,11 +713,21 @@ static uint32_t pciej_read(void *opaque, uint32_t addr)
static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
{
-#if defined (TARGET_I386)
+ BusState *bus = opaque;
+ DeviceState *qdev;
+ PCIDevice *dev;
int slot = ffs(val) - 1;
- pci_device_hot_remove_success(0, slot);
+ QLIST_FOREACH(qdev, &bus->children, sibling) {
+ dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ if (PCI_SLOT(dev->devfn) == slot) {
+#if defined (TARGET_I386)
+ pci_device_hot_remove_success(dev);
#endif
+ qdev_free(qdev);
+ }
+ }
+
#if defined(DEBUG)
printf("pciej write %x <== %d\n", addr, val);
@@ -726,9 +736,9 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
static const char *model;
-static void piix4_device_hot_add(int bus, int slot, int state);
+static int piix4_device_hotplug(PCIDevice *dev, int state);
-void piix4_acpi_system_hot_add_init(const char *cpu_model)
+void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *cpu_model)
{
int i = 0, cpus = smp_cpus;
@@ -745,12 +755,12 @@ void piix4_acpi_system_hot_add_init(const char *cpu_model)
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, &pci0_status);
- register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, NULL);
- register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, NULL);
+ register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
+ register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
model = cpu_model;
- qemu_system_device_hot_add_register(piix4_device_hot_add);
+ pci_bus_hotplug(bus, piix4_device_hotplug);
}
#if defined(TARGET_I386)
@@ -802,8 +812,10 @@ static void disable_device(struct pci_status *p, struct gpe_regs *g, int slot)
p->down |= (1 << slot);
}
-static void piix4_device_hot_add(int bus, int slot, int state)
+static int piix4_device_hotplug(PCIDevice *dev, int state)
{
+ int slot = PCI_SLOT(dev->devfn);
+
pci0_status.up = 0;
pci0_status.down = 0;
if (state)
@@ -814,18 +826,7 @@ static void piix4_device_hot_add(int bus, int slot, int state)
qemu_set_irq(pm_state->irq, 1);
qemu_set_irq(pm_state->irq, 0);
}
-}
-
-static qemu_system_device_hot_add_t device_hot_add_callback;
-void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback)
-{
- device_hot_add_callback = callback;
-}
-
-void qemu_system_device_hot_add(int pcibus, int slot, int state)
-{
- if (device_hot_add_callback)
- device_hot_add_callback(pcibus, slot, state);
+ return 0;
}
struct acpi_table_header
diff --git a/hw/pc.c b/hw/pc.c
index eb9d71429..8f8f2ea60 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1382,8 +1382,6 @@ static void pc_init1(ram_addr_t ram_size,
pci_nic_init(nd, "rtl8139", NULL);
}
- piix4_acpi_system_hot_add_init(cpu_model);
-
if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
fprintf(stderr, "qemu: too many IDE bus\n");
exit(1);
@@ -1434,6 +1432,7 @@ static void pc_init1(ram_addr_t ram_size,
qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
qdev_init(eeprom);
}
+ piix4_acpi_system_hot_add_init(pci_bus, cpu_model);
}
if (i440fx_state) {
diff --git a/hw/pc.h b/hw/pc.h
index fb482828a..53a40490e 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -113,7 +113,7 @@ int acpi_table_add(const char *table_desc);
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
-void piix4_acpi_system_hot_add_init(const char *model);
+void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *model);
/* hpet.c */
extern int no_hpet;
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 7a1fd5bf5..282d15d35 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -229,8 +229,6 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "invalid type: %s\n", type);
if (dev) {
- qemu_system_device_hot_add(pci_bus_num(dev->bus),
- PCI_SLOT(dev->devfn), 1);
monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
0, pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
@@ -254,8 +252,7 @@ void pci_device_hot_remove(Monitor *mon, const char *pci_addr)
monitor_printf(mon, "slot %d empty\n", slot);
return;
}
-
- qemu_system_device_hot_add(bus, slot, 0);
+ qdev_unplug(&d->qdev);
}
void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict)
@@ -274,21 +271,15 @@ static int pci_match_fn(void *dev_private, void *arg)
/*
* OS has executed _EJ0 method, we now can remove the device
*/
-void pci_device_hot_remove_success(int pcibus, int slot)
+void pci_device_hot_remove_success(PCIDevice *d)
{
- PCIDevice *d = pci_find_device(pcibus, slot, 0);
int class_code;
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
AssignedDevInfo *adev;
#endif
- if (!d) {
- monitor_printf(cur_mon, "invalid slot %d\n", slot);
- return;
- }
-
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
- adev = get_assigned_device(pcibus, slot);
+ adev = get_assigned_device(pci_bus_num(d->bus), d->devfn >> 3);
if (adev) {
qemu_pci_hot_deassign_device(cur_mon, adev);
return;
@@ -305,7 +296,5 @@ void pci_device_hot_remove_success(int pcibus, int slot)
destroy_nic(pci_match_fn, d);
break;
}
-
- qdev_free(&d->qdev);
}
diff --git a/hw/pci.c b/hw/pci.c
index a1a56a014..dad246b9c 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -44,6 +44,7 @@ struct PCIBus {
int devfn_min;
pci_set_irq_fn set_irq;
pci_map_irq_fn map_irq;
+ pci_hotplug_fn hotplug;
uint32_t config_reg; /* XXX: suppress */
void *irq_opaque;
PCIDevice *devices[256];
@@ -135,6 +136,12 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));
}
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug)
+{
+ bus->qbus.allow_hotplug = 1;
+ bus->hotplug = hotplug;
+}
+
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int devfn_min, int nirq)
@@ -1062,19 +1069,33 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
PCIDevice *pci_dev = (PCIDevice *)qdev;
PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
PCIBus *bus;
- int devfn;
+ int devfn, rc;
bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
devfn = pci_dev->devfn;
pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
info->config_read, info->config_write);
assert(pci_dev);
- return info->init(pci_dev);
+ rc = info->init(pci_dev);
+ if (rc != 0)
+ return rc;
+ if (qdev->hotplugged)
+ bus->hotplug(pci_dev, 1);
+ return 0;
+}
+
+static int pci_unplug_device(DeviceState *qdev)
+{
+ PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+
+ dev->bus->hotplug(dev, 0);
+ return 0;
}
void pci_qdev_register(PCIDeviceInfo *info)
{
info->qdev.init = pci_qdev_init;
+ info->qdev.unplug = pci_unplug_device;
info->qdev.exit = pci_unregister_device;
info->qdev.bus_info = &pci_bus_info;
qdev_register(&info->qdev);
diff --git a/hw/pci.h b/hw/pci.h
index bbc908f47..aaa2a1e0d 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -293,11 +293,13 @@ int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len);
typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
+typedef int (*pci_hotplug_fn)(PCIDevice *pci_dev, int state);
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name, int devfn_min);
PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min);
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug);
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int devfn_min, int nirq);
diff --git a/hw/qdev.c b/hw/qdev.c
index 064389dcd..ebddcaedb 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -31,6 +31,8 @@
#include "monitor.h"
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
+static int qdev_hotplug = 0;
+
static BusState *main_system_bus;
static DeviceInfo *device_info_list;
@@ -102,6 +104,10 @@ DeviceState *qdev_create(BusState *bus, const char *name)
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
qdev_prop_set_compat(dev);
QLIST_INSERT_HEAD(&bus->children, dev, sibling);
+ if (qdev_hotplug) {
+ assert(bus->allow_hotplug);
+ dev->hotplugged = 1;
+ }
dev->state = DEV_STATE_CREATED;
return dev;
}
@@ -192,6 +198,11 @@ DeviceState *qdev_device_add(QemuOpts *opts)
path ? path : info->bus_info->name, info->name);
return NULL;
}
+ if (qdev_hotplug && !bus->allow_hotplug) {
+ qemu_error("Bus %s does not support hotplugging\n",
+ bus->name);
+ return NULL;
+ }
/* create device, set properties */
qdev = qdev_create(bus, driver);
@@ -229,6 +240,24 @@ int qdev_init(DeviceState *dev)
return 0;
}
+int qdev_unplug(DeviceState *dev)
+{
+ if (!dev->parent_bus->allow_hotplug) {
+ qemu_error("Bus %s does not support hotplugging\n",
+ dev->parent_bus->name);
+ return -1;
+ }
+ return dev->info->unplug(dev);
+}
+
+/* can be used as ->unplug() callback for the simple cases */
+int qdev_simple_unplug_cb(DeviceState *dev)
+{
+ /* just zap it */
+ qdev_free(dev);
+ return 0;
+}
+
/* Unlink device from bus and free the structure. */
void qdev_free(DeviceState *dev)
{
@@ -252,6 +281,15 @@ void qdev_free(DeviceState *dev)
qemu_free(dev);
}
+void qdev_machine_creation_done(void)
+{
+ /*
+ * ok, initial machine setup is done, starting from now we can
+ * only create hotpluggable devices
+ */
+ qdev_hotplug = 1;
+}
+
/* Get a character (serial) device interface. */
CharDriverState *qdev_init_chardev(DeviceState *dev)
{
@@ -370,6 +408,24 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
return NULL;
}
+static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
+{
+ DeviceState *dev, *ret;
+ BusState *child;
+
+ QLIST_FOREACH(dev, &bus->children, sibling) {
+ if (dev->id && strcmp(dev->id, id) == 0)
+ return dev;
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ ret = qdev_find_recursive(child, id);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+ return NULL;
+}
+
static void qbus_list_bus(DeviceState *dev, char *dest, int len)
{
BusState *child;
@@ -647,3 +703,26 @@ void do_info_qdm(Monitor *mon)
monitor_printf(mon, "%s\n", msg);
}
}
+
+void do_device_add(Monitor *mon, const QDict *qdict)
+{
+ QemuOpts *opts;
+
+ opts = qemu_opts_parse(&qemu_device_opts,
+ qdict_get_str(qdict, "config"), "driver");
+ if (opts)
+ qdev_device_add(opts);
+}
+
+void do_device_del(Monitor *mon, const QDict *qdict)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ DeviceState *dev;
+
+ dev = qdev_find_recursive(main_system_bus, id);
+ if (NULL == dev) {
+ qemu_error("Device '%s' not found\n", id);
+ return;
+ }
+ qdev_unplug(dev);
+}
diff --git a/hw/qdev.h b/hw/qdev.h
index 6c2c4013d..ca7c21a3b 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -29,6 +29,7 @@ enum DevState {
struct DeviceState {
const char *id;
enum DevState state;
+ int hotplugged;
DeviceInfo *info;
BusState *parent_bus;
int num_gpio_out;
@@ -53,6 +54,7 @@ struct BusState {
DeviceState *parent;
BusInfo *info;
const char *name;
+ int allow_hotplug;
int qdev_allocated;
QLIST_HEAD(, DeviceState) children;
QLIST_ENTRY(BusState) sibling;
@@ -98,7 +100,10 @@ struct CompatProperty {
DeviceState *qdev_create(BusState *bus, const char *name);
DeviceState *qdev_device_add(QemuOpts *opts);
int qdev_init(DeviceState *dev);
+int qdev_unplug(DeviceState *dev);
void qdev_free(DeviceState *dev);
+int qdev_simple_unplug_cb(DeviceState *dev);
+void qdev_machine_creation_done(void);
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
@@ -108,7 +113,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
/*** Device API. ***/
typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
-typedef int (*qdev_exitfn)(DeviceState *dev);
+typedef int (*qdev_event)(DeviceState *dev);
struct DeviceInfo {
const char *name;
@@ -126,7 +131,8 @@ struct DeviceInfo {
/* Private to qdev / bus. */
qdev_initfn init;
- qdev_exitfn exit;
+ qdev_event unplug;
+ qdev_event exit;
BusInfo *bus_info;
struct DeviceInfo *next;
};
@@ -165,6 +171,8 @@ void qbus_free(BusState *bus);
void do_info_qtree(Monitor *mon);
void do_info_qdm(Monitor *mon);
+void do_device_add(Monitor *mon, const QDict *qdict);
+void do_device_del(Monitor *mon, const QDict *qdict);
/*** qdev-properties.c ***/
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 27defc410..fe8991e9c 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -23,6 +23,7 @@ void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
bus->tcq = tcq;
bus->ndev = ndev;
bus->complete = complete;
+ bus->qbus.allow_hotplug = 1;
}
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
@@ -75,6 +76,7 @@ void scsi_qdev_register(SCSIDeviceInfo *info)
{
info->qdev.bus_info = &scsi_bus_info;
info->qdev.init = scsi_qdev_init;
+ info->qdev.unplug = qdev_simple_unplug_cb;
info->qdev.exit = scsi_qdev_exit;
qdev_register(&info->qdev);
}
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 70fd4dd53..18d7a98b4 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -614,7 +614,6 @@ static void usb_bt_handle_destroy(USBDevice *dev)
s->hci->opaque = NULL;
s->hci->evt_recv = NULL;
s->hci->acl_recv = NULL;
- qemu_free(s);
}
static int usb_bt_initfn(USBDevice *dev)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 2cac1e85b..0c6327935 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -18,6 +18,7 @@ void usb_bus_new(USBBus *bus, DeviceState *host)
{
qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
bus->busnr = next_usb_bus++;
+ bus->qbus.allow_hotplug = 1; /* Yes, we can */
QTAILQ_INIT(&bus->free);
QTAILQ_INIT(&bus->used);
QTAILQ_INSERT_TAIL(&busses, bus, next);
@@ -50,10 +51,23 @@ 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.unplug = qdev_simple_unplug_cb;
+ info->qdev.exit = usb_qdev_exit;
qdev_register(&info->qdev);
}
@@ -101,6 +115,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 +158,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 +202,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;
}
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 3bf06fa41..d1cc45e02 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -843,7 +843,6 @@ static void usb_hid_handle_destroy(USBDevice *dev)
if (s->kind != USB_KEYBOARD)
qemu_remove_mouse_event_handler(s->ptr.eh_entry);
/* TODO: else */
- qemu_free(s);
}
static int usb_hid_initfn(USBDevice *dev, int kind)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 0a3998646..e5a093877 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -517,8 +517,12 @@ static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p)
static void usb_hub_handle_destroy(USBDevice *dev)
{
USBHubState *s = (USBHubState *)dev;
+ int i;
- qemu_free(s);
+ for (i = 0; i < s->nb_ports; i++) {
+ usb_unregister_port(usb_bus_from_device(dev),
+ &s->ports[i].port);
+ }
}
static int usb_hub_initfn(USBDevice *dev)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 6b9c8a5bd..a19b31d68 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -512,9 +512,7 @@ static void usb_msd_handle_destroy(USBDevice *dev)
{
MSDState *s = (MSDState *)dev;
- s->scsi_dev->info->destroy(s->scsi_dev);
drive_uninit(s->dinfo->bdrv);
- qemu_free(s);
}
static int usb_msd_initfn(USBDevice *dev)
@@ -529,6 +527,7 @@ static int usb_msd_initfn(USBDevice *dev)
s->dev.speed = USB_SPEED_FULL;
scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, s->dinfo, 0);
+ s->bus.qbus.allow_hotplug = 0;
usb_msd_handle_reset(dev);
return 0;
}
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 091ab2cbc..e2379c4d5 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -486,7 +486,6 @@ static void usb_serial_handle_destroy(USBDevice *dev)
USBSerialState *s = (USBSerialState *)dev;
qemu_chr_close(s->cs);
- qemu_free(s);
}
static int usb_serial_can_read(void *opaque)
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 55f06bfd9..3ea72411a 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -389,7 +389,6 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
USBWacomState *s = (USBWacomState *) dev;
qemu_remove_mouse_event_handler(s->eh_entry);
- qemu_free(s);
}
static int usb_wacom_initfn(USBDevice *dev)
diff --git a/hw/usb.h b/hw/usb.h
index 467cddb7b..be4fcf6d1 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -311,7 +311,9 @@ USBDevice *usb_create(USBBus *bus, const char *name);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
usb_attachfn attach);
+void usb_unregister_port(USBBus *bus, USBPort *port);
int usb_device_attach(USBDevice *dev);
+int usb_device_detach(USBDevice *dev);
int usb_device_delete_addr(int busnr, int addr);
static inline USBBus *usb_bus_from_device(USBDevice *d)
diff --git a/qemu-config.c b/qemu-config.c
index 22baf424b..cfb1d2982 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -1,6 +1,7 @@
#include "qemu-common.h"
#include "qemu-option.h"
#include "qemu-config.h"
+#include "sysemu.h"
QemuOptsList qemu_drive_opts = {
.name = "drive",
@@ -190,7 +191,7 @@ int qemu_set_option(const char *str)
rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
if (rc < 3 || str[offset] != '=') {
- fprintf(stderr, "can't parse: \"%s\"\n", str);
+ qemu_error("can't parse: \"%s\"\n", str);
return -1;
}
@@ -199,19 +200,19 @@ int qemu_set_option(const char *str)
break;
}
if (lists[i] == NULL) {
- fprintf(stderr, "there is no option group \"%s\"\n", group);
+ qemu_error("there is no option group \"%s\"\n", group);
return -1;
}
opts = qemu_opts_find(lists[i], id);
if (!opts) {
- fprintf(stderr, "there is no %s \"%s\" defined\n",
+ qemu_error("there is no %s \"%s\" defined\n",
lists[i]->name, id);
return -1;
}
if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
- fprintf(stderr, "failed to set \"%s\" for %s \"%s\"\n",
+ qemu_error("failed to set \"%s\" for %s \"%s\"\n",
arg, lists[i]->name, id);
return -1;
}
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index 7ba8c9b21..797746fae 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -369,8 +369,24 @@ hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor
command @code{info usb} to see the devices you can remove.
ETEXI
- { "cpu", "index:i", do_cpu_set,
- "index", "set the default CPU" },
+ { "device_add", "config:s", do_device_add,
+ "device", "add device, like -device on the command line" },
+STEXI
+@item device_add @var{config}
+
+Add device.
+ETEXI
+
+ { "device_del", "id:s", do_device_del,
+ "device", "remove device" },
+STEXI
+@item device_del @var{id}
+
+Remove device @var{id}.
+ETEXI
+
+ { "cpu", "index:i", do_cpu_set, "index", "set the default CPU" },
+
STEXI
Set the default CPU.
ETEXI
diff --git a/sysemu.h b/sysemu.h
index 9c9e32da3..6fda55a95 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -204,9 +204,6 @@ extern DriveInfo *drive_init(QemuOpts *arg, void *machine, int *fatal_error);
/* acpi */
void qemu_system_cpu_hot_add(int cpu, int state);
-typedef void (*qemu_system_device_hot_add_t)(int pcibus, int slot, int state);
-void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback);
-void qemu_system_device_hot_add(int pcibus, int slot, int state);
/* device-hotplug */
@@ -221,7 +218,7 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict);
void drive_hot_add(Monitor *mon, const QDict *qdict);
void pci_device_hot_remove(Monitor *mon, const char *pci_addr);
void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict);
-void pci_device_hot_remove_success(int pcibus, int slot);
+void pci_device_hot_remove_success(PCIDevice *dev);
/* serial ports */
diff --git a/vl.c b/vl.c
index d7acaf43f..f96398e31 100644
--- a/vl.c
+++ b/vl.c
@@ -6072,6 +6072,8 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
+ qdev_machine_creation_done();
+
if (loadvm) {
if (load_vmstate(cur_mon, loadvm) < 0) {
autostart = 0;