[U-Boot] [PATCH 1/2 V2] Add USB host ethernet adapter support

Simon Glass sjg at chromium.org
Tue Feb 8 19:55:36 CET 2011


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 at chromium.org>
---
 Makefile                    |    1 +
 common/cmd_usb.c            |   12 +++-
 common/usb.c                |    6 ++-
 doc/README.usb              |    4 +-
 drivers/usb/eth/Makefile    |   45 ++++++++++++++
 drivers/usb/eth/usb_ether.c |  143 +++++++++++++++++++++++++++++++++++++++++++
 include/usb.h               |    9 +++-
 include/usb_ether.h         |   61 ++++++++++++++++++
 net/eth.c                   |   47 +++++++--------
 9 files changed, 298 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/eth/Makefile
 create mode 100644 drivers/usb/eth/usb_ether.c
 create mode 100644 include/usb_ether.h

diff --git a/Makefile b/Makefile
index 60b6494..bbee4f8 100644
--- a/Makefile
+++ b/Makefile
@@ -237,6 +237,7 @@ endif
 LIBS += drivers/rtc/librtc.a
 LIBS += drivers/serial/libserial.a
 LIBS += drivers/twserial/libtws.a
+LIBS += drivers/usb/eth/libusb_eth.a
 LIBS += drivers/usb/gadget/libusb_gadget.a
 LIBS += drivers/usb/host/libusb_host.a
 LIBS += drivers/usb/musb/libusb_musb.a
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index 6b5c582..b270eb0 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)
@@ -521,11 +524,16 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char *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 10e23de..94f26f4 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -142,10 +142,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 b3bcb91..9aa4f62 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 0000000..a0f5676
--- /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 0000000..c2342ed
--- /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 26dc818..0a97187 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 0000000..31cbc8d
--- /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__ */
diff --git a/net/eth.c b/net/eth.c
index b650a20..894c9ab 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -158,20 +158,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);
 		d->next = dev;
@@ -246,15 +259,7 @@ int eth_initialize(bd_t *bis)
 			dev = dev->next;
 		} while(dev != eth_devices);
 
-#ifdef CONFIG_NET_MULTI
-		/* 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);
-#endif
+		eth_current_changed();
 
 		putc ('\n');
 	}
@@ -442,15 +447,7 @@ void eth_try_another(int first_restart)
 	}
 
 	eth_current = eth_current->next;
-
-#ifdef CONFIG_NET_MULTI
-	/* update current ethernet name */
-	{
-		char *act = getenv("ethact");
-		if (act == NULL || strcmp(act, eth_current->name) != 0)
-			setenv("ethact", eth_current->name);
-	}
-#endif
+	eth_current_changed();
 
 	if (first_failed == eth_current) {
 		NetRestartWrap = 1;
@@ -482,7 +479,7 @@ void eth_set_current(void)
 		} while (old_current != eth_current);
 	}
 
-	setenv("ethact", eth_current->name);
+	eth_current_changed();
 }
 #endif
 
-- 
1.7.3.1



More information about the U-Boot mailing list