uboot/drivers/usb/eth/usb_ether.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011 The Chromium OS Authors.
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <errno.h>
   9#include <log.h>
  10#include <malloc.h>
  11#include <net.h>
  12#include <usb.h>
  13#include <asm/cache.h>
  14#include <dm/device-internal.h>
  15
  16#include "usb_ether.h"
  17
  18#ifdef CONFIG_DM_ETH
  19
  20#define USB_BULK_RECV_TIMEOUT 500
  21
  22int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize)
  23{
  24        struct usb_device *udev = dev_get_parent_priv(dev);
  25        struct usb_interface_descriptor *iface_desc;
  26        bool ep_in_found = false, ep_out_found = false;
  27        struct usb_interface *iface;
  28        const int ifnum = 0; /* Always use interface 0 */
  29        int ret, i;
  30
  31        iface = &udev->config.if_desc[ifnum];
  32        iface_desc = &udev->config.if_desc[ifnum].desc;
  33
  34        /* Initialize the ueth_data structure with some useful info */
  35        ueth->ifnum = ifnum;
  36        ueth->subclass = iface_desc->bInterfaceSubClass;
  37        ueth->protocol = iface_desc->bInterfaceProtocol;
  38
  39        /*
  40         * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
  41         * We will ignore any others.
  42         */
  43        for (i = 0; i < iface_desc->bNumEndpoints; i++) {
  44                int ep_addr = iface->ep_desc[i].bEndpointAddress;
  45
  46                /* is it an BULK endpoint? */
  47                if ((iface->ep_desc[i].bmAttributes &
  48                     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
  49                        if (ep_addr & USB_DIR_IN && !ep_in_found) {
  50                                ueth->ep_in = ep_addr &
  51                                        USB_ENDPOINT_NUMBER_MASK;
  52                                ep_in_found = true;
  53                        } else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
  54                                ueth->ep_out = ep_addr &
  55                                        USB_ENDPOINT_NUMBER_MASK;
  56                                ep_out_found = true;
  57                        }
  58                }
  59
  60                /* is it an interrupt endpoint? */
  61                if ((iface->ep_desc[i].bmAttributes &
  62                    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
  63                        ueth->ep_int = iface->ep_desc[i].bEndpointAddress &
  64                                USB_ENDPOINT_NUMBER_MASK;
  65                        ueth->irqinterval = iface->ep_desc[i].bInterval;
  66                }
  67        }
  68        debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out,
  69              ueth->ep_int);
  70
  71        /* Do some basic sanity checks, and bail if we find a problem */
  72        if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) {
  73                debug("%s: %s: Cannot find endpoints\n", __func__, dev->name);
  74                return -ENXIO;
  75        }
  76
  77        ueth->rxsize = rxsize;
  78        ueth->rxbuf = memalign(ARCH_DMA_MINALIGN, rxsize);
  79        if (!ueth->rxbuf)
  80                return -ENOMEM;
  81
  82        ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum);
  83        if (ret) {
  84                debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name,
  85                      ret);
  86                return ret;
  87        }
  88        ueth->pusb_dev = udev;
  89
  90        return 0;
  91}
  92
  93int usb_ether_deregister(struct ueth_data *ueth)
  94{
  95        return 0;
  96}
  97
  98int usb_ether_receive(struct ueth_data *ueth, int rxsize)
  99{
 100        int actual_len;
 101        int ret;
 102
 103        if (rxsize > ueth->rxsize)
 104                return -EINVAL;
 105        ret = usb_bulk_msg(ueth->pusb_dev,
 106                           usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
 107                           ueth->rxbuf, rxsize, &actual_len,
 108                           USB_BULK_RECV_TIMEOUT);
 109        debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret);
 110        if (ret) {
 111                printf("Rx: failed to receive: %d\n", ret);
 112                return ret;
 113        }
 114        if (actual_len > rxsize) {
 115                debug("Rx: received too many bytes %d\n", actual_len);
 116                return -ENOSPC;
 117        }
 118        ueth->rxlen = actual_len;
 119        ueth->rxptr = 0;
 120
 121        return actual_len ? 0 : -EAGAIN;
 122}
 123
 124void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes)
 125{
 126        ueth->rxptr += num_bytes;
 127        if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen)
 128                ueth->rxlen = 0;
 129}
 130
 131int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp)
 132{
 133        if (!ueth->rxlen)
 134                return 0;
 135
 136        *ptrp = &ueth->rxbuf[ueth->rxptr];
 137
 138        return ueth->rxlen - ueth->rxptr;
 139}
 140
 141#else
 142
 143typedef void (*usb_eth_before_probe)(void);
 144typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
 145                        struct ueth_data *ss);
 146typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss,
 147                        struct eth_device *dev_desc);
 148
 149struct usb_eth_prob_dev {
 150        usb_eth_before_probe    before_probe; /* optional */
 151        usb_eth_probe                   probe;
 152        usb_eth_get_info                get_info;
 153};
 154
 155/* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */
 156static const struct usb_eth_prob_dev prob_dev[] = {
 157#ifdef CONFIG_USB_ETHER_ASIX
 158        {
 159                .before_probe = asix_eth_before_probe,
 160                .probe = asix_eth_probe,
 161                .get_info = asix_eth_get_info,
 162        },
 163#endif
 164#ifdef CONFIG_USB_ETHER_ASIX88179
 165        {
 166                .before_probe = ax88179_eth_before_probe,
 167                .probe = ax88179_eth_probe,
 168                .get_info = ax88179_eth_get_info,
 169        },
 170#endif
 171#ifdef CONFIG_USB_ETHER_MCS7830
 172        {
 173                .before_probe = mcs7830_eth_before_probe,
 174                .probe = mcs7830_eth_probe,
 175                .get_info = mcs7830_eth_get_info,
 176        },
 177#endif
 178#ifdef CONFIG_USB_ETHER_SMSC95XX
 179        {
 180                .before_probe = smsc95xx_eth_before_probe,
 181                .probe = smsc95xx_eth_probe,
 182                .get_info = smsc95xx_eth_get_info,
 183        },
 184#endif
 185#ifdef CONFIG_USB_ETHER_RTL8152
 186        {
 187                .before_probe = r8152_eth_before_probe,
 188                .probe = r8152_eth_probe,
 189                .get_info = r8152_eth_get_info,
 190        },
 191#endif
 192        { },            /* END */
 193};
 194
 195static int usb_max_eth_dev; /* number of highest available usb eth device */
 196static struct ueth_data usb_eth[USB_MAX_ETH_DEV];
 197
 198/*******************************************************************************
 199 * tell if current ethernet device is a usb dongle
 200 */
 201int is_eth_dev_on_usb_host(void)
 202{
 203        int i;
 204        struct eth_device *dev = eth_get_dev();
 205
 206        if (dev) {
 207                for (i = 0; i < usb_max_eth_dev; i++)
 208                        if (&usb_eth[i].eth_dev == dev)
 209                                return 1;
 210        }
 211        return 0;
 212}
 213
 214/*
 215 * Given a USB device, ask each driver if it can support it, and attach it
 216 * to the first driver that says 'yes'
 217 */
 218static void probe_valid_drivers(struct usb_device *dev)
 219{
 220        struct eth_device *eth;
 221        int j;
 222
 223        for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) {
 224                if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev]))
 225                        continue;
 226                /*
 227                 * ok, it is a supported eth device. Get info and fill it in
 228                 */
 229                eth = &usb_eth[usb_max_eth_dev].eth_dev;
 230                if (prob_dev[j].get_info(dev,
 231                        &usb_eth[usb_max_eth_dev],
 232                        eth)) {
 233                        /* found proper driver */
 234                        /* register with networking stack */
 235                        usb_max_eth_dev++;
 236
 237                        /*
 238                         * usb_max_eth_dev must be incremented prior to this
 239                         * call since eth_current_changed (internally called)
 240                         * relies on it
 241                         */
 242                        eth_register(eth);
 243                        if (eth_write_hwaddr(eth, "usbeth",
 244                                        usb_max_eth_dev - 1))
 245                                puts("Warning: failed to set MAC address\n");
 246                        break;
 247                        }
 248                }
 249        }
 250
 251/*******************************************************************************
 252 * scan the usb and reports device info
 253 * to the user if mode = 1
 254 * returns current device or -1 if no
 255 */
 256int usb_host_eth_scan(int mode)
 257{
 258        int i, old_async;
 259
 260        if (mode == 1)
 261                printf("       scanning usb for ethernet devices... ");
 262
 263        old_async = usb_disable_asynch(1); /* asynch transfer not allowed */
 264
 265        /* unregister a previously detected device */
 266        for (i = 0; i < usb_max_eth_dev; i++)
 267                eth_unregister(&usb_eth[i].eth_dev);
 268
 269        memset(usb_eth, 0, sizeof(usb_eth));
 270
 271        for (i = 0; prob_dev[i].probe; i++) {
 272                if (prob_dev[i].before_probe)
 273                        prob_dev[i].before_probe();
 274        }
 275
 276        usb_max_eth_dev = 0;
 277#if CONFIG_IS_ENABLED(DM_USB)
 278        /*
 279         * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
 280         * Ethernet driver and then most of this file can be removed.
 281         */
 282        struct udevice *bus;
 283        struct uclass *uc;
 284        int ret;
 285
 286        ret = uclass_get(UCLASS_USB, &uc);
 287        if (ret)
 288                return ret;
 289        uclass_foreach_dev(bus, uc) {
 290                for (i = 0; i < USB_MAX_DEVICE; i++) {
 291                        struct usb_device *dev;
 292
 293                        dev = usb_get_dev_index(bus, i); /* get device */
 294                        debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)");
 295                        if (!dev)
 296                                break; /* no more devices available */
 297
 298                        /*
 299                         * find valid usb_ether driver for this device,
 300                         * if any
 301                         */
 302                        probe_valid_drivers(dev);
 303
 304                        /* check limit */
 305                        if (usb_max_eth_dev == USB_MAX_ETH_DEV)
 306                                break;
 307                } /* for */
 308        }
 309#else
 310        for (i = 0; i < USB_MAX_DEVICE; i++) {
 311                struct usb_device *dev;
 312
 313                dev = usb_get_dev_index(i); /* get device */
 314                debug("i=%d\n", i);
 315                if (!dev)
 316                        break; /* no more devices available */
 317
 318                /* find valid usb_ether driver for this device, if any */
 319                probe_valid_drivers(dev);
 320
 321                /* check limit */
 322                if (usb_max_eth_dev == USB_MAX_ETH_DEV)
 323                        break;
 324        } /* for */
 325#endif
 326        if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
 327                printf("max USB Ethernet Device reached: %d stopping\n",
 328                       usb_max_eth_dev);
 329        }
 330        usb_disable_asynch(old_async); /* restore asynch value */
 331        printf("%d Ethernet Device(s) found\n", usb_max_eth_dev);
 332        if (usb_max_eth_dev > 0)
 333                return 0;
 334        return -1;
 335}
 336#endif
 337