diff options
| author | Simon Glass <sjg@chromium.org> | 2011-02-16 11:14:33 -0800 | 
|---|---|---|
| committer | Remy Bohmer <linux@bohmer.net> | 2011-02-19 20:32:36 +0100 | 
| commit | 89d48367edbc878f86db3008a4107331ef07f578 (patch) | |
| tree | 808742d920445274c97d867422762b3b67cc8391 | |
| parent | 96820a35873b4c005f732432c6a168decc9d22b9 (diff) | |
| download | olio-uboot-2014.01-89d48367edbc878f86db3008a4107331ef07f578.tar.xz olio-uboot-2014.01-89d48367edbc878f86db3008a4107331ef07f578.zip | |
Add USB host ethernet adapter support
This adds support for using USB Ethernet dongles in host mode. This is just
the framework - drivers will come later. A new config option called
CONFIG_USB_HOST_ETHER can be defined in board config files to switch this
on.
The was originally written by NVIDIA and was cleaned up for release by the
Chromium authors.
Signed-off-by: Simon Glass <sjg@chromium.org>
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | common/cmd_usb.c | 12 | ||||
| -rw-r--r-- | common/usb.c | 6 | ||||
| -rw-r--r-- | doc/README.usb | 4 | ||||
| -rw-r--r-- | drivers/usb/eth/Makefile | 45 | ||||
| -rw-r--r-- | drivers/usb/eth/usb_ether.c | 143 | ||||
| -rw-r--r-- | include/usb.h | 9 | ||||
| -rw-r--r-- | include/usb_ether.h | 61 | ||||
| -rw-r--r-- | net/eth.c | 41 | 
9 files changed, 298 insertions, 24 deletions
| @@ -235,6 +235,7 @@ endif  LIBS += drivers/rtc/librtc.o  LIBS += drivers/serial/libserial.o  LIBS += drivers/twserial/libtws.o +LIBS += drivers/usb/eth/libusb_eth.a  LIBS += drivers/usb/gadget/libusb_gadget.o  LIBS += drivers/usb/host/libusb_host.o  LIBS += drivers/usb/musb/libusb_musb.o diff --git a/common/cmd_usb.c b/common/cmd_usb.c index b04a8df76..b5731a7bb 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -34,6 +34,9 @@  #ifdef CONFIG_USB_STORAGE  static int usb_stor_curr_dev = -1; /* current device */  #endif +#ifdef CONFIG_USB_HOST_ETHER +static int usb_ether_curr_dev = -1; /* current ethernet device */ +#endif  /* some display routines (info command) */  char *usb_get_class_desc(unsigned char dclass) @@ -522,11 +525,16 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		usb_stop();  		printf("(Re)start USB...\n");  		i = usb_init(); +		if (i >= 0) {  #ifdef CONFIG_USB_STORAGE -		/* try to recognize storage devices immediately */ -		if (i >= 0) +			/* try to recognize storage devices immediately */  			usb_stor_curr_dev = usb_stor_scan(1);  #endif +#ifdef CONFIG_USB_HOST_ETHER +			/* try to recognize ethernet devices immediately */ +			usb_ether_curr_dev = usb_host_eth_scan(1); +#endif +		}  		return 0;  	}  	if (strncmp(argv[1], "stop", 4) == 0) { diff --git a/common/usb.c b/common/usb.c index 44a435af6..4f7c520b3 100644 --- a/common/usb.c +++ b/common/usb.c @@ -145,10 +145,14 @@ int usb_stop(void)  /*   * disables the asynch behaviour of the control message. This is used for data   * transfers that uses the exclusiv access to the control and bulk messages. + * Returns the old value so it can be restored later.   */ -void usb_disable_asynch(int disable) +int usb_disable_asynch(int disable)  { +	int old_value = asynch_allowed; +  	asynch_allowed = !disable; +	return old_value;  } diff --git a/doc/README.usb b/doc/README.usb index b3bcb91f4..9aa4f62dd 100644 --- a/doc/README.usb +++ b/doc/README.usb @@ -28,7 +28,8 @@ USB Support for PIP405 and MIP405 (UHCI)  The USB support is implemented on the base of the UHCI Host  controller. -Currently supported are USB Hubs, USB Keyboards and USB Floppys. +Currently supported are USB Hubs, USB Keyboards, USB Floppys, USB +flash sticks and USB network adaptors.  Tested with a TEAC Floppy TEAC FD-05PUB and Chicony KU-8933 Keyboard.  How it works: @@ -78,3 +79,4 @@ CONFIG_USB_UHCI	    defines the lowlevel part.A lowlevel part must be defined  		    if using CONFIG_CMD_USB  CONFIG_USB_KEYBOARD enables the USB Keyboard  CONFIG_USB_STORAGE  enables the USB storage devices +CONFIG_USB_HOST_ETHER	enables USB ethernet dongle support diff --git a/drivers/usb/eth/Makefile b/drivers/usb/eth/Makefile new file mode 100644 index 000000000..a0f56765b --- /dev/null +++ b/drivers/usb/eth/Makefile @@ -0,0 +1,45 @@ +# +# Copyright (c) 2011 The Chromium OS Authors. +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	:= $(obj)libusb_eth.a + +# new USB host ethernet layer dependencies +COBJS-$(CONFIG_USB_HOST_ETHER) += usb_ether.o + +COBJS	:= $(COBJS-y) +SRCS	:= $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) + +all:	$(LIB) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c new file mode 100644 index 000000000..c2342ed97 --- /dev/null +++ b/drivers/usb/eth/usb_ether.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <usb.h> + +#include "usb_ether.h" + +typedef void (*usb_eth_before_probe)(void); +typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum, +			struct ueth_data *ss); +typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss, +			struct eth_device *dev_desc); + +struct usb_eth_prob_dev { +	usb_eth_before_probe	before_probe; /* optional */ +	usb_eth_probe			probe; +	usb_eth_get_info		get_info; +}; + +/* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */ +static const struct usb_eth_prob_dev prob_dev[] = { +	{ },		/* END */ +}; + +static int usb_max_eth_dev; /* number of highest available usb eth device */ +static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; + +/******************************************************************************* + * tell if current ethernet device is a usb dongle + */ +int is_eth_dev_on_usb_host(void) +{ +	int i; +	struct eth_device *dev = eth_get_dev(); + +	if (dev) { +		for (i = 0; i < usb_max_eth_dev; i++) +			if (&usb_eth[i].eth_dev == dev) +				return 1; +	} +	return 0; +} + +/* + * Given a USB device, ask each driver if it can support it, and attach it + * to the first driver that says 'yes' + */ +static void probe_valid_drivers(struct usb_device *dev) +{ +	int j; + +	for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) { +		if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev])) +			continue; +		/* +		 * ok, it is a supported eth device. Get info and fill it in +		 */ +		if (prob_dev[j].get_info(dev, +			&usb_eth[usb_max_eth_dev], +			&usb_eth[usb_max_eth_dev].eth_dev)) { +			/* found proper driver */ +			/* register with networking stack */ +			usb_max_eth_dev++; + +			/* +			 * usb_max_eth_dev must be incremented prior to this +			 * call since eth_current_changed (internally called) +			 * relies on it +			 */ +			eth_register(&usb_eth[usb_max_eth_dev - 1].eth_dev); +			break; +			} +		} +	} + +/******************************************************************************* + * scan the usb and reports device info + * to the user if mode = 1 + * returns current device or -1 if no + */ +int usb_host_eth_scan(int mode) +{ +	int i, old_async; +	struct usb_device *dev; + + +	if (mode == 1) +		printf("       scanning bus for ethernet devices... "); + +	old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ + +	for (i = 0; i < USB_MAX_ETH_DEV; i++) +		memset(&usb_eth[i], 0, sizeof(usb_eth[i])); + +	for (i = 0; prob_dev[i].probe; i++) { +		if (prob_dev[i].before_probe) +			prob_dev[i].before_probe(); +	} + +	usb_max_eth_dev = 0; +	for (i = 0; i < USB_MAX_DEVICE; i++) { +		dev = usb_get_dev_index(i); /* get device */ +		debug("i=%d\n", i); +		if (dev == NULL) +			break; /* no more devices avaiable */ + +		/* find valid usb_ether driver for this device, if any */ +		probe_valid_drivers(dev); + +		/* check limit */ +		if (usb_max_eth_dev == USB_MAX_ETH_DEV) { +			printf("max USB Ethernet Device reached: %d stopping\n", +				usb_max_eth_dev); +			break; +		} +	} /* for */ + +	usb_disable_asynch(old_async); /* restore asynch value */ +	printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); +	if (usb_max_eth_dev > 0) +		return 0; +	return -1; +} + diff --git a/include/usb.h b/include/usb.h index 98576b73a..53603a558 100644 --- a/include/usb.h +++ b/include/usb.h @@ -168,6 +168,13 @@ int usb_stor_info(void);  #endif +#ifdef CONFIG_USB_HOST_ETHER + +#define USB_MAX_ETH_DEV 5 +int usb_host_eth_scan(int mode); + +#endif +  #ifdef CONFIG_USB_KEYBOARD  int drv_usb_kbd_init(void); @@ -191,7 +198,7 @@ int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,  			void *data, int len, int *actual_length, int timeout);  int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,  			void *buffer, int transfer_len, int interval); -void usb_disable_asynch(int disable); +int usb_disable_asynch(int disable);  int usb_maxpacket(struct usb_device *dev, unsigned long pipe);  inline void wait_ms(unsigned long ms);  int usb_get_configuration_no(struct usb_device *dev, unsigned char *buffer, diff --git a/include/usb_ether.h b/include/usb_ether.h new file mode 100644 index 000000000..31cbc8d58 --- /dev/null +++ b/include/usb_ether.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __USB_ETHER_H__ +#define __USB_ETHER_H__ + +#include <net.h> + +/* + *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble + *	and FCS/CRC (frame check sequence). + */ +#define ETH_ALEN	6		/* Octets in one ethernet addr	 */ +#define ETH_HLEN	14		/* Total octets in header.	 */ +#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */ +#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */ +#define ETH_FRAME_LEN	PKTSIZE_ALIGN	/* Max. octets in frame sans FCS */ +#define ETH_FCS_LEN	4		/* Octets in the FCS		 */ + +struct ueth_data { +	/* eth info */ +	struct eth_device eth_dev;		/* used with eth_register */ +	int phy_id;						/* mii phy id */ + +	/* usb info */ +	struct usb_device *pusb_dev;	/* this usb_device */ +	unsigned char	ifnum;			/* interface number */ +	unsigned char	ep_in;			/* in endpoint */ +	unsigned char	ep_out;			/* out ....... */ +	unsigned char	ep_int;			/* interrupt . */ +	unsigned char	subclass;		/* as in overview */ +	unsigned char	protocol;		/* .............. */ +	unsigned char	irqinterval;	/* Intervall for IRQ Pipe */ + +	/* private fields for each driver can go here if needed */ +}; + +/* + * Function definitions for each USB ethernet driver go here, bracketed by + * #ifdef CONFIG_USB_ETHER_xxx...#endif + */ + +#endif /* __USB_ETHER_H__ */ @@ -166,20 +166,33 @@ int eth_get_dev_index (void)  	return (0);  } -int eth_register(struct eth_device* dev) +static void eth_current_changed(void)  { -	struct eth_device *d; - -	if (!eth_devices) { -		eth_current = eth_devices = dev;  #ifdef CONFIG_NET_MULTI +	{ +		char *act = getenv("ethact");  		/* update current ethernet name */ +		if (eth_current)  		{ -			char *act = getenv("ethact");  			if (act == NULL || strcmp(act, eth_current->name) != 0)  				setenv("ethact", eth_current->name);  		} +		/* +		 * remove the variable completely if there is no active +		 * interface +		 */ +		else if (act != NULL) +			setenv("ethact", NULL); +	}  #endif +} + +int eth_register(struct eth_device *dev) +{ +	struct eth_device *d; +	if (!eth_devices) { +		eth_current = eth_devices = dev; +		eth_current_changed();  	} else {  		for (d=eth_devices; d->next!=eth_devices; d=d->next)  			; @@ -271,14 +284,7 @@ int eth_initialize(bd_t *bis)  			dev = dev->next;  		} while(dev != eth_devices); -		/* update current ethernet name */ -		if (eth_current) { -			char *act = getenv("ethact"); -			if (act == NULL || strcmp(act, eth_current->name) != 0) -				setenv("ethact", eth_current->name); -		} else -			setenv("ethact", NULL); - +		eth_current_changed();  		putc ('\n');  	} @@ -466,10 +472,7 @@ void eth_try_another(int first_restart)  	eth_current = eth_current->next; -	/* update current ethernet name */ -	act = getenv("ethact"); -	if (act == NULL || strcmp(act, eth_current->name) != 0) -		setenv("ethact", eth_current->name); +	eth_current_changed();  	if (first_failed == eth_current) {  		NetRestartWrap = 1; @@ -500,7 +503,7 @@ void eth_set_current(void)  		} while (old_current != eth_current);  	} -	setenv("ethact", eth_current->name); +	eth_current_changed();  }  char *eth_get_name (void) |