📄 ether.c
字号:
/* * 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/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_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. * 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 "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"#ifndef CONFIG_USB_ETH_RNDIS#define rndis_uninit(x) do{}while(0)#define rndis_deregister(c) do{}while(0)#define rndis_exit() do{}while(0)#endif/* 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; 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 __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(dev_addr, "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#ifdef CONFIG_USB_GADGET_AT91#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#ifdef CONFIG_USB_GADGET_S3C2410#define DEV_CONFIG_CDC#endif/*-------------------------------------------------------------------------*//* "main" config is either CDC, or its simple subset */static inline int is_cdc(struct eth_dev *dev){#if !defined(DEV_CONFIG_SUBSET) return 1; /* only cdc possible */#elif !defined (DEV_CONFIG_CDC) return 0; /* only subset possible */#else return dev->cdc; /* depends on what hardware we found */#endif}/* "secondary" RNDIS config may sometimes be activated */static inline int rndis_active(struct eth_dev *dev){#ifdef CONFIG_USB_ETH_RNDIS return dev->rndis;#else return 0;#endif}#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)#ifdef CONFIG_USB_GADGET_DUALSPEED#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;}#else /* full speed (low speed doesn't do bulk) */#define DEVSPEED USB_SPEED_FULL#define qlen(gadget) DEFAULT_QLENstatic inline int BITRATE(struct usb_gadget *g){ return FS_BPS;}#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/* 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,};#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 = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -