Merge remote-tracking branch 'kraxel/usb.14.pull' into staging

This commit is contained in:
Anthony Liguori 2011-05-31 08:17:15 -05:00
commit f590f4c4b6
23 changed files with 2441 additions and 387 deletions

View file

@ -193,6 +193,7 @@ hw-obj-$(CONFIG_PCSPK) += pcspk.o
hw-obj-$(CONFIG_PCKBD) += pckbd.o
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
hw-obj-$(CONFIG_FDC) += fdc.o
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o

View file

@ -3,6 +3,7 @@ CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO=y
CONFIG_USB_UHCI=y
CONFIG_USB_OHCI=y
CONFIG_USB_EHCI=y
CONFIG_NE2000_PCI=y
CONFIG_EEPRO100_PCI=y
CONFIG_PCNET_PCI=y

38
docs/usb2.txt Normal file
View file

@ -0,0 +1,38 @@
USB 2.0 Quick Start
===================
The QEMU EHCI Adapter does *not* support companion controllers. That
implies there are two completely separate USB busses: One USB 1.1 bus
driven by the UHCI controller and one USB 2.0 bus driven by the EHCI
controller. Devices must be attached to the correct controller
manually.
The '-usb' switch will make qemu create the UHCI controller as part of
the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0".
You can use the standard -device switch to add a EHCI controller to
your virtual machine. It is strongly recommended to specify an ID for
the controller so the USB 2.0 bus gets a individual name, for example
'-device usb-ehci,id=ehci". This will give you a USB 2.0 bus named
"ehci.0".
I strongly recomment to also use -device to attach usb devices because
you can specify the bus they should be attached to this way. Here is
a complete example:
qemu -M pc ${otheroptions} \
-drive if=none,id=usbstick,file=/path/to/image \
-usb \
-device usb-ehci,id=ehci \
-device usb-tablet,bus=usb.0 \
-device usb-storage,bus=ehci.0,drive=usbstick
This attaches a usb tablet to the UHCI adapter and a usb mass storage
device to the EHCI adapter.
enjoy,
Gerd
--
Gerd Hoffmann <kraxel@redhat.com>

View file

@ -323,7 +323,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
break;
}
s->proto = parameter;
s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
s->usbdev->info->handle_control(s->usbdev, NULL, 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->info->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
s->usbdev->info->handle_control(s->usbdev, NULL, 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->info->handle_control(s->usbdev,
ret = s->usbdev->info->handle_control(s->usbdev, NULL,
SET_IDLE, data[1], 0, 0, NULL) ?
BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
/* XXX: Does this generate a handshake? */

View file

@ -100,6 +100,7 @@
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010

View file

@ -372,13 +372,13 @@ static void usb_bt_handle_reset(USBDevice *dev)
s->altsetting = 0;
}
static int usb_bt_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
struct USBBtState *s = (struct USBBtState *) dev->opaque;
int ret;
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
switch (request) {
case DeviceRequest | USB_REQ_GET_CONFIGURATION:

View file

@ -602,8 +602,8 @@ static void ccid_handle_reset(USBDevice *dev)
ccid_reset(s);
}
static int ccid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
int value, int index, int length, uint8_t *data)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
int ret = 0;

View file

@ -76,7 +76,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
{
uint8_t bLength = 0x09;
uint16_t wTotalLength = 0;
int i, rc, count;
int i, rc;
if (len < bLength) {
return -1;
@ -91,8 +91,19 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
dest[0x08] = conf->bMaxPower;
wTotalLength += bLength;
count = conf->nif ? conf->nif : conf->bNumInterfaces;
for (i = 0; i < count; i++) {
/* handle grouped interfaces if any*/
for (i = 0; i < conf->nif_groups; i++) {
rc = usb_desc_iface_group(&(conf->if_groups[i]),
dest + wTotalLength,
len - wTotalLength);
if (rc < 0) {
return rc;
}
wTotalLength += rc;
}
/* handle normal (ungrouped / no IAD) interfaces if any */
for (i = 0; i < conf->nif; i++) {
rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
if (rc < 0) {
return rc;
@ -105,6 +116,41 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
return wTotalLength;
}
int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
size_t len)
{
int pos = 0;
int i = 0;
/* handle interface association descriptor */
uint8_t bLength = 0x08;
if (len < bLength) {
return -1;
}
dest[0x00] = bLength;
dest[0x01] = USB_DT_INTERFACE_ASSOC;
dest[0x02] = iad->bFirstInterface;
dest[0x03] = iad->bInterfaceCount;
dest[0x04] = iad->bFunctionClass;
dest[0x05] = iad->bFunctionSubClass;
dest[0x06] = iad->bFunctionProtocol;
dest[0x07] = iad->iFunction;
pos += bLength;
/* handle associated interfaces in this group */
for (i = 0; i < iad->nif; i++) {
int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos);
if (rc < 0) {
return rc;
}
pos += rc;
}
return pos;
}
int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
{
uint8_t bLength = 0x09;
@ -344,8 +390,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
return ret;
}
int usb_desc_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
const USBDesc *desc = dev->info->usb_desc;
int i, ret = -1;

View file

@ -30,6 +30,24 @@ struct USBDescConfig {
uint8_t bmAttributes;
uint8_t bMaxPower;
/* grouped interfaces */
uint8_t nif_groups;
const USBDescIfaceAssoc *if_groups;
/* "normal" interfaces */
uint8_t nif;
const USBDescIface *ifs;
};
/* conceptually an Interface Association Descriptor, and releated interfaces */
struct USBDescIfaceAssoc {
uint8_t bFirstInterface;
uint8_t bInterfaceCount;
uint8_t bFunctionClass;
uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol;
uint8_t iFunction;
uint8_t nif;
const USBDescIface *ifs;
};
@ -75,6 +93,8 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
int usb_desc_device_qualifier(const USBDescDevice *dev,
uint8_t *dest, size_t len);
int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
size_t len);
int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
@ -86,7 +106,7 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
int usb_desc_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data);
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data);
#endif /* QEMU_HW_USB_DESC_H */

2037
hw/usb-ehci.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -211,6 +211,7 @@ static const USBDescDevice desc_device_mouse = {
.iConfiguration = STR_CONFIG_MOUSE,
.bmAttributes = 0xa0,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_mouse,
},
},
@ -227,6 +228,7 @@ static const USBDescDevice desc_device_tablet = {
.iConfiguration = STR_CONFIG_TABLET,
.bmAttributes = 0xa0,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_tablet,
},
},
@ -243,6 +245,7 @@ static const USBDescDevice desc_device_keyboard = {
.iConfiguration = STR_CONFIG_KEYBOARD,
.bmAttributes = 0xa0,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_keyboard,
},
},
@ -724,13 +727,13 @@ static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
}
static int usb_hid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHIDState *s = (USBHIDState *)dev;
int ret;
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}

View file

@ -119,6 +119,7 @@ static const USBDescDevice desc_device_hub = {
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = 0xe0,
.nif = 1,
.ifs = &desc_iface_hub,
},
},
@ -284,13 +285,13 @@ static void usb_hub_handle_reset(USBDevice *dev)
/* XXX: do it */
}
static int usb_hub_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHubState *s = (USBHubState *)dev;
int ret;
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}
@ -494,7 +495,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->info->handle_packet(dev, p);
ret = usb_handle_packet(dev, p);
if (ret != USB_RET_NODEV) {
return ret;
}

View file

@ -119,6 +119,7 @@ static const USBDescDevice desc_device_full = {
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_FULL,
.bmAttributes = 0xc0,
.nif = 1,
.ifs = &desc_iface_full,
},
},
@ -153,6 +154,7 @@ static const USBDescDevice desc_device_high = {
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_HIGH,
.bmAttributes = 0xc0,
.nif = 1,
.ifs = &desc_iface_high,
},
},
@ -251,7 +253,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t 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) {
if (s->packet && s->usb_len == 0) {
/* Set s->packet to NULL before calling usb_packet_complete
because another request may be issued before
usb_packet_complete returns. */
@ -270,13 +272,13 @@ static void usb_msd_handle_reset(USBDevice *dev)
s->mode = USB_MSDM_CBW;
}
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
MSDState *s = (MSDState *)dev;
int ret;
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}
@ -313,9 +315,9 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
return ret;
}
static void usb_msd_cancel_io(USBPacket *p, void *opaque)
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
{
MSDState *s = opaque;
MSDState *s = DO_UPCAST(MSDState, dev, dev);
s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag);
s->packet = NULL;
s->scsi_len = 0;
@ -396,7 +398,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
if (s->usb_len) {
DPRINTF("Deferring packet %p\n", p);
usb_defer_packet(p, usb_msd_cancel_io, s);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
@ -419,7 +420,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (s->data_len != 0 || len < 13)
goto fail;
/* Waiting for SCSI write to complete. */
usb_defer_packet(p, usb_msd_cancel_io, s);
s->packet = p;
ret = USB_RET_ASYNC;
break;
@ -453,7 +453,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
if (s->usb_len) {
DPRINTF("Deferring packet %p\n", p);
usb_defer_packet(p, usb_msd_cancel_io, s);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
@ -602,6 +601,7 @@ static struct USBDeviceInfo msd_info = {
.usb_desc = &desc,
.init = usb_msd_initfn,
.handle_packet = usb_generic_handle_packet,
.cancel_packet = usb_msd_cancel_io,
.handle_attach = usb_desc_attach,
.handle_reset = usb_msd_handle_reset,
.handle_control = usb_msd_handle_control,

View file

@ -601,7 +601,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->packey[dir].dir = dir;
if (s->port.dev)
ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir].p);
ret = usb_handle_packet(s->port.dev, &ep->packey[dir].p);
else
ret = USB_RET_NODEV;

View file

@ -1042,13 +1042,13 @@ static void usb_net_handle_reset(USBDevice *dev)
{
}
static int usb_net_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBNetState *s = (USBNetState *) dev;
int ret;
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}

View file

@ -748,7 +748,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
ohci->usb_packet.data = ohci->usb_buf;
ohci->usb_packet.len = len;
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
ret = usb_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.devep = OHCI_BM(ed->flags, ED_EN);
ohci->usb_packet.data = ohci->usb_buf;
ohci->usb_packet.len = len;
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
}

View file

@ -146,6 +146,7 @@ static const USBDescDevice desc_device = {
.bConfigurationValue = 1,
.bmAttributes = 0x80,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface0,
},
},
@ -218,14 +219,14 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
return ret;
}
static int usb_serial_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBSerialState *s = (USBSerialState *)dev;
int ret;
DPRINTF("got control %x, value %x\n",request, value);
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}

View file

@ -632,7 +632,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
USBDevice *dev = port->port.dev;
if (dev && (port->ctrl & UHCI_PORT_EN))
ret = dev->info->handle_packet(dev, p);
ret = usb_handle_packet(dev, p);
}
DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
@ -702,11 +702,15 @@ out:
case USB_RET_STALL:
td->ctrl |= TD_CTRL_STALL;
td->ctrl &= ~TD_CTRL_ACTIVE;
s->status |= UHCI_STS_USBERR;
uhci_update_irq(s);
return 1;
case USB_RET_BABBLE:
td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
td->ctrl &= ~TD_CTRL_ACTIVE;
s->status |= UHCI_STS_USBERR;
uhci_update_irq(s);
/* frame interrupted */
return -1;

View file

@ -108,6 +108,7 @@ static const USBDescDevice desc_device_wacom = {
.bConfigurationValue = 1,
.bmAttributes = 0x80,
.bMaxPower = 40,
.nif = 1,
.ifs = &desc_iface_wacom,
},
},
@ -249,13 +250,13 @@ static void usb_wacom_handle_reset(USBDevice *dev)
s->mode = WACOM_MODE_HID;
}
static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBWacomState *s = (USBWacomState *) dev;
int ret;
ret = usb_desc_handle_control(dev, request, value, index, length, data);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}

101
hw/usb.c
View file

@ -63,9 +63,10 @@ void usb_wakeup(USBDevice *dev)
protocol)
*/
#define SETUP_STATE_IDLE 0
#define SETUP_STATE_DATA 1
#define SETUP_STATE_ACK 2
#define SETUP_STATE_IDLE 0
#define SETUP_STATE_SETUP 1
#define SETUP_STATE_DATA 2
#define SETUP_STATE_ACK 3
static int do_token_setup(USBDevice *s, USBPacket *p)
{
@ -82,10 +83,14 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
if (s->setup_buf[0] & USB_DIR_IN) {
ret = s->info->handle_control(s, request, value, index,
ret = s->info->handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
s->setup_state = SETUP_STATE_SETUP;
return USB_RET_ASYNC;
}
if (ret < 0)
return ret;
@ -123,9 +128,12 @@ static int do_token_in(USBDevice *s, USBPacket *p)
switch(s->setup_state) {
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
s->setup_state = SETUP_STATE_IDLE;
ret = s->info->handle_control(s, request, value, index,
ret = s->info->handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
return USB_RET_ASYNC;
}
s->setup_state = SETUP_STATE_IDLE;
if (ret > 0)
return 0;
return ret;
@ -238,6 +246,36 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
}
}
/* ctrl complete function for devices which use usb_generic_handle_packet and
may return USB_RET_ASYNC from their handle_control callback. Device code
which does this *must* call this function instead of the normal
usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
if (p->len < 0) {
s->setup_state = SETUP_STATE_IDLE;
}
switch (s->setup_state) {
case SETUP_STATE_SETUP:
if (p->len < s->setup_len) {
s->setup_len = p->len;
}
s->setup_state = SETUP_STATE_DATA;
p->len = 8;
break;
case SETUP_STATE_ACK:
s->setup_state = SETUP_STATE_IDLE;
p->len = 0;
break;
default:
break;
}
usb_packet_complete(s, p);
}
/* XXX: fix overflow */
int set_usb_string(uint8_t *buf, const char *str)
{
@ -259,9 +297,54 @@ int set_usb_string(uint8_t *buf, const char *str)
void usb_send_msg(USBDevice *dev, int msg)
{
USBPacket p;
int ret;
memset(&p, 0, sizeof(p));
p.pid = msg;
dev->info->handle_packet(dev, &p);
ret = usb_handle_packet(dev, &p);
/* This _must_ be synchronous */
assert(ret != USB_RET_ASYNC);
}
/* Hand over a packet to a device for processing. Return value
USB_RET_ASYNC indicates the processing isn't finished yet, the
driver will call usb_packet_complete() when done processing it. */
int usb_handle_packet(USBDevice *dev, USBPacket *p)
{
int ret;
assert(p->owner == NULL);
ret = dev->info->handle_packet(dev, p);
if (ret == USB_RET_ASYNC) {
if (p->owner == NULL) {
p->owner = dev;
} else {
/* We'll end up here when usb_handle_packet is called
* recursively due to a hub being in the chain. Nothing
* to do. Leave p->owner pointing to the device, not the
* hub. */;
}
}
return ret;
}
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred by returning USB_RET_ASYNC from
handle_packet. */
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
/* Note: p->owner != dev is possible in case dev is a hub */
assert(p->owner != NULL);
dev->port->ops->complete(dev, p);
p->owner = NULL;
}
/* Cancel an active packet. The packed must have been deferred by
returning USB_RET_ASYNC from handle_packet, and not yet
completed. */
void usb_cancel_packet(USBPacket * p)
{
assert(p->owner != NULL);
p->owner->info->cancel_packet(p->owner, p);
p->owner = NULL;
}

View file

@ -124,6 +124,7 @@
#define USB_DT_ENDPOINT 0x05
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_INTERFACE_ASSOC 0x0B
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
@ -140,6 +141,7 @@ typedef struct USBDesc USBDesc;
typedef struct USBDescID USBDescID;
typedef struct USBDescDevice USBDescDevice;
typedef struct USBDescConfig USBDescConfig;
typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
typedef struct USBDescIface USBDescIface;
typedef struct USBDescEndpoint USBDescEndpoint;
typedef struct USBDescOther USBDescOther;
@ -191,6 +193,11 @@ struct USBDeviceInfo {
*/
int (*handle_packet)(USBDevice *dev, USBPacket *p);
/*
* Called when a packet is canceled.
*/
void (*cancel_packet)(USBDevice *dev, USBPacket *p);
/*
* Called when device is destroyed.
*/
@ -212,7 +219,7 @@ struct USBDeviceInfo {
*
* Returns length or one of the USB_RET_ codes.
*/
int (*handle_control)(USBDevice *dev, int request, int value,
int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
int index, int length, uint8_t *data);
/*
@ -260,38 +267,17 @@ struct USBPacket {
uint8_t *data;
int len;
/* Internal use by the USB layer. */
USBCallback *cancel_cb;
void *cancel_opaque;
USBDevice *owner;
};
/* Defer completion of a USB packet. The hadle_packet routine should then
return USB_RET_ASYNC. Packets that complete immediately (before
handle_packet returns) should not call this method. */
static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel,
void * opaque)
{
p->cancel_cb = cancel;
p->cancel_opaque = opaque;
}
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred with usb_defer_packet, and
should never be called from within handle_packet. */
static inline void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
dev->port->ops->complete(dev, p);
}
/* Cancel an active packet. The packed must have been deferred with
usb_defer_packet, and not yet completed. */
static inline void usb_cancel_packet(USBPacket * p)
{
p->cancel_cb(p, p->cancel_opaque);
}
int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
void usb_attach(USBPort *port, USBDevice *dev);
void usb_wakeup(USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str);
void usb_send_msg(USBDevice *dev, int msg);

View file

@ -126,6 +126,7 @@ static void usb_host_handle_reset(USBDevice *dev)
* and return appropriate response
*/
static int usb_host_handle_control(USBDevice *dev,
USBPacket *p,
int request,
int value,
int index,

View file

@ -54,15 +54,7 @@ struct usb_ctrltransfer {
void *data;
};
struct usb_ctrlrequest {
uint8_t bRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
int class_id, int vendor_id, int product_id,
const char *product_name, int speed);
@ -79,6 +71,7 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
#define USBPROCBUS_PATH "/proc/bus/usb"
#define PRODUCT_NAME_SZ 32
#define MAX_ENDPOINTS 15
#define MAX_PORTLEN 16
#define USBDEVBUS_PATH "/dev/bus/usb"
#define USBSYSBUS_PATH "/sys/bus/usb"
@ -96,6 +89,9 @@ static int usb_fs_type;
#define ISO_URB_COUNT 3
#define INVALID_EP_TYPE 255
/* devio.c limits single requests to 16k */
#define MAX_USBFS_BUFFER_SIZE 16384
typedef struct AsyncURB AsyncURB;
struct endp_data {
@ -108,29 +104,10 @@ struct endp_data {
int max_packet_size;
};
enum {
CTRL_STATE_IDLE = 0,
CTRL_STATE_SETUP,
CTRL_STATE_DATA,
CTRL_STATE_ACK
};
/*
* Control transfer state.
* Note that 'buffer' _must_ follow 'req' field because
* we need contiguous buffer when we submit control URB.
*/
struct ctrl_struct {
uint16_t len;
uint16_t offset;
uint8_t state;
struct usb_ctrlrequest req;
uint8_t buffer[8192];
};
struct USBAutoFilter {
uint32_t bus_num;
uint32_t addr;
char *port;
uint32_t vendor_id;
uint32_t product_id;
};
@ -146,13 +123,13 @@ typedef struct USBHostDevice {
int closing;
Notifier exit;
struct ctrl_struct ctrl;
struct endp_data endp_table[MAX_ENDPOINTS];
QLIST_HEAD(, AsyncURB) aurbs;
/* Host side address */
int bus_num;
int addr;
int devpath;
char port[MAX_PORTLEN];
struct USBAutoFilter match;
QTAILQ_ENTRY(USBHostDevice) next;
@ -236,6 +213,22 @@ static int get_iso_buffer_used(USBHostDevice *s, int ep)
return s->endp_table[ep - 1].iso_buffer_used;
}
static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
{
int raw = descriptor[4] + (descriptor[5] << 8);
int size, microframes;
size = raw & 0x7ff;
switch ((raw >> 11) & 3) {
case 1: microframes = 2; break;
case 2: microframes = 3; break;
default: microframes = 1; break;
}
DPRINTF("husb: max packet size: 0x%x -> %d x %d\n",
raw, microframes, size);
s->endp_table[ep - 1].max_packet_size = size * microframes;
}
static int get_max_packet_size(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].max_packet_size;
@ -250,45 +243,31 @@ struct AsyncURB
{
struct usbdevfs_urb urb;
struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
USBHostDevice *hdev;
QLIST_ENTRY(AsyncURB) next;
/* For regular async urbs */
USBPacket *packet;
USBHostDevice *hdev;
int more; /* large transfer, more urbs follow */
/* For buffered iso handling */
int iso_frame_idx; /* -1 means in flight */
};
static AsyncURB *async_alloc(void)
static AsyncURB *async_alloc(USBHostDevice *s)
{
return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
AsyncURB *aurb = qemu_mallocz(sizeof(AsyncURB));
aurb->hdev = s;
QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
return aurb;
}
static void async_free(AsyncURB *aurb)
{
QLIST_REMOVE(aurb, next);
qemu_free(aurb);
}
static void async_complete_ctrl(USBHostDevice *s, USBPacket *p)
{
switch(s->ctrl.state) {
case CTRL_STATE_SETUP:
if (p->len < s->ctrl.len)
s->ctrl.len = p->len;
s->ctrl.state = CTRL_STATE_DATA;
p->len = 8;
break;
case CTRL_STATE_ACK:
s->ctrl.state = CTRL_STATE_IDLE;
p->len = 0;
break;
default:
break;
}
}
static void async_complete(void *opaque)
{
USBHostDevice *s = opaque;
@ -332,10 +311,7 @@ static void async_complete(void *opaque)
if (p) {
switch (aurb->urb.status) {
case 0:
p->len = aurb->urb.actual_length;
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
async_complete_ctrl(s, p);
}
p->len += aurb->urb.actual_length;
break;
case -EPIPE:
@ -348,26 +324,36 @@ static void async_complete(void *opaque)
break;
}
usb_packet_complete(&s->dev, p);
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
usb_generic_async_ctrl_complete(&s->dev, p);
} else if (!aurb->more) {
usb_packet_complete(&s->dev, p);
}
}
async_free(aurb);
}
}
static void async_cancel(USBPacket *unused, void *opaque)
static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
{
AsyncURB *aurb = opaque;
USBHostDevice *s = aurb->hdev;
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
AsyncURB *aurb;
DPRINTF("husb: async cancel. aurb %p\n", aurb);
QLIST_FOREACH(aurb, &s->aurbs, next) {
if (p != aurb->packet) {
continue;
}
/* Mark it as dead (see async_complete above) */
aurb->packet = NULL;
DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
if (r < 0) {
DPRINTF("husb: async. discard urb failed errno %d\n", errno);
/* Mark it as dead (see async_complete above) */
aurb->packet = NULL;
int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
if (r < 0) {
DPRINTF("husb: async. discard urb failed errno %d\n", errno);
}
}
}
@ -675,11 +661,13 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
return len;
}
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
struct usbdevfs_urb *urb;
AsyncURB *aurb;
int ret;
int ret, rem;
uint8_t *pbuf;
uint8_t ep;
if (!is_valid(s, p->devep)) {
@ -706,37 +694,48 @@ static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
}
aurb = async_alloc();
aurb->hdev = s;
aurb->packet = p;
rem = p->len;
pbuf = p->data;
p->len = 0;
while (rem) {
aurb = async_alloc(s);
aurb->packet = p;
urb = &aurb->urb;
urb = &aurb->urb;
urb->endpoint = ep;
urb->type = USBDEVFS_URB_TYPE_BULK;
urb->usercontext = s;
urb->buffer = pbuf;
urb->endpoint = ep;
urb->buffer = p->data;
urb->buffer_length = p->len;
urb->type = USBDEVFS_URB_TYPE_BULK;
urb->usercontext = s;
if (rem > MAX_USBFS_BUFFER_SIZE) {
urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
aurb->more = 1;
} else {
urb->buffer_length = rem;
aurb->more = 0;
}
pbuf += urb->buffer_length;
rem -= urb->buffer_length;
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
urb->endpoint, p->len, aurb);
DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
if (ret < 0) {
DPRINTF("husb: submit failed. errno %d\n", errno);
async_free(aurb);
if (ret < 0) {
DPRINTF("husb: submit failed. errno %d\n", errno);
async_free(aurb);
switch(errno) {
case ETIMEDOUT:
return USB_RET_NAK;
case EPIPE:
default:
return USB_RET_STALL;
switch(errno) {
case ETIMEDOUT:
return USB_RET_NAK;
case EPIPE:
default:
return USB_RET_STALL;
}
}
}
usb_defer_packet(p, async_cancel, aurb);
return USB_RET_ASYNC;
}
@ -796,50 +795,43 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
return 0;
}
static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
struct usbdevfs_urb *urb;
AsyncURB *aurb;
int ret, value, index;
int buffer_len;
int ret;
/*
* Process certain standard device requests.
* These are infrequent and are processed synchronously.
*/
value = le16_to_cpu(s->ctrl.req.wValue);
index = le16_to_cpu(s->ctrl.req.wIndex);
/* Note request is (bRequestType << 8) | bRequest */
DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
s->ctrl.len);
request >> 8, request & 0xff, value, index, length);
if (s->ctrl.req.bRequestType == 0) {
switch (s->ctrl.req.bRequest) {
case USB_REQ_SET_ADDRESS:
return usb_host_set_address(s, value);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
return usb_host_set_address(s, value);
case USB_REQ_SET_CONFIGURATION:
return usb_host_set_config(s, value & 0xff);
}
}
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
return usb_host_set_config(s, value & 0xff);
if (s->ctrl.req.bRequestType == 1 &&
s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
return usb_host_set_interface(s, index, value);
}
/* The rest are asynchronous */
buffer_len = 8 + s->ctrl.len;
if (buffer_len > sizeof(s->ctrl.buffer)) {
fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
buffer_len, sizeof(s->ctrl.buffer));
if (length > sizeof(dev->data_buf)) {
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
length, sizeof(dev->data_buf));
return USB_RET_STALL;
}
aurb = async_alloc();
aurb->hdev = s;
aurb = async_alloc(s);
aurb->packet = p;
/*
@ -853,8 +845,8 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
urb->type = USBDEVFS_URB_TYPE_CONTROL;
urb->endpoint = p->devep;
urb->buffer = &s->ctrl.req;
urb->buffer_length = buffer_len;
urb->buffer = &dev->setup_buf;
urb->buffer_length = length + 8;
urb->usercontext = s;
@ -875,174 +867,9 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
}
}
usb_defer_packet(p, async_cancel, aurb);
return USB_RET_ASYNC;
}
static int do_token_setup(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = (USBHostDevice *) dev;
int ret = 0;
if (p->len != 8) {
return USB_RET_STALL;
}
memcpy(&s->ctrl.req, p->data, 8);
s->ctrl.len = le16_to_cpu(s->ctrl.req.wLength);
s->ctrl.offset = 0;
s->ctrl.state = CTRL_STATE_SETUP;
if (s->ctrl.req.bRequestType & USB_DIR_IN) {
ret = usb_host_handle_control(s, p);
if (ret < 0) {
return ret;
}
if (ret < s->ctrl.len) {
s->ctrl.len = ret;
}
s->ctrl.state = CTRL_STATE_DATA;
} else {
if (s->ctrl.len == 0) {
s->ctrl.state = CTRL_STATE_ACK;
} else {
s->ctrl.state = CTRL_STATE_DATA;
}
}
return ret;
}
static int do_token_in(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = (USBHostDevice *) dev;
int ret = 0;
if (p->devep != 0) {
return usb_host_handle_data(s, p);
}
switch(s->ctrl.state) {
case CTRL_STATE_ACK:
if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
ret = usb_host_handle_control(s, p);
if (ret == USB_RET_ASYNC) {
return USB_RET_ASYNC;
}
s->ctrl.state = CTRL_STATE_IDLE;
return ret > 0 ? 0 : ret;
}
return 0;
case CTRL_STATE_DATA:
if (s->ctrl.req.bRequestType & USB_DIR_IN) {
int len = s->ctrl.len - s->ctrl.offset;
if (len > p->len) {
len = p->len;
}
memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len);
s->ctrl.offset += len;
if (s->ctrl.offset >= s->ctrl.len) {
s->ctrl.state = CTRL_STATE_ACK;
}
return len;
}
s->ctrl.state = CTRL_STATE_IDLE;
return USB_RET_STALL;
default:
return USB_RET_STALL;
}
}
static int do_token_out(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = (USBHostDevice *) dev;
if (p->devep != 0) {
return usb_host_handle_data(s, p);
}
switch(s->ctrl.state) {
case CTRL_STATE_ACK:
if (s->ctrl.req.bRequestType & USB_DIR_IN) {
s->ctrl.state = CTRL_STATE_IDLE;
/* transfer OK */
} else {
/* ignore additional output */
}
return 0;
case CTRL_STATE_DATA:
if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
int len = s->ctrl.len - s->ctrl.offset;
if (len > p->len) {
len = p->len;
}
memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len);
s->ctrl.offset += len;
if (s->ctrl.offset >= s->ctrl.len) {
s->ctrl.state = CTRL_STATE_ACK;
}
return len;
}
s->ctrl.state = CTRL_STATE_IDLE;
return USB_RET_STALL;
default:
return USB_RET_STALL;
}
}
/*
* Packet handler.
* Called by the HC (host controller).
*
* Returns length of the transaction or one of the USB_RET_XXX codes.
*/
static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
{
switch(p->pid) {
case USB_MSG_ATTACH:
s->state = USB_STATE_ATTACHED;
return 0;
case USB_MSG_DETACH:
s->state = USB_STATE_NOTATTACHED;
return 0;
case USB_MSG_RESET:
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
s->info->handle_reset(s);
return 0;
}
/* Rest of the PIDs must match our address */
if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) {
return USB_RET_NODEV;
}
switch (p->pid) {
case USB_TOKEN_SETUP:
return do_token_setup(s, p);
case USB_TOKEN_IN:
return do_token_in(s, p);
case USB_TOKEN_OUT:
return do_token_out(s, p);
default:
return USB_RET_STALL;
}
}
static int usb_linux_get_configuration(USBHostDevice *s)
{
uint8_t configuration;
@ -1053,7 +880,7 @@ static int usb_linux_get_configuration(USBHostDevice *s)
char device_name[32], line[1024];
int configuration;
sprintf(device_name, "%d-%d", s->bus_num, s->devpath);
sprintf(device_name, "%d-%s", s->bus_num, s->port);
if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
device_name)) {
@ -1099,7 +926,7 @@ static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
char device_name[64], line[1024];
int alt_setting;
sprintf(device_name, "%d-%d:%d.%d", s->bus_num, s->devpath,
sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
(int)configuration, (int)interface);
if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
@ -1195,8 +1022,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
break;
case 0x01:
type = USBDEVFS_URB_TYPE_ISO;
s->endp_table[(devep & 0xf) - 1].max_packet_size =
descriptors[i + 4] + (descriptors[i + 5] << 8);
set_max_packet_size(s, (devep & 0xf), descriptors + i);
break;
case 0x02:
type = USBDEVFS_URB_TYPE_BULK;
@ -1218,7 +1044,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
static int usb_host_open(USBHostDevice *dev, int bus_num,
int addr, int devpath, const char *prod_name)
int addr, char *port, const char *prod_name)
{
int fd = -1, ret;
struct usbdevfs_connectinfo ci;
@ -1244,7 +1070,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
dev->bus_num = bus_num;
dev->addr = addr;
dev->devpath = devpath;
strcpy(dev->port, port);
dev->fd = fd;
/* read the device description */
@ -1368,7 +1194,10 @@ static struct USBDeviceInfo usb_host_dev_info = {
.qdev.name = "usb-host",
.qdev.size = sizeof(USBHostDevice),
.init = usb_host_initfn,
.handle_packet = usb_host_handle_packet,
.handle_packet = usb_generic_handle_packet,
.cancel_packet = usb_host_async_cancel,
.handle_data = usb_host_handle_data,
.handle_control = usb_host_handle_control,
.handle_reset = usb_host_handle_reset,
.handle_destroy = usb_host_handle_destroy,
.usbdevice_name = "host",
@ -1376,6 +1205,7 @@ static struct USBDeviceInfo usb_host_dev_info = {
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_END_OF_LIST(),
@ -1616,8 +1446,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
{
DIR *dir = NULL;
char line[1024];
int bus_num, addr, devpath, speed, class_id, product_id, vendor_id;
int bus_num, addr, speed, class_id, product_id, vendor_id;
int ret = 0;
char port[MAX_PORTLEN];
char product_name[512];
struct dirent *de;
@ -1629,12 +1460,8 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
while ((de = readdir(dir))) {
if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
char *tmpstr = de->d_name;
if (!strncmp(de->d_name, "usb", 3)) {
tmpstr += 3;
}
if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) {
goto the_end;
if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
continue;
}
if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
@ -1686,7 +1513,7 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
speed = USB_SPEED_FULL;
}
ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id,
ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
product_id, product_name, speed);
if (ret) {
goto the_end;
@ -1777,7 +1604,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
static QEMUTimer *usb_auto_timer;
static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
int class_id, int vendor_id, int product_id,
const char *product_name, int speed)
{
@ -1797,6 +1624,9 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
if (f->addr > 0 && f->addr != addr) {
continue;
}
if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
continue;
}
if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
continue;
@ -1813,7 +1643,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
}
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
usb_host_open(s, bus_num, addr, devpath, product_name);
usb_host_open(s, bus_num, addr, port, product_name);
}
return 0;
@ -1935,8 +1765,8 @@ static const char *usb_class_str(uint8_t class)
return p->class_name;
}
static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
int vendor_id, int product_id,
static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
int class_id, int vendor_id, int product_id,
const char *product_name,
int speed)
{
@ -1957,8 +1787,8 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
break;
}
monitor_printf(mon, " Device %d.%d, speed %s Mb/s\n",
bus_num, addr, speed_str);
monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
bus_num, addr, port, speed_str);
class_str = usb_class_str(class_id);
if (class_str) {
monitor_printf(mon, " %s:", class_str);
@ -1973,14 +1803,14 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
}
static int usb_host_info_device(void *opaque, int bus_num, int addr,
int devpath, int class_id,
char *path, int class_id,
int vendor_id, int product_id,
const char *product_name,
int speed)
{
Monitor *mon = opaque;
usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
product_name, speed);
return 0;
}
@ -2022,7 +1852,7 @@ void usb_host_info(Monitor *mon)
dec2str(f->addr, addr, sizeof(addr));
hex2str(f->vendor_id, vid, sizeof(vid));
hex2str(f->product_id, pid, sizeof(pid));
monitor_printf(mon, " Device %s.%s ID %s:%s\n",
bus, addr, vid, pid);
monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
bus, addr, f->port ? f->port : "*", vid, pid);
}
}