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[] = { 41*9b70e007SSimon Glass #ifdef CONFIG_USB_ETHER_ASIX 42*9b70e007SSimon Glass { 43*9b70e007SSimon Glass .before_probe = asix_eth_before_probe, 44*9b70e007SSimon Glass .probe = asix_eth_probe, 45*9b70e007SSimon Glass .get_info = asix_eth_get_info, 46*9b70e007SSimon Glass }, 47*9b70e007SSimon Glass #endif 4889d48367SSimon Glass { }, /* END */ 4989d48367SSimon Glass }; 5089d48367SSimon Glass 5189d48367SSimon Glass static int usb_max_eth_dev; /* number of highest available usb eth device */ 5289d48367SSimon Glass static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; 5389d48367SSimon Glass 5489d48367SSimon Glass /******************************************************************************* 5589d48367SSimon Glass * tell if current ethernet device is a usb dongle 5689d48367SSimon Glass */ 5789d48367SSimon Glass int is_eth_dev_on_usb_host(void) 5889d48367SSimon Glass { 5989d48367SSimon Glass int i; 6089d48367SSimon Glass struct eth_device *dev = eth_get_dev(); 6189d48367SSimon Glass 6289d48367SSimon Glass if (dev) { 6389d48367SSimon Glass for (i = 0; i < usb_max_eth_dev; i++) 6489d48367SSimon Glass if (&usb_eth[i].eth_dev == dev) 6589d48367SSimon Glass return 1; 6689d48367SSimon Glass } 6789d48367SSimon Glass return 0; 6889d48367SSimon Glass } 6989d48367SSimon Glass 7089d48367SSimon Glass /* 7189d48367SSimon Glass * Given a USB device, ask each driver if it can support it, and attach it 7289d48367SSimon Glass * to the first driver that says 'yes' 7389d48367SSimon Glass */ 7489d48367SSimon Glass static void probe_valid_drivers(struct usb_device *dev) 7589d48367SSimon Glass { 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 */ 8489d48367SSimon Glass if (prob_dev[j].get_info(dev, 8589d48367SSimon Glass &usb_eth[usb_max_eth_dev], 8689d48367SSimon Glass &usb_eth[usb_max_eth_dev].eth_dev)) { 8789d48367SSimon Glass /* found proper driver */ 8889d48367SSimon Glass /* register with networking stack */ 8989d48367SSimon Glass usb_max_eth_dev++; 9089d48367SSimon Glass 9189d48367SSimon Glass /* 9289d48367SSimon Glass * usb_max_eth_dev must be incremented prior to this 9389d48367SSimon Glass * call since eth_current_changed (internally called) 9489d48367SSimon Glass * relies on it 9589d48367SSimon Glass */ 9689d48367SSimon Glass eth_register(&usb_eth[usb_max_eth_dev - 1].eth_dev); 9789d48367SSimon Glass break; 9889d48367SSimon Glass } 9989d48367SSimon Glass } 10089d48367SSimon Glass } 10189d48367SSimon Glass 10289d48367SSimon Glass /******************************************************************************* 10389d48367SSimon Glass * scan the usb and reports device info 10489d48367SSimon Glass * to the user if mode = 1 10589d48367SSimon Glass * returns current device or -1 if no 10689d48367SSimon Glass */ 10789d48367SSimon Glass int usb_host_eth_scan(int mode) 10889d48367SSimon Glass { 10989d48367SSimon Glass int i, old_async; 11089d48367SSimon Glass struct usb_device *dev; 11189d48367SSimon Glass 11289d48367SSimon Glass 11389d48367SSimon Glass if (mode == 1) 11489d48367SSimon Glass printf(" scanning bus for ethernet devices... "); 11589d48367SSimon Glass 11689d48367SSimon Glass old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ 11789d48367SSimon Glass 11889d48367SSimon Glass for (i = 0; i < USB_MAX_ETH_DEV; i++) 11989d48367SSimon Glass memset(&usb_eth[i], 0, sizeof(usb_eth[i])); 12089d48367SSimon Glass 12189d48367SSimon Glass for (i = 0; prob_dev[i].probe; i++) { 12289d48367SSimon Glass if (prob_dev[i].before_probe) 12389d48367SSimon Glass prob_dev[i].before_probe(); 12489d48367SSimon Glass } 12589d48367SSimon Glass 12689d48367SSimon Glass usb_max_eth_dev = 0; 12789d48367SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 12889d48367SSimon Glass dev = usb_get_dev_index(i); /* get device */ 12989d48367SSimon Glass debug("i=%d\n", i); 13089d48367SSimon Glass if (dev == NULL) 13189d48367SSimon Glass break; /* no more devices avaiable */ 13289d48367SSimon Glass 13389d48367SSimon Glass /* find valid usb_ether driver for this device, if any */ 13489d48367SSimon Glass probe_valid_drivers(dev); 13589d48367SSimon Glass 13689d48367SSimon Glass /* check limit */ 13789d48367SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) { 13889d48367SSimon Glass printf("max USB Ethernet Device reached: %d stopping\n", 13989d48367SSimon Glass usb_max_eth_dev); 14089d48367SSimon Glass break; 14189d48367SSimon Glass } 14289d48367SSimon Glass } /* for */ 14389d48367SSimon Glass 14489d48367SSimon Glass usb_disable_asynch(old_async); /* restore asynch value */ 14589d48367SSimon Glass printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); 14689d48367SSimon Glass if (usb_max_eth_dev > 0) 14789d48367SSimon Glass return 0; 14889d48367SSimon Glass return -1; 14989d48367SSimon Glass } 15089d48367SSimon Glass 151