diff options
Diffstat (limited to 'hw/usb-net.c')
-rw-r--r-- | hw/usb-net.c | 453 |
1 files 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, |