From 5d0d62feee8aa75525207ef24919c0522651a432 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 17 Dec 2010 11:11:25 +0100 Subject: [PATCH 01/32] usb: update MAINTAINERS Signed-off-by: Gerd Hoffmann --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 59effc7143..4b07192d4e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -329,8 +329,8 @@ F: hw/lsi53c895a.c F: hw/scsi* USB -M: qemu-devel@nongnu.org -S: Odd Fixes +M: Gerd Hoffmann +S: Maintained F: hw/usb* vhost From 37fb59d3032687b6f0d94c307bd0a846e0ca1fe0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Nov 2010 11:03:53 +0100 Subject: [PATCH 02/32] usb: data structs and helpers for usb descriptors. This patch adds hw/usb-desc.[ch] files. They carry data structures for various usb descriptors and helper functions to generate usb packets from the structures. The intention is to have a internal representation of the device desription which is more usable than the current char array blobs, so we can have common code handle common usb device emulation using the device description. The usage of this infrastructure is optional for usb drivers as there are cases such as pass-through where it probably isn't very useful. Signed-off-by: Gerd Hoffmann --- Makefile.objs | 2 +- hw/usb-desc.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb-desc.h | 86 ++++++++++++++++++ hw/usb.h | 9 ++ trace-events | 5 ++ 5 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 hw/usb-desc.c create mode 100644 hw/usb-desc.h diff --git a/Makefile.objs b/Makefile.objs index c3e52c5674..fda366d11c 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -88,7 +88,7 @@ common-obj-y += eeprom93xx.o common-obj-y += scsi-disk.o cdrom.o common-obj-y += scsi-generic.o scsi-bus.o common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o -common-obj-y += usb-serial.o usb-net.o usb-bus.o +common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o common-obj-$(CONFIG_SSI) += ssi.o common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o diff --git a/hw/usb-desc.c b/hw/usb-desc.c new file mode 100644 index 0000000000..559ced78b9 --- /dev/null +++ b/hw/usb-desc.c @@ -0,0 +1,238 @@ +#include "usb.h" +#include "usb-desc.h" +#include "trace.h" + +/* ------------------------------------------------------------------ */ + +static uint8_t usb_lo(uint16_t val) +{ + return val & 0xff; +} + +static uint8_t usb_hi(uint16_t val) +{ + return (val >> 8) & 0xff; +} + +int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, + uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x12; + + if (len < bLength) { + return -1; + } + + dest[0x00] = bLength; + dest[0x01] = USB_DT_DEVICE; + + dest[0x02] = usb_lo(dev->bcdUSB); + dest[0x03] = usb_hi(dev->bcdUSB); + dest[0x04] = dev->bDeviceClass; + dest[0x05] = dev->bDeviceSubClass; + dest[0x06] = dev->bDeviceProtocol; + dest[0x07] = dev->bMaxPacketSize0; + + dest[0x08] = usb_lo(id->idVendor); + dest[0x09] = usb_hi(id->idVendor); + dest[0x0a] = usb_lo(id->idProduct); + dest[0x0b] = usb_hi(id->idProduct); + dest[0x0c] = usb_lo(id->bcdDevice); + dest[0x0d] = usb_hi(id->bcdDevice); + dest[0x0e] = id->iManufacturer; + dest[0x0f] = id->iProduct; + dest[0x10] = id->iSerialNumber; + + dest[0x11] = dev->bNumConfigurations; + + return bLength; +} + +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; + + if (len < bLength) { + return -1; + } + + dest[0x00] = bLength; + dest[0x01] = USB_DT_CONFIG; + dest[0x04] = conf->bNumInterfaces; + dest[0x05] = conf->bConfigurationValue; + dest[0x06] = conf->iConfiguration; + dest[0x07] = conf->bmAttributes; + dest[0x08] = conf->bMaxPower; + wTotalLength += bLength; + + count = conf->nif ? conf->nif : conf->bNumInterfaces; + for (i = 0; i < count; i++) { + rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); + if (rc < 0) { + return rc; + } + wTotalLength += rc; + } + + dest[0x02] = usb_lo(wTotalLength); + dest[0x03] = usb_hi(wTotalLength); + return wTotalLength; +} + +int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x09; + int i, rc, pos = 0; + + if (len < bLength) { + return -1; + } + + dest[0x00] = bLength; + dest[0x01] = USB_DT_INTERFACE; + dest[0x02] = iface->bInterfaceNumber; + dest[0x03] = iface->bAlternateSetting; + dest[0x04] = iface->bNumEndpoints; + dest[0x05] = iface->bInterfaceClass; + dest[0x06] = iface->bInterfaceSubClass; + dest[0x07] = iface->bInterfaceProtocol; + dest[0x08] = iface->iInterface; + pos += bLength; + + for (i = 0; i < iface->ndesc; i++) { + rc = usb_desc_other(iface->descs + i, dest + pos, len - pos); + if (rc < 0) { + return rc; + } + pos += rc; + } + + for (i = 0; i < iface->bNumEndpoints; i++) { + rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); + if (rc < 0) { + return rc; + } + pos += rc; + } + + return pos; +} + +int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x07; + + if (len < bLength) { + return -1; + } + + dest[0x00] = bLength; + dest[0x01] = USB_DT_ENDPOINT; + dest[0x02] = ep->bEndpointAddress; + dest[0x03] = ep->bmAttributes; + dest[0x04] = usb_lo(ep->wMaxPacketSize); + dest[0x05] = usb_hi(ep->wMaxPacketSize); + dest[0x06] = ep->bInterval; + + return bLength; +} + +int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) +{ + int bLength = desc->length ? desc->length : desc->data[0]; + + if (len < bLength) { + return -1; + } + + memcpy(dest, desc->data, bLength); + return bLength; +} + +int usb_desc_string(const char* const *str, int index, uint8_t *dest, size_t len) +{ + uint8_t bLength, pos, i; + + if (len < 4) { + return -1; + } + + if (index == 0) { + /* language ids */ + dest[0] = 4; + dest[1] = USB_DT_STRING; + dest[2] = 0x09; + dest[3] = 0x04; + return 4; + } + + if (str[index] == NULL) { + return 0; + } + bLength = strlen(str[index]) * 2 + 2; + dest[0] = bLength; + dest[1] = USB_DT_STRING; + i = 0; pos = 2; + while (pos+1 < bLength && pos+1 < len) { + dest[pos++] = str[index][i++]; + dest[pos++] = 0; + } + return pos; +} + +/* ------------------------------------------------------------------ */ + +int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) +{ + const USBDesc *desc = dev->info->usb_desc; + uint8_t buf[256]; + uint8_t type = value >> 8; + uint8_t index = value & 0xff; + int ret = -1; + + switch(type) { + case USB_DT_DEVICE: + ret = usb_desc_device(&desc->id, desc->full, buf, sizeof(buf)); + trace_usb_desc_device(dev->addr, len, ret); + break; + case USB_DT_CONFIG: + if (index < desc->full->bNumConfigurations) { + ret = usb_desc_config(desc->full->confs + index, buf, sizeof(buf)); + } + trace_usb_desc_config(dev->addr, index, len, ret); + break; + case USB_DT_STRING: + ret = usb_desc_string(desc->str, index, buf, sizeof(buf)); + trace_usb_desc_string(dev->addr, index, len, ret); + break; + default: + fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, + dev->addr, type, len); + break; + } + + if (ret > 0) { + if (ret > len) { + ret = len; + } + memcpy(dest, buf, ret); + } + return ret; +} + +int usb_desc_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + const USBDesc *desc = dev->info->usb_desc; + int ret = -1; + + assert(desc != NULL); + switch(request) { + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + ret = usb_desc_get_descriptor(dev, value, data, length); + break; + } + return ret; +} diff --git a/hw/usb-desc.h b/hw/usb-desc.h new file mode 100644 index 0000000000..d80efdb24f --- /dev/null +++ b/hw/usb-desc.h @@ -0,0 +1,86 @@ +#ifndef QEMU_HW_USB_DESC_H +#define QEMU_HW_USB_DESC_H + +#include + +struct USBDescID { + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; +}; + +struct USBDescDevice { + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + + const USBDescConfig *confs; +}; + +struct USBDescConfig { + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; + + uint8_t nif; + const USBDescIface *ifs; +}; + +struct USBDescIface { + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; + + uint8_t ndesc; + USBDescOther *descs; + USBDescEndpoint *eps; +}; + +struct USBDescEndpoint { + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +}; + +struct USBDescOther { + uint8_t length; + uint8_t *data; +}; + +typedef const char *USBDescStrings[256]; + +struct USBDesc { + USBDescID id; + const USBDescDevice *full; + const USBDescDevice *high; + const char* const *str; +}; + +/* generate usb packages from structs */ +int usb_desc_device(const USBDescID *id, 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(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); +int usb_desc_string(const char* const *str, int index, uint8_t *dest, size_t len); + +/* control message emulation helpers */ +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); + +#endif /* QEMU_HW_USB_DESC_H */ diff --git a/hw/usb.h b/hw/usb.h index 0b32d77e6f..a29b6d6d8f 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -128,6 +128,14 @@ typedef struct USBDevice USBDevice; typedef struct USBDeviceInfo USBDeviceInfo; typedef struct USBPacket USBPacket; +typedef struct USBDesc USBDesc; +typedef struct USBDescID USBDescID; +typedef struct USBDescDevice USBDescDevice; +typedef struct USBDescConfig USBDescConfig; +typedef struct USBDescIface USBDescIface; +typedef struct USBDescEndpoint USBDescEndpoint; +typedef struct USBDescOther USBDescOther; + /* definition of a USB device */ struct USBDevice { DeviceState qdev; @@ -190,6 +198,7 @@ struct USBDeviceInfo { int (*handle_data)(USBDevice *dev, USBPacket *p); const char *product_desc; + const USBDesc *usb_desc; /* handle legacy -usbdevice command line options */ const char *usbdevice_name; diff --git a/trace-events b/trace-events index e8fed0f424..8264ff0e77 100644 --- a/trace-events +++ b/trace-events @@ -190,6 +190,11 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x" disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64"" +# hw/usb-desc.c +disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" +disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" +disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" + # vl.c disable vm_state_notify(int running, int reason) "running %d reason %d" From 0e4e9695d5c4a5923094906433b5f7b431ba35e4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Nov 2010 11:05:05 +0100 Subject: [PATCH 03/32] usb hid: use new descriptor infrastructure. Switch the usb hid drivers (keyboard, mouse, tablet) over to the new descriptor infrastructure. Signed-off-by: Gerd Hoffmann --- hw/usb-hid.c | 440 +++++++++++++++++++++++---------------------------- 1 file changed, 201 insertions(+), 239 deletions(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 882d933466..74d17fc26f 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -25,6 +25,7 @@ #include "hw.h" #include "console.h" #include "usb.h" +#include "usb-desc.h" #include "sysemu.h" /* HID interface requests */ @@ -73,190 +74,206 @@ typedef struct USBHIDState { void (*datain)(void *); } USBHIDState; -/* mostly the same values as the Bochs USB Mouse device */ -static const uint8_t qemu_mouse_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x00, 0x01, /* u16 bcdUSB; v1.0 */ - - 0x00, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - 0x27, 0x06, /* u16 idVendor; */ - 0x01, 0x00, /* u16 idProduct; */ - 0x00, 0x00, /* u16 bcdDevice */ - - 0x03, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x01, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ +enum { + STR_MANUFACTURER = 1, + STR_PRODUCT_MOUSE, + STR_PRODUCT_TABLET, + STR_PRODUCT_KEYBOARD, + STR_SERIALNUMBER, + STR_CONFIG_MOUSE, + STR_CONFIG_TABLET, + STR_CONFIG_KEYBOARD, }; -static const uint8_t qemu_mouse_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ - 0xe0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 50, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x03, /* u8 if_bInterfaceClass; */ - 0x01, /* u8 if_bInterfaceSubClass; */ - 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x07, /* u8 if_iInterface; */ - - /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ - 0x01, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 52, 0, /* u16 len */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x04, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, + [STR_PRODUCT_MOUSE] = "QEMU USB Mouse", + [STR_PRODUCT_TABLET] = "QEMU USB Tablet", + [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard", + [STR_SERIALNUMBER] = "1", + [STR_CONFIG_MOUSE] = "HID Mouse", + [STR_CONFIG_TABLET] = "HID Tablet", + [STR_CONFIG_KEYBOARD] = "HID Keyboard", }; -static const uint8_t qemu_tablet_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x05, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 50, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x03, /* u8 if_bInterfaceClass; */ - 0x01, /* u8 if_bInterfaceSubClass; */ - 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x07, /* u8 if_iInterface; */ - - /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ - 0x01, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 74, 0, /* u16 len */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +static const USBDescIface desc_iface_mouse = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0x01, /* boot */ + .bInterfaceProtocol = 0x02, + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_HID, /* u8 bDescriptorType */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type: Report */ + 52, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 4, + .bInterval = 0x0a, + }, + }, }; -static const uint8_t qemu_keyboard_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x06, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 0x32, /* u8 MaxPower; */ +static const USBDescIface desc_iface_tablet = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0x01, /* boot */ + .bInterfaceProtocol = 0x02, + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_HID, /* u8 bDescriptorType */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type: Report */ + 74, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 8, + .bInterval = 0x0a, + }, + }, +}; - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ +static const USBDescIface desc_iface_keyboard = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0x01, /* boot */ + .bInterfaceProtocol = 0x01, /* keyboard */ + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_HID, /* u8 bDescriptorType */ + 0x11, 0x01, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type: Report */ + 0x3f, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 8, + .bInterval = 0x0a, + }, + }, +}; - /* one interface */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x03, /* u8 if_bInterfaceClass; HID */ - 0x01, /* u8 if_bInterfaceSubClass; Boot */ - 0x01, /* u8 if_bInterfaceProtocol; Keyboard */ - 0x07, /* u8 if_iInterface; */ +static const USBDescDevice desc_device_mouse = { + .bcdUSB = 0x0100, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_MOUSE, + .bmAttributes = 0xa0, + .bMaxPower = 50, + .ifs = &desc_iface_mouse, + }, + }, +}; - /* HID descriptor */ - 0x09, /* u8 bLength; */ - USB_DT_HID, /* u8 bDescriptorType; */ - 0x11, 0x01, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - USB_DT_REPORT, /* u8 type; Report */ - 0x3f, 0x00, /* u16 len */ +static const USBDescDevice desc_device_tablet = { + .bcdUSB = 0x0100, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_TABLET, + .bmAttributes = 0xa0, + .bMaxPower = 50, + .ifs = &desc_iface_tablet, + }, + }, +}; - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ - USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +static const USBDescDevice desc_device_keyboard = { + .bcdUSB = 0x0100, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_KEYBOARD, + .bmAttributes = 0xa0, + .bMaxPower = 50, + .ifs = &desc_iface_keyboard, + }, + }, +}; + +static const USBDesc desc_mouse = { + .id = { + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_MOUSE, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_mouse, + .str = desc_strings, +}; + +static const USBDesc desc_tablet = { + .id = { + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_TABLET, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_tablet, + .str = desc_strings, +}; + +static const USBDesc desc_keyboard = { + .id = { + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_KEYBOARD, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_keyboard, + .str = desc_strings, }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { @@ -647,8 +664,14 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { USBHIDState *s = (USBHIDState *)dev; - int ret = 0; + int ret; + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + ret = 0; switch(request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | @@ -676,70 +699,6 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, dev->addr = value; ret = 0; break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_mouse_dev_descriptor, - sizeof(qemu_mouse_dev_descriptor)); - ret = sizeof(qemu_mouse_dev_descriptor); - break; - case USB_DT_CONFIG: - if (s->kind == USB_MOUSE) { - memcpy(data, qemu_mouse_config_descriptor, - sizeof(qemu_mouse_config_descriptor)); - ret = sizeof(qemu_mouse_config_descriptor); - } else if (s->kind == USB_TABLET) { - memcpy(data, qemu_tablet_config_descriptor, - sizeof(qemu_tablet_config_descriptor)); - ret = sizeof(qemu_tablet_config_descriptor); - } else if (s->kind == USB_KEYBOARD) { - memcpy(data, qemu_keyboard_config_descriptor, - sizeof(qemu_keyboard_config_descriptor)); - ret = sizeof(qemu_keyboard_config_descriptor); - } - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* serial number */ - ret = set_usb_string(data, "1"); - break; - case 2: - /* product description */ - ret = set_usb_string(data, s->dev.product_desc); - break; - case 3: - /* vendor description */ - ret = set_usb_string(data, "QEMU " QEMU_VERSION); - break; - case 4: - ret = set_usb_string(data, "HID Mouse"); - break; - case 5: - ret = set_usb_string(data, "HID Tablet"); - break; - case 6: - ret = set_usb_string(data, "HID Keyboard"); - break; - case 7: - ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; @@ -912,6 +871,7 @@ static struct USBDeviceInfo hid_info[] = { .qdev.name = "usb-tablet", .usbdevice_name = "tablet", .qdev.size = sizeof(USBHIDState), + .usb_desc = &desc_tablet, .init = usb_tablet_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_mouse_handle_reset, @@ -923,6 +883,7 @@ static struct USBDeviceInfo hid_info[] = { .qdev.name = "usb-mouse", .usbdevice_name = "mouse", .qdev.size = sizeof(USBHIDState), + .usb_desc = &desc_mouse, .init = usb_mouse_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_mouse_handle_reset, @@ -934,6 +895,7 @@ static struct USBDeviceInfo hid_info[] = { .qdev.name = "usb-kbd", .usbdevice_name = "keyboard", .qdev.size = sizeof(USBHIDState), + .usb_desc = &desc_keyboard, .init = usb_keyboard_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_keyboard_handle_reset, From f29783f72ea77dfbd7ea0c993d62d253d4c4e023 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Nov 2010 11:05:32 +0100 Subject: [PATCH 04/32] usb serial: use new descriptor infrastructure. Switch the usb serial drivers (serial, braille) over to the new descriptor infrastructure. Note that this removes the freely configurable vendor and product id properties. I think the only reason this was configurable is that the only difference between the serial and the braille device is the vendor+product id. Of course the serial and braille devices keep their different IDs, but they can't be overritten from the command line any more. Signed-off-by: Gerd Hoffmann --- hw/usb-serial.c | 192 ++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 113 deletions(-) diff --git a/hw/usb-serial.c b/hw/usb-serial.c index c19580f305..f89eb9b3a3 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -11,6 +11,7 @@ #include "qemu-common.h" #include "qemu-error.h" #include "usb.h" +#include "usb-desc.h" #include "qemu-char.h" //#define DEBUG_Serial @@ -91,8 +92,6 @@ do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0) typedef struct { USBDevice dev; - uint32_t vendorid; - uint32_t productid; uint8_t recv_buf[RECV_BUF]; uint16_t recv_ptr; uint16_t recv_used; @@ -104,69 +103,78 @@ typedef struct { CharDriverState *cs; } USBSerialState; -static const uint8_t qemu_serial_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x00, 0x02, /* u16 bcdUSB; v2.0 */ - - 0x00, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - /* Vendor and product id are arbitrary. */ - 0x03, 0x04, /* u16 idVendor; */ - 0x00, 0xFF, /* u16 idProduct; */ - 0x00, 0x04, /* u16 bcdDevice */ - - 0x01, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x03, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ +enum { + STR_MANUFACTURER = 1, + STR_PRODUCT_SERIAL, + STR_PRODUCT_BRAILLE, + STR_SERIALNUMBER, }; -static const uint8_t qemu_serial_config_descriptor[] = { +static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, + [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL", + [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE", + [STR_SERIALNUMBER] = "1", +}; - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x20, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0x80, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 100/2, /* u8 MaxPower; */ +static const USBDescIface desc_iface0 = { + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 64, + },{ + .bEndpointAddress = USB_DIR_OUT | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 64, + }, + } +}; - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xff, /* u8 if_bInterfaceClass; Vendor Specific */ - 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */ - 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */ - 0x02, /* u8 if_iInterface; */ +static const USBDescDevice desc_device = { + .bcdUSB = 0x0200, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .bmAttributes = 0x80, + .bMaxPower = 50, + .ifs = &desc_iface0, + }, + }, +}; - /* Bulk-In endpoint */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x02, /* u8 ep_bmAttributes; Bulk */ - 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x00, /* u8 ep_bInterval; */ +static const USBDesc desc_serial = { + .id = { + .idVendor = 0x0403, + .idProduct = 0x6001, + .bcdDevice = 0x0400, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_SERIAL, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device, + .str = desc_strings, +}; - /* Bulk-Out endpoint */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ - 0x02, /* u8 ep_bmAttributes; Bulk */ - 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x00 /* u8 ep_bInterval; */ +static const USBDesc desc_braille = { + .id = { + .idVendor = 0x0403, + .idProduct = 0xfe72, + .bcdDevice = 0x0400, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_BRAILLE, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device, + .str = desc_strings, }; static void usb_serial_reset(USBSerialState *s) @@ -214,9 +222,15 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { USBSerialState *s = (USBSerialState *)dev; - int ret = 0; + int ret; - //DPRINTF("got control %x, value %x\n",request, value); + DPRINTF("got control %x, value %x\n",request, value); + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + ret = 0; switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (0 << USB_DEVICE_SELF_POWERED) | @@ -244,52 +258,6 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value, dev->addr = value; ret = 0; break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_serial_dev_descriptor, - sizeof(qemu_serial_dev_descriptor)); - data[8] = s->vendorid & 0xff; - data[9] = ((s->vendorid) >> 8) & 0xff; - data[10] = s->productid & 0xff; - data[11] = ((s->productid) >> 8) & 0xff; - ret = sizeof(qemu_serial_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_serial_config_descriptor, - sizeof(qemu_serial_config_descriptor)); - ret = sizeof(qemu_serial_config_descriptor); - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* vendor description */ - ret = set_usb_string(data, "QEMU " QEMU_VERSION); - break; - case 2: - /* product description */ - ret = set_usb_string(data, "QEMU USB SERIAL"); - break; - case 3: - /* serial number */ - ret = set_usb_string(data, "1"); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; @@ -633,6 +601,7 @@ static struct USBDeviceInfo serial_info = { .product_desc = "QEMU USB Serial", .qdev.name = "usb-serial", .qdev.size = sizeof(USBSerialState), + .usb_desc = &desc_serial, .init = usb_serial_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_serial_handle_reset, @@ -642,9 +611,7 @@ static struct USBDeviceInfo serial_info = { .usbdevice_name = "serial", .usbdevice_init = usb_serial_init, .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", USBSerialState, cs), - DEFINE_PROP_HEX32("vendorid", USBSerialState, vendorid, 0x0403), - DEFINE_PROP_HEX32("productid", USBSerialState, productid, 0x6001), + DEFINE_PROP_CHR("chardev", USBSerialState, cs), DEFINE_PROP_END_OF_LIST(), }, }; @@ -653,6 +620,7 @@ static struct USBDeviceInfo braille_info = { .product_desc = "QEMU USB Braille", .qdev.name = "usb-braille", .qdev.size = sizeof(USBSerialState), + .usb_desc = &desc_braille, .init = usb_serial_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_serial_handle_reset, @@ -662,9 +630,7 @@ static struct USBDeviceInfo braille_info = { .usbdevice_name = "braille", .usbdevice_init = usb_braille_init, .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", USBSerialState, cs), - DEFINE_PROP_HEX32("vendorid", USBSerialState, vendorid, 0x0403), - DEFINE_PROP_HEX32("productid", USBSerialState, productid, 0xfe72), + DEFINE_PROP_CHR("chardev", USBSerialState, cs), DEFINE_PROP_END_OF_LIST(), }, }; From 81bfd2f24678c5f36d9a6942af3d4b48e4b87226 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Nov 2010 11:05:41 +0100 Subject: [PATCH 05/32] usb storage: use new descriptor infrastructure. Switch the usb storage driver over to the new descriptor infrastructure. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 161 +++++++++++++++++++-------------------------------- 1 file changed, 60 insertions(+), 101 deletions(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 0a95d8d506..20ab886747 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -11,6 +11,7 @@ #include "qemu-option.h" #include "qemu-config.h" #include "usb.h" +#include "usb-desc.h" #include "scsi.h" #include "console.h" #include "monitor.h" @@ -72,69 +73,62 @@ struct usb_msd_csw { uint8_t status; }; -static const uint8_t qemu_msd_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x00, 0x01, /* u16 bcdUSB; v1.0 */ - - 0x00, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - /* Vendor and product id are arbitrary. */ - 0x00, 0x00, /* u16 idVendor; */ - 0x00, 0x00, /* u16 idProduct; */ - 0x00, 0x00, /* u16 bcdDevice */ - - 0x01, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x03, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ +enum { + STR_MANUFACTURER = 1, + STR_PRODUCT, + STR_SERIALNUMBER, }; -static const uint8_t qemu_msd_config_descriptor[] = { +static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, + [STR_PRODUCT] = "QEMU USB HARDDRIVE", + [STR_SERIALNUMBER] = "1", +}; - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x20, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 0x00, /* u8 MaxPower; */ +static const USBDescIface desc_iface0 = { + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = 0x06, /* SCSI */ + .bInterfaceProtocol = 0x50, /* Bulk */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 64, + },{ + .bEndpointAddress = USB_DIR_OUT | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 64, + }, + } +}; - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0x08, /* u8 if_bInterfaceClass; MASS STORAGE */ - 0x06, /* u8 if_bInterfaceSubClass; SCSI */ - 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ - 0x00, /* u8 if_iInterface; */ +static const USBDescDevice desc_device = { + .bcdUSB = 0x0100, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .bmAttributes = 0xc0, + .ifs = &desc_iface0, + }, + }, +}; - /* Bulk-In endpoint */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x02, /* u8 ep_bmAttributes; Bulk */ - 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x00, /* u8 ep_bInterval; */ - - /* Bulk-Out endpoint */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ - 0x02, /* u8 ep_bmAttributes; Bulk */ - 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x00 /* u8 ep_bInterval; */ +static const USBDesc desc = { + .id = { + .idVendor = 0, + .idProduct = 0, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device, + .str = desc_strings, }; static void usb_msd_copy_data(MSDState *s) @@ -236,8 +230,14 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; - int ret = 0; + int ret; + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + ret = 0; switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | @@ -265,48 +265,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, dev->addr = value; ret = 0; break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_msd_dev_descriptor, - sizeof(qemu_msd_dev_descriptor)); - ret = sizeof(qemu_msd_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_msd_config_descriptor, - sizeof(qemu_msd_config_descriptor)); - ret = sizeof(qemu_msd_config_descriptor); - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* vendor description */ - ret = set_usb_string(data, "QEMU " QEMU_VERSION); - break; - case 2: - /* product description */ - ret = set_usb_string(data, "QEMU USB HARDDRIVE"); - break; - case 3: - /* serial number */ - ret = set_usb_string(data, "1"); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; @@ -625,6 +583,7 @@ static struct USBDeviceInfo msd_info = { .product_desc = "QEMU USB MSD", .qdev.name = "usb-storage", .qdev.size = sizeof(MSDState), + .usb_desc = &desc, .init = usb_msd_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_msd_handle_reset, From 037a5203de7b12e2e33a7f71753002ae582ac196 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 25 Nov 2010 16:12:06 +0100 Subject: [PATCH 06/32] usb wacom: use new descriptor infrastructure. Switch the usb wavom driver over to the new descriptor infrastructure. Signed-off-by: Gerd Hoffmann --- hw/usb-wacom.c | 178 ++++++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 105 deletions(-) diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 47f26cd0a3..ffe6ac7b0c 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -28,6 +28,7 @@ #include "hw.h" #include "console.h" #include "usb.h" +#include "usb-desc.h" /* Interface requests */ #define WACOM_GET_REPORT 0x2101 @@ -54,68 +55,75 @@ typedef struct USBWacomState { int changed; } USBWacomState; -static const uint8_t qemu_wacom_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x10, /* u16 bcdUSB; v1.10 */ - - 0x00, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - 0x6a, 0x05, /* u16 idVendor; */ - 0x00, 0x00, /* u16 idProduct; */ - 0x10, 0x42, /* u16 bcdDevice */ - - 0x01, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x00, /* u8 iSerialNumber; */ - 0x01, /* u8 bNumConfigurations; */ +enum { + STR_MANUFACTURER = 1, + STR_PRODUCT, + STR_SERIALNUMBER, }; -static const uint8_t qemu_wacom_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0x80, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 40, /* u8 MaxPower; */ +static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, + [STR_PRODUCT] = "Wacom PenPartner", + [STR_SERIALNUMBER] = "1", +}; - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x03, /* u8 if_bInterfaceClass; HID */ - 0x01, /* u8 if_bInterfaceSubClass; Boot */ - 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* u8 if_iInterface; */ +static const USBDescIface desc_iface_wacom = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0x01, /* boot */ + .bInterfaceProtocol = 0x02, + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + 0x21, /* u8 bDescriptorType */ + 0x01, 0x10, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type: Report */ + 0x6e, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 8, + .bInterval = 0x0a, + }, + }, +}; - /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ - 0x01, 0x10, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 0x6e, 0x00, /* u16 len */ +static const USBDescDevice desc_device_wacom = { + .bcdUSB = 0x0110, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .bmAttributes = 0x80, + .bMaxPower = 40, + .ifs = &desc_iface_wacom, + }, + }, +}; - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; */ +static const USBDesc desc_wacom = { + .id = { + .idVendor = 0x056a, + .idProduct = 0x0000, + .bcdDevice = 0x4210, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_wacom, + .str = desc_strings, }; static void usb_mouse_event(void *opaque, @@ -245,8 +253,14 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { USBWacomState *s = (USBWacomState *) dev; - int ret = 0; + int ret; + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + ret = 0; switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | @@ -274,53 +288,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, dev->addr = value; ret = 0; break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_wacom_dev_descriptor, - sizeof(qemu_wacom_dev_descriptor)); - ret = sizeof(qemu_wacom_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_wacom_config_descriptor, - sizeof(qemu_wacom_config_descriptor)); - ret = sizeof(qemu_wacom_config_descriptor); - break; - case USB_DT_STRING: - switch (value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* serial number */ - ret = set_usb_string(data, "1"); - break; - case 2: - ret = set_usb_string(data, "Wacom PenPartner"); - break; - case 3: - /* vendor description */ - ret = set_usb_string(data, "QEMU " QEMU_VERSION); - break; - case 4: - ret = set_usb_string(data, "Wacom Tablet"); - break; - case 5: - ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; @@ -420,6 +387,7 @@ static struct USBDeviceInfo wacom_info = { .qdev.name = "usb-wacom-tablet", .qdev.desc = "QEMU PenPartner Tablet", .usbdevice_name = "wacom-tablet", + .usb_desc = &desc_wacom, .qdev.size = sizeof(USBWacomState), .init = usb_wacom_initfn, .handle_packet = usb_generic_handle_packet, From 4696425cd05c7baa0a4b469d43ba4b8488bcfc0f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 25 Nov 2010 16:12:18 +0100 Subject: [PATCH 07/32] usb bluetooth: use new descriptor infrastructure. Switch the usb bluetooth driver over to the new descriptor infrastructure. Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 473 ++++++++++++++++++++++------------------------------ 1 file changed, 202 insertions(+), 271 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 56d1a6ce4a..d7959ad9fa 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -20,6 +20,7 @@ #include "qemu-common.h" #include "usb.h" +#include "usb-desc.h" #include "net.h" #include "bt.h" @@ -51,251 +52,202 @@ struct USBBtState { #define USB_ACL_EP 2 #define USB_SCO_EP 3 -static const uint8_t qemu_bt_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - USB_DT_DEVICE, /* u8 bDescriptorType; Device */ - 0x10, 0x01, /* u16 bcdUSB; v1.10 */ - - 0xe0, /* u8 bDeviceClass; Wireless */ - 0x01, /* u8 bDeviceSubClass; Radio Frequency */ - 0x01, /* u8 bDeviceProtocol; Bluetooth */ - 0x40, /* u8 bMaxPacketSize0; 64 Bytes */ - - 0x12, 0x0a, /* u16 idVendor; */ - 0x01, 0x00, /* u16 idProduct; Bluetooth Dongle (HCI mode) */ - 0x58, 0x19, /* u16 bcdDevice; (some devices have 0x48, 0x02) */ - - 0x00, /* u8 iManufacturer; */ - 0x00, /* u8 iProduct; */ - 0x00, /* u8 iSerialNumber; */ - 0x01, /* u8 bNumConfigurations; */ +enum { + STR_MANUFACTURER = 1, + STR_SERIALNUMBER, }; -static const uint8_t qemu_bt_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - USB_DT_CONFIG, /* u8 bDescriptorType; */ - 0xb1, 0x00, /* u16 wTotalLength; */ - 0x02, /* u8 bNumInterfaces; (2) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 0x00, /* u8 MaxPower; */ +static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, + [STR_SERIALNUMBER] = "1", +}; - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ +static const USBDescIface desc_iface_bluetooth[] = { + { + .bInterfaceNumber = 0, + .bNumEndpoints = 3, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | USB_EVT_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x10, + .bInterval = 0x02, + }, + { + .bEndpointAddress = USB_DIR_OUT | USB_ACL_EP, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0x40, + .bInterval = 0x0a, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_ACL_EP, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0x40, + .bInterval = 0x0a, + }, + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0, + .bInterval = 0x01, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0, + .bInterval = 0x01, + }, + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 1, + .bNumEndpoints = 2, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x09, + .bInterval = 0x01, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x09, + .bInterval = 0x01, + }, + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 2, + .bNumEndpoints = 2, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x11, + .bInterval = 0x01, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x11, + .bInterval = 0x01, + }, + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 3, + .bNumEndpoints = 2, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x19, + .bInterval = 0x01, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x19, + .bInterval = 0x01, + }, + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 4, + .bNumEndpoints = 2, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x21, + .bInterval = 0x01, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x21, + .bInterval = 0x01, + }, + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 5, + .bNumEndpoints = 2, + .bInterfaceClass = 0xe0, /* Wireless */ + .bInterfaceSubClass = 0x01, /* Radio Frequency */ + .bInterfaceProtocol = 0x01, /* Bluetooth */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x31, + .bInterval = 0x01, + }, + { + .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0x31, + .bInterval = 0x01, + }, + }, + } +}; - /* interface one */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x03, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ +static const USBDescDevice desc_device_bluetooth = { + .bcdUSB = 0x0110, + .bDeviceClass = 0xe0, /* Wireless */ + .bDeviceSubClass = 0x01, /* Radio Frequency */ + .bDeviceProtocol = 0x01, /* Bluetooth */ + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .bmAttributes = 0xc0, + .bMaxPower = 0, + .nif = ARRAY_SIZE(desc_iface_bluetooth), + .ifs = desc_iface_bluetooth, + }, + }, +}; - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_EVT_EP, /* u8 ep_bEndpointAddress; */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x10, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x02, /* u8 ep_bInterval; */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_ACL_EP, /* u8 ep_bEndpointAddress; */ - 0x02, /* u8 ep_bmAttributes; Bulk */ - 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint three */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_ACL_EP, /* u8 ep_bEndpointAddress; */ - 0x02, /* u8 ep_bmAttributes; Bulk */ - 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* interface two setting one */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x01, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ - - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x00, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x00, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* interface two setting two */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x01, /* u8 if_bInterfaceNumber; */ - 0x01, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ - - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x09, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x09, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* interface two setting three */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x01, /* u8 if_bInterfaceNumber; */ - 0x02, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ - - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x11, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x11, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* interface two setting four */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x01, /* u8 if_bInterfaceNumber; */ - 0x03, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ - - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x19, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x19, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* interface two setting five */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x01, /* u8 if_bInterfaceNumber; */ - 0x04, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ - - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x21, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x21, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* interface two setting six */ - 0x09, /* u8 if_bLength; */ - USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ - 0x01, /* u8 if_bInterfaceNumber; */ - 0x05, /* u8 if_bAlternateSetting; */ - 0x02, /* u8 if_bNumEndpoints; */ - 0xe0, /* u8 if_bInterfaceClass; Wireless */ - 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ - 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ - 0x00, /* u8 if_iInterface; */ - - /* endpoint one */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x31, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* endpoint two */ - 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ - USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ - 0x01, /* u8 ep_bmAttributes; Isochronous */ - 0x31, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ - - /* If implemented, the DFU interface descriptor goes here with no - * endpoints or alternative settings. */ +static const USBDesc desc_bluetooth = { + .id = { + .idVendor = 0x0a12, + .idProduct = 0x0001, + .bcdDevice = 0x1958, + .iManufacturer = STR_MANUFACTURER, + .iProduct = 0, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_bluetooth, + .str = desc_strings, }; static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo) @@ -424,8 +376,14 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { struct USBBtState *s = (struct USBBtState *) dev->opaque; - int ret = 0; + int ret; + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + ret = 0; switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: case InterfaceRequest | USB_REQ_GET_STATUS: @@ -459,42 +417,14 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value, dev->addr = value; ret = 0; break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (value >> 8) { - case USB_DT_DEVICE: - ret = sizeof(qemu_bt_dev_descriptor); - memcpy(data, qemu_bt_dev_descriptor, ret); - break; - case USB_DT_CONFIG: - ret = sizeof(qemu_bt_config_descriptor); - memcpy(data, qemu_bt_config_descriptor, ret); - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = qemu_bt_config_descriptor[0x5]; + data[0] = 1; ret = 1; s->config = 0; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ret = 0; - if (value != qemu_bt_config_descriptor[0x5] && value != 0) { + if (value != 1 && value != 0) { printf("%s: Wrong SET_CONFIGURATION request (%i)\n", __FUNCTION__, value); goto fail; @@ -648,6 +578,7 @@ static struct USBDeviceInfo bt_info = { .product_desc = "QEMU BT dongle", .qdev.name = "usb-bt-dongle", .qdev.size = sizeof(struct USBBtState), + .usb_desc = &desc_bluetooth, .init = usb_bt_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_bt_handle_reset, From 062651c7e750a0c06a693d336c2b9edb893a2c94 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 26 Nov 2010 13:13:22 +0100 Subject: [PATCH 08/32] usb hub: use new descriptor infrastructure. Switch the usb hub driver over to the new descriptor infrastructure. It also removes the nr_ports variable and MAX_PORTS define and introduces a NUM_PORTS define instead. The numver of ports was (and still is) fixed at 8 anyway. Signed-off-by: Gerd Hoffmann --- hw/usb-hub.c | 141 ++++++++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 8a3f829c96..421d43d9d8 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -23,10 +23,11 @@ */ #include "qemu-common.h" #include "usb.h" +#include "usb-desc.h" //#define DEBUG -#define MAX_PORTS 8 +#define NUM_PORTS 8 typedef struct USBHubPort { USBPort port; @@ -36,8 +37,7 @@ typedef struct USBHubPort { typedef struct USBHubState { USBDevice dev; - int nb_ports; - USBHubPort ports[MAX_PORTS]; + USBHubPort ports[NUM_PORTS]; } USBHubState; #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) @@ -83,6 +83,60 @@ typedef struct USBHubState { /* same as Linux kernel root hubs */ +enum { + STR_MANUFACTURER = 1, + STR_PRODUCT, + STR_SERIALNUMBER, +}; + +static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, + [STR_PRODUCT] = "QEMU USB Hub", + [STR_SERIALNUMBER] = "314159", +}; + +static const USBDescIface desc_iface_hub = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HUB, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8, + .bInterval = 0xff, + }, + } +}; + +static const USBDescDevice desc_device_hub = { + .bcdUSB = 0x0110, + .bDeviceClass = USB_CLASS_HUB, + .bMaxPacketSize0 = 8, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .bmAttributes = 0xe0, + .ifs = &desc_iface_hub, + }, + }, +}; + +static const USBDesc desc_hub = { + .id = { + .idVendor = 0, + .idProduct = 0, + .bcdDevice = 0x0101, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_hub, + .str = desc_strings, +}; + static const uint8_t qemu_hub_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ @@ -209,6 +263,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, USBHubState *s = (USBHubState *)dev; int ret; + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + switch(request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | @@ -242,53 +301,6 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, dev->addr = value; ret = 0; break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_hub_dev_descriptor, - sizeof(qemu_hub_dev_descriptor)); - ret = sizeof(qemu_hub_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_hub_config_descriptor, - sizeof(qemu_hub_config_descriptor)); - - /* status change endpoint size based on number - * of ports */ - data[22] = (s->nb_ports + 1 + 7) / 8; - - ret = sizeof(qemu_hub_config_descriptor); - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* serial number */ - ret = set_usb_string(data, "314159"); - break; - case 2: - /* product description */ - ret = set_usb_string(data, "QEMU USB Hub"); - break; - case 3: - /* vendor description */ - ret = set_usb_string(data, "QEMU " QEMU_VERSION); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; @@ -315,8 +327,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, { unsigned int n = index - 1; USBHubPort *port; - if (n >= s->nb_ports) + if (n >= NUM_PORTS) { goto fail; + } port = &s->ports[n]; data[0] = port->wPortStatus; data[1] = port->wPortStatus >> 8; @@ -338,8 +351,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, unsigned int n = index - 1; USBHubPort *port; USBDevice *dev; - if (n >= s->nb_ports) + if (n >= NUM_PORTS) { goto fail; + } port = &s->ports[n]; dev = port->port.dev; switch(value) { @@ -367,8 +381,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, unsigned int n = index - 1; USBHubPort *port; - if (n >= s->nb_ports) + if (n >= NUM_PORTS) { goto fail; + } port = &s->ports[n]; switch(value) { case PORT_ENABLE: @@ -403,17 +418,17 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, unsigned int n, limit, var_hub_size = 0; memcpy(data, qemu_hub_hub_descriptor, sizeof(qemu_hub_hub_descriptor)); - data[2] = s->nb_ports; + data[2] = NUM_PORTS; /* fill DeviceRemovable bits */ - limit = ((s->nb_ports + 1 + 7) / 8) + 7; + limit = ((NUM_PORTS + 1 + 7) / 8) + 7; for (n = 7; n < limit; n++) { data[n] = 0x00; var_hub_size++; } /* fill PortPwrCtrlMask bits */ - limit = limit + ((s->nb_ports + 7) / 8); + limit = limit + ((NUM_PORTS + 7) / 8); for (;n < limit; n++) { data[n] = 0xff; var_hub_size++; @@ -442,14 +457,14 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) USBHubPort *port; unsigned int status; int i, n; - n = (s->nb_ports + 1 + 7) / 8; + n = (NUM_PORTS + 1 + 7) / 8; if (p->len == 1) { /* FreeBSD workaround */ n = 1; } else if (n > p->len) { return USB_RET_BABBLE; } status = 0; - for(i = 0; i < s->nb_ports; i++) { + for(i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; if (port->wPortChange) status |= (1 << (i + 1)); @@ -481,7 +496,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p) USBDevice *dev; int i, ret; - for(i = 0; i < s->nb_ports; i++) { + for(i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; dev = port->port.dev; if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { @@ -518,7 +533,7 @@ static void usb_hub_handle_destroy(USBDevice *dev) USBHubState *s = (USBHubState *)dev; int i; - for (i = 0; i < s->nb_ports; i++) { + for (i = 0; i < NUM_PORTS; i++) { usb_unregister_port(usb_bus_from_device(dev), &s->ports[i].port); } @@ -530,9 +545,8 @@ static int usb_hub_initfn(USBDevice *dev) USBHubPort *port; int i; - s->dev.speed = USB_SPEED_FULL, - s->nb_ports = MAX_PORTS; /* FIXME: make configurable */ - for (i = 0; i < s->nb_ports; i++) { + s->dev.speed = USB_SPEED_FULL; + for (i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; usb_register_port(usb_bus_from_device(dev), &port->port, s, i, &s->dev, usb_hub_attach); @@ -547,6 +561,7 @@ static struct USBDeviceInfo hub_info = { .qdev.name = "usb-hub", .qdev.fw_name = "hub", .qdev.size = sizeof(USBHubState), + .usb_desc = &desc_hub, .init = usb_hub_initfn, .handle_packet = usb_hub_handle_packet, .handle_reset = usb_hub_handle_reset, From 132a3f55f05dff4eedde0d23d844ecdedef8ba68 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 26 Nov 2010 12:25:32 +0100 Subject: [PATCH 09/32] usb descriptors: add settable strings. This patch allows to set usb descriptor strings per device instance. Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 1 + hw/usb-desc.c | 52 +++++++++++++++++++++++++++++++++++++++++++-------- hw/usb-desc.h | 4 +++- hw/usb.h | 9 +++++++++ 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 8b4583c1e6..af537c238f 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -48,6 +48,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc); dev->info = info; dev->auto_attach = 1; + QLIST_INIT(&dev->strings); rc = dev->info->init(dev); if (rc == 0 && dev->auto_attach) usb_device_attach(dev); diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 559ced78b9..69ab207703 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -151,9 +151,42 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) return bLength; } -int usb_desc_string(const char* const *str, int index, uint8_t *dest, size_t len) +/* ------------------------------------------------------------------ */ + +void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) +{ + USBDescString *s; + + QLIST_FOREACH(s, &dev->strings, next) { + if (s->index == index) { + break; + } + } + if (s == NULL) { + s = qemu_mallocz(sizeof(*s)); + s->index = index; + QLIST_INSERT_HEAD(&dev->strings, s, next); + } + qemu_free(s->str); + s->str = qemu_strdup(str); +} + +const char *usb_desc_get_string(USBDevice *dev, uint8_t index) +{ + USBDescString *s; + + QLIST_FOREACH(s, &dev->strings, next) { + if (s->index == index) { + return s->str; + } + } + return NULL; +} + +int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) { uint8_t bLength, pos, i; + const char *str; if (len < 4) { return -1; @@ -168,22 +201,25 @@ int usb_desc_string(const char* const *str, int index, uint8_t *dest, size_t len return 4; } - if (str[index] == NULL) { - return 0; + str = usb_desc_get_string(dev, index); + if (str == NULL) { + str = dev->info->usb_desc->str[index]; + if (str == NULL) { + return 0; + } } - bLength = strlen(str[index]) * 2 + 2; + + bLength = strlen(str) * 2 + 2; dest[0] = bLength; dest[1] = USB_DT_STRING; i = 0; pos = 2; while (pos+1 < bLength && pos+1 < len) { - dest[pos++] = str[index][i++]; + dest[pos++] = str[i++]; dest[pos++] = 0; } return pos; } -/* ------------------------------------------------------------------ */ - int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) { const USBDesc *desc = dev->info->usb_desc; @@ -204,7 +240,7 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len trace_usb_desc_config(dev->addr, index, len, ret); break; case USB_DT_STRING: - ret = usb_desc_string(desc->str, index, buf, sizeof(buf)); + ret = usb_desc_string(dev, index, buf, sizeof(buf)); trace_usb_desc_string(dev->addr, index, len, ret); break; default: diff --git a/hw/usb-desc.h b/hw/usb-desc.h index d80efdb24f..20fc4006c0 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -76,9 +76,11 @@ int usb_desc_config(const USBDescConfig *conf, 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); -int usb_desc_string(const char* const *str, int index, uint8_t *dest, size_t len); /* control message emulation helpers */ +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); diff --git a/hw/usb.h b/hw/usb.h index a29b6d6d8f..7b5c8df0b0 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -135,6 +135,13 @@ typedef struct USBDescConfig USBDescConfig; typedef struct USBDescIface USBDescIface; typedef struct USBDescEndpoint USBDescEndpoint; typedef struct USBDescOther USBDescOther; +typedef struct USBDescString USBDescString; + +struct USBDescString { + uint8_t index; + char *str; + QLIST_ENTRY(USBDescString) next; +}; /* definition of a USB device */ struct USBDevice { @@ -155,6 +162,8 @@ struct USBDevice { int setup_state; int setup_len; int setup_index; + + QLIST_HEAD(, USBDescString) strings; }; struct USBDeviceInfo { From 4a1e1bc416e99254dcc59a689b3806775ae8dabd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 26 Nov 2010 12:26:17 +0100 Subject: [PATCH 10/32] usb storage: serial number support If a serial number is present for the drive fill it into the usb serialnumber string descriptor. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 20ab886747..9aa8888bae 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -482,6 +482,7 @@ static int usb_msd_initfn(USBDevice *dev) { MSDState *s = DO_UPCAST(MSDState, dev, dev); BlockDriverState *bs = s->conf.bs; + DriveInfo *dinfo; if (!bs) { error_report("usb-msd: drive property not set"); @@ -500,6 +501,11 @@ static int usb_msd_initfn(USBDevice *dev) bdrv_detach(bs, &s->dev.qdev); s->conf.bs = NULL; + dinfo = drive_get_by_blockdev(bs); + if (dinfo && dinfo->serial) { + usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial); + } + s->dev.speed = USB_SPEED_FULL; scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete); s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0); From 30c7d32a0a822a9496aee51e7269073311339ed9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 26 Nov 2010 10:25:06 +0100 Subject: [PATCH 11/32] usb network: use new descriptor infrastructure. Switch the usb network driver over to the new descriptor infrastructure. Signed-off-by: Gerd Hoffmann --- hw/usb-net.c | 453 ++++++++++++++++++++++++--------------------------- 1 file changed, 209 insertions(+), 244 deletions(-) diff --git a/hw/usb-net.c b/hw/usb-net.c index 84924550fd..b2fe42ea9b 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -25,6 +25,7 @@ #include "qemu-common.h" #include "usb.h" +#include "usb-desc.h" #include "net.h" #include "qemu-queue.h" #include "sysemu.h" @@ -89,182 +90,209 @@ enum usbstring_idx { #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ -/* - * mostly the same descriptor as the linux gadget rndis driver - */ -static const uint8_t qemu_net_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - USB_DT_DEVICE, /* u8 bDescriptorType; Device */ - 0x00, 0x02, /* u16 bcdUSB; v2.0 */ - USB_CLASS_COMM, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full only ] */ - 0x40, /* u8 bMaxPacketSize0 */ - RNDIS_VENDOR_NUM & 0xff, RNDIS_VENDOR_NUM >> 8, /* u16 idVendor; */ - RNDIS_PRODUCT_NUM & 0xff, RNDIS_PRODUCT_NUM >> 8, /* u16 idProduct; */ - 0x00, 0x00, /* u16 bcdDevice */ - STRING_MANUFACTURER, /* u8 iManufacturer; */ - STRING_PRODUCT, /* u8 iProduct; */ - STRING_SERIALNUMBER, /* u8 iSerialNumber; */ - 0x02, /* u8 bNumConfigurations; */ +static const USBDescStrings usb_net_stringtable = { + [STRING_MANUFACTURER] = "QEMU", + [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device", + [STRING_ETHADDR] = "400102030405", + [STRING_DATA] = "QEMU USB Net Data Interface", + [STRING_CONTROL] = "QEMU USB Net Control Interface", + [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface", + [STRING_CDC] = "QEMU USB Net CDC", + [STRING_SUBSET] = "QEMU USB Net Subset", + [STRING_RNDIS] = "QEMU USB Net RNDIS", + [STRING_SERIALNUMBER] = "1", }; -static const uint8_t qemu_net_rndis_config_descriptor[] = { - /* Configuration Descriptor */ - 0x09, /* u8 bLength */ - USB_DT_CONFIG, /* u8 bDescriptorType */ - 0x43, 0x00, /* le16 wTotalLength */ - 0x02, /* u8 bNumInterfaces */ - DEV_RNDIS_CONFIG_VALUE, /* u8 bConfigurationValue */ - STRING_RNDIS, /* u8 iConfiguration */ - 0xc0, /* u8 bmAttributes */ - 0x32, /* u8 bMaxPower */ - /* RNDIS Control Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x00, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x01, /* u8 bNumEndpoints */ - USB_CLASS_COMM, /* u8 bInterfaceClass */ - USB_CDC_SUBCLASS_ACM, /* u8 bInterfaceSubClass */ - USB_CDC_ACM_PROTO_VENDOR, /* u8 bInterfaceProtocol */ - STRING_RNDIS_CONTROL, /* u8 iInterface */ - /* Header Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ - 0x10, 0x01, /* le16 bcdCDC */ - /* Call Management Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bmCapabilities */ - 0x01, /* u8 bDataInterface */ - /* ACM Descriptor */ - 0x04, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bmCapabilities */ - /* Union Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bMasterInterface0 */ - 0x01, /* u8 bSlaveInterface0 */ - /* Status Descriptor */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 1, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ - STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ - 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ - /* RNDIS Data Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x01, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x02, /* u8 bNumEndpoints */ - USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ - 0x00, /* u8 bInterfaceSubClass */ - 0x00, /* u8 bInterfaceProtocol */ - STRING_DATA, /* u8 iInterface */ - /* Source Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00, /* u8 bInterval */ - /* Sink Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_OUT | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00 /* u8 bInterval */ +static const USBDescIface desc_iface_rndis[] = { + { + /* RNDIS Control Interface */ + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, + .iInterface = STRING_RNDIS_CONTROL, + .ndesc = 4, + .descs = (USBDescOther[]) { + { + /* Header Descriptor */ + .data = (uint8_t[]) { + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ + 0x10, 0x01, /* le16 bcdCDC */ + }, + },{ + /* Call Management Descriptor */ + .data = (uint8_t[]) { + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bmCapabilities */ + 0x01, /* u8 bDataInterface */ + }, + },{ + /* ACM Descriptor */ + .data = (uint8_t[]) { + 0x04, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bmCapabilities */ + }, + },{ + /* Union Descriptor */ + .data = (uint8_t[]) { + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bMasterInterface0 */ + 0x01, /* u8 bSlaveInterface0 */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = STATUS_BYTECOUNT, + .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + }, + } + },{ + /* RNDIS Data Interface */ + .bInterfaceNumber = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .iInterface = STRING_DATA, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0x40, + },{ + .bEndpointAddress = USB_DIR_OUT | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0x40, + } + } + } }; -static const uint8_t qemu_net_cdc_config_descriptor[] = { - /* Configuration Descriptor */ - 0x09, /* u8 bLength */ - USB_DT_CONFIG, /* u8 bDescriptorType */ - 0x50, 0x00, /* le16 wTotalLength */ - 0x02, /* u8 bNumInterfaces */ - DEV_CONFIG_VALUE, /* u8 bConfigurationValue */ - STRING_CDC, /* u8 iConfiguration */ - 0xc0, /* u8 bmAttributes */ - 0x32, /* u8 bMaxPower */ - /* CDC Control Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x00, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x01, /* u8 bNumEndpoints */ - USB_CLASS_COMM, /* u8 bInterfaceClass */ - USB_CDC_SUBCLASS_ETHERNET, /* u8 bInterfaceSubClass */ - USB_CDC_PROTO_NONE, /* u8 bInterfaceProtocol */ - STRING_CONTROL, /* u8 iInterface */ - /* Header Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ - 0x10, 0x01, /* le16 bcdCDC */ - /* Union Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bMasterInterface0 */ - 0x01, /* u8 bSlaveInterface0 */ - /* Ethernet Descriptor */ - 0x0d, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */ - STRING_ETHADDR, /* u8 iMACAddress */ - 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */ - ETH_FRAME_LEN & 0xff, ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */ - 0x00, 0x00, /* le16 wNumberMCFilters */ - 0x00, /* u8 bNumberPowerFilters */ - /* Status Descriptor */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 1, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ - STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ - 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ - /* CDC Data (nop) Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x01, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x00, /* u8 bNumEndpoints */ - USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ - 0x00, /* u8 bInterfaceSubClass */ - 0x00, /* u8 bInterfaceProtocol */ - 0x00, /* u8 iInterface */ - /* CDC Data Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x01, /* u8 bInterfaceNumber */ - 0x01, /* u8 bAlternateSetting */ - 0x02, /* u8 bNumEndpoints */ - USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ - 0x00, /* u8 bInterfaceSubClass */ - 0x00, /* u8 bInterfaceProtocol */ - STRING_DATA, /* u8 iInterface */ - /* Source Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00, /* u8 bInterval */ - /* Sink Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_OUT | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00 /* u8 bInterval */ +static const USBDescIface desc_iface_cdc[] = { + { + /* CDC Control Interface */ + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .iInterface = STRING_CONTROL, + .ndesc = 3, + .descs = (USBDescOther[]) { + { + /* Header Descriptor */ + .data = (uint8_t[]) { + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ + 0x10, 0x01, /* le16 bcdCDC */ + }, + },{ + /* Union Descriptor */ + .data = (uint8_t[]) { + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bMasterInterface0 */ + 0x01, /* u8 bSlaveInterface0 */ + }, + },{ + /* Ethernet Descriptor */ + .data = (uint8_t[]) { + 0x0d, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */ + STRING_ETHADDR, /* u8 iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */ + ETH_FRAME_LEN & 0xff, + ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */ + 0x00, 0x00, /* le16 wNumberMCFilters */ + 0x00, /* u8 bNumberPowerFilters */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = STATUS_BYTECOUNT, + .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + }, + } + },{ + /* CDC Data Interface (off) */ + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_CDC_DATA, + },{ + /* CDC Data Interface */ + .bInterfaceNumber = 1, + .bAlternateSetting = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .iInterface = STRING_DATA, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0x40, + },{ + .bEndpointAddress = USB_DIR_OUT | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0x40, + } + } + } +}; + +static const USBDescDevice desc_device_net = { + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_COMM, + .bMaxPacketSize0 = 0x40, + .bNumConfigurations = 2, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 2, + .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE, + .iConfiguration = STRING_RNDIS, + .bmAttributes = 0xc0, + .bMaxPower = 0x32, + .nif = ARRAY_SIZE(desc_iface_rndis), + .ifs = desc_iface_rndis, + },{ + .bNumInterfaces = 2, + .bConfigurationValue = DEV_CONFIG_VALUE, + .iConfiguration = STRING_CDC, + .bmAttributes = 0xc0, + .bMaxPower = 0x32, + .nif = ARRAY_SIZE(desc_iface_cdc), + .ifs = desc_iface_cdc, + } + }, +}; + +static const USBDesc desc_net = { + .id = { + .idVendor = RNDIS_VENDOR_NUM, + .idProduct = RNDIS_PRODUCT_NUM, + .bcdDevice = 0, + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIALNUMBER, + }, + .full = &desc_device_net, + .str = usb_net_stringtable, }; /* @@ -1010,25 +1038,18 @@ static void usb_net_handle_reset(USBDevice *dev) { } -static const char * const usb_net_stringtable[] = { - [STRING_MANUFACTURER] = "QEMU", - [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device", - [STRING_ETHADDR] = "400102030405", - [STRING_DATA] = "QEMU USB Net Data Interface", - [STRING_CONTROL] = "QEMU USB Net Control Interface", - [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface", - [STRING_CDC] = "QEMU USB Net CDC", - [STRING_SUBSET] = "QEMU USB Net Subset", - [STRING_RNDIS] = "QEMU USB Net RNDIS", - [STRING_SERIALNUMBER] = "1", -}; - static int usb_net_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { USBNetState *s = (USBNetState *) dev; - int ret = 0; + int ret; + ret = usb_desc_handle_control(dev, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + ret = 0; switch(request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | @@ -1100,64 +1121,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, #endif break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - ret = sizeof(qemu_net_dev_descriptor); - memcpy(data, qemu_net_dev_descriptor, ret); - break; - - case USB_DT_CONFIG: - switch (value & 0xff) { - case 0: - ret = sizeof(qemu_net_rndis_config_descriptor); - memcpy(data, qemu_net_rndis_config_descriptor, ret); - break; - - case 1: - ret = sizeof(qemu_net_cdc_config_descriptor); - memcpy(data, qemu_net_cdc_config_descriptor, ret); - break; - - default: - goto fail; - } - - data[2] = ret & 0xff; - data[3] = ret >> 8; - break; - - case USB_DT_STRING: - switch (value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - - case STRING_ETHADDR: - ret = set_usb_string(data, s->usbstring_mac); - break; - - default: - if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) { - ret = set_usb_string(data, - usb_net_stringtable[value & 0xff]); - break; - } - - goto fail; - } - break; - - default: - goto fail; - } - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE; ret = 1; @@ -1463,6 +1426,7 @@ static int usb_net_initfn(USBDevice *dev) s->conf.macaddr.a[3], s->conf.macaddr.a[4], s->conf.macaddr.a[5]); + usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac); add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet@0"); return 0; @@ -1500,6 +1464,7 @@ static struct USBDeviceInfo net_info = { .qdev.name = "usb-net", .qdev.fw_name = "network", .qdev.size = sizeof(USBNetState), + .usb_desc = &desc_net, .init = usb_net_initfn, .handle_packet = usb_generic_handle_packet, .handle_reset = usb_net_handle_reset, From 41c6abbdeb5a86a135ee80a30541ecf52ffd3e23 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 26 Nov 2010 12:35:10 +0100 Subject: [PATCH 12/32] usb: move USB_REQ_SET_ADDRESS handling to common code USB_REQ_SET_ADDRESS handling is identical in *all* emulated devices. Move it to common code. Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 4 ---- hw/usb-desc.c | 6 ++++++ hw/usb-hid.c | 4 ---- hw/usb-hub.c | 4 ---- hw/usb-msd.c | 4 ---- hw/usb-net.c | 5 ----- hw/usb-serial.c | 4 ---- hw/usb-wacom.c | 4 ---- trace-events | 1 + 9 files changed, 7 insertions(+), 29 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index d7959ad9fa..c0bfc352fb 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -413,10 +413,6 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 69ab207703..3e87f46d7b 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -266,6 +266,12 @@ int usb_desc_handle_control(USBDevice *dev, int request, int value, assert(desc != NULL); switch(request) { + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + trace_usb_set_addr(dev->addr); + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: ret = usb_desc_get_descriptor(dev, value, data, length); break; diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 74d17fc26f..72daddfe7d 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -695,10 +695,6 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 421d43d9d8..1d321acaeb 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -297,10 +297,6 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 9aa8888bae..b54ccbc599 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -261,10 +261,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; diff --git a/hw/usb-net.c b/hw/usb-net.c index b2fe42ea9b..141d7491f7 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1076,11 +1076,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; - case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: if (!s->rndis || value || index != 0) goto fail; diff --git a/hw/usb-serial.c b/hw/usb-serial.c index f89eb9b3a3..c1f31c76d3 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -254,10 +254,6 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index ffe6ac7b0c..ad1c3aef3d 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -284,10 +284,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; diff --git a/trace-events b/trace-events index 8264ff0e77..7948c6c175 100644 --- a/trace-events +++ b/trace-events @@ -194,6 +194,7 @@ disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64"" disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" +disable usb_set_addr(int addr) "dev %d" # vl.c disable vm_state_notify(int running, int reason) "running %d reason %d" From a980a065fb5e86d6dec337e6cb6ff432f1a143c9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 26 Nov 2010 20:20:41 +0100 Subject: [PATCH 13/32] usb: move USB_REQ_{GET,SET}_CONFIGURATION handling to common code This patch adds fields to the USBDevice struct for the current speed (hard-wired to full speed for now) and current device configuration. Also a init function is added which inializes these fields. This allows USB_REQ_{GET,SET}_CONFIGURATION handling to be moved to common code. For most drivers the conversion is trivial ad they support a single configuration only anyway. One exception is bluetooth where some device-specific setup code runs after get/set configuration. The other is usb-net which actually has two configurations so the the code to check for the active configuration has been adapted. Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 31 ++++++++++++------------------- hw/usb-desc.c | 32 ++++++++++++++++++++++++++++---- hw/usb-desc.h | 1 + hw/usb-hid.c | 10 ++-------- hw/usb-hub.c | 9 +-------- hw/usb-msd.c | 9 +-------- hw/usb-net.c | 45 +++++++++++++++------------------------------ hw/usb-serial.c | 10 ++-------- hw/usb-wacom.c | 9 +-------- hw/usb.h | 2 ++ trace-events | 1 + 11 files changed, 66 insertions(+), 93 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index c0bfc352fb..36c90a35cf 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -380,6 +380,17 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value, ret = usb_desc_handle_control(dev, request, value, index, length, data); if (ret >= 0) { + switch (request) { + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + s->config = 0; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + s->config = 1; + usb_bt_fifo_reset(&s->evt); + usb_bt_fifo_reset(&s->acl); + usb_bt_fifo_reset(&s->sco); + break; + } return ret; } @@ -413,23 +424,6 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - s->config = 0; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - if (value != 1 && value != 0) { - printf("%s: Wrong SET_CONFIGURATION request (%i)\n", - __FUNCTION__, value); - goto fail; - } - s->config = 1; - usb_bt_fifo_reset(&s->evt); - usb_bt_fifo_reset(&s->acl); - usb_bt_fifo_reset(&s->sco); - break; case InterfaceRequest | USB_REQ_GET_INTERFACE: if (value != 0 || (index & ~1) || length != 1) goto fail; @@ -544,8 +538,7 @@ static void usb_bt_handle_destroy(USBDevice *dev) static int usb_bt_initfn(USBDevice *dev) { - struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev); - s->dev.speed = USB_SPEED_HIGH; + usb_desc_init(dev); return 0; } diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 3e87f46d7b..14c9e112ce 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -153,6 +153,16 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) /* ------------------------------------------------------------------ */ +void usb_desc_init(USBDevice *dev) +{ + const USBDesc *desc = dev->info->usb_desc; + + assert(desc != NULL); + dev->speed = USB_SPEED_FULL; + dev->device = desc->full; + dev->config = dev->device->confs; +} + void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) { USBDescString *s; @@ -230,12 +240,12 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len switch(type) { case USB_DT_DEVICE: - ret = usb_desc_device(&desc->id, desc->full, buf, sizeof(buf)); + ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); trace_usb_desc_device(dev->addr, len, ret); break; case USB_DT_CONFIG: - if (index < desc->full->bNumConfigurations) { - ret = usb_desc_config(desc->full->confs + index, buf, sizeof(buf)); + if (index < dev->device->bNumConfigurations) { + ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); } trace_usb_desc_config(dev->addr, index, len, ret); break; @@ -262,7 +272,7 @@ int usb_desc_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { const USBDesc *desc = dev->info->usb_desc; - int ret = -1; + int i, ret = -1; assert(desc != NULL); switch(request) { @@ -275,6 +285,20 @@ int usb_desc_handle_control(USBDevice *dev, int request, int value, case DeviceRequest | USB_REQ_GET_DESCRIPTOR: ret = usb_desc_get_descriptor(dev, value, data, length); break; + + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = dev->config->bConfigurationValue; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + for (i = 0; i < dev->device->bNumConfigurations; i++) { + if (dev->device->confs[i].bConfigurationValue == value) { + dev->config = dev->device->confs + i; + ret = 0; + } + } + trace_usb_set_config(dev->addr, value, ret); + break; } return ret; } diff --git a/hw/usb-desc.h b/hw/usb-desc.h index 20fc4006c0..d441725355 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -78,6 +78,7 @@ 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); /* control message emulation helpers */ +void usb_desc_init(USBDevice *dev); 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); diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 72daddfe7d..21c0c7224c 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -695,13 +695,6 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -822,7 +815,8 @@ static void usb_hid_handle_destroy(USBDevice *dev) static int usb_hid_initfn(USBDevice *dev, int kind) { USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev); - s->dev.speed = USB_SPEED_FULL; + + usb_desc_init(dev); s->kind = kind; if (s->kind == USB_MOUSE) { diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 1d321acaeb..fc0b94b20e 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -297,13 +297,6 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -541,7 +534,7 @@ static int usb_hub_initfn(USBDevice *dev) USBHubPort *port; int i; - s->dev.speed = USB_SPEED_FULL; + usb_desc_init(dev); for (i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; usb_register_port(usb_bus_from_device(dev), diff --git a/hw/usb-msd.c b/hw/usb-msd.c index b54ccbc599..56c6f3dcf2 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -261,13 +261,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -502,7 +495,7 @@ static int usb_msd_initfn(USBDevice *dev) usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial); } - s->dev.speed = USB_SPEED_FULL; + usb_desc_init(dev); scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete); s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0); if (!s->scsi_dev) { diff --git a/hw/usb-net.c b/hw/usb-net.c index 141d7491f7..f12304590b 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -627,7 +627,6 @@ struct rndis_response { typedef struct USBNetState { USBDevice dev; - unsigned int rndis; enum rndis_state rndis_state; uint32_t medium; uint32_t speed; @@ -648,6 +647,11 @@ typedef struct USBNetState { QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp; } USBNetState; +static int is_rndis(USBNetState *s) +{ + return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE; +} + static int ndis_query(USBNetState *s, uint32_t oid, uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf, size_t outlen) @@ -1077,8 +1081,9 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, break; case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: - if (!s->rndis || value || index != 0) + if (!is_rndis(s) || value || index != 0) { goto fail; + } #ifdef TRAFFIC_DEBUG { unsigned int i; @@ -1095,8 +1100,9 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, break; case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE: - if (!s->rndis || value || index != 0) + if (!is_rndis(s) || value || index != 0) { goto fail; + } ret = rndis_get_response(s, data); if (!ret) { data[0] = 0; @@ -1116,27 +1122,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, #endif break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE; - ret = 1; - break; - - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - switch (value & 0xff) { - case DEV_CONFIG_VALUE: - s->rndis = 0; - break; - - case DEV_RNDIS_CONFIG_VALUE: - s->rndis = 1; - break; - - default: - goto fail; - } - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: case InterfaceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; @@ -1207,7 +1192,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) memcpy(p->data, &s->in_buf[s->in_ptr], ret); s->in_ptr += ret; if (s->in_ptr >= s->in_len && - (s->rndis || (s->in_len & (64 - 1)) || !ret)) { + (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { /* no short packet necessary */ s->in_ptr = s->in_len = 0; } @@ -1256,7 +1241,7 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) memcpy(&s->out_buf[s->out_ptr], p->data, sz); s->out_ptr += sz; - if (!s->rndis) { + if (!is_rndis(s)) { if (ret < 64) { qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr); s->out_ptr = 0; @@ -1327,7 +1312,7 @@ static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t si USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; struct rndis_packet_msg_type *msg; - if (s->rndis) { + if (is_rndis(s)) { msg = (struct rndis_packet_msg_type *) s->in_buf; if (!s->rndis_state == RNDIS_DATA_INITIALIZED) return -1; @@ -1363,8 +1348,9 @@ static int usbnet_can_receive(VLANClientState *nc) { USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED) + if (is_rndis(s) && !s->rndis_state == RNDIS_DATA_INITIALIZED) { return 1; + } return !s->in_len; } @@ -1397,9 +1383,8 @@ static int usb_net_initfn(USBDevice *dev) { USBNetState *s = DO_UPCAST(USBNetState, dev, dev); - s->dev.speed = USB_SPEED_FULL; + usb_desc_init(dev); - s->rndis = 1; s->rndis_state = RNDIS_UNINITIALIZED; QTAILQ_INIT(&s->rndis_resp); diff --git a/hw/usb-serial.c b/hw/usb-serial.c index c1f31c76d3..2bdb10b8fe 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -254,13 +254,6 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -507,7 +500,8 @@ 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; + + usb_desc_init(dev); if (!s->cs) { error_report("Property chardev is required"); diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index ad1c3aef3d..3a98e8066f 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -284,13 +284,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -373,7 +366,7 @@ static void usb_wacom_handle_destroy(USBDevice *dev) static int usb_wacom_initfn(USBDevice *dev) { USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev); - s->dev.speed = USB_SPEED_FULL; + usb_desc_init(dev); s->changed = 1; return 0; } diff --git a/hw/usb.h b/hw/usb.h index 7b5c8df0b0..966d47e5ee 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -164,6 +164,8 @@ struct USBDevice { int setup_index; QLIST_HEAD(, USBDescString) strings; + const USBDescDevice *device; + const USBDescConfig *config; }; struct USBDeviceInfo { diff --git a/trace-events b/trace-events index 7948c6c175..9ef84747a0 100644 --- a/trace-events +++ b/trace-events @@ -195,6 +195,7 @@ disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" disable usb_set_addr(int addr) "dev %d" +disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d" # vl.c disable vm_state_notify(int running, int reason) "running %d reason %d" From ed5a83ddd8c1d8ec7b1015315530cf29949e7c48 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 30 Nov 2010 17:35:34 +0100 Subject: [PATCH 14/32] usb: move remote wakeup handling to common code This patch moves setting and clearing the remote_wakeup feature bit (via USB_REQ_{SET,CLEAR}_FEATURE) to common code. Also USB_REQ_GET_STATUS handling is moved to common code. Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 21 +++------------------ hw/usb-desc.c | 26 ++++++++++++++++++++++++++ hw/usb-hid.c | 22 ---------------------- hw/usb-hub.c | 22 ---------------------- hw/usb-msd.c | 23 ----------------------- hw/usb-net.c | 25 ------------------------- hw/usb-serial.c | 22 ---------------------- hw/usb-wacom.c | 23 ----------------------- trace-events | 2 ++ 9 files changed, 31 insertions(+), 155 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 36c90a35cf..22e6845049 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -396,33 +396,18 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_STATUS: case InterfaceRequest | USB_REQ_GET_STATUS: case EndpointRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[0] = 0x00; data[1] = 0x00; ret = 2; break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: + goto fail; case InterfaceOutRequest | USB_REQ_SET_FEATURE: case EndpointOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; + goto fail; break; case InterfaceRequest | USB_REQ_GET_INTERFACE: if (value != 0 || (index & ~1) || length != 1) diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 14c9e112ce..56ef734bde 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -299,6 +299,32 @@ int usb_desc_handle_control(USBDevice *dev, int request, int value, } trace_usb_set_config(dev->addr, value, ret); break; + + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = 0; + if (dev->config->bmAttributes & 0x40) { + data[0] |= 1 << USB_DEVICE_SELF_POWERED; + } + if (dev->remote_wakeup) { + data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; + } + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + ret = 0; + } + trace_usb_clear_device_feature(dev->addr, value, ret); + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + ret = 0; + } + trace_usb_set_device_feature(dev->addr, value, ret); + break; } return ret; } diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 21c0c7224c..1c3596025f 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -673,28 +673,6 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, ret = 0; switch(request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index fc0b94b20e..3c7c3eee43 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -269,34 +269,12 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } switch(request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: if (value == 0 && index != 0x81) { /* clear ep halt */ goto fail; } ret = 0; break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 56c6f3dcf2..74e657e7f9 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -239,28 +239,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -285,7 +263,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, ret = 1; break; default: - fail: ret = USB_RET_STALL; break; } diff --git a/hw/usb-net.c b/hw/usb-net.c index f12304590b..bf51bb3890 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1055,31 +1055,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, ret = 0; switch(request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; - case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: if (!is_rndis(s) || value || index != 0) { goto fail; diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 2bdb10b8fe..6763d52040 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -232,28 +232,6 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (0 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 3a98e8066f..16be7a20cf 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -262,28 +262,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -320,7 +298,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, ret = 0; break; default: - fail: ret = USB_RET_STALL; break; } diff --git a/trace-events b/trace-events index 9ef84747a0..45e75828dc 100644 --- a/trace-events +++ b/trace-events @@ -196,6 +196,8 @@ disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query con disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" disable usb_set_addr(int addr) "dev %d" disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d" +disable usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d" +disable usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d" # vl.c disable vm_state_notify(int running, int reason) "running %d reason %d" From 0d86d2bebb625a222f70b76972139f6a272e3e0b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Dec 2010 11:08:44 +0100 Subject: [PATCH 15/32] usb: create USBPortOps, move attach there. Create USBPortOps struct, move the attach function to that struct. Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 6 ++++-- hw/usb-hub.c | 6 +++++- hw/usb-musb.c | 6 +++++- hw/usb-ohci.c | 6 +++++- hw/usb-uhci.c | 6 +++++- hw/usb.c | 2 +- hw/usb.h | 8 +++++--- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index af537c238f..9dc8793148 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -113,12 +113,14 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) } void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBDevice *pdev, usb_attachfn attach) + USBDevice *pdev, USBPortOps *ops) { port->opaque = opaque; port->index = index; - port->attach = attach; port->pdev = pdev; + port->opaque = opaque; + port->index = index; + port->ops = ops; QTAILQ_INSERT_TAIL(&bus->free, port, next); bus->nfree++; } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 3c7c3eee43..b3d72987f3 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -506,6 +506,10 @@ static void usb_hub_handle_destroy(USBDevice *dev) } } +static USBPortOps usb_hub_port_ops = { + .attach = usb_hub_attach, +}; + static int usb_hub_initfn(USBDevice *dev) { USBHubState *s = DO_UPCAST(USBHubState, dev, dev); @@ -516,7 +520,7 @@ static int usb_hub_initfn(USBDevice *dev) for (i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; usb_register_port(usb_bus_from_device(dev), - &port->port, s, i, &s->dev, usb_hub_attach); + &port->port, s, i, &s->dev, &usb_hub_port_ops); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; } diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 9efe7a6344..592d3e67f4 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -261,6 +261,10 @@ static void musb_attach(USBPort *port, USBDevice *dev); +static USBPortOps musb_port_ops = { + .attach = musb_attach, +}; + typedef struct { uint16_t faddr[2]; uint8_t haddr[2]; @@ -343,7 +347,7 @@ struct MUSBState { } usb_bus_new(&s->bus, NULL /* FIXME */); - usb_register_port(&s->bus, &s->port, s, 0, NULL, musb_attach); + usb_register_port(&s->bus, &s->port, s, 0, NULL, &musb_port_ops); return s; } diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 240e8409af..7b13bdd0d3 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1669,6 +1669,10 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={ ohci_mem_write }; +static USBPortOps ohci_port_ops = { + .attach = ohci_attach, +}; + static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, int num_ports, uint32_t localmem_base) { @@ -1699,7 +1703,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, usb_bus_new(&ohci->bus, dev); ohci->num_ports = num_ports; for (i = 0; i < num_ports; i++) { - usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, ohci_attach); + usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, &ohci_port_ops); } ohci->async_td = 0; diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index b9b822fcb1..0f9ef1edc3 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1101,6 +1101,10 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } +static USBPortOps uhci_port_ops = { + .attach = uhci_attach, +}; + static int usb_uhci_common_initfn(UHCIState *s) { uint8_t *pci_conf = s->dev.config; @@ -1115,7 +1119,7 @@ static int usb_uhci_common_initfn(UHCIState *s) usb_bus_new(&s->bus, &s->dev.qdev); for(i = 0; i < NB_PORTS; i++) { - usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, uhci_attach); + usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, &uhci_port_ops); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); s->expire_time = qemu_get_clock(vm_clock) + diff --git a/hw/usb.c b/hw/usb.c index a326bcfffe..39d29f3daf 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -28,7 +28,7 @@ void usb_attach(USBPort *port, USBDevice *dev) { - port->attach(port, dev); + port->ops->attach(port, dev); } /**********************/ diff --git a/hw/usb.h b/hw/usb.h index 966d47e5ee..218788fceb 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -216,12 +216,14 @@ struct USBDeviceInfo { USBDevice *(*usbdevice_init)(const char *params); }; -typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); +typedef struct USBPortOps { + void (*attach)(USBPort *port, USBDevice *dev); +} USBPortOps; /* USB port on which a device can be connected */ struct USBPort { USBDevice *dev; - usb_attachfn attach; + USBPortOps *ops; void *opaque; USBDevice *pdev; int index; /* internal port index, may be used with the opaque */ @@ -333,7 +335,7 @@ USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBDevice *pdev, usb_attachfn attach); + USBDevice *pdev, USBPortOps *ops); void usb_unregister_port(USBBus *bus, USBPort *port); int usb_device_attach(USBDevice *dev); int usb_device_detach(USBDevice *dev); From 618c169b577db64ac6589ad48825d2e11760d1a6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Dec 2010 11:27:05 +0100 Subject: [PATCH 16/32] usb: rework attach/detach workflow Add separate detach callback to USBPortOps, split uhci/ohci/musb/usbhub attach functions into two. Move common code to the usb_attach() function, only the hardware-specific bits remain in the attach/detach callbacks. Keep track of the port it is attached to for each usb device. [ v3: fix tyops in usb-musb.c ] Signed-off-by: Gerd Hoffmann --- hw/usb-hub.c | 46 +++++++++++++---------------- hw/usb-musb.c | 36 ++++++++--------------- hw/usb-ohci.c | 80 ++++++++++++++++++++++++--------------------------- hw/usb-uhci.c | 73 +++++++++++++++++++++------------------------- hw/usb.c | 20 ++++++++++++- hw/usb.h | 4 ++- 6 files changed, 124 insertions(+), 135 deletions(-) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index b3d72987f3..8837bd9efe 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -218,37 +218,30 @@ static const uint8_t qemu_hub_hub_descriptor[] = /* DeviceRemovable and PortPwrCtrlMask patched in later */ }; -static void usb_hub_attach(USBPort *port1, USBDevice *dev) +static void usb_hub_attach(USBPort *port1) { USBHubState *s = port1->opaque; USBHubPort *port = &s->ports[port1->index]; - if (dev) { - if (port->port.dev) - usb_attach(port1, NULL); - - port->wPortStatus |= PORT_STAT_CONNECTION; - port->wPortChange |= PORT_STAT_C_CONNECTION; - if (dev->speed == USB_SPEED_LOW) - port->wPortStatus |= PORT_STAT_LOW_SPEED; - else - port->wPortStatus &= ~PORT_STAT_LOW_SPEED; - port->port.dev = dev; - /* send the attach message */ - usb_send_msg(dev, USB_MSG_ATTACH); + port->wPortStatus |= PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (port->port.dev->speed == USB_SPEED_LOW) { + port->wPortStatus |= PORT_STAT_LOW_SPEED; } else { - dev = port->port.dev; - if (dev) { - port->wPortStatus &= ~PORT_STAT_CONNECTION; - port->wPortChange |= PORT_STAT_C_CONNECTION; - if (port->wPortStatus & PORT_STAT_ENABLE) { - port->wPortStatus &= ~PORT_STAT_ENABLE; - port->wPortChange |= PORT_STAT_C_ENABLE; - } - /* send the detach message */ - usb_send_msg(dev, USB_MSG_DETACH); - port->port.dev = NULL; - } + port->wPortStatus &= ~PORT_STAT_LOW_SPEED; + } +} + +static void usb_hub_detach(USBPort *port1) +{ + USBHubState *s = port1->opaque; + USBHubPort *port = &s->ports[port1->index]; + + port->wPortStatus &= ~PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (port->wPortStatus & PORT_STAT_ENABLE) { + port->wPortStatus &= ~PORT_STAT_ENABLE; + port->wPortChange |= PORT_STAT_C_ENABLE; } } @@ -508,6 +501,7 @@ static void usb_hub_handle_destroy(USBDevice *dev) static USBPortOps usb_hub_port_ops = { .attach = usb_hub_attach, + .detach = usb_hub_detach, }; static int usb_hub_initfn(USBDevice *dev) diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 592d3e67f4..233a2657c0 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -259,10 +259,12 @@ #endif -static void musb_attach(USBPort *port, USBDevice *dev); +static void musb_attach(USBPort *port); +static void musb_detach(USBPort *port); static USBPortOps musb_port_ops = { .attach = musb_attach, + .detach = musb_detach, }; typedef struct { @@ -464,34 +466,20 @@ static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess) } /* Attach or detach a device on our only port. */ -static void musb_attach(USBPort *port, USBDevice *dev) +static void musb_attach(USBPort *port) { MUSBState *s = (MUSBState *) port->opaque; - USBDevice *curr; - port = &s->port; - curr = port->dev; + musb_intr_set(s, musb_irq_vbus_request, 1); + musb_session_update(s, 0, s->session); +} - if (dev) { - if (curr) { - usb_attach(port, NULL); - /* TODO: signal some interrupts */ - } +static void musb_detach(USBPort *port) +{ + MUSBState *s = (MUSBState *) port->opaque; - musb_intr_set(s, musb_irq_vbus_request, 1); - - /* Send the attach message to device */ - usb_send_msg(dev, USB_MSG_ATTACH); - } else if (curr) { - /* Send the detach message */ - usb_send_msg(curr, USB_MSG_DETACH); - - musb_intr_set(s, musb_irq_disconnect, 1); - } - - port->dev = dev; - - musb_session_update(s, !!curr, s->session); + musb_intr_set(s, musb_irq_disconnect, 1); + musb_session_update(s, 1, s->session); } static inline void musb_cb_tick0(void *opaque) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 7b13bdd0d3..c859540c19 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -322,52 +322,46 @@ static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) } /* Attach or detach a device on a root hub port. */ -static void ohci_attach(USBPort *port1, USBDevice *dev) +static void ohci_attach(USBPort *port1) +{ + OHCIState *s = port1->opaque; + OHCIPort *port = &s->rhport[port1->index]; + + /* set connect status */ + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + + /* update speed */ + if (port->port.dev->speed == USB_SPEED_LOW) { + port->ctrl |= OHCI_PORT_LSDA; + } else { + port->ctrl &= ~OHCI_PORT_LSDA; + } + + /* notify of remote-wakeup */ + if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { + ohci_set_interrupt(s, OHCI_INTR_RD); + } + + DPRINTF("usb-ohci: Attached port %d\n", port1->index); +} + +static void ohci_detach(USBPort *port1) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; uint32_t old_state = port->ctrl; - if (dev) { - if (port->port.dev) { - usb_attach(port1, NULL); - } - /* set connect status */ - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; - - /* update speed */ - if (dev->speed == USB_SPEED_LOW) - port->ctrl |= OHCI_PORT_LSDA; - else - port->ctrl &= ~OHCI_PORT_LSDA; - port->port.dev = dev; - - /* notify of remote-wakeup */ - if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) - ohci_set_interrupt(s, OHCI_INTR_RD); - - /* send the attach message */ - usb_send_msg(dev, USB_MSG_ATTACH); - DPRINTF("usb-ohci: Attached port %d\n", port1->index); - } else { - /* set connect status */ - if (port->ctrl & OHCI_PORT_CCS) { - port->ctrl &= ~OHCI_PORT_CCS; - port->ctrl |= OHCI_PORT_CSC; - } - /* disable port */ - if (port->ctrl & OHCI_PORT_PES) { - port->ctrl &= ~OHCI_PORT_PES; - port->ctrl |= OHCI_PORT_PESC; - } - dev = port->port.dev; - if (dev) { - /* send the detach message */ - usb_send_msg(dev, USB_MSG_DETACH); - } - port->port.dev = NULL; - DPRINTF("usb-ohci: Detached port %d\n", port1->index); + /* set connect status */ + if (port->ctrl & OHCI_PORT_CCS) { + port->ctrl &= ~OHCI_PORT_CCS; + port->ctrl |= OHCI_PORT_CSC; } + /* disable port */ + if (port->ctrl & OHCI_PORT_PES) { + port->ctrl &= ~OHCI_PORT_PES; + port->ctrl |= OHCI_PORT_PESC; + } + DPRINTF("usb-ohci: Detached port %d\n", port1->index); if (old_state != port->ctrl) ohci_set_interrupt(s, OHCI_INTR_RHSC); @@ -413,8 +407,9 @@ static void ohci_reset(void *opaque) { port = &ohci->rhport[i]; port->ctrl = 0; - if (port->port.dev) - ohci_attach(&port->port, port->port.dev); + if (port->port.dev) { + usb_attach(&port->port, port->port.dev); + } } if (ohci->async_td) { usb_cancel_packet(&ohci->usb_packet); @@ -1671,6 +1666,7 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={ static USBPortOps ohci_port_ops = { .attach = ohci_attach, + .detach = ohci_detach, }; static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 0f9ef1edc3..5e2e34a51c 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -307,8 +307,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token return match; } -static void uhci_attach(USBPort *port1, USBDevice *dev); - static void uhci_update_irq(UHCIState *s) { int level; @@ -348,8 +346,9 @@ static void uhci_reset(void *opaque) for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; port->ctrl = 0x0080; - if (port->port.dev) - uhci_attach(&port->port, port->port.dev); + if (port->port.dev) { + usb_attach(&port->port, port->port.dev); + } } uhci_async_cancel_all(s); @@ -593,50 +592,41 @@ static void uhci_resume (void *opaque) } } -static void uhci_attach(USBPort *port1, USBDevice *dev) +static void uhci_attach(USBPort *port1) { UHCIState *s = port1->opaque; UHCIPort *port = &s->ports[port1->index]; - if (dev) { - if (port->port.dev) { - usb_attach(port1, NULL); - } - /* set connect status */ - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + /* set connect status */ + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; - /* update speed */ - if (dev->speed == USB_SPEED_LOW) - port->ctrl |= UHCI_PORT_LSDA; - else - port->ctrl &= ~UHCI_PORT_LSDA; - - uhci_resume(s); - - port->port.dev = dev; - /* send the attach message */ - usb_send_msg(dev, USB_MSG_ATTACH); + /* update speed */ + if (port->port.dev->speed == USB_SPEED_LOW) { + port->ctrl |= UHCI_PORT_LSDA; } else { - /* set connect status */ - if (port->ctrl & UHCI_PORT_CCS) { - port->ctrl &= ~UHCI_PORT_CCS; - port->ctrl |= UHCI_PORT_CSC; - } - /* disable port */ - if (port->ctrl & UHCI_PORT_EN) { - port->ctrl &= ~UHCI_PORT_EN; - port->ctrl |= UHCI_PORT_ENC; - } - - uhci_resume(s); - - dev = port->port.dev; - if (dev) { - /* send the detach message */ - usb_send_msg(dev, USB_MSG_DETACH); - } - port->port.dev = NULL; + port->ctrl &= ~UHCI_PORT_LSDA; } + + uhci_resume(s); +} + +static void uhci_detach(USBPort *port1) +{ + UHCIState *s = port1->opaque; + UHCIPort *port = &s->ports[port1->index]; + + /* set connect status */ + if (port->ctrl & UHCI_PORT_CCS) { + port->ctrl &= ~UHCI_PORT_CCS; + port->ctrl |= UHCI_PORT_CSC; + } + /* disable port */ + if (port->ctrl & UHCI_PORT_EN) { + port->ctrl &= ~UHCI_PORT_EN; + port->ctrl |= UHCI_PORT_ENC; + } + + uhci_resume(s); } static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) @@ -1103,6 +1093,7 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, static USBPortOps uhci_port_ops = { .attach = uhci_attach, + .detach = uhci_detach, }; static int usb_uhci_common_initfn(UHCIState *s) diff --git a/hw/usb.c b/hw/usb.c index 39d29f3daf..2eda86a58c 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -28,7 +28,25 @@ void usb_attach(USBPort *port, USBDevice *dev) { - port->ops->attach(port, dev); + if (dev != NULL) { + /* attach */ + if (port->dev) { + usb_attach(port, NULL); + } + dev->port = port; + port->dev = dev; + port->ops->attach(port); + usb_send_msg(dev, USB_MSG_ATTACH); + } else { + /* detach */ + dev = port->dev; + port->ops->detach(port); + if (dev) { + usb_send_msg(dev, USB_MSG_DETACH); + dev->port = NULL; + port->dev = NULL; + } + } } /**********************/ diff --git a/hw/usb.h b/hw/usb.h index 218788fceb..3744d19be3 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -147,6 +147,7 @@ struct USBDescString { struct USBDevice { DeviceState qdev; USBDeviceInfo *info; + USBPort *port; void *opaque; int speed; @@ -217,7 +218,8 @@ struct USBDeviceInfo { }; typedef struct USBPortOps { - void (*attach)(USBPort *port, USBDevice *dev); + void (*attach)(USBPort *port); + void (*detach)(USBPort *port); } USBPortOps; /* USB port on which a device can be connected */ From 01eacab6e95267fd894d0c1013aa5bf55c320dc8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Dec 2010 11:32:45 +0100 Subject: [PATCH 17/32] usb: add usb_wakeup() + wakeup callback to port ops Add wakeup callback to port ops for remote wakeup handling. Also add a usb_wakeup() function for devices which want trigger a remote wakeup. Signed-off-by: Gerd Hoffmann --- hw/usb.c | 7 +++++++ hw/usb.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/hw/usb.c b/hw/usb.c index 2eda86a58c..ba720b48e0 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -49,6 +49,13 @@ void usb_attach(USBPort *port, USBDevice *dev) } } +void usb_wakeup(USBDevice *dev) +{ + if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) { + dev->port->ops->wakeup(dev); + } +} + /**********************/ /* generic USB device helpers (you are not forced to use them when diff --git a/hw/usb.h b/hw/usb.h index 3744d19be3..250ec71a97 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -220,6 +220,7 @@ struct USBDeviceInfo { typedef struct USBPortOps { void (*attach)(USBPort *port); void (*detach)(USBPort *port); + void (*wakeup)(USBDevice *dev); } USBPortOps; /* USB port on which a device can be connected */ @@ -275,6 +276,7 @@ static inline 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); int set_usb_string(uint8_t *buf, const char *str); void usb_send_msg(USBDevice *dev, int msg); From 9159f6798ebfe0cdcfd1d1fb91c2c08b6d95954a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Dec 2010 11:47:40 +0100 Subject: [PATCH 18/32] usb: uhci: remote wakeup support. Add support for remote wakeup to the UHCI adapter. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 5e2e34a51c..2d2a9e791d 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -57,13 +57,18 @@ #define TD_CTRL_NAK (1 << 19) #define TD_CTRL_TIMEOUT (1 << 18) +#define UHCI_PORT_SUSPEND (1 << 12) #define UHCI_PORT_RESET (1 << 9) #define UHCI_PORT_LSDA (1 << 8) +#define UHCI_PORT_RD (1 << 6) #define UHCI_PORT_ENC (1 << 3) #define UHCI_PORT_EN (1 << 2) #define UHCI_PORT_CSC (1 << 1) #define UHCI_PORT_CCS (1 << 0) +#define UHCI_PORT_READ_ONLY (0x1bb) +#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC) + #define FRAME_TIMER_FREQ 1000 #define FRAME_MAX_LOOPS 100 @@ -497,9 +502,10 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) usb_send_msg(dev, USB_MSG_RESET); } } - port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); + port->ctrl &= UHCI_PORT_READ_ONLY; + port->ctrl |= (val & ~UHCI_PORT_READ_ONLY); /* some bits are reset when a '1' is written to them */ - port->ctrl &= ~(val & 0x000a); + port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR); } break; } @@ -629,6 +635,18 @@ static void uhci_detach(USBPort *port1) uhci_resume(s); } +static void uhci_wakeup(USBDevice *dev) +{ + USBBus *bus = usb_bus_from_device(dev); + UHCIState *s = container_of(bus, UHCIState, bus); + UHCIPort *port = s->ports + dev->port->index; + + if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) { + port->ctrl |= UHCI_PORT_RD; + uhci_resume(s); + } +} + static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) { int i, ret; @@ -1094,6 +1112,7 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, static USBPortOps uhci_port_ops = { .attach = uhci_attach, .detach = uhci_detach, + .wakeup = uhci_wakeup, }; static int usb_uhci_common_initfn(UHCIState *s) From 34239c7bc972735391ca84283f8c8ad908dc61ef Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 15 Dec 2010 12:26:59 +0100 Subject: [PATCH 19/32] usb: hub: remote wakeup support. This patch makes the usb hub handle remote wakeup requests from devices properly by updating the port status register and forwarding the wakeup to the upstream port. Signed-off-by: Gerd Hoffmann --- hw/usb-hub.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 8837bd9efe..8a80151da2 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -245,6 +245,17 @@ static void usb_hub_detach(USBPort *port1) } } +static void usb_hub_wakeup(USBDevice *dev) +{ + USBHubState *s = dev->port->opaque; + USBHubPort *port = &s->ports[dev->port->index]; + + if (port->wPortStatus & PORT_STAT_SUSPEND) { + port->wPortChange |= PORT_STAT_C_SUSPEND; + usb_wakeup(&s->dev); + } +} + static void usb_hub_handle_reset(USBDevice *dev) { /* XXX: do it */ @@ -502,6 +513,7 @@ static void usb_hub_handle_destroy(USBDevice *dev) static USBPortOps usb_hub_port_ops = { .attach = usb_hub_attach, .detach = usb_hub_detach, + .wakeup = usb_hub_wakeup, }; static int usb_hub_initfn(USBDevice *dev) From ac57bbb614ace4f7b8b965562826a7f7fda00cdc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Dec 2010 11:50:04 +0100 Subject: [PATCH 20/32] usb: hid: remote wakeup support. Add usb_wakeup() call to the hid driver so remote wakeup actually works. Signed-off-by: Gerd Hoffmann --- hw/usb-hid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 1c3596025f..60fa57fd9c 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -429,6 +429,8 @@ static void usb_hid_changed(USBHIDState *hs) if (hs->datain) hs->datain(hs->datain_opaque); + + usb_wakeup(&hs->dev); } static void usb_mouse_event(void *opaque, From 7b074a22dab4bdda9864b933f1bc811a3db42845 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 14 Dec 2010 16:46:40 +0100 Subject: [PATCH 21/32] usb: hid: change serial number to "42". It would be nice to have some way to signal our hid devices support remote wakeup. There is a descriptor bit for that of course. Problem with using is one is that older qemu versions used to set the bit even though they did *not* support remote wakeup. Bummer. This patch changes the serial number of our hid devices from "1" to "42" to signal "it is safe to enable remote wakeup". The serial number was choosen because it isn't used for anything and it is available in sysfs so it is easy to match it using udev rules like this: ACTION=="add", SUBSYSTEM=="usb", \ ATTR{product}=="QEMU USB Tablet", ATTR{serial}=="42", \ RUN+="usb_enable_autosuspend %p" Signed-off-by: Gerd Hoffmann --- hw/usb-hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 60fa57fd9c..1fec163d05 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -90,7 +90,7 @@ static const USBDescStrings desc_strings = { [STR_PRODUCT_MOUSE] = "QEMU USB Mouse", [STR_PRODUCT_TABLET] = "QEMU USB Tablet", [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard", - [STR_SERIALNUMBER] = "1", + [STR_SERIALNUMBER] = "42", /* == remote wakeup works */ [STR_CONFIG_MOUSE] = "HID Mouse", [STR_CONFIG_TABLET] = "HID Tablet", [STR_CONFIG_KEYBOARD] = "HID Keyboard", From 843d4e0c633824a11c4067d0e84bd683520b5d39 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 3 Dec 2010 17:30:13 +0100 Subject: [PATCH 22/32] usb: add speed mask to ports Add a field to usb ports indicating the speed(s) they are able to handle. Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 3 ++- hw/usb-hub.c | 3 ++- hw/usb-musb.c | 3 ++- hw/usb-ohci.c | 3 ++- hw/usb-uhci.c | 3 ++- hw/usb.h | 9 ++++++++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 9dc8793148..e94b88ded5 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -113,7 +113,7 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) } void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBDevice *pdev, USBPortOps *ops) + USBDevice *pdev, USBPortOps *ops, int speedmask) { port->opaque = opaque; port->index = index; @@ -121,6 +121,7 @@ void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, port->opaque = opaque; port->index = index; port->ops = ops; + port->speedmask = speedmask; QTAILQ_INSERT_TAIL(&bus->free, port, next); bus->nfree++; } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 8a80151da2..ba712d6252 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -526,7 +526,8 @@ static int usb_hub_initfn(USBDevice *dev) for (i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; usb_register_port(usb_bus_from_device(dev), - &port->port, s, i, &s->dev, &usb_hub_port_ops); + &port->port, s, i, &s->dev, &usb_hub_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; } diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 233a2657c0..87eb9ca0ce 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -349,7 +349,8 @@ struct MUSBState { } usb_bus_new(&s->bus, NULL /* FIXME */); - usb_register_port(&s->bus, &s->port, s, 0, NULL, &musb_port_ops); + usb_register_port(&s->bus, &s->port, s, 0, NULL, &musb_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); return s; } diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index c859540c19..0d4271692d 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1699,7 +1699,8 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, usb_bus_new(&ohci->bus, dev); ohci->num_ports = num_ports; for (i = 0; i < num_ports; i++) { - usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, &ohci_port_ops); + usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, &ohci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } ohci->async_td = 0; diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 2d2a9e791d..253561f528 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1129,7 +1129,8 @@ static int usb_uhci_common_initfn(UHCIState *s) usb_bus_new(&s->bus, &s->dev.qdev); for(i = 0; i < NB_PORTS; i++) { - usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, &uhci_port_ops); + usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, &uhci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); s->expire_time = qemu_get_clock(vm_clock) + diff --git a/hw/usb.h b/hw/usb.h index 250ec71a97..407a11465a 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -44,6 +44,12 @@ #define USB_SPEED_LOW 0 #define USB_SPEED_FULL 1 #define USB_SPEED_HIGH 2 +#define USB_SPEED_SUPER 3 + +#define USB_SPEED_MASK_LOW (1 << USB_SPEED_LOW) +#define USB_SPEED_MASK_FULL (1 << USB_SPEED_FULL) +#define USB_SPEED_MASK_HIGH (1 << USB_SPEED_HIGH) +#define USB_SPEED_MASK_SUPER (1 << USB_SPEED_SUPER) #define USB_STATE_NOTATTACHED 0 #define USB_STATE_ATTACHED 1 @@ -226,6 +232,7 @@ typedef struct USBPortOps { /* USB port on which a device can be connected */ struct USBPort { USBDevice *dev; + int speedmask; USBPortOps *ops; void *opaque; USBDevice *pdev; @@ -339,7 +346,7 @@ USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBDevice *pdev, USBPortOps *ops); + USBDevice *pdev, USBPortOps *ops, int speedmask); void usb_unregister_port(USBBus *bus, USBPort *port); int usb_device_attach(USBDevice *dev); int usb_device_detach(USBDevice *dev); From b6f77fbe230ad3e9ec5c9115a1535137d5e5d04b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 3 Dec 2010 17:59:36 +0100 Subject: [PATCH 23/32] usb: add attach callback Add handle_attach() callback to USBDeviceInfo which is called by the generic package handler when the device is attached to the usb bus (i.e. plugged into a port). Signed-off-by: Gerd Hoffmann --- hw/usb.c | 7 ++++++- hw/usb.h | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/usb.c b/hw/usb.c index ba720b48e0..82a6217a0b 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -194,6 +194,9 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) switch(p->pid) { case USB_MSG_ATTACH: s->state = USB_STATE_ATTACHED; + if (s->info->handle_attach) { + s->info->handle_attach(s); + } return 0; case USB_MSG_DETACH: @@ -204,7 +207,9 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - s->info->handle_reset(s); + if (s->info->handle_reset) { + s->info->handle_reset(s); + } return 0; } diff --git a/hw/usb.h b/hw/usb.h index 407a11465a..892ff724ff 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -193,6 +193,11 @@ struct USBDeviceInfo { */ void (*handle_destroy)(USBDevice *dev); + /* + * Attach the device + */ + void (*handle_attach)(USBDevice *dev); + /* * Reset the device */ From 32d41919784abe56b10f6d7784c00bb27e4f4d39 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 3 Dec 2010 18:07:20 +0100 Subject: [PATCH 24/32] usb: add usb_desc_attach Add usb_desc_attach() which sets up the device according to the speed the usb port is able to handle. This function can be hooked into the handle_attach callback. Signed-off-by: Gerd Hoffmann --- hw/usb-desc.c | 36 +++++++++++++++++++++++++++++++++--- hw/usb-desc.h | 1 + 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 56ef734bde..f01e1cf43d 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -153,16 +153,46 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) /* ------------------------------------------------------------------ */ -void usb_desc_init(USBDevice *dev) +static void usb_desc_setdefaults(USBDevice *dev) { const USBDesc *desc = dev->info->usb_desc; assert(desc != NULL); - dev->speed = USB_SPEED_FULL; - dev->device = desc->full; + switch (dev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + dev->device = desc->full; + break; + case USB_SPEED_HIGH: + dev->device = desc->high; + break; + } dev->config = dev->device->confs; } +void usb_desc_init(USBDevice *dev) +{ + dev->speed = USB_SPEED_FULL; + usb_desc_setdefaults(dev); +} + +void usb_desc_attach(USBDevice *dev) +{ + const USBDesc *desc = dev->info->usb_desc; + + assert(desc != NULL); + if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { + dev->speed = USB_SPEED_HIGH; + } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { + dev->speed = USB_SPEED_FULL; + } else { + fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n", + dev->info->product_desc); + return; + } + usb_desc_setdefaults(dev); +} + void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) { USBDescString *s; diff --git a/hw/usb-desc.h b/hw/usb-desc.h index d441725355..484c7c7fc3 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -79,6 +79,7 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len); /* control message emulation helpers */ void usb_desc_init(USBDevice *dev); +void usb_desc_attach(USBDevice *dev); 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); From 25620cba94d7ca126a24d74ce6f2ac42aa9a2fe8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 8 Dec 2010 17:35:22 +0100 Subject: [PATCH 25/32] usb: add device qualifier support Add support for device_qualifier and other_speed_config descriptors. These are used to query the "other speed" configuration of usb 2.0 devices, i.e. in high-speed mode they return the full-speed configuration and visa versa. Signed-off-by: Gerd Hoffmann --- hw/usb-desc.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ hw/usb-desc.h | 2 ++ hw/usb.h | 2 ++ trace-events | 2 ++ 4 files changed, 52 insertions(+) diff --git a/hw/usb-desc.c b/hw/usb-desc.c index f01e1cf43d..62591f20aa 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -48,6 +48,30 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, return bLength; } +int usb_desc_device_qualifier(const USBDescDevice *dev, + uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x0a; + + if (len < bLength) { + return -1; + } + + dest[0x00] = bLength; + dest[0x01] = USB_DT_DEVICE_QUALIFIER; + + dest[0x02] = usb_lo(dev->bcdUSB); + dest[0x03] = usb_hi(dev->bcdUSB); + dest[0x04] = dev->bDeviceClass; + dest[0x05] = dev->bDeviceSubClass; + dest[0x06] = dev->bDeviceProtocol; + dest[0x07] = dev->bMaxPacketSize0; + dest[0x08] = dev->bNumConfigurations; + dest[0x09] = 0; /* reserved */ + + return bLength; +} + int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) { uint8_t bLength = 0x09; @@ -263,11 +287,18 @@ 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) { const USBDesc *desc = dev->info->usb_desc; + const USBDescDevice *other_dev; uint8_t buf[256]; uint8_t type = value >> 8; uint8_t index = value & 0xff; int ret = -1; + if (dev->speed == USB_SPEED_HIGH) { + other_dev = dev->info->usb_desc->full; + } else { + other_dev = dev->info->usb_desc->high; + } + switch(type) { case USB_DT_DEVICE: ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); @@ -283,6 +314,21 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len ret = usb_desc_string(dev, index, buf, sizeof(buf)); trace_usb_desc_string(dev->addr, index, len, ret); break; + + case USB_DT_DEVICE_QUALIFIER: + if (other_dev != NULL) { + ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); + } + trace_usb_desc_device_qualifier(dev->addr, len, ret); + break; + case USB_DT_OTHER_SPEED_CONFIG: + if (other_dev != NULL && index < other_dev->bNumConfigurations) { + ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); + buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; + } + trace_usb_desc_other_speed_config(dev->addr, index, len, ret); + break; + default: fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, dev->addr, type, len); diff --git a/hw/usb-desc.h b/hw/usb-desc.h index 484c7c7fc3..ac734ab088 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -72,6 +72,8 @@ struct USBDesc { /* generate usb packages from structs */ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, uint8_t *dest, size_t len); +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(const USBDescIface *iface, uint8_t *dest, size_t len); int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len); diff --git a/hw/usb.h b/hw/usb.h index 892ff724ff..99139e22e0 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -122,6 +122,8 @@ #define USB_DT_STRING 0x03 #define USB_DT_INTERFACE 0x04 #define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 #define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_ISOC 1 diff --git a/trace-events b/trace-events index 45e75828dc..19cee6a1d8 100644 --- a/trace-events +++ b/trace-events @@ -192,7 +192,9 @@ disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64"" # hw/usb-desc.c disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" +disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d" disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" +disable usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" disable usb_set_addr(int addr) "dev %d" disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d" From ca0c730df977abd7ca24afd17fa640f1af47f0b1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 3 Dec 2010 17:12:49 +0100 Subject: [PATCH 26/32] usb storage: high speed support Add high speed support to the usb mass storage device. With this patch applied the linux kernel recognises the usb storage device as highspeed capable device and suggests to connect it to a highspeed port instead of the uhci. Tested with both uhci and (not-yet submitted) ehci. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 74e657e7f9..7b8189fe0c 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -77,15 +77,19 @@ enum { STR_MANUFACTURER = 1, STR_PRODUCT, STR_SERIALNUMBER, + STR_CONFIG_FULL, + STR_CONFIG_HIGH, }; static const USBDescStrings desc_strings = { [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, [STR_PRODUCT] = "QEMU USB HARDDRIVE", [STR_SERIALNUMBER] = "1", + [STR_CONFIG_FULL] = "Full speed config (usb 1.1)", + [STR_CONFIG_HIGH] = "High speed config (usb 2.0)", }; -static const USBDescIface desc_iface0 = { +static const USBDescIface desc_iface_full = { .bInterfaceNumber = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_MASS_STORAGE, @@ -104,16 +108,51 @@ static const USBDescIface desc_iface0 = { } }; -static const USBDescDevice desc_device = { - .bcdUSB = 0x0100, +static const USBDescDevice desc_device_full = { + .bcdUSB = 0x0200, .bMaxPacketSize0 = 8, .bNumConfigurations = 1, .confs = (USBDescConfig[]) { { .bNumInterfaces = 1, .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_FULL, .bmAttributes = 0xc0, - .ifs = &desc_iface0, + .ifs = &desc_iface_full, + }, + }, +}; + +static const USBDescIface desc_iface_high = { + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = 0x06, /* SCSI */ + .bInterfaceProtocol = 0x50, /* Bulk */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 512, + },{ + .bEndpointAddress = USB_DIR_OUT | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 512, + }, + } +}; + +static const USBDescDevice desc_device_high = { + .bcdUSB = 0x0200, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_HIGH, + .bmAttributes = 0xc0, + .ifs = &desc_iface_high, }, }, }; @@ -127,7 +166,8 @@ static const USBDesc desc = { .iProduct = STR_PRODUCT, .iSerialNumber = STR_SERIALNUMBER, }, - .full = &desc_device, + .full = &desc_device_full, + .high = &desc_device_high, .str = desc_strings, }; @@ -558,6 +598,7 @@ static struct USBDeviceInfo msd_info = { .usb_desc = &desc, .init = usb_msd_initfn, .handle_packet = usb_generic_handle_packet, + .handle_attach = usb_desc_attach, .handle_reset = usb_msd_handle_reset, .handle_control = usb_msd_handle_control, .handle_data = usb_msd_handle_data, From ab4797ad2ec34e63ee8751fbd3e5d0a9888eaf4a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 9 Dec 2010 10:36:35 +0100 Subject: [PATCH 27/32] usb storage: fix status reporting Change usb_msd_send_status() to take a pointer to the status packet instead of writing the status to s->usb_buf which might not point to the correct location. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 7b8189fe0c..28c12dd632 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -196,15 +196,18 @@ static void usb_msd_copy_data(MSDState *s) } } -static void usb_msd_send_status(MSDState *s) +static void usb_msd_send_status(MSDState *s, USBPacket *p) { struct usb_msd_csw csw; + int len; csw.sig = cpu_to_le32(0x53425355); csw.tag = cpu_to_le32(s->tag); csw.residue = s->residue; csw.status = s->result; - memcpy(s->usb_buf, &csw, 13); + + len = MIN(sizeof(csw), p->len); + memcpy(p->data, &csw, len); } static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, @@ -224,7 +227,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { /* A deferred packet with no write data remaining must be the status read packet. */ - usb_msd_send_status(s); + usb_msd_send_status(s, p); s->mode = USB_MSDM_CBW; } else { if (s->data_len) { @@ -425,9 +428,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (len < 13) goto fail; - s->usb_len = len; - s->usb_buf = data; - usb_msd_send_status(s); + usb_msd_send_status(s, p); s->mode = USB_MSDM_CBW; ret = 13; break; From fa7935c1e1f84b600fcb1983485352b8d99e01d3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 9 Dec 2010 23:31:49 +0100 Subject: [PATCH 28/32] usb storage: handle long responses The scsi layer may return us more data than the guests wants to have. Handle this by just ignoring the extra bytes and calling the {read,write}_data callback to finish the request. Seen happening in real life with some extended inquiry command. With this patch applied the linux kernel stops reseting the device once at boot. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 28c12dd632..729d96ccc3 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -187,7 +187,7 @@ static void usb_msd_copy_data(MSDState *s) s->usb_buf += len; s->scsi_buf += len; s->data_len -= len; - if (s->scsi_len == 0) { + if (s->scsi_len == 0 || s->data_len == 0) { if (s->mode == USB_MSDM_DATAIN) { s->scsi_dev->info->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { @@ -434,7 +434,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) break; case USB_MSDM_DATAIN: - DPRINTF("Data in %d/%d\n", len, s->data_len); + DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len); if (len > s->data_len) len = s->data_len; s->usb_buf = data; From c7a2196a4fcdaba977b99aca0b6a6de5e5e7f64a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 10 Dec 2010 11:37:45 +0100 Subject: [PATCH 29/32] usb: keep track of physical port address. Add a path string to USBPort. Add usb_port_location() function to set the physical location of the usb port. Update all drivers implementing usb ports to call it. Update the monitor commands to print it. Wind it up in qdev. Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 26 +++++++++++++++++++++++--- hw/usb-hub.c | 11 +++++++++++ hw/usb-musb.c | 1 + hw/usb-ohci.c | 1 + hw/usb-uhci.c | 1 + hw/usb.h | 2 ++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index e94b88ded5..0cb03c9137 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -5,12 +5,15 @@ #include "monitor.h" static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); + +static char *usb_get_dev_path(DeviceState *dev); static char *usbbus_get_fw_dev_path(DeviceState *dev); static struct BusInfo usb_bus_info = { .name = "USB", .size = sizeof(USBBus), .print_dev = usb_bus_dev_print, + .get_dev_path = usb_get_dev_path, .get_fw_dev_path = usbbus_get_fw_dev_path, }; static int next_usb_bus = 0; @@ -126,6 +129,16 @@ void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, bus->nfree++; } +void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr) +{ + if (upstream) { + snprintf(downstream->path, sizeof(downstream->path), "%s.%d", + upstream->path, portnr); + } else { + snprintf(downstream->path, sizeof(downstream->path), "%d", portnr); + } +} + void usb_unregister_port(USBBus *bus, USBPort *port) { if (port->dev) @@ -235,12 +248,19 @@ 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%s\n", + monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n", indent, "", bus->busnr, dev->addr, + dev->port ? dev->port->path : "-", usb_speed(dev->speed), dev->product_desc, dev->attached ? ", attached" : ""); } +static char *usb_get_dev_path(DeviceState *qdev) +{ + USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + return qemu_strdup(dev->port->path); +} + void usb_info(Monitor *mon) { USBBus *bus; @@ -257,8 +277,8 @@ void usb_info(Monitor *mon) 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), + monitor_printf(mon, " Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n", + bus->busnr, dev->addr, port->path, usb_speed(dev->speed), dev->product_desc); } } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index ba712d6252..387c40c040 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -256,6 +256,16 @@ static void usb_hub_wakeup(USBDevice *dev) } } +static void usb_hub_handle_attach(USBDevice *dev) +{ + USBHubState *s = DO_UPCAST(USBHubState, dev, dev); + int i; + + for (i = 0; i < NUM_PORTS; i++) { + usb_port_location(&s->ports[i].port, dev->port, i+1); + } +} + static void usb_hub_handle_reset(USBDevice *dev) { /* XXX: do it */ @@ -542,6 +552,7 @@ static struct USBDeviceInfo hub_info = { .usb_desc = &desc_hub, .init = usb_hub_initfn, .handle_packet = usb_hub_handle_packet, + .handle_attach = usb_hub_handle_attach, .handle_reset = usb_hub_handle_reset, .handle_control = usb_hub_handle_control, .handle_data = usb_hub_handle_data, diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 87eb9ca0ce..4b5f35b4b1 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -351,6 +351,7 @@ struct MUSBState { usb_bus_new(&s->bus, NULL /* FIXME */); usb_register_port(&s->bus, &s->port, s, 0, NULL, &musb_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); + usb_port_location(&s->port, NULL, 1); return s; } diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 0d4271692d..6344f81806 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1701,6 +1701,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, for (i = 0; i < num_ports; i++) { usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, &ohci_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); + usb_port_location(&ohci->rhport[i].port, NULL, i+1); } ohci->async_td = 0; diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 253561f528..6db19602e6 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1131,6 +1131,7 @@ static int usb_uhci_common_initfn(UHCIState *s) for(i = 0; i < NB_PORTS; i++) { usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, &uhci_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); + usb_port_location(&s->ports[i].port, NULL, i+1); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); s->expire_time = qemu_get_clock(vm_clock) + diff --git a/hw/usb.h b/hw/usb.h index 99139e22e0..8fdda2971e 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -240,6 +240,7 @@ typedef struct USBPortOps { struct USBPort { USBDevice *dev; int speedmask; + char path[16]; USBPortOps *ops; void *opaque; USBDevice *pdev; @@ -354,6 +355,7 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, USBDevice *pdev, USBPortOps *ops, int speedmask); +void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr); void usb_unregister_port(USBBus *bus, USBPort *port); int usb_device_attach(USBDevice *dev); int usb_device_detach(USBDevice *dev); From 5f69076b8dda325dcbbc87bdb00e04ffac0f6137 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 10 Dec 2010 11:43:35 +0100 Subject: [PATCH 30/32] usb: add port property. This allows to explictily set the physical port where you want to plug the usb device. Example: -device usb-tablet,bus=usb.0,port=2 With explicit port addressing qemu can and will not automagically add USB Hubs. This means that: (a) You can plug two devices of your choice into the two uhci root ports. (b) If you want plug in more that two devices you have to care about adding a hub yourself. Plugging a hub works this way: -device usb-hub,bus=usb.0,port=1 Use this to add a device to the hub: -device usb-tablet,bus=usb.0,port=1.1 Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 26 ++++++++++++++++++++++---- hw/usb.h | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 0cb03c9137..1f59f9a949 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -15,6 +15,10 @@ static struct BusInfo usb_bus_info = { .print_dev = usb_bus_dev_print, .get_dev_path = usb_get_dev_path, .get_fw_dev_path = usbbus_get_fw_dev_path, + .props = (Property[]) { + DEFINE_PROP_STRING("port", USBDevice, port_path), + DEFINE_PROP_END_OF_LIST() + }, }; static int next_usb_bus = 0; static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses); @@ -157,9 +161,22 @@ static void do_attach(USBDevice *dev) dev->product_desc); return; } - dev->attached++; + if (dev->port_path) { + QTAILQ_FOREACH(port, &bus->free, next) { + if (strcmp(port->path, dev->port_path) == 0) { + break; + } + } + if (port == NULL) { + fprintf(stderr, "Warning: usb port %s (bus %s) not found\n", + dev->port_path, bus->qbus.name); + return; + } + } else { + port = QTAILQ_FIRST(&bus->free); + } - port = QTAILQ_FIRST(&bus->free); + dev->attached++; QTAILQ_REMOVE(&bus->free, port, next); bus->nfree--; @@ -173,8 +190,9 @@ int usb_device_attach(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); - if (bus->nfree == 1) { - /* Create a new hub and chain it on. */ + if (bus->nfree == 1 && dev->port_path == NULL) { + /* Create a new hub and chain it on + (unless a physical port location is specified). */ usb_create_simple(bus, "usb-hub"); } do_attach(dev); diff --git a/hw/usb.h b/hw/usb.h index 8fdda2971e..c6e3e25286 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -156,6 +156,7 @@ struct USBDevice { DeviceState qdev; USBDeviceInfo *info; USBPort *port; + char *port_path; void *opaque; int speed; From 70d31cb22cb67745741b2bb349c9c7c3a184f88b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Jan 2011 10:58:27 +0100 Subject: [PATCH 31/32] usb: rewrite fw path, fix numbering This patch rewrites the firmware path code to use the physical port location tracking just added to the qemu usb core. It also fixes the port numbering to start with "1" in the firmware path. Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 68 ++++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 1f59f9a949..f89176b912 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -7,14 +7,14 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); static char *usb_get_dev_path(DeviceState *dev); -static char *usbbus_get_fw_dev_path(DeviceState *dev); +static char *usb_get_fw_dev_path(DeviceState *qdev); static struct BusInfo usb_bus_info = { .name = "USB", .size = sizeof(USBBus), .print_dev = usb_bus_dev_print, .get_dev_path = usb_get_dev_path, - .get_fw_dev_path = usbbus_get_fw_dev_path, + .get_fw_dev_path = usb_get_fw_dev_path, .props = (Property[]) { DEFINE_PROP_STRING("port", USBDevice, port_path), DEFINE_PROP_END_OF_LIST() @@ -279,6 +279,30 @@ static char *usb_get_dev_path(DeviceState *qdev) return qemu_strdup(dev->port->path); } +static char *usb_get_fw_dev_path(DeviceState *qdev) +{ + USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + char *fw_path, *in; + int pos = 0; + long nr; + + fw_path = qemu_malloc(32 + strlen(dev->port->path) * 6); + in = dev->port->path; + while (true) { + nr = strtol(in, &in, 10); + if (in[0] == '.') { + /* some hub between root port and device */ + pos += sprintf(fw_path + pos, "hub@%ld/", nr); + in++; + } else { + /* the device itself */ + pos += sprintf(fw_path + pos, "%s@%ld", qdev_fw_name(qdev), nr); + break; + } + } + return fw_path; +} + void usb_info(Monitor *mon) { USBBus *bus; @@ -351,43 +375,3 @@ USBDevice *usbdevice_create(const char *cmdline) } return usb->usbdevice_init(params); } - -static int usbbus_get_fw_dev_path_helper(USBDevice *d, USBBus *bus, char *p, - int len) -{ - int l = 0; - USBPort *port; - - QTAILQ_FOREACH(port, &bus->used, next) { - if (port->dev == d) { - if (port->pdev) { - l = usbbus_get_fw_dev_path_helper(port->pdev, bus, p, len); - } - l += snprintf(p + l, len - l, "%s@%x/", qdev_fw_name(&d->qdev), - port->index); - break; - } - } - - return l; -} - -static char *usbbus_get_fw_dev_path(DeviceState *dev) -{ - USBDevice *d = (USBDevice*)dev; - USBBus *bus = usb_bus_from_device(d); - char path[100]; - int l; - - assert(d->attached != 0); - - l = usbbus_get_fw_dev_path_helper(d, bus, path, sizeof(path)); - - if (l == 0) { - abort(); - } - - path[l-1] = '\0'; - - return strdup(path); -} From ace1318b8ea95efa332fb3e8e159924d4f928753 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Jan 2011 11:34:50 +0100 Subject: [PATCH 32/32] usb: zap pdev from usbport It isn't needed any more. Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 3 +-- hw/usb-hub.c | 2 +- hw/usb-musb.c | 2 +- hw/usb-ohci.c | 2 +- hw/usb-uhci.c | 2 +- hw/usb.h | 3 +-- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index f89176b912..6e2e5fd17a 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -120,11 +120,10 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) } void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBDevice *pdev, USBPortOps *ops, int speedmask) + USBPortOps *ops, int speedmask) { port->opaque = opaque; port->index = index; - port->pdev = pdev; port->opaque = opaque; port->index = index; port->ops = ops; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 387c40c040..78698caf67 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -536,7 +536,7 @@ static int usb_hub_initfn(USBDevice *dev) for (i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; usb_register_port(usb_bus_from_device(dev), - &port->port, s, i, &s->dev, &usb_hub_port_ops, + &port->port, s, i, &usb_hub_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 4b5f35b4b1..782cfa2282 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -349,7 +349,7 @@ struct MUSBState { } usb_bus_new(&s->bus, NULL /* FIXME */); - usb_register_port(&s->bus, &s->port, s, 0, NULL, &musb_port_ops, + usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); usb_port_location(&s->port, NULL, 1); diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 6344f81806..09ea0b6260 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1699,7 +1699,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, usb_bus_new(&ohci->bus, dev); ohci->num_ports = num_ports; for (i = 0; i < num_ports; i++) { - usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, &ohci_port_ops, + usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); usb_port_location(&ohci->rhport[i].port, NULL, i+1); } diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 6db19602e6..b384e1ddec 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1129,7 +1129,7 @@ static int usb_uhci_common_initfn(UHCIState *s) usb_bus_new(&s->bus, &s->dev.qdev); for(i = 0; i < NB_PORTS; i++) { - usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, &uhci_port_ops, + usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); usb_port_location(&s->ports[i].port, NULL, i+1); } diff --git a/hw/usb.h b/hw/usb.h index c6e3e25286..5c1da3ed25 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -244,7 +244,6 @@ struct USBPort { char path[16]; USBPortOps *ops; void *opaque; - USBDevice *pdev; int index; /* internal port index, may be used with the opaque */ QTAILQ_ENTRY(USBPort) next; }; @@ -355,7 +354,7 @@ USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBDevice *pdev, USBPortOps *ops, int speedmask); + USBPortOps *ops, int speedmask); void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr); void usb_unregister_port(USBBus *bus, USBPort *port); int usb_device_attach(USBDevice *dev);