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 + -
显示快捷键?