1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Simple "CDC Subset" USB Networking Links |
4 | * Copyright (C) 2000-2005 by David Brownell |
5 | */ |
6 | |
7 | #include <linux/module.h> |
8 | #include <linux/kmod.h> |
9 | #include <linux/netdevice.h> |
10 | #include <linux/etherdevice.h> |
11 | #include <linux/ethtool.h> |
12 | #include <linux/workqueue.h> |
13 | #include <linux/mii.h> |
14 | #include <linux/usb.h> |
15 | #include <linux/usb/usbnet.h> |
16 | |
17 | |
18 | /* |
19 | * This supports simple USB network links that don't require any special |
20 | * framing or hardware control operations. The protocol used here is a |
21 | * strict subset of CDC Ethernet, with three basic differences reflecting |
22 | * the goal that almost any hardware should run it: |
23 | * |
24 | * - Minimal runtime control: one interface, no altsettings, and |
25 | * no vendor or class specific control requests. If a device is |
26 | * configured, it is allowed to exchange packets with the host. |
27 | * Fancier models would mean not working on some hardware. |
28 | * |
29 | * - Minimal manufacturing control: no IEEE "Organizationally |
30 | * Unique ID" required, or an EEPROMs to store one. Each host uses |
31 | * one random "locally assigned" Ethernet address instead, which can |
32 | * of course be overridden using standard tools like "ifconfig". |
33 | * (With 2^46 such addresses, same-net collisions are quite rare.) |
34 | * |
35 | * - There is no additional framing data for USB. Packets are written |
36 | * exactly as in CDC Ethernet, starting with an Ethernet header and |
37 | * terminated by a short packet. However, the host will never send a |
38 | * zero length packet; some systems can't handle those robustly. |
39 | * |
40 | * Anything that can transmit and receive USB bulk packets can implement |
41 | * this protocol. That includes both smart peripherals and quite a lot |
42 | * of "host-to-host" USB cables (which embed two devices back-to-back). |
43 | * |
44 | * Note that although Linux may use many of those host-to-host links |
45 | * with this "cdc_subset" framing, that doesn't mean there may not be a |
46 | * better approach. Handling the "other end unplugs/replugs" scenario |
47 | * well tends to require chip-specific vendor requests. Also, Windows |
48 | * peers at the other end of host-to-host cables may expect their own |
49 | * framing to be used rather than this "cdc_subset" model. |
50 | */ |
51 | |
52 | #if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX) |
53 | /* PDA style devices are always connected if present */ |
54 | static int always_connected (struct usbnet *dev) |
55 | { |
56 | return 0; |
57 | } |
58 | #endif |
59 | |
60 | #ifdef CONFIG_USB_ALI_M5632 |
61 | #define HAVE_HARDWARE |
62 | |
63 | /*------------------------------------------------------------------------- |
64 | * |
65 | * ALi M5632 driver ... does high speed |
66 | * |
67 | * NOTE that the MS-Windows drivers for this chip use some funky and |
68 | * (naturally) undocumented 7-byte prefix to each packet, so this is a |
69 | * case where we don't currently interoperate. Also, once you unplug |
70 | * one end of the cable, you need to replug the other end too ... since |
71 | * chip docs are unavailable, there's no way to reset the relevant state |
72 | * short of a power cycle. |
73 | * |
74 | *-------------------------------------------------------------------------*/ |
75 | |
76 | static void m5632_recover(struct usbnet *dev) |
77 | { |
78 | struct usb_device *udev = dev->udev; |
79 | struct usb_interface *intf = dev->intf; |
80 | int r; |
81 | |
82 | r = usb_lock_device_for_reset(udev, iface: intf); |
83 | if (r < 0) |
84 | return; |
85 | |
86 | usb_reset_device(dev: udev); |
87 | usb_unlock_device(udev); |
88 | } |
89 | |
90 | static const struct driver_info ali_m5632_info = { |
91 | .description = "ALi M5632" , |
92 | .flags = FLAG_POINTTOPOINT, |
93 | .recover = m5632_recover, |
94 | }; |
95 | |
96 | #endif |
97 | |
98 | #ifdef CONFIG_USB_AN2720 |
99 | #define HAVE_HARDWARE |
100 | |
101 | /*------------------------------------------------------------------------- |
102 | * |
103 | * AnchorChips 2720 driver ... http://www.cypress.com |
104 | * |
105 | * This doesn't seem to have a way to detect whether the peer is |
106 | * connected, or need any reset handshaking. It's got pretty big |
107 | * internal buffers (handles most of a frame's worth of data). |
108 | * Chip data sheets don't describe any vendor control messages. |
109 | * |
110 | *-------------------------------------------------------------------------*/ |
111 | |
112 | static const struct driver_info an2720_info = { |
113 | .description = "AnchorChips/Cypress 2720" , |
114 | .flags = FLAG_POINTTOPOINT, |
115 | // no reset available! |
116 | // no check_connect available! |
117 | |
118 | .in = 2, .out = 2, // direction distinguishes these |
119 | }; |
120 | |
121 | #endif /* CONFIG_USB_AN2720 */ |
122 | |
123 | |
124 | #ifdef CONFIG_USB_BELKIN |
125 | #define HAVE_HARDWARE |
126 | |
127 | /*------------------------------------------------------------------------- |
128 | * |
129 | * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller |
130 | * |
131 | * ... also two eTEK designs, including one sold as "Advance USBNET" |
132 | * |
133 | *-------------------------------------------------------------------------*/ |
134 | |
135 | static const struct driver_info belkin_info = { |
136 | .description = "Belkin, eTEK, or compatible" , |
137 | .flags = FLAG_POINTTOPOINT, |
138 | }; |
139 | |
140 | #endif /* CONFIG_USB_BELKIN */ |
141 | |
142 | |
143 | |
144 | #ifdef CONFIG_USB_EPSON2888 |
145 | #define HAVE_HARDWARE |
146 | |
147 | /*------------------------------------------------------------------------- |
148 | * |
149 | * EPSON USB clients |
150 | * |
151 | * This is the same idea as Linux PDAs (below) except the firmware in the |
152 | * device might not be Tux-powered. Epson provides reference firmware that |
153 | * implements this interface. Product developers can reuse or modify that |
154 | * code, such as by using their own product and vendor codes. |
155 | * |
156 | * Support was from Juro Bystricky <bystricky.juro@erd.epson.com> |
157 | * |
158 | *-------------------------------------------------------------------------*/ |
159 | |
160 | static const struct driver_info epson2888_info = { |
161 | .description = "Epson USB Device" , |
162 | .check_connect = always_connected, |
163 | .flags = FLAG_POINTTOPOINT, |
164 | |
165 | .in = 4, .out = 3, |
166 | }; |
167 | |
168 | #endif /* CONFIG_USB_EPSON2888 */ |
169 | |
170 | |
171 | /*------------------------------------------------------------------------- |
172 | * |
173 | * info from Jonathan McDowell <noodles@earth.li> |
174 | * |
175 | *-------------------------------------------------------------------------*/ |
176 | #ifdef CONFIG_USB_KC2190 |
177 | #define HAVE_HARDWARE |
178 | static const struct driver_info kc2190_info = { |
179 | .description = "KC Technology KC-190" , |
180 | .flags = FLAG_POINTTOPOINT, |
181 | }; |
182 | #endif /* CONFIG_USB_KC2190 */ |
183 | |
184 | |
185 | #ifdef CONFIG_USB_ARMLINUX |
186 | #define HAVE_HARDWARE |
187 | |
188 | /*------------------------------------------------------------------------- |
189 | * |
190 | * Intel's SA-1100 chip integrates basic USB support, and is used |
191 | * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. |
192 | * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to |
193 | * network using minimal USB framing data. |
194 | * |
195 | * This describes the driver currently in standard ARM Linux kernels. |
196 | * The Zaurus uses a different driver (see later). |
197 | * |
198 | * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support |
199 | * and different USB endpoint numbering than the SA1100 devices. The |
200 | * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 |
201 | * so we rely on the endpoint descriptors. |
202 | * |
203 | *-------------------------------------------------------------------------*/ |
204 | |
205 | static const struct driver_info linuxdev_info = { |
206 | .description = "Linux Device" , |
207 | .check_connect = always_connected, |
208 | .flags = FLAG_POINTTOPOINT, |
209 | }; |
210 | |
211 | static const struct driver_info yopy_info = { |
212 | .description = "Yopy" , |
213 | .check_connect = always_connected, |
214 | .flags = FLAG_POINTTOPOINT, |
215 | }; |
216 | |
217 | static const struct driver_info blob_info = { |
218 | .description = "Boot Loader OBject" , |
219 | .check_connect = always_connected, |
220 | .flags = FLAG_POINTTOPOINT, |
221 | }; |
222 | |
223 | #endif /* CONFIG_USB_ARMLINUX */ |
224 | |
225 | |
226 | /*-------------------------------------------------------------------------*/ |
227 | |
228 | #ifndef HAVE_HARDWARE |
229 | #warning You need to configure some hardware for this driver |
230 | #endif |
231 | |
232 | /* |
233 | * chip vendor names won't normally be on the cables, and |
234 | * may not be on the device. |
235 | */ |
236 | |
237 | static const struct usb_device_id products [] = { |
238 | |
239 | #ifdef CONFIG_USB_ALI_M5632 |
240 | { |
241 | USB_DEVICE (0x0402, 0x5632), // ALi defaults |
242 | .driver_info = (unsigned long) &ali_m5632_info, |
243 | }, |
244 | { |
245 | USB_DEVICE (0x182d,0x207c), // SiteCom CN-124 |
246 | .driver_info = (unsigned long) &ali_m5632_info, |
247 | }, |
248 | #endif |
249 | |
250 | #ifdef CONFIG_USB_AN2720 |
251 | { |
252 | USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults |
253 | .driver_info = (unsigned long) &an2720_info, |
254 | }, { |
255 | USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET |
256 | .driver_info = (unsigned long) &an2720_info, |
257 | }, |
258 | #endif |
259 | |
260 | #ifdef CONFIG_USB_BELKIN |
261 | { |
262 | USB_DEVICE (0x050d, 0x0004), // Belkin |
263 | .driver_info = (unsigned long) &belkin_info, |
264 | }, { |
265 | USB_DEVICE (0x056c, 0x8100), // eTEK |
266 | .driver_info = (unsigned long) &belkin_info, |
267 | }, { |
268 | USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK) |
269 | .driver_info = (unsigned long) &belkin_info, |
270 | }, |
271 | #endif |
272 | |
273 | #ifdef CONFIG_USB_EPSON2888 |
274 | { |
275 | USB_DEVICE (0x0525, 0x2888), // EPSON USB client |
276 | .driver_info = (unsigned long) &epson2888_info, |
277 | }, |
278 | #endif |
279 | |
280 | #ifdef CONFIG_USB_KC2190 |
281 | { |
282 | USB_DEVICE (0x050f, 0x0190), // KC-190 |
283 | .driver_info = (unsigned long) &kc2190_info, |
284 | }, |
285 | #endif |
286 | |
287 | #ifdef CONFIG_USB_ARMLINUX |
288 | /* |
289 | * SA-1100 using standard ARM Linux kernels, or compatible. |
290 | * Often used when talking to Linux PDAs (iPaq, Yopy, etc). |
291 | * The sa-1100 "usb-eth" driver handles the basic framing. |
292 | * |
293 | * PXA25x or PXA210 ... these use a "usb-eth" driver much like |
294 | * the sa1100 one, but hardware uses different endpoint numbers. |
295 | * |
296 | * Or the Linux "Ethernet" gadget on hardware that can't talk |
297 | * CDC Ethernet (e.g., no altsettings), in either of two modes: |
298 | * - acting just like the old "usb-eth" firmware, though |
299 | * the implementation is different |
300 | * - supporting RNDIS as the first/default configuration for |
301 | * MS-Windows interop; Linux needs to use the other config |
302 | */ |
303 | { |
304 | // 1183 = 0x049F, both used as hex values? |
305 | // Compaq "Itsy" vendor/product id |
306 | USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible |
307 | .driver_info = (unsigned long) &linuxdev_info, |
308 | }, { |
309 | USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" |
310 | .driver_info = (unsigned long) &yopy_info, |
311 | }, { |
312 | USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader |
313 | .driver_info = (unsigned long) &blob_info, |
314 | }, { |
315 | USB_DEVICE (0x1286, 0x8001), // "blob" bootloader |
316 | .driver_info = (unsigned long) &blob_info, |
317 | }, { |
318 | // Linux Ethernet/RNDIS gadget, mostly on PXA, second config |
319 | // e.g. Gumstix, current OpenZaurus, ... or anything else |
320 | // that just enables this gadget option. |
321 | USB_DEVICE (0x0525, 0xa4a2), |
322 | .driver_info = (unsigned long) &linuxdev_info, |
323 | }, |
324 | #endif |
325 | |
326 | { }, // END |
327 | }; |
328 | MODULE_DEVICE_TABLE(usb, products); |
329 | |
330 | /*-------------------------------------------------------------------------*/ |
331 | static int dummy_prereset(struct usb_interface *intf) |
332 | { |
333 | return 0; |
334 | } |
335 | |
336 | static int dummy_postreset(struct usb_interface *intf) |
337 | { |
338 | return 0; |
339 | } |
340 | |
341 | static struct usb_driver cdc_subset_driver = { |
342 | .name = "cdc_subset" , |
343 | .probe = usbnet_probe, |
344 | .suspend = usbnet_suspend, |
345 | .resume = usbnet_resume, |
346 | .pre_reset = dummy_prereset, |
347 | .post_reset = dummy_postreset, |
348 | .disconnect = usbnet_disconnect, |
349 | .id_table = products, |
350 | .disable_hub_initiated_lpm = 1, |
351 | }; |
352 | |
353 | module_usb_driver(cdc_subset_driver); |
354 | |
355 | MODULE_AUTHOR("David Brownell" ); |
356 | MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links" ); |
357 | MODULE_LICENSE("GPL" ); |
358 | |