// SPDX-License-Identifier: GPL-2.0+ /* * f_subset.c -- "CDC Subset" Ethernet link function driver * * Copyright (C) 2003-2005,2008 David Brownell * Copyright (C) 2008 Nokia Corporation */ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/etherdevice.h> #include "u_ether.h" #include "u_ether_configfs.h" #include "u_gether.h" /* * This function packages a simple "CDC Subset" Ethernet port with no real * control mechanisms; just raw data transfer over two bulk endpoints. * The data transfer model is exactly that of CDC Ethernet, which is * why we call it the "CDC Subset". * * Because it's not standardized, this has some interoperability issues. * They mostly relate to driver binding, since the data transfer model is * so simple (CDC Ethernet). The original versions of this protocol used * specific product/vendor IDs: byteswapped IDs for Digital Equipment's * SA-1100 "Itsy" board, which could run Linux 2.4 kernels and supported * daughtercards with USB peripheral connectors. (It was used more often * with other boards, using the Itsy identifiers.) Linux hosts recognized * this with CONFIG_USB_ARMLINUX; these devices have only one configuration * and one interface. * * At some point, MCCI defined a (nonconformant) CDC MDLM variant called * "SAFE", which happens to have a mode which is identical to the "CDC * Subset" in terms of data transfer and lack of control model. This was * adopted by later Sharp Zaurus models, and by some other software which * Linux hosts recognize with CONFIG_USB_NET_ZAURUS. * * Because Microsoft's RNDIS drivers are far from robust, we added a few * descriptors to the CDC Subset code, making this code look like a SAFE * implementation. This lets you use MCCI's host side MS-Windows drivers * if you get fed up with RNDIS. It also makes it easier for composite * drivers to work, since they can use class based binding instead of * caring about specific product and vendor IDs. */ struct f_gether { … }; static inline struct f_gether *func_to_geth(struct usb_function *f) { … } /*-------------------------------------------------------------------------*/ /* * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. * To assist host side drivers, we fancy it up a bit, and add descriptors so * some host side drivers will understand it as a "SAFE" variant. * * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various ways. * Data endpoints live in the control interface, there's no data interface. * And it's not used to talk to a cell phone radio. */ /* interface descriptor: */ static struct usb_interface_descriptor subset_data_intf = …; static struct usb_cdc_header_desc mdlm_header_desc = …; static struct usb_cdc_mdlm_desc mdlm_desc = …; /* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we * can't really use its struct. All we do here is say that we're using * the submode of "SAFE" which directly matches the CDC Subset. */ static u8 mdlm_detail_desc[] = …; static struct usb_cdc_ether_desc ether_desc = …; /* full speed support: */ static struct usb_endpoint_descriptor fs_subset_in_desc = …; static struct usb_endpoint_descriptor fs_subset_out_desc = …; static struct usb_descriptor_header *fs_eth_function[] = …; /* high speed support: */ static struct usb_endpoint_descriptor hs_subset_in_desc = …; static struct usb_endpoint_descriptor hs_subset_out_desc = …; static struct usb_descriptor_header *hs_eth_function[] = …; /* super speed support: */ static struct usb_endpoint_descriptor ss_subset_in_desc = …; static struct usb_endpoint_descriptor ss_subset_out_desc = …; static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = …; static struct usb_descriptor_header *ss_eth_function[] = …; /* string descriptors: */ static struct usb_string geth_string_defs[] = …; static struct usb_gadget_strings geth_string_table = …; static struct usb_gadget_strings *geth_strings[] = …; /*-------------------------------------------------------------------------*/ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { … } static void geth_disable(struct usb_function *f) { … } /*-------------------------------------------------------------------------*/ /* serial function driver setup/binding */ static int geth_bind(struct usb_configuration *c, struct usb_function *f) { … } static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item) { … } /* f_gether_item_ops */ USB_ETHERNET_CONFIGFS_ITEM(…); /* f_gether_opts_dev_addr */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(…); /* f_gether_opts_host_addr */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(…); /* f_gether_opts_qmult */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(…); /* f_gether_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(…); static struct configfs_attribute *gether_attrs[] = …; static const struct config_item_type gether_func_type = …; static void geth_free_inst(struct usb_function_instance *f) { … } static struct usb_function_instance *geth_alloc_inst(void) { … } static void geth_free(struct usb_function *f) { … } static void geth_unbind(struct usb_configuration *c, struct usb_function *f) { … } static struct usb_function *geth_alloc(struct usb_function_instance *fi) { … } DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc); MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …;