Commit 89d48367edbc878f86db3008a4107331ef07f578

Authored by Simon Glass
Committed by Remy Bohmer
1 parent 96820a3587

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>

Showing 9 changed files with 298 additions and 24 deletions Side-by-side Diff

... ... @@ -235,6 +235,7 @@
235 235 LIBS += drivers/rtc/librtc.o
236 236 LIBS += drivers/serial/libserial.o
237 237 LIBS += drivers/twserial/libtws.o
  238 +LIBS += drivers/usb/eth/libusb_eth.a
238 239 LIBS += drivers/usb/gadget/libusb_gadget.o
239 240 LIBS += drivers/usb/host/libusb_host.o
240 241 LIBS += drivers/usb/musb/libusb_musb.o
... ... @@ -34,6 +34,9 @@
34 34 #ifdef CONFIG_USB_STORAGE
35 35 static int usb_stor_curr_dev = -1; /* current device */
36 36 #endif
  37 +#ifdef CONFIG_USB_HOST_ETHER
  38 +static int usb_ether_curr_dev = -1; /* current ethernet device */
  39 +#endif
37 40  
38 41 /* some display routines (info command) */
39 42 char *usb_get_class_desc(unsigned char dclass)
40 43  
41 44  
... ... @@ -522,11 +525,16 @@
522 525 usb_stop();
523 526 printf("(Re)start USB...\n");
524 527 i = usb_init();
  528 + if (i >= 0) {
525 529 #ifdef CONFIG_USB_STORAGE
526   - /* try to recognize storage devices immediately */
527   - if (i >= 0)
  530 + /* try to recognize storage devices immediately */
528 531 usb_stor_curr_dev = usb_stor_scan(1);
529 532 #endif
  533 +#ifdef CONFIG_USB_HOST_ETHER
  534 + /* try to recognize ethernet devices immediately */
  535 + usb_ether_curr_dev = usb_host_eth_scan(1);
  536 +#endif
  537 + }
530 538 return 0;
531 539 }
532 540 if (strncmp(argv[1], "stop", 4) == 0) {
... ... @@ -145,10 +145,14 @@
145 145 /*
146 146 * disables the asynch behaviour of the control message. This is used for data
147 147 * transfers that uses the exclusiv access to the control and bulk messages.
  148 + * Returns the old value so it can be restored later.
148 149 */
149   -void usb_disable_asynch(int disable)
  150 +int usb_disable_asynch(int disable)
150 151 {
  152 + int old_value = asynch_allowed;
  153 +
151 154 asynch_allowed = !disable;
  155 + return old_value;
152 156 }
153 157  
154 158  
... ... @@ -28,7 +28,8 @@
28 28 The USB support is implemented on the base of the UHCI Host
29 29 controller.
30 30  
31   -Currently supported are USB Hubs, USB Keyboards and USB Floppys.
  31 +Currently supported are USB Hubs, USB Keyboards, USB Floppys, USB
  32 +flash sticks and USB network adaptors.
32 33 Tested with a TEAC Floppy TEAC FD-05PUB and Chicony KU-8933 Keyboard.
33 34  
34 35 How it works:
... ... @@ -78,4 +79,5 @@
78 79 if using CONFIG_CMD_USB
79 80 CONFIG_USB_KEYBOARD enables the USB Keyboard
80 81 CONFIG_USB_STORAGE enables the USB storage devices
  82 +CONFIG_USB_HOST_ETHER enables USB ethernet dongle support
drivers/usb/eth/Makefile
  1 +#
  2 +# Copyright (c) 2011 The Chromium OS Authors.
  3 +# See file CREDITS for list of people who contributed to this
  4 +# project.
  5 +#
  6 +# This program is free software; you can redistribute it and/or
  7 +# modify it under the terms of the GNU General Public License as
  8 +# published by the Free Software Foundation; either version 2 of
  9 +# the License, or (at your option) any later version.
  10 +#
  11 +# This program is distributed in the hope that it will be useful,
  12 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 +# GNU General Public License for more details.
  15 +#
  16 +# You should have received a copy of the GNU General Public License
  17 +# along with this program; if not, write to the Free Software
  18 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19 +# MA 02111-1307 USA
  20 +#
  21 +
  22 +include $(TOPDIR)/config.mk
  23 +
  24 +LIB := $(obj)libusb_eth.a
  25 +
  26 +# new USB host ethernet layer dependencies
  27 +COBJS-$(CONFIG_USB_HOST_ETHER) += usb_ether.o
  28 +
  29 +COBJS := $(COBJS-y)
  30 +SRCS := $(COBJS:.o=.c)
  31 +OBJS := $(addprefix $(obj),$(COBJS))
  32 +
  33 +all: $(LIB)
  34 +
  35 +$(LIB): $(obj).depend $(OBJS)
  36 + $(AR) $(ARFLAGS) $@ $(OBJS)
  37 +
  38 +#########################################################################
  39 +
  40 +# defines $(obj).depend target
  41 +include $(SRCTREE)/rules.mk
  42 +
  43 +sinclude $(obj).depend
  44 +
  45 +#########################################################################
drivers/usb/eth/usb_ether.c
  1 +/*
  2 + * Copyright (c) 2011 The Chromium OS Authors.
  3 + * See file CREDITS for list of people who contributed to this
  4 + * project.
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License as
  8 + * published by the Free Software Foundation; either version 2 of
  9 + * the License, or (at your option) any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU General Public License
  17 + * along with this program; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19 + * MA 02111-1307 USA
  20 + */
  21 +
  22 +#include <common.h>
  23 +#include <usb.h>
  24 +
  25 +#include "usb_ether.h"
  26 +
  27 +typedef void (*usb_eth_before_probe)(void);
  28 +typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
  29 + struct ueth_data *ss);
  30 +typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss,
  31 + struct eth_device *dev_desc);
  32 +
  33 +struct usb_eth_prob_dev {
  34 + usb_eth_before_probe before_probe; /* optional */
  35 + usb_eth_probe probe;
  36 + usb_eth_get_info get_info;
  37 +};
  38 +
  39 +/* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */
  40 +static const struct usb_eth_prob_dev prob_dev[] = {
  41 + { }, /* END */
  42 +};
  43 +
  44 +static int usb_max_eth_dev; /* number of highest available usb eth device */
  45 +static struct ueth_data usb_eth[USB_MAX_ETH_DEV];
  46 +
  47 +/*******************************************************************************
  48 + * tell if current ethernet device is a usb dongle
  49 + */
  50 +int is_eth_dev_on_usb_host(void)
  51 +{
  52 + int i;
  53 + struct eth_device *dev = eth_get_dev();
  54 +
  55 + if (dev) {
  56 + for (i = 0; i < usb_max_eth_dev; i++)
  57 + if (&usb_eth[i].eth_dev == dev)
  58 + return 1;
  59 + }
  60 + return 0;
  61 +}
  62 +
  63 +/*
  64 + * Given a USB device, ask each driver if it can support it, and attach it
  65 + * to the first driver that says 'yes'
  66 + */
  67 +static void probe_valid_drivers(struct usb_device *dev)
  68 +{
  69 + int j;
  70 +
  71 + for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) {
  72 + if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev]))
  73 + continue;
  74 + /*
  75 + * ok, it is a supported eth device. Get info and fill it in
  76 + */
  77 + if (prob_dev[j].get_info(dev,
  78 + &usb_eth[usb_max_eth_dev],
  79 + &usb_eth[usb_max_eth_dev].eth_dev)) {
  80 + /* found proper driver */
  81 + /* register with networking stack */
  82 + usb_max_eth_dev++;
  83 +
  84 + /*
  85 + * usb_max_eth_dev must be incremented prior to this
  86 + * call since eth_current_changed (internally called)
  87 + * relies on it
  88 + */
  89 + eth_register(&usb_eth[usb_max_eth_dev - 1].eth_dev);
  90 + break;
  91 + }
  92 + }
  93 + }
  94 +
  95 +/*******************************************************************************
  96 + * scan the usb and reports device info
  97 + * to the user if mode = 1
  98 + * returns current device or -1 if no
  99 + */
  100 +int usb_host_eth_scan(int mode)
  101 +{
  102 + int i, old_async;
  103 + struct usb_device *dev;
  104 +
  105 +
  106 + if (mode == 1)
  107 + printf(" scanning bus for ethernet devices... ");
  108 +
  109 + old_async = usb_disable_asynch(1); /* asynch transfer not allowed */
  110 +
  111 + for (i = 0; i < USB_MAX_ETH_DEV; i++)
  112 + memset(&usb_eth[i], 0, sizeof(usb_eth[i]));
  113 +
  114 + for (i = 0; prob_dev[i].probe; i++) {
  115 + if (prob_dev[i].before_probe)
  116 + prob_dev[i].before_probe();
  117 + }
  118 +
  119 + usb_max_eth_dev = 0;
  120 + for (i = 0; i < USB_MAX_DEVICE; i++) {
  121 + dev = usb_get_dev_index(i); /* get device */
  122 + debug("i=%d\n", i);
  123 + if (dev == NULL)
  124 + break; /* no more devices avaiable */
  125 +
  126 + /* find valid usb_ether driver for this device, if any */
  127 + probe_valid_drivers(dev);
  128 +
  129 + /* check limit */
  130 + if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
  131 + printf("max USB Ethernet Device reached: %d stopping\n",
  132 + usb_max_eth_dev);
  133 + break;
  134 + }
  135 + } /* for */
  136 +
  137 + usb_disable_asynch(old_async); /* restore asynch value */
  138 + printf("%d Ethernet Device(s) found\n", usb_max_eth_dev);
  139 + if (usb_max_eth_dev > 0)
  140 + return 0;
  141 + return -1;
  142 +}
... ... @@ -168,6 +168,13 @@
168 168  
169 169 #endif
170 170  
  171 +#ifdef CONFIG_USB_HOST_ETHER
  172 +
  173 +#define USB_MAX_ETH_DEV 5
  174 +int usb_host_eth_scan(int mode);
  175 +
  176 +#endif
  177 +
171 178 #ifdef CONFIG_USB_KEYBOARD
172 179  
173 180 int drv_usb_kbd_init(void);
... ... @@ -191,7 +198,7 @@
191 198 void *data, int len, int *actual_length, int timeout);
192 199 int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
193 200 void *buffer, int transfer_len, int interval);
194   -void usb_disable_asynch(int disable);
  201 +int usb_disable_asynch(int disable);
195 202 int usb_maxpacket(struct usb_device *dev, unsigned long pipe);
196 203 inline void wait_ms(unsigned long ms);
197 204 int usb_get_configuration_no(struct usb_device *dev, unsigned char *buffer,
  1 +/*
  2 + * Copyright (c) 2011 The Chromium OS Authors.
  3 + * See file CREDITS for list of people who contributed to this
  4 + * project.
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License as
  8 + * published by the Free Software Foundation; either version 2 of
  9 + * the License, or (at your option) any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU General Public License
  17 + * along with this program; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19 + * MA 02111-1307 USA
  20 + */
  21 +
  22 +#ifndef __USB_ETHER_H__
  23 +#define __USB_ETHER_H__
  24 +
  25 +#include <net.h>
  26 +
  27 +/*
  28 + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
  29 + * and FCS/CRC (frame check sequence).
  30 + */
  31 +#define ETH_ALEN 6 /* Octets in one ethernet addr */
  32 +#define ETH_HLEN 14 /* Total octets in header. */
  33 +#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
  34 +#define ETH_DATA_LEN 1500 /* Max. octets in payload */
  35 +#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
  36 +#define ETH_FCS_LEN 4 /* Octets in the FCS */
  37 +
  38 +struct ueth_data {
  39 + /* eth info */
  40 + struct eth_device eth_dev; /* used with eth_register */
  41 + int phy_id; /* mii phy id */
  42 +
  43 + /* usb info */
  44 + struct usb_device *pusb_dev; /* this usb_device */
  45 + unsigned char ifnum; /* interface number */
  46 + unsigned char ep_in; /* in endpoint */
  47 + unsigned char ep_out; /* out ....... */
  48 + unsigned char ep_int; /* interrupt . */
  49 + unsigned char subclass; /* as in overview */
  50 + unsigned char protocol; /* .............. */
  51 + unsigned char irqinterval; /* Intervall for IRQ Pipe */
  52 +
  53 + /* private fields for each driver can go here if needed */
  54 +};
  55 +
  56 +/*
  57 + * Function definitions for each USB ethernet driver go here, bracketed by
  58 + * #ifdef CONFIG_USB_ETHER_xxx...#endif
  59 + */
  60 +
  61 +#endif /* __USB_ETHER_H__ */
... ... @@ -166,20 +166,33 @@
166 166 return (0);
167 167 }
168 168  
169   -int eth_register(struct eth_device* dev)
  169 +static void eth_current_changed(void)
170 170 {
171   - struct eth_device *d;
172   -
173   - if (!eth_devices) {
174   - eth_current = eth_devices = dev;
175 171 #ifdef CONFIG_NET_MULTI
  172 + {
  173 + char *act = getenv("ethact");
176 174 /* update current ethernet name */
  175 + if (eth_current)
177 176 {
178   - char *act = getenv("ethact");
179 177 if (act == NULL || strcmp(act, eth_current->name) != 0)
180 178 setenv("ethact", eth_current->name);
181 179 }
  180 + /*
  181 + * remove the variable completely if there is no active
  182 + * interface
  183 + */
  184 + else if (act != NULL)
  185 + setenv("ethact", NULL);
  186 + }
182 187 #endif
  188 +}
  189 +
  190 +int eth_register(struct eth_device *dev)
  191 +{
  192 + struct eth_device *d;
  193 + if (!eth_devices) {
  194 + eth_current = eth_devices = dev;
  195 + eth_current_changed();
183 196 } else {
184 197 for (d=eth_devices; d->next!=eth_devices; d=d->next)
185 198 ;
... ... @@ -271,14 +284,7 @@
271 284 dev = dev->next;
272 285 } while(dev != eth_devices);
273 286  
274   - /* update current ethernet name */
275   - if (eth_current) {
276   - char *act = getenv("ethact");
277   - if (act == NULL || strcmp(act, eth_current->name) != 0)
278   - setenv("ethact", eth_current->name);
279   - } else
280   - setenv("ethact", NULL);
281   -
  287 + eth_current_changed();
282 288 putc ('\n');
283 289 }
284 290  
... ... @@ -466,10 +472,7 @@
466 472  
467 473 eth_current = eth_current->next;
468 474  
469   - /* update current ethernet name */
470   - act = getenv("ethact");
471   - if (act == NULL || strcmp(act, eth_current->name) != 0)
472   - setenv("ethact", eth_current->name);
  475 + eth_current_changed();
473 476  
474 477 if (first_failed == eth_current) {
475 478 NetRestartWrap = 1;
... ... @@ -500,7 +503,7 @@
500 503 } while (old_current != eth_current);
501 504 }
502 505  
503   - setenv("ethact", eth_current->name);
  506 + eth_current_changed();
504 507 }
505 508  
506 509 char *eth_get_name (void)