aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb-net.c453
1 files changed, 209 insertions, 244 deletions
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 8492455..b2fe42e 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,