summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-07-07 20:53:42 -0600
committerSimon Glass <sjg@chromium.org>2015-08-06 07:44:28 -0600
commit0990fcb772192af615f23cd78bbfc081ec40236b (patch)
tree3cf93fa114ef5a3136bc3674d5d67b6119478040 /drivers/usb
parent527298c4b51963c7f3ed072d26fcb3e1bcafd092 (diff)
downloadtalos-obmc-uboot-0990fcb772192af615f23cd78bbfc081ec40236b.tar.gz
talos-obmc-uboot-0990fcb772192af615f23cd78bbfc081ec40236b.zip
net: smsc95xx: Add driver-model support
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/eth/smsc95xx.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index b0c610dcdd..1dcd088b8d 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -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>
@@ -137,11 +139,16 @@
#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
OpenPOWER on IntegriCloud