]> git.sur5r.net Git - u-boot/blobdiff - drivers/usb/gadget/ether.c
usb: gadget: g_dnl: hold maximum string descriptor
[u-boot] / drivers / usb / gadget / ether.c
index 7e3b3ed859560ecc27ec8a373431a400ce63eddf..4137d76c42afb29a95a29b66a49798e54322af64 100644 (file)
@@ -9,18 +9,26 @@
  */
 
 #include <common.h>
-#include <asm/errno.h>
+#include <console.h>
+#include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/gadget.h>
 #include <net.h>
+#include <usb.h>
 #include <malloc.h>
+#include <memalign.h>
 #include <linux/ctype.h>
 
 #include "gadget_chips.h"
 #include "rndis.h"
 
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <dm/device-internal.h>
+
 #define USB_NET_NAME "usb_ether"
 
 #define atomic_read
@@ -73,7 +81,6 @@ unsigned packet_received, packet_sent;
 /* Based on linux 2.6.27 version */
 #define DRIVER_VERSION         "May Day 2005"
 
-static const char shortname[] = "ether";
 static const char driver_desc[] = DRIVER_DESC;
 
 #define RX_EXTRA       20              /* guard against rx overflows */
@@ -98,6 +105,9 @@ struct eth_dev {
        struct usb_gadget       *gadget;
        struct usb_request      *req;           /* for control responses */
        struct usb_request      *stat_req;      /* for cdc & rndis status */
+#ifdef CONFIG_DM_USB
+       struct udevice          *usb_udev;
+#endif
 
        u8                      config;
        struct usb_ep           *in_ep, *out_ep, *status_ep;
@@ -106,7 +116,11 @@ struct eth_dev {
 
        struct usb_request      *tx_req, *rx_req;
 
+#ifndef CONFIG_DM_ETH
        struct eth_device       *net;
+#else
+       struct udevice          *net;
+#endif
        struct net_device_stats stats;
        unsigned int            tx_qlen;
 
@@ -131,9 +145,18 @@ struct eth_dev {
  */
 
 /*-------------------------------------------------------------------------*/
-static struct eth_dev l_ethdev;
-static struct eth_device l_netdev;
-static struct usb_gadget_driver eth_driver;
+struct ether_priv {
+       struct eth_dev ethdev;
+#ifndef CONFIG_DM_ETH
+       struct eth_device netdev;
+#else
+       struct udevice *netdev;
+#endif
+       struct usb_gadget_driver eth_driver;
+};
+
+struct ether_priv eth_priv;
+struct ether_priv *l_priv = &eth_priv;
 
 /*-------------------------------------------------------------------------*/
 
@@ -253,7 +276,7 @@ static inline int BITRATE(struct usb_gadget *g)
 #if defined(CONFIG_USBNET_MANUFACTURER)
 static char *iManufacturer = CONFIG_USBNET_MANUFACTURER;
 #else
-static char *iManufacturer = "U-boot";
+static char *iManufacturer = "U-Boot";
 #endif
 
 /* These probably need to be configurable. */
@@ -484,6 +507,7 @@ static const struct usb_cdc_mdlm_desc mdlm_desc = {
  * 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.
  */
+#ifdef CONFIG_USB_ETH_SUBSET
 static const u8 mdlm_detail_desc[] = {
        6,
        USB_DT_CS_INTERFACE,
@@ -493,6 +517,7 @@ static const u8 mdlm_detail_desc[] = {
        0,      /* network control capabilities (none) */
        0,      /* network data capabilities ("raw" encapsulation) */
 };
+#endif
 
 #endif
 
@@ -1132,7 +1157,7 @@ static void eth_status_complete(struct usb_ep *ep, struct usb_request *req)
                        event->bNotificationType, value);
                if (event->bNotificationType ==
                                USB_CDC_NOTIFY_SPEED_CHANGE) {
-                       l_ethdev.network_started = 1;
+                       dev->network_started = 1;
                        printf("USB network up!\n");
                }
        }
@@ -1320,7 +1345,7 @@ eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                         * that network is working. So we signalize it
                         * here.
                         */
-                       l_ethdev.network_started = 1;
+                       dev->network_started = 1;
                        debug("USB network up!\n");
                        goto done_set_intf;
                }
@@ -1522,7 +1547,7 @@ static int rx_submit(struct eth_dev *dev, struct usb_request *req,
         * RNDIS headers involve variable numbers of LE32 values.
         */
 
-       req->buf = (u8 *) NetRxPackets[0];
+       req->buf = (u8 *)net_rx_packets[0];
        req->length = size;
        req->complete = rx_complete;
 
@@ -1645,13 +1670,13 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
        if (!eth_is_promisc (dev)) {
                u8              *dest = skb->data;
 
-               if (is_multicast_ether_addr(dest)) {
+               if (is_multicast_ethaddr(dest)) {
                        u16     type;
 
                        /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
                         * SET_ETHERNET_MULTICAST_FILTERS requests
                         */
-                       if (is_broadcast_ether_addr(dest))
+                       if (is_broadcast_ethaddr(dest))
                                type = USB_CDC_PACKET_TYPE_BROADCAST;
                        else
                                type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
@@ -1820,10 +1845,10 @@ static void rndis_control_ack_complete(struct usb_ep *ep,
                debug("rndis control ack complete --> %d, %d/%d\n",
                        req->status, req->actual, req->length);
 
-       if (!l_ethdev.network_started) {
+       if (!dev->network_started) {
                if (rndis_get_state(dev->rndis_config)
                                == RNDIS_DATA_INITIALIZED) {
-                       l_ethdev.network_started = 1;
+                       dev->network_started = 1;
                        printf("USB RNDIS network up!\n");
                }
        }
@@ -1836,9 +1861,14 @@ static void rndis_control_ack_complete(struct usb_ep *ep,
 
 static char rndis_resp_buf[8] __attribute__((aligned(sizeof(__le32))));
 
+#ifndef CONFIG_DM_ETH
 static int rndis_control_ack(struct eth_device *net)
+#else
+static int rndis_control_ack(struct udevice *net)
+#endif
 {
-       struct eth_dev          *dev = &l_ethdev;
+       struct ether_priv       *priv = (struct ether_priv *)net->priv;
+       struct eth_dev          *dev = &priv->ethdev;
        int                     length;
        struct usb_request      *resp = dev->stat_req;
 
@@ -1942,7 +1972,7 @@ static int is_eth_addr_valid(char *str)
                }
 
                /* Now check the contents. */
-               return is_valid_ether_addr(ea);
+               return is_valid_ethaddr(ea);
        }
        return 0;
 }
@@ -1971,7 +2001,7 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
                        num |= (nibble(*str++));
                        dev_addr[i] = num;
                }
-               if (is_valid_ether_addr(dev_addr))
+               if (is_valid_ethaddr(dev_addr))
                        return 0;
        }
        return 1;
@@ -1979,12 +2009,15 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
 
 static int eth_bind(struct usb_gadget *gadget)
 {
-       struct eth_dev          *dev = &l_ethdev;
+       struct eth_dev          *dev = &l_priv->ethdev;
        u8                      cdc = 1, zlp = 1, rndis = 1;
        struct usb_ep           *in_ep, *out_ep, *status_ep = NULL;
        int                     status = -ENOMEM;
        int                     gcnum;
        u8                      tmp[7];
+#ifdef CONFIG_DM_ETH
+       struct eth_pdata        *pdata = dev_get_platdata(l_priv->netdev);
+#endif
 
        /* these flags are only ever cleared; compiler take note */
 #ifndef        CONFIG_USB_ETH_CDC
@@ -2172,7 +2205,11 @@ autoconf_fail:
 
 
        /* network device setup */
-       dev->net = &l_netdev;
+#ifndef CONFIG_DM_ETH
+       dev->net = &l_priv->netdev;
+#else
+       dev->net = l_priv->netdev;
+#endif
 
        dev->cdc = cdc;
        dev->zlp = zlp;
@@ -2181,6 +2218,7 @@ autoconf_fail:
        dev->out_ep = out_ep;
        dev->status_ep = status_ep;
 
+       memset(tmp, 0, sizeof(tmp));
        /*
         * Module params for these addresses should come from ID proms.
         * The host side address is used with CDC and RNDIS, and commonly
@@ -2188,10 +2226,13 @@ autoconf_fail:
         * host side code for the SAFE thing cares -- its original BLAN
         * thing didn't, Sharp never assigned those addresses on Zaurii.
         */
+#ifndef CONFIG_DM_ETH
        get_ether_addr(dev_addr, dev->net->enetaddr);
-
-       memset(tmp, 0, sizeof(tmp));
        memcpy(tmp, dev->net->enetaddr, sizeof(dev->net->enetaddr));
+#else
+       get_ether_addr(dev_addr, pdata->enetaddr);
+       memcpy(tmp, pdata->enetaddr, sizeof(pdata->enetaddr));
+#endif
 
        get_ether_addr(host_addr, dev->host_mac);
 
@@ -2252,10 +2293,11 @@ autoconf_fail:
                status_ep ? " STATUS " : "",
                status_ep ? status_ep->name : ""
                );
-       printf("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-               dev->net->enetaddr[0], dev->net->enetaddr[1],
-               dev->net->enetaddr[2], dev->net->enetaddr[3],
-               dev->net->enetaddr[4], dev->net->enetaddr[5]);
+#ifndef CONFIG_DM_ETH
+       printf("MAC %pM\n", dev->net->enetaddr);
+#else
+       printf("MAC %pM\n", pdata->enetaddr);
+#endif
 
        if (cdc || rndis)
                printf("HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -2300,17 +2342,39 @@ fail:
 
 /*-------------------------------------------------------------------------*/
 
-static int usb_eth_init(struct eth_device *netdev, bd_t *bd)
+#ifdef CONFIG_DM_USB
+int dm_usb_init(struct eth_dev *e_dev)
 {
-       struct eth_dev *dev = &l_ethdev;
+       struct udevice *dev = NULL;
+       int ret;
+
+       ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev);
+       if (!dev || ret) {
+               error("No USB device found\n");
+               return -ENODEV;
+       }
+
+       e_dev->usb_udev = dev;
+
+       return ret;
+}
+#endif
+
+static int _usb_eth_init(struct ether_priv *priv)
+{
+       struct eth_dev *dev = &priv->ethdev;
        struct usb_gadget *gadget;
        unsigned long ts;
        unsigned long timeout = USB_CONNECT_TIMEOUT;
 
-       if (!netdev) {
-               error("received NULL ptr");
-               goto fail;
+#ifdef CONFIG_DM_USB
+       if (dm_usb_init(dev)) {
+               error("USB ether not found\n");
+               return -ENODEV;
        }
+#else
+       board_usb_init(0, USB_INIT_DEVICE);
+#endif
 
        /* Configure default mac-addresses for the USB ethernet device */
 #ifdef CONFIG_USBNET_DEV_ADDR
@@ -2337,7 +2401,15 @@ static int usb_eth_init(struct eth_device *netdev, bd_t *bd)
                goto fail;
        }
 
-       if (usb_gadget_register_driver(&eth_driver) < 0)
+       priv->eth_driver.speed          = DEVSPEED;
+       priv->eth_driver.bind           = eth_bind;
+       priv->eth_driver.unbind         = eth_unbind;
+       priv->eth_driver.setup          = eth_setup;
+       priv->eth_driver.reset          = eth_disconnect;
+       priv->eth_driver.disconnect     = eth_disconnect;
+       priv->eth_driver.suspend        = eth_suspend;
+       priv->eth_driver.resume         = eth_resume;
+       if (usb_gadget_register_driver(&priv->eth_driver) < 0)
                goto fail;
 
        dev->network_started = 0;
@@ -2352,7 +2424,7 @@ static int usb_eth_init(struct eth_device *netdev, bd_t *bd)
                timeout = simple_strtoul(getenv("cdc_connect_timeout"),
                                                NULL, 10) * CONFIG_SYS_HZ;
        ts = get_timer(0);
-       while (!l_ethdev.network_started) {
+       while (!dev->network_started) {
                /* Handle control-c and timeouts */
                if (ctrlc() || (get_timer(ts) > timeout)) {
                        error("The remote end did not respond in time.");
@@ -2368,11 +2440,11 @@ fail:
        return -1;
 }
 
-static int usb_eth_send(struct eth_device *netdev, void *packet, int length)
+static int _usb_eth_send(struct ether_priv *priv, void *packet, int length)
 {
        int                     retval;
        void                    *rndis_pkt = NULL;
-       struct eth_dev          *dev = &l_ethdev;
+       struct eth_dev          *dev = &priv->ethdev;
        struct usb_request      *req = dev->tx_req;
        unsigned long ts;
        unsigned long timeout = USB_CONNECT_TIMEOUT;
@@ -2437,33 +2509,16 @@ drop:
        return -ENOMEM;
 }
 
-static int usb_eth_recv(struct eth_device *netdev)
+static int _usb_eth_recv(struct ether_priv *priv)
 {
-       struct eth_dev *dev = &l_ethdev;
-
        usb_gadget_handle_interrupts(0);
 
-       if (packet_received) {
-               debug("%s: packet received\n", __func__);
-               if (dev->rx_req) {
-                       NetReceive(NetRxPackets[0], dev->rx_req->length);
-                       packet_received = 0;
-
-                       rx_submit(dev, dev->rx_req, 0);
-               } else
-                       error("dev->rx_req invalid");
-       }
        return 0;
 }
 
-void usb_eth_halt(struct eth_device *netdev)
+void _usb_eth_halt(struct ether_priv *priv)
 {
-       struct eth_dev *dev = &l_ethdev;
-
-       if (!netdev) {
-               error("received NULL ptr");
-               return;
-       }
+       struct eth_dev *dev = &priv->ethdev;
 
        /* If the gadget not registered, simple return */
        if (!dev->gadget)
@@ -2490,25 +2545,64 @@ void usb_eth_halt(struct eth_device *netdev)
                dev->network_started = 0;
        }
 
-       usb_gadget_unregister_driver(&eth_driver);
+       usb_gadget_unregister_driver(&priv->eth_driver);
+#ifndef CONFIG_DM_USB
+       board_usb_cleanup(0, USB_INIT_DEVICE);
+#endif
 }
 
-static struct usb_gadget_driver eth_driver = {
-       .speed          = DEVSPEED,
+#ifndef CONFIG_DM_ETH
+static int usb_eth_init(struct eth_device *netdev, bd_t *bd)
+{
+       struct ether_priv *priv = (struct ether_priv *)netdev->priv;
 
-       .bind           = eth_bind,
-       .unbind         = eth_unbind,
+       return _usb_eth_init(priv);
+}
 
-       .setup          = eth_setup,
-       .disconnect     = eth_disconnect,
+static int usb_eth_send(struct eth_device *netdev, void *packet, int length)
+{
+       struct ether_priv       *priv = (struct ether_priv *)netdev->priv;
 
-       .suspend        = eth_suspend,
-       .resume         = eth_resume,
-};
+       return _usb_eth_send(priv, packet, length);
+}
+
+static int usb_eth_recv(struct eth_device *netdev)
+{
+       struct ether_priv *priv = (struct ether_priv *)netdev->priv;
+       struct eth_dev *dev = &priv->ethdev;
+       int ret;
+
+       ret = _usb_eth_recv(priv);
+       if (ret) {
+               error("error packet receive\n");
+               return ret;
+       }
+
+       if (!packet_received)
+               return 0;
+
+       if (dev->rx_req) {
+               net_process_received_packet(net_rx_packets[0],
+                                           dev->rx_req->length);
+       } else {
+               error("dev->rx_req invalid");
+       }
+       packet_received = 0;
+       rx_submit(dev, dev->rx_req, 0);
+
+       return 0;
+}
+
+void usb_eth_halt(struct eth_device *netdev)
+{
+       struct ether_priv *priv = (struct ether_priv *)netdev->priv;
+
+       _usb_eth_halt(priv);
+}
 
 int usb_eth_initialize(bd_t *bi)
 {
-       struct eth_device *netdev = &l_netdev;
+       struct eth_device *netdev = &l_priv->netdev;
 
        strlcpy(netdev->name, USB_NET_NAME, sizeof(netdev->name));
 
@@ -2516,6 +2610,7 @@ int usb_eth_initialize(bd_t *bi)
        netdev->send = usb_eth_send;
        netdev->recv = usb_eth_recv;
        netdev->halt = usb_eth_halt;
+       netdev->priv = l_priv;
 
 #ifdef CONFIG_MCAST_TFTP
   #error not supported
@@ -2523,3 +2618,114 @@ int usb_eth_initialize(bd_t *bi)
        eth_register(netdev);
        return 0;
 }
+#else
+static int usb_eth_start(struct udevice *dev)
+{
+       struct ether_priv *priv = dev_get_priv(dev);
+
+       return _usb_eth_init(priv);
+}
+
+static int usb_eth_send(struct udevice *dev, void *packet, int length)
+{
+       struct ether_priv *priv = dev_get_priv(dev);
+
+       return _usb_eth_send(priv, packet, length);
+}
+
+static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct ether_priv *priv = dev_get_priv(dev);
+       struct eth_dev *ethdev = &priv->ethdev;
+       int ret;
+
+       ret = _usb_eth_recv(priv);
+       if (ret) {
+               error("error packet receive\n");
+               return ret;
+       }
+
+       if (packet_received) {
+               if (ethdev->rx_req) {
+                       *packetp = (uchar *)net_rx_packets[0];
+                       return ethdev->rx_req->length;
+               } else {
+                       error("dev->rx_req invalid");
+                       return -EFAULT;
+               }
+       }
+
+       return -EAGAIN;
+}
+
+static int usb_eth_free_pkt(struct udevice *dev, uchar *packet,
+                                  int length)
+{
+       struct ether_priv *priv = dev_get_priv(dev);
+       struct eth_dev *ethdev = &priv->ethdev;
+
+       packet_received = 0;
+
+       return rx_submit(ethdev, ethdev->rx_req, 0);
+}
+
+static void usb_eth_stop(struct udevice *dev)
+{
+       struct ether_priv *priv = dev_get_priv(dev);
+
+       _usb_eth_halt(priv);
+}
+
+static int usb_eth_probe(struct udevice *dev)
+{
+       struct ether_priv *priv = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+
+       priv->netdev = dev;
+       l_priv = priv;
+
+       get_ether_addr(CONFIG_USBNET_DEVADDR, pdata->enetaddr);
+       eth_setenv_enetaddr("usbnet_devaddr", pdata->enetaddr);
+
+       return 0;
+}
+
+static const struct eth_ops usb_eth_ops = {
+       .start          = usb_eth_start,
+       .send           = usb_eth_send,
+       .recv           = usb_eth_recv,
+       .free_pkt       = usb_eth_free_pkt,
+       .stop           = usb_eth_stop,
+};
+
+int usb_ether_init(void)
+{
+       struct udevice *dev;
+       struct udevice *usb_dev;
+       int ret;
+
+       ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &usb_dev);
+       if (!usb_dev || ret) {
+               error("No USB device found\n");
+               return ret;
+       }
+
+       ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev);
+       if (!dev || ret) {
+               error("usb - not able to bind usb_ether device\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+U_BOOT_DRIVER(eth_usb) = {
+       .name   = "usb_ether",
+       .id     = UCLASS_ETH,
+       .probe  = usb_eth_probe,
+       .ops    = &usb_eth_ops,
+       .priv_auto_alloc_size = sizeof(struct ether_priv),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+       .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* CONFIG_DM_ETH */