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