usb network: use new descriptor infrastructure.

Switch the usb network driver over to the
new descriptor infrastructure.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Gerd Hoffmann 2010-11-26 10:25:06 +01:00
parent 4a1e1bc416
commit 30c7d32a0a

View file

@ -25,6 +25,7 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "usb.h" #include "usb.h"
#include "usb-desc.h"
#include "net.h" #include "net.h"
#include "qemu-queue.h" #include "qemu-queue.h"
#include "sysemu.h" #include "sysemu.h"
@ -89,182 +90,209 @@ enum usbstring_idx {
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
/* static const USBDescStrings usb_net_stringtable = {
* mostly the same descriptor as the linux gadget rndis driver [STRING_MANUFACTURER] = "QEMU",
*/ [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device",
static const uint8_t qemu_net_dev_descriptor[] = { [STRING_ETHADDR] = "400102030405",
0x12, /* u8 bLength; */ [STRING_DATA] = "QEMU USB Net Data Interface",
USB_DT_DEVICE, /* u8 bDescriptorType; Device */ [STRING_CONTROL] = "QEMU USB Net Control Interface",
0x00, 0x02, /* u16 bcdUSB; v2.0 */ [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface",
USB_CLASS_COMM, /* u8 bDeviceClass; */ [STRING_CDC] = "QEMU USB Net CDC",
0x00, /* u8 bDeviceSubClass; */ [STRING_SUBSET] = "QEMU USB Net Subset",
0x00, /* u8 bDeviceProtocol; [ low/full only ] */ [STRING_RNDIS] = "QEMU USB Net RNDIS",
0x40, /* u8 bMaxPacketSize0 */ [STRING_SERIALNUMBER] = "1",
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 uint8_t qemu_net_rndis_config_descriptor[] = { static const USBDescIface desc_iface_rndis[] = {
/* Configuration Descriptor */ {
0x09, /* u8 bLength */ /* RNDIS Control Interface */
USB_DT_CONFIG, /* u8 bDescriptorType */ .bInterfaceNumber = 0,
0x43, 0x00, /* le16 wTotalLength */ .bNumEndpoints = 1,
0x02, /* u8 bNumInterfaces */ .bInterfaceClass = USB_CLASS_COMM,
DEV_RNDIS_CONFIG_VALUE, /* u8 bConfigurationValue */ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
STRING_RNDIS, /* u8 iConfiguration */ .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
0xc0, /* u8 bmAttributes */ .iInterface = STRING_RNDIS_CONTROL,
0x32, /* u8 bMaxPower */ .ndesc = 4,
/* RNDIS Control Interface */ .descs = (USBDescOther[]) {
0x09, /* u8 bLength */ {
USB_DT_INTERFACE, /* u8 bDescriptorType */ /* Header Descriptor */
0x00, /* u8 bInterfaceNumber */ .data = (uint8_t[]) {
0x00, /* u8 bAlternateSetting */ 0x05, /* u8 bLength */
0x01, /* u8 bNumEndpoints */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
USB_CLASS_COMM, /* u8 bInterfaceClass */ USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
USB_CDC_SUBCLASS_ACM, /* u8 bInterfaceSubClass */ 0x10, 0x01, /* le16 bcdCDC */
USB_CDC_ACM_PROTO_VENDOR, /* u8 bInterfaceProtocol */ },
STRING_RNDIS_CONTROL, /* u8 iInterface */ },{
/* Header Descriptor */ /* Call Management Descriptor */
0x05, /* u8 bLength */ .data = (uint8_t[]) {
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ 0x05, /* u8 bLength */
USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
0x10, 0x01, /* le16 bcdCDC */ USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */
/* Call Management Descriptor */ 0x00, /* u8 bmCapabilities */
0x05, /* u8 bLength */ 0x01, /* u8 bDataInterface */
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ },
USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */ },{
0x00, /* u8 bmCapabilities */ /* ACM Descriptor */
0x01, /* u8 bDataInterface */ .data = (uint8_t[]) {
/* ACM Descriptor */ 0x04, /* u8 bLength */
0x04, /* u8 bLength */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */
USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */ 0x00, /* u8 bmCapabilities */
0x00, /* u8 bmCapabilities */ },
/* Union Descriptor */ },{
0x05, /* u8 bLength */ /* Union Descriptor */
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ .data = (uint8_t[]) {
USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ 0x05, /* u8 bLength */
0x00, /* u8 bMasterInterface0 */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
0x01, /* u8 bSlaveInterface0 */ USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
/* Status Descriptor */ 0x00, /* u8 bMasterInterface0 */
0x07, /* u8 bLength */ 0x01, /* u8 bSlaveInterface0 */
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 */ .eps = (USBDescEndpoint[]) {
1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ {
/* RNDIS Data Interface */ .bEndpointAddress = USB_DIR_IN | 0x01,
0x09, /* u8 bLength */ .bmAttributes = USB_ENDPOINT_XFER_INT,
USB_DT_INTERFACE, /* u8 bDescriptorType */ .wMaxPacketSize = STATUS_BYTECOUNT,
0x01, /* u8 bInterfaceNumber */ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
0x00, /* u8 bAlternateSetting */ },
0x02, /* u8 bNumEndpoints */ }
USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ },{
0x00, /* u8 bInterfaceSubClass */ /* RNDIS Data Interface */
0x00, /* u8 bInterfaceProtocol */ .bInterfaceNumber = 1,
STRING_DATA, /* u8 iInterface */ .bNumEndpoints = 2,
/* Source Endpoint */ .bInterfaceClass = USB_CLASS_CDC_DATA,
0x07, /* u8 bLength */ .iInterface = STRING_DATA,
USB_DT_ENDPOINT, /* u8 bDescriptorType */ .eps = (USBDescEndpoint[]) {
USB_DIR_IN | 2, /* u8 bEndpointAddress */ {
USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ .bEndpointAddress = USB_DIR_IN | 0x02,
0x40, 0x00, /* le16 wMaxPacketSize */ .bmAttributes = USB_ENDPOINT_XFER_BULK,
0x00, /* u8 bInterval */ .wMaxPacketSize = 0x40,
/* Sink Endpoint */ },{
0x07, /* u8 bLength */ .bEndpointAddress = USB_DIR_OUT | 0x02,
USB_DT_ENDPOINT, /* u8 bDescriptorType */ .bmAttributes = USB_ENDPOINT_XFER_BULK,
USB_DIR_OUT | 2, /* u8 bEndpointAddress */ .wMaxPacketSize = 0x40,
USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ }
0x40, 0x00, /* le16 wMaxPacketSize */ }
0x00 /* u8 bInterval */ }
}; };
static const uint8_t qemu_net_cdc_config_descriptor[] = { static const USBDescIface desc_iface_cdc[] = {
/* Configuration Descriptor */ {
0x09, /* u8 bLength */ /* CDC Control Interface */
USB_DT_CONFIG, /* u8 bDescriptorType */ .bInterfaceNumber = 0,
0x50, 0x00, /* le16 wTotalLength */ .bNumEndpoints = 1,
0x02, /* u8 bNumInterfaces */ .bInterfaceClass = USB_CLASS_COMM,
DEV_CONFIG_VALUE, /* u8 bConfigurationValue */ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
STRING_CDC, /* u8 iConfiguration */ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
0xc0, /* u8 bmAttributes */ .iInterface = STRING_CONTROL,
0x32, /* u8 bMaxPower */ .ndesc = 3,
/* CDC Control Interface */ .descs = (USBDescOther[]) {
0x09, /* u8 bLength */ {
USB_DT_INTERFACE, /* u8 bDescriptorType */ /* Header Descriptor */
0x00, /* u8 bInterfaceNumber */ .data = (uint8_t[]) {
0x00, /* u8 bAlternateSetting */ 0x05, /* u8 bLength */
0x01, /* u8 bNumEndpoints */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
USB_CLASS_COMM, /* u8 bInterfaceClass */ USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
USB_CDC_SUBCLASS_ETHERNET, /* u8 bInterfaceSubClass */ 0x10, 0x01, /* le16 bcdCDC */
USB_CDC_PROTO_NONE, /* u8 bInterfaceProtocol */ },
STRING_CONTROL, /* u8 iInterface */ },{
/* Header Descriptor */ /* Union Descriptor */
0x05, /* u8 bLength */ .data = (uint8_t[]) {
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ 0x05, /* u8 bLength */
USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
0x10, 0x01, /* le16 bcdCDC */ USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
/* Union Descriptor */ 0x00, /* u8 bMasterInterface0 */
0x05, /* u8 bLength */ 0x01, /* u8 bSlaveInterface0 */
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ },
USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ },{
0x00, /* u8 bMasterInterface0 */ /* Ethernet Descriptor */
0x01, /* u8 bSlaveInterface0 */ .data = (uint8_t[]) {
/* Ethernet Descriptor */ 0x0d, /* u8 bLength */
0x0d, /* u8 bLength */ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */
USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */ STRING_ETHADDR, /* u8 iMACAddress */
STRING_ETHADDR, /* u8 iMACAddress */ 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */
0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */ ETH_FRAME_LEN & 0xff,
ETH_FRAME_LEN & 0xff, ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */ ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */
0x00, 0x00, /* le16 wNumberMCFilters */ 0x00, 0x00, /* le16 wNumberMCFilters */
0x00, /* u8 bNumberPowerFilters */ 0x00, /* u8 bNumberPowerFilters */
/* Status Descriptor */ },
0x07, /* u8 bLength */ },
USB_DT_ENDPOINT, /* u8 bDescriptorType */ },
USB_DIR_IN | 1, /* u8 bEndpointAddress */ .eps = (USBDescEndpoint[]) {
USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ {
STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ .bEndpointAddress = USB_DIR_IN | 0x01,
1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ .bmAttributes = USB_ENDPOINT_XFER_INT,
/* CDC Data (nop) Interface */ .wMaxPacketSize = STATUS_BYTECOUNT,
0x09, /* u8 bLength */ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
USB_DT_INTERFACE, /* u8 bDescriptorType */ },
0x01, /* u8 bInterfaceNumber */ }
0x00, /* u8 bAlternateSetting */ },{
0x00, /* u8 bNumEndpoints */ /* CDC Data Interface (off) */
USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ .bInterfaceNumber = 1,
0x00, /* u8 bInterfaceSubClass */ .bAlternateSetting = 0,
0x00, /* u8 bInterfaceProtocol */ .bNumEndpoints = 0,
0x00, /* u8 iInterface */ .bInterfaceClass = USB_CLASS_CDC_DATA,
/* CDC Data Interface */ },{
0x09, /* u8 bLength */ /* CDC Data Interface */
USB_DT_INTERFACE, /* u8 bDescriptorType */ .bInterfaceNumber = 1,
0x01, /* u8 bInterfaceNumber */ .bAlternateSetting = 1,
0x01, /* u8 bAlternateSetting */ .bNumEndpoints = 2,
0x02, /* u8 bNumEndpoints */ .bInterfaceClass = USB_CLASS_CDC_DATA,
USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ .iInterface = STRING_DATA,
0x00, /* u8 bInterfaceSubClass */ .eps = (USBDescEndpoint[]) {
0x00, /* u8 bInterfaceProtocol */ {
STRING_DATA, /* u8 iInterface */ .bEndpointAddress = USB_DIR_IN | 0x02,
/* Source Endpoint */ .bmAttributes = USB_ENDPOINT_XFER_BULK,
0x07, /* u8 bLength */ .wMaxPacketSize = 0x40,
USB_DT_ENDPOINT, /* u8 bDescriptorType */ },{
USB_DIR_IN | 2, /* u8 bEndpointAddress */ .bEndpointAddress = USB_DIR_OUT | 0x02,
USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ .bmAttributes = USB_ENDPOINT_XFER_BULK,
0x40, 0x00, /* le16 wMaxPacketSize */ .wMaxPacketSize = 0x40,
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 */ static const USBDescDevice desc_device_net = {
0x40, 0x00, /* le16 wMaxPacketSize */ .bcdUSB = 0x0200,
0x00 /* u8 bInterval */ .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, static int usb_net_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data) int index, int length, uint8_t *data)
{ {
USBNetState *s = (USBNetState *) dev; 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) { switch(request) {
case DeviceRequest | USB_REQ_GET_STATUS: case DeviceRequest | USB_REQ_GET_STATUS:
data[0] = (1 << USB_DEVICE_SELF_POWERED) | data[0] = (1 << USB_DEVICE_SELF_POWERED) |
@ -1100,64 +1121,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
#endif #endif
break; 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: case DeviceRequest | USB_REQ_GET_CONFIGURATION:
data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE; data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE;
ret = 1; ret = 1;
@ -1463,6 +1426,7 @@ static int usb_net_initfn(USBDevice *dev)
s->conf.macaddr.a[3], s->conf.macaddr.a[3],
s->conf.macaddr.a[4], s->conf.macaddr.a[4],
s->conf.macaddr.a[5]); 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"); add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet@0");
return 0; return 0;
@ -1500,6 +1464,7 @@ static struct USBDeviceInfo net_info = {
.qdev.name = "usb-net", .qdev.name = "usb-net",
.qdev.fw_name = "network", .qdev.fw_name = "network",
.qdev.size = sizeof(USBNetState), .qdev.size = sizeof(USBNetState),
.usb_desc = &desc_net,
.init = usb_net_initfn, .init = usb_net_initfn,
.handle_packet = usb_generic_handle_packet, .handle_packet = usb_generic_handle_packet,
.handle_reset = usb_net_handle_reset, .handle_reset = usb_net_handle_reset,