// SPDX-License-Identifier: GPL-2.0+ /* * ether.c -- Ethernet gadget driver, with CDC and non-CDC options * * Copyright (C) 2003-2005,2008 David Brownell * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger * Copyright (C) 2008 Nokia Corporation */ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> #include <linux/netdevice.h> #if defined USB_ETH_RNDIS # undef USB_ETH_RNDIS #endif #ifdef CONFIG_USB_ETH_RNDIS #define USB_ETH_RNDIS … #endif #include "u_ether.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. * * This is sometimes called "CDC ECM" (Ethernet Control Model) to support * TLA-soup. "CDC ACM" (Abstract Control Model) is for modems, and a new * "CDC EEM" (Ethernet Emulation Model) is starting to spread. * * There's some hardware that can't talk CDC ECM. 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. They borrow more from CDC ACM than CDC ECM. */ #define DRIVER_DESC … #define DRIVER_VERSION … #ifdef USB_ETH_RNDIS #define PREFIX … #else #define PREFIX … #endif /* * This driver aims for interoperability by using CDC ECM unless * * can_support_ecm() * * returns false, in which case it supports the CDC Subset. By default, * that returns true; most hardware has no problems with CDC ECM, that's * a good default. Previous versions of this driver had no default; this * version changes that, removing overhead for new controller support. * * IF YOUR HARDWARE CAN'T SUPPORT CDC ECM, UPDATE THAT ROUTINE! */ static inline bool has_rndis(void) { … } #include <linux/module.h> #include "u_ecm.h" #include "u_gether.h" #ifdef USB_ETH_RNDIS #include "u_rndis.h" #include "rndis.h" #else #define rndis_borrow_net … #endif #include "u_eem.h" /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(…); USB_ETHERNET_MODULE_PARAMETERS(…); /* 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 … #define CDC_PRODUCT_NUM … /* 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 … #define SIMPLE_PRODUCT_NUM … /* 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 … #define RNDIS_PRODUCT_NUM … /* For EEM gadgets */ #define EEM_VENDOR_NUM … #define EEM_PRODUCT_NUM … /*-------------------------------------------------------------------------*/ static struct usb_device_descriptor device_desc = …; static const struct usb_descriptor_header *otg_desc[2]; static struct usb_string strings_dev[] = …; static struct usb_gadget_strings stringtab_dev = …; static struct usb_gadget_strings *dev_strings[] = …; static struct usb_function_instance *fi_ecm; static struct usb_function *f_ecm; static struct usb_function_instance *fi_eem; static struct usb_function *f_eem; static struct usb_function_instance *fi_geth; static struct usb_function *f_geth; static struct usb_function_instance *fi_rndis; static struct usb_function *f_rndis; /*-------------------------------------------------------------------------*/ /* * We may not have an RNDIS configuration, but if we do it needs to be * the first one present. That's to make Microsoft's drivers happy, * and to follow DOCSIS 1.0 (cable modem standard). */ static int rndis_do_config(struct usb_configuration *c) { … } static struct usb_configuration rndis_config_driver = …; /*-------------------------------------------------------------------------*/ #ifdef CONFIG_USB_ETH_EEM static bool use_eem = …; #else static bool use_eem; #endif module_param(use_eem, bool, 0); MODULE_PARM_DESC(…) …; /* * We _always_ have an ECM, CDC Subset, or EEM configuration. */ static int eth_do_config(struct usb_configuration *c) { … } static struct usb_configuration eth_config_driver = …; /*-------------------------------------------------------------------------*/ static int eth_bind(struct usb_composite_dev *cdev) { … } static int eth_unbind(struct usb_composite_dev *cdev) { … } static struct usb_composite_driver eth_driver = …; module_usb_composite_driver(…); MODULE_DESCRIPTION(…); MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …;