qdev/usb: add usb bus support to qdev, convert drivers.
* 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> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
7557008854
commit
806b602482
2
Makefile
2
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-disk.o cdrom.o
|
||||||
obj-y += scsi-generic.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.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 += 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.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
|
obj-y += bt-hci-csr.o
|
||||||
|
18
hw/bt-hid.c
18
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_done(&s->btdev);
|
||||||
bt_l2cap_device_init(&s->btdev, net);
|
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->proto = BT_HID_PROTO_REPORT;
|
||||||
s->state = bt_state_ready;
|
s->state = bt_state_ready;
|
||||||
s->dataother.len = 0;
|
s->dataother.len = 0;
|
||||||
@ -131,7 +131,7 @@ static int bt_hid_out(struct bt_hid_device_s *s)
|
|||||||
p.devep = 1;
|
p.devep = 1;
|
||||||
p.data = s->dataout.buffer;
|
p.data = s->dataout.buffer;
|
||||||
p.len = s->dataout.len;
|
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;
|
return s->dataout.len;
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ static int bt_hid_in(struct bt_hid_device_s *s)
|
|||||||
p.devep = 1;
|
p.devep = 1;
|
||||||
p.data = s->datain.buffer;
|
p.data = s->datain.buffer;
|
||||||
p.len = sizeof(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;
|
return s->datain.len;
|
||||||
}
|
}
|
||||||
@ -323,8 +323,8 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
s->proto = parameter;
|
s->proto = parameter;
|
||||||
s->usbdev->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
|
s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
|
||||||
NULL);
|
NULL);
|
||||||
ret = BT_HS_SUCCESSFUL;
|
ret = BT_HS_SUCCESSFUL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
|
|||||||
ret = BT_HS_ERR_INVALID_PARAMETER;
|
ret = BT_HS_ERR_INVALID_PARAMETER;
|
||||||
break;
|
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_out(s->control, 1));
|
||||||
s->control->sdu_submit(s->control);
|
s->control->sdu_submit(s->control);
|
||||||
break;
|
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,
|
/* We don't need to know about the Idle Rate here really,
|
||||||
* so just pass it on to the device. */
|
* 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) ?
|
SET_IDLE, data[1], 0, 0, NULL) ?
|
||||||
BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
|
BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
|
||||||
/* XXX: Does this generate a handshake? */
|
/* 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;
|
hid->btdev.device.inquiry_scan = !hid->connected;
|
||||||
|
|
||||||
if (hid->connected && !prev) {
|
if (hid->connected && !prev) {
|
||||||
hid->usbdev->handle_reset(hid->usbdev);
|
hid->usbdev->info->handle_reset(hid->usbdev);
|
||||||
hid->proto = BT_HID_PROTO_REPORT;
|
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_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
|
||||||
bt_l2cap_device_done(&hid->btdev);
|
bt_l2cap_device_done(&hid->btdev);
|
||||||
|
|
||||||
hid->usbdev->handle_destroy(hid->usbdev);
|
hid->usbdev->info->handle_destroy(hid->usbdev);
|
||||||
|
|
||||||
qemu_free(hid);
|
qemu_free(hid);
|
||||||
}
|
}
|
||||||
|
38
hw/usb-bt.c
38
hw/usb-bt.c
@ -617,22 +617,23 @@ static void usb_bt_handle_destroy(USBDevice *dev)
|
|||||||
qemu_free(s);
|
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 *usb_bt_init(HCIInfo *hci)
|
||||||
{
|
{
|
||||||
|
USBDevice *dev;
|
||||||
struct USBBtState *s;
|
struct USBBtState *s;
|
||||||
|
|
||||||
if (!hci)
|
if (!hci)
|
||||||
return NULL;
|
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.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 = hci;
|
||||||
s->hci->opaque = s;
|
s->hci->opaque = s;
|
||||||
@ -641,5 +642,22 @@ USBDevice *usb_bt_init(HCIInfo *hci)
|
|||||||
|
|
||||||
usb_bt_handle_reset(&s->dev);
|
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)
|
||||||
|
82
hw/usb-bus.c
Normal file
82
hw/usb-bus.c
Normal file
@ -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);
|
||||||
|
}
|
108
hw/usb-hid.c
108
hw/usb-hid.c
@ -846,65 +846,44 @@ static void usb_hid_handle_destroy(USBDevice *dev)
|
|||||||
qemu_free(s);
|
qemu_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
USBDevice *usb_tablet_init(void)
|
static int usb_hid_initfn(USBDevice *dev, int kind)
|
||||||
{
|
{
|
||||||
USBHIDState *s;
|
USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(USBHIDState));
|
|
||||||
s->dev.speed = USB_SPEED_FULL;
|
s->dev.speed = USB_SPEED_FULL;
|
||||||
s->dev.handle_packet = usb_generic_handle_packet;
|
s->kind = kind;
|
||||||
|
|
||||||
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;
|
|
||||||
/* Force poll routine to be run and grab input the first time. */
|
/* Force poll routine to be run and grab input the first time. */
|
||||||
s->changed = 1;
|
s->changed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
|
static int usb_tablet_initfn(USBDevice *dev)
|
||||||
|
{
|
||||||
|
return usb_hid_initfn(dev, USB_TABLET);
|
||||||
|
}
|
||||||
|
|
||||||
return (USBDevice *)s;
|
static int usb_mouse_initfn(USBDevice *dev)
|
||||||
|
{
|
||||||
|
return usb_hid_initfn(dev, USB_MOUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
USBDevice *usb_mouse_init(void)
|
||||||
{
|
{
|
||||||
USBHIDState *s;
|
return usb_create_simple(NULL /* FIXME */, "QEMU USB Mouse");
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(USBHIDState));
|
|
||||||
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_MOUSE;
|
|
||||||
/* 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 Mouse");
|
|
||||||
|
|
||||||
return (USBDevice *)s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
USBDevice *usb_keyboard_init(void)
|
USBDevice *usb_keyboard_init(void)
|
||||||
{
|
{
|
||||||
USBHIDState *s;
|
return usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
|
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_opaque = opaque;
|
||||||
s->datain = datain;
|
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)
|
||||||
|
49
hw/usb-hub.c
49
hw/usb-hub.c
@ -486,7 +486,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
|
|||||||
port = &s->ports[i];
|
port = &s->ports[i];
|
||||||
dev = port->port.dev;
|
dev = port->port.dev;
|
||||||
if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
|
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) {
|
if (ret != USB_RET_NODEV) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -521,32 +521,41 @@ static void usb_hub_handle_destroy(USBDevice *dev)
|
|||||||
qemu_free(s);
|
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;
|
USBHubPort *port;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (nb_ports > MAX_PORTS)
|
s->dev.speed = USB_SPEED_FULL,
|
||||||
return NULL;
|
s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
|
||||||
s = qemu_mallocz(sizeof(USBHubState));
|
for (i = 0; i < s->nb_ports; i++) {
|
||||||
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++) {
|
|
||||||
port = &s->ports[i];
|
port = &s->ports[i];
|
||||||
qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
|
qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
|
||||||
port->wPortStatus = PORT_STAT_POWER;
|
port->wPortStatus = PORT_STAT_POWER;
|
||||||
port->wPortChange = 0;
|
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)
|
||||||
|
45
hw/usb-msd.c
45
hw/usb-msd.c
@ -514,8 +514,17 @@ static void usb_msd_handle_destroy(USBDevice *dev)
|
|||||||
qemu_free(s);
|
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 *usb_msd_init(const char *filename)
|
||||||
{
|
{
|
||||||
|
USBDevice *dev;
|
||||||
MSDState *s;
|
MSDState *s;
|
||||||
BlockDriverState *bdrv;
|
BlockDriverState *bdrv;
|
||||||
BlockDriver *drv = NULL;
|
BlockDriver *drv = NULL;
|
||||||
@ -548,30 +557,19 @@ USBDevice *usb_msd_init(const char *filename)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(MSDState));
|
|
||||||
|
|
||||||
bdrv = bdrv_new("usb");
|
bdrv = bdrv_new("usb");
|
||||||
if (bdrv_open2(bdrv, filename, 0, drv) < 0)
|
if (bdrv_open2(bdrv, filename, 0, drv) < 0)
|
||||||
goto fail;
|
return NULL;
|
||||||
|
|
||||||
|
dev = usb_create_simple(NULL /* FIXME */, "QEMU USB MSD");
|
||||||
|
s = DO_UPCAST(MSDState, dev, dev);
|
||||||
s->bs = bdrv;
|
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;
|
|
||||||
|
|
||||||
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
|
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
|
s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
|
||||||
usb_msd_handle_reset((USBDevice *)s);
|
usb_msd_handle_reset((USBDevice *)s);
|
||||||
return (USBDevice *)s;
|
return (USBDevice *)s;
|
||||||
fail:
|
|
||||||
qemu_free(s);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
|
BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
|
||||||
@ -580,3 +578,20 @@ BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
|
|||||||
|
|
||||||
return s->bs;
|
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)
|
||||||
|
@ -590,7 +590,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
|
|||||||
ep->packey[dir].complete_opaque = ep;
|
ep->packey[dir].complete_opaque = ep;
|
||||||
|
|
||||||
if (s->port.dev)
|
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
|
else
|
||||||
ret = USB_RET_NODEV;
|
ret = USB_RET_NODEV;
|
||||||
|
|
||||||
|
45
hw/usb-net.c
45
hw/usb-net.c
@ -1432,32 +1432,34 @@ static void usb_net_handle_destroy(USBDevice *dev)
|
|||||||
qemu_del_vlan_client(s->vc);
|
qemu_del_vlan_client(s->vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
USBDevice *usb_net_init(NICInfo *nd)
|
static int usb_net_initfn(USBDevice *dev)
|
||||||
{
|
{
|
||||||
USBNetState *s;
|
USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(USBNetState));
|
s->dev.speed = USB_SPEED_FULL;
|
||||||
s->dev.speed = USB_SPEED_FULL;
|
|
||||||
s->dev.handle_packet = usb_generic_handle_packet;
|
|
||||||
|
|
||||||
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->rndis = 1;
|
s->rndis = 1;
|
||||||
s->rndis_state = RNDIS_UNINITIALIZED;
|
s->rndis_state = RNDIS_UNINITIALIZED;
|
||||||
|
TAILQ_INIT(&s->rndis_resp);
|
||||||
|
|
||||||
s->medium = 0; /* NDIS_MEDIUM_802_3 */
|
s->medium = 0; /* NDIS_MEDIUM_802_3 */
|
||||||
s->speed = 1000000; /* 100MBps, in 100Bps units */
|
s->speed = 1000000; /* 100MBps, in 100Bps units */
|
||||||
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
||||||
s->filter = 0;
|
s->filter = 0;
|
||||||
s->vendorid = 0x1234;
|
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);
|
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,
|
s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
|
||||||
usbnet_can_receive,
|
usbnet_can_receive,
|
||||||
usbnet_receive,
|
usbnet_receive,
|
||||||
@ -1476,3 +1478,20 @@ USBDevice *usb_net_init(NICInfo *nd)
|
|||||||
|
|
||||||
return (USBDevice *) s;
|
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)
|
||||||
|
@ -754,7 +754,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||||||
ohci->usb_packet.len = len;
|
ohci->usb_packet.len = len;
|
||||||
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
|
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
|
||||||
ohci->usb_packet.complete_opaque = ohci;
|
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)
|
if (ret != USB_RET_NODEV)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -944,7 +944,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||||||
ohci->usb_packet.len = len;
|
ohci->usb_packet.len = len;
|
||||||
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
|
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
|
||||||
ohci->usb_packet.complete_opaque = ohci;
|
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)
|
if (ret != USB_RET_NODEV)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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 *usb_serial_init(const char *filename)
|
||||||
{
|
{
|
||||||
|
USBDevice *dev;
|
||||||
USBSerialState *s;
|
USBSerialState *s;
|
||||||
CharDriverState *cdrv;
|
CharDriverState *cdrv;
|
||||||
unsigned short vendorid = 0x0403, productid = 0x6001;
|
unsigned short vendorid = 0x0403, productid = 0x6001;
|
||||||
@ -561,32 +569,40 @@ USBDevice *usb_serial_init(const char *filename)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
filename++;
|
filename++;
|
||||||
s = qemu_mallocz(sizeof(USBSerialState));
|
|
||||||
|
|
||||||
snprintf(label, sizeof(label), "usbserial%d", index++);
|
snprintf(label, sizeof(label), "usbserial%d", index++);
|
||||||
cdrv = qemu_chr_open(label, filename, NULL);
|
cdrv = qemu_chr_open(label, filename, NULL);
|
||||||
if (!cdrv)
|
if (!cdrv)
|
||||||
goto fail;
|
return NULL;
|
||||||
|
|
||||||
|
dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Serial");
|
||||||
|
s = DO_UPCAST(USBSerialState, dev, dev);
|
||||||
s->cs = cdrv;
|
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;
|
|
||||||
|
|
||||||
s->vendorid = vendorid;
|
s->vendorid = vendorid;
|
||||||
s->productid = productid;
|
s->productid = productid;
|
||||||
|
|
||||||
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)",
|
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)",
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read,
|
||||||
|
usb_serial_event, s);
|
||||||
|
|
||||||
usb_serial_handle_reset((USBDevice *)s);
|
usb_serial_handle_reset((USBDevice *)s);
|
||||||
return (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)
|
||||||
|
@ -660,7 +660,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
|
|||||||
USBDevice *dev = port->port.dev;
|
USBDevice *dev = port->port.dev;
|
||||||
|
|
||||||
if (dev && (port->ctrl & UHCI_PORT_EN))
|
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);
|
dprintf("uhci: packet exit. ret %d len %d\n", ret, p->len);
|
||||||
|
@ -392,21 +392,31 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
|
|||||||
qemu_free(s);
|
qemu_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int usb_wacom_initfn(USBDevice *dev)
|
||||||
|
{
|
||||||
|
USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
|
||||||
|
s->dev.speed = USB_SPEED_FULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
USBDevice *usb_wacom_init(void)
|
USBDevice *usb_wacom_init(void)
|
||||||
{
|
{
|
||||||
USBWacomState *s;
|
return usb_create_simple(NULL /* FIXME */, "QEMU PenPartner Tablet");
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(USBWacomState));
|
|
||||||
s->dev.speed = USB_SPEED_FULL;
|
|
||||||
s->dev.handle_packet = usb_generic_handle_packet;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
pstrcpy(s->dev.devname, sizeof(s->dev.devname),
|
|
||||||
"QEMU PenPartner Tablet");
|
|
||||||
|
|
||||||
return (USBDevice *) s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void usb_wacom_register_devices(void)
|
||||||
|
{
|
||||||
|
usb_qdev_register(&wacom_info);
|
||||||
|
}
|
||||||
|
device_init(usb_wacom_register_devices)
|
||||||
|
16
hw/usb.c
16
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];
|
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||||
|
|
||||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||||
ret = s->handle_control(s, request, value, index,
|
ret = s->info->handle_control(s, request, value, index,
|
||||||
s->setup_len, s->data_buf);
|
s->setup_len, s->data_buf);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (p->devep != 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];
|
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
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:
|
case SETUP_STATE_ACK:
|
||||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||||
s->setup_state = SETUP_STATE_IDLE;
|
s->setup_state = SETUP_STATE_IDLE;
|
||||||
ret = s->handle_control(s, request, value, index,
|
ret = s->info->handle_control(s, request, value, index,
|
||||||
s->setup_len, s->data_buf);
|
s->setup_len, s->data_buf);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return 0;
|
return 0;
|
||||||
return ret;
|
return ret;
|
||||||
@ -126,7 +126,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
|
|||||||
static int do_token_out(USBDevice *s, USBPacket *p)
|
static int do_token_out(USBDevice *s, USBPacket *p)
|
||||||
{
|
{
|
||||||
if (p->devep != 0)
|
if (p->devep != 0)
|
||||||
return s->handle_data(s, p);
|
return s->info->handle_data(s, p);
|
||||||
|
|
||||||
switch(s->setup_state) {
|
switch(s->setup_state) {
|
||||||
case SETUP_STATE_ACK:
|
case SETUP_STATE_ACK:
|
||||||
@ -179,7 +179,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
|
|||||||
s->remote_wakeup = 0;
|
s->remote_wakeup = 0;
|
||||||
s->addr = 0;
|
s->addr = 0;
|
||||||
s->state = USB_STATE_DEFAULT;
|
s->state = USB_STATE_DEFAULT;
|
||||||
s->handle_reset(s);
|
s->info->handle_reset(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ void usb_send_msg(USBDevice *dev, int msg)
|
|||||||
USBPacket p;
|
USBPacket p;
|
||||||
memset(&p, 0, sizeof(p));
|
memset(&p, 0, sizeof(p));
|
||||||
p.pid = msg;
|
p.pid = msg;
|
||||||
dev->handle_packet(dev, &p);
|
dev->info->handle_packet(dev, &p);
|
||||||
|
|
||||||
/* This _must_ be synchronous */
|
/* This _must_ be synchronous */
|
||||||
}
|
}
|
||||||
|
69
hw/usb.h
69
hw/usb.h
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "block.h"
|
#include "block.h"
|
||||||
|
#include "qdev.h"
|
||||||
|
|
||||||
#define USB_TOKEN_SETUP 0x2d
|
#define USB_TOKEN_SETUP 0x2d
|
||||||
#define USB_TOKEN_IN 0x69 /* device -> host */
|
#define USB_TOKEN_IN 0x69 /* device -> host */
|
||||||
@ -116,37 +117,52 @@
|
|||||||
#define USB_ENDPOINT_XFER_BULK 2
|
#define USB_ENDPOINT_XFER_BULK 2
|
||||||
#define USB_ENDPOINT_XFER_INT 3
|
#define USB_ENDPOINT_XFER_INT 3
|
||||||
|
|
||||||
|
typedef struct USBBus USBBus;
|
||||||
typedef struct USBPort USBPort;
|
typedef struct USBPort USBPort;
|
||||||
typedef struct USBDevice USBDevice;
|
typedef struct USBDevice USBDevice;
|
||||||
|
typedef struct USBDeviceInfo USBDeviceInfo;
|
||||||
typedef struct USBPacket USBPacket;
|
typedef struct USBPacket USBPacket;
|
||||||
|
|
||||||
/* definition of a USB device */
|
/* definition of a USB device */
|
||||||
struct USBDevice {
|
struct USBDevice {
|
||||||
|
DeviceState qdev;
|
||||||
|
USBDeviceInfo *info;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
/*
|
int speed;
|
||||||
* Process USB packet.
|
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).
|
* Called by the HC (Host Controller).
|
||||||
*
|
*
|
||||||
* Returns length of the transaction
|
* Returns length of the transaction
|
||||||
* or one of the USB_RET_XXX codes.
|
* or one of the USB_RET_XXX codes.
|
||||||
*/
|
*/
|
||||||
int (*handle_packet)(USBDevice *dev, USBPacket *p);
|
int (*handle_packet)(USBDevice *dev, USBPacket *p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when device is destroyed.
|
* Called when device is destroyed.
|
||||||
*/
|
*/
|
||||||
void (*handle_destroy)(USBDevice *dev);
|
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
|
* Reset the device
|
||||||
*/
|
*/
|
||||||
void (*handle_reset)(USBDevice *dev);
|
void (*handle_reset)(USBDevice *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -165,17 +181,6 @@ struct USBDevice {
|
|||||||
* Returns length or one of the USB_RET_ codes.
|
* Returns length or one of the USB_RET_ codes.
|
||||||
*/
|
*/
|
||||||
int (*handle_data)(USBDevice *dev, USBPacket *p);
|
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);
|
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);
|
uint32_t musb_core_intr_get(MUSBState *s);
|
||||||
void musb_core_intr_clear(MUSBState *s, uint32_t mask);
|
void musb_core_intr_clear(MUSBState *s, uint32_t mask);
|
||||||
void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
|
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);
|
||||||
|
53
usb-linux.c
53
usb-linux.c
@ -751,7 +751,7 @@ static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
|
|||||||
s->remote_wakeup = 0;
|
s->remote_wakeup = 0;
|
||||||
s->addr = 0;
|
s->addr = 0;
|
||||||
s->state = USB_STATE_DEFAULT;
|
s->state = USB_STATE_DEFAULT;
|
||||||
s->handle_reset(s);
|
s->info->handle_reset(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,18 +881,19 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||||||
return 0;
|
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)
|
static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name)
|
||||||
{
|
{
|
||||||
int fd = -1, ret;
|
int fd = -1, ret;
|
||||||
USBHostDevice *dev = NULL;
|
USBDevice *d = NULL;
|
||||||
|
USBHostDevice *dev;
|
||||||
struct usbdevfs_connectinfo ci;
|
struct usbdevfs_connectinfo ci;
|
||||||
char buf[1024];
|
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);
|
printf("husb: open device %d.%d\n", bus_num, addr);
|
||||||
|
|
||||||
if (!usb_host_device_path) {
|
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);
|
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 */
|
/* read the device description */
|
||||||
dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
|
dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
|
||||||
if (dev->descr_len <= 0) {
|
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
|
#endif
|
||||||
|
|
||||||
dev->fd = fd;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial configuration is -1 which makes us claim first
|
* 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
|
else
|
||||||
dev->dev.speed = USB_SPEED_HIGH;
|
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')
|
if (!prod_name || prod_name[0] == '\0')
|
||||||
snprintf(dev->dev.devname, sizeof(dev->dev.devname),
|
snprintf(dev->dev.devname, sizeof(dev->dev.devname),
|
||||||
"host:%d.%d", bus_num, addr);
|
"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;
|
return (USBDevice *) dev;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (dev)
|
if (d)
|
||||||
qemu_free(dev);
|
qdev_free(&d->qdev);
|
||||||
|
if (fd != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
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_add(const char *spec);
|
||||||
static int usb_host_auto_del(const char *spec);
|
static int usb_host_auto_del(const char *spec);
|
||||||
|
|
||||||
|
4
vl.c
4
vl.c
@ -2481,7 +2481,7 @@ static void usb_msd_password_cb(void *opaque, int err)
|
|||||||
if (!err)
|
if (!err)
|
||||||
usb_device_add_dev(dev);
|
usb_device_add_dev(dev);
|
||||||
else
|
else
|
||||||
dev->handle_destroy(dev);
|
dev->info->handle_destroy(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usb_device_add(const char *devname, int is_hotplug)
|
static int usb_device_add(const char *devname, int is_hotplug)
|
||||||
@ -2567,7 +2567,7 @@ int usb_device_del_addr(int bus_num, int addr)
|
|||||||
dev = port->dev;
|
dev = port->dev;
|
||||||
*lastp = port->next;
|
*lastp = port->next;
|
||||||
usb_attach(port, NULL);
|
usb_attach(port, NULL);
|
||||||
dev->handle_destroy(dev);
|
dev->info->handle_destroy(dev);
|
||||||
port->next = free_usb_ports;
|
port->next = free_usb_ports;
|
||||||
free_usb_ports = port;
|
free_usb_ports = port;
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user