};
 
 static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
 /*-------------------------------------------------------------------------*/
 static struct usb_function *f_acm;
 static struct usb_function_instance *fi_serial;
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       status = ecm_bind_config(c, hostaddr);
+       status = ecm_bind_config(c, hostaddr, the_dev);
        if (status < 0)
                return status;
 
        }
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* set up serial link layer */
        status = gserial_alloc_line(&tty_line);
 fail1:
        gserial_free_line(tty_line);
 fail0:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
        usb_put_function(f_acm);
        usb_put_function_instance(fi_serial);
        gserial_free_line(tty_line);
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
 
 };
 
 static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
 /*-------------------------------------------------------------------------*/
 
 /*
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       return rndis_bind_config(c, hostaddr);
+       return rndis_bind_config(c, hostaddr, the_dev);
 }
 
 static struct usb_configuration rndis_config_driver = {
        }
 
        if (use_eem)
-               return eem_bind_config(c);
+               return eem_bind_config(c, the_dev);
        else if (can_support_ecm(c->cdev->gadget))
-               return ecm_bind_config(c, hostaddr);
+               return ecm_bind_config(c, hostaddr, the_dev);
        else
-               return geth_bind_config(c, hostaddr);
+               return geth_bind_config(c, hostaddr, the_dev);
 }
 
 static struct usb_configuration eth_config_driver = {
        int                     status;
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* set up main config label and device descriptor */
        if (use_eem) {
        return 0;
 
 fail:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
 static int __exit eth_unbind(struct usb_composite_dev *cdev)
 {
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
 
  * for calling @gether_cleanup() before module unload.
  */
 int
-ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        struct f_ecm    *ecm;
        int             status;
        snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
        ecm_string_defs[1].s = ecm->ethaddr;
 
+       ecm->port.ioport = dev;
        ecm->port.cdc_filter = DEFAULT_FILTER;
 
        ecm->port.func.name = "cdc_ethernet";
 
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init eem_bind_config(struct usb_configuration *c)
+int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
 {
        struct f_eem    *eem;
        int             status;
        if (!eem)
                return -ENOMEM;
 
+       eem->port.ioport = dev;
        eem->port.cdc_filter = DEFAULT_FILTER;
 
        eem->port.func.name = "cdc_eem";
 
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        struct f_ncm    *ncm;
        int             status;
 
        spin_lock_init(&ncm->lock);
        ncm_reset_values(ncm);
+       ncm->port.ioport = dev;
        ncm->port.is_fixed = true;
 
        ncm->port.func.name = "cdc_network";
 
 
 int
 rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
-                               u32 vendorID, const char *manufacturer)
+               u32 vendorID, const char *manufacturer, struct eth_dev *dev)
 {
        struct f_rndis  *rndis;
        int             status;
        rndis->vendorID = vendorID;
        rndis->manufacturer = manufacturer;
 
+       rndis->port.ioport = dev;
        /* RNDIS activates when the host changes this filter */
        rndis->port.cdc_filter = 0;
 
 
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        struct f_gether *geth;
        int             status;
        snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
        geth_string_defs[1].s = geth->ethaddr;
 
+       geth->port.ioport = dev;
        geth->port.cdc_filter = DEFAULT_FILTER;
 
        geth->port.func.name = "cdc_subset";
 
 #define pr_fmt(fmt) "g_ffs: " fmt
 
 #include <linux/module.h>
-
 /*
  * kbuild is not very cooperative with respect to linking separately
  * compiled library objects into one module.  So for now we won't use
 #  include "u_ether.c"
 
 static u8 gfs_hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
 #  ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
 #  endif
 #else
-#  define gether_cleanup() do { } while (0)
-#  define gether_setup(gadget, hostaddr)   ((int)0)
+#  define the_dev      NULL
+#  define gether_cleanup(dev) do { } while (0)
 #  define gfs_hostaddr NULL
+struct eth_dev;
 #endif
 
 #include "f_fs.c"
 
 struct gfs_configuration {
        struct usb_configuration c;
-       int (*eth)(struct usb_configuration *c, u8 *ethaddr);
+       int (*eth)(struct usb_configuration *c, u8 *ethaddr,
+                       struct eth_dev *dev);
 } gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
 
        if (missing_funcs)
                return -ENODEV;
-
-       ret = gether_setup(cdev->gadget, gfs_hostaddr);
-       if (unlikely(ret < 0))
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+       the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
+#endif
+       if (IS_ERR(the_dev)) {
+               ret = PTR_ERR(the_dev);
                goto error_quick;
+       }
        gfs_ether_setup = true;
 
        ret = usb_string_ids_tab(cdev, gfs_strings);
        for (i = 0; i < func_num; i++)
                functionfs_unbind(ffs_tab[i].ffs_data);
 error:
-       gether_cleanup();
+       gether_cleanup(the_dev);
 error_quick:
        gfs_ether_setup = false;
        return ret;
         * do...?
         */
        if (gfs_ether_setup)
-               gether_cleanup();
+               gether_cleanup(the_dev);
        gfs_ether_setup = false;
 
        for (i = func_num; --i; )
        }
 
        if (gc->eth) {
-               ret = gc->eth(c, gfs_hostaddr);
+               ret = gc->eth(c, gfs_hostaddr, the_dev);
                if (unlikely(ret < 0))
                        return ret;
        }
 
 #ifdef CONFIG_USB_FUNCTIONFS_ETH
 
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        return can_support_ecm(c->cdev->gadget)
-               ? ecm_bind_config(c, ethaddr)
-               : geth_bind_config(c, ethaddr);
+               ? ecm_bind_config(c, ethaddr, dev)
+               : geth_bind_config(c, ethaddr, dev);
 }
 
 #endif
 
 
 static unsigned char tty_line;
 static struct usb_function_instance *fi_acm;
+static struct eth_dev *the_dev;
 
 /********** RNDIS **********/
 
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       ret = rndis_bind_config(c, hostaddr);
+       ret = rndis_bind_config(c, hostaddr, the_dev);
        if (ret < 0)
                return ret;
 
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       ret = ecm_bind_config(c, hostaddr);
+       ret = ecm_bind_config(c, hostaddr, the_dev);
        if (ret < 0)
                return ret;
 
        }
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* set up serial link layer */
        status = gserial_alloc_line(&tty_line);
 fail0dot5:
        gserial_free_line(tty_line);
 fail0:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
 #endif
        usb_put_function_instance(fi_acm);
        gserial_free_line(tty_line);
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
 
        NULL,
 };
 
+struct eth_dev *the_dev;
 static u8 hostaddr[ETH_ALEN];
 
 /*-------------------------------------------------------------------------*/
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       return ncm_bind_config(c, hostaddr);
+       return ncm_bind_config(c, hostaddr, the_dev);
 }
 
 static struct usb_configuration ncm_config_driver = {
        int                     status;
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
        return 0;
 
 fail:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
 static int __exit gncm_unbind(struct usb_composite_dev *cdev)
 {
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
 
 static struct usb_function *f_acm_cfg1;
 static struct usb_function *f_acm_cfg2;
 static u8 hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
 
 enum {
        TTY_PORT_OBEX0,
        if (status)
                goto err_conf;
 
-       status = ecm_bind_config(c, hostaddr);
+       status = ecm_bind_config(c, hostaddr, the_dev);
        if (status) {
                pr_debug("could not bind ecm config %d\n", status);
                goto err_ecm;
                        goto err_ether;
        }
 
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev)) {
+               status = PTR_ERR(the_dev);
                goto err_ether;
+       }
 
        status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
 err_acm_inst:
        usb_put_function_instance(fi_acm);
 err_usb:
-       gether_cleanup();
+       gether_cleanup(the_dev);
 err_ether:
        cur_line--;
        while (cur_line >= 0)
        for (i = 0; i < TTY_PORTS_MAX; i++)
                gserial_free_line(tty_lines[i]);
 
-       gether_cleanup();
+       gether_cleanup(the_dev);
 
        return 0;
 }
 
 
 struct eth_dev {
        /* lock is held while accessing port_usb
-        * or updating its backlink port_usb->ioport
         */
        spinlock_t              lock;
        struct gether           *port_usb;
        return 1;
 }
 
-static struct eth_dev *the_dev;
-
 static const struct net_device_ops eth_netdev_ops = {
        .ndo_open               = eth_open,
        .ndo_stop               = eth_stop,
  *
  * Returns negative errno, or zero on success
  */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
                const char *netname)
 {
        struct eth_dev          *dev;
        struct net_device       *net;
        int                     status;
 
-       if (the_dev)
-               return -EBUSY;
-
        net = alloc_etherdev(sizeof *dev);
        if (!net)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        dev = netdev_priv(net);
        spin_lock_init(&dev->lock);
        if (status < 0) {
                dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
                free_netdev(net);
+               dev = ERR_PTR(status);
        } else {
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               the_dev = dev;
-
                /* two kinds of host-initiated state changes:
                 *  - iff DATA transfer is active, carrier is "on"
                 *  - tx queueing enabled if open *and* carrier is "on"
                netif_carrier_off(net);
        }
 
-       return status;
+       return dev;
 }
 
 /**
  *
  * This is called to free all resources allocated by @gether_setup().
  */
-void gether_cleanup(void)
+void gether_cleanup(struct eth_dev *dev)
 {
-       if (!the_dev)
+       if (!dev)
                return;
 
-       unregister_netdev(the_dev->net);
-       flush_work(&the_dev->work);
-       free_netdev(the_dev->net);
-
-       the_dev = NULL;
+       unregister_netdev(dev->net);
+       flush_work(&dev->work);
+       free_netdev(dev->net);
 }
 
-
 /**
  * gether_connect - notify network layer that USB link is active
  * @link: the USB link, set up with endpoints, descriptors matching
  */
 struct net_device *gether_connect(struct gether *link)
 {
-       struct eth_dev          *dev = the_dev;
+       struct eth_dev          *dev = link->ioport;
        int                     result = 0;
 
        if (!dev)
 
                spin_lock(&dev->lock);
                dev->port_usb = link;
-               link->ioport = dev;
                if (netif_running(dev->net)) {
                        if (link->open)
                                link->open(link);
 
        spin_lock(&dev->lock);
        dev->port_usb = NULL;
-       link->ioport = NULL;
        spin_unlock(&dev->lock);
 }
 
 
 #include "gadget_chips.h"
 
+struct eth_dev;
 
 /*
  * This represents the USB side of an "ethernet" link, managed by a USB
                        |USB_CDC_PACKET_TYPE_DIRECTED)
 
 /* variant of gether_setup that allows customizing network device name */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
                const char *netname);
 
 /* netdev setup/teardown as directed by the gadget driver */
  *
  * Returns negative errno, or zero on success
  */
-static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+static inline struct eth_dev *gether_setup(struct usb_gadget *g,
+               u8 ethaddr[ETH_ALEN])
 {
        return gether_setup_name(g, ethaddr, "usb");
 }
 
-void gether_cleanup(void);
+void gether_cleanup(struct eth_dev *dev);
 
 /* connect/disconnect is handled by individual functions */
 struct net_device *gether_connect(struct gether *);
 }
 
 /* each configuration may bind one instance of an ethernet link */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int eem_bind_config(struct usb_configuration *c);
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
+int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
+int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
 
 #ifdef USB_ETH_RNDIS
 
 int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
-                               u32 vendorID, const char *manufacturer);
+               u32 vendorID, const char *manufacturer, struct eth_dev *dev);
 
 #else
 
 static inline int
 rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
-                               u32 vendorID, const char *manufacturer)
+               u32 vendorID, const char *manufacturer, struct eth_dev *dev)
 {
        return 0;
 }
  * for calling @gether_cleanup() before module unload.
  */
 static inline int rndis_bind_config(struct usb_configuration *c,
-                                   u8 ethaddr[ETH_ALEN])
+               u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
 {
-       return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+       return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
 }