📄 ether.c
字号:
/* compute wTotalLength on the fly */ .bNumInterfaces = 2, .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE, .iConfiguration = STRING_RNDIS, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = 50,};#endif/* * Compared to the simple CDC subset, the full CDC Ethernet model adds * three class descriptors, two interface descriptors, optional status * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. * * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it * may hang or oops. Since bugfixes (or accurate specs, letting Linux * work around those bugs) are unlikely to ever come from MSFT, you may * wish to avoid using RNDIS. * * MCCI offers an alternative to RNDIS if you need to connect to Windows * but have hardware that can't support CDC Ethernet. We add descriptors * to present the CDC Subset as a (nonconformant) CDC MDLM variant called * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can * get those drivers from MCCI, or bundled with various products. */#ifdef DEV_CONFIG_CDCstatic struct usb_interface_descriptorcontrol_intf = { .bLength = sizeof control_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, /* status endpoint is optional; this may be patched later */ .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, .bInterfaceProtocol = USB_CDC_PROTO_NONE, .iInterface = STRING_CONTROL,};#endif#ifdef CONFIG_USB_ETH_RNDISstatic const struct usb_interface_descriptorrndis_control_intf = { .bLength = sizeof rndis_control_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, .iInterface = STRING_RNDIS_CONTROL,};#endifstatic const struct usb_cdc_header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, .bcdCDC = __constant_cpu_to_le16 (0x0110),};#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_UNION_TYPE, .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of DATA interface */};#endif /* CDC || RNDIS */#ifdef CONFIG_USB_ETH_RNDISstatic const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { .bLength = sizeof call_mgmt_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, .bmCapabilities = 0x00, .bDataInterface = 0x01,};static const struct usb_cdc_acm_descriptor acm_descriptor = { .bLength = sizeof acm_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, .bmCapabilities = 0x00,};#endif#ifndef DEV_CONFIG_CDC/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various * ways: data endpoints live in the control interface, there's no data * interface, and it's not used to talk to a cell phone radio. */static const struct usb_cdc_mdlm_desc mdlm_desc = { .bLength = sizeof mdlm_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_MDLM_TYPE, .bcdVersion = __constant_cpu_to_le16(0x0100), .bGUID = { 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, },};/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we * can't really use its struct. All we do here is say that we're using * the submode of "SAFE" which directly matches the CDC Subset. */static const u8 mdlm_detail_desc[] = { 6, USB_DT_CS_INTERFACE, USB_CDC_MDLM_DETAIL_TYPE, 0, /* "SAFE" */ 0, /* network control capabilities (none) */ 0, /* network data capabilities ("raw" encapsulation) */};#endifstatic const struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, /* this descriptor actually adds value, surprise! */ .iMACAddress = STRING_ETHADDR, .bmEthernetStatistics = __constant_cpu_to_le32 (0), /* no statistics */ .wMaxSegmentSize = __constant_cpu_to_le16 (ETH_FRAME_LEN), .wNumberMCFilters = __constant_cpu_to_le16 (0), .bNumberPowerFilters = 0,};#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)/* include the status endpoint if we can, even where it's optional. * use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one * packet, to simplify cancellation; and a big transfer interval, to * waste less bandwidth. * * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even * if they ignore the connect/disconnect notifications that real aether * can provide. more advanced cdc configurations might want to support * encapsulated commands (vendor-specific, using control-OUT). * * RNDIS requires the status endpoint, since it uses that encapsulation * mechanism for its funky RPC scheme. */#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */#define STATUS_BYTECOUNT 16 /* 8 byte header + data */static struct usb_endpoint_descriptorfs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,};#endif#ifdef DEV_CONFIG_CDC/* the default data interface has no endpoints ... */static const struct usb_interface_descriptordata_nop_intf = { .bLength = sizeof data_nop_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0,};/* ... but the "real" data interface has two bulk endpoints */static const struct usb_interface_descriptordata_intf = { .bLength = sizeof data_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, .bAlternateSetting = 1, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = STRING_DATA,};#endif#ifdef CONFIG_USB_ETH_RNDIS/* RNDIS doesn't activate by changing to the "real" altsetting */static const struct usb_interface_descriptorrndis_data_intf = { .bLength = sizeof rndis_data_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = STRING_DATA,};#endif#ifdef DEV_CONFIG_SUBSET/* * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. * * To assist host side drivers, we fancy it up a bit, and add descriptors * so some host side drivers will understand it as a "SAFE" variant. */static const struct usb_interface_descriptorsubset_data_intf = { .bLength = sizeof subset_data_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, .bInterfaceProtocol = 0, .iInterface = STRING_DATA,};#endif /* SUBSET */static struct usb_endpoint_descriptorfs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK,};static struct usb_endpoint_descriptorfs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK,};static const struct usb_descriptor_header *fs_eth_function [11] = { (struct usb_descriptor_header *) &otg_descriptor,#ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) ðer_desc, /* NOTE: status endpoint may need to be removed */ (struct usb_descriptor_header *) &fs_status_desc, /* data interface, with altsetting */ (struct usb_descriptor_header *) &data_nop_intf, (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, NULL,#endif /* DEV_CONFIG_CDC */};static inline void __init fs_subset_descriptors(void){#ifdef DEV_CONFIG_SUBSET /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; fs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc; fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc; fs_eth_function[8] = NULL;#else fs_eth_function[1] = NULL;#endif}#ifdef CONFIG_USB_ETH_RNDISstatic const struct usb_descriptor_header *fs_rndis_function [] = { (struct usb_descriptor_header *) &otg_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &call_mgmt_descriptor, (struct usb_descriptor_header *) &acm_descriptor, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) &fs_status_desc, /* data interface has no altsetting */ (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, NULL,};#endif/* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. */#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)static struct usb_endpoint_descriptorhs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,};#endif /* DEV_CONFIG_CDC */static struct usb_endpoint_descriptorhs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512),};static struct usb_endpoint_descriptorhs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512),};static struct usb_qualifier_descriptordev_qualifier = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), .bDeviceClass = USB_CLASS_COMM, .bNumConfigurations = 1,};static const struct usb_descriptor_header *hs_eth_function [11] = { (struct usb_descriptor_header *) &otg_descriptor,#ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) ðer_desc, /* NOTE: status endpoint may need to be removed */ (struct usb_descriptor_header *) &hs_status_desc, /* data interface, with altsetting */ (struct usb_descriptor_header *) &data_nop_intf, (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, NULL,#endif /* DEV_CONFIG_CDC */};static inline void __init hs_subset_descriptors(void){#ifdef DEV_CONFIG_SUBSET /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; hs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc; hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc; hs_eth_function[8] = NULL;#else hs_eth_function[1] = NULL;#endif}#ifdef CONFIG_USB_ETH_RNDISstatic const struct usb_descriptor_header *hs_rndis_function [] = { (struct usb_descriptor_header *) &otg_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &call_mgmt_descriptor, (struct usb_descriptor_header *) &acm_descriptor, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) &hs_status_desc, /* data interface has no altsetting */ (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, NULL,};#endif/* maxpacket and other transfer characteristics vary by speed. */static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, struct usb_endpoint_descriptor *fs){ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return hs; return fs;}/*-------------------------------------------------------------------------*//* descriptors that are built on-demand */static char manufacturer [50];static char product_desc [40] = DRIVER_DESC;static char serial_number [20];/* address that the host will use ... usually assigned at random */static char ethaddr [2 * ETH_ALEN + 1];/* static strings, in UTF-8 */static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, product_desc, }, { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, { STRING_ETHADDR, ethaddr, },#ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, { STRING_CONTROL, "CDC Communications Control", },#endif#ifdef DEV_CONFIG_SUBSET { STRING_SUBSET, "CDC Ethernet Subset", },#endif#ifdef CONFIG_USB_ETH_RNDIS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -