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> 8*c0ad74e4SSimon Glass #include <dm.h> 989d48367SSimon Glass #include <usb.h> 10*c0ad74e4SSimon Glass #include <dm/device-internal.h> 1189d48367SSimon Glass 1289d48367SSimon Glass #include "usb_ether.h" 1389d48367SSimon Glass 1489d48367SSimon Glass typedef void (*usb_eth_before_probe)(void); 1589d48367SSimon Glass typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum, 1689d48367SSimon Glass struct ueth_data *ss); 1789d48367SSimon Glass typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss, 1889d48367SSimon Glass struct eth_device *dev_desc); 1989d48367SSimon Glass 2089d48367SSimon Glass struct usb_eth_prob_dev { 2189d48367SSimon Glass usb_eth_before_probe before_probe; /* optional */ 2289d48367SSimon Glass usb_eth_probe probe; 2389d48367SSimon Glass usb_eth_get_info get_info; 2489d48367SSimon Glass }; 2589d48367SSimon Glass 2689d48367SSimon Glass /* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */ 2789d48367SSimon Glass static const struct usb_eth_prob_dev prob_dev[] = { 289b70e007SSimon Glass #ifdef CONFIG_USB_ETHER_ASIX 299b70e007SSimon Glass { 309b70e007SSimon Glass .before_probe = asix_eth_before_probe, 319b70e007SSimon Glass .probe = asix_eth_probe, 329b70e007SSimon Glass .get_info = asix_eth_get_info, 339b70e007SSimon Glass }, 349b70e007SSimon Glass #endif 35e9954b86SRene Griessl #ifdef CONFIG_USB_ETHER_ASIX88179 36e9954b86SRene Griessl { 37e9954b86SRene Griessl .before_probe = ax88179_eth_before_probe, 38e9954b86SRene Griessl .probe = ax88179_eth_probe, 39e9954b86SRene Griessl .get_info = ax88179_eth_get_info, 40e9954b86SRene Griessl }, 41e9954b86SRene Griessl #endif 42df4fb1c3SGerhard Sittig #ifdef CONFIG_USB_ETHER_MCS7830 43df4fb1c3SGerhard Sittig { 44df4fb1c3SGerhard Sittig .before_probe = mcs7830_eth_before_probe, 45df4fb1c3SGerhard Sittig .probe = mcs7830_eth_probe, 46df4fb1c3SGerhard Sittig .get_info = mcs7830_eth_get_info, 47df4fb1c3SGerhard Sittig }, 48df4fb1c3SGerhard Sittig #endif 49291391beSSimon Glass #ifdef CONFIG_USB_ETHER_SMSC95XX 50291391beSSimon Glass { 51291391beSSimon Glass .before_probe = smsc95xx_eth_before_probe, 52291391beSSimon Glass .probe = smsc95xx_eth_probe, 53291391beSSimon Glass .get_info = smsc95xx_eth_get_info, 54291391beSSimon Glass }, 55291391beSSimon Glass #endif 5689d48367SSimon Glass { }, /* END */ 5789d48367SSimon Glass }; 5889d48367SSimon Glass 5989d48367SSimon Glass static int usb_max_eth_dev; /* number of highest available usb eth device */ 6089d48367SSimon Glass static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; 6189d48367SSimon Glass 6289d48367SSimon Glass /******************************************************************************* 6389d48367SSimon Glass * tell if current ethernet device is a usb dongle 6489d48367SSimon Glass */ 6589d48367SSimon Glass int is_eth_dev_on_usb_host(void) 6689d48367SSimon Glass { 6789d48367SSimon Glass int i; 6889d48367SSimon Glass struct eth_device *dev = eth_get_dev(); 6989d48367SSimon Glass 7089d48367SSimon Glass if (dev) { 7189d48367SSimon Glass for (i = 0; i < usb_max_eth_dev; i++) 7289d48367SSimon Glass if (&usb_eth[i].eth_dev == dev) 7389d48367SSimon Glass return 1; 7489d48367SSimon Glass } 7589d48367SSimon Glass return 0; 7689d48367SSimon Glass } 7789d48367SSimon Glass 7889d48367SSimon Glass /* 7989d48367SSimon Glass * Given a USB device, ask each driver if it can support it, and attach it 8089d48367SSimon Glass * to the first driver that says 'yes' 8189d48367SSimon Glass */ 8289d48367SSimon Glass static void probe_valid_drivers(struct usb_device *dev) 8389d48367SSimon Glass { 847616e785SSimon Glass struct eth_device *eth; 8589d48367SSimon Glass int j; 8689d48367SSimon Glass 8789d48367SSimon Glass for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) { 8889d48367SSimon Glass if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev])) 8989d48367SSimon Glass continue; 9089d48367SSimon Glass /* 9189d48367SSimon Glass * ok, it is a supported eth device. Get info and fill it in 9289d48367SSimon Glass */ 937616e785SSimon Glass eth = &usb_eth[usb_max_eth_dev].eth_dev; 9489d48367SSimon Glass if (prob_dev[j].get_info(dev, 9589d48367SSimon Glass &usb_eth[usb_max_eth_dev], 967616e785SSimon Glass eth)) { 9789d48367SSimon Glass /* found proper driver */ 9889d48367SSimon Glass /* register with networking stack */ 9989d48367SSimon Glass usb_max_eth_dev++; 10089d48367SSimon Glass 10189d48367SSimon Glass /* 10289d48367SSimon Glass * usb_max_eth_dev must be incremented prior to this 10389d48367SSimon Glass * call since eth_current_changed (internally called) 10489d48367SSimon Glass * relies on it 10589d48367SSimon Glass */ 1067616e785SSimon Glass eth_register(eth); 1077616e785SSimon Glass if (eth_write_hwaddr(eth, "usbeth", 1087616e785SSimon Glass usb_max_eth_dev - 1)) 1097616e785SSimon Glass puts("Warning: failed to set MAC address\n"); 11089d48367SSimon Glass break; 11189d48367SSimon Glass } 11289d48367SSimon Glass } 11389d48367SSimon Glass } 11489d48367SSimon Glass 11589d48367SSimon Glass /******************************************************************************* 11689d48367SSimon Glass * scan the usb and reports device info 11789d48367SSimon Glass * to the user if mode = 1 11889d48367SSimon Glass * returns current device or -1 if no 11989d48367SSimon Glass */ 12089d48367SSimon Glass int usb_host_eth_scan(int mode) 12189d48367SSimon Glass { 12289d48367SSimon Glass int i, old_async; 12389d48367SSimon Glass 12489d48367SSimon Glass if (mode == 1) 12593c2582fSLucas Stach printf(" scanning usb for ethernet devices... "); 12689d48367SSimon Glass 12789d48367SSimon Glass old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ 12889d48367SSimon Glass 129e7e982d6SVincent Palatin /* unregister a previously detected device */ 130e7e982d6SVincent Palatin for (i = 0; i < usb_max_eth_dev; i++) 131e7e982d6SVincent Palatin eth_unregister(&usb_eth[i].eth_dev); 132e7e982d6SVincent Palatin 133e7e982d6SVincent Palatin memset(usb_eth, 0, sizeof(usb_eth)); 13489d48367SSimon Glass 13589d48367SSimon Glass for (i = 0; prob_dev[i].probe; i++) { 13689d48367SSimon Glass if (prob_dev[i].before_probe) 13789d48367SSimon Glass prob_dev[i].before_probe(); 13889d48367SSimon Glass } 13989d48367SSimon Glass 14089d48367SSimon Glass usb_max_eth_dev = 0; 141*c0ad74e4SSimon Glass #ifdef CONFIG_DM_USB 142*c0ad74e4SSimon Glass /* 143*c0ad74e4SSimon Glass * TODO: We should add USB_DEVICE() declarations to each USB ethernet 144*c0ad74e4SSimon Glass * driver and then most of this file can be removed. 145*c0ad74e4SSimon Glass */ 146*c0ad74e4SSimon Glass struct udevice *bus; 147*c0ad74e4SSimon Glass struct uclass *uc; 148*c0ad74e4SSimon Glass int ret; 149*c0ad74e4SSimon Glass 150*c0ad74e4SSimon Glass ret = uclass_get(UCLASS_USB, &uc); 151*c0ad74e4SSimon Glass if (ret) 152*c0ad74e4SSimon Glass return ret; 153*c0ad74e4SSimon Glass uclass_foreach_dev(bus, uc) { 15489d48367SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 155*c0ad74e4SSimon Glass struct usb_device *dev; 156*c0ad74e4SSimon Glass 157*c0ad74e4SSimon Glass dev = usb_get_dev_index(bus, i); /* get device */ 158*c0ad74e4SSimon Glass debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)"); 159*c0ad74e4SSimon Glass if (!dev) 160*c0ad74e4SSimon Glass break; /* no more devices available */ 161*c0ad74e4SSimon Glass 162*c0ad74e4SSimon Glass /* 163*c0ad74e4SSimon Glass * find valid usb_ether driver for this device, 164*c0ad74e4SSimon Glass * if any 165*c0ad74e4SSimon Glass */ 166*c0ad74e4SSimon Glass probe_valid_drivers(dev); 167*c0ad74e4SSimon Glass 168*c0ad74e4SSimon Glass /* check limit */ 169*c0ad74e4SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) 170*c0ad74e4SSimon Glass break; 171*c0ad74e4SSimon Glass } /* for */ 172*c0ad74e4SSimon Glass } 173*c0ad74e4SSimon Glass #else 174*c0ad74e4SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 175*c0ad74e4SSimon Glass struct usb_device *dev; 176*c0ad74e4SSimon Glass 17789d48367SSimon Glass dev = usb_get_dev_index(i); /* get device */ 17889d48367SSimon Glass debug("i=%d\n", i); 179*c0ad74e4SSimon Glass if (!dev) 180d1f862f9SPeter Meerwald break; /* no more devices available */ 18189d48367SSimon Glass 18289d48367SSimon Glass /* find valid usb_ether driver for this device, if any */ 18389d48367SSimon Glass probe_valid_drivers(dev); 18489d48367SSimon Glass 18589d48367SSimon Glass /* check limit */ 186*c0ad74e4SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) 187*c0ad74e4SSimon Glass break; 188*c0ad74e4SSimon Glass } /* for */ 189*c0ad74e4SSimon Glass #endif 19089d48367SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) { 19189d48367SSimon Glass printf("max USB Ethernet Device reached: %d stopping\n", 19289d48367SSimon Glass usb_max_eth_dev); 19389d48367SSimon Glass } 19489d48367SSimon Glass usb_disable_asynch(old_async); /* restore asynch value */ 19589d48367SSimon Glass printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); 19689d48367SSimon Glass if (usb_max_eth_dev > 0) 19789d48367SSimon Glass return 0; 19889d48367SSimon Glass return -1; 19989d48367SSimon Glass } 200