usb: gadget: u_ether: construct with default values and add setters/getters
[deliverable/linux.git] / drivers / usb / gadget / u_ether.c
index 5f9dacfe6be5f68f1061e4f7619c6811e0fc1ef8..6d3ccdc09e1eaa4481d40b494ed087a78a5563fa 100644 (file)
@@ -78,6 +78,7 @@ struct eth_dev {
 
        bool                    zlp;
        u8                      host_mac[ETH_ALEN];
+       u8                      dev_mac[ETH_ALEN];
 };
 
 /*-------------------------------------------------------------------------*/
@@ -716,6 +717,17 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
        return 1;
 }
 
+static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
+{
+       if (len < 18)
+               return -EINVAL;
+
+       snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
+                dev_addr[0], dev_addr[1], dev_addr[2],
+                dev_addr[3], dev_addr[4], dev_addr[5]);
+       return 18;
+}
+
 static const struct net_device_ops eth_netdev_ops = {
        .ndo_open               = eth_open,
        .ndo_stop               = eth_stop,
@@ -796,7 +808,8 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               /* two kinds of host-initiated state changes:
+               /*
+                * two kinds of host-initiated state changes:
                 *  - iff DATA transfer is active, carrier is "on"
                 *  - tx queueing enabled if open *and* carrier is "on"
                 */
@@ -807,6 +820,176 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
 }
 EXPORT_SYMBOL(gether_setup_name);
 
+struct net_device *gether_setup_name_default(const char *netname)
+{
+       struct net_device       *net;
+       struct eth_dev          *dev;
+
+       net = alloc_etherdev(sizeof(*dev));
+       if (!net)
+               return ERR_PTR(-ENOMEM);
+
+       dev = netdev_priv(net);
+       spin_lock_init(&dev->lock);
+       spin_lock_init(&dev->req_lock);
+       INIT_WORK(&dev->work, eth_work);
+       INIT_LIST_HEAD(&dev->tx_reqs);
+       INIT_LIST_HEAD(&dev->rx_reqs);
+
+       skb_queue_head_init(&dev->rx_frames);
+
+       /* network device setup */
+       dev->net = net;
+       dev->qmult = QMULT_DEFAULT;
+       snprintf(net->name, sizeof(net->name), "%s%%d", netname);
+
+       eth_random_addr(dev->dev_mac);
+       pr_warn("using random %s ethernet address\n", "self");
+       eth_random_addr(dev->host_mac);
+       pr_warn("using random %s ethernet address\n", "host");
+
+       net->netdev_ops = &eth_netdev_ops;
+
+       SET_ETHTOOL_OPS(net, &ops);
+       SET_NETDEV_DEVTYPE(net, &gadget_type);
+
+       return net;
+}
+EXPORT_SYMBOL(gether_setup_name_default);
+
+int gether_register_netdev(struct net_device *net)
+{
+       struct eth_dev *dev;
+       struct usb_gadget *g;
+       struct sockaddr sa;
+       int status;
+
+       if (!net->dev.parent)
+               return -EINVAL;
+       dev = netdev_priv(net);
+       g = dev->gadget;
+       status = register_netdev(net);
+       if (status < 0) {
+               dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
+               return status;
+       } else {
+               INFO(dev, "HOST MAC %pM\n", dev->host_mac);
+
+               /* 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);
+       }
+       sa.sa_family = net->type;
+       memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN);
+       rtnl_lock();
+       status = dev_set_mac_address(net, &sa);
+       rtnl_unlock();
+       if (status)
+               pr_warn("cannot set self ethernet address: %d\n", status);
+       else
+               INFO(dev, "MAC %pM\n", dev->dev_mac);
+
+       return status;
+}
+EXPORT_SYMBOL(gether_register_netdev);
+
+void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
+{
+       struct eth_dev *dev;
+
+       dev = netdev_priv(net);
+       dev->gadget = g;
+       SET_NETDEV_DEV(net, &g->dev);
+}
+EXPORT_SYMBOL(gether_set_gadget);
+
+int gether_set_dev_addr(struct net_device *net, const char *dev_addr)
+{
+       struct eth_dev *dev;
+       u8 new_addr[ETH_ALEN];
+
+       dev = netdev_priv(net);
+       if (get_ether_addr(dev_addr, new_addr))
+               return -EINVAL;
+       memcpy(dev->dev_mac, new_addr, ETH_ALEN);
+       return 0;
+}
+EXPORT_SYMBOL(gether_set_dev_addr);
+
+int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len)
+{
+       struct eth_dev *dev;
+
+       dev = netdev_priv(net);
+       return get_ether_addr_str(dev->dev_mac, dev_addr, len);
+}
+EXPORT_SYMBOL(gether_get_dev_addr);
+
+int gether_set_host_addr(struct net_device *net, const char *host_addr)
+{
+       struct eth_dev *dev;
+       u8 new_addr[ETH_ALEN];
+
+       dev = netdev_priv(net);
+       if (get_ether_addr(host_addr, new_addr))
+               return -EINVAL;
+       memcpy(dev->host_mac, new_addr, ETH_ALEN);
+       return 0;
+}
+EXPORT_SYMBOL(gether_set_host_addr);
+
+int gether_get_host_addr(struct net_device *net, char *host_addr, int len)
+{
+       struct eth_dev *dev;
+
+       dev = netdev_priv(net);
+       return get_ether_addr_str(dev->host_mac, host_addr, len);
+}
+EXPORT_SYMBOL(gether_get_host_addr);
+
+int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)
+{
+       struct eth_dev *dev;
+
+       if (len < 13)
+               return -EINVAL;
+
+       dev = netdev_priv(net);
+       snprintf(host_addr, len, "%pm", dev->host_mac);
+
+       return strlen(host_addr);
+}
+EXPORT_SYMBOL(gether_get_host_addr_cdc);
+
+void gether_set_qmult(struct net_device *net, unsigned qmult)
+{
+       struct eth_dev *dev;
+
+       dev = netdev_priv(net);
+       dev->qmult = qmult;
+}
+EXPORT_SYMBOL(gether_set_qmult);
+
+unsigned gether_get_qmult(struct net_device *net)
+{
+       struct eth_dev *dev;
+
+       dev = netdev_priv(net);
+       return dev->qmult;
+}
+EXPORT_SYMBOL(gether_get_qmult);
+
+int gether_get_ifname(struct net_device *net, char *name, int len)
+{
+       rtnl_lock();
+       strlcpy(name, netdev_name(net), len);
+       rtnl_unlock();
+       return strlen(name);
+}
+EXPORT_SYMBOL(gether_get_ifname);
+
 /**
  * gether_cleanup - remove Ethernet-over-USB device
  * Context: may sleep
This page took 0.02768 seconds and 5 git commands to generate.