📄 ether.c
字号:
.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,};#endif#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)static 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),};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#ifdef DEV_CONFIG_CDCstatic 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,};#endif#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. */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_VENDOR_SPEC, .bInterfaceSubClass = 0, .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 fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; fs_eth_function[4] = 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#ifdef CONFIG_USB_GADGET_DUALSPEED/* * 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 hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; hs_eth_function[4] = 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. */#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))#else/* if there's no high speed support, maxpacket doesn't change. */#define ep_desc(g,hs,fs) (((void)(g)), (fs))static inline void __init hs_subset_descriptors(void){}#endif /* !CONFIG_USB_GADGET_DUALSPEED *//*-------------------------------------------------------------------------*//* descriptors that are built on-demand */static char manufacturer [50];static char product_desc [40] = DRIVER_DESC;#ifdef DEV_CONFIG_CDC/* address that the host will use ... usually assigned at random */static char ethaddr [2 * ETH_ALEN + 1];#endif/* static strings, in UTF-8 */static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, product_desc, }, { STRING_DATA, "Ethernet Data", },#ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, { STRING_ETHADDR, ethaddr, }, { STRING_CONTROL, "CDC Communications Control", },#endif#ifdef DEV_CONFIG_SUBSET { STRING_SUBSET, "CDC Ethernet Subset", },#endif#ifdef CONFIG_USB_ETH_RNDIS { STRING_RNDIS, "RNDIS", }, { STRING_RNDIS_CONTROL, "RNDIS Communications Control", },#endif { } /* end of list */};static struct usb_gadget_strings stringtab = { .language = 0x0409, /* en-us */ .strings = strings,};/* * one config, two interfaces: control, data. * complications: class descriptors, and an altsetting. */static intconfig_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, int is_otg){ int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function;#ifdef CONFIG_USB_GADGET_DUALSPEED int hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs;#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)#else#define which_fn(t) (fs_ ## t ## _function)#endif if (index >= device_desc.bNumConfigurations) return -EINVAL;#ifdef CONFIG_USB_ETH_RNDIS /* list the RNDIS config first, to make Microsoft's drivers * happy. DOCSIS 1.0 needs this too. */ if (device_desc.bNumConfigurations == 2 && index == 0) { config = &rndis_config; function = which_fn (rndis); } else#endif { config = ð_config; function = which_fn (eth); } /* for now, don't advertise srp-only devices */ if (!is_otg) function++; len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len;}/*-------------------------------------------------------------------------*/static void eth_start (struct eth_dev *dev, gfp_t gfp_flags);static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags);static intset_ether_config (struct eth_dev *dev, gfp_t gfp_flags){ int result = 0; struct usb_gadget *gadget = dev->gadget;#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* status endpoint used for RNDIS and (optionally) CDC */ if (!subset_active(dev) && dev->status_ep) { dev->status = ep_desc (gadget, &hs_status_desc, &fs_status_desc); dev->status_ep->driver_data = dev; result = usb_ep_enable (dev->status_ep, dev->status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -