123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- /*
- * u_qc_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack
- *
- * Copyright (C) 2003-2005,2008 David Brownell
- * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
- * Copyright (C) 2008 Nokia Corporation
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- *
- * 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 VERBOSE_DEBUG */
- #include <linux/kernel.h>
- #include <linux/gfp.h>
- #include <linux/device.h>
- #include <linux/ctype.h>
- #include <linux/etherdevice.h>
- #include <linux/ethtool.h>
- #include "u_ether.h"
- /*
- * This component encapsulates the Ethernet link glue needed to provide
- * one (!) network link through the USB gadget stack, normally "usb0".
- *
- * The control and data models are handled by the function driver which
- * connects to this code; such as CDC Ethernet (ECM or EEM),
- * "CDC Subset", or RNDIS. That includes all descriptor and endpoint
- * management.
- *
- * Link level addressing is handled by this component using module
- * parameters; if no such parameters are provided, random link level
- * addresses are used. Each end of the link uses one address. The
- * host end address is exported in various ways, and is often recorded
- * in configuration databases.
- *
- * The driver which assembles each configuration using such a link is
- * responsible for ensuring that each configuration includes at most one
- * instance of is network link. (The network layer provides ways for
- * this single "physical" link to be used by multiple virtual links.)
- *
- * This utilities is based on Ethernet-over-USB link layer utilities and
- * contains MSM specific implementation.
- */
- #define UETH__VERSION "29-May-2008"
- struct eth_qc_dev {
- /* lock is held while accessing port_usb
- * or updating its backlink port_usb->ioport
- */
- spinlock_t lock;
- struct qc_gether *port_usb;
- struct net_device *net;
- struct usb_gadget *gadget;
- unsigned header_len;
- bool zlp;
- u8 host_mac[ETH_ALEN];
- };
- /*-------------------------------------------------------------------------*/
- #undef DBG
- #undef VDBG
- #undef ERROR
- #undef INFO
- #define xprintk(d, level, fmt, args...) \
- printk(level "%s: " fmt , (d)->net->name , ## args)
- #ifdef DEBUG
- #undef DEBUG
- #define DBG(dev, fmt, args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
- #else
- #define DBG(dev, fmt, args...) \
- do { } while (0)
- #endif /* DEBUG */
- #ifdef VERBOSE_DEBUG
- #define VDBG DBG
- #else
- #define VDBG(dev, fmt, args...) \
- do { } while (0)
- #endif /* DEBUG */
- #define ERROR(dev, fmt, args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
- #define INFO(dev, fmt, args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
- /*-------------------------------------------------------------------------*/
- /* NETWORK DRIVER HOOKUP (to the layer above this driver) */
- static int ueth_qc_change_mtu(struct net_device *net, int new_mtu)
- {
- struct eth_qc_dev *dev = netdev_priv(net);
- unsigned long flags;
- int status = 0;
- /* don't change MTU on "live" link (peer won't know) */
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb)
- status = -EBUSY;
- else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
- status = -ERANGE;
- else
- net->mtu = new_mtu;
- spin_unlock_irqrestore(&dev->lock, flags);
- return status;
- }
- static void eth_qc_get_drvinfo(struct net_device *net,
- struct ethtool_drvinfo *p)
- {
- struct eth_qc_dev *dev = netdev_priv(net);
- strlcpy(p->driver, "g_qc_ether", sizeof p->driver);
- strlcpy(p->version, UETH__VERSION, sizeof p->version);
- strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
- strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
- }
- static const struct ethtool_ops qc_ethtool_ops = {
- .get_drvinfo = eth_qc_get_drvinfo,
- .get_link = ethtool_op_get_link,
- };
- static netdev_tx_t eth_qc_start_xmit(struct sk_buff *skb,
- struct net_device *net)
- {
- return NETDEV_TX_OK;
- }
- static int eth_qc_open(struct net_device *net)
- {
- struct eth_qc_dev *dev = netdev_priv(net);
- struct qc_gether *link;
- DBG(dev, "%s\n", __func__);
- if (netif_carrier_ok(dev->net)) {
- /* Force the netif to send the RTM_NEWLINK event
- * that in use to notify on the USB cable status.
- */
- netif_carrier_off(dev->net);
- netif_carrier_on(dev->net);
- netif_wake_queue(dev->net);
- }
- spin_lock_irq(&dev->lock);
- link = dev->port_usb;
- if (link && link->open)
- link->open(link);
- spin_unlock_irq(&dev->lock);
- return 0;
- }
- static int eth_qc_stop(struct net_device *net)
- {
- struct eth_qc_dev *dev = netdev_priv(net);
- unsigned long flags;
- struct qc_gether *link = dev->port_usb;
- VDBG(dev, "%s\n", __func__);
- netif_stop_queue(net);
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb && link->close)
- link->close(link);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- /*-------------------------------------------------------------------------*/
- /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
- static char *qc_dev_addr;
- module_param(qc_dev_addr, charp, S_IRUGO);
- MODULE_PARM_DESC(qc_dev_addr, "QC Device Ethernet Address");
- /* this address is invisible to ifconfig */
- static char *qc_host_addr;
- module_param(qc_host_addr, charp, S_IRUGO);
- MODULE_PARM_DESC(qc_host_addr, "QC Host Ethernet Address");
- static int get_qc_ether_addr(const char *str, u8 *dev_addr)
- {
- if (str) {
- unsigned i;
- for (i = 0; i < 6; i++) {
- unsigned char num;
- if ((*str == '.') || (*str == ':'))
- str++;
- num = hex_to_bin(*str++) << 4;
- num |= hex_to_bin(*str++);
- dev_addr[i] = num;
- }
- if (is_valid_ether_addr(dev_addr))
- return 0;
- }
- random_ether_addr(dev_addr);
- return 1;
- }
- static const struct net_device_ops eth_qc_netdev_ops = {
- .ndo_open = eth_qc_open,
- .ndo_stop = eth_qc_stop,
- .ndo_start_xmit = eth_qc_start_xmit,
- .ndo_change_mtu = ueth_qc_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- };
- static struct device_type qc_gadget_type = {
- .name = "gadget",
- };
- void gether_qc_get_macs(u8 dev_mac[ETH_ALEN], u8 host_mac[ETH_ALEN])
- {
- if (get_qc_ether_addr(qc_dev_addr, dev_mac))
- pr_debug("using random dev_mac ethernet address\n");
- if (get_qc_ether_addr(qc_host_addr, host_mac))
- pr_debug("using random host_mac ethernet address\n");
- }
- /**
- * gether_qc_setup - initialize one ethernet-over-usb link
- * @g: gadget to associated with these links
- * @ethaddr: NULL, or a buffer in which the ethernet address of the
- * host side of the link is recorded
- * Context: may sleep
- *
- * This sets up the single network link that may be exported by a
- * gadget driver using this framework. The link layer addresses are
- * set up using module parameters.
- *
- * Returns negative errno, or zero on success
- */
- int gether_qc_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
- {
- return gether_qc_setup_name(g, ethaddr, "usb");
- }
- /**
- * gether_qc_setup_name - initialize one ethernet-over-usb link
- * @g: gadget to associated with these links
- * @ethaddr: NULL, or a buffer in which the ethernet address of the
- * host side of the link is recorded
- * @netname: name for network device (for example, "usb")
- * Context: may sleep
- *
- * This sets up the single network link that may be exported by a
- * gadget driver using this framework. The link layer addresses are
- * set up using module parameters.
- *
- * Returns negative errno, or zero on success
- */
- int gether_qc_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
- const char *netname)
- {
- struct eth_qc_dev *dev;
- struct net_device *net;
- int status;
- net = alloc_etherdev(sizeof *dev);
- if (!net)
- return -ENOMEM;
- dev = netdev_priv(net);
- spin_lock_init(&dev->lock);
- /* network device setup */
- dev->net = net;
- snprintf(net->name, sizeof(net->name), "%s%%d", netname);
- if (get_qc_ether_addr(qc_dev_addr, net->dev_addr))
- dev_warn(&g->dev,
- "using random %s ethernet address\n", "self");
- if (get_qc_ether_addr(qc_host_addr, dev->host_mac))
- dev_warn(&g->dev,
- "using random %s ethernet address\n", "host");
- if (ethaddr)
- memcpy(ethaddr, dev->host_mac, ETH_ALEN);
- net->netdev_ops = ð_qc_netdev_ops;
- SET_ETHTOOL_OPS(net, &qc_ethtool_ops);
- netif_carrier_off(net);
- dev->gadget = g;
- SET_NETDEV_DEV(net, &g->dev);
- SET_NETDEV_DEVTYPE(net, &qc_gadget_type);
- status = register_netdev(net);
- if (status < 0) {
- dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
- free_netdev(net);
- } else {
- INFO(dev, "MAC %pM\n", net->dev_addr);
- INFO(dev, "HOST MAC %pM\n", dev->host_mac);
- }
- return status;
- }
- /**
- * gether_qc_cleanup_name - remove Ethernet-over-USB device
- * @netname: name for network device (for example, "usb")
- * Context: may sleep
- *
- * This is called to free all resources allocated by @gether_qc_setup().
- */
- void gether_qc_cleanup_name(const char *netname)
- {
- struct net_device *net_dev;
- /* Extract the eth_qc_dev from the net device */
- net_dev = dev_get_by_name(&init_net, netname);
- if (net_dev) {
- dev_put(net_dev);
- unregister_netdev(net_dev);
- free_netdev(net_dev);
- }
- }
- /**
- * gether_qc_connect_name - notify network layer that USB link
- * is active
- * @link: the USB link, set up with endpoints, descriptors matching
- * current device speed, and any framing wrapper(s) set up.
- * @netname: name for network device (for example, "usb")
- * Context: irqs blocked
- * @netif_enable: if true, net interface will be turned on
- *
- * This is called to let the network layer know the connection
- * is active ("carrier detect").
- */
- struct net_device *gether_qc_connect_name(struct qc_gether *link,
- const char *netname, bool netif_enable)
- {
- struct net_device *net_dev;
- struct eth_qc_dev *dev;
- /* Extract the eth_qc_dev from the net device */
- net_dev = dev_get_by_name(&init_net, netname);
- if (!net_dev)
- return ERR_PTR(-EINVAL);
- dev_put(net_dev);
- dev = netdev_priv(net_dev);
- if (!dev)
- return ERR_PTR(-EINVAL);
- dev->zlp = link->is_zlp_ok;
- dev->header_len = link->header_len;
- spin_lock(&dev->lock);
- dev->port_usb = link;
- link->ioport = dev;
- if (netif_running(dev->net)) {
- if (link->open)
- link->open(link);
- } else {
- if (link->close)
- link->close(link);
- }
- spin_unlock(&dev->lock);
- if (netif_enable) {
- netif_carrier_on(dev->net);
- if (netif_running(dev->net))
- netif_wake_queue(dev->net);
- }
- return dev->net;
- }
- /**
- * gether_qc_disconnect_name - notify network layer that USB
- * link is inactive
- * @link: the USB link, on which gether_connect() was called
- * @netname: name for network device (for example, "usb")
- * Context: irqs blocked
- *
- * This is called to let the network layer know the connection
- * went inactive ("no carrier").
- *
- * On return, the state is as if gether_connect() had never been called.
- */
- void gether_qc_disconnect_name(struct qc_gether *link, const char *netname)
- {
- struct net_device *net_dev;
- struct eth_qc_dev *dev;
- /* Extract the eth_qc_dev from the net device */
- net_dev = dev_get_by_name(&init_net, netname);
- if (!net_dev)
- return;
- dev_put(net_dev);
- dev = netdev_priv(net_dev);
- if (!dev)
- return;
- DBG(dev, "%s\n", __func__);
- netif_stop_queue(dev->net);
- netif_carrier_off(dev->net);
- spin_lock(&dev->lock);
- dev->port_usb = NULL;
- link->ioport = NULL;
- spin_unlock(&dev->lock);
- }
|