189d48367SSimon Glass /* 289d48367SSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 389d48367SSimon Glass * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 589d48367SSimon Glass */ 689d48367SSimon Glass 789d48367SSimon Glass #include <common.h> 8c0ad74e4SSimon Glass #include <dm.h> 92e5350feSSimon Glass #include <errno.h> 10c8c2797cSSimon Glass #include <malloc.h> 1189d48367SSimon Glass #include <usb.h> 12c0ad74e4SSimon Glass #include <dm/device-internal.h> 1389d48367SSimon Glass 1489d48367SSimon Glass #include "usb_ether.h" 1589d48367SSimon Glass 16c8c2797cSSimon Glass #ifdef CONFIG_DM_ETH 17c8c2797cSSimon Glass 18c8c2797cSSimon Glass #define USB_BULK_RECV_TIMEOUT 500 19c8c2797cSSimon Glass 20c8c2797cSSimon Glass int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize) 21c8c2797cSSimon Glass { 22*bcbe3d15SSimon Glass struct usb_device *udev = dev_get_parent_priv(dev); 23c8c2797cSSimon Glass struct usb_interface_descriptor *iface_desc; 24c8c2797cSSimon Glass bool ep_in_found = false, ep_out_found = false; 25c8c2797cSSimon Glass struct usb_interface *iface; 26c8c2797cSSimon Glass const int ifnum = 0; /* Always use interface 0 */ 27c8c2797cSSimon Glass int ret, i; 28c8c2797cSSimon Glass 29c8c2797cSSimon Glass iface = &udev->config.if_desc[ifnum]; 30c8c2797cSSimon Glass iface_desc = &udev->config.if_desc[ifnum].desc; 31c8c2797cSSimon Glass 32c8c2797cSSimon Glass /* Initialize the ueth_data structure with some useful info */ 33c8c2797cSSimon Glass ueth->ifnum = ifnum; 34c8c2797cSSimon Glass ueth->subclass = iface_desc->bInterfaceSubClass; 35c8c2797cSSimon Glass ueth->protocol = iface_desc->bInterfaceProtocol; 36c8c2797cSSimon Glass 37c8c2797cSSimon Glass /* 38c8c2797cSSimon Glass * We are expecting a minimum of 3 endpoints - in, out (bulk), and int. 39c8c2797cSSimon Glass * We will ignore any others. 40c8c2797cSSimon Glass */ 41c8c2797cSSimon Glass for (i = 0; i < iface_desc->bNumEndpoints; i++) { 42c8c2797cSSimon Glass int ep_addr = iface->ep_desc[i].bEndpointAddress; 43c8c2797cSSimon Glass 44c8c2797cSSimon Glass /* is it an BULK endpoint? */ 45c8c2797cSSimon Glass if ((iface->ep_desc[i].bmAttributes & 46c8c2797cSSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { 47c8c2797cSSimon Glass if (ep_addr & USB_DIR_IN && !ep_in_found) { 48c8c2797cSSimon Glass ueth->ep_in = ep_addr & 49c8c2797cSSimon Glass USB_ENDPOINT_NUMBER_MASK; 50c8c2797cSSimon Glass ep_in_found = true; 51c8c2797cSSimon Glass } else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) { 52c8c2797cSSimon Glass ueth->ep_out = ep_addr & 53c8c2797cSSimon Glass USB_ENDPOINT_NUMBER_MASK; 54c8c2797cSSimon Glass ep_out_found = true; 55c8c2797cSSimon Glass } 56c8c2797cSSimon Glass } 57c8c2797cSSimon Glass 58c8c2797cSSimon Glass /* is it an interrupt endpoint? */ 59c8c2797cSSimon Glass if ((iface->ep_desc[i].bmAttributes & 60c8c2797cSSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { 61c8c2797cSSimon Glass ueth->ep_int = iface->ep_desc[i].bEndpointAddress & 62c8c2797cSSimon Glass USB_ENDPOINT_NUMBER_MASK; 63c8c2797cSSimon Glass ueth->irqinterval = iface->ep_desc[i].bInterval; 64c8c2797cSSimon Glass } 65c8c2797cSSimon Glass } 66c8c2797cSSimon Glass debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out, 67c8c2797cSSimon Glass ueth->ep_int); 68c8c2797cSSimon Glass 69c8c2797cSSimon Glass /* Do some basic sanity checks, and bail if we find a problem */ 70c8c2797cSSimon Glass if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) { 71c8c2797cSSimon Glass debug("%s: %s: Cannot find endpoints\n", __func__, dev->name); 72c8c2797cSSimon Glass return -ENXIO; 73c8c2797cSSimon Glass } 74c8c2797cSSimon Glass 75c8c2797cSSimon Glass ueth->rxsize = rxsize; 76c8c2797cSSimon Glass ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN); 77c8c2797cSSimon Glass if (!ueth->rxbuf) 78c8c2797cSSimon Glass return -ENOMEM; 79c8c2797cSSimon Glass 80c8c2797cSSimon Glass ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum); 81c8c2797cSSimon Glass if (ret) { 82c8c2797cSSimon Glass debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name, 83c8c2797cSSimon Glass ret); 84c8c2797cSSimon Glass return ret; 85c8c2797cSSimon Glass } 86c8c2797cSSimon Glass ueth->pusb_dev = udev; 87c8c2797cSSimon Glass 88c8c2797cSSimon Glass return 0; 89c8c2797cSSimon Glass } 90c8c2797cSSimon Glass 91c8c2797cSSimon Glass int usb_ether_deregister(struct ueth_data *ueth) 92c8c2797cSSimon Glass { 93c8c2797cSSimon Glass return 0; 94c8c2797cSSimon Glass } 95c8c2797cSSimon Glass 96c8c2797cSSimon Glass int usb_ether_receive(struct ueth_data *ueth, int rxsize) 97c8c2797cSSimon Glass { 98c8c2797cSSimon Glass int actual_len; 99c8c2797cSSimon Glass int ret; 100c8c2797cSSimon Glass 101c8c2797cSSimon Glass if (rxsize > ueth->rxsize) 102c8c2797cSSimon Glass return -EINVAL; 103c8c2797cSSimon Glass ret = usb_bulk_msg(ueth->pusb_dev, 104c8c2797cSSimon Glass usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in), 105c8c2797cSSimon Glass ueth->rxbuf, rxsize, &actual_len, 106c8c2797cSSimon Glass USB_BULK_RECV_TIMEOUT); 107c8c2797cSSimon Glass debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret); 108c8c2797cSSimon Glass if (ret) { 109c8c2797cSSimon Glass printf("Rx: failed to receive: %d\n", ret); 110c8c2797cSSimon Glass return ret; 111c8c2797cSSimon Glass } 112c8c2797cSSimon Glass if (actual_len > rxsize) { 113c8c2797cSSimon Glass debug("Rx: received too many bytes %d\n", actual_len); 114c8c2797cSSimon Glass return -ENOSPC; 115c8c2797cSSimon Glass } 116c8c2797cSSimon Glass ueth->rxlen = actual_len; 117c8c2797cSSimon Glass ueth->rxptr = 0; 118c8c2797cSSimon Glass 119c8c2797cSSimon Glass return actual_len ? 0 : -EAGAIN; 120c8c2797cSSimon Glass } 121c8c2797cSSimon Glass 122c8c2797cSSimon Glass void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes) 123c8c2797cSSimon Glass { 124c8c2797cSSimon Glass ueth->rxptr += num_bytes; 125c8c2797cSSimon Glass if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen) 126c8c2797cSSimon Glass ueth->rxlen = 0; 127c8c2797cSSimon Glass } 128c8c2797cSSimon Glass 129c8c2797cSSimon Glass int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp) 130c8c2797cSSimon Glass { 131c8c2797cSSimon Glass if (!ueth->rxlen) 132c8c2797cSSimon Glass return 0; 133c8c2797cSSimon Glass 134c8c2797cSSimon Glass *ptrp = &ueth->rxbuf[ueth->rxptr]; 135c8c2797cSSimon Glass 136c8c2797cSSimon Glass return ueth->rxlen - ueth->rxptr; 137c8c2797cSSimon Glass } 138c8c2797cSSimon Glass 139c8c2797cSSimon Glass #else 140c8c2797cSSimon Glass 14189d48367SSimon Glass typedef void (*usb_eth_before_probe)(void); 14289d48367SSimon Glass typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum, 14389d48367SSimon Glass struct ueth_data *ss); 14489d48367SSimon Glass typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss, 14589d48367SSimon Glass struct eth_device *dev_desc); 14689d48367SSimon Glass 14789d48367SSimon Glass struct usb_eth_prob_dev { 14889d48367SSimon Glass usb_eth_before_probe before_probe; /* optional */ 14989d48367SSimon Glass usb_eth_probe probe; 15089d48367SSimon Glass usb_eth_get_info get_info; 15189d48367SSimon Glass }; 15289d48367SSimon Glass 15389d48367SSimon Glass /* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */ 15489d48367SSimon Glass static const struct usb_eth_prob_dev prob_dev[] = { 1559b70e007SSimon Glass #ifdef CONFIG_USB_ETHER_ASIX 1569b70e007SSimon Glass { 1579b70e007SSimon Glass .before_probe = asix_eth_before_probe, 1589b70e007SSimon Glass .probe = asix_eth_probe, 1599b70e007SSimon Glass .get_info = asix_eth_get_info, 1609b70e007SSimon Glass }, 1619b70e007SSimon Glass #endif 162e9954b86SRene Griessl #ifdef CONFIG_USB_ETHER_ASIX88179 163e9954b86SRene Griessl { 164e9954b86SRene Griessl .before_probe = ax88179_eth_before_probe, 165e9954b86SRene Griessl .probe = ax88179_eth_probe, 166e9954b86SRene Griessl .get_info = ax88179_eth_get_info, 167e9954b86SRene Griessl }, 168e9954b86SRene Griessl #endif 169df4fb1c3SGerhard Sittig #ifdef CONFIG_USB_ETHER_MCS7830 170df4fb1c3SGerhard Sittig { 171df4fb1c3SGerhard Sittig .before_probe = mcs7830_eth_before_probe, 172df4fb1c3SGerhard Sittig .probe = mcs7830_eth_probe, 173df4fb1c3SGerhard Sittig .get_info = mcs7830_eth_get_info, 174df4fb1c3SGerhard Sittig }, 175df4fb1c3SGerhard Sittig #endif 176291391beSSimon Glass #ifdef CONFIG_USB_ETHER_SMSC95XX 177291391beSSimon Glass { 178291391beSSimon Glass .before_probe = smsc95xx_eth_before_probe, 179291391beSSimon Glass .probe = smsc95xx_eth_probe, 180291391beSSimon Glass .get_info = smsc95xx_eth_get_info, 181291391beSSimon Glass }, 182291391beSSimon Glass #endif 18389d48367SSimon Glass { }, /* END */ 18489d48367SSimon Glass }; 18589d48367SSimon Glass 18689d48367SSimon Glass static int usb_max_eth_dev; /* number of highest available usb eth device */ 18789d48367SSimon Glass static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; 18889d48367SSimon Glass 18989d48367SSimon Glass /******************************************************************************* 19089d48367SSimon Glass * tell if current ethernet device is a usb dongle 19189d48367SSimon Glass */ 19289d48367SSimon Glass int is_eth_dev_on_usb_host(void) 19389d48367SSimon Glass { 19489d48367SSimon Glass int i; 19589d48367SSimon Glass struct eth_device *dev = eth_get_dev(); 19689d48367SSimon Glass 19789d48367SSimon Glass if (dev) { 19889d48367SSimon Glass for (i = 0; i < usb_max_eth_dev; i++) 19989d48367SSimon Glass if (&usb_eth[i].eth_dev == dev) 20089d48367SSimon Glass return 1; 20189d48367SSimon Glass } 20289d48367SSimon Glass return 0; 20389d48367SSimon Glass } 20489d48367SSimon Glass 20589d48367SSimon Glass /* 20689d48367SSimon Glass * Given a USB device, ask each driver if it can support it, and attach it 20789d48367SSimon Glass * to the first driver that says 'yes' 20889d48367SSimon Glass */ 20989d48367SSimon Glass static void probe_valid_drivers(struct usb_device *dev) 21089d48367SSimon Glass { 2117616e785SSimon Glass struct eth_device *eth; 21289d48367SSimon Glass int j; 21389d48367SSimon Glass 21489d48367SSimon Glass for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) { 21589d48367SSimon Glass if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev])) 21689d48367SSimon Glass continue; 21789d48367SSimon Glass /* 21889d48367SSimon Glass * ok, it is a supported eth device. Get info and fill it in 21989d48367SSimon Glass */ 2207616e785SSimon Glass eth = &usb_eth[usb_max_eth_dev].eth_dev; 22189d48367SSimon Glass if (prob_dev[j].get_info(dev, 22289d48367SSimon Glass &usb_eth[usb_max_eth_dev], 2237616e785SSimon Glass eth)) { 22489d48367SSimon Glass /* found proper driver */ 22589d48367SSimon Glass /* register with networking stack */ 22689d48367SSimon Glass usb_max_eth_dev++; 22789d48367SSimon Glass 22889d48367SSimon Glass /* 22989d48367SSimon Glass * usb_max_eth_dev must be incremented prior to this 23089d48367SSimon Glass * call since eth_current_changed (internally called) 23189d48367SSimon Glass * relies on it 23289d48367SSimon Glass */ 2337616e785SSimon Glass eth_register(eth); 2347616e785SSimon Glass if (eth_write_hwaddr(eth, "usbeth", 2357616e785SSimon Glass usb_max_eth_dev - 1)) 2367616e785SSimon Glass puts("Warning: failed to set MAC address\n"); 23789d48367SSimon Glass break; 23889d48367SSimon Glass } 23989d48367SSimon Glass } 24089d48367SSimon Glass } 24189d48367SSimon Glass 24289d48367SSimon Glass /******************************************************************************* 24389d48367SSimon Glass * scan the usb and reports device info 24489d48367SSimon Glass * to the user if mode = 1 24589d48367SSimon Glass * returns current device or -1 if no 24689d48367SSimon Glass */ 24789d48367SSimon Glass int usb_host_eth_scan(int mode) 24889d48367SSimon Glass { 24989d48367SSimon Glass int i, old_async; 25089d48367SSimon Glass 25189d48367SSimon Glass if (mode == 1) 25293c2582fSLucas Stach printf(" scanning usb for ethernet devices... "); 25389d48367SSimon Glass 25489d48367SSimon Glass old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ 25589d48367SSimon Glass 256e7e982d6SVincent Palatin /* unregister a previously detected device */ 257e7e982d6SVincent Palatin for (i = 0; i < usb_max_eth_dev; i++) 258e7e982d6SVincent Palatin eth_unregister(&usb_eth[i].eth_dev); 259e7e982d6SVincent Palatin 260e7e982d6SVincent Palatin memset(usb_eth, 0, sizeof(usb_eth)); 26189d48367SSimon Glass 26289d48367SSimon Glass for (i = 0; prob_dev[i].probe; i++) { 26389d48367SSimon Glass if (prob_dev[i].before_probe) 26489d48367SSimon Glass prob_dev[i].before_probe(); 26589d48367SSimon Glass } 26689d48367SSimon Glass 26789d48367SSimon Glass usb_max_eth_dev = 0; 268c0ad74e4SSimon Glass #ifdef CONFIG_DM_USB 269c0ad74e4SSimon Glass /* 270abb59cffSSimon Glass * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB 271abb59cffSSimon Glass * Ethernet driver and then most of this file can be removed. 272c0ad74e4SSimon Glass */ 273c0ad74e4SSimon Glass struct udevice *bus; 274c0ad74e4SSimon Glass struct uclass *uc; 275c0ad74e4SSimon Glass int ret; 276c0ad74e4SSimon Glass 277c0ad74e4SSimon Glass ret = uclass_get(UCLASS_USB, &uc); 278c0ad74e4SSimon Glass if (ret) 279c0ad74e4SSimon Glass return ret; 280c0ad74e4SSimon Glass uclass_foreach_dev(bus, uc) { 28189d48367SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 282c0ad74e4SSimon Glass struct usb_device *dev; 283c0ad74e4SSimon Glass 284c0ad74e4SSimon Glass dev = usb_get_dev_index(bus, i); /* get device */ 285c0ad74e4SSimon Glass debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)"); 286c0ad74e4SSimon Glass if (!dev) 287c0ad74e4SSimon Glass break; /* no more devices available */ 288c0ad74e4SSimon Glass 289c0ad74e4SSimon Glass /* 290c0ad74e4SSimon Glass * find valid usb_ether driver for this device, 291c0ad74e4SSimon Glass * if any 292c0ad74e4SSimon Glass */ 293c0ad74e4SSimon Glass probe_valid_drivers(dev); 294c0ad74e4SSimon Glass 295c0ad74e4SSimon Glass /* check limit */ 296c0ad74e4SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) 297c0ad74e4SSimon Glass break; 298c0ad74e4SSimon Glass } /* for */ 299c0ad74e4SSimon Glass } 300c0ad74e4SSimon Glass #else 301c0ad74e4SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 302c0ad74e4SSimon Glass struct usb_device *dev; 303c0ad74e4SSimon Glass 30489d48367SSimon Glass dev = usb_get_dev_index(i); /* get device */ 30589d48367SSimon Glass debug("i=%d\n", i); 306c0ad74e4SSimon Glass if (!dev) 307d1f862f9SPeter Meerwald break; /* no more devices available */ 30889d48367SSimon Glass 30989d48367SSimon Glass /* find valid usb_ether driver for this device, if any */ 31089d48367SSimon Glass probe_valid_drivers(dev); 31189d48367SSimon Glass 31289d48367SSimon Glass /* check limit */ 313c0ad74e4SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) 314c0ad74e4SSimon Glass break; 315c0ad74e4SSimon Glass } /* for */ 316c0ad74e4SSimon Glass #endif 31789d48367SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) { 31889d48367SSimon Glass printf("max USB Ethernet Device reached: %d stopping\n", 31989d48367SSimon Glass usb_max_eth_dev); 32089d48367SSimon Glass } 32189d48367SSimon Glass usb_disable_asynch(old_async); /* restore asynch value */ 32289d48367SSimon Glass printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); 32389d48367SSimon Glass if (usb_max_eth_dev > 0) 32489d48367SSimon Glass return 0; 32589d48367SSimon Glass return -1; 32689d48367SSimon Glass } 327c8c2797cSSimon Glass #endif 328