Revision | 89d48367edbc878f86db3008a4107331ef07f578 (tree) |
---|---|
Time | 2011-02-20 04:32:36 |
Author | Simon Glass <sjg@chro...> |
Commiter | Remy Bohmer |
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>
@@ -235,6 +235,7 @@ endif | ||
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) |
@@ -522,11 +525,16 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | ||
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 @@ int usb_stop(void) | ||
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 @@ USB Support for PIP405 and MIP405 (UHCI) | ||
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,3 +79,4 @@ CONFIG_USB_UHCI defines the lowlevel part.A lowlevel part must be defined | ||
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 |
@@ -0,0 +1,45 @@ | ||
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 | +######################################################################### |
@@ -0,0 +1,143 @@ | ||
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 | +} | |
143 | + |
@@ -168,6 +168,13 @@ int usb_stor_info(void); | ||
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 @@ int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, | ||
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, |
@@ -0,0 +1,61 @@ | ||
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 @@ int eth_get_dev_index (void) | ||
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 @@ int eth_initialize(bd_t *bis) | ||
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 @@ void eth_try_another(int first_restart) | ||
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 @@ void eth_set_current(void) | ||
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) |