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 *) &ether_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 *) &ether_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 = &eth_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 + -
显示快捷键?