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> 889d48367SSimon Glass #include <usb.h> 989d48367SSimon Glass 1089d48367SSimon Glass #include "usb_ether.h" 1189d48367SSimon Glass 1289d48367SSimon Glass typedef void (*usb_eth_before_probe)(void); 1389d48367SSimon Glass typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum, 1489d48367SSimon Glass struct ueth_data *ss); 1589d48367SSimon Glass typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss, 1689d48367SSimon Glass struct eth_device *dev_desc); 1789d48367SSimon Glass 1889d48367SSimon Glass struct usb_eth_prob_dev { 1989d48367SSimon Glass usb_eth_before_probe before_probe; /* optional */ 2089d48367SSimon Glass usb_eth_probe probe; 2189d48367SSimon Glass usb_eth_get_info get_info; 2289d48367SSimon Glass }; 2389d48367SSimon Glass 2489d48367SSimon Glass /* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */ 2589d48367SSimon Glass static const struct usb_eth_prob_dev prob_dev[] = { 269b70e007SSimon Glass #ifdef CONFIG_USB_ETHER_ASIX 279b70e007SSimon Glass { 289b70e007SSimon Glass .before_probe = asix_eth_before_probe, 299b70e007SSimon Glass .probe = asix_eth_probe, 309b70e007SSimon Glass .get_info = asix_eth_get_info, 319b70e007SSimon Glass }, 329b70e007SSimon Glass #endif 33*df4fb1c3SGerhard Sittig #ifdef CONFIG_USB_ETHER_MCS7830 34*df4fb1c3SGerhard Sittig { 35*df4fb1c3SGerhard Sittig .before_probe = mcs7830_eth_before_probe, 36*df4fb1c3SGerhard Sittig .probe = mcs7830_eth_probe, 37*df4fb1c3SGerhard Sittig .get_info = mcs7830_eth_get_info, 38*df4fb1c3SGerhard Sittig }, 39*df4fb1c3SGerhard Sittig #endif 40291391beSSimon Glass #ifdef CONFIG_USB_ETHER_SMSC95XX 41291391beSSimon Glass { 42291391beSSimon Glass .before_probe = smsc95xx_eth_before_probe, 43291391beSSimon Glass .probe = smsc95xx_eth_probe, 44291391beSSimon Glass .get_info = smsc95xx_eth_get_info, 45291391beSSimon Glass }, 46291391beSSimon Glass #endif 4789d48367SSimon Glass { }, /* END */ 4889d48367SSimon Glass }; 4989d48367SSimon Glass 5089d48367SSimon Glass static int usb_max_eth_dev; /* number of highest available usb eth device */ 5189d48367SSimon Glass static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; 5289d48367SSimon Glass 5389d48367SSimon Glass /******************************************************************************* 5489d48367SSimon Glass * tell if current ethernet device is a usb dongle 5589d48367SSimon Glass */ 5689d48367SSimon Glass int is_eth_dev_on_usb_host(void) 5789d48367SSimon Glass { 5889d48367SSimon Glass int i; 5989d48367SSimon Glass struct eth_device *dev = eth_get_dev(); 6089d48367SSimon Glass 6189d48367SSimon Glass if (dev) { 6289d48367SSimon Glass for (i = 0; i < usb_max_eth_dev; i++) 6389d48367SSimon Glass if (&usb_eth[i].eth_dev == dev) 6489d48367SSimon Glass return 1; 6589d48367SSimon Glass } 6689d48367SSimon Glass return 0; 6789d48367SSimon Glass } 6889d48367SSimon Glass 6989d48367SSimon Glass /* 7089d48367SSimon Glass * Given a USB device, ask each driver if it can support it, and attach it 7189d48367SSimon Glass * to the first driver that says 'yes' 7289d48367SSimon Glass */ 7389d48367SSimon Glass static void probe_valid_drivers(struct usb_device *dev) 7489d48367SSimon Glass { 757616e785SSimon Glass struct eth_device *eth; 7689d48367SSimon Glass int j; 7789d48367SSimon Glass 7889d48367SSimon Glass for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) { 7989d48367SSimon Glass if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev])) 8089d48367SSimon Glass continue; 8189d48367SSimon Glass /* 8289d48367SSimon Glass * ok, it is a supported eth device. Get info and fill it in 8389d48367SSimon Glass */ 847616e785SSimon Glass eth = &usb_eth[usb_max_eth_dev].eth_dev; 8589d48367SSimon Glass if (prob_dev[j].get_info(dev, 8689d48367SSimon Glass &usb_eth[usb_max_eth_dev], 877616e785SSimon Glass eth)) { 8889d48367SSimon Glass /* found proper driver */ 8989d48367SSimon Glass /* register with networking stack */ 9089d48367SSimon Glass usb_max_eth_dev++; 9189d48367SSimon Glass 9289d48367SSimon Glass /* 9389d48367SSimon Glass * usb_max_eth_dev must be incremented prior to this 9489d48367SSimon Glass * call since eth_current_changed (internally called) 9589d48367SSimon Glass * relies on it 9689d48367SSimon Glass */ 977616e785SSimon Glass eth_register(eth); 987616e785SSimon Glass if (eth_write_hwaddr(eth, "usbeth", 997616e785SSimon Glass usb_max_eth_dev - 1)) 1007616e785SSimon Glass puts("Warning: failed to set MAC address\n"); 10189d48367SSimon Glass break; 10289d48367SSimon Glass } 10389d48367SSimon Glass } 10489d48367SSimon Glass } 10589d48367SSimon Glass 10689d48367SSimon Glass /******************************************************************************* 10789d48367SSimon Glass * scan the usb and reports device info 10889d48367SSimon Glass * to the user if mode = 1 10989d48367SSimon Glass * returns current device or -1 if no 11089d48367SSimon Glass */ 11189d48367SSimon Glass int usb_host_eth_scan(int mode) 11289d48367SSimon Glass { 11389d48367SSimon Glass int i, old_async; 11489d48367SSimon Glass struct usb_device *dev; 11589d48367SSimon Glass 11689d48367SSimon Glass 11789d48367SSimon Glass if (mode == 1) 11893c2582fSLucas Stach printf(" scanning usb for ethernet devices... "); 11989d48367SSimon Glass 12089d48367SSimon Glass old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ 12189d48367SSimon Glass 122e7e982d6SVincent Palatin /* unregister a previously detected device */ 123e7e982d6SVincent Palatin for (i = 0; i < usb_max_eth_dev; i++) 124e7e982d6SVincent Palatin eth_unregister(&usb_eth[i].eth_dev); 125e7e982d6SVincent Palatin 126e7e982d6SVincent Palatin memset(usb_eth, 0, sizeof(usb_eth)); 12789d48367SSimon Glass 12889d48367SSimon Glass for (i = 0; prob_dev[i].probe; i++) { 12989d48367SSimon Glass if (prob_dev[i].before_probe) 13089d48367SSimon Glass prob_dev[i].before_probe(); 13189d48367SSimon Glass } 13289d48367SSimon Glass 13389d48367SSimon Glass usb_max_eth_dev = 0; 13489d48367SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 13589d48367SSimon Glass dev = usb_get_dev_index(i); /* get device */ 13689d48367SSimon Glass debug("i=%d\n", i); 13789d48367SSimon Glass if (dev == NULL) 138d1f862f9SPeter Meerwald break; /* no more devices available */ 13989d48367SSimon Glass 14089d48367SSimon Glass /* find valid usb_ether driver for this device, if any */ 14189d48367SSimon Glass probe_valid_drivers(dev); 14289d48367SSimon Glass 14389d48367SSimon Glass /* check limit */ 14489d48367SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) { 14589d48367SSimon Glass printf("max USB Ethernet Device reached: %d stopping\n", 14689d48367SSimon Glass usb_max_eth_dev); 14789d48367SSimon Glass break; 14889d48367SSimon Glass } 14989d48367SSimon Glass } /* for */ 15089d48367SSimon Glass 15189d48367SSimon Glass usb_disable_asynch(old_async); /* restore asynch value */ 15289d48367SSimon Glass printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); 15389d48367SSimon Glass if (usb_max_eth_dev > 0) 15489d48367SSimon Glass return 0; 15589d48367SSimon Glass return -1; 15689d48367SSimon Glass } 157