net: smsc95xx: Add driver-model support
authorSimon Glass <sjg@chromium.org>
Wed, 8 Jul 2015 02:53:42 +0000 (20:53 -0600)
committerSimon Glass <sjg@chromium.org>
Thu, 6 Aug 2015 13:44:28 +0000 (07:44 -0600)
Add support for driver model, so that CONFIG_DM_ETH can be defined and used
with this driver.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/usb/eth/smsc95xx.c

index b0c610dcdd8cc77e2b51a78ce830a4729822f769..1dcd088b8dfc4772ff2d621774aa04767fc13eff 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2015 Google, Inc
  * Copyright (c) 2011 The Chromium OS Authors.
  * Copyright (C) 2009 NVIDIA, Corporation
  * Copyright (C) 2007-2008 SMSC (Steve Glendinning)
@@ -7,6 +8,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <usb.h>
 
 #define TURBO_MODE
 
+#ifndef CONFIG_DM_ETH
 /* local vars */
 static int curr_eth_dev; /* index for name of next device detected */
+#endif
 
 /* driver private */
 struct smsc95xx_private {
+#ifdef CONFIG_DM_ETH
+       struct ueth_data ueth;
+#endif
        size_t rx_urb_size;  /* maximum USB URB size */
        u32 mac_cr;  /* MAC control register value */
        int have_hwaddr;  /* 1 if we have a hardware MAC address */
@@ -714,6 +721,7 @@ static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length)
        return err;
 }
 
+#ifndef CONFIG_DM_ETH
 /*
  * Smsc95xx callbacks
  */
@@ -931,3 +939,137 @@ int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
        eth->priv = ss;
        return 1;
 }
+#endif /* !CONFIG_DM_ETH */
+
+#ifdef CONFIG_DM_ETH
+static int smsc95xx_eth_start(struct udevice *dev)
+{
+       struct usb_device *udev = dev_get_parentdata(dev);
+       struct smsc95xx_private *priv = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+
+       /* Driver-model Ethernet ensures we have this */
+       priv->have_hwaddr = 1;
+
+       return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr);
+}
+
+void smsc95xx_eth_stop(struct udevice *dev)
+{
+       debug("** %s()\n", __func__);
+}
+
+int smsc95xx_eth_send(struct udevice *dev, void *packet, int length)
+{
+       struct smsc95xx_private *priv = dev_get_priv(dev);
+
+       return smsc95xx_send_common(&priv->ueth, packet, length);
+}
+
+int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct smsc95xx_private *priv = dev_get_priv(dev);
+       struct ueth_data *ueth = &priv->ueth;
+       uint8_t *ptr;
+       int ret, len;
+       u32 packet_len;
+
+       len = usb_ether_get_rx_bytes(ueth, &ptr);
+       debug("%s: first try, len=%d\n", __func__, len);
+       if (!len) {
+               if (!(flags & ETH_RECV_CHECK_DEVICE))
+                       return -EAGAIN;
+               ret = usb_ether_receive(ueth, RX_URB_SIZE);
+               if (ret == -EAGAIN)
+                       return ret;
+
+               len = usb_ether_get_rx_bytes(ueth, &ptr);
+               debug("%s: second try, len=%d\n", __func__, len);
+       }
+
+       /*
+        * 1st 4 bytes contain the length of the actual data plus error info.
+        * Extract data length.
+        */
+       if (len < sizeof(packet_len)) {
+               debug("Rx: incomplete packet length\n");
+               goto err;
+       }
+       memcpy(&packet_len, ptr, sizeof(packet_len));
+       le32_to_cpus(&packet_len);
+       if (packet_len & RX_STS_ES_) {
+               debug("Rx: Error header=%#x", packet_len);
+               goto err;
+       }
+       packet_len = ((packet_len & RX_STS_FL_) >> 16);
+
+       if (packet_len > len - sizeof(packet_len)) {
+               debug("Rx: too large packet: %d\n", packet_len);
+               goto err;
+       }
+
+       *packetp = ptr + sizeof(packet_len);
+       return packet_len;
+
+err:
+       usb_ether_advance_rxbuf(ueth, -1);
+       return -EINVAL;
+}
+
+static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+       struct smsc95xx_private *priv = dev_get_priv(dev);
+
+       packet_len = ALIGN(packet_len, 4);
+       usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+       return 0;
+}
+
+int smsc95xx_write_hwaddr(struct udevice *dev)
+{
+       struct usb_device *udev = dev_get_parentdata(dev);
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct smsc95xx_private *priv = dev_get_priv(dev);
+
+       return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr);
+}
+
+static int smsc95xx_eth_probe(struct udevice *dev)
+{
+       struct smsc95xx_private *priv = dev_get_priv(dev);
+       struct ueth_data *ueth = &priv->ueth;
+
+       return usb_ether_register(dev, ueth, RX_URB_SIZE);
+}
+
+static const struct eth_ops smsc95xx_eth_ops = {
+       .start  = smsc95xx_eth_start,
+       .send   = smsc95xx_eth_send,
+       .recv   = smsc95xx_eth_recv,
+       .free_pkt = smsc95xx_free_pkt,
+       .stop   = smsc95xx_eth_stop,
+       .write_hwaddr = smsc95xx_write_hwaddr,
+};
+
+U_BOOT_DRIVER(smsc95xx_eth) = {
+       .name   = "smsc95xx_eth",
+       .id     = UCLASS_ETH,
+       .probe = smsc95xx_eth_probe,
+       .ops    = &smsc95xx_eth_ops,
+       .priv_auto_alloc_size = sizeof(struct smsc95xx_private),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id smsc95xx_eth_id_table[] = {
+       { USB_DEVICE(0x05ac, 0x1402) },
+       { USB_DEVICE(0x0424, 0xec00) }, /* LAN9512/LAN9514 Ethernet */
+       { USB_DEVICE(0x0424, 0x9500) }, /* LAN9500 Ethernet */
+       { USB_DEVICE(0x0424, 0x9730) }, /* LAN9730 Ethernet (HSIC) */
+       { USB_DEVICE(0x0424, 0x9900) }, /* SMSC9500 USB Ethernet (SAL10) */
+       { USB_DEVICE(0x0424, 0x9e00) }, /* LAN9500A Ethernet */
+       { }             /* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table);
+#endif