diff options
author | Alban Bedel <alban.bedel@avionic-design.de> | 2016-08-09 09:10:03 (GMT) |
---|---|---|
committer | Marek Vasut <marex@denx.de> | 2016-08-09 10:52:05 (GMT) |
commit | 76b2fad775ee3cb58788b11454655ba5a244ac56 (patch) | |
tree | 93df3ce675ac70c1d9077b9de7a2e98709ed984c /drivers/usb | |
parent | 620452e7aed023205d9432e0f3476906018ad688 (diff) | |
download | u-boot-76b2fad775ee3cb58788b11454655ba5a244ac56.tar.xz |
eth: asix88179: Add support for the driver model
Adjust this driver to support driver model for Ethernet.
Signed-off-by: Alban Bedel <alban.bedel@avionic-design.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/eth/asix88179.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c index f3179bc..7548269 100644 --- a/drivers/usb/eth/asix88179.c +++ b/drivers/usb/eth/asix88179.c @@ -7,6 +7,7 @@ */ #include <common.h> +#include <dm.h> #include <usb.h> #include <net.h> #include <linux/mii.h> @@ -197,10 +198,18 @@ static const struct { {7, 0xcc, 0x4c, 0x04, 8}, }; +#ifndef CONFIG_DM_ETH static int curr_eth_dev; /* index for name of next device detected */ +#endif /* driver private */ struct asix_private { +#ifdef CONFIG_DM_ETH + struct ueth_data ueth; + unsigned pkt_cnt; + uint8_t *pkt_data; + uint32_t *pkt_hdr; +#endif int flags; int rx_urb_size; int maxpacketsize; @@ -495,6 +504,7 @@ static int asix_send_common(struct ueth_data *dev, return err; } +#ifndef CONFIG_DM_ETH /* * Asix callbacks */ @@ -734,3 +744,177 @@ int ax88179_eth_get_info(struct usb_device *dev, struct ueth_data *ss, return 1; } + +#else /* !CONFIG_DM_ETH */ + +static int ax88179_eth_start(struct udevice *dev) +{ + struct asix_private *priv = dev_get_priv(dev); + + return asix_init_common(&priv->ueth, priv); +} + +void ax88179_eth_stop(struct udevice *dev) +{ + struct asix_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + + debug("** %s()\n", __func__); + + usb_ether_advance_rxbuf(ueth, -1); + priv->pkt_cnt = 0; + priv->pkt_data = NULL; + priv->pkt_hdr = NULL; +} + +int ax88179_eth_send(struct udevice *dev, void *packet, int length) +{ + struct asix_private *priv = dev_get_priv(dev); + + return asix_send_common(&priv->ueth, priv, packet, length); +} + +int ax88179_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct asix_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + int ret, len; + u16 pkt_len; + + /* No packet left, get a new one */ + if (priv->pkt_cnt == 0) { + uint8_t *ptr; + u16 pkt_cnt; + u16 hdr_off; + u32 rx_hdr; + + 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, priv->rx_urb_size); + if (ret < 0) + return ret; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: second try, len=%d\n", __func__, len); + } + + if (len < 4) { + usb_ether_advance_rxbuf(ueth, -1); + return -EMSGSIZE; + } + + rx_hdr = *(u32 *)(ptr + len - 4); + le32_to_cpus(&rx_hdr); + + pkt_cnt = (u16)rx_hdr; + if (pkt_cnt == 0) { + usb_ether_advance_rxbuf(ueth, -1); + return 0; + } + + hdr_off = (u16)(rx_hdr >> 16); + if (hdr_off > len - 4) { + usb_ether_advance_rxbuf(ueth, -1); + return -EIO; + } + + priv->pkt_cnt = pkt_cnt; + priv->pkt_data = ptr; + priv->pkt_hdr = (u32 *)(ptr + hdr_off); + debug("%s: %d packets received, pkt header at %d\n", + __func__, (int)priv->pkt_cnt, (int)hdr_off); + } + + le32_to_cpus(priv->pkt_hdr); + pkt_len = (*priv->pkt_hdr >> 16) & 0x1fff; + + *packetp = priv->pkt_data + 2; + + priv->pkt_data += (pkt_len + 7) & 0xFFF8; + priv->pkt_cnt--; + priv->pkt_hdr++; + + debug("%s: return packet of %d bytes (%d packets left)\n", + __func__, (int)pkt_len, priv->pkt_cnt); + return pkt_len; +} + +static int ax88179_free_pkt(struct udevice *dev, uchar *packet, int packet_len) +{ + struct asix_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + + if (priv->pkt_cnt == 0) + usb_ether_advance_rxbuf(ueth, -1); + + return 0; +} + +int ax88179_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct asix_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + + return asix_write_mac(ueth, pdata->enetaddr); +} + +static int ax88179_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct asix_private *priv = dev_get_priv(dev); + struct usb_device *usb_dev; + int ret; + + priv->flags = dev->driver_data; + ret = usb_ether_register(dev, &priv->ueth, AX_RX_URB_SIZE); + if (ret) + return ret; + + usb_dev = priv->ueth.pusb_dev; + priv->maxpacketsize = usb_dev->epmaxpacketout[AX_ENDPOINT_OUT]; + + /* Get the MAC address */ + ret = asix_read_mac(&priv->ueth, pdata->enetaddr); + if (ret) + return ret; + debug("MAC %pM\n", pdata->enetaddr); + + return 0; +} + +static const struct eth_ops ax88179_eth_ops = { + .start = ax88179_eth_start, + .send = ax88179_eth_send, + .recv = ax88179_eth_recv, + .free_pkt = ax88179_free_pkt, + .stop = ax88179_eth_stop, + .write_hwaddr = ax88179_write_hwaddr, +}; + +U_BOOT_DRIVER(ax88179_eth) = { + .name = "ax88179_eth", + .id = UCLASS_ETH, + .probe = ax88179_eth_probe, + .ops = &ax88179_eth_ops, + .priv_auto_alloc_size = sizeof(struct asix_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +static const struct usb_device_id ax88179_eth_id_table[] = { + { USB_DEVICE(0x0b95, 0x1790), .driver_info = FLAG_TYPE_AX88179 }, + { USB_DEVICE(0x0b95, 0x178a), .driver_info = FLAG_TYPE_AX88178a }, + { USB_DEVICE(0x2001, 0x4a00), .driver_info = FLAG_TYPE_DLINK_DUB1312 }, + { USB_DEVICE(0x0df6, 0x0072), .driver_info = FLAG_TYPE_SITECOM }, + { USB_DEVICE(0x04e8, 0xa100), .driver_info = FLAG_TYPE_SAMSUNG }, + { USB_DEVICE(0x17ef, 0x304b), .driver_info = FLAG_TYPE_LENOVO }, + { USB_DEVICE(0x04b4, 0x3610), .driver_info = FLAG_TYPE_GX3 }, + { } /* Terminating entry */ +}; + +U_BOOT_USB_DEVICE(ax88179_eth, ax88179_eth_id_table); +#endif /* !CONFIG_DM_ETH */ |