189d48367SSimon Glass /* 289d48367SSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 389d48367SSimon Glass * See file CREDITS for list of people who contributed to this 489d48367SSimon Glass * project. 589d48367SSimon Glass * 689d48367SSimon Glass * This program is free software; you can redistribute it and/or 789d48367SSimon Glass * modify it under the terms of the GNU General Public License as 889d48367SSimon Glass * published by the Free Software Foundation; either version 2 of 989d48367SSimon Glass * the License, or (at your option) any later version. 1089d48367SSimon Glass * 1189d48367SSimon Glass * This program is distributed in the hope that it will be useful, 1289d48367SSimon Glass * but WITHOUT ANY WARRANTY; without even the implied warranty of 1389d48367SSimon Glass * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1489d48367SSimon Glass * GNU General Public License for more details. 1589d48367SSimon Glass * 1689d48367SSimon Glass * You should have received a copy of the GNU General Public License 1789d48367SSimon Glass * along with this program; if not, write to the Free Software 1889d48367SSimon Glass * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 1989d48367SSimon Glass * MA 02111-1307 USA 2089d48367SSimon Glass */ 2189d48367SSimon Glass 2289d48367SSimon Glass #include <common.h> 2389d48367SSimon Glass #include <usb.h> 2489d48367SSimon Glass 2589d48367SSimon Glass #include "usb_ether.h" 2689d48367SSimon Glass 2789d48367SSimon Glass typedef void (*usb_eth_before_probe)(void); 2889d48367SSimon Glass typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum, 2989d48367SSimon Glass struct ueth_data *ss); 3089d48367SSimon Glass typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss, 3189d48367SSimon Glass struct eth_device *dev_desc); 3289d48367SSimon Glass 3389d48367SSimon Glass struct usb_eth_prob_dev { 3489d48367SSimon Glass usb_eth_before_probe before_probe; /* optional */ 3589d48367SSimon Glass usb_eth_probe probe; 3689d48367SSimon Glass usb_eth_get_info get_info; 3789d48367SSimon Glass }; 3889d48367SSimon Glass 3989d48367SSimon Glass /* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */ 4089d48367SSimon Glass static const struct usb_eth_prob_dev prob_dev[] = { 419b70e007SSimon Glass #ifdef CONFIG_USB_ETHER_ASIX 429b70e007SSimon Glass { 439b70e007SSimon Glass .before_probe = asix_eth_before_probe, 449b70e007SSimon Glass .probe = asix_eth_probe, 459b70e007SSimon Glass .get_info = asix_eth_get_info, 469b70e007SSimon Glass }, 479b70e007SSimon Glass #endif 48291391beSSimon Glass #ifdef CONFIG_USB_ETHER_SMSC95XX 49291391beSSimon Glass { 50291391beSSimon Glass .before_probe = smsc95xx_eth_before_probe, 51291391beSSimon Glass .probe = smsc95xx_eth_probe, 52291391beSSimon Glass .get_info = smsc95xx_eth_get_info, 53291391beSSimon Glass }, 54291391beSSimon Glass #endif 5589d48367SSimon Glass { }, /* END */ 5689d48367SSimon Glass }; 5789d48367SSimon Glass 5889d48367SSimon Glass static int usb_max_eth_dev; /* number of highest available usb eth device */ 5989d48367SSimon Glass static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; 6089d48367SSimon Glass 6189d48367SSimon Glass /******************************************************************************* 6289d48367SSimon Glass * tell if current ethernet device is a usb dongle 6389d48367SSimon Glass */ 6489d48367SSimon Glass int is_eth_dev_on_usb_host(void) 6589d48367SSimon Glass { 6689d48367SSimon Glass int i; 6789d48367SSimon Glass struct eth_device *dev = eth_get_dev(); 6889d48367SSimon Glass 6989d48367SSimon Glass if (dev) { 7089d48367SSimon Glass for (i = 0; i < usb_max_eth_dev; i++) 7189d48367SSimon Glass if (&usb_eth[i].eth_dev == dev) 7289d48367SSimon Glass return 1; 7389d48367SSimon Glass } 7489d48367SSimon Glass return 0; 7589d48367SSimon Glass } 7689d48367SSimon Glass 7789d48367SSimon Glass /* 7889d48367SSimon Glass * Given a USB device, ask each driver if it can support it, and attach it 7989d48367SSimon Glass * to the first driver that says 'yes' 8089d48367SSimon Glass */ 8189d48367SSimon Glass static void probe_valid_drivers(struct usb_device *dev) 8289d48367SSimon Glass { 837616e785SSimon Glass struct eth_device *eth; 8489d48367SSimon Glass int j; 8589d48367SSimon Glass 8689d48367SSimon Glass for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) { 8789d48367SSimon Glass if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev])) 8889d48367SSimon Glass continue; 8989d48367SSimon Glass /* 9089d48367SSimon Glass * ok, it is a supported eth device. Get info and fill it in 9189d48367SSimon Glass */ 927616e785SSimon Glass eth = &usb_eth[usb_max_eth_dev].eth_dev; 9389d48367SSimon Glass if (prob_dev[j].get_info(dev, 9489d48367SSimon Glass &usb_eth[usb_max_eth_dev], 957616e785SSimon Glass eth)) { 9689d48367SSimon Glass /* found proper driver */ 9789d48367SSimon Glass /* register with networking stack */ 9889d48367SSimon Glass usb_max_eth_dev++; 9989d48367SSimon Glass 10089d48367SSimon Glass /* 10189d48367SSimon Glass * usb_max_eth_dev must be incremented prior to this 10289d48367SSimon Glass * call since eth_current_changed (internally called) 10389d48367SSimon Glass * relies on it 10489d48367SSimon Glass */ 1057616e785SSimon Glass eth_register(eth); 1067616e785SSimon Glass if (eth_write_hwaddr(eth, "usbeth", 1077616e785SSimon Glass usb_max_eth_dev - 1)) 1087616e785SSimon Glass puts("Warning: failed to set MAC address\n"); 10989d48367SSimon Glass break; 11089d48367SSimon Glass } 11189d48367SSimon Glass } 11289d48367SSimon Glass } 11389d48367SSimon Glass 11489d48367SSimon Glass /******************************************************************************* 11589d48367SSimon Glass * scan the usb and reports device info 11689d48367SSimon Glass * to the user if mode = 1 11789d48367SSimon Glass * returns current device or -1 if no 11889d48367SSimon Glass */ 11989d48367SSimon Glass int usb_host_eth_scan(int mode) 12089d48367SSimon Glass { 12189d48367SSimon Glass int i, old_async; 12289d48367SSimon Glass struct usb_device *dev; 12389d48367SSimon Glass 12489d48367SSimon Glass 12589d48367SSimon Glass if (mode == 1) 12689d48367SSimon Glass printf(" scanning bus for ethernet devices... "); 12789d48367SSimon Glass 12889d48367SSimon Glass old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ 12989d48367SSimon Glass 13089d48367SSimon Glass for (i = 0; i < USB_MAX_ETH_DEV; i++) 13189d48367SSimon Glass memset(&usb_eth[i], 0, sizeof(usb_eth[i])); 13289d48367SSimon Glass 13389d48367SSimon Glass for (i = 0; prob_dev[i].probe; i++) { 13489d48367SSimon Glass if (prob_dev[i].before_probe) 13589d48367SSimon Glass prob_dev[i].before_probe(); 13689d48367SSimon Glass } 13789d48367SSimon Glass 13889d48367SSimon Glass usb_max_eth_dev = 0; 13989d48367SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 14089d48367SSimon Glass dev = usb_get_dev_index(i); /* get device */ 14189d48367SSimon Glass debug("i=%d\n", i); 14289d48367SSimon Glass if (dev == NULL) 143*d1f862f9SPeter Meerwald break; /* no more devices available */ 14489d48367SSimon Glass 14589d48367SSimon Glass /* find valid usb_ether driver for this device, if any */ 14689d48367SSimon Glass probe_valid_drivers(dev); 14789d48367SSimon Glass 14889d48367SSimon Glass /* check limit */ 14989d48367SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) { 15089d48367SSimon Glass printf("max USB Ethernet Device reached: %d stopping\n", 15189d48367SSimon Glass usb_max_eth_dev); 15289d48367SSimon Glass break; 15389d48367SSimon Glass } 15489d48367SSimon Glass } /* for */ 15589d48367SSimon Glass 15689d48367SSimon Glass usb_disable_asynch(old_async); /* restore asynch value */ 15789d48367SSimon Glass printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); 15889d48367SSimon Glass if (usb_max_eth_dev > 0) 15989d48367SSimon Glass return 0; 16089d48367SSimon Glass return -1; 16189d48367SSimon Glass } 162