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>
This commit is contained in:
Simon Glass 2015-07-07 20:53:42 -06:00
parent 527298c4b5
commit 0990fcb772

View 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>
@ -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