* [Qemu-devel] [PATCH 1/9] allow passing null machine pointer to drive_init().
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
@ 2009-08-31 12:23 ` Gerd Hoffmann
2009-08-31 12:23 ` [Qemu-devel] [PATCH 2/9] qdev: add error message to qdev_device_add() Gerd Hoffmann
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:23 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
vl.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/vl.c b/vl.c
index a894285..6c6c4f8 100644
--- a/vl.c
+++ b/vl.c
@@ -1924,7 +1924,7 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque,
translation = BIOS_ATA_TRANSLATION_AUTO;
cache = 1;
- if (machine->use_scsi) {
+ if (machine && machine->use_scsi) {
type = IF_SCSI;
max_devs = MAX_SCSI_DEVS;
pstrcpy(devname, sizeof(devname), "scsi");
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 2/9] qdev: add error message to qdev_device_add().
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
2009-08-31 12:23 ` [Qemu-devel] [PATCH 1/9] allow passing null machine pointer to drive_init() Gerd Hoffmann
@ 2009-08-31 12:23 ` Gerd Hoffmann
2009-08-31 12:23 ` [Qemu-devel] [PATCH 3/9] qdev/usb: add usb bus support to qdev, convert drivers Gerd Hoffmann
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:23 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/qdev.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/hw/qdev.c b/hw/qdev.c
index ff2f096..f9754b1 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -186,8 +186,11 @@ DeviceState *qdev_device_add(QemuOpts *opts)
} else {
bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
}
- if (!bus)
+ if (!bus) {
+ qemu_error("Did not find %s bus for %s\n",
+ path ? path : info->bus_info->name, info->name);
return NULL;
+ }
/* create device, set properties */
qdev = qdev_create(bus, driver);
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 3/9] qdev/usb: add usb bus support to qdev, convert drivers.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
2009-08-31 12:23 ` [Qemu-devel] [PATCH 1/9] allow passing null machine pointer to drive_init() Gerd Hoffmann
2009-08-31 12:23 ` [Qemu-devel] [PATCH 2/9] qdev: add error message to qdev_device_add() Gerd Hoffmann
@ 2009-08-31 12:23 ` Gerd Hoffmann
2009-08-31 12:24 ` [Qemu-devel] [PATCH 4/9] qdev/usb: make qemu aware of usb busses Gerd Hoffmann
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:23 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
* Add USBBus.
* Add USBDeviceInfo, move device callbacks here.
* Add usb-qdev helper functions.
* Switch drivers to qdev.
TODO:
* make the rest of qemu aware of usb busses and kill the FIXMEs
added by this patch.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
Makefile | 2 +-
hw/bt-hid.c | 18 +++++-----
hw/usb-bt.c | 38 ++++++++++++++-----
hw/usb-bus.c | 82 ++++++++++++++++++++++++++++++++++++++++++
hw/usb-hid.c | 106 ++++++++++++++++++++++++++++++++-----------------------
hw/usb-hub.c | 49 +++++++++++++++----------
hw/usb-msd.c | 45 +++++++++++++++--------
hw/usb-musb.c | 2 +-
hw/usb-net.c | 45 ++++++++++++++++-------
hw/usb-ohci.c | 4 +-
hw/usb-serial.c | 48 ++++++++++++++++--------
hw/usb-uhci.c | 2 +-
hw/usb-wacom.c | 34 +++++++++++------
hw/usb.c | 16 ++++----
hw/usb.h | 69 ++++++++++++++++++++++++------------
usb-linux.c | 53 +++++++++++++++++++--------
vl.c | 4 +-
17 files changed, 424 insertions(+), 193 deletions(-)
create mode 100644 hw/usb-bus.c
diff --git a/Makefile b/Makefile
index bdac9b3..735282c 100644
--- a/Makefile
+++ b/Makefile
@@ -83,7 +83,7 @@ obj-y += tmp105.o lm832x.o eeprom93xx.o tsc2005.o
obj-y += scsi-disk.o cdrom.o
obj-y += scsi-generic.o
obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
-obj-y += usb-serial.o usb-net.o
+obj-y += usb-serial.o usb-net.o usb-bus.o
obj-y += sd.o ssi-sd.o
obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
obj-y += bt-hci-csr.o
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index e495dbf..6f37705 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -111,7 +111,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
bt_l2cap_device_done(&s->btdev);
bt_l2cap_device_init(&s->btdev, net);
- s->usbdev->handle_reset(s->usbdev);
+ s->usbdev->info->handle_reset(s->usbdev);
s->proto = BT_HID_PROTO_REPORT;
s->state = bt_state_ready;
s->dataother.len = 0;
@@ -131,7 +131,7 @@ static int bt_hid_out(struct bt_hid_device_s *s)
p.devep = 1;
p.data = s->dataout.buffer;
p.len = s->dataout.len;
- s->dataout.len = s->usbdev->handle_data(s->usbdev, &p);
+ s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
return s->dataout.len;
}
@@ -154,7 +154,7 @@ static int bt_hid_in(struct bt_hid_device_s *s)
p.devep = 1;
p.data = s->datain.buffer;
p.len = sizeof(s->datain.buffer);
- s->datain.len = s->usbdev->handle_data(s->usbdev, &p);
+ s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
return s->datain.len;
}
@@ -323,8 +323,8 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
break;
}
s->proto = parameter;
- s->usbdev->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
- NULL);
+ s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
+ NULL);
ret = BT_HS_SUCCESSFUL;
break;
@@ -333,7 +333,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
ret = BT_HS_ERR_INVALID_PARAMETER;
break;
}
- s->usbdev->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
+ s->usbdev->info->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
s->control->sdu_out(s->control, 1));
s->control->sdu_submit(s->control);
break;
@@ -346,7 +346,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
/* We don't need to know about the Idle Rate here really,
* so just pass it on to the device. */
- ret = s->usbdev->handle_control(s->usbdev,
+ ret = s->usbdev->info->handle_control(s->usbdev,
SET_IDLE, data[1], 0, 0, NULL) ?
BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
/* XXX: Does this generate a handshake? */
@@ -450,7 +450,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid)
hid->btdev.device.inquiry_scan = !hid->connected;
if (hid->connected && !prev) {
- hid->usbdev->handle_reset(hid->usbdev);
+ hid->usbdev->info->handle_reset(hid->usbdev);
hid->proto = BT_HID_PROTO_REPORT;
}
@@ -518,7 +518,7 @@ static void bt_hid_destroy(struct bt_device_s *dev)
bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
bt_l2cap_device_done(&hid->btdev);
- hid->usbdev->handle_destroy(hid->usbdev);
+ hid->usbdev->info->handle_destroy(hid->usbdev);
qemu_free(hid);
}
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 72245f6..4c60d42 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -617,22 +617,23 @@ static void usb_bt_handle_destroy(USBDevice *dev)
qemu_free(s);
}
+static int usb_bt_initfn(USBDevice *dev)
+{
+ struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev);
+ s->dev.speed = USB_SPEED_HIGH;
+ return 0;
+}
+
USBDevice *usb_bt_init(HCIInfo *hci)
{
+ USBDevice *dev;
struct USBBtState *s;
if (!hci)
return NULL;
- s = qemu_mallocz(sizeof(struct USBBtState));
+ dev = usb_create_simple(NULL /* FIXME */, "QEMU BT dongle");
+ s = DO_UPCAST(struct USBBtState, dev, dev);
s->dev.opaque = s;
- s->dev.speed = USB_SPEED_HIGH;
- s->dev.handle_packet = usb_generic_handle_packet;
- pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU BT dongle");
-
- s->dev.handle_reset = usb_bt_handle_reset;
- s->dev.handle_control = usb_bt_handle_control;
- s->dev.handle_data = usb_bt_handle_data;
- s->dev.handle_destroy = usb_bt_handle_destroy;
s->hci = hci;
s->hci->opaque = s;
@@ -641,5 +642,22 @@ USBDevice *usb_bt_init(HCIInfo *hci)
usb_bt_handle_reset(&s->dev);
- return &s->dev;
+ return dev;
+}
+
+static struct USBDeviceInfo bt_info = {
+ .qdev.name = "QEMU BT dongle",
+ .qdev.size = sizeof(struct USBBtState),
+ .init = usb_bt_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_bt_handle_reset,
+ .handle_control = usb_bt_handle_control,
+ .handle_data = usb_bt_handle_data,
+ .handle_destroy = usb_bt_handle_destroy,
+};
+
+static void usb_bt_register_devices(void)
+{
+ usb_qdev_register(&bt_info);
}
+device_init(usb_bt_register_devices)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
new file mode 100644
index 0000000..c695a37
--- /dev/null
+++ b/hw/usb-bus.c
@@ -0,0 +1,82 @@
+#include "hw.h"
+#include "usb.h"
+#include "qdev.h"
+
+static struct BusInfo usb_bus_info = {
+ .name = "USB",
+ .size = sizeof(USBBus),
+};
+static int next_usb_bus = 0;
+static TAILQ_HEAD(, USBBus) busses = TAILQ_HEAD_INITIALIZER(busses);
+
+USBBus *usb_bus_new(DeviceState *host)
+{
+ USBBus *bus;
+
+ bus = FROM_QBUS(USBBus, qbus_create(&usb_bus_info, host, NULL));
+ bus->busnr = next_usb_bus++;
+ TAILQ_INIT(&bus->free);
+ TAILQ_INIT(&bus->used);
+ TAILQ_INSERT_TAIL(&busses, bus, next);
+ return bus;
+}
+
+USBBus *usb_bus_find(int busnr)
+{
+ USBBus *bus;
+
+ if (-1 == busnr)
+ return TAILQ_FIRST(&busses);
+ TAILQ_FOREACH(bus, &busses, next) {
+ if (bus->busnr == busnr)
+ return bus;
+ }
+ return NULL;
+}
+
+static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+ USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
+ int rc;
+
+ pstrcpy(dev->devname, sizeof(dev->devname), qdev->info->name);
+ dev->info = info;
+ rc = dev->info->init(dev);
+ return rc;
+}
+
+void usb_qdev_register(USBDeviceInfo *info)
+{
+ info->qdev.bus_info = &usb_bus_info;
+ info->qdev.init = usb_qdev_init;
+ qdev_register(&info->qdev);
+}
+
+void usb_qdev_register_many(USBDeviceInfo *info)
+{
+ while (info->qdev.name) {
+ usb_qdev_register(info);
+ info++;
+ }
+}
+
+USBDevice *usb_create_simple(USBBus *bus, const char *name)
+{
+ DeviceState *dev;
+
+#if 1
+ /* temporary stopgap until all usb is properly qdev-ified */
+ if (!bus) {
+ bus = usb_bus_find(-1);
+ if (!bus)
+ return NULL;
+ fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n",
+ __FUNCTION__, bus->qbus.name, name);
+ }
+#endif
+
+ dev = qdev_create(&bus->qbus, name);
+ qdev_init(dev);
+ return DO_UPCAST(USBDevice, qdev, dev);
+}
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index c850a91..c8b6ee7 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -846,65 +846,44 @@ static void usb_hid_handle_destroy(USBDevice *dev)
qemu_free(s);
}
-USBDevice *usb_tablet_init(void)
+static int usb_hid_initfn(USBDevice *dev, int kind)
{
- USBHIDState *s;
-
- s = qemu_mallocz(sizeof(USBHIDState));
+ USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
-
- s->dev.handle_reset = usb_mouse_handle_reset;
- s->dev.handle_control = usb_hid_handle_control;
- s->dev.handle_data = usb_hid_handle_data;
- s->dev.handle_destroy = usb_hid_handle_destroy;
- s->kind = USB_TABLET;
+ s->kind = kind;
/* Force poll routine to be run and grab input the first time. */
s->changed = 1;
-
- pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
-
- return (USBDevice *)s;
+ return 0;
}
-USBDevice *usb_mouse_init(void)
+static int usb_tablet_initfn(USBDevice *dev)
{
- USBHIDState *s;
+ return usb_hid_initfn(dev, USB_TABLET);
+}
- s = qemu_mallocz(sizeof(USBHIDState));
- s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
+static int usb_mouse_initfn(USBDevice *dev)
+{
+ return usb_hid_initfn(dev, USB_MOUSE);
+}
- s->dev.handle_reset = usb_mouse_handle_reset;
- s->dev.handle_control = usb_hid_handle_control;
- s->dev.handle_data = usb_hid_handle_data;
- s->dev.handle_destroy = usb_hid_handle_destroy;
- s->kind = USB_MOUSE;
- /* Force poll routine to be run and grab input the first time. */
- s->changed = 1;
+static int usb_keyboard_initfn(USBDevice *dev)
+{
+ return usb_hid_initfn(dev, USB_KEYBOARD);
+}
- pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
+USBDevice *usb_tablet_init(void)
+{
+ return usb_create_simple(NULL /* FIXME */, "QEMU USB Tablet");
+}
- return (USBDevice *)s;
+USBDevice *usb_mouse_init(void)
+{
+ return usb_create_simple(NULL /* FIXME */, "QEMU USB Mouse");
}
USBDevice *usb_keyboard_init(void)
{
- USBHIDState *s;
-
- s = qemu_mallocz(sizeof(USBHIDState));
- s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
-
- s->dev.handle_reset = usb_keyboard_handle_reset;
- s->dev.handle_control = usb_hid_handle_control;
- s->dev.handle_data = usb_hid_handle_data;
- s->dev.handle_destroy = usb_hid_handle_destroy;
- s->kind = USB_KEYBOARD;
-
- pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard");
-
- return (USBDevice *) s;
+ return usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
}
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
@@ -914,3 +893,42 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
s->datain_opaque = opaque;
s->datain = datain;
}
+
+static struct USBDeviceInfo hid_info[] = {
+ {
+ .qdev.name = "QEMU USB Tablet",
+ .qdev.size = sizeof(USBHIDState),
+ .init = usb_tablet_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_mouse_handle_reset,
+ .handle_control = usb_hid_handle_control,
+ .handle_data = usb_hid_handle_data,
+ .handle_destroy = usb_hid_handle_destroy,
+ },{
+ .qdev.name = "QEMU USB Mouse",
+ .qdev.size = sizeof(USBHIDState),
+ .init = usb_mouse_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_mouse_handle_reset,
+ .handle_control = usb_hid_handle_control,
+ .handle_data = usb_hid_handle_data,
+ .handle_destroy = usb_hid_handle_destroy,
+ },{
+ .qdev.name = "QEMU USB Keyboard",
+ .qdev.size = sizeof(USBHIDState),
+ .init = usb_keyboard_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_keyboard_handle_reset,
+ .handle_control = usb_hid_handle_control,
+ .handle_data = usb_hid_handle_data,
+ .handle_destroy = usb_hid_handle_destroy,
+ },{
+ /* end of list */
+ }
+};
+
+static void usb_hid_register_devices(void)
+{
+ usb_qdev_register_many(hid_info);
+}
+device_init(usb_hid_register_devices)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 9f26bbe..116b1d2 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -486,7 +486,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
port = &s->ports[i];
dev = port->port.dev;
if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
- ret = dev->handle_packet(dev, p);
+ ret = dev->info->handle_packet(dev, p);
if (ret != USB_RET_NODEV) {
return ret;
}
@@ -521,32 +521,41 @@ static void usb_hub_handle_destroy(USBDevice *dev)
qemu_free(s);
}
-USBDevice *usb_hub_init(int nb_ports)
+static int usb_hub_initfn(USBDevice *dev)
{
- USBHubState *s;
+ USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
USBHubPort *port;
int i;
- if (nb_ports > MAX_PORTS)
- return NULL;
- s = qemu_mallocz(sizeof(USBHubState));
- s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_hub_handle_packet;
-
- /* generic USB device init */
- s->dev.handle_reset = usb_hub_handle_reset;
- s->dev.handle_control = usb_hub_handle_control;
- s->dev.handle_data = usb_hub_handle_data;
- s->dev.handle_destroy = usb_hub_handle_destroy;
-
- pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub");
-
- s->nb_ports = nb_ports;
- for(i = 0; i < s->nb_ports; i++) {
+ s->dev.speed = USB_SPEED_FULL,
+ s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
+ for (i = 0; i < s->nb_ports; i++) {
port = &s->ports[i];
qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
port->wPortStatus = PORT_STAT_POWER;
port->wPortChange = 0;
}
- return (USBDevice *)s;
+ return 0;
+}
+
+USBDevice *usb_hub_init(int nb_ports)
+{
+ return usb_create_simple(NULL /* FIXME */, "QEMU USB Hub");
+}
+
+static struct USBDeviceInfo hub_info = {
+ .qdev.name = "QEMU USB Hub",
+ .qdev.size = sizeof(USBHubState),
+ .init = usb_hub_initfn,
+ .handle_packet = usb_hub_handle_packet,
+ .handle_reset = usb_hub_handle_reset,
+ .handle_control = usb_hub_handle_control,
+ .handle_data = usb_hub_handle_data,
+ .handle_destroy = usb_hub_handle_destroy,
+};
+
+static void usb_hub_register_devices(void)
+{
+ usb_qdev_register(&hub_info);
}
+device_init(usb_hub_register_devices)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 3a3eb4a..bc5150f 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -514,8 +514,17 @@ static void usb_msd_handle_destroy(USBDevice *dev)
qemu_free(s);
}
+static int usb_msd_initfn(USBDevice *dev)
+{
+ MSDState *s = DO_UPCAST(MSDState, dev, dev);
+
+ s->dev.speed = USB_SPEED_FULL;
+ return 0;
+}
+
USBDevice *usb_msd_init(const char *filename)
{
+ USBDevice *dev;
MSDState *s;
BlockDriverState *bdrv;
BlockDriver *drv = NULL;
@@ -548,30 +557,19 @@ USBDevice *usb_msd_init(const char *filename)
return NULL;
}
- s = qemu_mallocz(sizeof(MSDState));
-
bdrv = bdrv_new("usb");
if (bdrv_open2(bdrv, filename, 0, drv) < 0)
- goto fail;
- s->bs = bdrv;
-
- s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
-
- s->dev.handle_reset = usb_msd_handle_reset;
- s->dev.handle_control = usb_msd_handle_control;
- s->dev.handle_data = usb_msd_handle_data;
- s->dev.handle_destroy = usb_msd_handle_destroy;
+ return NULL;
+ dev = usb_create_simple(NULL /* FIXME */, "QEMU USB MSD");
+ s = DO_UPCAST(MSDState, dev, dev);
+ s->bs = bdrv;
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
filename);
s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
usb_msd_handle_reset((USBDevice *)s);
return (USBDevice *)s;
- fail:
- qemu_free(s);
- return NULL;
}
BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
@@ -580,3 +578,20 @@ BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
return s->bs;
}
+
+static struct USBDeviceInfo msd_info = {
+ .qdev.name = "QEMU USB MSD",
+ .qdev.size = sizeof(MSDState),
+ .init = usb_msd_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_msd_handle_reset,
+ .handle_control = usb_msd_handle_control,
+ .handle_data = usb_msd_handle_data,
+ .handle_destroy = usb_msd_handle_destroy,
+};
+
+static void usb_msd_register_devices(void)
+{
+ usb_qdev_register(&msd_info);
+}
+device_init(usb_msd_register_devices)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 664f467..b23ed3f 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -590,7 +590,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->packey[dir].complete_opaque = ep;
if (s->port.dev)
- ret = s->port.dev->handle_packet(s->port.dev, &ep->packey[dir]);
+ ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir]);
else
ret = USB_RET_NODEV;
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 8214a68..f19309e 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1432,32 +1432,34 @@ static void usb_net_handle_destroy(USBDevice *dev)
qemu_del_vlan_client(s->vc);
}
-USBDevice *usb_net_init(NICInfo *nd)
+static int usb_net_initfn(USBDevice *dev)
{
- USBNetState *s;
-
- s = qemu_mallocz(sizeof(USBNetState));
- s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
+ USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
- s->dev.handle_reset = usb_net_handle_reset;
- s->dev.handle_control = usb_net_handle_control;
- s->dev.handle_data = usb_net_handle_data;
- s->dev.handle_destroy = usb_net_handle_destroy;
+ s->dev.speed = USB_SPEED_FULL;
s->rndis = 1;
s->rndis_state = RNDIS_UNINITIALIZED;
+ TAILQ_INIT(&s->rndis_resp);
+
s->medium = 0; /* NDIS_MEDIUM_802_3 */
s->speed = 1000000; /* 100MBps, in 100Bps units */
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
s->filter = 0;
s->vendorid = 0x1234;
+ return 0;
+}
+
+USBDevice *usb_net_init(NICInfo *nd)
+{
+ USBDevice *dev;
+ USBNetState *s;
+
+ dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Network Interface");
+ s = DO_UPCAST(USBNetState, dev, dev);
memcpy(s->mac, nd->macaddr, 6);
- TAILQ_INIT(&s->rndis_resp);
- pstrcpy(s->dev.devname, sizeof(s->dev.devname),
- "QEMU USB Network Interface");
s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
usbnet_can_receive,
usbnet_receive,
@@ -1476,3 +1478,20 @@ USBDevice *usb_net_init(NICInfo *nd)
return (USBDevice *) s;
}
+
+static struct USBDeviceInfo net_info = {
+ .qdev.name = "QEMU USB Network Interface",
+ .qdev.size = sizeof(USBNetState),
+ .init = usb_net_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_net_handle_reset,
+ .handle_control = usb_net_handle_control,
+ .handle_data = usb_net_handle_data,
+ .handle_destroy = usb_net_handle_destroy,
+};
+
+static void usb_net_register_devices(void)
+{
+ usb_qdev_register(&net_info);
+}
+device_init(usb_net_register_devices)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 0c08e9f..e725e97 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -754,7 +754,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
ohci->usb_packet.len = len;
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
ohci->usb_packet.complete_opaque = ohci;
- ret = dev->handle_packet(dev, &ohci->usb_packet);
+ ret = dev->info->handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
}
@@ -944,7 +944,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
ohci->usb_packet.len = len;
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
ohci->usb_packet.complete_opaque = ohci;
- ret = dev->handle_packet(dev, &ohci->usb_packet);
+ ret = dev->info->handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
}
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 19870a5..091ab2c 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -524,8 +524,16 @@ static void usb_serial_event(void *opaque, int event)
}
}
+static int usb_serial_initfn(USBDevice *dev)
+{
+ USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
+ s->dev.speed = USB_SPEED_FULL;
+ return 0;
+}
+
USBDevice *usb_serial_init(const char *filename)
{
+ USBDevice *dev;
USBSerialState *s;
CharDriverState *cdrv;
unsigned short vendorid = 0x0403, productid = 0x6001;
@@ -561,32 +569,40 @@ USBDevice *usb_serial_init(const char *filename)
return NULL;
}
filename++;
- s = qemu_mallocz(sizeof(USBSerialState));
snprintf(label, sizeof(label), "usbserial%d", index++);
cdrv = qemu_chr_open(label, filename, NULL);
if (!cdrv)
- goto fail;
- s->cs = cdrv;
- qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s);
-
- s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
-
- s->dev.handle_reset = usb_serial_handle_reset;
- s->dev.handle_control = usb_serial_handle_control;
- s->dev.handle_data = usb_serial_handle_data;
- s->dev.handle_destroy = usb_serial_handle_destroy;
+ return NULL;
+ dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Serial");
+ s = DO_UPCAST(USBSerialState, dev, dev);
+ s->cs = cdrv;
s->vendorid = vendorid;
s->productid = productid;
-
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)",
filename);
+ qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read,
+ usb_serial_event, s);
+
usb_serial_handle_reset((USBDevice *)s);
return (USBDevice *)s;
- fail:
- qemu_free(s);
- return NULL;
}
+
+static struct USBDeviceInfo serial_info = {
+ .qdev.name = "QEMU USB Serial",
+ .qdev.size = sizeof(USBSerialState),
+ .init = usb_serial_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_serial_handle_reset,
+ .handle_control = usb_serial_handle_control,
+ .handle_data = usb_serial_handle_data,
+ .handle_destroy = usb_serial_handle_destroy,
+};
+
+static void usb_serial_register_devices(void)
+{
+ usb_qdev_register(&serial_info);
+}
+device_init(usb_serial_register_devices)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index a61887b..a112a69 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -660,7 +660,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
USBDevice *dev = port->port.dev;
if (dev && (port->ctrl & UHCI_PORT_EN))
- ret = dev->handle_packet(dev, p);
+ ret = dev->info->handle_packet(dev, p);
}
dprintf("uhci: packet exit. ret %d len %d\n", ret, p->len);
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index eaf0d29..a5abb98 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -392,21 +392,31 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
qemu_free(s);
}
-USBDevice *usb_wacom_init(void)
+static int usb_wacom_initfn(USBDevice *dev)
{
- USBWacomState *s;
-
- s = qemu_mallocz(sizeof(USBWacomState));
+ USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
s->dev.speed = USB_SPEED_FULL;
- s->dev.handle_packet = usb_generic_handle_packet;
+ return 0;
+}
- s->dev.handle_reset = usb_wacom_handle_reset;
- s->dev.handle_control = usb_wacom_handle_control;
- s->dev.handle_data = usb_wacom_handle_data;
- s->dev.handle_destroy = usb_wacom_handle_destroy;
+USBDevice *usb_wacom_init(void)
+{
+ return usb_create_simple(NULL /* FIXME */, "QEMU PenPartner Tablet");
+}
- pstrcpy(s->dev.devname, sizeof(s->dev.devname),
- "QEMU PenPartner Tablet");
+static struct USBDeviceInfo wacom_info = {
+ .qdev.name = "QEMU PenPartner Tablet",
+ .qdev.size = sizeof(USBWacomState),
+ .init = usb_wacom_initfn,
+ .handle_packet = usb_generic_handle_packet,
+ .handle_reset = usb_wacom_handle_reset,
+ .handle_control = usb_wacom_handle_control,
+ .handle_data = usb_wacom_handle_data,
+ .handle_destroy = usb_wacom_handle_destroy,
+};
- return (USBDevice *) s;
+static void usb_wacom_register_devices(void)
+{
+ usb_qdev_register(&wacom_info);
}
+device_init(usb_wacom_register_devices)
diff --git a/hw/usb.c b/hw/usb.c
index c17266d..a326bcf 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -59,8 +59,8 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
if (s->setup_buf[0] & USB_DIR_IN) {
- ret = s->handle_control(s, request, value, index,
- s->setup_len, s->data_buf);
+ ret = s->info->handle_control(s, request, value, index,
+ s->setup_len, s->data_buf);
if (ret < 0)
return ret;
@@ -83,7 +83,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
int ret = 0;
if (p->devep != 0)
- return s->handle_data(s, p);
+ return s->info->handle_data(s, p);
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -93,8 +93,8 @@ static int do_token_in(USBDevice *s, USBPacket *p)
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
s->setup_state = SETUP_STATE_IDLE;
- ret = s->handle_control(s, request, value, index,
- s->setup_len, s->data_buf);
+ ret = s->info->handle_control(s, request, value, index,
+ s->setup_len, s->data_buf);
if (ret > 0)
return 0;
return ret;
@@ -126,7 +126,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
static int do_token_out(USBDevice *s, USBPacket *p)
{
if (p->devep != 0)
- return s->handle_data(s, p);
+ return s->info->handle_data(s, p);
switch(s->setup_state) {
case SETUP_STATE_ACK:
@@ -179,7 +179,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
- s->handle_reset(s);
+ s->info->handle_reset(s);
return 0;
}
@@ -225,7 +225,7 @@ void usb_send_msg(USBDevice *dev, int msg)
USBPacket p;
memset(&p, 0, sizeof(p));
p.pid = msg;
- dev->handle_packet(dev, &p);
+ dev->info->handle_packet(dev, &p);
/* This _must_ be synchronous */
}
diff --git a/hw/usb.h b/hw/usb.h
index e9d4bc2..dea5718 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -23,6 +23,7 @@
*/
#include "block.h"
+#include "qdev.h"
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
@@ -116,37 +117,52 @@
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
+typedef struct USBBus USBBus;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
+typedef struct USBDeviceInfo USBDeviceInfo;
typedef struct USBPacket USBPacket;
/* definition of a USB device */
struct USBDevice {
+ DeviceState qdev;
+ USBDeviceInfo *info;
void *opaque;
- /*
- * Process USB packet.
+ int speed;
+ uint8_t addr;
+ char devname[32];
+
+ int state;
+ uint8_t setup_buf[8];
+ uint8_t data_buf[1024];
+ int remote_wakeup;
+ int setup_state;
+ int setup_len;
+ int setup_index;
+};
+
+struct USBDeviceInfo {
+ DeviceInfo qdev;
+ int (*init)(USBDevice *dev);
+
+ /*
+ * Process USB packet.
* Called by the HC (Host Controller).
*
- * Returns length of the transaction
+ * Returns length of the transaction
* or one of the USB_RET_XXX codes.
- */
+ */
int (*handle_packet)(USBDevice *dev, USBPacket *p);
- /*
+ /*
* Called when device is destroyed.
*/
void (*handle_destroy)(USBDevice *dev);
- int speed;
-
- /* The following fields are used by the generic USB device
- layer. They are here just to avoid creating a new structure
- for them. */
-
/*
* Reset the device
- */
+ */
void (*handle_reset)(USBDevice *dev);
/*
@@ -165,17 +181,6 @@ struct USBDevice {
* Returns length or one of the USB_RET_ codes.
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
-
- uint8_t addr;
- char devname[32];
-
- int state;
- uint8_t setup_buf[8];
- uint8_t data_buf[1024];
- int remote_wakeup;
- int setup_state;
- int setup_len;
- int setup_index;
};
typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev);
@@ -297,3 +302,21 @@ MUSBState *musb_init(qemu_irq *irqs);
uint32_t musb_core_intr_get(MUSBState *s);
void musb_core_intr_clear(MUSBState *s, uint32_t mask);
void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
+
+/* usb-bus.c */
+
+struct USBBus {
+ BusState qbus;
+ int busnr;
+ int nfree;
+ int nused;
+ TAILQ_HEAD(, USBPort) free;
+ TAILQ_HEAD(, USBPort) used;
+ TAILQ_ENTRY(USBBus) next;
+};
+
+USBBus *usb_bus_new(DeviceState *host);
+USBBus *usb_bus_find(int busnr);
+void usb_qdev_register(USBDeviceInfo *info);
+void usb_qdev_register_many(USBDeviceInfo *info);
+USBDevice *usb_create_simple(USBBus *bus, const char *name);
diff --git a/usb-linux.c b/usb-linux.c
index 043f6b6..0130b71 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -751,7 +751,7 @@ static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
- s->handle_reset(s);
+ s->info->handle_reset(s);
return 0;
}
@@ -881,18 +881,19 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
return 0;
}
+static int usb_host_initfn(USBDevice *dev)
+{
+ return 0;
+}
+
static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name)
{
int fd = -1, ret;
- USBHostDevice *dev = NULL;
+ USBDevice *d = NULL;
+ USBHostDevice *dev;
struct usbdevfs_connectinfo ci;
char buf[1024];
- dev = qemu_mallocz(sizeof(USBHostDevice));
-
- dev->bus_num = bus_num;
- dev->addr = addr;
-
printf("husb: open device %d.%d\n", bus_num, addr);
if (!usb_host_device_path) {
@@ -908,6 +909,12 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
}
dprintf("husb: opened %s\n", buf);
+ d = usb_create_simple(NULL /* FIXME */, "USB Host Device");
+ dev = DO_UPCAST(USBHostDevice, dev, d);
+
+ dev->bus_num = bus_num;
+ dev->addr = addr;
+
/* read the device description */
dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
if (dev->descr_len <= 0) {
@@ -925,7 +932,6 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
}
#endif
- dev->fd = fd;
/*
* Initial configuration is -1 which makes us claim first
@@ -953,10 +959,6 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
else
dev->dev.speed = USB_SPEED_HIGH;
- dev->dev.handle_packet = usb_host_handle_packet;
- dev->dev.handle_reset = usb_host_handle_reset;
- dev->dev.handle_destroy = usb_host_handle_destroy;
-
if (!prod_name || prod_name[0] == '\0')
snprintf(dev->dev.devname, sizeof(dev->dev.devname),
"host:%d.%d", bus_num, addr);
@@ -972,13 +974,32 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
return (USBDevice *) dev;
fail:
- if (dev)
- qemu_free(dev);
-
- close(fd);
+ if (d)
+ qdev_free(&d->qdev);
+ if (fd != -1)
+ close(fd);
return NULL;
}
+static struct USBDeviceInfo usb_host_dev_info = {
+ .qdev.name = "USB Host Device",
+ .qdev.size = sizeof(USBHostDevice),
+ .init = usb_host_initfn,
+ .handle_packet = usb_host_handle_packet,
+ .handle_reset = usb_host_handle_reset,
+#if 0
+ .handle_control = usb_host_handle_control,
+ .handle_data = usb_host_handle_data,
+#endif
+ .handle_destroy = usb_host_handle_destroy,
+};
+
+static void usb_host_register_devices(void)
+{
+ usb_qdev_register(&usb_host_dev_info);
+}
+device_init(usb_host_register_devices)
+
static int usb_host_auto_add(const char *spec);
static int usb_host_auto_del(const char *spec);
diff --git a/vl.c b/vl.c
index 6c6c4f8..c362d1f 100644
--- a/vl.c
+++ b/vl.c
@@ -2477,7 +2477,7 @@ static void usb_msd_password_cb(void *opaque, int err)
if (!err)
usb_device_add_dev(dev);
else
- dev->handle_destroy(dev);
+ dev->info->handle_destroy(dev);
}
static int usb_device_add(const char *devname, int is_hotplug)
@@ -2563,7 +2563,7 @@ int usb_device_del_addr(int bus_num, int addr)
dev = port->dev;
*lastp = port->next;
usb_attach(port, NULL);
- dev->handle_destroy(dev);
+ dev->info->handle_destroy(dev);
port->next = free_usb_ports;
free_usb_ports = port;
return 0;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 4/9] qdev/usb: make qemu aware of usb busses.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
` (2 preceding siblings ...)
2009-08-31 12:23 ` [Qemu-devel] [PATCH 3/9] qdev/usb: add usb bus support to qdev, convert drivers Gerd Hoffmann
@ 2009-08-31 12:24 ` Gerd Hoffmann
[not found] ` <m34oro5ezg.fsf@neno.mitica>
2009-08-31 12:24 ` [Qemu-devel] [PATCH 5/9] qdev/usb: add some convinience aliases Gerd Hoffmann
` (4 subsequent siblings)
8 siblings, 1 reply; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Move usb code from vl.c to usb-bus.c and make it use the new data
structures added by qdev conversion. qemu usb core should be able
to handle multiple USB busses just fine now (untested though).
Kill some usb_*_init() legacy functions, use usb_create_simple()
instead.
Kill some FIXMEs added by the first qdev/usb patch.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/bt-hid.c | 3 +-
hw/usb-bus.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++--
hw/usb-hid.c | 15 -----
hw/usb-hub.c | 8 +--
hw/usb-musb.c | 4 +-
hw/usb-ohci.c | 4 +-
hw/usb-uhci.c | 7 ++-
hw/usb-wacom.c | 5 --
hw/usb.h | 28 +++++-----
pc-bios/bios.bin | Bin 131072 -> 131072 bytes
usb-linux.c | 12 ++--
vl.c | 154 +++++++++++++-----------------------------------------
12 files changed, 206 insertions(+), 174 deletions(-)
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 6f37705..020176e 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -566,5 +566,6 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
{
- return bt_hid_init(net, usb_keyboard_init(), class_keyboard);
+ USBDevice *dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
+ return bt_hid_init(net, dev, class_keyboard);
}
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index c695a37..169fb2f 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -1,10 +1,15 @@
#include "hw.h"
#include "usb.h"
#include "qdev.h"
+#include "sysemu.h"
+#include "monitor.h"
+
+static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
static struct BusInfo usb_bus_info = {
- .name = "USB",
- .size = sizeof(USBBus),
+ .name = "USB",
+ .size = sizeof(USBBus),
+ .print_dev = usb_bus_dev_print,
};
static int next_usb_bus = 0;
static TAILQ_HEAD(, USBBus) busses = TAILQ_HEAD_INITIALIZER(busses);
@@ -43,6 +48,8 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
pstrcpy(dev->devname, sizeof(dev->devname), qdev->info->name);
dev->info = info;
rc = dev->info->init(dev);
+ if (rc == 0)
+ usb_device_attach(dev);
return rc;
}
@@ -61,7 +68,7 @@ void usb_qdev_register_many(USBDeviceInfo *info)
}
}
-USBDevice *usb_create_simple(USBBus *bus, const char *name)
+USBDevice *usb_create(USBBus *bus, const char *name)
{
DeviceState *dev;
@@ -77,6 +84,131 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
#endif
dev = qdev_create(&bus->qbus, name);
- qdev_init(dev);
return DO_UPCAST(USBDevice, qdev, dev);
}
+
+USBDevice *usb_create_simple(USBBus *bus, const char *name)
+{
+ USBDevice *dev = usb_create(bus, name);
+ qdev_init(&dev->qdev);
+ return dev;
+}
+
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+ usb_attachfn attach)
+{
+ port->opaque = opaque;
+ port->index = index;
+ port->attach = attach;
+ TAILQ_INSERT_TAIL(&bus->free, port, next);
+ bus->nfree++;
+}
+
+static void do_attach(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ USBPort *port;
+
+ if (dev->attached) {
+ fprintf(stderr, "Warning: tried to attach usb device %s twice\n",
+ dev->devname);
+ return;
+ }
+ dev->attached++;
+
+ port = TAILQ_FIRST(&bus->free);
+ TAILQ_REMOVE(&bus->free, port, next);
+ bus->nfree--;
+
+ usb_attach(port, dev);
+
+ TAILQ_INSERT_TAIL(&bus->used, port, next);
+ bus->nused++;
+}
+
+int usb_device_attach(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ USBDevice *hub;
+
+ if (bus->nfree == 1) {
+ /* Create a new hub and chain it on. */
+ hub = usb_create_simple(bus, "QEMU USB Hub");
+ }
+ do_attach(dev);
+ return 0;
+}
+
+int usb_device_delete_addr(int busnr, int addr)
+{
+ USBBus *bus;
+ USBPort *port;
+ USBDevice *dev;
+
+ bus = usb_bus_find(busnr);
+ if (!bus)
+ return -1;
+
+ TAILQ_FOREACH(port, &bus->used, next) {
+ if (port->dev->addr == addr)
+ break;
+ }
+ if (!port)
+ return -1;
+
+ dev = port->dev;
+ TAILQ_REMOVE(&bus->used, port, next);
+ bus->nused--;
+
+ usb_attach(port, NULL);
+ dev->info->handle_destroy(dev);
+
+ TAILQ_INSERT_TAIL(&bus->free, port, next);
+ bus->nfree++;
+ return 0;
+}
+
+static const char *usb_speed(unsigned int speed)
+{
+ static const char *txt[] = {
+ [ USB_SPEED_LOW ] = "1.5",
+ [ USB_SPEED_FULL ] = "12",
+ [ USB_SPEED_HIGH ] = "480",
+ };
+ if (speed >= ARRAY_SIZE(txt))
+ return "?";
+ return txt[speed];
+}
+
+static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+{
+ USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBBus *bus = usb_bus_from_device(dev);
+
+ monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s\n", indent, "",
+ bus->busnr, dev->addr,
+ usb_speed(dev->speed), dev->devname);
+}
+
+void usb_info(Monitor *mon)
+{
+ USBBus *bus;
+ USBDevice *dev;
+ USBPort *port;
+
+ if (TAILQ_EMPTY(&busses)) {
+ monitor_printf(mon, "USB support not enabled\n");
+ return;
+ }
+
+ TAILQ_FOREACH(bus, &busses, next) {
+ TAILQ_FOREACH(port, &bus->used, next) {
+ dev = port->dev;
+ if (!dev)
+ continue;
+ monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n",
+ bus->busnr, dev->addr, usb_speed(dev->speed), dev->devname);
+ }
+ }
+}
+
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index c8b6ee7..0837ec1 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -871,21 +871,6 @@ static int usb_keyboard_initfn(USBDevice *dev)
return usb_hid_initfn(dev, USB_KEYBOARD);
}
-USBDevice *usb_tablet_init(void)
-{
- return usb_create_simple(NULL /* FIXME */, "QEMU USB Tablet");
-}
-
-USBDevice *usb_mouse_init(void)
-{
- return usb_create_simple(NULL /* FIXME */, "QEMU USB Mouse");
-}
-
-USBDevice *usb_keyboard_init(void)
-{
- return usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
-}
-
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
{
USBHIDState *s = (USBHIDState *)dev;
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 116b1d2..0a39986 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -531,18 +531,14 @@ static int usb_hub_initfn(USBDevice *dev)
s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
for (i = 0; i < s->nb_ports; i++) {
port = &s->ports[i];
- qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
+ usb_register_port(usb_bus_from_device(dev),
+ &port->port, s, i, usb_hub_attach);
port->wPortStatus = PORT_STAT_POWER;
port->wPortChange = 0;
}
return 0;
}
-USBDevice *usb_hub_init(int nb_ports)
-{
- return usb_create_simple(NULL /* FIXME */, "QEMU USB Hub");
-}
-
static struct USBDeviceInfo hub_info = {
.qdev.name = "QEMU USB Hub",
.qdev.size = sizeof(USBHubState),
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index b23ed3f..8fba84d 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -281,6 +281,7 @@ typedef struct {
struct MUSBState {
qemu_irq *irqs;
+ USBBus *bus;
USBPort port;
int idx;
@@ -330,7 +331,8 @@ struct MUSBState {
s->ep[i].epnum = i;
}
- qemu_register_usb_port(&s->port, s, 0, musb_attach);
+ s->bus = usb_bus_new(NULL /* FIXME */);
+ usb_register_port(s->bus, &s->port, s, 0, musb_attach);
return s;
}
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index e725e97..7f620c7 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -65,6 +65,7 @@ enum ohci_type {
};
typedef struct {
+ USBBus *bus;
qemu_irq irq;
enum ohci_type type;
int mem;
@@ -1688,9 +1689,10 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
ohci->irq = irq;
ohci->type = type;
+ ohci->bus = usb_bus_new(NULL /* FIXME */);
ohci->num_ports = num_ports;
for (i = 0; i < num_ports; i++) {
- qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
+ usb_register_port(ohci->bus, &ohci->rhport[i].port, ohci, i, ohci_attach);
}
ohci->async_td = 0;
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index a112a69..2ff287b 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -122,6 +122,7 @@ typedef struct UHCIPort {
typedef struct UHCIState {
PCIDevice dev;
+ USBBus *bus;
uint16_t cmd; /* cmd register */
uint16_t status;
uint16_t intr; /* interrupt enable register */
@@ -1089,8 +1090,9 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn)
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
+ s->bus = usb_bus_new(NULL /* FIXME */);
for(i = 0; i < NB_PORTS; i++) {
- qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
+ usb_register_port(s->bus, &s->ports[i].port, s, i, uhci_attach);
}
s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
@@ -1124,8 +1126,9 @@ void usb_uhci_piix4_init(PCIBus *bus, int devfn)
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
+ s->bus = usb_bus_new(NULL /* FIXME */);
for(i = 0; i < NB_PORTS; i++) {
- qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
+ usb_register_port(s->bus, &s->ports[i].port, s, i, uhci_attach);
}
s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index a5abb98..4007e0f 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -399,11 +399,6 @@ static int usb_wacom_initfn(USBDevice *dev)
return 0;
}
-USBDevice *usb_wacom_init(void)
-{
- return usb_create_simple(NULL /* FIXME */, "QEMU PenPartner Tablet");
-}
-
static struct USBDeviceInfo wacom_info = {
.qdev.name = "QEMU PenPartner Tablet",
.qdev.size = sizeof(USBWacomState),
diff --git a/hw/usb.h b/hw/usb.h
index dea5718..3632639 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -24,6 +24,7 @@
#include "block.h"
#include "qdev.h"
+#include "sys-queue.h"
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
@@ -132,6 +133,7 @@ struct USBDevice {
int speed;
uint8_t addr;
char devname[32];
+ int attached;
int state;
uint8_t setup_buf[8];
@@ -191,7 +193,7 @@ struct USBPort {
usb_attachfn attach;
void *opaque;
int index; /* internal port index, may be used with the opaque */
- struct USBPort *next; /* Used internally by qemu. */
+ TAILQ_ENTRY(USBPort) next;
};
typedef void USBCallback(USBPacket * packet, void *opaque);
@@ -236,25 +238,17 @@ static inline void usb_cancel_packet(USBPacket * p)
p->cancel_cb(p, p->cancel_opaque);
}
-int usb_device_add_dev(USBDevice *dev);
-int usb_device_del_addr(int bus_num, int addr);
void usb_attach(USBPort *port, USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str);
void usb_send_msg(USBDevice *dev, int msg);
-/* usb hub */
-USBDevice *usb_hub_init(int nb_ports);
-
/* usb-linux.c */
USBDevice *usb_host_device_open(const char *devname);
int usb_host_device_close(const char *devname);
void usb_host_info(Monitor *mon);
/* usb-hid.c */
-USBDevice *usb_mouse_init(void);
-USBDevice *usb_tablet_init(void);
-USBDevice *usb_keyboard_init(void);
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
/* usb-msd.c */
@@ -267,17 +261,11 @@ USBDevice *usb_net_init(NICInfo *nd);
/* usb-bt.c */
USBDevice *usb_bt_init(HCIInfo *hci);
-/* usb-wacom.c */
-USBDevice *usb_wacom_init(void);
-
/* usb-serial.c */
USBDevice *usb_serial_init(const char *filename);
/* usb ports of the VM */
-void qemu_register_usb_port(USBPort *port, void *opaque, int index,
- usb_attachfn attach);
-
#define VM_USB_HUB_SIZE 8
/* usb-musb.c */
@@ -319,4 +307,14 @@ USBBus *usb_bus_new(DeviceState *host);
USBBus *usb_bus_find(int busnr);
void usb_qdev_register(USBDeviceInfo *info);
void usb_qdev_register_many(USBDeviceInfo *info);
+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);
+int usb_device_attach(USBDevice *dev);
+int usb_device_delete_addr(int busnr, int addr);
+
+static inline USBBus *usb_bus_from_device(USBDevice *d)
+{
+ return DO_UPCAST(USBBus, qbus, d->qdev.parent_bus);
+}
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index dc7d3825ec59a33f065ea005014ffcf3a8b1b632..542beddc6fa9c267893283c919158be28f61cb05 100644
GIT binary patch
delta 18738
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
Dg%aIO
delta 13343
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
diff --git a/usb-linux.c b/usb-linux.c
index 0130b71..df3d54d 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -252,7 +252,7 @@ static void async_complete(void *opaque)
if (errno == ENODEV && !s->closing) {
printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr);
- usb_device_del_addr(0, s->dev.addr);
+ usb_device_delete_addr(s->bus_num, s->dev.addr);
return;
}
@@ -909,7 +909,7 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
}
dprintf("husb: opened %s\n", buf);
- d = usb_create_simple(NULL /* FIXME */, "USB Host Device");
+ d = usb_create(NULL /* FIXME */, "USB Host Device");
dev = DO_UPCAST(USBHostDevice, dev, d);
dev->bus_num = bus_num;
@@ -1039,16 +1039,16 @@ int usb_host_device_close(const char *devname)
if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name),
devname) < 0)
return -1;
-
+
s = hostdev_find(bus_num, addr);
if (s) {
- usb_device_del_addr(0, s->dev.addr);
+ usb_device_delete_addr(s->bus_num, s->dev.addr);
return 0;
}
return -1;
}
-
+
static int get_tag_value(char *buf, int buf_size,
const char *str, const char *tag,
const char *stopchars)
@@ -1387,7 +1387,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
dev = usb_host_device_open_addr(bus_num, addr, product_name);
if (dev)
- usb_device_add_dev(dev);
+ qdev_init(&dev->qdev);
}
return 0;
diff --git a/vl.c b/vl.c
index c362d1f..72f7dd6 100644
--- a/vl.c
+++ b/vl.c
@@ -2430,72 +2430,56 @@ static void smp_parse(const char *optarg)
/***********************************************************/
/* USB devices */
-static USBPort *used_usb_ports;
-static USBPort *free_usb_ports;
-
-/* ??? Maybe change this to register a hub to keep track of the topology. */
-void qemu_register_usb_port(USBPort *port, void *opaque, int index,
- usb_attachfn attach)
-{
- port->opaque = opaque;
- port->index = index;
- port->attach = attach;
- port->next = free_usb_ports;
- free_usb_ports = port;
-}
-
-int usb_device_add_dev(USBDevice *dev)
-{
- USBPort *port;
-
- /* Find a USB port to add the device to. */
- port = free_usb_ports;
- if (!port->next) {
- USBDevice *hub;
-
- /* Create a new hub and chain it on. */
- free_usb_ports = NULL;
- port->next = used_usb_ports;
- used_usb_ports = port;
-
- hub = usb_hub_init(VM_USB_HUB_SIZE);
- usb_attach(port, hub);
- port = free_usb_ports;
- }
-
- free_usb_ports = port->next;
- port->next = used_usb_ports;
- used_usb_ports = port;
- usb_attach(port, dev);
- return 0;
-}
-
static void usb_msd_password_cb(void *opaque, int err)
{
USBDevice *dev = opaque;
if (!err)
- usb_device_add_dev(dev);
+ usb_device_attach(dev);
else
dev->info->handle_destroy(dev);
}
+static struct {
+ const char *name;
+ const char *qdev;
+} usbdevs[] = {
+ {
+ .name = "mouse",
+ .qdev = "QEMU USB Mouse",
+ },{
+ .name = "tablet",
+ .qdev = "QEMU USB Tablet",
+ },{
+ .name = "keyboard",
+ .qdev = "QEMU USB Keyboard",
+ },{
+ .name = "wacom-tablet",
+ .qdev = "QEMU PenPartner Tablet",
+ }
+};
+
static int usb_device_add(const char *devname, int is_hotplug)
{
const char *p;
- USBDevice *dev;
+ USBBus *bus = usb_bus_find(-1 /* any */);
+ USBDevice *dev = NULL;
+ int i;
- if (!free_usb_ports)
+ if (!usb_enabled)
return -1;
+ /* simple devices which don't need extra care */
+ for (i = 0; i < ARRAY_SIZE(usbdevs); i++) {
+ if (strcmp(devname, usbdevs[i].name) != 0)
+ continue;
+ dev = usb_create_simple(bus, usbdevs[i].qdev);
+ goto done;
+ }
+
+ /* the other ones */
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(p);
- } else if (!strcmp(devname, "mouse")) {
- dev = usb_mouse_init();
- } else if (!strcmp(devname, "tablet")) {
- dev = usb_tablet_init();
- } else if (!strcmp(devname, "keyboard")) {
- dev = usb_keyboard_init();
} else if (strstart(devname, "disk:", &p)) {
BlockDriverState *bs;
@@ -2511,8 +2495,6 @@ static int usb_device_add(const char *devname, int is_hotplug)
return 0;
}
}
- } else if (!strcmp(devname, "wacom-tablet")) {
- dev = usb_wacom_init();
} else if (strstart(devname, "serial:", &p)) {
dev = usb_serial_init(p);
#ifdef CONFIG_BRLAPI
@@ -2535,37 +2517,7 @@ static int usb_device_add(const char *devname, int is_hotplug)
if (!dev)
return -1;
- return usb_device_add_dev(dev);
-}
-
-int usb_device_del_addr(int bus_num, int addr)
-{
- USBPort *port;
- USBPort **lastp;
- USBDevice *dev;
-
- if (!used_usb_ports)
- return -1;
-
- if (bus_num != 0)
- return -1;
-
- lastp = &used_usb_ports;
- port = used_usb_ports;
- while (port && port->dev->addr != addr) {
- lastp = &port->next;
- port = port->next;
- }
-
- if (!port)
- return -1;
-
- dev = port->dev;
- *lastp = port->next;
- usb_attach(port, NULL);
- dev->info->handle_destroy(dev);
- port->next = free_usb_ports;
- free_usb_ports = port;
+done:
return 0;
}
@@ -2577,7 +2529,7 @@ static int usb_device_del(const char *devname)
if (strstart(devname, "host:", &p))
return usb_host_device_close(p);
- if (!used_usb_ports)
+ if (!usb_enabled)
return -1;
p = strchr(devname, '.');
@@ -2586,7 +2538,7 @@ static int usb_device_del(const char *devname)
bus_num = strtoul(devname, NULL, 0);
addr = strtoul(p + 1, NULL, 0);
- return usb_device_del_addr(bus_num, addr);
+ return usb_device_delete_addr(bus_num, addr);
}
static int usb_parse(const char *cmdline)
@@ -2604,40 +2556,6 @@ void do_usb_del(Monitor *mon, const char *devname)
usb_device_del(devname);
}
-void usb_info(Monitor *mon)
-{
- USBDevice *dev;
- USBPort *port;
- const char *speed_str;
-
- if (!usb_enabled) {
- monitor_printf(mon, "USB support not enabled\n");
- return;
- }
-
- for (port = used_usb_ports; port; port = port->next) {
- dev = port->dev;
- if (!dev)
- continue;
- switch(dev->speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
- break;
- case USB_SPEED_FULL:
- speed_str = "12";
- break;
- case USB_SPEED_HIGH:
- speed_str = "480";
- break;
- default:
- speed_str = "?";
- break;
- }
- monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n",
- 0, dev->addr, speed_str, dev->devname);
- }
-}
-
/***********************************************************/
/* PCMCIA/Cardbus */
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 5/9] qdev/usb: add some convinience aliases.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
` (3 preceding siblings ...)
2009-08-31 12:24 ` [Qemu-devel] [PATCH 4/9] qdev/usb: make qemu aware of usb busses Gerd Hoffmann
@ 2009-08-31 12:24 ` Gerd Hoffmann
2009-08-31 12:24 ` [Qemu-devel] [PATCH 6/9] qdev/usb: convert uhci Gerd Hoffmann
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-hid.c | 3 +++
hw/usb-wacom.c | 1 +
2 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 0837ec1..3bf06fa 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -882,6 +882,7 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
static struct USBDeviceInfo hid_info[] = {
{
.qdev.name = "QEMU USB Tablet",
+ .qdev.alias = "usb-tablet",
.qdev.size = sizeof(USBHIDState),
.init = usb_tablet_initfn,
.handle_packet = usb_generic_handle_packet,
@@ -891,6 +892,7 @@ static struct USBDeviceInfo hid_info[] = {
.handle_destroy = usb_hid_handle_destroy,
},{
.qdev.name = "QEMU USB Mouse",
+ .qdev.alias = "usb-mouse",
.qdev.size = sizeof(USBHIDState),
.init = usb_mouse_initfn,
.handle_packet = usb_generic_handle_packet,
@@ -900,6 +902,7 @@ static struct USBDeviceInfo hid_info[] = {
.handle_destroy = usb_hid_handle_destroy,
},{
.qdev.name = "QEMU USB Keyboard",
+ .qdev.alias = "usb-kbd",
.qdev.size = sizeof(USBHIDState),
.init = usb_keyboard_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 4007e0f..55f06bf 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -401,6 +401,7 @@ static int usb_wacom_initfn(USBDevice *dev)
static struct USBDeviceInfo wacom_info = {
.qdev.name = "QEMU PenPartner Tablet",
+ .qdev.alias = "wacom-tablet",
.qdev.size = sizeof(USBWacomState),
.init = usb_wacom_initfn,
.handle_packet = usb_generic_handle_packet,
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 6/9] qdev/usb: convert uhci.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
` (4 preceding siblings ...)
2009-08-31 12:24 ` [Qemu-devel] [PATCH 5/9] qdev/usb: add some convinience aliases Gerd Hoffmann
@ 2009-08-31 12:24 ` Gerd Hoffmann
2009-08-31 12:24 ` [Qemu-devel] [PATCH 7/9] qdev/usb: convert ohci Gerd Hoffmann
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Hookup pci device into qdev.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-uhci.c | 78 +++++++++++++++++++++++++++++++-------------------------
1 files changed, 43 insertions(+), 35 deletions(-)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 2ff287b..09ffd4b 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1071,18 +1071,11 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
-void usb_uhci_piix3_init(PCIBus *bus, int devfn)
+static int usb_uhci_common_initfn(UHCIState *s)
{
- UHCIState *s;
- uint8_t *pci_conf;
+ uint8_t *pci_conf = s->dev.config;
int i;
- s = (UHCIState *)pci_register_device(bus,
- "USB-UHCI", sizeof(UHCIState),
- devfn, NULL, NULL);
- pci_conf = s->dev.config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_2);
pci_conf[0x08] = 0x01; // revision number
pci_conf[0x09] = 0x00;
pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
@@ -1090,7 +1083,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn)
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
- s->bus = usb_bus_new(NULL /* FIXME */);
+ s->bus = usb_bus_new(&s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(s->bus, &s->ports[i].port, s, i, uhci_attach);
}
@@ -1105,40 +1098,55 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn)
PCI_ADDRESS_SPACE_IO, uhci_map);
register_savevm("uhci", 0, 1, uhci_save, uhci_load, s);
+ return 0;
}
-void usb_uhci_piix4_init(PCIBus *bus, int devfn)
+static int usb_uhci_piix3_initfn(PCIDevice *dev)
{
- UHCIState *s;
- uint8_t *pci_conf;
- int i;
+ UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_2);
+ return usb_uhci_common_initfn(s);
+}
+
+static int usb_uhci_piix4_initfn(PCIDevice *dev)
+{
+ UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
- s = (UHCIState *)pci_register_device(bus,
- "USB-UHCI", sizeof(UHCIState),
- devfn, NULL, NULL);
- pci_conf = s->dev.config;
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_2);
- pci_conf[0x08] = 0x01; // revision number
- pci_conf[0x09] = 0x00;
- pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
- pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
- pci_conf[0x3d] = 4; // interrupt pin 3
- pci_conf[0x60] = 0x10; // release number
+ return usb_uhci_common_initfn(s);
+}
- s->bus = usb_bus_new(NULL /* FIXME */);
- for(i = 0; i < NB_PORTS; i++) {
- usb_register_port(s->bus, &s->ports[i].port, s, i, uhci_attach);
+static PCIDeviceInfo uhci_info[] = {
+ {
+ .qdev.name = "PIIX3 USB-UHCI",
+ .qdev.size = sizeof(UHCIState),
+ .init = usb_uhci_piix3_initfn,
+ },{
+ .qdev.name = "PIIX4 USB-UHCI",
+ .qdev.size = sizeof(UHCIState),
+ .init = usb_uhci_piix4_initfn,
+ },{
+ /* end of list */
}
- s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
+};
- qemu_register_reset(uhci_reset, s);
- uhci_reset(s);
+static void uhci_register(void)
+{
+ pci_qdev_register_many(uhci_info);
+}
+device_init(uhci_register);
- /* Use region 4 for consistency with real hardware. BSD guests seem
- to rely on this. */
- pci_register_bar(&s->dev, 4, 0x20,
- PCI_ADDRESS_SPACE_IO, uhci_map);
+void usb_uhci_piix3_init(PCIBus *bus, int devfn)
+{
+ pci_create_simple(bus, devfn, "PIIX3 USB-UHCI");
+}
- register_savevm("uhci", 0, 1, uhci_save, uhci_load, s);
+void usb_uhci_piix4_init(PCIBus *bus, int devfn)
+{
+ pci_create_simple(bus, devfn, "PIIX4 USB-UHCI");
}
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 7/9] qdev/usb: convert ohci.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
` (5 preceding siblings ...)
2009-08-31 12:24 ` [Qemu-devel] [PATCH 6/9] qdev/usb: convert uhci Gerd Hoffmann
@ 2009-08-31 12:24 ` Gerd Hoffmann
2009-08-31 12:24 ` [Qemu-devel] [PATCH 8/9] qdev/scsi: add scsi bus support to qdev, convert drivers Gerd Hoffmann
2009-08-31 12:24 ` [Qemu-devel] [PATCH 9/9] qdev/scsi+usb: convert usb-storage to qdev Gerd Hoffmann
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Drop num_ports argument for usb_ohci_init_pci(), everybody
calls it with num_ports == 3, so it is pointless.
Convert ohci pci device into qdev.
TODO: convert non-pci ohci adapters.
You can add a OHCI USB Controller to your virtual pc now using
'-device pci-ohci'. Specifying a id is a good idea, so you can
attach usb devices to it, like this:
-device pci-ohci,id=ohci
-device usb-mouse,bus=ohci.0
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/pci.h | 2 +-
hw/ppc_newworld.c | 2 +-
hw/ppc_oldworld.c | 2 +-
hw/ppc_prep.c | 2 +-
hw/realview.c | 2 +-
hw/usb-ohci.c | 44 +++++++++++++++++++++++++++++---------------
hw/versatilepb.c | 2 +-
7 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/hw/pci.h b/hw/pci.h
index fd1d35c..f94341a 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -341,7 +341,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn);
void usb_uhci_piix4_init(PCIBus *bus, int devfn);
/* usb-ohci.c */
-void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn);
+void usb_ohci_init_pci(struct PCIBus *bus, int devfn);
/* prep_pci.c */
PCIBus *pci_prep_init(qemu_irq *pic);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 3ad0057..ecd79fb 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -334,7 +334,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
escc_mem_index);
if (usb_enabled) {
- usb_ohci_init_pci(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, -1);
}
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index fc0e6f7..2986d67 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -361,7 +361,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
escc_mem_index);
if (usb_enabled) {
- usb_ohci_init_pci(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, -1);
}
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 1cad17f..d336b7f 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -746,7 +746,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
#endif
if (usb_enabled) {
- usb_ohci_init_pci(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, -1);
}
m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
diff --git a/hw/realview.c b/hw/realview.c
index 8e176b9..a55fba7 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -111,7 +111,7 @@ static void realview_init(ram_addr_t ram_size,
pic[48], pic[49], pic[50], pic[51], NULL);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
if (usb_enabled) {
- usb_ohci_init_pci(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, -1);
}
n = drive_get_max_bus(IF_SCSI);
while (n >= 0) {
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 7f620c7..96a9555 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1660,7 +1660,8 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
ohci_mem_write
};
-static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
+static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
+ int num_ports, int devfn,
qemu_irq irq, enum ohci_type type,
const char *name, uint32_t localmem_base)
{
@@ -1689,7 +1690,7 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
ohci->irq = irq;
ohci->type = type;
- ohci->bus = usb_bus_new(NULL /* FIXME */);
+ ohci->bus = usb_bus_new(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_attach);
@@ -1712,17 +1713,10 @@ static void ohci_mapfunc(PCIDevice *pci_dev, int i,
cpu_register_physical_memory(addr, size, ohci->state.mem);
}
-void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
+static int usb_ohci_initfn_pci(struct PCIDevice *dev)
{
- OHCIPCIState *ohci;
-
- ohci = DO_UPCAST(OHCIPCIState, pci_dev,
- pci_register_device(bus, "OHCI USB", sizeof(*ohci),
- devfn, NULL, NULL));
- if (ohci == NULL) {
- fprintf(stderr, "usb-ohci: Failed to register PCI device\n");
- return;
- }
+ OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
+ int num_ports = 3;
pci_config_set_vendor_id(ohci->pci_dev.config, PCI_VENDOR_ID_APPLE);
pci_config_set_device_id(ohci->pci_dev.config,
@@ -1731,11 +1725,18 @@ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
pci_config_set_class(ohci->pci_dev.config, PCI_CLASS_SERIAL_USB);
ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
- usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
+ usb_ohci_init(&ohci->state, &dev->qdev, num_ports,
+ ohci->pci_dev.devfn, ohci->pci_dev.irq[0],
OHCI_TYPE_PCI, ohci->pci_dev.name, 0);
pci_register_bar((struct PCIDevice *)ohci, 0, 256,
PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
+ return 0;
+}
+
+void usb_ohci_init_pci(struct PCIBus *bus, int devfn)
+{
+ pci_create_simple(bus, devfn, "OHCI USB PCI");
}
void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
@@ -1743,7 +1744,7 @@ void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
{
OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
- usb_ohci_init(ohci, num_ports, devfn, irq,
+ usb_ohci_init(ohci, NULL /* FIXME */, num_ports, devfn, irq,
OHCI_TYPE_PXA, "OHCI USB", 0);
cpu_register_physical_memory(base, 0x1000, ohci->mem);
@@ -1754,9 +1755,22 @@ void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
{
OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
- usb_ohci_init(ohci, num_ports, devfn, irq,
+ usb_ohci_init(ohci, NULL /* FIXME */, num_ports, devfn, irq,
OHCI_TYPE_SM501, "OHCI USB", localmem_base);
cpu_register_physical_memory(mmio_base, 0x1000, ohci->mem);
}
+static PCIDeviceInfo ohci_info = {
+ .qdev.name = "OHCI USB PCI",
+ .qdev.alias = "pci-ohci",
+ .qdev.desc = "Apple USB Controller",
+ .qdev.size = sizeof(OHCIPCIState),
+ .init = usb_ohci_initfn_pci,
+};
+
+static void ohci_register(void)
+{
+ pci_qdev_register(&ohci_info);
+}
+device_init(ohci_register);
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 4c01720..29b85ae 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -217,7 +217,7 @@ static void versatile_init(ram_addr_t ram_size,
}
}
if (usb_enabled) {
- usb_ohci_init_pci(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, -1);
}
n = drive_get_max_bus(IF_SCSI);
while (n >= 0) {
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 8/9] qdev/scsi: add scsi bus support to qdev, convert drivers.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
` (6 preceding siblings ...)
2009-08-31 12:24 ` [Qemu-devel] [PATCH 7/9] qdev/usb: convert ohci Gerd Hoffmann
@ 2009-08-31 12:24 ` Gerd Hoffmann
2009-08-31 12:24 ` [Qemu-devel] [PATCH 9/9] qdev/scsi+usb: convert usb-storage to qdev Gerd Hoffmann
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
* Add SCSIBus.
* Add SCSIDeviceInfo, move device callbacks here.
* add qdev/scsi helper functions.
* convert drivers.
Adding scsi disks via -device works now, i.e. you can do:
-drive id=sda,if=none,...
-device lsi
-device scsi-disk,drive=sda
legacy command lines (-drive if=scsi,...) continue to work.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
Makefile | 2 +-
hw/esp.c | 54 +++++-------------
hw/lsi53c895a.c | 65 +++++++---------------
hw/pci-hotplug.c | 7 ++-
hw/pci.h | 1 -
hw/qdev.c | 19 ------
hw/qdev.h | 4 -
hw/scsi-bus.c | 93 +++++++++++++++++++++++++++++++
hw/scsi-disk.c | 158 ++++++++++++++++++++++++++++-------------------------
hw/scsi-disk.h | 51 ++++++++++++++---
hw/scsi-generic.c | 145 ++++++++++++++++++++++++++-----------------------
hw/usb-msd.c | 26 +++++----
12 files changed, 351 insertions(+), 274 deletions(-)
create mode 100644 hw/scsi-bus.c
diff --git a/Makefile b/Makefile
index 735282c..013e2c1 100644
--- a/Makefile
+++ b/Makefile
@@ -81,7 +81,7 @@ obj-y += i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
obj-y += ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
obj-y += tmp105.o lm832x.o eeprom93xx.o tsc2005.o
obj-y += scsi-disk.o cdrom.o
-obj-y += scsi-generic.o
+obj-y += scsi-generic.o scsi-bus.o
obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
obj-y += usb-serial.o usb-net.o usb-bus.o
obj-y += sd.o ssi-sd.o
diff --git a/hw/esp.c b/hw/esp.c
index aad547e..527faa8 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -63,7 +63,7 @@ struct ESPState {
uint8_t ti_buf[TI_BUFSZ];
uint32_t sense;
uint32_t dma;
- SCSIDevice *scsi_dev[ESP_MAX_DEVS];
+ SCSIBus *bus;
SCSIDevice *current_dev;
uint8_t cmdbuf[TI_BUFSZ];
uint32_t cmdlen;
@@ -187,11 +187,11 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
if (s->current_dev) {
/* Started a new command before the old one finished. Cancel it. */
- s->current_dev->cancel_io(s->current_dev, 0);
+ s->current_dev->info->cancel_io(s->current_dev, 0);
s->async_len = 0;
}
- if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) {
+ if (target >= ESP_MAX_DEVS || !s->bus->devs[target]) {
// No such drive
s->rregs[ESP_RSTAT] = 0;
s->rregs[ESP_RINTR] = INTR_DC;
@@ -199,7 +199,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
esp_raise_irq(s);
return 0;
}
- s->current_dev = s->scsi_dev[target];
+ s->current_dev = s->bus->devs[target];
return dmalen;
}
@@ -210,7 +210,7 @@ static void do_cmd(ESPState *s, uint8_t *buf)
DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
lun = buf[0] & 7;
- datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
+ datalen = s->current_dev->info->send_command(s->current_dev, 0, &buf[1], lun);
s->ti_size = datalen;
if (datalen != 0) {
s->rregs[ESP_RSTAT] = STAT_TC;
@@ -218,10 +218,10 @@ static void do_cmd(ESPState *s, uint8_t *buf)
s->dma_counter = 0;
if (datalen > 0) {
s->rregs[ESP_RSTAT] |= STAT_DI;
- s->current_dev->read_data(s->current_dev, 0);
+ s->current_dev->info->read_data(s->current_dev, 0);
} else {
s->rregs[ESP_RSTAT] |= STAT_DO;
- s->current_dev->write_data(s->current_dev, 0);
+ s->current_dev->info->write_data(s->current_dev, 0);
}
}
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
@@ -320,9 +320,9 @@ static void esp_do_dma(ESPState *s)
if (s->async_len == 0) {
if (to_device) {
// ti_size is negative
- s->current_dev->write_data(s->current_dev, 0);
+ s->current_dev->info->write_data(s->current_dev, 0);
} else {
- s->current_dev->read_data(s->current_dev, 0);
+ s->current_dev->info->read_data(s->current_dev, 0);
/* If there is still data to be read from the device then
complete the DMA operation immediately. Otherwise defer
until the scsi layer has completed. */
@@ -336,10 +336,10 @@ static void esp_do_dma(ESPState *s)
}
}
-static void esp_command_complete(void *opaque, int reason, uint32_t tag,
+static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag,
uint32_t arg)
{
- ESPState *s = (ESPState *)opaque;
+ ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent);
if (reason == SCSI_REASON_DONE) {
DPRINTF("SCSI Command complete\n");
@@ -357,7 +357,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag,
} else {
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
s->async_len = arg;
- s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
+ s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0);
if (s->dma_left) {
esp_do_dma(s);
} else if (s->dma_counter != 0 && s->ti_size <= 0) {
@@ -633,33 +633,6 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static void esp_scsi_attach(DeviceState *host, BlockDriverState *bd, int id)
-{
- ESPState *s = FROM_SYSBUS(ESPState, sysbus_from_qdev(host));
-
- if (id < 0) {
- for (id = 0; id < ESP_MAX_DEVS; id++) {
- if (id == (s->rregs[ESP_CFG1] & 0x7))
- continue;
- if (s->scsi_dev[id] == NULL)
- break;
- }
- }
- if (id >= ESP_MAX_DEVS) {
- DPRINTF("Bad Device ID %d\n", id);
- return;
- }
- if (s->scsi_dev[id]) {
- DPRINTF("Destroying device %d\n", id);
- s->scsi_dev[id]->destroy(s->scsi_dev[id]);
- }
- DPRINTF("Attaching block device %d\n", id);
- /* Command queueing is not implemented. */
- s->scsi_dev[id] = scsi_generic_init(bd, 0, esp_command_complete, s);
- if (s->scsi_dev[id] == NULL)
- s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
-}
-
void esp_init(target_phys_addr_t espaddr, int it_shift,
espdma_memory_read_write dma_memory_read,
espdma_memory_read_write dma_memory_write,
@@ -700,7 +673,8 @@ static int esp_init1(SysBusDevice *dev)
qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1);
- scsi_bus_new(&dev->qdev, esp_scsi_attach);
+ s->bus = scsi_bus_new(&dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
+ scsi_bus_legacy_handle_cmdline(s->bus);
return 0;
}
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index bf9f072..62bdca8 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -14,6 +14,7 @@
#include "hw.h"
#include "pci.h"
+#include "scsi.h"
#include "scsi-disk.h"
#include "block_int.h"
@@ -192,7 +193,7 @@ typedef struct {
* 2 if processing DMA from lsi_execute_script.
* 3 if a DMA operation is in progress. */
int waiting;
- SCSIDevice *scsi_dev[LSI_MAX_DEVS];
+ SCSIBus *bus;
SCSIDevice *current_dev;
int current_lun;
/* The tag is a combination of the device ID and the SCSI tag. */
@@ -510,8 +511,8 @@ static void lsi_do_dma(LSIState *s, int out)
s->dbc -= count;
if (s->dma_buf == NULL) {
- s->dma_buf = s->current_dev->get_buf(s->current_dev,
- s->current_tag);
+ s->dma_buf = s->current_dev->info->get_buf(s->current_dev,
+ s->current_tag);
}
/* ??? Set SFBR to first data byte. */
@@ -525,10 +526,10 @@ static void lsi_do_dma(LSIState *s, int out)
s->dma_buf = NULL;
if (out) {
/* Write the data. */
- s->current_dev->write_data(s->current_dev, s->current_tag);
+ s->current_dev->info->write_data(s->current_dev, s->current_tag);
} else {
/* Request any remaining data. */
- s->current_dev->read_data(s->current_dev, s->current_tag);
+ s->current_dev->info->read_data(s->current_dev, s->current_tag);
}
} else {
s->dma_buf += count;
@@ -584,7 +585,7 @@ static void lsi_reselect(LSIState *s, uint32_t tag)
id = (tag >> 8) & 0xf;
s->ssid = id | 0x80;
DPRINTF("Reselected target %d\n", id);
- s->current_dev = s->scsi_dev[id];
+ s->current_dev = s->bus->devs[id];
s->current_tag = tag;
s->scntl1 |= LSI_SCNTL1_CON;
lsi_set_phase(s, PHASE_MI);
@@ -632,10 +633,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
}
/* Callback to indicate that the SCSI layer has completed a transfer. */
-static void lsi_command_complete(void *opaque, int reason, uint32_t tag,
+static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
uint32_t arg)
{
- LSIState *s = opaque;
+ LSIState *s = DO_UPCAST(LSIState, dev.qdev, bus->qbus.parent);
int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
@@ -680,14 +681,14 @@ static void lsi_do_command(LSIState *s)
cpu_physical_memory_read(s->dnad, buf, s->dbc);
s->sfbr = buf[0];
s->command_complete = 0;
- n = s->current_dev->send_command(s->current_dev, s->current_tag, buf,
- s->current_lun);
+ n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf,
+ s->current_lun);
if (n > 0) {
lsi_set_phase(s, PHASE_DI);
- s->current_dev->read_data(s->current_dev, s->current_tag);
+ s->current_dev->info->read_data(s->current_dev, s->current_tag);
} else if (n < 0) {
lsi_set_phase(s, PHASE_DO);
- s->current_dev->write_data(s->current_dev, s->current_tag);
+ s->current_dev->info->write_data(s->current_dev, s->current_tag);
}
if (!s->command_complete) {
@@ -1040,7 +1041,7 @@ again:
}
s->sstat0 |= LSI_SSTAT0_WOA;
s->scntl1 &= ~LSI_SCNTL1_IARB;
- if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) {
+ if (id >= LSI_MAX_DEVS || !s->bus->devs[id]) {
DPRINTF("Selected absent target %d\n", id);
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
@@ -1051,7 +1052,7 @@ again:
/* ??? Linux drivers compain when this is set. Maybe
it only applies in low-level mode (unimplemented).
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
- s->current_dev = s->scsi_dev[id];
+ s->current_dev = s->bus->devs[id];
s->current_tag = id << 8;
s->scntl1 |= LSI_SCNTL1_CON;
if (insn & (1 << 3)) {
@@ -1958,31 +1959,6 @@ static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
}
-void lsi_scsi_attach(DeviceState *host, BlockDriverState *bd, int id)
-{
- LSIState *s = DO_UPCAST(LSIState, dev.qdev, host);
-
- if (id < 0) {
- for (id = 0; id < LSI_MAX_DEVS; id++) {
- if (s->scsi_dev[id] == NULL)
- break;
- }
- }
- if (id >= LSI_MAX_DEVS) {
- BADF("Bad Device ID %d\n", id);
- return;
- }
- if (s->scsi_dev[id]) {
- DPRINTF("Destroying device %d\n", id);
- s->scsi_dev[id]->destroy(s->scsi_dev[id]);
- }
- DPRINTF("Attaching block device %d\n", id);
- s->scsi_dev[id] = scsi_generic_init(bd, 1, lsi_command_complete, s);
- if (s->scsi_dev[id] == NULL)
- s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
- bd->private = &s->dev;
-}
-
static void lsi_scsi_save(QEMUFile *f, void *opaque)
{
LSIState *s = opaque;
@@ -2202,16 +2178,17 @@ static int lsi_scsi_init(PCIDevice *dev)
lsi_soft_reset(s);
- scsi_bus_new(&dev->qdev, lsi_scsi_attach);
-
+ s->bus = scsi_bus_new(&dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
+ scsi_bus_legacy_handle_cmdline(s->bus);
register_savevm("lsiscsi", -1, 0, lsi_scsi_save, lsi_scsi_load, s);
return 0;
}
static PCIDeviceInfo lsi_info = {
- .qdev.name = "lsi53c895a",
- .qdev.size = sizeof(LSIState),
- .init = lsi_scsi_init,
+ .qdev.name = "lsi53c895a",
+ .qdev.alias = "lsi",
+ .qdev.size = sizeof(LSIState),
+ .init = lsi_scsi_init,
};
static void lsi53c895a_register_devices(void)
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 26ff808..18c2562 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -30,6 +30,7 @@
#include "pc.h"
#include "monitor.h"
#include "block_int.h"
+#include "scsi-disk.h"
#include "virtio-blk.h"
#if defined(TARGET_I386) || defined(TARGET_X86_64)
@@ -56,6 +57,7 @@ void drive_hot_add(Monitor *mon, const char *pci_addr, const char *opts)
int success = 0;
PCIDevice *dev;
DriveInfo *dinfo;
+ BusState *scsibus;
if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
return;
@@ -80,8 +82,9 @@ void drive_hot_add(Monitor *mon, const char *pci_addr, const char *opts)
switch (type) {
case IF_SCSI:
success = 1;
- lsi_scsi_attach(&dev->qdev, dinfo->bdrv,
- dinfo->unit);
+ scsibus = LIST_FIRST(&dev->qdev.child_bus);
+ scsi_bus_legacy_add_drive(DO_UPCAST(SCSIBus, qbus, scsibus),
+ dinfo, dinfo->unit);
break;
default:
monitor_printf(mon, "Can't hot-add drive to type %d\n", type);
diff --git a/hw/pci.h b/hw/pci.h
index f94341a..d0edfdb 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -331,7 +331,6 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
/* lsi53c895a.c */
#define LSI_MAX_DEVS 7
-void lsi_scsi_attach(DeviceState *host, BlockDriverState *bd, int id);
/* vmware_vga.c */
void pci_vmsvga_init(PCIBus *bus);
diff --git a/hw/qdev.c b/hw/qdev.c
index f9754b1..0e9732b 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -314,25 +314,6 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
return NULL;
}
-static int next_scsi_bus;
-
-/* Create a scsi bus, and attach devices to it. */
-/* TODO: Actually create a scsi bus for hotplug to use. */
-void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
-{
- int bus = next_scsi_bus++;
- int unit;
- DriveInfo *dinfo;
-
- for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
- dinfo = drive_get(IF_SCSI, bus, unit);
- if (!dinfo) {
- continue;
- }
- attach(host, dinfo->bdrv, unit);
- }
-}
-
static BusState *qbus_find_recursive(BusState *bus, const char *name,
const BusInfo *info)
{
diff --git a/hw/qdev.h b/hw/qdev.h
index af735d7..56a0c1f 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -99,8 +99,6 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
/*** Device API. ***/
typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
-typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
- int unit);
struct DeviceInfo {
const char *name;
@@ -123,8 +121,6 @@ void qdev_register(DeviceInfo *info);
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
-void scsi_bus_new(DeviceState *host, SCSIAttachFn attach);
-
CharDriverState *qdev_init_chardev(DeviceState *dev);
BusState *qdev_get_parent_bus(DeviceState *dev);
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
new file mode 100644
index 0000000..16afa05
--- /dev/null
+++ b/hw/scsi-bus.c
@@ -0,0 +1,93 @@
+#include "hw.h"
+#include "sysemu.h"
+#include "scsi-disk.h"
+#include "block.h"
+#include "qdev.h"
+
+static struct BusInfo scsi_bus_info = {
+ .name = "SCSI",
+ .size = sizeof(SCSIBus),
+ .props = (Property[]) {
+ DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+static int next_scsi_bus;
+
+/* Create a scsi bus, and attach devices to it. */
+SCSIBus *scsi_bus_new(DeviceState *host, int tcq, int ndev,
+ scsi_completionfn complete)
+{
+ SCSIBus *bus;
+
+ bus = FROM_QBUS(SCSIBus, qbus_create(&scsi_bus_info, host, NULL));
+ bus->busnr = next_scsi_bus++;
+ bus->tcq = tcq;
+ bus->ndev = ndev;
+ bus->complete = complete;
+ return bus;
+}
+
+static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+ SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+
+ if (dev->id == -1) {
+ for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
+ if (bus->devs[dev->id] == NULL)
+ break;
+ }
+ }
+ if (dev->id >= bus->ndev) {
+ qemu_error("bad scsi device id: %d\n", dev->id);
+ goto err;
+ }
+
+ if (bus->devs[dev->id]) {
+ bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
+ }
+ bus->devs[dev->id] = dev;
+
+ dev->info = info;
+ return dev->info->init(dev);
+
+err:
+ return -1;
+}
+
+void scsi_qdev_register(SCSIDeviceInfo *info)
+{
+ info->qdev.bus_info = &scsi_bus_info;
+ info->qdev.init = scsi_qdev_init;
+ qdev_register(&info->qdev);
+}
+
+/* handle legacy '-drive if=scsi,...' cmd line args */
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit)
+{
+ const char *driver;
+ DeviceState *dev;
+
+ driver = bdrv_is_sg(dinfo->bdrv) ? "scsi-generic" : "scsi-disk";
+ dev = qdev_create(&bus->qbus, driver);
+ qdev_prop_set_uint32(dev, "scsi-id", unit);
+ qdev_prop_set_drive(dev, "drive", dinfo);
+ qdev_init(dev);
+ return DO_UPCAST(SCSIDevice, qdev, dev);
+}
+
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
+{
+ DriveInfo *dinfo;
+ int unit;
+
+ for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
+ dinfo = drive_get(IF_SCSI, bus->busnr, unit);
+ if (dinfo == NULL) {
+ continue;
+ }
+ scsi_bus_legacy_add_drive(bus, dinfo, unit);
+ }
+}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5b825c9..ffc2654 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -44,8 +44,11 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_REQ_STATUS_RETRY 0x01
+typedef struct SCSIDiskState SCSIDiskState;
+
typedef struct SCSIRequest {
- SCSIDeviceState *dev;
+ SCSIBus *bus;
+ SCSIDiskState *dev;
uint32_t tag;
/* ??? We should probably keep track of whether the data transfer is
a read or a write. Currently we rely on the host getting it right. */
@@ -59,20 +62,16 @@ typedef struct SCSIRequest {
uint32_t status;
} SCSIRequest;
-struct SCSIDeviceState
+struct SCSIDiskState
{
- BlockDriverState *bdrv;
+ SCSIDevice qdev;
+ DriveInfo *dinfo;
SCSIRequest *requests;
/* The qemu block layer uses a fixed 512 byte sector size.
This is the number of 512 byte blocks in a single scsi sector. */
int cluster_size;
uint64_t max_lba;
int sense;
- int tcq;
- /* Completion functions may be called from either scsi_{read,write}_data
- or from the AIO completion routines. */
- scsi_completionfn completion;
- void *opaque;
char drive_serial_str[21];
QEMUBH *bh;
};
@@ -80,8 +79,9 @@ struct SCSIDeviceState
/* Global pool of SCSIRequest structures. */
static SCSIRequest *free_requests = NULL;
-static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag)
{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *r;
if (free_requests) {
@@ -91,6 +91,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
r = qemu_malloc(sizeof(SCSIRequest));
r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
}
+ r->bus = scsi_bus_from_device(d);
r->dev = s;
r->tag = tag;
r->sector_count = 0;
@@ -106,7 +107,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
static void scsi_remove_request(SCSIRequest *r)
{
SCSIRequest *last;
- SCSIDeviceState *s = r->dev;
+ SCSIDiskState *s = r->dev;
if (s->requests == r) {
s->requests = r->next;
@@ -124,7 +125,7 @@ static void scsi_remove_request(SCSIRequest *r)
free_requests = r;
}
-static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
+static SCSIRequest *scsi_find_request(SCSIDiskState *s, uint32_t tag)
{
SCSIRequest *r;
@@ -138,19 +139,19 @@ static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
/* Helper function for command completion. */
static void scsi_command_complete(SCSIRequest *r, int status, int sense)
{
- SCSIDeviceState *s = r->dev;
+ SCSIDiskState *s = r->dev;
uint32_t tag;
DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense);
s->sense = sense;
tag = r->tag;
scsi_remove_request(r);
- s->completion(s->opaque, SCSI_REASON_DONE, tag, status);
+ r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status);
}
/* Cancel a pending data transfer. */
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *r;
DPRINTF("Cancel tag=0x%x\n", tag);
r = scsi_find_request(s, tag);
@@ -165,23 +166,22 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
static void scsi_read_complete(void * opaque, int ret)
{
SCSIRequest *r = (SCSIRequest *)opaque;
- SCSIDeviceState *s = r->dev;
if (ret) {
DPRINTF("IO error\n");
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 0);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, 0);
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
return;
}
DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->tag, r->iov.iov_len);
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
}
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *r;
uint32_t n;
@@ -195,7 +195,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
r->sector_count = 0;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
return;
}
DPRINTF("Read sector_count=%d\n", r->sector_count);
@@ -210,7 +210,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
r->iov.iov_len = n * 512;
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
- r->aiocb = bdrv_aio_readv(s->bdrv, r->sector, &r->qiov, n,
+ r->aiocb = bdrv_aio_readv(s->dinfo->bdrv, r->sector, &r->qiov, n,
scsi_read_complete, r);
if (r->aiocb == NULL)
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
@@ -220,7 +220,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
static int scsi_handle_write_error(SCSIRequest *r, int error)
{
- BlockInterfaceErrorAction action = drive_get_onerror(r->dev->bdrv);
+ BlockInterfaceErrorAction action = drive_get_onerror(r->dev->dinfo->bdrv);
if (action == BLOCK_ERR_IGNORE)
return 0;
@@ -240,7 +240,6 @@ static int scsi_handle_write_error(SCSIRequest *r, int error)
static void scsi_write_complete(void * opaque, int ret)
{
SCSIRequest *r = (SCSIRequest *)opaque;
- SCSIDeviceState *s = r->dev;
uint32_t len;
uint32_t n;
@@ -263,19 +262,19 @@ static void scsi_write_complete(void * opaque, int ret)
}
r->iov.iov_len = len;
DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len);
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len);
}
}
static void scsi_write_request(SCSIRequest *r)
{
- SCSIDeviceState *s = r->dev;
+ SCSIDiskState *s = r->dev;
uint32_t n;
n = r->iov.iov_len / 512;
if (n) {
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
- r->aiocb = bdrv_aio_writev(s->bdrv, r->sector, &r->qiov, n,
+ r->aiocb = bdrv_aio_writev(s->dinfo->bdrv, r->sector, &r->qiov, n,
scsi_write_complete, r);
if (r->aiocb == NULL)
scsi_command_complete(r, STATUS_CHECK_CONDITION,
@@ -290,7 +289,7 @@ static void scsi_write_request(SCSIRequest *r)
The transfer may complete asynchronously. */
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *r;
DPRINTF("Write data tag=0x%x\n", tag);
@@ -311,7 +310,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
static void scsi_dma_restart_bh(void *opaque)
{
- SCSIDeviceState *s = opaque;
+ SCSIDiskState *s = opaque;
SCSIRequest *r = s->requests;
qemu_bh_delete(s->bh);
@@ -328,7 +327,7 @@ static void scsi_dma_restart_bh(void *opaque)
static void scsi_dma_restart_cb(void *opaque, int running, int reason)
{
- SCSIDeviceState *s = opaque;
+ SCSIDiskState *s = opaque;
if (!running)
return;
@@ -342,7 +341,7 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason)
/* Return a pointer to the data buffer. */
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *r;
r = scsi_find_request(s, tag);
@@ -361,7 +360,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
uint8_t *buf, int lun)
{
- SCSIDeviceState *s = d->state;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
uint64_t nb_sectors;
uint64_t lba;
uint32_t len;
@@ -379,7 +378,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
}
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
- r = scsi_new_request(s, tag);
+ r = scsi_new_request(d, tag);
outbuf = (uint8_t *)r->iov.iov_base;
is_write = 0;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
@@ -433,7 +432,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
switch (command) {
case 0x0:
DPRINTF("Test Unit Ready\n");
- if (!bdrv_is_inserted(s->bdrv))
+ if (!bdrv_is_inserted(s->dinfo->bdrv))
goto notready;
break;
case 0x03:
@@ -479,7 +478,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
r->iov.iov_len = 0;
- if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
outbuf[r->iov.iov_len++] = 5;
} else {
outbuf[r->iov.iov_len++] = 0;
@@ -510,7 +509,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
r->iov.iov_len = 0;
/* Supported page codes */
- if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
outbuf[r->iov.iov_len++] = 5;
} else {
outbuf[r->iov.iov_len++] = 0;
@@ -528,14 +527,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
{
/* Device identification page, mandatory */
int max_len = 255 - 8;
- int id_len = strlen(bdrv_get_device_name(s->bdrv));
+ int id_len = strlen(bdrv_get_device_name(s->dinfo->bdrv));
if (id_len > max_len)
id_len = max_len;
DPRINTF("Inquiry EVPD[Device identification] "
"buffer size %d\n", len);
r->iov.iov_len = 0;
- if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
outbuf[r->iov.iov_len++] = 5;
} else {
outbuf[r->iov.iov_len++] = 0;
@@ -551,7 +550,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
outbuf[r->iov.iov_len++] = id_len; // length of data following
memcpy(&outbuf[r->iov.iov_len],
- bdrv_get_device_name(s->bdrv), id_len);
+ bdrv_get_device_name(s->dinfo->bdrv), id_len);
r->iov.iov_len += id_len;
}
break;
@@ -591,7 +590,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
if (lun || buf[1] >> 5) {
outbuf[0] = 0x7f; /* LUN not supported */
- } else if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ } else if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
outbuf[0] = 5;
outbuf[1] = 0x80;
memcpy(&outbuf[16], "QEMU CD-ROM ", 16);
@@ -607,7 +606,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
outbuf[3] = 2; /* Format 2 */
outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */
/* Sync data transfer and TCQ. */
- outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0);
+ outbuf[7] = 0x10 | (r->bus->tcq ? 0x02 : 0);
r->iov.iov_len = len;
break;
case 0x16:
@@ -632,7 +631,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
memset(p, 0, 4);
outbuf[1] = 0; /* Default media type. */
outbuf[3] = 0; /* Block descriptor length. */
- if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
outbuf[2] = 0x80; /* Readonly. */
}
p += 4;
@@ -643,7 +642,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
p[0] = 4;
p[1] = 0x16;
/* if a geometry hint is available, use it */
- bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs);
+ bdrv_get_geometry_hint(s->dinfo->bdrv, &cylinders, &heads, &secs);
p[2] = (cylinders >> 16) & 0xff;
p[3] = (cylinders >> 8) & 0xff;
p[4] = cylinders & 0xff;
@@ -677,7 +676,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
p[2] = 5000 >> 8;
p[3] = 5000 & 0xff;
/* if a geometry hint is available, use it */
- bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs);
+ bdrv_get_geometry_hint(s->dinfo->bdrv, &cylinders, &heads, &secs);
p[4] = heads & 0xff;
p[5] = secs & 0xff;
p[6] = s->cluster_size * 2;
@@ -714,7 +713,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
p += 20;
}
if ((page == 0x3f || page == 0x2a)
- && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
+ && (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM)) {
/* CD Capabilities and Mechanical Status page. */
p[0] = 0x2a;
p[1] = 0x14;
@@ -725,7 +724,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
p[5] = 0xff; /* CD DA, DA accurate, RW supported,
RW corrected, C2 errors, ISRC,
UPC, Bar code */
- p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0);
+ p[6] = 0x2d | (bdrv_is_locked(s->dinfo->bdrv)? 2 : 0);
/* Locking supported, jumper present, eject, tray */
p[7] = 0; /* no volume & mute control, no
changer */
@@ -751,20 +750,20 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
break;
case 0x1b:
DPRINTF("Start Stop Unit\n");
- if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM &&
+ if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM &&
(buf[4] & 2))
/* load/eject medium */
- bdrv_eject(s->bdrv, !(buf[4] & 1));
+ bdrv_eject(s->dinfo->bdrv, !(buf[4] & 1));
break;
case 0x1e:
DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
- bdrv_set_locked(s->bdrv, buf[4] & 1);
+ bdrv_set_locked(s->dinfo->bdrv, buf[4] & 1);
break;
case 0x25:
DPRINTF("Read Capacity\n");
/* The normal LEN field for this command is zero. */
memset(outbuf, 0, 8);
- bdrv_get_geometry(s->bdrv, &nb_sectors);
+ bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
nb_sectors /= s->cluster_size;
/* Returned value is the address of the last sector. */
if (nb_sectors) {
@@ -810,7 +809,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
break;
case 0x35:
DPRINTF("Synchronise cache (sector %" PRId64 ", count %d)\n", lba, len);
- bdrv_flush(s->bdrv);
+ bdrv_flush(s->dinfo->bdrv);
break;
case 0x43:
{
@@ -819,7 +818,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
msf = buf[1] & 2;
format = buf[2] & 0xf;
start_track = buf[6];
- bdrv_get_geometry(s->bdrv, &nb_sectors);
+ bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
nb_sectors /= s->cluster_size;
switch(format) {
@@ -873,7 +872,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
if ((buf[1] & 31) == 0x10) {
DPRINTF("SAI READ CAPACITY(16)\n");
memset(outbuf, 0, len);
- bdrv_get_geometry(s->bdrv, &nb_sectors);
+ bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
nb_sectors /= s->cluster_size;
/* Returned value is the address of the last sector. */
if (nb_sectors) {
@@ -937,45 +936,56 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
static void scsi_destroy(SCSIDevice *d)
{
- qemu_free(d->state);
qemu_free(d);
}
-SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
- scsi_completionfn completion, void *opaque)
+static int scsi_disk_initfn(SCSIDevice *dev)
{
- SCSIDevice *d;
- SCSIDeviceState *s;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
uint64_t nb_sectors;
- s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
- s->bdrv = bdrv;
- s->tcq = tcq;
- s->completion = completion;
- s->opaque = opaque;
- if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ if (!s->dinfo || !s->dinfo->bdrv) {
+ qemu_error("scsi-disk: drive property not set\n");
+ return -1;
+ }
+
+ if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
s->cluster_size = 4;
} else {
s->cluster_size = 1;
}
- bdrv_get_geometry(s->bdrv, &nb_sectors);
+ bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
nb_sectors /= s->cluster_size;
if (nb_sectors)
nb_sectors--;
s->max_lba = nb_sectors;
- strncpy(s->drive_serial_str, drive_get_serial(s->bdrv),
+ strncpy(s->drive_serial_str, drive_get_serial(s->dinfo->bdrv),
sizeof(s->drive_serial_str));
if (strlen(s->drive_serial_str) == 0)
pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0");
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
- d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
- d->state = s;
- d->destroy = scsi_destroy;
- d->send_command = scsi_send_command;
- d->read_data = scsi_read_data;
- d->write_data = scsi_write_data;
- d->cancel_io = scsi_cancel_io;
- d->get_buf = scsi_get_buf;
-
- return d;
+ return 0;
+}
+
+static SCSIDeviceInfo scsi_disk_info = {
+ .qdev.name = "scsi-disk",
+ .qdev.desc = "virtual scsi disk or cdrom",
+ .qdev.size = sizeof(SCSIDiskState),
+ .init = scsi_disk_initfn,
+ .destroy = scsi_destroy,
+ .send_command = scsi_send_command,
+ .read_data = scsi_read_data,
+ .write_data = scsi_write_data,
+ .cancel_io = scsi_cancel_io,
+ .get_buf = scsi_get_buf,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_DRIVE("drive", SCSIDiskState, dinfo),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static void scsi_disk_register_devices(void)
+{
+ scsi_qdev_register(&scsi_disk_info);
}
+device_init(scsi_disk_register_devices)
diff --git a/hw/scsi-disk.h b/hw/scsi-disk.h
index f42212b..febde44 100644
--- a/hw/scsi-disk.h
+++ b/hw/scsi-disk.h
@@ -1,20 +1,36 @@
#ifndef SCSI_DISK_H
#define SCSI_DISK_H
+#include "qdev.h"
+
/* scsi-disk.c */
enum scsi_reason {
SCSI_REASON_DONE, /* Command complete. */
SCSI_REASON_DATA /* Transfer complete, more data required. */
};
-typedef struct SCSIDeviceState SCSIDeviceState;
+typedef struct SCSIBus SCSIBus;
typedef struct SCSIDevice SCSIDevice;
-typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag,
+typedef struct SCSIDeviceInfo SCSIDeviceInfo;
+typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag,
uint32_t arg);
struct SCSIDevice
{
- SCSIDeviceState *state;
+ DeviceState qdev;
+ uint32_t id;
+ SCSIDeviceInfo *info;
+};
+
+/* cdrom.c */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
+
+/* scsi-bus.c */
+typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
+struct SCSIDeviceInfo {
+ DeviceInfo qdev;
+ scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s);
int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf,
int lun);
@@ -24,13 +40,28 @@ struct SCSIDevice
uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
};
-SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
- scsi_completionfn completion, void *opaque);
-SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
- scsi_completionfn completion, void *opaque);
+typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
+ int unit);
+struct SCSIBus {
+ BusState qbus;
+ int busnr;
-/* cdrom.c */
-int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
-int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
+ int tcq, ndev;
+ scsi_completionfn complete;
+
+ SCSIDevice *devs[8];
+};
+
+SCSIBus *scsi_bus_new(DeviceState *host, int tcq, int ndev,
+ scsi_completionfn complete);
+void scsi_qdev_register(SCSIDeviceInfo *info);
+
+static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
+{
+ return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
+}
+
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit);
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
#endif
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index c827c04..f8c010b 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -15,15 +15,7 @@
#include "block.h"
#include "scsi-disk.h"
-#ifndef __linux__
-
-SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
- scsi_completionfn completion, void *opaque)
-{
- return NULL;
-}
-
-#else /* __linux__ */
+#ifdef __linux__
//#define DEBUG_SCSI
@@ -60,10 +52,13 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#define MAX_UINT ((unsigned int)-1)
#endif
+typedef struct SCSIGenericState SCSIGenericState;
+
typedef struct SCSIRequest {
BlockDriverAIOCB *aiocb;
struct SCSIRequest *next;
- SCSIDeviceState *dev;
+ SCSIBus *bus;
+ SCSIGenericState *dev;
uint32_t tag;
uint8_t cmd[SCSI_CMD_BUF_SIZE];
int cmdlen;
@@ -73,15 +68,14 @@ typedef struct SCSIRequest {
sg_io_hdr_t io_header;
} SCSIRequest;
-struct SCSIDeviceState
+struct SCSIGenericState
{
+ SCSIDevice qdev;
SCSIRequest *requests;
- BlockDriverState *bdrv;
+ DriveInfo *dinfo;
int type;
int blocksize;
int lun;
- scsi_completionfn completion;
- void *opaque;
int driver_status;
uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
uint8_t senselen;
@@ -90,8 +84,9 @@ struct SCSIDeviceState
/* Global pool of SCSIRequest structures. */
static SCSIRequest *free_requests = NULL;
-static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag)
{
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIRequest *r;
if (free_requests) {
@@ -102,6 +97,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
r->buf = NULL;
r->buflen = 0;
}
+ r->bus = scsi_bus_from_device(d);
r->dev = s;
r->tag = tag;
memset(r->cmd, 0, sizeof(r->cmd));
@@ -120,7 +116,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
static void scsi_remove_request(SCSIRequest *r)
{
SCSIRequest *last;
- SCSIDeviceState *s = r->dev;
+ SCSIGenericState *s = r->dev;
if (s->requests == r) {
s->requests = r->next;
@@ -138,7 +134,7 @@ static void scsi_remove_request(SCSIRequest *r)
free_requests = r;
}
-static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
+static SCSIRequest *scsi_find_request(SCSIGenericState *s, uint32_t tag)
{
SCSIRequest *r;
@@ -153,7 +149,7 @@ static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
static void scsi_command_complete(void *opaque, int ret)
{
SCSIRequest *r = (SCSIRequest *)opaque;
- SCSIDeviceState *s = r->dev;
+ SCSIGenericState *s = r->dev;
uint32_t tag;
int status;
@@ -178,14 +174,14 @@ static void scsi_command_complete(void *opaque, int ret)
r, r->tag, status);
tag = r->tag;
scsi_remove_request(r);
- s->completion(s->opaque, SCSI_REASON_DONE, tag, status);
+ r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status);
}
/* Cancel a pending data transfer. */
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
{
DPRINTF("scsi_cancel_io 0x%x\n", tag);
- SCSIDeviceState *s = d->state;
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIRequest *r;
DPRINTF("Cancel tag=0x%x\n", tag);
r = scsi_find_request(s, tag);
@@ -225,7 +221,6 @@ static int execute_command(BlockDriverState *bdrv,
static void scsi_read_complete(void * opaque, int ret)
{
SCSIRequest *r = (SCSIRequest *)opaque;
- SCSIDeviceState *s = r->dev;
int len;
if (ret) {
@@ -237,7 +232,7 @@ static void scsi_read_complete(void * opaque, int ret)
DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len);
r->len = -1;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len);
if (len == 0)
scsi_command_complete(r, 0);
}
@@ -245,7 +240,7 @@ static void scsi_read_complete(void * opaque, int ret)
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIRequest *r;
int ret;
@@ -275,11 +270,11 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
r->buf[0], r->buf[1], r->buf[2], r->buf[3],
r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, s->senselen);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, s->senselen);
return;
}
- ret = execute_command(s->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+ ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete);
if (ret == -1) {
scsi_command_complete(r, -EINVAL);
return;
@@ -310,7 +305,7 @@ static void scsi_write_complete(void * opaque, int ret)
The transfer may complete asynchronously. */
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIRequest *r;
int ret;
@@ -325,11 +320,11 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
if (r->len == 0) {
r->len = r->buflen;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->len);
+ r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->len);
return 0;
}
- ret = execute_command(s->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
+ ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret == -1) {
scsi_command_complete(r, -EINVAL);
return 1;
@@ -341,7 +336,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
/* Return a pointer to the data buffer. */
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
{
- SCSIDeviceState *s = d->state;
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIRequest *r;
r = scsi_find_request(s, tag);
if (!r) {
@@ -514,10 +509,11 @@ static int is_write(int command)
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
uint8_t *cmd, int lun)
{
- SCSIDeviceState *s = d->state;
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
uint32_t len=0;
int cmdlen=0;
SCSIRequest *r;
+ SCSIBus *bus;
int ret;
if (s->type == TYPE_TAPE) {
@@ -548,7 +544,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
s->sensebuf[6] = 0x00;
s->senselen = 7;
s->driver_status = SG_ERR_DRIVER_SENSE;
- s->completion(s->opaque, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
+ bus = scsi_bus_from_device(d);
+ bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
return 0;
}
@@ -557,7 +554,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
BADF("Tag 0x%x already in use %p\n", tag, r);
scsi_cancel_io(d, tag);
}
- r = scsi_new_request(s, tag);
+ r = scsi_new_request(d, tag);
memcpy(r->cmd, cmd, cmdlen);
r->cmdlen = cmdlen;
@@ -567,7 +564,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
free(r->buf);
r->buflen = 0;
r->buf = NULL;
- ret = execute_command(s->bdrv, r, SG_DXFER_NONE, scsi_command_complete);
+ ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete);
if (ret == -1) {
scsi_command_complete(r, -EINVAL);
return 0;
@@ -655,9 +652,10 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
static void scsi_destroy(SCSIDevice *d)
{
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIRequest *r, *n;
- r = d->state->requests;
+ r = s->requests;
while (r) {
n = r->next;
qemu_free(r);
@@ -671,51 +669,50 @@ static void scsi_destroy(SCSIDevice *d)
r = n;
}
- qemu_free(d->state);
qemu_free(d);
}
-SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
- scsi_completionfn completion, void *opaque)
+static int scsi_generic_initfn(SCSIDevice *dev)
{
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
int sg_version;
- SCSIDevice *d;
- SCSIDeviceState *s;
struct sg_scsi_id scsiid;
- /* check we are really using a /dev/sg* file */
+ if (!s->dinfo || !s->dinfo->bdrv) {
+ qemu_error("scsi-generic: drive property not set\n");
+ return -1;
+ }
- if (!bdrv_is_sg(bdrv))
- return NULL;
+ /* check we are really using a /dev/sg* file */
+ if (!bdrv_is_sg(s->dinfo->bdrv)) {
+ qemu_error("scsi-generic: not /dev/sg*\n");
+ return -1;
+ }
/* check we are using a driver managing SG_IO (version 3 and after */
-
- if (bdrv_ioctl(bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 ||
- sg_version < 30000)
- return NULL;
+ if (bdrv_ioctl(s->dinfo->bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+ sg_version < 30000) {
+ qemu_error("scsi-generic: scsi generic interface too old\n");
+ return -1;
+ }
/* get LUN of the /dev/sg? */
-
- if (bdrv_ioctl(bdrv, SG_GET_SCSI_ID, &scsiid))
- return NULL;
+ if (bdrv_ioctl(s->dinfo->bdrv, SG_GET_SCSI_ID, &scsiid)) {
+ qemu_error("scsi-generic: SG_GET_SCSI_ID ioctl failed\n");
+ return -1;
+ }
/* define device state */
-
- s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
- s->bdrv = bdrv;
- s->requests = NULL;
- s->completion = completion;
- s->opaque = opaque;
s->lun = scsiid.lun;
DPRINTF("LUN %d\n", s->lun);
s->type = scsiid.scsi_type;
DPRINTF("device type %d\n", s->type);
if (s->type == TYPE_TAPE) {
- s->blocksize = get_stream_blocksize(s->bdrv);
+ s->blocksize = get_stream_blocksize(s->dinfo->bdrv);
if (s->blocksize == -1)
s->blocksize = 0;
} else {
- s->blocksize = get_blocksize(s->bdrv);
+ s->blocksize = get_blocksize(s->dinfo->bdrv);
/* removable media returns 0 if not present */
if (s->blocksize <= 0) {
if (s->type == TYPE_ROM || s->type == TYPE_WORM)
@@ -727,18 +724,30 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
DPRINTF("block size %d\n", s->blocksize);
s->driver_status = 0;
memset(s->sensebuf, 0, sizeof(s->sensebuf));
+ return 0;
+}
- /* define function to manage device */
-
- d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
- d->state = s;
- d->destroy = scsi_destroy;
- d->send_command = scsi_send_command;
- d->read_data = scsi_read_data;
- d->write_data = scsi_write_data;
- d->cancel_io = scsi_cancel_io;
- d->get_buf = scsi_get_buf;
+static SCSIDeviceInfo scsi_generic_info = {
+ .qdev.name = "scsi-generic",
+ .qdev.desc = "pass through generic scsi device (/dev/sg*)",
+ .qdev.size = sizeof(SCSIGenericState),
+ .init = scsi_generic_initfn,
+ .destroy = scsi_destroy,
+ .send_command = scsi_send_command,
+ .read_data = scsi_read_data,
+ .write_data = scsi_write_data,
+ .cancel_io = scsi_cancel_io,
+ .get_buf = scsi_get_buf,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_DRIVE("drive", SCSIGenericState, dinfo),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
- return d;
+static void scsi_generic_register_devices(void)
+{
+ scsi_qdev_register(&scsi_generic_info);
}
+device_init(scsi_generic_register_devices)
+
#endif /* __linux__ */
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index bc5150f..222689a 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -44,6 +44,7 @@ typedef struct {
uint32_t residue;
uint32_t tag;
BlockDriverState *bs;
+ SCSIBus *bus;
SCSIDevice *scsi_dev;
int result;
/* For async completion. */
@@ -150,9 +151,9 @@ static void usb_msd_copy_data(MSDState *s)
s->data_len -= len;
if (s->scsi_len == 0) {
if (s->mode == USB_MSDM_DATAIN) {
- s->scsi_dev->read_data(s->scsi_dev, s->tag);
+ s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
- s->scsi_dev->write_data(s->scsi_dev, s->tag);
+ s->scsi_dev->info->write_data(s->scsi_dev, s->tag);
}
}
}
@@ -168,10 +169,10 @@ static void usb_msd_send_status(MSDState *s)
memcpy(s->usb_buf, &csw, 13);
}
-static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag,
+static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
uint32_t arg)
{
- MSDState *s = (MSDState *)opaque;
+ MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent);
USBPacket *p = s->packet;
if (tag != s->tag) {
@@ -205,7 +206,7 @@ static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag,
return;
}
s->scsi_len = arg;
- s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag);
+ s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag);
if (p) {
usb_msd_copy_data(s);
if (s->usb_len == 0) {
@@ -343,7 +344,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
static void usb_msd_cancel_io(USBPacket *p, void *opaque)
{
MSDState *s = opaque;
- s->scsi_dev->cancel_io(s->scsi_dev, s->tag);
+ s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag);
s->packet = NULL;
s->scsi_len = 0;
}
@@ -391,14 +392,14 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0;
- s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
+ s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
/* ??? Should check that USB and SCSI data transfer
directions match. */
if (s->residue == 0) {
if (s->mode == USB_MSDM_DATAIN) {
- s->scsi_dev->read_data(s->scsi_dev, s->tag);
+ s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
- s->scsi_dev->write_data(s->scsi_dev, s->tag);
+ s->scsi_dev->info->write_data(s->scsi_dev, s->tag);
}
}
ret = len;
@@ -509,7 +510,7 @@ static void usb_msd_handle_destroy(USBDevice *dev)
{
MSDState *s = (MSDState *)dev;
- s->scsi_dev->destroy(s->scsi_dev);
+ s->scsi_dev->info->destroy(s->scsi_dev);
bdrv_delete(s->bs);
qemu_free(s);
}
@@ -567,7 +568,10 @@ USBDevice *usb_msd_init(const char *filename)
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
filename);
- s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
+ s->bus = scsi_bus_new(&s->dev.qdev, 0, 1, usb_msd_command_complete);
+#if 0
+ s->scsi_dev = scsi_disk_init(s->bus, bdrv);
+#endif
usb_msd_handle_reset((USBDevice *)s);
return (USBDevice *)s;
}
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 9/9] qdev/scsi+usb: convert usb-storage to qdev.
2009-08-31 12:23 [Qemu-devel] [PATCH 0/9] qdev: usb + scsi support Gerd Hoffmann
` (7 preceding siblings ...)
2009-08-31 12:24 ` [Qemu-devel] [PATCH 8/9] qdev/scsi: add scsi bus support to qdev, convert drivers Gerd Hoffmann
@ 2009-08-31 12:24 ` Gerd Hoffmann
8 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-08-31 12:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Full coverage with properties and everything. You can add virtual usb
sticks this way now:
-drive if=none,id=pendrive,path=/some/where
-device usb-storage,drive=pendrive
-usbdevice disk:/path/to/image continues to work.
Other side effects:
usb storage is listed in 'info block' now.
kvm tree should be able to boot from usb via extboot (untested though).
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-msd.c | 67 ++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 40 insertions(+), 27 deletions(-)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 222689a..aa0ce6a 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -8,6 +8,8 @@
*/
#include "qemu-common.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
#include "usb.h"
#include "block.h"
#include "scsi-disk.h"
@@ -43,8 +45,8 @@ typedef struct {
uint32_t data_len;
uint32_t residue;
uint32_t tag;
- BlockDriverState *bs;
SCSIBus *bus;
+ DriveInfo *dinfo;
SCSIDevice *scsi_dev;
int result;
/* For async completion. */
@@ -511,7 +513,7 @@ static void usb_msd_handle_destroy(USBDevice *dev)
MSDState *s = (MSDState *)dev;
s->scsi_dev->info->destroy(s->scsi_dev);
- bdrv_delete(s->bs);
+ drive_uninit(s->dinfo->bdrv);
qemu_free(s);
}
@@ -519,19 +521,33 @@ static int usb_msd_initfn(USBDevice *dev)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
+ if (!s->dinfo || !s->dinfo->bdrv) {
+ qemu_error("usb-msd: drive property not set\n");
+ return -1;
+ }
+
s->dev.speed = USB_SPEED_FULL;
+ s->bus = scsi_bus_new(&s->dev.qdev, 0, 1, usb_msd_command_complete);
+ s->scsi_dev = scsi_bus_legacy_add_drive(s->bus, s->dinfo, 0);
+ usb_msd_handle_reset(dev);
return 0;
}
USBDevice *usb_msd_init(const char *filename)
{
+ static int nr=0;
+ char id[8];
+ QemuOpts *opts;
+ DriveInfo *dinfo;
USBDevice *dev;
- MSDState *s;
- BlockDriverState *bdrv;
- BlockDriver *drv = NULL;
+ int fatal_error;
const char *p1;
char fmt[32];
+ /* parse -usbdevice disk: syntax into drive opts */
+ snprintf(id, sizeof(id), "usb%d", nr++);
+ opts = qemu_opts_create(&qemu_drive_opts, id, 0);
+
p1 = strchr(filename, ':');
if (p1++) {
const char *p2;
@@ -539,52 +555,45 @@ USBDevice *usb_msd_init(const char *filename)
if (strstart(filename, "format=", &p2)) {
int len = MIN(p1 - p2, sizeof(fmt));
pstrcpy(fmt, len, p2);
-
- drv = bdrv_find_format(fmt);
- if (!drv) {
- printf("invalid format %s\n", fmt);
- return NULL;
- }
+ qemu_opt_set(opts, "format", fmt);
} else if (*filename != ':') {
printf("unrecognized USB mass-storage option %s\n", filename);
return NULL;
}
-
filename = p1;
}
-
if (!*filename) {
printf("block device specification needed\n");
return NULL;
}
+ qemu_opt_set(opts, "file", filename);
+ qemu_opt_set(opts, "if", "none");
- bdrv = bdrv_new("usb");
- if (bdrv_open2(bdrv, filename, 0, drv) < 0)
+ /* create host drive */
+ dinfo = drive_init(opts, NULL, &fatal_error);
+ if (!dinfo) {
+ qemu_opts_del(opts);
return NULL;
+ }
- dev = usb_create_simple(NULL /* FIXME */, "QEMU USB MSD");
- s = DO_UPCAST(MSDState, dev, dev);
- s->bs = bdrv;
- snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
- filename);
+ /* create guest device */
+ dev = usb_create(NULL /* FIXME */, "QEMU USB MSD");
+ qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
+ qdev_init(&dev->qdev);
- s->bus = scsi_bus_new(&s->dev.qdev, 0, 1, usb_msd_command_complete);
-#if 0
- s->scsi_dev = scsi_disk_init(s->bus, bdrv);
-#endif
- usb_msd_handle_reset((USBDevice *)s);
- return (USBDevice *)s;
+ return dev;
}
BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
{
MSDState *s = (MSDState *)dev;
- return s->bs;
+ return s->dinfo->bdrv;
}
static struct USBDeviceInfo msd_info = {
.qdev.name = "QEMU USB MSD",
+ .qdev.alias = "usb-storage",
.qdev.size = sizeof(MSDState),
.init = usb_msd_initfn,
.handle_packet = usb_generic_handle_packet,
@@ -592,6 +601,10 @@ static struct USBDeviceInfo msd_info = {
.handle_control = usb_msd_handle_control,
.handle_data = usb_msd_handle_data,
.handle_destroy = usb_msd_handle_destroy,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_DRIVE("drive", MSDState, dinfo),
+ DEFINE_PROP_END_OF_LIST(),
+ },
};
static void usb_msd_register_devices(void)
--
1.6.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread