📄 ether.c
字号:
/* * ether.c -- Ethernet gadget driver, with CDC and non-CDC options * * Copyright (C) 2003-2004 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/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.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_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. * Linux supports it, but other host operating systems may not. * (This is a subset of CDC Ethernet.) * * 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 "Equinox 2004"static const char shortname [] = "ether";static const char driver_desc [] = DRIVER_DESC;#define RX_EXTRA 20 /* guard against rx overflows */#ifdef CONFIG_USB_ETH_RNDIS#include "rndis.h"#else#define rndis_init() 0#define rndis_exit() do{}while(0)#endif/*-------------------------------------------------------------------------*/struct eth_dev { spinlock_t lock; struct usb_gadget *gadget; struct usb_request *req; /* for control responses */ u8 config; struct usb_ep *in_ep, *out_ep, *status_ep; const struct usb_endpoint_descriptor *in, *out, *status; 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. */static const char *EP_IN_NAME;static const char *EP_OUT_NAME;static const char *EP_STATUS_NAME;/*-------------------------------------------------------------------------*//* 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 __initdata idVendor;module_param(idVendor, ushort, S_IRUGO);MODULE_PARM_DESC(idVendor, "USB Vendor ID");static ushort __initdata idProduct;module_param(idProduct, ushort, S_IRUGO);MODULE_PARM_DESC(idProduct, "USB Product ID");static ushort __initdata bcdDevice;module_param(bcdDevice, ushort, S_IRUGO);MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");static char *__initdata iManufacturer;module_param(iManufacturer, charp, S_IRUGO);MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");static char *__initdata iProduct;module_param(iProduct, charp, S_IRUGO);MODULE_PARM_DESC(iProduct, "USB Product string");/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */static char *__initdata dev_addr;module_param(dev_addr, charp, S_IRUGO);MODULE_PARM_DESC(iProduct, "Device Ethernet Address");/* this address is invisible to ifconfig */static char *__initdata 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. */#ifdef CONFIG_USB_GADGET_NET2280#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_DUMMY_HCD#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_GOKU#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_LH7A40X#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_MQ11XX#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_OMAP#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_N9604#define DEV_CONFIG_CDC#endif#ifdef CONFIG_USB_GADGET_PXA27X#define DEV_CONFIG_CDC#endif/* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. */#ifdef CONFIG_USB_GADGET_PXA2XX#define DEV_CONFIG_SUBSET#endif#ifdef CONFIG_USB_GADGET_SH#define DEV_CONFIG_SUBSET#endif#ifdef CONFIG_USB_GADGET_SA1100/* use non-CDC for backwards compatibility */#define DEV_CONFIG_SUBSET#endif/*-------------------------------------------------------------------------*/#define DEFAULT_QLEN 2 /* double buffering by default */#ifdef CONFIG_USB_GADGET_DUALSPEEDstatic 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 qmult#define BITRATE(g) ((g->speed == USB_SPEED_HIGH) ? 4800000 : 120000)#else /* full speed (low speed doesn't do bulk) */#define qlen(gadget) DEFAULT_QLEN#define BITRATE(g) (12000)#endif/*-------------------------------------------------------------------------*/#define xprintk(d,level,fmt,args...) \ printk(level "%s: " fmt , (d)->net->name , ## args)#ifdef DEBUG#undef DEBUG#define DEBUG(dev,fmt,args...) \ xprintk(dev , KERN_DEBUG , fmt , ## args)#else#define DEBUG(dev,fmt,args...) \ do { } while (0)#endif /* DEBUG */#ifdef VERBOSE#define VDEBUG DEBUG#else#define VDEBUG(dev,fmt,args...) \ do { } while (0)#endif /* DEBUG */#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 USB_BUFSIZ 256 /* holds our biggest descriptor *//* * 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,};#ifdef CONFIG_USB_ETH_RNDISstatic struct usb_config_descriptor rndis_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,};#endif/* * 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. */#ifdef DEV_CONFIG_CDCstatic 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 = 6, /* ethernet control model */ .bInterfaceProtocol = 0, .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 = 2, /* abstract control model */ .bInterfaceProtocol = 0xff, /* vendor specific */ .iInterface = STRING_RNDIS_CONTROL,};#endif#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */struct header_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u16 bcdCDC;} __attribute__ ((packed));static const struct header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = 0, .bcdCDC = __constant_cpu_to_le16 (0x0110),};/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */struct union_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u8 bMasterInterface0; u8 bSlaveInterface0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -