ether.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,360 行 · 第 1/5 页
C
2,360 行
static 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,};static 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,};/* 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,};/* 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,};/* 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,};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, /* "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,};static inline void __init fs_subset_descriptors(void){ fs_eth_function[1] = NULL;}static 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,};/* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. */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,};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, /* "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,};static inline void __init hs_subset_descriptors(void){ hs_eth_function[1] = NULL;}static 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,};/* maxpacket and other transfer characteristics vary by speed. */#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(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, }, { STRING_CDC, "CDC Ethernet", }, { STRING_CONTROL, "CDC Communications Control", }, { STRING_RNDIS, "RNDIS", }, { STRING_RNDIS_CONTROL, "RNDIS Communications Control", }, { } /* 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; 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) if (index >= device_desc.bNumConfigurations) return -EINVAL; /* 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 { 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; /* 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); if (result != 0) { DEBUG (dev, "enable %s --> %d\n", dev->status_ep->name, result); goto done; } } dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data * endpoints in the default altsetting for the interface. * so we don't activate them yet. Reset from SET_INTERFACE. * * Strictly speaking RNDIS should work the same: activation is * a side effect of setting a packet filter. Deactivation is * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG. */ if (!cdc_active(dev)) { result = usb_ep_enable (dev->in_ep, dev->in); if (result != 0) { DEBUG(dev, "enable %s --> %d\n", dev->in_ep->name, result); goto done; } result = usb_ep_enable (dev->out_ep, dev->out); if (result != 0) { DEBUG (dev, "enable %s --> %d\n", dev->out_ep->name, result); goto done; } }done: if (result == 0) result = alloc_requests (dev, qlen (gadget), gfp_flags); /* on error, disable any endpoints */ if (result < 0) { if (!subset_active(dev)) (void) usb_ep_disable (dev->status_ep); dev->status = NULL; (void) usb_ep_disable (dev->in_ep); (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; } else /* activate non-CDC configs right away * this isn't strictly according to the RNDIS spec */ if (!cdc_active (dev)) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); eth_start (dev, GFP_ATOMIC); spin_lock (&dev->lock); } } if (result == 0) DEBUG (dev, "qlen %d\n", qlen (gadget)); /* caller is responsible for cleanup on error */ return result;}static void eth_reset_config (struct eth_dev *dev){ struct usb_request *req; if (dev->config == 0) return; DEBUG (dev, "%s\n", __FUNCTION__); netif_stop_queue (dev->net); netif_carrier_off (dev->net); rndis_uninit(dev->rndis_config); /* disable endpoints, forcing (synchronous) completion of * pending i/o. then free the requests. */ if (dev->in) { usb_ep_disable (dev->in_ep); spin_lock(&dev->req_lock); while (likely (!list_empty (&dev->tx_reqs))) { req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); spin_unlock(&dev->req_lock); usb_ep_free_request (dev->in_ep, req); spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); } if (dev->out) { usb_ep_disable (dev->out_ep); spin_lock(&dev->req_lock); while (likely (!list_empty (&dev->rx_reqs))) { req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del (&req->list); spin_unlock(&dev->req_lock); usb_ep_free_request (dev->out_ep, req); spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); } if (dev->status) { usb_ep_disable (dev->status_ep);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?