ether.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,360 行 · 第 1/5 页

C
2,360
字号
/* * ether.c -- Ethernet gadget driver, with CDC and non-CDC options * * Copyright (C) 2003-2005 David Brownell * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */// #define DEBUG 1// #define VERBOSE#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/utsname.h>#include <linux/device.h>#include <linux/moduleparam.h>#include <linux/ctype.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <linux/usb/ch9.h>#include <linux/usb/cdc.h>#include <linux/usb_gadget.h>#include <linux/random.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include "gadget_chips.h"/*-------------------------------------------------------------------------*//* * Ethernet gadget driver -- with CDC and non-CDC options * Builds on hardware support for a full duplex link. * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB.  Real hardware tends to use the same framing protocol but look * different for control features.  This driver strongly prefers to use * this USB-IF standard as its open-systems interoperability solution; * most host side USB stacks (except from Microsoft) support it. * * There's some hardware that can't talk CDC.  We make that hardware * implement a "minimalist" vendor-agnostic CDC core:  same framing, but * link-level setup only requires activating the configuration.  Only the * endpoint descriptors, and product/vendor IDs, are relevant; no control * operations are available.  Linux supports it, but other host operating * systems may not.  (This is a subset of CDC Ethernet.) * * It turns out that if you add a few descriptors to that "CDC Subset", * (Windows) host side drivers from MCCI can treat it as one submode of * a proprietary scheme called "SAFE" ... without needing to know about * specific product/vendor IDs.  So we do that, making it easier to use * those MS-Windows drivers.  Those added descriptors make it resemble a * CDC MDLM device, but they don't change device behavior at all.  (See * MCCI Engineering report 950198 "SAFE Networking Functions".) * * A third option is also in use.  Rather than CDC Ethernet, or something * simpler, Microsoft pushes their own approach: RNDIS.  The published * RNDIS specs are ambiguous and appear to be incomplete, and are also * needlessly complex. */#define DRIVER_DESC		"Ethernet Gadget"#define DRIVER_VERSION		"May Day 2005"static const char shortname [] = "ether";static const char driver_desc [] = DRIVER_DESC;#define RX_EXTRA	20		/* guard against rx overflows */#include "rndis.h"/* CDC and RNDIS support the same host-chosen outgoing packet filters. */#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \			|USB_CDC_PACKET_TYPE_PROMISCUOUS \			|USB_CDC_PACKET_TYPE_DIRECTED)/*-------------------------------------------------------------------------*/struct eth_dev {	spinlock_t		lock;	struct usb_gadget	*gadget;	struct usb_request	*req;		/* for control responses */	struct usb_request	*stat_req;	/* for cdc & rndis status */	u8			config;	struct usb_ep		*in_ep, *out_ep, *status_ep;	const struct usb_endpoint_descriptor				*in, *out, *status;	spinlock_t		req_lock;	struct list_head	tx_reqs, rx_reqs;	struct net_device	*net;	struct net_device_stats	stats;	atomic_t		tx_qlen;	struct work_struct	work;	unsigned		zlp:1;	unsigned		cdc:1;	unsigned		rndis:1;	unsigned		suspended:1;	u16			cdc_filter;	unsigned long		todo;#define	WORK_RX_MEMORY		0	int			rndis_config;	u8			host_mac [ETH_ALEN];};/* This version autoconfigures as much as possible at run-time. * * It also ASSUMES a self-powered device, without remote wakeup, * although remote wakeup support would make sense. *//*-------------------------------------------------------------------------*//* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!! * Instead:  allocate your own, using normal USB-IF procedures. *//* Thanks to NetChip Technologies for donating this product ID. * It's for devices with only CDC Ethernet configurations. */#define CDC_VENDOR_NUM	0x0525		/* NetChip */#define CDC_PRODUCT_NUM	0xa4a1		/* Linux-USB Ethernet Gadget *//* For hardware that can't talk CDC, we use the same vendor ID that * ARM Linux has used for ethernet-over-usb, both with sa1100 and * with pxa250.  We're protocol-compatible, if the host-side drivers * use the endpoint descriptors.  bcdDevice (version) is nonzero, so * drivers that need to hard-wire endpoint numbers have a hook. * * The protocol is a minimal subset of CDC Ether, which works on any bulk * hardware that's not deeply broken ... even on hardware that can't talk * RNDIS (like SA-1100, with no interrupt endpoint, or anything that * doesn't handle control-OUT). */#define	SIMPLE_VENDOR_NUM	0x049f#define	SIMPLE_PRODUCT_NUM	0x505a/* For hardware that can talk RNDIS and either of the above protocols, * use this ID ... the windows INF files will know it.  Unless it's * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose * the non-RNDIS configuration. */#define RNDIS_VENDOR_NUM	0x0525	/* NetChip */#define RNDIS_PRODUCT_NUM	0xa4a2	/* Ethernet/RNDIS Gadget *//* Some systems will want different product identifers published in the * device descriptor, either numbers or strings or both.  These string * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */static ushort idVendor;module_param(idVendor, ushort, S_IRUGO);MODULE_PARM_DESC(idVendor, "USB Vendor ID");static ushort idProduct;module_param(idProduct, ushort, S_IRUGO);MODULE_PARM_DESC(idProduct, "USB Product ID");static ushort bcdDevice;module_param(bcdDevice, ushort, S_IRUGO);MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");static char *iManufacturer;module_param(iManufacturer, charp, S_IRUGO);MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");static char *iProduct;module_param(iProduct, charp, S_IRUGO);MODULE_PARM_DESC(iProduct, "USB Product string");static char *iSerialNumber;module_param(iSerialNumber, charp, S_IRUGO);MODULE_PARM_DESC(iSerialNumber, "SerialNumber");/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */static char *dev_addr;module_param(dev_addr, charp, S_IRUGO);MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");/* this address is invisible to ifconfig */static char *host_addr;module_param(host_addr, charp, S_IRUGO);MODULE_PARM_DESC(host_addr, "Host Ethernet Address");/*-------------------------------------------------------------------------*//* Include CDC support if we could run on CDC-capable hardware. */#define DEV_CONFIG_CDC/* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. *//*-------------------------------------------------------------------------*//* "main" config is either CDC, or its simple subset */static inline int is_cdc(struct eth_dev *dev){	return 1;		/* only cdc possible */}/* "secondary" RNDIS config may sometimes be activated */static inline int rndis_active(struct eth_dev *dev){	return dev->rndis;}#define	subset_active(dev)	(!is_cdc(dev) && !rndis_active(dev))#define	cdc_active(dev)		( is_cdc(dev) && !rndis_active(dev))#define DEFAULT_QLEN	2	/* double buffering by default *//* peak bulk transfer bits-per-second */#define	HS_BPS		(13 * 512 * 8 * 1000 * 8)#define	FS_BPS		(19 *  64 * 1 * 1000 * 8)#define	DEVSPEED	USB_SPEED_HIGHstatic unsigned qmult = 5;module_param (qmult, uint, S_IRUGO|S_IWUSR);/* for dual-speed hardware, use deeper queues at highspeed */#define qlen(gadget) \	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))/* also defer IRQs on highspeed TX */#define TX_DELAY	qmultstatic inline int BITRATE(struct usb_gadget *g){	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;}/*-------------------------------------------------------------------------*/#define xprintk(d,level,fmt,args...) \	printk(level "%s: " fmt , (d)->net->name , ## args)#define DEBUG(dev,fmt,args...) \	do { } while (0)#define VDEBUG(dev,fmt,args...) \	do { } while (0)#define ERROR(dev,fmt,args...) \	xprintk(dev , KERN_ERR , fmt , ## args)#define WARN(dev,fmt,args...) \	xprintk(dev , KERN_WARNING , fmt , ## args)#define INFO(dev,fmt,args...) \	xprintk(dev , KERN_INFO , fmt , ## args)/*-------------------------------------------------------------------------*//* USB DRIVER HOOKUP (to the hardware driver, below us), mostly * ep0 implementation:  descriptors, config management, setup(). * also optional class-specific notification interrupt transfer. *//* * DESCRIPTORS ... most are static, but strings and (full) configuration * descriptors are built on demand.  For now we do either full CDC, or * our simple subset, with RNDIS as an optional second configuration. * * RNDIS includes some CDC ACM descriptors ... like CDC Ethernet.  But * the class descriptors match a modem (they're ignored; it's really just * Ethernet functionality), they don't need the NOP altsetting, and the * status transfer endpoint isn't optional. */#define STRING_MANUFACTURER		1#define STRING_PRODUCT			2#define STRING_ETHADDR			3#define STRING_DATA			4#define STRING_CONTROL			5#define STRING_RNDIS_CONTROL		6#define STRING_CDC			7#define STRING_SUBSET			8#define STRING_RNDIS			9#define STRING_SERIALNUMBER		10/* holds our biggest descriptor (or RNDIS response) */#define USB_BUFSIZ	256/* * This device advertises one configuration, eth_config, unless RNDIS * is enabled (rndis_config) on hardware supporting at least two configs. * * NOTE:  Controllers like superh_udc should probably be able to use * an RNDIS-only configuration. * * FIXME define some higher-powered configurations to make it easier * to recharge batteries ... */#define DEV_CONFIG_VALUE	1	/* cdc or subset */#define DEV_RNDIS_CONFIG_VALUE	2	/* rndis; optional */static struct usb_device_descriptordevice_desc = {	.bLength =		sizeof device_desc,	.bDescriptorType =	USB_DT_DEVICE,	.bcdUSB =		__constant_cpu_to_le16 (0x0200),	.bDeviceClass =		USB_CLASS_COMM,	.bDeviceSubClass =	0,	.bDeviceProtocol =	0,	.idVendor =		__constant_cpu_to_le16 (CDC_VENDOR_NUM),	.idProduct =		__constant_cpu_to_le16 (CDC_PRODUCT_NUM),	.iManufacturer =	STRING_MANUFACTURER,	.iProduct =		STRING_PRODUCT,	.bNumConfigurations =	1,};static struct usb_otg_descriptorotg_descriptor = {	.bLength =		sizeof otg_descriptor,	.bDescriptorType =	USB_DT_OTG,	.bmAttributes =		USB_OTG_SRP,};static struct usb_config_descriptoreth_config = {	.bLength =		sizeof eth_config,	.bDescriptorType =	USB_DT_CONFIG,	/* compute wTotalLength on the fly */	.bNumInterfaces =	2,	.bConfigurationValue =	DEV_CONFIG_VALUE,	.iConfiguration =	STRING_CDC,	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,	.bMaxPower =		50,};static struct usb_config_descriptorrndis_config = {	.bLength =              sizeof rndis_config,	.bDescriptorType =      USB_DT_CONFIG,	/* 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,};/* * 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. */static 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,};static 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,};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 */};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?