diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/Makefile | 8 | ||||
-rw-r--r-- | drivers/net/usb/Kconfig | 338 | ||||
-rw-r--r-- | drivers/net/usb/Makefile | 23 | ||||
-rw-r--r-- | drivers/net/usb/asix.c | 1490 | ||||
-rw-r--r-- | drivers/net/usb/catc.c | 963 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ether.c | 570 | ||||
-rw-r--r-- | drivers/net/usb/cdc_subset.c | 344 | ||||
-rw-r--r-- | drivers/net/usb/dm9601.c | 619 | ||||
-rw-r--r-- | drivers/net/usb/gl620a.c | 245 | ||||
-rw-r--r-- | drivers/net/usb/kaweth.c | 1337 | ||||
-rw-r--r-- | drivers/net/usb/kawethfw.h | 557 | ||||
-rw-r--r-- | drivers/net/usb/mcs7830.c | 534 | ||||
-rw-r--r-- | drivers/net/usb/net1080.c | 615 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.c | 1504 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.h | 307 | ||||
-rw-r--r-- | drivers/net/usb/plusb.c | 150 | ||||
-rw-r--r-- | drivers/net/usb/rndis_host.c | 727 | ||||
-rw-r--r-- | drivers/net/usb/rtl8150.c | 1004 | ||||
-rw-r--r-- | drivers/net/usb/usbnet.c | 1304 | ||||
-rw-r--r-- | drivers/net/usb/usbnet.h | 200 | ||||
-rw-r--r-- | drivers/net/usb/zaurus.c | 385 |
22 files changed, 13226 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b86ccd2ecd5b..d9842d8544dc 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2499,6 +2499,8 @@ source "drivers/net/tokenring/Kconfig" | |||
2499 | 2499 | ||
2500 | source "drivers/net/wireless/Kconfig" | 2500 | source "drivers/net/wireless/Kconfig" |
2501 | 2501 | ||
2502 | source "drivers/net/usb/Kconfig" | ||
2503 | |||
2502 | source "drivers/net/pcmcia/Kconfig" | 2504 | source "drivers/net/pcmcia/Kconfig" |
2503 | 2505 | ||
2504 | source "drivers/net/wan/Kconfig" | 2506 | source "drivers/net/wan/Kconfig" |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 59c0459a037c..c5d8423573b6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -206,6 +206,14 @@ obj-$(CONFIG_TR) += tokenring/ | |||
206 | obj-$(CONFIG_WAN) += wan/ | 206 | obj-$(CONFIG_WAN) += wan/ |
207 | obj-$(CONFIG_ARCNET) += arcnet/ | 207 | obj-$(CONFIG_ARCNET) += arcnet/ |
208 | obj-$(CONFIG_NET_PCMCIA) += pcmcia/ | 208 | obj-$(CONFIG_NET_PCMCIA) += pcmcia/ |
209 | |||
210 | obj-$(CONFIG_USB_CATC) += usb/ | ||
211 | obj-$(CONFIG_USB_KAWETH) += usb/ | ||
212 | obj-$(CONFIG_USB_PEGASUS) += usb/ | ||
213 | obj-$(CONFIG_USB_RTL8150) += usb/ | ||
214 | obj-$(CONFIG_USB_USBNET) += usb/ | ||
215 | obj-$(CONFIG_USB_ZD1201) += usb/ | ||
216 | |||
209 | obj-y += wireless/ | 217 | obj-y += wireless/ |
210 | obj-$(CONFIG_NET_TULIP) += tulip/ | 218 | obj-$(CONFIG_NET_TULIP) += tulip/ |
211 | obj-$(CONFIG_HAMRADIO) += hamradio/ | 219 | obj-$(CONFIG_HAMRADIO) += hamradio/ |
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig new file mode 100644 index 000000000000..3de564b23147 --- /dev/null +++ b/drivers/net/usb/Kconfig | |||
@@ -0,0 +1,338 @@ | |||
1 | # | ||
2 | # USB Network devices configuration | ||
3 | # | ||
4 | comment "Networking support is needed for USB Network Adapter support" | ||
5 | depends on USB && !NET | ||
6 | |||
7 | menu "USB Network Adapters" | ||
8 | depends on USB && NET | ||
9 | |||
10 | config USB_CATC | ||
11 | tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)" | ||
12 | depends on EXPERIMENTAL | ||
13 | select CRC32 | ||
14 | ---help--- | ||
15 | Say Y if you want to use one of the following 10Mbps USB Ethernet | ||
16 | device based on the EL1210A chip. Supported devices are: | ||
17 | Belkin F5U011 | ||
18 | Belkin F5U111 | ||
19 | CATC NetMate | ||
20 | CATC NetMate II | ||
21 | smartBridges smartNIC | ||
22 | |||
23 | This driver makes the adapter appear as a normal Ethernet interface, | ||
24 | typically on eth0, if it is the only ethernet device, or perhaps on | ||
25 | eth1, if you have a PCI or ISA ethernet card installed. | ||
26 | |||
27 | To compile this driver as a module, choose M here: the | ||
28 | module will be called catc. | ||
29 | |||
30 | config USB_KAWETH | ||
31 | tristate "USB KLSI KL5USB101-based ethernet device support" | ||
32 | ---help--- | ||
33 | Say Y here if you want to use one of the following 10Mbps only | ||
34 | USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: | ||
35 | 3Com 3C19250 | ||
36 | ADS USB-10BT | ||
37 | ATEN USB Ethernet | ||
38 | ASANTE USB To Ethernet Adapter | ||
39 | AOX Endpoints USB Ethernet | ||
40 | Correga K.K. | ||
41 | D-Link DSB-650C and DU-E10 | ||
42 | Entrega / Portgear E45 | ||
43 | I-O DATA USB-ET/T | ||
44 | Jaton USB Ethernet Device Adapter | ||
45 | Kingston Technology USB Ethernet Adapter | ||
46 | Linksys USB10T | ||
47 | Mobility USB-Ethernet Adapter | ||
48 | NetGear EA-101 | ||
49 | Peracom Enet and Enet2 | ||
50 | Portsmith Express Ethernet Adapter | ||
51 | Shark Pocket Adapter | ||
52 | SMC 2202USB | ||
53 | Sony Vaio port extender | ||
54 | |||
55 | This driver is likely to work with most 10Mbps only USB Ethernet | ||
56 | adapters, including some "no brand" devices. It does NOT work on | ||
57 | SmartBridges smartNIC or on Belkin F5U111 devices - you should use | ||
58 | the CATC NetMate driver for those. If you are not sure which one | ||
59 | you need, select both, and the correct one should be selected for | ||
60 | you. | ||
61 | |||
62 | This driver makes the adapter appear as a normal Ethernet interface, | ||
63 | typically on eth0, if it is the only ethernet device, or perhaps on | ||
64 | eth1, if you have a PCI or ISA ethernet card installed. | ||
65 | |||
66 | To compile this driver as a module, choose M here: the | ||
67 | module will be called kaweth. | ||
68 | |||
69 | config USB_PEGASUS | ||
70 | tristate "USB Pegasus/Pegasus-II based ethernet device support" | ||
71 | select MII | ||
72 | ---help--- | ||
73 | Say Y here if you know you have Pegasus or Pegasus-II based adapter. | ||
74 | If in doubt then look at <file:drivers/usb/net/pegasus.h> for the | ||
75 | complete list of supported devices. | ||
76 | |||
77 | If your particular adapter is not in the list and you are _sure_ it | ||
78 | is Pegasus or Pegasus II based then send me | ||
79 | <petkan@users.sourceforge.net> vendor and device IDs. | ||
80 | |||
81 | To compile this driver as a module, choose M here: the | ||
82 | module will be called pegasus. | ||
83 | |||
84 | config USB_RTL8150 | ||
85 | tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)" | ||
86 | depends on EXPERIMENTAL | ||
87 | select MII | ||
88 | help | ||
89 | Say Y here if you have RTL8150 based usb-ethernet adapter. | ||
90 | Send me <petkan@users.sourceforge.net> any comments you may have. | ||
91 | You can also check for updates at <http://pegasus2.sourceforge.net/>. | ||
92 | |||
93 | To compile this driver as a module, choose M here: the | ||
94 | module will be called rtl8150. | ||
95 | |||
96 | config USB_USBNET_MII | ||
97 | tristate | ||
98 | default n | ||
99 | |||
100 | config USB_USBNET | ||
101 | tristate "Multi-purpose USB Networking Framework" | ||
102 | select MII if USB_USBNET_MII != n | ||
103 | ---help--- | ||
104 | This driver supports several kinds of network links over USB, | ||
105 | with "minidrivers" built around a common network driver core | ||
106 | that supports deep queues for efficient transfers. (This gives | ||
107 | better performance with small packets and at high speeds). | ||
108 | |||
109 | The USB host runs "usbnet", and the other end of the link might be: | ||
110 | |||
111 | - Another USB host, when using USB "network" or "data transfer" | ||
112 | cables. These are often used to network laptops to PCs, like | ||
113 | "Laplink" parallel cables or some motherboards. These rely | ||
114 | on specialized chips from many suppliers. | ||
115 | |||
116 | - An intelligent USB gadget, perhaps embedding a Linux system. | ||
117 | These include PDAs running Linux (iPaq, Yopy, Zaurus, and | ||
118 | others), and devices that interoperate using the standard | ||
119 | CDC-Ethernet specification (including many cable modems). | ||
120 | |||
121 | - Network adapter hardware (like those for 10/100 Ethernet) which | ||
122 | uses this driver framework. | ||
123 | |||
124 | The link will appear with a name like "usb0", when the link is | ||
125 | a two-node link, or "eth0" for most CDC-Ethernet devices. Those | ||
126 | two-node links are most easily managed with Ethernet Bridging | ||
127 | (CONFIG_BRIDGE) instead of routing. | ||
128 | |||
129 | For more information see <http://www.linux-usb.org/usbnet/>. | ||
130 | |||
131 | To compile this driver as a module, choose M here: the | ||
132 | module will be called usbnet. | ||
133 | |||
134 | config USB_NET_AX8817X | ||
135 | tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" | ||
136 | depends on USB_USBNET && NET_ETHERNET | ||
137 | select CRC32 | ||
138 | select USB_USBNET_MII | ||
139 | default y | ||
140 | help | ||
141 | This option adds support for ASIX AX88xxx based USB 2.0 | ||
142 | 10/100 Ethernet adapters. | ||
143 | |||
144 | This driver should work with at least the following devices: | ||
145 | * Aten UC210T | ||
146 | * ASIX AX88172 | ||
147 | * Billionton Systems, USB2AR | ||
148 | * Buffalo LUA-U2-KTX | ||
149 | * Corega FEther USB2-TX | ||
150 | * D-Link DUB-E100 | ||
151 | * Hawking UF200 | ||
152 | * Linksys USB200M | ||
153 | * Netgear FA120 | ||
154 | * Sitecom LN-029 | ||
155 | * Intellinet USB 2.0 Ethernet | ||
156 | * ST Lab USB 2.0 Ethernet | ||
157 | * TrendNet TU2-ET100 | ||
158 | |||
159 | This driver creates an interface named "ethX", where X depends on | ||
160 | what other networking devices you have in use. | ||
161 | |||
162 | |||
163 | config USB_NET_CDCETHER | ||
164 | tristate "CDC Ethernet support (smart devices such as cable modems)" | ||
165 | depends on USB_USBNET | ||
166 | default y | ||
167 | help | ||
168 | This option supports devices conforming to the Communication Device | ||
169 | Class (CDC) Ethernet Control Model, a specification that's easy to | ||
170 | implement in device firmware. The CDC specifications are available | ||
171 | from <http://www.usb.org/>. | ||
172 | |||
173 | CDC Ethernet is an implementation option for DOCSIS cable modems | ||
174 | that support USB connectivity, used for non-Microsoft USB hosts. | ||
175 | The Linux-USB CDC Ethernet Gadget driver is an open implementation. | ||
176 | This driver should work with at least the following devices: | ||
177 | |||
178 | * Ericsson PipeRider (all variants) | ||
179 | * Motorola (DM100 and SB4100) | ||
180 | * Broadcom Cable Modem (reference design) | ||
181 | * Toshiba PCX1100U | ||
182 | * ... | ||
183 | |||
184 | This driver creates an interface named "ethX", where X depends on | ||
185 | what other networking devices you have in use. However, if the | ||
186 | IEEE 802 "local assignment" bit is set in the address, a "usbX" | ||
187 | name is used instead. | ||
188 | |||
189 | config USB_NET_DM9601 | ||
190 | tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" | ||
191 | depends on USB_USBNET | ||
192 | select CRC32 | ||
193 | select USB_USBNET_MII | ||
194 | help | ||
195 | This option adds support for Davicom DM9601 based USB 1.1 | ||
196 | 10/100 Ethernet adapters. | ||
197 | |||
198 | config USB_NET_GL620A | ||
199 | tristate "GeneSys GL620USB-A based cables" | ||
200 | depends on USB_USBNET | ||
201 | help | ||
202 | Choose this option if you're using a host-to-host cable, | ||
203 | or PC2PC motherboard, with this chip. | ||
204 | |||
205 | Note that the half-duplex "GL620USB" is not supported. | ||
206 | |||
207 | config USB_NET_NET1080 | ||
208 | tristate "NetChip 1080 based cables (Laplink, ...)" | ||
209 | default y | ||
210 | depends on USB_USBNET | ||
211 | help | ||
212 | Choose this option if you're using a host-to-host cable based | ||
213 | on this design: one NetChip 1080 chip and supporting logic, | ||
214 | optionally with LEDs that indicate traffic | ||
215 | |||
216 | config USB_NET_PLUSB | ||
217 | tristate "Prolific PL-2301/2302 based cables" | ||
218 | # if the handshake/init/reset problems, from original 'plusb', | ||
219 | # are ever resolved ... then remove "experimental" | ||
220 | depends on USB_USBNET && EXPERIMENTAL | ||
221 | help | ||
222 | Choose this option if you're using a host-to-host cable | ||
223 | with one of these chips. | ||
224 | |||
225 | config USB_NET_MCS7830 | ||
226 | tristate "MosChip MCS7830 based Ethernet adapters" | ||
227 | depends on USB_USBNET | ||
228 | select USB_USBNET_MII | ||
229 | help | ||
230 | Choose this option if you're using a 10/100 Ethernet USB2 | ||
231 | adapter based on the MosChip 7830 controller. This includes | ||
232 | adapters marketed under the DeLOCK brand. | ||
233 | |||
234 | config USB_NET_RNDIS_HOST | ||
235 | tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)" | ||
236 | depends on USB_USBNET && EXPERIMENTAL | ||
237 | select USB_NET_CDCETHER | ||
238 | help | ||
239 | This option enables hosting "Remote NDIS" USB networking links, | ||
240 | as encouraged by Microsoft (instead of CDC Ethernet!) for use in | ||
241 | various devices that may only support this protocol. A variant | ||
242 | of this protocol (with even less public documentation) seems to | ||
243 | be at the root of Microsoft's "ActiveSync" too. | ||
244 | |||
245 | Avoid using this protocol unless you have no better options. | ||
246 | The protocol specification is incomplete, and is controlled by | ||
247 | (and for) Microsoft; it isn't an "Open" ecosystem or market. | ||
248 | |||
249 | config USB_NET_CDC_SUBSET | ||
250 | tristate "Simple USB Network Links (CDC Ethernet subset)" | ||
251 | depends on USB_USBNET | ||
252 | default y | ||
253 | help | ||
254 | This driver module supports USB network devices that can work | ||
255 | without any device-specific information. Select it if you have | ||
256 | one of these drivers. | ||
257 | |||
258 | Note that while many USB host-to-host cables can work in this mode, | ||
259 | that may mean not being able to talk to Win32 systems or more | ||
260 | commonly not being able to handle certain events (like replugging | ||
261 | the host on the other end) very well. Also, these devices will | ||
262 | not generally have permanently assigned Ethernet addresses. | ||
263 | |||
264 | config USB_ALI_M5632 | ||
265 | boolean "ALi M5632 based 'USB 2.0 Data Link' cables" | ||
266 | depends on USB_NET_CDC_SUBSET | ||
267 | help | ||
268 | Choose this option if you're using a host-to-host cable | ||
269 | based on this design, which supports USB 2.0 high speed. | ||
270 | |||
271 | config USB_AN2720 | ||
272 | boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)" | ||
273 | depends on USB_NET_CDC_SUBSET | ||
274 | help | ||
275 | Choose this option if you're using a host-to-host cable | ||
276 | based on this design. Note that AnchorChips is now a | ||
277 | Cypress brand. | ||
278 | |||
279 | config USB_BELKIN | ||
280 | boolean "eTEK based host-to-host cables (Advance, Belkin, ...)" | ||
281 | depends on USB_NET_CDC_SUBSET | ||
282 | default y | ||
283 | help | ||
284 | Choose this option if you're using a host-to-host cable | ||
285 | based on this design: two NetChip 2890 chips and an Atmel | ||
286 | microcontroller, with LEDs that indicate traffic. | ||
287 | |||
288 | config USB_ARMLINUX | ||
289 | boolean "Embedded ARM Linux links (iPaq, ...)" | ||
290 | depends on USB_NET_CDC_SUBSET | ||
291 | default y | ||
292 | help | ||
293 | Choose this option to support the "usb-eth" networking driver | ||
294 | used by most of the ARM Linux community with device controllers | ||
295 | such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities | ||
296 | in some PXA versions of the "blob" boot loader. | ||
297 | |||
298 | Linux-based "Gumstix" PXA-25x based systems use this protocol | ||
299 | to talk with other Linux systems. | ||
300 | |||
301 | Although the ROMs shipped with Sharp Zaurus products use a | ||
302 | different link level framing protocol, you can have them use | ||
303 | this simpler protocol by installing a different kernel. | ||
304 | |||
305 | config USB_EPSON2888 | ||
306 | boolean "Epson 2888 based firmware (DEVELOPMENT)" | ||
307 | depends on USB_NET_CDC_SUBSET | ||
308 | help | ||
309 | Choose this option to support the usb networking links used | ||
310 | by some sample firmware from Epson. | ||
311 | |||
312 | config USB_KC2190 | ||
313 | boolean "KT Technology KC2190 based cables (InstaNet)" | ||
314 | depends on USB_NET_CDC_SUBSET && EXPERIMENTAL | ||
315 | help | ||
316 | Choose this option if you're using a host-to-host cable | ||
317 | with one of these chips. | ||
318 | |||
319 | config USB_NET_ZAURUS | ||
320 | tristate "Sharp Zaurus (stock ROMs) and compatible" | ||
321 | depends on USB_USBNET | ||
322 | select USB_NET_CDCETHER | ||
323 | select CRC32 | ||
324 | default y | ||
325 | help | ||
326 | Choose this option to support the usb networking links used by | ||
327 | Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500. | ||
328 | This also supports some related device firmware, as used in some | ||
329 | PDAs from Olympus and some cell phones from Motorola. | ||
330 | |||
331 | If you install an alternate image, such as the Linux 2.6 based | ||
332 | versions of OpenZaurus, you should no longer need to support this | ||
333 | protocol. Only the "eth-fd" or "net_fd" drivers in these devices | ||
334 | really need this non-conformant variant of CDC Ethernet (or in | ||
335 | some cases CDC MDLM) protocol, not "g_ether". | ||
336 | |||
337 | |||
338 | endmenu | ||
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile new file mode 100644 index 000000000000..595a539f8384 --- /dev/null +++ b/drivers/net/usb/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | # | ||
2 | # Makefile for USB Network drivers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_USB_CATC) += catc.o | ||
6 | obj-$(CONFIG_USB_KAWETH) += kaweth.o | ||
7 | obj-$(CONFIG_USB_PEGASUS) += pegasus.o | ||
8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o | ||
9 | obj-$(CONFIG_USB_NET_AX8817X) += asix.o | ||
10 | obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o | ||
11 | obj-$(CONFIG_USB_NET_DM9601) += dm9601.o | ||
12 | obj-$(CONFIG_USB_NET_GL620A) += gl620a.o | ||
13 | obj-$(CONFIG_USB_NET_NET1080) += net1080.o | ||
14 | obj-$(CONFIG_USB_NET_PLUSB) += plusb.o | ||
15 | obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o | ||
16 | obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o | ||
17 | obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o | ||
18 | obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o | ||
19 | obj-$(CONFIG_USB_USBNET) += usbnet.o | ||
20 | |||
21 | ifeq ($(CONFIG_USB_DEBUG),y) | ||
22 | EXTRA_CFLAGS += -DDEBUG | ||
23 | endif | ||
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c new file mode 100644 index 000000000000..d5ef97bc4d01 --- /dev/null +++ b/drivers/net/usb/asix.c | |||
@@ -0,0 +1,1490 @@ | |||
1 | /* | ||
2 | * ASIX AX8817X based USB 2.0 Ethernet Devices | ||
3 | * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | ||
4 | * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | ||
5 | * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | ||
6 | * Copyright (c) 2002-2003 TiVo Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | // #define DEBUG // error path messages, extra info | ||
24 | // #define VERBOSE // more; success messages | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/kmod.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/usb.h> | ||
35 | #include <linux/crc32.h> | ||
36 | |||
37 | #include "usbnet.h" | ||
38 | |||
39 | #define DRIVER_VERSION "14-Jun-2006" | ||
40 | static const char driver_name [] = "asix"; | ||
41 | |||
42 | /* ASIX AX8817X based USB 2.0 Ethernet Devices */ | ||
43 | |||
44 | #define AX_CMD_SET_SW_MII 0x06 | ||
45 | #define AX_CMD_READ_MII_REG 0x07 | ||
46 | #define AX_CMD_WRITE_MII_REG 0x08 | ||
47 | #define AX_CMD_SET_HW_MII 0x0a | ||
48 | #define AX_CMD_READ_EEPROM 0x0b | ||
49 | #define AX_CMD_WRITE_EEPROM 0x0c | ||
50 | #define AX_CMD_WRITE_ENABLE 0x0d | ||
51 | #define AX_CMD_WRITE_DISABLE 0x0e | ||
52 | #define AX_CMD_READ_RX_CTL 0x0f | ||
53 | #define AX_CMD_WRITE_RX_CTL 0x10 | ||
54 | #define AX_CMD_READ_IPG012 0x11 | ||
55 | #define AX_CMD_WRITE_IPG0 0x12 | ||
56 | #define AX_CMD_WRITE_IPG1 0x13 | ||
57 | #define AX_CMD_READ_NODE_ID 0x13 | ||
58 | #define AX_CMD_WRITE_IPG2 0x14 | ||
59 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 | ||
60 | #define AX88172_CMD_READ_NODE_ID 0x17 | ||
61 | #define AX_CMD_READ_PHY_ID 0x19 | ||
62 | #define AX_CMD_READ_MEDIUM_STATUS 0x1a | ||
63 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | ||
64 | #define AX_CMD_READ_MONITOR_MODE 0x1c | ||
65 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d | ||
66 | #define AX_CMD_READ_GPIOS 0x1e | ||
67 | #define AX_CMD_WRITE_GPIOS 0x1f | ||
68 | #define AX_CMD_SW_RESET 0x20 | ||
69 | #define AX_CMD_SW_PHY_STATUS 0x21 | ||
70 | #define AX_CMD_SW_PHY_SELECT 0x22 | ||
71 | |||
72 | #define AX_MONITOR_MODE 0x01 | ||
73 | #define AX_MONITOR_LINK 0x02 | ||
74 | #define AX_MONITOR_MAGIC 0x04 | ||
75 | #define AX_MONITOR_HSFS 0x10 | ||
76 | |||
77 | /* AX88172 Medium Status Register values */ | ||
78 | #define AX88172_MEDIUM_FD 0x02 | ||
79 | #define AX88172_MEDIUM_TX 0x04 | ||
80 | #define AX88172_MEDIUM_FC 0x10 | ||
81 | #define AX88172_MEDIUM_DEFAULT \ | ||
82 | ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) | ||
83 | |||
84 | #define AX_MCAST_FILTER_SIZE 8 | ||
85 | #define AX_MAX_MCAST 64 | ||
86 | |||
87 | #define AX_SWRESET_CLEAR 0x00 | ||
88 | #define AX_SWRESET_RR 0x01 | ||
89 | #define AX_SWRESET_RT 0x02 | ||
90 | #define AX_SWRESET_PRTE 0x04 | ||
91 | #define AX_SWRESET_PRL 0x08 | ||
92 | #define AX_SWRESET_BZ 0x10 | ||
93 | #define AX_SWRESET_IPRL 0x20 | ||
94 | #define AX_SWRESET_IPPD 0x40 | ||
95 | |||
96 | #define AX88772_IPG0_DEFAULT 0x15 | ||
97 | #define AX88772_IPG1_DEFAULT 0x0c | ||
98 | #define AX88772_IPG2_DEFAULT 0x12 | ||
99 | |||
100 | /* AX88772 & AX88178 Medium Mode Register */ | ||
101 | #define AX_MEDIUM_PF 0x0080 | ||
102 | #define AX_MEDIUM_JFE 0x0040 | ||
103 | #define AX_MEDIUM_TFC 0x0020 | ||
104 | #define AX_MEDIUM_RFC 0x0010 | ||
105 | #define AX_MEDIUM_ENCK 0x0008 | ||
106 | #define AX_MEDIUM_AC 0x0004 | ||
107 | #define AX_MEDIUM_FD 0x0002 | ||
108 | #define AX_MEDIUM_GM 0x0001 | ||
109 | #define AX_MEDIUM_SM 0x1000 | ||
110 | #define AX_MEDIUM_SBP 0x0800 | ||
111 | #define AX_MEDIUM_PS 0x0200 | ||
112 | #define AX_MEDIUM_RE 0x0100 | ||
113 | |||
114 | #define AX88178_MEDIUM_DEFAULT \ | ||
115 | (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | ||
116 | AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | ||
117 | AX_MEDIUM_RE ) | ||
118 | |||
119 | #define AX88772_MEDIUM_DEFAULT \ | ||
120 | (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | ||
121 | AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | ||
122 | AX_MEDIUM_AC | AX_MEDIUM_RE ) | ||
123 | |||
124 | /* AX88772 & AX88178 RX_CTL values */ | ||
125 | #define AX_RX_CTL_SO 0x0080 | ||
126 | #define AX_RX_CTL_AP 0x0020 | ||
127 | #define AX_RX_CTL_AM 0x0010 | ||
128 | #define AX_RX_CTL_AB 0x0008 | ||
129 | #define AX_RX_CTL_SEP 0x0004 | ||
130 | #define AX_RX_CTL_AMALL 0x0002 | ||
131 | #define AX_RX_CTL_PRO 0x0001 | ||
132 | #define AX_RX_CTL_MFB_2048 0x0000 | ||
133 | #define AX_RX_CTL_MFB_4096 0x0100 | ||
134 | #define AX_RX_CTL_MFB_8192 0x0200 | ||
135 | #define AX_RX_CTL_MFB_16384 0x0300 | ||
136 | |||
137 | #define AX_DEFAULT_RX_CTL \ | ||
138 | (AX_RX_CTL_SO | AX_RX_CTL_AB ) | ||
139 | |||
140 | /* GPIO 0 .. 2 toggles */ | ||
141 | #define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ | ||
142 | #define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ | ||
143 | #define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ | ||
144 | #define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ | ||
145 | #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | ||
146 | #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | ||
147 | #define AX_GPIO_RESERVED 0x40 /* Reserved */ | ||
148 | #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | ||
149 | |||
150 | #define AX_EEPROM_MAGIC 0xdeadbeef | ||
151 | #define AX88172_EEPROM_LEN 0x40 | ||
152 | #define AX88772_EEPROM_LEN 0xff | ||
153 | |||
154 | #define PHY_MODE_MARVELL 0x0000 | ||
155 | #define MII_MARVELL_LED_CTRL 0x0018 | ||
156 | #define MII_MARVELL_STATUS 0x001b | ||
157 | #define MII_MARVELL_CTRL 0x0014 | ||
158 | |||
159 | #define MARVELL_LED_MANUAL 0x0019 | ||
160 | |||
161 | #define MARVELL_STATUS_HWCFG 0x0004 | ||
162 | |||
163 | #define MARVELL_CTRL_TXDELAY 0x0002 | ||
164 | #define MARVELL_CTRL_RXDELAY 0x0080 | ||
165 | |||
166 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | ||
167 | struct asix_data { | ||
168 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | ||
169 | u8 phymode; | ||
170 | u8 ledmode; | ||
171 | u8 eeprom_len; | ||
172 | }; | ||
173 | |||
174 | struct ax88172_int_data { | ||
175 | u16 res1; | ||
176 | u8 link; | ||
177 | u16 res2; | ||
178 | u8 status; | ||
179 | u16 res3; | ||
180 | } __attribute__ ((packed)); | ||
181 | |||
182 | static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
183 | u16 size, void *data) | ||
184 | { | ||
185 | devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d", | ||
186 | cmd, value, index, size); | ||
187 | return usb_control_msg( | ||
188 | dev->udev, | ||
189 | usb_rcvctrlpipe(dev->udev, 0), | ||
190 | cmd, | ||
191 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
192 | value, | ||
193 | index, | ||
194 | data, | ||
195 | size, | ||
196 | USB_CTRL_GET_TIMEOUT); | ||
197 | } | ||
198 | |||
199 | static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
200 | u16 size, void *data) | ||
201 | { | ||
202 | devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d", | ||
203 | cmd, value, index, size); | ||
204 | return usb_control_msg( | ||
205 | dev->udev, | ||
206 | usb_sndctrlpipe(dev->udev, 0), | ||
207 | cmd, | ||
208 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
209 | value, | ||
210 | index, | ||
211 | data, | ||
212 | size, | ||
213 | USB_CTRL_SET_TIMEOUT); | ||
214 | } | ||
215 | |||
216 | static void asix_async_cmd_callback(struct urb *urb) | ||
217 | { | ||
218 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
219 | |||
220 | if (urb->status < 0) | ||
221 | printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", | ||
222 | urb->status); | ||
223 | |||
224 | kfree(req); | ||
225 | usb_free_urb(urb); | ||
226 | } | ||
227 | |||
228 | static void | ||
229 | asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
230 | u16 size, void *data) | ||
231 | { | ||
232 | struct usb_ctrlrequest *req; | ||
233 | int status; | ||
234 | struct urb *urb; | ||
235 | |||
236 | devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d", | ||
237 | cmd, value, index, size); | ||
238 | if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { | ||
239 | deverr(dev, "Error allocating URB in write_cmd_async!"); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { | ||
244 | deverr(dev, "Failed to allocate memory for control request"); | ||
245 | usb_free_urb(urb); | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
250 | req->bRequest = cmd; | ||
251 | req->wValue = cpu_to_le16(value); | ||
252 | req->wIndex = cpu_to_le16(index); | ||
253 | req->wLength = cpu_to_le16(size); | ||
254 | |||
255 | usb_fill_control_urb(urb, dev->udev, | ||
256 | usb_sndctrlpipe(dev->udev, 0), | ||
257 | (void *)req, data, size, | ||
258 | asix_async_cmd_callback, req); | ||
259 | |||
260 | if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { | ||
261 | deverr(dev, "Error submitting the control message: status=%d", | ||
262 | status); | ||
263 | kfree(req); | ||
264 | usb_free_urb(urb); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
269 | { | ||
270 | u8 *head; | ||
271 | u32 header; | ||
272 | char *packet; | ||
273 | struct sk_buff *ax_skb; | ||
274 | u16 size; | ||
275 | |||
276 | head = (u8 *) skb->data; | ||
277 | memcpy(&header, head, sizeof(header)); | ||
278 | le32_to_cpus(&header); | ||
279 | packet = head + sizeof(header); | ||
280 | |||
281 | skb_pull(skb, 4); | ||
282 | |||
283 | while (skb->len > 0) { | ||
284 | if ((short)(header & 0x0000ffff) != | ||
285 | ~((short)((header & 0xffff0000) >> 16))) { | ||
286 | deverr(dev,"asix_rx_fixup() Bad Header Length"); | ||
287 | } | ||
288 | /* get the packet length */ | ||
289 | size = (u16) (header & 0x0000ffff); | ||
290 | |||
291 | if ((skb->len) - ((size + 1) & 0xfffe) == 0) | ||
292 | return 2; | ||
293 | if (size > ETH_FRAME_LEN) { | ||
294 | deverr(dev,"asix_rx_fixup() Bad RX Length %d", size); | ||
295 | return 0; | ||
296 | } | ||
297 | ax_skb = skb_clone(skb, GFP_ATOMIC); | ||
298 | if (ax_skb) { | ||
299 | ax_skb->len = size; | ||
300 | ax_skb->data = packet; | ||
301 | skb_set_tail_pointer(ax_skb, size); | ||
302 | usbnet_skb_return(dev, ax_skb); | ||
303 | } else { | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | skb_pull(skb, (size + 1) & 0xfffe); | ||
308 | |||
309 | if (skb->len == 0) | ||
310 | break; | ||
311 | |||
312 | head = (u8 *) skb->data; | ||
313 | memcpy(&header, head, sizeof(header)); | ||
314 | le32_to_cpus(&header); | ||
315 | packet = head + sizeof(header); | ||
316 | skb_pull(skb, 4); | ||
317 | } | ||
318 | |||
319 | if (skb->len < 0) { | ||
320 | deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len); | ||
321 | return 0; | ||
322 | } | ||
323 | return 1; | ||
324 | } | ||
325 | |||
326 | static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
327 | gfp_t flags) | ||
328 | { | ||
329 | int padlen; | ||
330 | int headroom = skb_headroom(skb); | ||
331 | int tailroom = skb_tailroom(skb); | ||
332 | u32 packet_len; | ||
333 | u32 padbytes = 0xffff0000; | ||
334 | |||
335 | padlen = ((skb->len + 4) % 512) ? 0 : 4; | ||
336 | |||
337 | if ((!skb_cloned(skb)) | ||
338 | && ((headroom + tailroom) >= (4 + padlen))) { | ||
339 | if ((headroom < 4) || (tailroom < padlen)) { | ||
340 | skb->data = memmove(skb->head + 4, skb->data, skb->len); | ||
341 | skb_set_tail_pointer(skb, skb->len); | ||
342 | } | ||
343 | } else { | ||
344 | struct sk_buff *skb2; | ||
345 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | ||
346 | dev_kfree_skb_any(skb); | ||
347 | skb = skb2; | ||
348 | if (!skb) | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | skb_push(skb, 4); | ||
353 | packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); | ||
354 | cpu_to_le32s(&packet_len); | ||
355 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | ||
356 | |||
357 | if ((skb->len % 512) == 0) { | ||
358 | cpu_to_le32s(&padbytes); | ||
359 | memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | ||
360 | skb_put(skb, sizeof(padbytes)); | ||
361 | } | ||
362 | return skb; | ||
363 | } | ||
364 | |||
365 | static void asix_status(struct usbnet *dev, struct urb *urb) | ||
366 | { | ||
367 | struct ax88172_int_data *event; | ||
368 | int link; | ||
369 | |||
370 | if (urb->actual_length < 8) | ||
371 | return; | ||
372 | |||
373 | event = urb->transfer_buffer; | ||
374 | link = event->link & 0x01; | ||
375 | if (netif_carrier_ok(dev->net) != link) { | ||
376 | if (link) { | ||
377 | netif_carrier_on(dev->net); | ||
378 | usbnet_defer_kevent (dev, EVENT_LINK_RESET ); | ||
379 | } else | ||
380 | netif_carrier_off(dev->net); | ||
381 | devdbg(dev, "Link Status is: %d", link); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | static inline int asix_set_sw_mii(struct usbnet *dev) | ||
386 | { | ||
387 | int ret; | ||
388 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | ||
389 | if (ret < 0) | ||
390 | deverr(dev, "Failed to enable software MII access"); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | static inline int asix_set_hw_mii(struct usbnet *dev) | ||
395 | { | ||
396 | int ret; | ||
397 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | ||
398 | if (ret < 0) | ||
399 | deverr(dev, "Failed to enable hardware MII access"); | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | static inline int asix_get_phy_addr(struct usbnet *dev) | ||
404 | { | ||
405 | int ret = 0; | ||
406 | void *buf; | ||
407 | |||
408 | devdbg(dev, "asix_get_phy_addr()"); | ||
409 | |||
410 | buf = kmalloc(2, GFP_KERNEL); | ||
411 | if (!buf) | ||
412 | goto out1; | ||
413 | |||
414 | if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, | ||
415 | 0, 0, 2, buf)) < 2) { | ||
416 | deverr(dev, "Error reading PHYID register: %02x", ret); | ||
417 | goto out2; | ||
418 | } | ||
419 | devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((u16 *)buf)); | ||
420 | ret = *((u8 *)buf + 1); | ||
421 | out2: | ||
422 | kfree(buf); | ||
423 | out1: | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | static int asix_sw_reset(struct usbnet *dev, u8 flags) | ||
428 | { | ||
429 | int ret; | ||
430 | |||
431 | ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | ||
432 | if (ret < 0) | ||
433 | deverr(dev,"Failed to send software reset: %02x", ret); | ||
434 | |||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static u16 asix_read_rx_ctl(struct usbnet *dev) | ||
439 | { | ||
440 | u16 ret = 0; | ||
441 | void *buf; | ||
442 | |||
443 | buf = kmalloc(2, GFP_KERNEL); | ||
444 | if (!buf) | ||
445 | goto out1; | ||
446 | |||
447 | if ((ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, | ||
448 | 0, 0, 2, buf)) < 2) { | ||
449 | deverr(dev, "Error reading RX_CTL register: %02x", ret); | ||
450 | goto out2; | ||
451 | } | ||
452 | ret = le16_to_cpu(*((u16 *)buf)); | ||
453 | out2: | ||
454 | kfree(buf); | ||
455 | out1: | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | ||
460 | { | ||
461 | int ret; | ||
462 | |||
463 | devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode); | ||
464 | ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | ||
465 | if (ret < 0) | ||
466 | deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x", | ||
467 | mode, ret); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | static u16 asix_read_medium_status(struct usbnet *dev) | ||
473 | { | ||
474 | u16 ret = 0; | ||
475 | void *buf; | ||
476 | |||
477 | buf = kmalloc(2, GFP_KERNEL); | ||
478 | if (!buf) | ||
479 | goto out1; | ||
480 | |||
481 | if ((ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, | ||
482 | 0, 0, 2, buf)) < 2) { | ||
483 | deverr(dev, "Error reading Medium Status register: %02x", ret); | ||
484 | goto out2; | ||
485 | } | ||
486 | ret = le16_to_cpu(*((u16 *)buf)); | ||
487 | out2: | ||
488 | kfree(buf); | ||
489 | out1: | ||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | static int asix_write_medium_mode(struct usbnet *dev, u16 mode) | ||
494 | { | ||
495 | int ret; | ||
496 | |||
497 | devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode); | ||
498 | ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
499 | if (ret < 0) | ||
500 | deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x", | ||
501 | mode, ret); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | ||
507 | { | ||
508 | int ret; | ||
509 | |||
510 | devdbg(dev,"asix_write_gpio() - value = 0x%04x", value); | ||
511 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | ||
512 | if (ret < 0) | ||
513 | deverr(dev, "Failed to write GPIO value 0x%04x: %02x", | ||
514 | value, ret); | ||
515 | |||
516 | if (sleep) | ||
517 | msleep(sleep); | ||
518 | |||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * AX88772 & AX88178 have a 16-bit RX_CTL value | ||
524 | */ | ||
525 | static void asix_set_multicast(struct net_device *net) | ||
526 | { | ||
527 | struct usbnet *dev = netdev_priv(net); | ||
528 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
529 | u16 rx_ctl = AX_DEFAULT_RX_CTL; | ||
530 | |||
531 | if (net->flags & IFF_PROMISC) { | ||
532 | rx_ctl |= AX_RX_CTL_PRO; | ||
533 | } else if (net->flags & IFF_ALLMULTI | ||
534 | || net->mc_count > AX_MAX_MCAST) { | ||
535 | rx_ctl |= AX_RX_CTL_AMALL; | ||
536 | } else if (net->mc_count == 0) { | ||
537 | /* just broadcast and directed */ | ||
538 | } else { | ||
539 | /* We use the 20 byte dev->data | ||
540 | * for our 8 byte filter buffer | ||
541 | * to avoid allocating memory that | ||
542 | * is tricky to free later */ | ||
543 | struct dev_mc_list *mc_list = net->mc_list; | ||
544 | u32 crc_bits; | ||
545 | int i; | ||
546 | |||
547 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
548 | |||
549 | /* Build the multicast hash filter. */ | ||
550 | for (i = 0; i < net->mc_count; i++) { | ||
551 | crc_bits = | ||
552 | ether_crc(ETH_ALEN, | ||
553 | mc_list->dmi_addr) >> 26; | ||
554 | data->multi_filter[crc_bits >> 3] |= | ||
555 | 1 << (crc_bits & 7); | ||
556 | mc_list = mc_list->next; | ||
557 | } | ||
558 | |||
559 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
560 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
561 | |||
562 | rx_ctl |= AX_RX_CTL_AM; | ||
563 | } | ||
564 | |||
565 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
566 | } | ||
567 | |||
568 | static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | ||
569 | { | ||
570 | struct usbnet *dev = netdev_priv(netdev); | ||
571 | u16 res; | ||
572 | |||
573 | mutex_lock(&dev->phy_mutex); | ||
574 | asix_set_sw_mii(dev); | ||
575 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | ||
576 | (__u16)loc, 2, (u16 *)&res); | ||
577 | asix_set_hw_mii(dev); | ||
578 | mutex_unlock(&dev->phy_mutex); | ||
579 | |||
580 | devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); | ||
581 | |||
582 | return le16_to_cpu(res & 0xffff); | ||
583 | } | ||
584 | |||
585 | static void | ||
586 | asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | ||
587 | { | ||
588 | struct usbnet *dev = netdev_priv(netdev); | ||
589 | u16 res = cpu_to_le16(val); | ||
590 | |||
591 | devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); | ||
592 | mutex_lock(&dev->phy_mutex); | ||
593 | asix_set_sw_mii(dev); | ||
594 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, | ||
595 | (__u16)loc, 2, (u16 *)&res); | ||
596 | asix_set_hw_mii(dev); | ||
597 | mutex_unlock(&dev->phy_mutex); | ||
598 | } | ||
599 | |||
600 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | ||
601 | static u32 asix_get_phyid(struct usbnet *dev) | ||
602 | { | ||
603 | int phy_reg; | ||
604 | u32 phy_id; | ||
605 | |||
606 | phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); | ||
607 | if (phy_reg < 0) | ||
608 | return 0; | ||
609 | |||
610 | phy_id = (phy_reg & 0xffff) << 16; | ||
611 | |||
612 | phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); | ||
613 | if (phy_reg < 0) | ||
614 | return 0; | ||
615 | |||
616 | phy_id |= (phy_reg & 0xffff); | ||
617 | |||
618 | return phy_id; | ||
619 | } | ||
620 | |||
621 | static void | ||
622 | asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
623 | { | ||
624 | struct usbnet *dev = netdev_priv(net); | ||
625 | u8 opt; | ||
626 | |||
627 | if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | ||
628 | wolinfo->supported = 0; | ||
629 | wolinfo->wolopts = 0; | ||
630 | return; | ||
631 | } | ||
632 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
633 | wolinfo->wolopts = 0; | ||
634 | if (opt & AX_MONITOR_MODE) { | ||
635 | if (opt & AX_MONITOR_LINK) | ||
636 | wolinfo->wolopts |= WAKE_PHY; | ||
637 | if (opt & AX_MONITOR_MAGIC) | ||
638 | wolinfo->wolopts |= WAKE_MAGIC; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | static int | ||
643 | asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
644 | { | ||
645 | struct usbnet *dev = netdev_priv(net); | ||
646 | u8 opt = 0; | ||
647 | u8 buf[1]; | ||
648 | |||
649 | if (wolinfo->wolopts & WAKE_PHY) | ||
650 | opt |= AX_MONITOR_LINK; | ||
651 | if (wolinfo->wolopts & WAKE_MAGIC) | ||
652 | opt |= AX_MONITOR_MAGIC; | ||
653 | if (opt != 0) | ||
654 | opt |= AX_MONITOR_MODE; | ||
655 | |||
656 | if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, | ||
657 | opt, 0, 0, &buf) < 0) | ||
658 | return -EINVAL; | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static int asix_get_eeprom_len(struct net_device *net) | ||
664 | { | ||
665 | struct usbnet *dev = netdev_priv(net); | ||
666 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
667 | |||
668 | return data->eeprom_len; | ||
669 | } | ||
670 | |||
671 | static int asix_get_eeprom(struct net_device *net, | ||
672 | struct ethtool_eeprom *eeprom, u8 *data) | ||
673 | { | ||
674 | struct usbnet *dev = netdev_priv(net); | ||
675 | u16 *ebuf = (u16 *)data; | ||
676 | int i; | ||
677 | |||
678 | /* Crude hack to ensure that we don't overwrite memory | ||
679 | * if an odd length is supplied | ||
680 | */ | ||
681 | if (eeprom->len % 2) | ||
682 | return -EINVAL; | ||
683 | |||
684 | eeprom->magic = AX_EEPROM_MAGIC; | ||
685 | |||
686 | /* ax8817x returns 2 bytes from eeprom on read */ | ||
687 | for (i=0; i < eeprom->len / 2; i++) { | ||
688 | if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, | ||
689 | eeprom->offset + i, 0, 2, &ebuf[i]) < 0) | ||
690 | return -EINVAL; | ||
691 | } | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static void asix_get_drvinfo (struct net_device *net, | ||
696 | struct ethtool_drvinfo *info) | ||
697 | { | ||
698 | struct usbnet *dev = netdev_priv(net); | ||
699 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
700 | |||
701 | /* Inherit standard device info */ | ||
702 | usbnet_get_drvinfo(net, info); | ||
703 | strncpy (info->driver, driver_name, sizeof info->driver); | ||
704 | strncpy (info->version, DRIVER_VERSION, sizeof info->version); | ||
705 | info->eedump_len = data->eeprom_len; | ||
706 | } | ||
707 | |||
708 | static u32 asix_get_link(struct net_device *net) | ||
709 | { | ||
710 | struct usbnet *dev = netdev_priv(net); | ||
711 | |||
712 | return mii_link_ok(&dev->mii); | ||
713 | } | ||
714 | |||
715 | static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | ||
716 | { | ||
717 | struct usbnet *dev = netdev_priv(net); | ||
718 | |||
719 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
720 | } | ||
721 | |||
722 | /* We need to override some ethtool_ops so we require our | ||
723 | own structure so we don't interfere with other usbnet | ||
724 | devices that may be connected at the same time. */ | ||
725 | static struct ethtool_ops ax88172_ethtool_ops = { | ||
726 | .get_drvinfo = asix_get_drvinfo, | ||
727 | .get_link = asix_get_link, | ||
728 | .get_msglevel = usbnet_get_msglevel, | ||
729 | .set_msglevel = usbnet_set_msglevel, | ||
730 | .get_wol = asix_get_wol, | ||
731 | .set_wol = asix_set_wol, | ||
732 | .get_eeprom_len = asix_get_eeprom_len, | ||
733 | .get_eeprom = asix_get_eeprom, | ||
734 | .get_settings = usbnet_get_settings, | ||
735 | .set_settings = usbnet_set_settings, | ||
736 | .nway_reset = usbnet_nway_reset, | ||
737 | }; | ||
738 | |||
739 | static void ax88172_set_multicast(struct net_device *net) | ||
740 | { | ||
741 | struct usbnet *dev = netdev_priv(net); | ||
742 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
743 | u8 rx_ctl = 0x8c; | ||
744 | |||
745 | if (net->flags & IFF_PROMISC) { | ||
746 | rx_ctl |= 0x01; | ||
747 | } else if (net->flags & IFF_ALLMULTI | ||
748 | || net->mc_count > AX_MAX_MCAST) { | ||
749 | rx_ctl |= 0x02; | ||
750 | } else if (net->mc_count == 0) { | ||
751 | /* just broadcast and directed */ | ||
752 | } else { | ||
753 | /* We use the 20 byte dev->data | ||
754 | * for our 8 byte filter buffer | ||
755 | * to avoid allocating memory that | ||
756 | * is tricky to free later */ | ||
757 | struct dev_mc_list *mc_list = net->mc_list; | ||
758 | u32 crc_bits; | ||
759 | int i; | ||
760 | |||
761 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
762 | |||
763 | /* Build the multicast hash filter. */ | ||
764 | for (i = 0; i < net->mc_count; i++) { | ||
765 | crc_bits = | ||
766 | ether_crc(ETH_ALEN, | ||
767 | mc_list->dmi_addr) >> 26; | ||
768 | data->multi_filter[crc_bits >> 3] |= | ||
769 | 1 << (crc_bits & 7); | ||
770 | mc_list = mc_list->next; | ||
771 | } | ||
772 | |||
773 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
774 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
775 | |||
776 | rx_ctl |= 0x10; | ||
777 | } | ||
778 | |||
779 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
780 | } | ||
781 | |||
782 | static int ax88172_link_reset(struct usbnet *dev) | ||
783 | { | ||
784 | u8 mode; | ||
785 | struct ethtool_cmd ecmd; | ||
786 | |||
787 | mii_check_media(&dev->mii, 1, 1); | ||
788 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
789 | mode = AX88172_MEDIUM_DEFAULT; | ||
790 | |||
791 | if (ecmd.duplex != DUPLEX_FULL) | ||
792 | mode |= ~AX88172_MEDIUM_FD; | ||
793 | |||
794 | devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode); | ||
795 | |||
796 | asix_write_medium_mode(dev, mode); | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | ||
802 | { | ||
803 | int ret = 0; | ||
804 | void *buf; | ||
805 | int i; | ||
806 | unsigned long gpio_bits = dev->driver_info->data; | ||
807 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
808 | |||
809 | data->eeprom_len = AX88172_EEPROM_LEN; | ||
810 | |||
811 | usbnet_get_endpoints(dev,intf); | ||
812 | |||
813 | buf = kmalloc(ETH_ALEN, GFP_KERNEL); | ||
814 | if(!buf) { | ||
815 | ret = -ENOMEM; | ||
816 | goto out1; | ||
817 | } | ||
818 | |||
819 | /* Toggle the GPIOs in a manufacturer/model specific way */ | ||
820 | for (i = 2; i >= 0; i--) { | ||
821 | if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, | ||
822 | (gpio_bits >> (i * 8)) & 0xff, 0, 0, | ||
823 | buf)) < 0) | ||
824 | goto out2; | ||
825 | msleep(5); | ||
826 | } | ||
827 | |||
828 | if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0) | ||
829 | goto out2; | ||
830 | |||
831 | /* Get the MAC address */ | ||
832 | memset(buf, 0, ETH_ALEN); | ||
833 | if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, | ||
834 | 0, 0, 6, buf)) < 0) { | ||
835 | dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); | ||
836 | goto out2; | ||
837 | } | ||
838 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
839 | |||
840 | /* Initialize MII structure */ | ||
841 | dev->mii.dev = dev->net; | ||
842 | dev->mii.mdio_read = asix_mdio_read; | ||
843 | dev->mii.mdio_write = asix_mdio_write; | ||
844 | dev->mii.phy_id_mask = 0x3f; | ||
845 | dev->mii.reg_num_mask = 0x1f; | ||
846 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
847 | dev->net->do_ioctl = asix_ioctl; | ||
848 | |||
849 | dev->net->set_multicast_list = ax88172_set_multicast; | ||
850 | dev->net->ethtool_ops = &ax88172_ethtool_ops; | ||
851 | |||
852 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
853 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
854 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
855 | mii_nway_restart(&dev->mii); | ||
856 | |||
857 | return 0; | ||
858 | out2: | ||
859 | kfree(buf); | ||
860 | out1: | ||
861 | return ret; | ||
862 | } | ||
863 | |||
864 | static struct ethtool_ops ax88772_ethtool_ops = { | ||
865 | .get_drvinfo = asix_get_drvinfo, | ||
866 | .get_link = asix_get_link, | ||
867 | .get_msglevel = usbnet_get_msglevel, | ||
868 | .set_msglevel = usbnet_set_msglevel, | ||
869 | .get_wol = asix_get_wol, | ||
870 | .set_wol = asix_set_wol, | ||
871 | .get_eeprom_len = asix_get_eeprom_len, | ||
872 | .get_eeprom = asix_get_eeprom, | ||
873 | .get_settings = usbnet_get_settings, | ||
874 | .set_settings = usbnet_set_settings, | ||
875 | .nway_reset = usbnet_nway_reset, | ||
876 | }; | ||
877 | |||
878 | static int ax88772_link_reset(struct usbnet *dev) | ||
879 | { | ||
880 | u16 mode; | ||
881 | struct ethtool_cmd ecmd; | ||
882 | |||
883 | mii_check_media(&dev->mii, 1, 1); | ||
884 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
885 | mode = AX88772_MEDIUM_DEFAULT; | ||
886 | |||
887 | if (ecmd.speed != SPEED_100) | ||
888 | mode &= ~AX_MEDIUM_PS; | ||
889 | |||
890 | if (ecmd.duplex != DUPLEX_FULL) | ||
891 | mode &= ~AX_MEDIUM_FD; | ||
892 | |||
893 | devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode); | ||
894 | |||
895 | asix_write_medium_mode(dev, mode); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | ||
901 | { | ||
902 | int ret, embd_phy; | ||
903 | void *buf; | ||
904 | u16 rx_ctl; | ||
905 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
906 | u32 phyid; | ||
907 | |||
908 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
909 | |||
910 | usbnet_get_endpoints(dev,intf); | ||
911 | |||
912 | buf = kmalloc(6, GFP_KERNEL); | ||
913 | if(!buf) { | ||
914 | dbg ("Cannot allocate memory for buffer"); | ||
915 | ret = -ENOMEM; | ||
916 | goto out1; | ||
917 | } | ||
918 | |||
919 | if ((ret = asix_write_gpio(dev, | ||
920 | AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0) | ||
921 | goto out2; | ||
922 | |||
923 | /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ | ||
924 | embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | ||
925 | if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, | ||
926 | embd_phy, 0, 0, buf)) < 0) { | ||
927 | dbg("Select PHY #1 failed: %d", ret); | ||
928 | goto out2; | ||
929 | } | ||
930 | |||
931 | if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0) | ||
932 | goto out2; | ||
933 | |||
934 | msleep(150); | ||
935 | if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0) | ||
936 | goto out2; | ||
937 | |||
938 | msleep(150); | ||
939 | if (embd_phy) { | ||
940 | if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0) | ||
941 | goto out2; | ||
942 | } | ||
943 | else { | ||
944 | if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0) | ||
945 | goto out2; | ||
946 | } | ||
947 | |||
948 | msleep(150); | ||
949 | rx_ctl = asix_read_rx_ctl(dev); | ||
950 | dbg("RX_CTL is 0x%04x after software reset", rx_ctl); | ||
951 | if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0) | ||
952 | goto out2; | ||
953 | |||
954 | rx_ctl = asix_read_rx_ctl(dev); | ||
955 | dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); | ||
956 | |||
957 | /* Get the MAC address */ | ||
958 | memset(buf, 0, ETH_ALEN); | ||
959 | if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, | ||
960 | 0, 0, ETH_ALEN, buf)) < 0) { | ||
961 | dbg("Failed to read MAC address: %d", ret); | ||
962 | goto out2; | ||
963 | } | ||
964 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
965 | |||
966 | /* Initialize MII structure */ | ||
967 | dev->mii.dev = dev->net; | ||
968 | dev->mii.mdio_read = asix_mdio_read; | ||
969 | dev->mii.mdio_write = asix_mdio_write; | ||
970 | dev->mii.phy_id_mask = 0x1f; | ||
971 | dev->mii.reg_num_mask = 0x1f; | ||
972 | dev->net->do_ioctl = asix_ioctl; | ||
973 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
974 | |||
975 | phyid = asix_get_phyid(dev); | ||
976 | dbg("PHYID=0x%08x", phyid); | ||
977 | |||
978 | if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0) | ||
979 | goto out2; | ||
980 | |||
981 | msleep(150); | ||
982 | |||
983 | if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) | ||
984 | goto out2; | ||
985 | |||
986 | msleep(150); | ||
987 | |||
988 | dev->net->set_multicast_list = asix_set_multicast; | ||
989 | dev->net->ethtool_ops = &ax88772_ethtool_ops; | ||
990 | |||
991 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
992 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
993 | ADVERTISE_ALL | ADVERTISE_CSMA); | ||
994 | mii_nway_restart(&dev->mii); | ||
995 | |||
996 | if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0) | ||
997 | goto out2; | ||
998 | |||
999 | if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | ||
1000 | AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | ||
1001 | AX88772_IPG2_DEFAULT, 0, buf)) < 0) { | ||
1002 | dbg("Write IPG,IPG1,IPG2 failed: %d", ret); | ||
1003 | goto out2; | ||
1004 | } | ||
1005 | |||
1006 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | ||
1007 | if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0) | ||
1008 | goto out2; | ||
1009 | |||
1010 | rx_ctl = asix_read_rx_ctl(dev); | ||
1011 | dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); | ||
1012 | |||
1013 | rx_ctl = asix_read_medium_status(dev); | ||
1014 | dbg("Medium Status is 0x%04x after all initializations", rx_ctl); | ||
1015 | |||
1016 | kfree(buf); | ||
1017 | |||
1018 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
1019 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
1020 | /* hard_mtu is still the default - the device does not support | ||
1021 | jumbo eth frames */ | ||
1022 | dev->rx_urb_size = 2048; | ||
1023 | } | ||
1024 | |||
1025 | return 0; | ||
1026 | |||
1027 | out2: | ||
1028 | kfree(buf); | ||
1029 | out1: | ||
1030 | return ret; | ||
1031 | } | ||
1032 | |||
1033 | static struct ethtool_ops ax88178_ethtool_ops = { | ||
1034 | .get_drvinfo = asix_get_drvinfo, | ||
1035 | .get_link = asix_get_link, | ||
1036 | .get_msglevel = usbnet_get_msglevel, | ||
1037 | .set_msglevel = usbnet_set_msglevel, | ||
1038 | .get_wol = asix_get_wol, | ||
1039 | .set_wol = asix_set_wol, | ||
1040 | .get_eeprom_len = asix_get_eeprom_len, | ||
1041 | .get_eeprom = asix_get_eeprom, | ||
1042 | .get_settings = usbnet_get_settings, | ||
1043 | .set_settings = usbnet_set_settings, | ||
1044 | .nway_reset = usbnet_nway_reset, | ||
1045 | }; | ||
1046 | |||
1047 | static int marvell_phy_init(struct usbnet *dev) | ||
1048 | { | ||
1049 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1050 | u16 reg; | ||
1051 | |||
1052 | devdbg(dev,"marvell_phy_init()"); | ||
1053 | |||
1054 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); | ||
1055 | devdbg(dev,"MII_MARVELL_STATUS = 0x%04x", reg); | ||
1056 | |||
1057 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, | ||
1058 | MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); | ||
1059 | |||
1060 | if (data->ledmode) { | ||
1061 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, | ||
1062 | MII_MARVELL_LED_CTRL); | ||
1063 | devdbg(dev,"MII_MARVELL_LED_CTRL (1) = 0x%04x", reg); | ||
1064 | |||
1065 | reg &= 0xf8ff; | ||
1066 | reg |= (1 + 0x0100); | ||
1067 | asix_mdio_write(dev->net, dev->mii.phy_id, | ||
1068 | MII_MARVELL_LED_CTRL, reg); | ||
1069 | |||
1070 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, | ||
1071 | MII_MARVELL_LED_CTRL); | ||
1072 | devdbg(dev,"MII_MARVELL_LED_CTRL (2) = 0x%04x", reg); | ||
1073 | reg &= 0xfc0f; | ||
1074 | } | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int marvell_led_status(struct usbnet *dev, u16 speed) | ||
1080 | { | ||
1081 | u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); | ||
1082 | |||
1083 | devdbg(dev, "marvell_led_status() read 0x%04x", reg); | ||
1084 | |||
1085 | /* Clear out the center LED bits - 0x03F0 */ | ||
1086 | reg &= 0xfc0f; | ||
1087 | |||
1088 | switch (speed) { | ||
1089 | case SPEED_1000: | ||
1090 | reg |= 0x03e0; | ||
1091 | break; | ||
1092 | case SPEED_100: | ||
1093 | reg |= 0x03b0; | ||
1094 | break; | ||
1095 | default: | ||
1096 | reg |= 0x02f0; | ||
1097 | } | ||
1098 | |||
1099 | devdbg(dev, "marvell_led_status() writing 0x%04x", reg); | ||
1100 | asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | static int ax88178_link_reset(struct usbnet *dev) | ||
1106 | { | ||
1107 | u16 mode; | ||
1108 | struct ethtool_cmd ecmd; | ||
1109 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1110 | |||
1111 | devdbg(dev,"ax88178_link_reset()"); | ||
1112 | |||
1113 | mii_check_media(&dev->mii, 1, 1); | ||
1114 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
1115 | mode = AX88178_MEDIUM_DEFAULT; | ||
1116 | |||
1117 | if (ecmd.speed == SPEED_1000) | ||
1118 | mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK; | ||
1119 | else if (ecmd.speed == SPEED_100) | ||
1120 | mode |= AX_MEDIUM_PS; | ||
1121 | else | ||
1122 | mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); | ||
1123 | |||
1124 | if (ecmd.duplex == DUPLEX_FULL) | ||
1125 | mode |= AX_MEDIUM_FD; | ||
1126 | else | ||
1127 | mode &= ~AX_MEDIUM_FD; | ||
1128 | |||
1129 | devdbg(dev, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode); | ||
1130 | |||
1131 | asix_write_medium_mode(dev, mode); | ||
1132 | |||
1133 | if (data->phymode == PHY_MODE_MARVELL && data->ledmode) | ||
1134 | marvell_led_status(dev, ecmd.speed); | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static void ax88178_set_mfb(struct usbnet *dev) | ||
1140 | { | ||
1141 | u16 mfb = AX_RX_CTL_MFB_16384; | ||
1142 | u16 rxctl; | ||
1143 | u16 medium; | ||
1144 | int old_rx_urb_size = dev->rx_urb_size; | ||
1145 | |||
1146 | if (dev->hard_mtu < 2048) { | ||
1147 | dev->rx_urb_size = 2048; | ||
1148 | mfb = AX_RX_CTL_MFB_2048; | ||
1149 | } else if (dev->hard_mtu < 4096) { | ||
1150 | dev->rx_urb_size = 4096; | ||
1151 | mfb = AX_RX_CTL_MFB_4096; | ||
1152 | } else if (dev->hard_mtu < 8192) { | ||
1153 | dev->rx_urb_size = 8192; | ||
1154 | mfb = AX_RX_CTL_MFB_8192; | ||
1155 | } else if (dev->hard_mtu < 16384) { | ||
1156 | dev->rx_urb_size = 16384; | ||
1157 | mfb = AX_RX_CTL_MFB_16384; | ||
1158 | } | ||
1159 | |||
1160 | rxctl = asix_read_rx_ctl(dev); | ||
1161 | asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); | ||
1162 | |||
1163 | medium = asix_read_medium_status(dev); | ||
1164 | if (dev->net->mtu > 1500) | ||
1165 | medium |= AX_MEDIUM_JFE; | ||
1166 | else | ||
1167 | medium &= ~AX_MEDIUM_JFE; | ||
1168 | asix_write_medium_mode(dev, medium); | ||
1169 | |||
1170 | if (dev->rx_urb_size > old_rx_urb_size) | ||
1171 | usbnet_unlink_rx_urbs(dev); | ||
1172 | } | ||
1173 | |||
1174 | static int ax88178_change_mtu(struct net_device *net, int new_mtu) | ||
1175 | { | ||
1176 | struct usbnet *dev = netdev_priv(net); | ||
1177 | int ll_mtu = new_mtu + net->hard_header_len + 4; | ||
1178 | |||
1179 | devdbg(dev, "ax88178_change_mtu() new_mtu=%d", new_mtu); | ||
1180 | |||
1181 | if (new_mtu <= 0 || ll_mtu > 16384) | ||
1182 | return -EINVAL; | ||
1183 | |||
1184 | if ((ll_mtu % dev->maxpacket) == 0) | ||
1185 | return -EDOM; | ||
1186 | |||
1187 | net->mtu = new_mtu; | ||
1188 | dev->hard_mtu = net->mtu + net->hard_header_len; | ||
1189 | ax88178_set_mfb(dev); | ||
1190 | |||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1194 | static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) | ||
1195 | { | ||
1196 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1197 | int ret; | ||
1198 | void *buf; | ||
1199 | u16 eeprom; | ||
1200 | int gpio0 = 0; | ||
1201 | u32 phyid; | ||
1202 | |||
1203 | usbnet_get_endpoints(dev,intf); | ||
1204 | |||
1205 | buf = kmalloc(6, GFP_KERNEL); | ||
1206 | if(!buf) { | ||
1207 | dbg ("Cannot allocate memory for buffer"); | ||
1208 | ret = -ENOMEM; | ||
1209 | goto out1; | ||
1210 | } | ||
1211 | |||
1212 | eeprom = 0; | ||
1213 | asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &eeprom); | ||
1214 | dbg("GPIO Status: 0x%04x", eeprom); | ||
1215 | |||
1216 | asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); | ||
1217 | asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); | ||
1218 | asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); | ||
1219 | |||
1220 | dbg("EEPROM index 0x17 is 0x%04x", eeprom); | ||
1221 | |||
1222 | if (eeprom == 0xffff) { | ||
1223 | data->phymode = PHY_MODE_MARVELL; | ||
1224 | data->ledmode = 0; | ||
1225 | gpio0 = 1; | ||
1226 | } else { | ||
1227 | data->phymode = eeprom & 7; | ||
1228 | data->ledmode = eeprom >> 8; | ||
1229 | gpio0 = (eeprom & 0x80) ? 0 : 1; | ||
1230 | } | ||
1231 | dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); | ||
1232 | |||
1233 | asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); | ||
1234 | if ((eeprom >> 8) != 1) { | ||
1235 | asix_write_gpio(dev, 0x003c, 30); | ||
1236 | asix_write_gpio(dev, 0x001c, 300); | ||
1237 | asix_write_gpio(dev, 0x003c, 30); | ||
1238 | } else { | ||
1239 | dbg("gpio phymode == 1 path"); | ||
1240 | asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); | ||
1241 | asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); | ||
1242 | } | ||
1243 | |||
1244 | asix_sw_reset(dev, 0); | ||
1245 | msleep(150); | ||
1246 | |||
1247 | asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | ||
1248 | msleep(150); | ||
1249 | |||
1250 | asix_write_rx_ctl(dev, 0); | ||
1251 | |||
1252 | /* Get the MAC address */ | ||
1253 | memset(buf, 0, ETH_ALEN); | ||
1254 | if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, | ||
1255 | 0, 0, ETH_ALEN, buf)) < 0) { | ||
1256 | dbg("Failed to read MAC address: %d", ret); | ||
1257 | goto out2; | ||
1258 | } | ||
1259 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
1260 | |||
1261 | /* Initialize MII structure */ | ||
1262 | dev->mii.dev = dev->net; | ||
1263 | dev->mii.mdio_read = asix_mdio_read; | ||
1264 | dev->mii.mdio_write = asix_mdio_write; | ||
1265 | dev->mii.phy_id_mask = 0x1f; | ||
1266 | dev->mii.reg_num_mask = 0xff; | ||
1267 | dev->mii.supports_gmii = 1; | ||
1268 | dev->net->do_ioctl = asix_ioctl; | ||
1269 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
1270 | dev->net->set_multicast_list = asix_set_multicast; | ||
1271 | dev->net->ethtool_ops = &ax88178_ethtool_ops; | ||
1272 | dev->net->change_mtu = &ax88178_change_mtu; | ||
1273 | |||
1274 | phyid = asix_get_phyid(dev); | ||
1275 | dbg("PHYID=0x%08x", phyid); | ||
1276 | |||
1277 | if (data->phymode == PHY_MODE_MARVELL) { | ||
1278 | marvell_phy_init(dev); | ||
1279 | msleep(60); | ||
1280 | } | ||
1281 | |||
1282 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, | ||
1283 | BMCR_RESET | BMCR_ANENABLE); | ||
1284 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
1285 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
1286 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, | ||
1287 | ADVERTISE_1000FULL); | ||
1288 | |||
1289 | mii_nway_restart(&dev->mii); | ||
1290 | |||
1291 | if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0) | ||
1292 | goto out2; | ||
1293 | |||
1294 | if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0) | ||
1295 | goto out2; | ||
1296 | |||
1297 | kfree(buf); | ||
1298 | |||
1299 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
1300 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
1301 | /* hard_mtu is still the default - the device does not support | ||
1302 | jumbo eth frames */ | ||
1303 | dev->rx_urb_size = 2048; | ||
1304 | } | ||
1305 | |||
1306 | return 0; | ||
1307 | |||
1308 | out2: | ||
1309 | kfree(buf); | ||
1310 | out1: | ||
1311 | return ret; | ||
1312 | } | ||
1313 | |||
1314 | static const struct driver_info ax8817x_info = { | ||
1315 | .description = "ASIX AX8817x USB 2.0 Ethernet", | ||
1316 | .bind = ax88172_bind, | ||
1317 | .status = asix_status, | ||
1318 | .link_reset = ax88172_link_reset, | ||
1319 | .reset = ax88172_link_reset, | ||
1320 | .flags = FLAG_ETHER, | ||
1321 | .data = 0x00130103, | ||
1322 | }; | ||
1323 | |||
1324 | static const struct driver_info dlink_dub_e100_info = { | ||
1325 | .description = "DLink DUB-E100 USB Ethernet", | ||
1326 | .bind = ax88172_bind, | ||
1327 | .status = asix_status, | ||
1328 | .link_reset = ax88172_link_reset, | ||
1329 | .reset = ax88172_link_reset, | ||
1330 | .flags = FLAG_ETHER, | ||
1331 | .data = 0x009f9d9f, | ||
1332 | }; | ||
1333 | |||
1334 | static const struct driver_info netgear_fa120_info = { | ||
1335 | .description = "Netgear FA-120 USB Ethernet", | ||
1336 | .bind = ax88172_bind, | ||
1337 | .status = asix_status, | ||
1338 | .link_reset = ax88172_link_reset, | ||
1339 | .reset = ax88172_link_reset, | ||
1340 | .flags = FLAG_ETHER, | ||
1341 | .data = 0x00130103, | ||
1342 | }; | ||
1343 | |||
1344 | static const struct driver_info hawking_uf200_info = { | ||
1345 | .description = "Hawking UF200 USB Ethernet", | ||
1346 | .bind = ax88172_bind, | ||
1347 | .status = asix_status, | ||
1348 | .link_reset = ax88172_link_reset, | ||
1349 | .reset = ax88172_link_reset, | ||
1350 | .flags = FLAG_ETHER, | ||
1351 | .data = 0x001f1d1f, | ||
1352 | }; | ||
1353 | |||
1354 | static const struct driver_info ax88772_info = { | ||
1355 | .description = "ASIX AX88772 USB 2.0 Ethernet", | ||
1356 | .bind = ax88772_bind, | ||
1357 | .status = asix_status, | ||
1358 | .link_reset = ax88772_link_reset, | ||
1359 | .reset = ax88772_link_reset, | ||
1360 | .flags = FLAG_ETHER | FLAG_FRAMING_AX, | ||
1361 | .rx_fixup = asix_rx_fixup, | ||
1362 | .tx_fixup = asix_tx_fixup, | ||
1363 | }; | ||
1364 | |||
1365 | static const struct driver_info ax88178_info = { | ||
1366 | .description = "ASIX AX88178 USB 2.0 Ethernet", | ||
1367 | .bind = ax88178_bind, | ||
1368 | .status = asix_status, | ||
1369 | .link_reset = ax88178_link_reset, | ||
1370 | .reset = ax88178_link_reset, | ||
1371 | .flags = FLAG_ETHER | FLAG_FRAMING_AX, | ||
1372 | .rx_fixup = asix_rx_fixup, | ||
1373 | .tx_fixup = asix_tx_fixup, | ||
1374 | }; | ||
1375 | |||
1376 | static const struct usb_device_id products [] = { | ||
1377 | { | ||
1378 | // Linksys USB200M | ||
1379 | USB_DEVICE (0x077b, 0x2226), | ||
1380 | .driver_info = (unsigned long) &ax8817x_info, | ||
1381 | }, { | ||
1382 | // Netgear FA120 | ||
1383 | USB_DEVICE (0x0846, 0x1040), | ||
1384 | .driver_info = (unsigned long) &netgear_fa120_info, | ||
1385 | }, { | ||
1386 | // DLink DUB-E100 | ||
1387 | USB_DEVICE (0x2001, 0x1a00), | ||
1388 | .driver_info = (unsigned long) &dlink_dub_e100_info, | ||
1389 | }, { | ||
1390 | // Intellinet, ST Lab USB Ethernet | ||
1391 | USB_DEVICE (0x0b95, 0x1720), | ||
1392 | .driver_info = (unsigned long) &ax8817x_info, | ||
1393 | }, { | ||
1394 | // Hawking UF200, TrendNet TU2-ET100 | ||
1395 | USB_DEVICE (0x07b8, 0x420a), | ||
1396 | .driver_info = (unsigned long) &hawking_uf200_info, | ||
1397 | }, { | ||
1398 | // Billionton Systems, USB2AR | ||
1399 | USB_DEVICE (0x08dd, 0x90ff), | ||
1400 | .driver_info = (unsigned long) &ax8817x_info, | ||
1401 | }, { | ||
1402 | // ATEN UC210T | ||
1403 | USB_DEVICE (0x0557, 0x2009), | ||
1404 | .driver_info = (unsigned long) &ax8817x_info, | ||
1405 | }, { | ||
1406 | // Buffalo LUA-U2-KTX | ||
1407 | USB_DEVICE (0x0411, 0x003d), | ||
1408 | .driver_info = (unsigned long) &ax8817x_info, | ||
1409 | }, { | ||
1410 | // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" | ||
1411 | USB_DEVICE (0x6189, 0x182d), | ||
1412 | .driver_info = (unsigned long) &ax8817x_info, | ||
1413 | }, { | ||
1414 | // corega FEther USB2-TX | ||
1415 | USB_DEVICE (0x07aa, 0x0017), | ||
1416 | .driver_info = (unsigned long) &ax8817x_info, | ||
1417 | }, { | ||
1418 | // Surecom EP-1427X-2 | ||
1419 | USB_DEVICE (0x1189, 0x0893), | ||
1420 | .driver_info = (unsigned long) &ax8817x_info, | ||
1421 | }, { | ||
1422 | // goodway corp usb gwusb2e | ||
1423 | USB_DEVICE (0x1631, 0x6200), | ||
1424 | .driver_info = (unsigned long) &ax8817x_info, | ||
1425 | }, { | ||
1426 | // JVC MP-PRX1 Port Replicator | ||
1427 | USB_DEVICE (0x04f1, 0x3008), | ||
1428 | .driver_info = (unsigned long) &ax8817x_info, | ||
1429 | }, { | ||
1430 | // ASIX AX88772 10/100 | ||
1431 | USB_DEVICE (0x0b95, 0x7720), | ||
1432 | .driver_info = (unsigned long) &ax88772_info, | ||
1433 | }, { | ||
1434 | // ASIX AX88178 10/100/1000 | ||
1435 | USB_DEVICE (0x0b95, 0x1780), | ||
1436 | .driver_info = (unsigned long) &ax88178_info, | ||
1437 | }, { | ||
1438 | // Linksys USB200M Rev 2 | ||
1439 | USB_DEVICE (0x13b1, 0x0018), | ||
1440 | .driver_info = (unsigned long) &ax88772_info, | ||
1441 | }, { | ||
1442 | // 0Q0 cable ethernet | ||
1443 | USB_DEVICE (0x1557, 0x7720), | ||
1444 | .driver_info = (unsigned long) &ax88772_info, | ||
1445 | }, { | ||
1446 | // DLink DUB-E100 H/W Ver B1 | ||
1447 | USB_DEVICE (0x07d1, 0x3c05), | ||
1448 | .driver_info = (unsigned long) &ax88772_info, | ||
1449 | }, { | ||
1450 | // DLink DUB-E100 H/W Ver B1 Alternate | ||
1451 | USB_DEVICE (0x2001, 0x3c05), | ||
1452 | .driver_info = (unsigned long) &ax88772_info, | ||
1453 | }, { | ||
1454 | // Linksys USB1000 | ||
1455 | USB_DEVICE (0x1737, 0x0039), | ||
1456 | .driver_info = (unsigned long) &ax88178_info, | ||
1457 | }, { | ||
1458 | // IO-DATA ETG-US2 | ||
1459 | USB_DEVICE (0x04bb, 0x0930), | ||
1460 | .driver_info = (unsigned long) &ax88178_info, | ||
1461 | }, | ||
1462 | { }, // END | ||
1463 | }; | ||
1464 | MODULE_DEVICE_TABLE(usb, products); | ||
1465 | |||
1466 | static struct usb_driver asix_driver = { | ||
1467 | .name = "asix", | ||
1468 | .id_table = products, | ||
1469 | .probe = usbnet_probe, | ||
1470 | .suspend = usbnet_suspend, | ||
1471 | .resume = usbnet_resume, | ||
1472 | .disconnect = usbnet_disconnect, | ||
1473 | }; | ||
1474 | |||
1475 | static int __init asix_init(void) | ||
1476 | { | ||
1477 | return usb_register(&asix_driver); | ||
1478 | } | ||
1479 | module_init(asix_init); | ||
1480 | |||
1481 | static void __exit asix_exit(void) | ||
1482 | { | ||
1483 | usb_deregister(&asix_driver); | ||
1484 | } | ||
1485 | module_exit(asix_exit); | ||
1486 | |||
1487 | MODULE_AUTHOR("David Hollis"); | ||
1488 | MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); | ||
1489 | MODULE_LICENSE("GPL"); | ||
1490 | |||
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c new file mode 100644 index 000000000000..86e90c59d551 --- /dev/null +++ b/drivers/net/usb/catc.c | |||
@@ -0,0 +1,963 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2001 Vojtech Pavlik | ||
3 | * | ||
4 | * CATC EL1210A NetMate USB Ethernet driver | ||
5 | * | ||
6 | * Sponsored by SuSE | ||
7 | * | ||
8 | * Based on the work of | ||
9 | * Donald Becker | ||
10 | * | ||
11 | * Old chipset support added by Simon Evans <spse@secret.org.uk> 2002 | ||
12 | * - adds support for Belkin F5U011 | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | * Should you need to contact me, the author, you can do so either by | ||
31 | * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | ||
32 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
33 | */ | ||
34 | |||
35 | #include <linux/init.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/string.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/etherdevice.h> | ||
42 | #include <linux/skbuff.h> | ||
43 | #include <linux/spinlock.h> | ||
44 | #include <linux/ethtool.h> | ||
45 | #include <linux/crc32.h> | ||
46 | #include <linux/bitops.h> | ||
47 | #include <asm/uaccess.h> | ||
48 | |||
49 | #undef DEBUG | ||
50 | |||
51 | #include <linux/usb.h> | ||
52 | |||
53 | /* | ||
54 | * Version information. | ||
55 | */ | ||
56 | |||
57 | #define DRIVER_VERSION "v2.8" | ||
58 | #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>" | ||
59 | #define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver" | ||
60 | #define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet" | ||
61 | |||
62 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
63 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
64 | MODULE_LICENSE("GPL"); | ||
65 | |||
66 | static const char driver_name[] = "catc"; | ||
67 | |||
68 | /* | ||
69 | * Some defines. | ||
70 | */ | ||
71 | |||
72 | #define STATS_UPDATE (HZ) /* Time between stats updates */ | ||
73 | #define TX_TIMEOUT (5*HZ) /* Max time the queue can be stopped */ | ||
74 | #define PKT_SZ 1536 /* Max Ethernet packet size */ | ||
75 | #define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */ | ||
76 | #define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */ | ||
77 | #define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */ | ||
78 | #define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */ | ||
79 | |||
80 | /* | ||
81 | * Control requests. | ||
82 | */ | ||
83 | |||
84 | enum control_requests { | ||
85 | ReadMem = 0xf1, | ||
86 | GetMac = 0xf2, | ||
87 | Reset = 0xf4, | ||
88 | SetMac = 0xf5, | ||
89 | SetRxMode = 0xf5, /* F5U011 only */ | ||
90 | WriteROM = 0xf8, | ||
91 | SetReg = 0xfa, | ||
92 | GetReg = 0xfb, | ||
93 | WriteMem = 0xfc, | ||
94 | ReadROM = 0xfd, | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * Registers. | ||
99 | */ | ||
100 | |||
101 | enum register_offsets { | ||
102 | TxBufCount = 0x20, | ||
103 | RxBufCount = 0x21, | ||
104 | OpModes = 0x22, | ||
105 | TxQed = 0x23, | ||
106 | RxQed = 0x24, | ||
107 | MaxBurst = 0x25, | ||
108 | RxUnit = 0x60, | ||
109 | EthStatus = 0x61, | ||
110 | StationAddr0 = 0x67, | ||
111 | EthStats = 0x69, | ||
112 | LEDCtrl = 0x81, | ||
113 | }; | ||
114 | |||
115 | enum eth_stats { | ||
116 | TxSingleColl = 0x00, | ||
117 | TxMultiColl = 0x02, | ||
118 | TxExcessColl = 0x04, | ||
119 | RxFramErr = 0x06, | ||
120 | }; | ||
121 | |||
122 | enum op_mode_bits { | ||
123 | Op3MemWaits = 0x03, | ||
124 | OpLenInclude = 0x08, | ||
125 | OpRxMerge = 0x10, | ||
126 | OpTxMerge = 0x20, | ||
127 | OpWin95bugfix = 0x40, | ||
128 | OpLoopback = 0x80, | ||
129 | }; | ||
130 | |||
131 | enum rx_filter_bits { | ||
132 | RxEnable = 0x01, | ||
133 | RxPolarity = 0x02, | ||
134 | RxForceOK = 0x04, | ||
135 | RxMultiCast = 0x08, | ||
136 | RxPromisc = 0x10, | ||
137 | AltRxPromisc = 0x20, /* F5U011 uses different bit */ | ||
138 | }; | ||
139 | |||
140 | enum led_values { | ||
141 | LEDFast = 0x01, | ||
142 | LEDSlow = 0x02, | ||
143 | LEDFlash = 0x03, | ||
144 | LEDPulse = 0x04, | ||
145 | LEDLink = 0x08, | ||
146 | }; | ||
147 | |||
148 | enum link_status { | ||
149 | LinkNoChange = 0, | ||
150 | LinkGood = 1, | ||
151 | LinkBad = 2 | ||
152 | }; | ||
153 | |||
154 | /* | ||
155 | * The catc struct. | ||
156 | */ | ||
157 | |||
158 | #define CTRL_RUNNING 0 | ||
159 | #define RX_RUNNING 1 | ||
160 | #define TX_RUNNING 2 | ||
161 | |||
162 | struct catc { | ||
163 | struct net_device *netdev; | ||
164 | struct usb_device *usbdev; | ||
165 | |||
166 | struct net_device_stats stats; | ||
167 | unsigned long flags; | ||
168 | |||
169 | unsigned int tx_ptr, tx_idx; | ||
170 | unsigned int ctrl_head, ctrl_tail; | ||
171 | spinlock_t tx_lock, ctrl_lock; | ||
172 | |||
173 | u8 tx_buf[2][TX_MAX_BURST * (PKT_SZ + 2)]; | ||
174 | u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)]; | ||
175 | u8 irq_buf[2]; | ||
176 | u8 ctrl_buf[64]; | ||
177 | struct usb_ctrlrequest ctrl_dr; | ||
178 | |||
179 | struct timer_list timer; | ||
180 | u8 stats_buf[8]; | ||
181 | u16 stats_vals[4]; | ||
182 | unsigned long last_stats; | ||
183 | |||
184 | u8 multicast[64]; | ||
185 | |||
186 | struct ctrl_queue { | ||
187 | u8 dir; | ||
188 | u8 request; | ||
189 | u16 value; | ||
190 | u16 index; | ||
191 | void *buf; | ||
192 | int len; | ||
193 | void (*callback)(struct catc *catc, struct ctrl_queue *q); | ||
194 | } ctrl_queue[CTRL_QUEUE]; | ||
195 | |||
196 | struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb; | ||
197 | |||
198 | u8 is_f5u011; /* Set if device is an F5U011 */ | ||
199 | u8 rxmode[2]; /* Used for F5U011 */ | ||
200 | atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */ | ||
201 | }; | ||
202 | |||
203 | /* | ||
204 | * Useful macros. | ||
205 | */ | ||
206 | |||
207 | #define catc_get_mac(catc, mac) catc_ctrl_msg(catc, USB_DIR_IN, GetMac, 0, 0, mac, 6) | ||
208 | #define catc_reset(catc) catc_ctrl_msg(catc, USB_DIR_OUT, Reset, 0, 0, NULL, 0) | ||
209 | #define catc_set_reg(catc, reg, val) catc_ctrl_msg(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0) | ||
210 | #define catc_get_reg(catc, reg, buf) catc_ctrl_msg(catc, USB_DIR_IN, GetReg, 0, reg, buf, 1) | ||
211 | #define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size) | ||
212 | #define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size) | ||
213 | |||
214 | #define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2) | ||
215 | #define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL) | ||
216 | #define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL) | ||
217 | |||
218 | #define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL) | ||
219 | #define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb) | ||
220 | #define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL) | ||
221 | |||
222 | /* | ||
223 | * Receive routines. | ||
224 | */ | ||
225 | |||
226 | static void catc_rx_done(struct urb *urb) | ||
227 | { | ||
228 | struct catc *catc = urb->context; | ||
229 | u8 *pkt_start = urb->transfer_buffer; | ||
230 | struct sk_buff *skb; | ||
231 | int pkt_len, pkt_offset = 0; | ||
232 | |||
233 | if (!catc->is_f5u011) { | ||
234 | clear_bit(RX_RUNNING, &catc->flags); | ||
235 | pkt_offset = 2; | ||
236 | } | ||
237 | |||
238 | if (urb->status) { | ||
239 | dbg("rx_done, status %d, length %d", urb->status, urb->actual_length); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | do { | ||
244 | if(!catc->is_f5u011) { | ||
245 | pkt_len = le16_to_cpup((__le16*)pkt_start); | ||
246 | if (pkt_len > urb->actual_length) { | ||
247 | catc->stats.rx_length_errors++; | ||
248 | catc->stats.rx_errors++; | ||
249 | break; | ||
250 | } | ||
251 | } else { | ||
252 | pkt_len = urb->actual_length; | ||
253 | } | ||
254 | |||
255 | if (!(skb = dev_alloc_skb(pkt_len))) | ||
256 | return; | ||
257 | |||
258 | eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0); | ||
259 | skb_put(skb, pkt_len); | ||
260 | |||
261 | skb->protocol = eth_type_trans(skb, catc->netdev); | ||
262 | netif_rx(skb); | ||
263 | |||
264 | catc->stats.rx_packets++; | ||
265 | catc->stats.rx_bytes += pkt_len; | ||
266 | |||
267 | /* F5U011 only does one packet per RX */ | ||
268 | if (catc->is_f5u011) | ||
269 | break; | ||
270 | pkt_start += (((pkt_len + 1) >> 6) + 1) << 6; | ||
271 | |||
272 | } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); | ||
273 | |||
274 | catc->netdev->last_rx = jiffies; | ||
275 | |||
276 | if (catc->is_f5u011) { | ||
277 | if (atomic_read(&catc->recq_sz)) { | ||
278 | int status; | ||
279 | atomic_dec(&catc->recq_sz); | ||
280 | dbg("getting extra packet"); | ||
281 | urb->dev = catc->usbdev; | ||
282 | if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { | ||
283 | dbg("submit(rx_urb) status %d", status); | ||
284 | } | ||
285 | } else { | ||
286 | clear_bit(RX_RUNNING, &catc->flags); | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | static void catc_irq_done(struct urb *urb) | ||
292 | { | ||
293 | struct catc *catc = urb->context; | ||
294 | u8 *data = urb->transfer_buffer; | ||
295 | int status; | ||
296 | unsigned int hasdata = 0, linksts = LinkNoChange; | ||
297 | |||
298 | if (!catc->is_f5u011) { | ||
299 | hasdata = data[1] & 0x80; | ||
300 | if (data[1] & 0x40) | ||
301 | linksts = LinkGood; | ||
302 | else if (data[1] & 0x20) | ||
303 | linksts = LinkBad; | ||
304 | } else { | ||
305 | hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff); | ||
306 | if (data[0] == 0x90) | ||
307 | linksts = LinkGood; | ||
308 | else if (data[0] == 0xA0) | ||
309 | linksts = LinkBad; | ||
310 | } | ||
311 | |||
312 | switch (urb->status) { | ||
313 | case 0: /* success */ | ||
314 | break; | ||
315 | case -ECONNRESET: /* unlink */ | ||
316 | case -ENOENT: | ||
317 | case -ESHUTDOWN: | ||
318 | return; | ||
319 | /* -EPIPE: should clear the halt */ | ||
320 | default: /* error */ | ||
321 | dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]); | ||
322 | goto resubmit; | ||
323 | } | ||
324 | |||
325 | if (linksts == LinkGood) { | ||
326 | netif_carrier_on(catc->netdev); | ||
327 | dbg("link ok"); | ||
328 | } | ||
329 | |||
330 | if (linksts == LinkBad) { | ||
331 | netif_carrier_off(catc->netdev); | ||
332 | dbg("link bad"); | ||
333 | } | ||
334 | |||
335 | if (hasdata) { | ||
336 | if (test_and_set_bit(RX_RUNNING, &catc->flags)) { | ||
337 | if (catc->is_f5u011) | ||
338 | atomic_inc(&catc->recq_sz); | ||
339 | } else { | ||
340 | catc->rx_urb->dev = catc->usbdev; | ||
341 | if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { | ||
342 | err("submit(rx_urb) status %d", status); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | resubmit: | ||
347 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
348 | if (status) | ||
349 | err ("can't resubmit intr, %s-%s, status %d", | ||
350 | catc->usbdev->bus->bus_name, | ||
351 | catc->usbdev->devpath, status); | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Transmit routines. | ||
356 | */ | ||
357 | |||
358 | static int catc_tx_run(struct catc *catc) | ||
359 | { | ||
360 | int status; | ||
361 | |||
362 | if (catc->is_f5u011) | ||
363 | catc->tx_ptr = (catc->tx_ptr + 63) & ~63; | ||
364 | |||
365 | catc->tx_urb->transfer_buffer_length = catc->tx_ptr; | ||
366 | catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx]; | ||
367 | catc->tx_urb->dev = catc->usbdev; | ||
368 | |||
369 | if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0) | ||
370 | err("submit(tx_urb), status %d", status); | ||
371 | |||
372 | catc->tx_idx = !catc->tx_idx; | ||
373 | catc->tx_ptr = 0; | ||
374 | |||
375 | catc->netdev->trans_start = jiffies; | ||
376 | return status; | ||
377 | } | ||
378 | |||
379 | static void catc_tx_done(struct urb *urb) | ||
380 | { | ||
381 | struct catc *catc = urb->context; | ||
382 | unsigned long flags; | ||
383 | int r; | ||
384 | |||
385 | if (urb->status == -ECONNRESET) { | ||
386 | dbg("Tx Reset."); | ||
387 | urb->status = 0; | ||
388 | catc->netdev->trans_start = jiffies; | ||
389 | catc->stats.tx_errors++; | ||
390 | clear_bit(TX_RUNNING, &catc->flags); | ||
391 | netif_wake_queue(catc->netdev); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | if (urb->status) { | ||
396 | dbg("tx_done, status %d, length %d", urb->status, urb->actual_length); | ||
397 | return; | ||
398 | } | ||
399 | |||
400 | spin_lock_irqsave(&catc->tx_lock, flags); | ||
401 | |||
402 | if (catc->tx_ptr) { | ||
403 | r = catc_tx_run(catc); | ||
404 | if (unlikely(r < 0)) | ||
405 | clear_bit(TX_RUNNING, &catc->flags); | ||
406 | } else { | ||
407 | clear_bit(TX_RUNNING, &catc->flags); | ||
408 | } | ||
409 | |||
410 | netif_wake_queue(catc->netdev); | ||
411 | |||
412 | spin_unlock_irqrestore(&catc->tx_lock, flags); | ||
413 | } | ||
414 | |||
415 | static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) | ||
416 | { | ||
417 | struct catc *catc = netdev_priv(netdev); | ||
418 | unsigned long flags; | ||
419 | int r = 0; | ||
420 | char *tx_buf; | ||
421 | |||
422 | spin_lock_irqsave(&catc->tx_lock, flags); | ||
423 | |||
424 | catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; | ||
425 | tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; | ||
426 | *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len); | ||
427 | skb_copy_from_linear_data(skb, tx_buf + 2, skb->len); | ||
428 | catc->tx_ptr += skb->len + 2; | ||
429 | |||
430 | if (!test_and_set_bit(TX_RUNNING, &catc->flags)) { | ||
431 | r = catc_tx_run(catc); | ||
432 | if (r < 0) | ||
433 | clear_bit(TX_RUNNING, &catc->flags); | ||
434 | } | ||
435 | |||
436 | if ((catc->is_f5u011 && catc->tx_ptr) | ||
437 | || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) | ||
438 | netif_stop_queue(netdev); | ||
439 | |||
440 | spin_unlock_irqrestore(&catc->tx_lock, flags); | ||
441 | |||
442 | if (r >= 0) { | ||
443 | catc->stats.tx_bytes += skb->len; | ||
444 | catc->stats.tx_packets++; | ||
445 | } | ||
446 | |||
447 | dev_kfree_skb(skb); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static void catc_tx_timeout(struct net_device *netdev) | ||
453 | { | ||
454 | struct catc *catc = netdev_priv(netdev); | ||
455 | |||
456 | warn("Transmit timed out."); | ||
457 | usb_unlink_urb(catc->tx_urb); | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Control messages. | ||
462 | */ | ||
463 | |||
464 | static int catc_ctrl_msg(struct catc *catc, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) | ||
465 | { | ||
466 | int retval = usb_control_msg(catc->usbdev, | ||
467 | dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0), | ||
468 | request, 0x40 | dir, value, index, buf, len, 1000); | ||
469 | return retval < 0 ? retval : 0; | ||
470 | } | ||
471 | |||
472 | static void catc_ctrl_run(struct catc *catc) | ||
473 | { | ||
474 | struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail; | ||
475 | struct usb_device *usbdev = catc->usbdev; | ||
476 | struct urb *urb = catc->ctrl_urb; | ||
477 | struct usb_ctrlrequest *dr = &catc->ctrl_dr; | ||
478 | int status; | ||
479 | |||
480 | dr->bRequest = q->request; | ||
481 | dr->bRequestType = 0x40 | q->dir; | ||
482 | dr->wValue = cpu_to_le16(q->value); | ||
483 | dr->wIndex = cpu_to_le16(q->index); | ||
484 | dr->wLength = cpu_to_le16(q->len); | ||
485 | |||
486 | urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0); | ||
487 | urb->transfer_buffer_length = q->len; | ||
488 | urb->transfer_buffer = catc->ctrl_buf; | ||
489 | urb->setup_packet = (void *) dr; | ||
490 | urb->dev = usbdev; | ||
491 | |||
492 | if (!q->dir && q->buf && q->len) | ||
493 | memcpy(catc->ctrl_buf, q->buf, q->len); | ||
494 | |||
495 | if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL))) | ||
496 | err("submit(ctrl_urb) status %d", status); | ||
497 | } | ||
498 | |||
499 | static void catc_ctrl_done(struct urb *urb) | ||
500 | { | ||
501 | struct catc *catc = urb->context; | ||
502 | struct ctrl_queue *q; | ||
503 | unsigned long flags; | ||
504 | |||
505 | if (urb->status) | ||
506 | dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length); | ||
507 | |||
508 | spin_lock_irqsave(&catc->ctrl_lock, flags); | ||
509 | |||
510 | q = catc->ctrl_queue + catc->ctrl_tail; | ||
511 | |||
512 | if (q->dir) { | ||
513 | if (q->buf && q->len) | ||
514 | memcpy(q->buf, catc->ctrl_buf, q->len); | ||
515 | else | ||
516 | q->buf = catc->ctrl_buf; | ||
517 | } | ||
518 | |||
519 | if (q->callback) | ||
520 | q->callback(catc, q); | ||
521 | |||
522 | catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); | ||
523 | |||
524 | if (catc->ctrl_head != catc->ctrl_tail) | ||
525 | catc_ctrl_run(catc); | ||
526 | else | ||
527 | clear_bit(CTRL_RUNNING, &catc->flags); | ||
528 | |||
529 | spin_unlock_irqrestore(&catc->ctrl_lock, flags); | ||
530 | } | ||
531 | |||
532 | static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value, | ||
533 | u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q)) | ||
534 | { | ||
535 | struct ctrl_queue *q; | ||
536 | int retval = 0; | ||
537 | unsigned long flags; | ||
538 | |||
539 | spin_lock_irqsave(&catc->ctrl_lock, flags); | ||
540 | |||
541 | q = catc->ctrl_queue + catc->ctrl_head; | ||
542 | |||
543 | q->dir = dir; | ||
544 | q->request = request; | ||
545 | q->value = value; | ||
546 | q->index = index; | ||
547 | q->buf = buf; | ||
548 | q->len = len; | ||
549 | q->callback = callback; | ||
550 | |||
551 | catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1); | ||
552 | |||
553 | if (catc->ctrl_head == catc->ctrl_tail) { | ||
554 | err("ctrl queue full"); | ||
555 | catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); | ||
556 | retval = -1; | ||
557 | } | ||
558 | |||
559 | if (!test_and_set_bit(CTRL_RUNNING, &catc->flags)) | ||
560 | catc_ctrl_run(catc); | ||
561 | |||
562 | spin_unlock_irqrestore(&catc->ctrl_lock, flags); | ||
563 | |||
564 | return retval; | ||
565 | } | ||
566 | |||
567 | /* | ||
568 | * Statistics. | ||
569 | */ | ||
570 | |||
571 | static void catc_stats_done(struct catc *catc, struct ctrl_queue *q) | ||
572 | { | ||
573 | int index = q->index - EthStats; | ||
574 | u16 data, last; | ||
575 | |||
576 | catc->stats_buf[index] = *((char *)q->buf); | ||
577 | |||
578 | if (index & 1) | ||
579 | return; | ||
580 | |||
581 | data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1]; | ||
582 | last = catc->stats_vals[index >> 1]; | ||
583 | |||
584 | switch (index) { | ||
585 | case TxSingleColl: | ||
586 | case TxMultiColl: | ||
587 | catc->stats.collisions += data - last; | ||
588 | break; | ||
589 | case TxExcessColl: | ||
590 | catc->stats.tx_aborted_errors += data - last; | ||
591 | catc->stats.tx_errors += data - last; | ||
592 | break; | ||
593 | case RxFramErr: | ||
594 | catc->stats.rx_frame_errors += data - last; | ||
595 | catc->stats.rx_errors += data - last; | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | catc->stats_vals[index >> 1] = data; | ||
600 | } | ||
601 | |||
602 | static void catc_stats_timer(unsigned long data) | ||
603 | { | ||
604 | struct catc *catc = (void *) data; | ||
605 | int i; | ||
606 | |||
607 | for (i = 0; i < 8; i++) | ||
608 | catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done); | ||
609 | |||
610 | mod_timer(&catc->timer, jiffies + STATS_UPDATE); | ||
611 | } | ||
612 | |||
613 | static struct net_device_stats *catc_get_stats(struct net_device *netdev) | ||
614 | { | ||
615 | struct catc *catc = netdev_priv(netdev); | ||
616 | return &catc->stats; | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * Receive modes. Broadcast, Multicast, Promisc. | ||
621 | */ | ||
622 | |||
623 | static void catc_multicast(unsigned char *addr, u8 *multicast) | ||
624 | { | ||
625 | u32 crc; | ||
626 | |||
627 | crc = ether_crc_le(6, addr); | ||
628 | multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); | ||
629 | } | ||
630 | |||
631 | static void catc_set_multicast_list(struct net_device *netdev) | ||
632 | { | ||
633 | struct catc *catc = netdev_priv(netdev); | ||
634 | struct dev_mc_list *mc; | ||
635 | u8 broadcast[6]; | ||
636 | u8 rx = RxEnable | RxPolarity | RxMultiCast; | ||
637 | int i; | ||
638 | |||
639 | memset(broadcast, 0xff, 6); | ||
640 | memset(catc->multicast, 0, 64); | ||
641 | |||
642 | catc_multicast(broadcast, catc->multicast); | ||
643 | catc_multicast(netdev->dev_addr, catc->multicast); | ||
644 | |||
645 | if (netdev->flags & IFF_PROMISC) { | ||
646 | memset(catc->multicast, 0xff, 64); | ||
647 | rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc; | ||
648 | } | ||
649 | |||
650 | if (netdev->flags & IFF_ALLMULTI) { | ||
651 | memset(catc->multicast, 0xff, 64); | ||
652 | } else { | ||
653 | for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { | ||
654 | u32 crc = ether_crc_le(6, mc->dmi_addr); | ||
655 | if (!catc->is_f5u011) { | ||
656 | catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); | ||
657 | } else { | ||
658 | catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7); | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | if (!catc->is_f5u011) { | ||
663 | catc_set_reg_async(catc, RxUnit, rx); | ||
664 | catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); | ||
665 | } else { | ||
666 | f5u011_mchash_async(catc, catc->multicast); | ||
667 | if (catc->rxmode[0] != rx) { | ||
668 | catc->rxmode[0] = rx; | ||
669 | dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0], catc->rxmode[1]); | ||
670 | f5u011_rxmode_async(catc, catc->rxmode); | ||
671 | } | ||
672 | } | ||
673 | } | ||
674 | |||
675 | static void catc_get_drvinfo(struct net_device *dev, | ||
676 | struct ethtool_drvinfo *info) | ||
677 | { | ||
678 | struct catc *catc = netdev_priv(dev); | ||
679 | strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); | ||
680 | strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); | ||
681 | usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info); | ||
682 | } | ||
683 | |||
684 | static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
685 | { | ||
686 | struct catc *catc = netdev_priv(dev); | ||
687 | if (!catc->is_f5u011) | ||
688 | return -EOPNOTSUPP; | ||
689 | |||
690 | cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; | ||
691 | cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; | ||
692 | cmd->speed = SPEED_10; | ||
693 | cmd->duplex = DUPLEX_HALF; | ||
694 | cmd->port = PORT_TP; | ||
695 | cmd->phy_address = 0; | ||
696 | cmd->transceiver = XCVR_INTERNAL; | ||
697 | cmd->autoneg = AUTONEG_DISABLE; | ||
698 | cmd->maxtxpkt = 1; | ||
699 | cmd->maxrxpkt = 1; | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static struct ethtool_ops ops = { | ||
704 | .get_drvinfo = catc_get_drvinfo, | ||
705 | .get_settings = catc_get_settings, | ||
706 | .get_link = ethtool_op_get_link | ||
707 | }; | ||
708 | |||
709 | /* | ||
710 | * Open, close. | ||
711 | */ | ||
712 | |||
713 | static int catc_open(struct net_device *netdev) | ||
714 | { | ||
715 | struct catc *catc = netdev_priv(netdev); | ||
716 | int status; | ||
717 | |||
718 | catc->irq_urb->dev = catc->usbdev; | ||
719 | if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) { | ||
720 | err("submit(irq_urb) status %d", status); | ||
721 | return -1; | ||
722 | } | ||
723 | |||
724 | netif_start_queue(netdev); | ||
725 | |||
726 | if (!catc->is_f5u011) | ||
727 | mod_timer(&catc->timer, jiffies + STATS_UPDATE); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int catc_stop(struct net_device *netdev) | ||
733 | { | ||
734 | struct catc *catc = netdev_priv(netdev); | ||
735 | |||
736 | netif_stop_queue(netdev); | ||
737 | |||
738 | if (!catc->is_f5u011) | ||
739 | del_timer_sync(&catc->timer); | ||
740 | |||
741 | usb_kill_urb(catc->rx_urb); | ||
742 | usb_kill_urb(catc->tx_urb); | ||
743 | usb_kill_urb(catc->irq_urb); | ||
744 | usb_kill_urb(catc->ctrl_urb); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | /* | ||
750 | * USB probe, disconnect. | ||
751 | */ | ||
752 | |||
753 | static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
754 | { | ||
755 | struct usb_device *usbdev = interface_to_usbdev(intf); | ||
756 | struct net_device *netdev; | ||
757 | struct catc *catc; | ||
758 | u8 broadcast[6]; | ||
759 | int i, pktsz; | ||
760 | |||
761 | if (usb_set_interface(usbdev, | ||
762 | intf->altsetting->desc.bInterfaceNumber, 1)) { | ||
763 | err("Can't set altsetting 1."); | ||
764 | return -EIO; | ||
765 | } | ||
766 | |||
767 | netdev = alloc_etherdev(sizeof(struct catc)); | ||
768 | if (!netdev) | ||
769 | return -ENOMEM; | ||
770 | |||
771 | catc = netdev_priv(netdev); | ||
772 | |||
773 | netdev->open = catc_open; | ||
774 | netdev->hard_start_xmit = catc_hard_start_xmit; | ||
775 | netdev->stop = catc_stop; | ||
776 | netdev->get_stats = catc_get_stats; | ||
777 | netdev->tx_timeout = catc_tx_timeout; | ||
778 | netdev->watchdog_timeo = TX_TIMEOUT; | ||
779 | netdev->set_multicast_list = catc_set_multicast_list; | ||
780 | SET_ETHTOOL_OPS(netdev, &ops); | ||
781 | |||
782 | catc->usbdev = usbdev; | ||
783 | catc->netdev = netdev; | ||
784 | |||
785 | spin_lock_init(&catc->tx_lock); | ||
786 | spin_lock_init(&catc->ctrl_lock); | ||
787 | |||
788 | init_timer(&catc->timer); | ||
789 | catc->timer.data = (long) catc; | ||
790 | catc->timer.function = catc_stats_timer; | ||
791 | |||
792 | catc->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
793 | catc->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
794 | catc->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
795 | catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
796 | if ((!catc->ctrl_urb) || (!catc->tx_urb) || | ||
797 | (!catc->rx_urb) || (!catc->irq_urb)) { | ||
798 | err("No free urbs available."); | ||
799 | usb_free_urb(catc->ctrl_urb); | ||
800 | usb_free_urb(catc->tx_urb); | ||
801 | usb_free_urb(catc->rx_urb); | ||
802 | usb_free_urb(catc->irq_urb); | ||
803 | free_netdev(netdev); | ||
804 | return -ENOMEM; | ||
805 | } | ||
806 | |||
807 | /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */ | ||
808 | if (le16_to_cpu(usbdev->descriptor.idVendor) == 0x0423 && | ||
809 | le16_to_cpu(usbdev->descriptor.idProduct) == 0xa && | ||
810 | le16_to_cpu(catc->usbdev->descriptor.bcdDevice) == 0x0130) { | ||
811 | dbg("Testing for f5u011"); | ||
812 | catc->is_f5u011 = 1; | ||
813 | atomic_set(&catc->recq_sz, 0); | ||
814 | pktsz = RX_PKT_SZ; | ||
815 | } else { | ||
816 | pktsz = RX_MAX_BURST * (PKT_SZ + 2); | ||
817 | } | ||
818 | |||
819 | usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0), | ||
820 | NULL, NULL, 0, catc_ctrl_done, catc); | ||
821 | |||
822 | usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1), | ||
823 | NULL, 0, catc_tx_done, catc); | ||
824 | |||
825 | usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1), | ||
826 | catc->rx_buf, pktsz, catc_rx_done, catc); | ||
827 | |||
828 | usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2), | ||
829 | catc->irq_buf, 2, catc_irq_done, catc, 1); | ||
830 | |||
831 | if (!catc->is_f5u011) { | ||
832 | dbg("Checking memory size\n"); | ||
833 | |||
834 | i = 0x12345678; | ||
835 | catc_write_mem(catc, 0x7a80, &i, 4); | ||
836 | i = 0x87654321; | ||
837 | catc_write_mem(catc, 0xfa80, &i, 4); | ||
838 | catc_read_mem(catc, 0x7a80, &i, 4); | ||
839 | |||
840 | switch (i) { | ||
841 | case 0x12345678: | ||
842 | catc_set_reg(catc, TxBufCount, 8); | ||
843 | catc_set_reg(catc, RxBufCount, 32); | ||
844 | dbg("64k Memory\n"); | ||
845 | break; | ||
846 | default: | ||
847 | warn("Couldn't detect memory size, assuming 32k"); | ||
848 | case 0x87654321: | ||
849 | catc_set_reg(catc, TxBufCount, 4); | ||
850 | catc_set_reg(catc, RxBufCount, 16); | ||
851 | dbg("32k Memory\n"); | ||
852 | break; | ||
853 | } | ||
854 | |||
855 | dbg("Getting MAC from SEEROM."); | ||
856 | |||
857 | catc_get_mac(catc, netdev->dev_addr); | ||
858 | |||
859 | dbg("Setting MAC into registers."); | ||
860 | |||
861 | for (i = 0; i < 6; i++) | ||
862 | catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); | ||
863 | |||
864 | dbg("Filling the multicast list."); | ||
865 | |||
866 | memset(broadcast, 0xff, 6); | ||
867 | catc_multicast(broadcast, catc->multicast); | ||
868 | catc_multicast(netdev->dev_addr, catc->multicast); | ||
869 | catc_write_mem(catc, 0xfa80, catc->multicast, 64); | ||
870 | |||
871 | dbg("Clearing error counters."); | ||
872 | |||
873 | for (i = 0; i < 8; i++) | ||
874 | catc_set_reg(catc, EthStats + i, 0); | ||
875 | catc->last_stats = jiffies; | ||
876 | |||
877 | dbg("Enabling."); | ||
878 | |||
879 | catc_set_reg(catc, MaxBurst, RX_MAX_BURST); | ||
880 | catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); | ||
881 | catc_set_reg(catc, LEDCtrl, LEDLink); | ||
882 | catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); | ||
883 | } else { | ||
884 | dbg("Performing reset\n"); | ||
885 | catc_reset(catc); | ||
886 | catc_get_mac(catc, netdev->dev_addr); | ||
887 | |||
888 | dbg("Setting RX Mode"); | ||
889 | catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast; | ||
890 | catc->rxmode[1] = 0; | ||
891 | f5u011_rxmode(catc, catc->rxmode); | ||
892 | } | ||
893 | dbg("Init done."); | ||
894 | printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, ", | ||
895 | netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", | ||
896 | usbdev->bus->bus_name, usbdev->devpath); | ||
897 | for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); | ||
898 | printk("%2.2x.\n", netdev->dev_addr[i]); | ||
899 | usb_set_intfdata(intf, catc); | ||
900 | |||
901 | SET_NETDEV_DEV(netdev, &intf->dev); | ||
902 | if (register_netdev(netdev) != 0) { | ||
903 | usb_set_intfdata(intf, NULL); | ||
904 | usb_free_urb(catc->ctrl_urb); | ||
905 | usb_free_urb(catc->tx_urb); | ||
906 | usb_free_urb(catc->rx_urb); | ||
907 | usb_free_urb(catc->irq_urb); | ||
908 | free_netdev(netdev); | ||
909 | return -EIO; | ||
910 | } | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static void catc_disconnect(struct usb_interface *intf) | ||
915 | { | ||
916 | struct catc *catc = usb_get_intfdata(intf); | ||
917 | |||
918 | usb_set_intfdata(intf, NULL); | ||
919 | if (catc) { | ||
920 | unregister_netdev(catc->netdev); | ||
921 | usb_free_urb(catc->ctrl_urb); | ||
922 | usb_free_urb(catc->tx_urb); | ||
923 | usb_free_urb(catc->rx_urb); | ||
924 | usb_free_urb(catc->irq_urb); | ||
925 | free_netdev(catc->netdev); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * Module functions and tables. | ||
931 | */ | ||
932 | |||
933 | static struct usb_device_id catc_id_table [] = { | ||
934 | { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */ | ||
935 | { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */ | ||
936 | { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */ | ||
937 | { } | ||
938 | }; | ||
939 | |||
940 | MODULE_DEVICE_TABLE(usb, catc_id_table); | ||
941 | |||
942 | static struct usb_driver catc_driver = { | ||
943 | .name = driver_name, | ||
944 | .probe = catc_probe, | ||
945 | .disconnect = catc_disconnect, | ||
946 | .id_table = catc_id_table, | ||
947 | }; | ||
948 | |||
949 | static int __init catc_init(void) | ||
950 | { | ||
951 | int result = usb_register(&catc_driver); | ||
952 | if (result == 0) | ||
953 | info(DRIVER_VERSION " " DRIVER_DESC); | ||
954 | return result; | ||
955 | } | ||
956 | |||
957 | static void __exit catc_exit(void) | ||
958 | { | ||
959 | usb_deregister(&catc_driver); | ||
960 | } | ||
961 | |||
962 | module_init(catc_init); | ||
963 | module_exit(catc_exit); | ||
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c new file mode 100644 index 000000000000..5a21f06bf8a5 --- /dev/null +++ b/drivers/net/usb/cdc_ether.c | |||
@@ -0,0 +1,570 @@ | |||
1 | /* | ||
2 | * CDC Ethernet based networking peripherals | ||
3 | * Copyright (C) 2003-2005 by David Brownell | ||
4 | * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (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, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | // #define DEBUG // error path messages, extra info | ||
22 | // #define VERBOSE // more; success messages | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/ctype.h> | ||
29 | #include <linux/ethtool.h> | ||
30 | #include <linux/workqueue.h> | ||
31 | #include <linux/mii.h> | ||
32 | #include <linux/usb.h> | ||
33 | #include <linux/usb/cdc.h> | ||
34 | |||
35 | #include "usbnet.h" | ||
36 | |||
37 | |||
38 | #if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) | ||
39 | |||
40 | static int is_rndis(struct usb_interface_descriptor *desc) | ||
41 | { | ||
42 | return desc->bInterfaceClass == USB_CLASS_COMM | ||
43 | && desc->bInterfaceSubClass == 2 | ||
44 | && desc->bInterfaceProtocol == 0xff; | ||
45 | } | ||
46 | |||
47 | static int is_activesync(struct usb_interface_descriptor *desc) | ||
48 | { | ||
49 | return desc->bInterfaceClass == USB_CLASS_MISC | ||
50 | && desc->bInterfaceSubClass == 1 | ||
51 | && desc->bInterfaceProtocol == 1; | ||
52 | } | ||
53 | |||
54 | #else | ||
55 | |||
56 | #define is_rndis(desc) 0 | ||
57 | #define is_activesync(desc) 0 | ||
58 | |||
59 | #endif | ||
60 | |||
61 | /* | ||
62 | * probes control interface, claims data interface, collects the bulk | ||
63 | * endpoints, activates data interface (if needed), maybe sets MTU. | ||
64 | * all pure cdc, except for certain firmware workarounds, and knowing | ||
65 | * that rndis uses one different rule. | ||
66 | */ | ||
67 | int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) | ||
68 | { | ||
69 | u8 *buf = intf->cur_altsetting->extra; | ||
70 | int len = intf->cur_altsetting->extralen; | ||
71 | struct usb_interface_descriptor *d; | ||
72 | struct cdc_state *info = (void *) &dev->data; | ||
73 | int status; | ||
74 | int rndis; | ||
75 | struct usb_driver *driver = driver_of(intf); | ||
76 | |||
77 | if (sizeof dev->data < sizeof *info) | ||
78 | return -EDOM; | ||
79 | |||
80 | /* expect strict spec conformance for the descriptors, but | ||
81 | * cope with firmware which stores them in the wrong place | ||
82 | */ | ||
83 | if (len == 0 && dev->udev->actconfig->extralen) { | ||
84 | /* Motorola SB4100 (and others: Brad Hards says it's | ||
85 | * from a Broadcom design) put CDC descriptors here | ||
86 | */ | ||
87 | buf = dev->udev->actconfig->extra; | ||
88 | len = dev->udev->actconfig->extralen; | ||
89 | if (len) | ||
90 | dev_dbg(&intf->dev, | ||
91 | "CDC descriptors on config\n"); | ||
92 | } | ||
93 | |||
94 | /* this assumes that if there's a non-RNDIS vendor variant | ||
95 | * of cdc-acm, it'll fail RNDIS requests cleanly. | ||
96 | */ | ||
97 | rndis = is_rndis(&intf->cur_altsetting->desc) | ||
98 | || is_activesync(&intf->cur_altsetting->desc); | ||
99 | |||
100 | memset(info, 0, sizeof *info); | ||
101 | info->control = intf; | ||
102 | while (len > 3) { | ||
103 | if (buf [1] != USB_DT_CS_INTERFACE) | ||
104 | goto next_desc; | ||
105 | |||
106 | /* use bDescriptorSubType to identify the CDC descriptors. | ||
107 | * We expect devices with CDC header and union descriptors. | ||
108 | * For CDC Ethernet we need the ethernet descriptor. | ||
109 | * For RNDIS, ignore two (pointless) CDC modem descriptors | ||
110 | * in favor of a complicated OID-based RPC scheme doing what | ||
111 | * CDC Ethernet achieves with a simple descriptor. | ||
112 | */ | ||
113 | switch (buf [2]) { | ||
114 | case USB_CDC_HEADER_TYPE: | ||
115 | if (info->header) { | ||
116 | dev_dbg(&intf->dev, "extra CDC header\n"); | ||
117 | goto bad_desc; | ||
118 | } | ||
119 | info->header = (void *) buf; | ||
120 | if (info->header->bLength != sizeof *info->header) { | ||
121 | dev_dbg(&intf->dev, "CDC header len %u\n", | ||
122 | info->header->bLength); | ||
123 | goto bad_desc; | ||
124 | } | ||
125 | break; | ||
126 | case USB_CDC_ACM_TYPE: | ||
127 | /* paranoia: disambiguate a "real" vendor-specific | ||
128 | * modem interface from an RNDIS non-modem. | ||
129 | */ | ||
130 | if (rndis) { | ||
131 | struct usb_cdc_acm_descriptor *d; | ||
132 | |||
133 | d = (void *) buf; | ||
134 | if (d->bmCapabilities) { | ||
135 | dev_dbg(&intf->dev, | ||
136 | "ACM capabilities %02x, " | ||
137 | "not really RNDIS?\n", | ||
138 | d->bmCapabilities); | ||
139 | goto bad_desc; | ||
140 | } | ||
141 | } | ||
142 | break; | ||
143 | case USB_CDC_UNION_TYPE: | ||
144 | if (info->u) { | ||
145 | dev_dbg(&intf->dev, "extra CDC union\n"); | ||
146 | goto bad_desc; | ||
147 | } | ||
148 | info->u = (void *) buf; | ||
149 | if (info->u->bLength != sizeof *info->u) { | ||
150 | dev_dbg(&intf->dev, "CDC union len %u\n", | ||
151 | info->u->bLength); | ||
152 | goto bad_desc; | ||
153 | } | ||
154 | |||
155 | /* we need a master/control interface (what we're | ||
156 | * probed with) and a slave/data interface; union | ||
157 | * descriptors sort this all out. | ||
158 | */ | ||
159 | info->control = usb_ifnum_to_if(dev->udev, | ||
160 | info->u->bMasterInterface0); | ||
161 | info->data = usb_ifnum_to_if(dev->udev, | ||
162 | info->u->bSlaveInterface0); | ||
163 | if (!info->control || !info->data) { | ||
164 | dev_dbg(&intf->dev, | ||
165 | "master #%u/%p slave #%u/%p\n", | ||
166 | info->u->bMasterInterface0, | ||
167 | info->control, | ||
168 | info->u->bSlaveInterface0, | ||
169 | info->data); | ||
170 | goto bad_desc; | ||
171 | } | ||
172 | if (info->control != intf) { | ||
173 | dev_dbg(&intf->dev, "bogus CDC Union\n"); | ||
174 | /* Ambit USB Cable Modem (and maybe others) | ||
175 | * interchanges master and slave interface. | ||
176 | */ | ||
177 | if (info->data == intf) { | ||
178 | info->data = info->control; | ||
179 | info->control = intf; | ||
180 | } else | ||
181 | goto bad_desc; | ||
182 | } | ||
183 | |||
184 | /* a data interface altsetting does the real i/o */ | ||
185 | d = &info->data->cur_altsetting->desc; | ||
186 | if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { | ||
187 | dev_dbg(&intf->dev, "slave class %u\n", | ||
188 | d->bInterfaceClass); | ||
189 | goto bad_desc; | ||
190 | } | ||
191 | break; | ||
192 | case USB_CDC_ETHERNET_TYPE: | ||
193 | if (info->ether) { | ||
194 | dev_dbg(&intf->dev, "extra CDC ether\n"); | ||
195 | goto bad_desc; | ||
196 | } | ||
197 | info->ether = (void *) buf; | ||
198 | if (info->ether->bLength != sizeof *info->ether) { | ||
199 | dev_dbg(&intf->dev, "CDC ether len %u\n", | ||
200 | info->ether->bLength); | ||
201 | goto bad_desc; | ||
202 | } | ||
203 | dev->hard_mtu = le16_to_cpu( | ||
204 | info->ether->wMaxSegmentSize); | ||
205 | /* because of Zaurus, we may be ignoring the host | ||
206 | * side link address we were given. | ||
207 | */ | ||
208 | break; | ||
209 | } | ||
210 | next_desc: | ||
211 | len -= buf [0]; /* bLength */ | ||
212 | buf += buf [0]; | ||
213 | } | ||
214 | |||
215 | /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors, | ||
216 | * so we'll hard-wire the interfaces and not check for descriptors. | ||
217 | */ | ||
218 | if (is_activesync(&intf->cur_altsetting->desc) && !info->u) { | ||
219 | info->control = usb_ifnum_to_if(dev->udev, 0); | ||
220 | info->data = usb_ifnum_to_if(dev->udev, 1); | ||
221 | if (!info->control || !info->data) { | ||
222 | dev_dbg(&intf->dev, | ||
223 | "activesync: master #0/%p slave #1/%p\n", | ||
224 | info->control, | ||
225 | info->data); | ||
226 | goto bad_desc; | ||
227 | } | ||
228 | |||
229 | } else if (!info->header || !info->u || (!rndis && !info->ether)) { | ||
230 | dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", | ||
231 | info->header ? "" : "header ", | ||
232 | info->u ? "" : "union ", | ||
233 | info->ether ? "" : "ether "); | ||
234 | goto bad_desc; | ||
235 | } | ||
236 | |||
237 | /* claim data interface and set it up ... with side effects. | ||
238 | * network traffic can't flow until an altsetting is enabled. | ||
239 | */ | ||
240 | status = usb_driver_claim_interface(driver, info->data, dev); | ||
241 | if (status < 0) | ||
242 | return status; | ||
243 | status = usbnet_get_endpoints(dev, info->data); | ||
244 | if (status < 0) { | ||
245 | /* ensure immediate exit from usbnet_disconnect */ | ||
246 | usb_set_intfdata(info->data, NULL); | ||
247 | usb_driver_release_interface(driver, info->data); | ||
248 | return status; | ||
249 | } | ||
250 | |||
251 | /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ | ||
252 | dev->status = NULL; | ||
253 | if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { | ||
254 | struct usb_endpoint_descriptor *desc; | ||
255 | |||
256 | dev->status = &info->control->cur_altsetting->endpoint [0]; | ||
257 | desc = &dev->status->desc; | ||
258 | if (!usb_endpoint_is_int_in(desc) | ||
259 | || (le16_to_cpu(desc->wMaxPacketSize) | ||
260 | < sizeof(struct usb_cdc_notification)) | ||
261 | || !desc->bInterval) { | ||
262 | dev_dbg(&intf->dev, "bad notification endpoint\n"); | ||
263 | dev->status = NULL; | ||
264 | } | ||
265 | } | ||
266 | if (rndis && !dev->status) { | ||
267 | dev_dbg(&intf->dev, "missing RNDIS status endpoint\n"); | ||
268 | usb_set_intfdata(info->data, NULL); | ||
269 | usb_driver_release_interface(driver, info->data); | ||
270 | return -ENODEV; | ||
271 | } | ||
272 | return 0; | ||
273 | |||
274 | bad_desc: | ||
275 | dev_info(&dev->udev->dev, "bad CDC descriptors\n"); | ||
276 | return -ENODEV; | ||
277 | } | ||
278 | EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); | ||
279 | |||
280 | void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
281 | { | ||
282 | struct cdc_state *info = (void *) &dev->data; | ||
283 | struct usb_driver *driver = driver_of(intf); | ||
284 | |||
285 | /* disconnect master --> disconnect slave */ | ||
286 | if (intf == info->control && info->data) { | ||
287 | /* ensure immediate exit from usbnet_disconnect */ | ||
288 | usb_set_intfdata(info->data, NULL); | ||
289 | usb_driver_release_interface(driver, info->data); | ||
290 | info->data = NULL; | ||
291 | } | ||
292 | |||
293 | /* and vice versa (just in case) */ | ||
294 | else if (intf == info->data && info->control) { | ||
295 | /* ensure immediate exit from usbnet_disconnect */ | ||
296 | usb_set_intfdata(info->control, NULL); | ||
297 | usb_driver_release_interface(driver, info->control); | ||
298 | info->control = NULL; | ||
299 | } | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); | ||
302 | |||
303 | |||
304 | /*------------------------------------------------------------------------- | ||
305 | * | ||
306 | * Communications Device Class, Ethernet Control model | ||
307 | * | ||
308 | * Takes two interfaces. The DATA interface is inactive till an altsetting | ||
309 | * is selected. Configuration data includes class descriptors. There's | ||
310 | * an optional status endpoint on the control interface. | ||
311 | * | ||
312 | * This should interop with whatever the 2.4 "CDCEther.c" driver | ||
313 | * (by Brad Hards) talked with, with more functionality. | ||
314 | * | ||
315 | *-------------------------------------------------------------------------*/ | ||
316 | |||
317 | static void dumpspeed(struct usbnet *dev, __le32 *speeds) | ||
318 | { | ||
319 | if (netif_msg_timer(dev)) | ||
320 | devinfo(dev, "link speeds: %u kbps up, %u kbps down", | ||
321 | __le32_to_cpu(speeds[0]) / 1000, | ||
322 | __le32_to_cpu(speeds[1]) / 1000); | ||
323 | } | ||
324 | |||
325 | static void cdc_status(struct usbnet *dev, struct urb *urb) | ||
326 | { | ||
327 | struct usb_cdc_notification *event; | ||
328 | |||
329 | if (urb->actual_length < sizeof *event) | ||
330 | return; | ||
331 | |||
332 | /* SPEED_CHANGE can get split into two 8-byte packets */ | ||
333 | if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { | ||
334 | dumpspeed(dev, (__le32 *) urb->transfer_buffer); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | event = urb->transfer_buffer; | ||
339 | switch (event->bNotificationType) { | ||
340 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | ||
341 | if (netif_msg_timer(dev)) | ||
342 | devdbg(dev, "CDC: carrier %s", | ||
343 | event->wValue ? "on" : "off"); | ||
344 | if (event->wValue) | ||
345 | netif_carrier_on(dev->net); | ||
346 | else | ||
347 | netif_carrier_off(dev->net); | ||
348 | break; | ||
349 | case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ | ||
350 | if (netif_msg_timer(dev)) | ||
351 | devdbg(dev, "CDC: speed change (len %d)", | ||
352 | urb->actual_length); | ||
353 | if (urb->actual_length != (sizeof *event + 8)) | ||
354 | set_bit(EVENT_STS_SPLIT, &dev->flags); | ||
355 | else | ||
356 | dumpspeed(dev, (__le32 *) &event[1]); | ||
357 | break; | ||
358 | /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS), | ||
359 | * but there are no standard formats for the response data. | ||
360 | */ | ||
361 | default: | ||
362 | deverr(dev, "CDC: unexpected notification %02x!", | ||
363 | event->bNotificationType); | ||
364 | break; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | static u8 nibble(unsigned char c) | ||
369 | { | ||
370 | if (likely(isdigit(c))) | ||
371 | return c - '0'; | ||
372 | c = toupper(c); | ||
373 | if (likely(isxdigit(c))) | ||
374 | return 10 + c - 'A'; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static inline int | ||
379 | get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) | ||
380 | { | ||
381 | int tmp, i; | ||
382 | unsigned char buf [13]; | ||
383 | |||
384 | tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); | ||
385 | if (tmp != 12) { | ||
386 | dev_dbg(&dev->udev->dev, | ||
387 | "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); | ||
388 | if (tmp >= 0) | ||
389 | tmp = -EINVAL; | ||
390 | return tmp; | ||
391 | } | ||
392 | for (i = tmp = 0; i < 6; i++, tmp += 2) | ||
393 | dev->net->dev_addr [i] = | ||
394 | (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) | ||
399 | { | ||
400 | int status; | ||
401 | struct cdc_state *info = (void *) &dev->data; | ||
402 | |||
403 | status = usbnet_generic_cdc_bind(dev, intf); | ||
404 | if (status < 0) | ||
405 | return status; | ||
406 | |||
407 | status = get_ethernet_addr(dev, info->ether); | ||
408 | if (status < 0) { | ||
409 | usb_set_intfdata(info->data, NULL); | ||
410 | usb_driver_release_interface(driver_of(intf), info->data); | ||
411 | return status; | ||
412 | } | ||
413 | |||
414 | /* FIXME cdc-ether has some multicast code too, though it complains | ||
415 | * in routine cases. info->ether describes the multicast support. | ||
416 | * Implement that here, manipulating the cdc filter as needed. | ||
417 | */ | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static const struct driver_info cdc_info = { | ||
422 | .description = "CDC Ethernet Device", | ||
423 | .flags = FLAG_ETHER, | ||
424 | // .check_connect = cdc_check_connect, | ||
425 | .bind = cdc_bind, | ||
426 | .unbind = usbnet_cdc_unbind, | ||
427 | .status = cdc_status, | ||
428 | }; | ||
429 | |||
430 | /*-------------------------------------------------------------------------*/ | ||
431 | |||
432 | |||
433 | static const struct usb_device_id products [] = { | ||
434 | /* | ||
435 | * BLACKLIST !! | ||
436 | * | ||
437 | * First blacklist any products that are egregiously nonconformant | ||
438 | * with the CDC Ethernet specs. Minor braindamage we cope with; when | ||
439 | * they're not even trying, needing a separate driver is only the first | ||
440 | * of the differences to show up. | ||
441 | */ | ||
442 | |||
443 | #define ZAURUS_MASTER_INTERFACE \ | ||
444 | .bInterfaceClass = USB_CLASS_COMM, \ | ||
445 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ | ||
446 | .bInterfaceProtocol = USB_CDC_PROTO_NONE | ||
447 | |||
448 | /* SA-1100 based Sharp Zaurus ("collie"), or compatible; | ||
449 | * wire-incompatible with true CDC Ethernet implementations. | ||
450 | * (And, it seems, needlessly so...) | ||
451 | */ | ||
452 | { | ||
453 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
454 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
455 | .idVendor = 0x04DD, | ||
456 | .idProduct = 0x8004, | ||
457 | ZAURUS_MASTER_INTERFACE, | ||
458 | .driver_info = 0, | ||
459 | }, | ||
460 | |||
461 | /* PXA-25x based Sharp Zaurii. Note that it seems some of these | ||
462 | * (later models especially) may have shipped only with firmware | ||
463 | * advertising false "CDC MDLM" compatibility ... but we're not | ||
464 | * clear which models did that, so for now let's assume the worst. | ||
465 | */ | ||
466 | { | ||
467 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
468 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
469 | .idVendor = 0x04DD, | ||
470 | .idProduct = 0x8005, /* A-300 */ | ||
471 | ZAURUS_MASTER_INTERFACE, | ||
472 | .driver_info = 0, | ||
473 | }, { | ||
474 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
475 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
476 | .idVendor = 0x04DD, | ||
477 | .idProduct = 0x8006, /* B-500/SL-5600 */ | ||
478 | ZAURUS_MASTER_INTERFACE, | ||
479 | .driver_info = 0, | ||
480 | }, { | ||
481 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
482 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
483 | .idVendor = 0x04DD, | ||
484 | .idProduct = 0x8007, /* C-700 */ | ||
485 | ZAURUS_MASTER_INTERFACE, | ||
486 | .driver_info = 0, | ||
487 | }, { | ||
488 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
489 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
490 | .idVendor = 0x04DD, | ||
491 | .idProduct = 0x9031, /* C-750 C-760 */ | ||
492 | ZAURUS_MASTER_INTERFACE, | ||
493 | .driver_info = 0, | ||
494 | }, { | ||
495 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
496 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
497 | .idVendor = 0x04DD, | ||
498 | .idProduct = 0x9032, /* SL-6000 */ | ||
499 | ZAURUS_MASTER_INTERFACE, | ||
500 | .driver_info = 0, | ||
501 | }, { | ||
502 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
503 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
504 | .idVendor = 0x04DD, | ||
505 | /* reported with some C860 units */ | ||
506 | .idProduct = 0x9050, /* C-860 */ | ||
507 | ZAURUS_MASTER_INTERFACE, | ||
508 | .driver_info = 0, | ||
509 | }, | ||
510 | |||
511 | /* Olympus has some models with a Zaurus-compatible option. | ||
512 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) | ||
513 | */ | ||
514 | { | ||
515 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
516 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
517 | .idVendor = 0x07B4, | ||
518 | .idProduct = 0x0F02, /* R-1000 */ | ||
519 | ZAURUS_MASTER_INTERFACE, | ||
520 | .driver_info = 0, | ||
521 | }, | ||
522 | |||
523 | /* | ||
524 | * WHITELIST!!! | ||
525 | * | ||
526 | * CDC Ether uses two interfaces, not necessarily consecutive. | ||
527 | * We match the main interface, ignoring the optional device | ||
528 | * class so we could handle devices that aren't exclusively | ||
529 | * CDC ether. | ||
530 | * | ||
531 | * NOTE: this match must come AFTER entries blacklisting devices | ||
532 | * because of bugs/quirks in a given product (like Zaurus, above). | ||
533 | */ | ||
534 | { | ||
535 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, | ||
536 | USB_CDC_PROTO_NONE), | ||
537 | .driver_info = (unsigned long) &cdc_info, | ||
538 | }, | ||
539 | { }, // END | ||
540 | }; | ||
541 | MODULE_DEVICE_TABLE(usb, products); | ||
542 | |||
543 | static struct usb_driver cdc_driver = { | ||
544 | .name = "cdc_ether", | ||
545 | .id_table = products, | ||
546 | .probe = usbnet_probe, | ||
547 | .disconnect = usbnet_disconnect, | ||
548 | .suspend = usbnet_suspend, | ||
549 | .resume = usbnet_resume, | ||
550 | }; | ||
551 | |||
552 | |||
553 | static int __init cdc_init(void) | ||
554 | { | ||
555 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) | ||
556 | < sizeof(struct cdc_state))); | ||
557 | |||
558 | return usb_register(&cdc_driver); | ||
559 | } | ||
560 | module_init(cdc_init); | ||
561 | |||
562 | static void __exit cdc_exit(void) | ||
563 | { | ||
564 | usb_deregister(&cdc_driver); | ||
565 | } | ||
566 | module_exit(cdc_exit); | ||
567 | |||
568 | MODULE_AUTHOR("David Brownell"); | ||
569 | MODULE_DESCRIPTION("USB CDC Ethernet devices"); | ||
570 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c new file mode 100644 index 000000000000..bc62b012602b --- /dev/null +++ b/drivers/net/usb/cdc_subset.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * Simple "CDC Subset" USB Networking Links | ||
3 | * Copyright (C) 2000-2005 by David Brownell | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/kmod.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/netdevice.h> | ||
24 | #include <linux/etherdevice.h> | ||
25 | #include <linux/ethtool.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/mii.h> | ||
28 | #include <linux/usb.h> | ||
29 | |||
30 | #include "usbnet.h" | ||
31 | |||
32 | |||
33 | /* | ||
34 | * This supports simple USB network links that don't require any special | ||
35 | * framing or hardware control operations. The protocol used here is a | ||
36 | * strict subset of CDC Ethernet, with three basic differences reflecting | ||
37 | * the goal that almost any hardware should run it: | ||
38 | * | ||
39 | * - Minimal runtime control: one interface, no altsettings, and | ||
40 | * no vendor or class specific control requests. If a device is | ||
41 | * configured, it is allowed to exchange packets with the host. | ||
42 | * Fancier models would mean not working on some hardware. | ||
43 | * | ||
44 | * - Minimal manufacturing control: no IEEE "Organizationally | ||
45 | * Unique ID" required, or an EEPROMs to store one. Each host uses | ||
46 | * one random "locally assigned" Ethernet address instead, which can | ||
47 | * of course be overridden using standard tools like "ifconfig". | ||
48 | * (With 2^46 such addresses, same-net collisions are quite rare.) | ||
49 | * | ||
50 | * - There is no additional framing data for USB. Packets are written | ||
51 | * exactly as in CDC Ethernet, starting with an Ethernet header and | ||
52 | * terminated by a short packet. However, the host will never send a | ||
53 | * zero length packet; some systems can't handle those robustly. | ||
54 | * | ||
55 | * Anything that can transmit and receive USB bulk packets can implement | ||
56 | * this protocol. That includes both smart peripherals and quite a lot | ||
57 | * of "host-to-host" USB cables (which embed two devices back-to-back). | ||
58 | * | ||
59 | * Note that although Linux may use many of those host-to-host links | ||
60 | * with this "cdc_subset" framing, that doesn't mean there may not be a | ||
61 | * better approach. Handling the "other end unplugs/replugs" scenario | ||
62 | * well tends to require chip-specific vendor requests. Also, Windows | ||
63 | * peers at the other end of host-to-host cables may expect their own | ||
64 | * framing to be used rather than this "cdc_subset" model. | ||
65 | */ | ||
66 | |||
67 | #if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX) | ||
68 | /* PDA style devices are always connected if present */ | ||
69 | static int always_connected (struct usbnet *dev) | ||
70 | { | ||
71 | return 0; | ||
72 | } | ||
73 | #endif | ||
74 | |||
75 | #ifdef CONFIG_USB_ALI_M5632 | ||
76 | #define HAVE_HARDWARE | ||
77 | |||
78 | /*------------------------------------------------------------------------- | ||
79 | * | ||
80 | * ALi M5632 driver ... does high speed | ||
81 | * | ||
82 | * NOTE that the MS-Windows drivers for this chip use some funky and | ||
83 | * (naturally) undocumented 7-byte prefix to each packet, so this is a | ||
84 | * case where we don't currently interoperate. Also, once you unplug | ||
85 | * one end of the cable, you need to replug the other end too ... since | ||
86 | * chip docs are unavailable, there's no way to reset the relevant state | ||
87 | * short of a power cycle. | ||
88 | * | ||
89 | *-------------------------------------------------------------------------*/ | ||
90 | |||
91 | static const struct driver_info ali_m5632_info = { | ||
92 | .description = "ALi M5632", | ||
93 | }; | ||
94 | |||
95 | #endif | ||
96 | |||
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 | // no reset available! | ||
115 | // no check_connect available! | ||
116 | |||
117 | .in = 2, .out = 2, // direction distinguishes these | ||
118 | }; | ||
119 | |||
120 | #endif /* CONFIG_USB_AN2720 */ | ||
121 | |||
122 | |||
123 | #ifdef CONFIG_USB_BELKIN | ||
124 | #define HAVE_HARDWARE | ||
125 | |||
126 | /*------------------------------------------------------------------------- | ||
127 | * | ||
128 | * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller | ||
129 | * | ||
130 | * ... also two eTEK designs, including one sold as "Advance USBNET" | ||
131 | * | ||
132 | *-------------------------------------------------------------------------*/ | ||
133 | |||
134 | static const struct driver_info belkin_info = { | ||
135 | .description = "Belkin, eTEK, or compatible", | ||
136 | }; | ||
137 | |||
138 | #endif /* CONFIG_USB_BELKIN */ | ||
139 | |||
140 | |||
141 | |||
142 | #ifdef CONFIG_USB_EPSON2888 | ||
143 | #define HAVE_HARDWARE | ||
144 | |||
145 | /*------------------------------------------------------------------------- | ||
146 | * | ||
147 | * EPSON USB clients | ||
148 | * | ||
149 | * This is the same idea as Linux PDAs (below) except the firmware in the | ||
150 | * device might not be Tux-powered. Epson provides reference firmware that | ||
151 | * implements this interface. Product developers can reuse or modify that | ||
152 | * code, such as by using their own product and vendor codes. | ||
153 | * | ||
154 | * Support was from Juro Bystricky <bystricky.juro@erd.epson.com> | ||
155 | * | ||
156 | *-------------------------------------------------------------------------*/ | ||
157 | |||
158 | static const struct driver_info epson2888_info = { | ||
159 | .description = "Epson USB Device", | ||
160 | .check_connect = always_connected, | ||
161 | |||
162 | .in = 4, .out = 3, | ||
163 | }; | ||
164 | |||
165 | #endif /* CONFIG_USB_EPSON2888 */ | ||
166 | |||
167 | |||
168 | /*------------------------------------------------------------------------- | ||
169 | * | ||
170 | * info from Jonathan McDowell <noodles@earth.li> | ||
171 | * | ||
172 | *-------------------------------------------------------------------------*/ | ||
173 | #ifdef CONFIG_USB_KC2190 | ||
174 | #define HAVE_HARDWARE | ||
175 | static const struct driver_info kc2190_info = { | ||
176 | .description = "KC Technology KC-190", | ||
177 | }; | ||
178 | #endif /* CONFIG_USB_KC2190 */ | ||
179 | |||
180 | |||
181 | #ifdef CONFIG_USB_ARMLINUX | ||
182 | #define HAVE_HARDWARE | ||
183 | |||
184 | /*------------------------------------------------------------------------- | ||
185 | * | ||
186 | * Intel's SA-1100 chip integrates basic USB support, and is used | ||
187 | * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. | ||
188 | * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to | ||
189 | * network using minimal USB framing data. | ||
190 | * | ||
191 | * This describes the driver currently in standard ARM Linux kernels. | ||
192 | * The Zaurus uses a different driver (see later). | ||
193 | * | ||
194 | * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support | ||
195 | * and different USB endpoint numbering than the SA1100 devices. The | ||
196 | * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 | ||
197 | * so we rely on the endpoint descriptors. | ||
198 | * | ||
199 | *-------------------------------------------------------------------------*/ | ||
200 | |||
201 | static const struct driver_info linuxdev_info = { | ||
202 | .description = "Linux Device", | ||
203 | .check_connect = always_connected, | ||
204 | }; | ||
205 | |||
206 | static const struct driver_info yopy_info = { | ||
207 | .description = "Yopy", | ||
208 | .check_connect = always_connected, | ||
209 | }; | ||
210 | |||
211 | static const struct driver_info blob_info = { | ||
212 | .description = "Boot Loader OBject", | ||
213 | .check_connect = always_connected, | ||
214 | }; | ||
215 | |||
216 | #endif /* CONFIG_USB_ARMLINUX */ | ||
217 | |||
218 | |||
219 | /*-------------------------------------------------------------------------*/ | ||
220 | |||
221 | #ifndef HAVE_HARDWARE | ||
222 | #error You need to configure some hardware for this driver | ||
223 | #endif | ||
224 | |||
225 | /* | ||
226 | * chip vendor names won't normally be on the cables, and | ||
227 | * may not be on the device. | ||
228 | */ | ||
229 | |||
230 | static const struct usb_device_id products [] = { | ||
231 | |||
232 | #ifdef CONFIG_USB_ALI_M5632 | ||
233 | { | ||
234 | USB_DEVICE (0x0402, 0x5632), // ALi defaults | ||
235 | .driver_info = (unsigned long) &ali_m5632_info, | ||
236 | }, | ||
237 | { | ||
238 | USB_DEVICE (0x182d,0x207c), // SiteCom CN-124 | ||
239 | .driver_info = (unsigned long) &ali_m5632_info, | ||
240 | }, | ||
241 | #endif | ||
242 | |||
243 | #ifdef CONFIG_USB_AN2720 | ||
244 | { | ||
245 | USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults | ||
246 | .driver_info = (unsigned long) &an2720_info, | ||
247 | }, { | ||
248 | USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET | ||
249 | .driver_info = (unsigned long) &an2720_info, | ||
250 | }, | ||
251 | #endif | ||
252 | |||
253 | #ifdef CONFIG_USB_BELKIN | ||
254 | { | ||
255 | USB_DEVICE (0x050d, 0x0004), // Belkin | ||
256 | .driver_info = (unsigned long) &belkin_info, | ||
257 | }, { | ||
258 | USB_DEVICE (0x056c, 0x8100), // eTEK | ||
259 | .driver_info = (unsigned long) &belkin_info, | ||
260 | }, { | ||
261 | USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK) | ||
262 | .driver_info = (unsigned long) &belkin_info, | ||
263 | }, | ||
264 | #endif | ||
265 | |||
266 | #ifdef CONFIG_USB_EPSON2888 | ||
267 | { | ||
268 | USB_DEVICE (0x0525, 0x2888), // EPSON USB client | ||
269 | .driver_info = (unsigned long) &epson2888_info, | ||
270 | }, | ||
271 | #endif | ||
272 | |||
273 | #ifdef CONFIG_USB_KC2190 | ||
274 | { | ||
275 | USB_DEVICE (0x050f, 0x0190), // KC-190 | ||
276 | .driver_info = (unsigned long) &kc2190_info, | ||
277 | }, | ||
278 | #endif | ||
279 | |||
280 | #ifdef CONFIG_USB_ARMLINUX | ||
281 | /* | ||
282 | * SA-1100 using standard ARM Linux kernels, or compatible. | ||
283 | * Often used when talking to Linux PDAs (iPaq, Yopy, etc). | ||
284 | * The sa-1100 "usb-eth" driver handles the basic framing. | ||
285 | * | ||
286 | * PXA25x or PXA210 ... these use a "usb-eth" driver much like | ||
287 | * the sa1100 one, but hardware uses different endpoint numbers. | ||
288 | * | ||
289 | * Or the Linux "Ethernet" gadget on hardware that can't talk | ||
290 | * CDC Ethernet (e.g., no altsettings), in either of two modes: | ||
291 | * - acting just like the old "usb-eth" firmware, though | ||
292 | * the implementation is different | ||
293 | * - supporting RNDIS as the first/default configuration for | ||
294 | * MS-Windows interop; Linux needs to use the other config | ||
295 | */ | ||
296 | { | ||
297 | // 1183 = 0x049F, both used as hex values? | ||
298 | // Compaq "Itsy" vendor/product id | ||
299 | USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible | ||
300 | .driver_info = (unsigned long) &linuxdev_info, | ||
301 | }, { | ||
302 | USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" | ||
303 | .driver_info = (unsigned long) &yopy_info, | ||
304 | }, { | ||
305 | USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader | ||
306 | .driver_info = (unsigned long) &blob_info, | ||
307 | }, { | ||
308 | // Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config | ||
309 | // e.g. Gumstix, current OpenZaurus, ... | ||
310 | USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203), | ||
311 | .driver_info = (unsigned long) &linuxdev_info, | ||
312 | }, | ||
313 | #endif | ||
314 | |||
315 | { }, // END | ||
316 | }; | ||
317 | MODULE_DEVICE_TABLE(usb, products); | ||
318 | |||
319 | /*-------------------------------------------------------------------------*/ | ||
320 | |||
321 | static struct usb_driver cdc_subset_driver = { | ||
322 | .name = "cdc_subset", | ||
323 | .probe = usbnet_probe, | ||
324 | .suspend = usbnet_suspend, | ||
325 | .resume = usbnet_resume, | ||
326 | .disconnect = usbnet_disconnect, | ||
327 | .id_table = products, | ||
328 | }; | ||
329 | |||
330 | static int __init cdc_subset_init(void) | ||
331 | { | ||
332 | return usb_register(&cdc_subset_driver); | ||
333 | } | ||
334 | module_init(cdc_subset_init); | ||
335 | |||
336 | static void __exit cdc_subset_exit(void) | ||
337 | { | ||
338 | usb_deregister(&cdc_subset_driver); | ||
339 | } | ||
340 | module_exit(cdc_subset_exit); | ||
341 | |||
342 | MODULE_AUTHOR("David Brownell"); | ||
343 | MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links"); | ||
344 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c new file mode 100644 index 000000000000..a67638601477 --- /dev/null +++ b/drivers/net/usb/dm9601.c | |||
@@ -0,0 +1,619 @@ | |||
1 | /* | ||
2 | * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices | ||
3 | * | ||
4 | * Peter Korsgaard <jacmet@sunsite.dk> | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public License | ||
7 | * version 2. This program is licensed "as is" without any warranty of any | ||
8 | * kind, whether express or implied. | ||
9 | */ | ||
10 | |||
11 | //#define DEBUG | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/stddef.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/ethtool.h> | ||
20 | #include <linux/mii.h> | ||
21 | #include <linux/usb.h> | ||
22 | #include <linux/crc32.h> | ||
23 | |||
24 | #include "usbnet.h" | ||
25 | |||
26 | /* datasheet: | ||
27 | http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf | ||
28 | */ | ||
29 | |||
30 | /* control requests */ | ||
31 | #define DM_READ_REGS 0x00 | ||
32 | #define DM_WRITE_REGS 0x01 | ||
33 | #define DM_READ_MEMS 0x02 | ||
34 | #define DM_WRITE_REG 0x03 | ||
35 | #define DM_WRITE_MEMS 0x05 | ||
36 | #define DM_WRITE_MEM 0x07 | ||
37 | |||
38 | /* registers */ | ||
39 | #define DM_NET_CTRL 0x00 | ||
40 | #define DM_RX_CTRL 0x05 | ||
41 | #define DM_SHARED_CTRL 0x0b | ||
42 | #define DM_SHARED_ADDR 0x0c | ||
43 | #define DM_SHARED_DATA 0x0d /* low + high */ | ||
44 | #define DM_PHY_ADDR 0x10 /* 6 bytes */ | ||
45 | #define DM_MCAST_ADDR 0x16 /* 8 bytes */ | ||
46 | #define DM_GPR_CTRL 0x1e | ||
47 | #define DM_GPR_DATA 0x1f | ||
48 | |||
49 | #define DM_MAX_MCAST 64 | ||
50 | #define DM_MCAST_SIZE 8 | ||
51 | #define DM_EEPROM_LEN 256 | ||
52 | #define DM_TX_OVERHEAD 2 /* 2 byte header */ | ||
53 | #define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */ | ||
54 | #define DM_TIMEOUT 1000 | ||
55 | |||
56 | |||
57 | static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) | ||
58 | { | ||
59 | devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length); | ||
60 | return usb_control_msg(dev->udev, | ||
61 | usb_rcvctrlpipe(dev->udev, 0), | ||
62 | DM_READ_REGS, | ||
63 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
64 | 0, reg, data, length, USB_CTRL_SET_TIMEOUT); | ||
65 | } | ||
66 | |||
67 | static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) | ||
68 | { | ||
69 | return dm_read(dev, reg, 1, value); | ||
70 | } | ||
71 | |||
72 | static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) | ||
73 | { | ||
74 | devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length); | ||
75 | return usb_control_msg(dev->udev, | ||
76 | usb_sndctrlpipe(dev->udev, 0), | ||
77 | DM_WRITE_REGS, | ||
78 | USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, | ||
79 | 0, reg, data, length, USB_CTRL_SET_TIMEOUT); | ||
80 | } | ||
81 | |||
82 | static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) | ||
83 | { | ||
84 | devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value); | ||
85 | return usb_control_msg(dev->udev, | ||
86 | usb_sndctrlpipe(dev->udev, 0), | ||
87 | DM_WRITE_REG, | ||
88 | USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, | ||
89 | value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
90 | } | ||
91 | |||
92 | static void dm_write_async_callback(struct urb *urb) | ||
93 | { | ||
94 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
95 | |||
96 | if (urb->status < 0) | ||
97 | printk(KERN_DEBUG "dm_write_async_callback() failed with %d", | ||
98 | urb->status); | ||
99 | |||
100 | kfree(req); | ||
101 | usb_free_urb(urb); | ||
102 | } | ||
103 | |||
104 | static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) | ||
105 | { | ||
106 | struct usb_ctrlrequest *req; | ||
107 | struct urb *urb; | ||
108 | int status; | ||
109 | |||
110 | devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); | ||
111 | |||
112 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
113 | if (!urb) { | ||
114 | deverr(dev, "Error allocating URB in dm_write_async!"); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
119 | if (!req) { | ||
120 | deverr(dev, "Failed to allocate memory for control request"); | ||
121 | usb_free_urb(urb); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
126 | req->bRequest = DM_WRITE_REGS; | ||
127 | req->wValue = 0; | ||
128 | req->wIndex = cpu_to_le16(reg); | ||
129 | req->wLength = cpu_to_le16(length); | ||
130 | |||
131 | usb_fill_control_urb(urb, dev->udev, | ||
132 | usb_sndctrlpipe(dev->udev, 0), | ||
133 | (void *)req, data, length, | ||
134 | dm_write_async_callback, req); | ||
135 | |||
136 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
137 | if (status < 0) { | ||
138 | deverr(dev, "Error submitting the control message: status=%d", | ||
139 | status); | ||
140 | kfree(req); | ||
141 | usb_free_urb(urb); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) | ||
146 | { | ||
147 | struct usb_ctrlrequest *req; | ||
148 | struct urb *urb; | ||
149 | int status; | ||
150 | |||
151 | devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x", | ||
152 | reg, value); | ||
153 | |||
154 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
155 | if (!urb) { | ||
156 | deverr(dev, "Error allocating URB in dm_write_async!"); | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
161 | if (!req) { | ||
162 | deverr(dev, "Failed to allocate memory for control request"); | ||
163 | usb_free_urb(urb); | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
168 | req->bRequest = DM_WRITE_REG; | ||
169 | req->wValue = cpu_to_le16(value); | ||
170 | req->wIndex = cpu_to_le16(reg); | ||
171 | req->wLength = 0; | ||
172 | |||
173 | usb_fill_control_urb(urb, dev->udev, | ||
174 | usb_sndctrlpipe(dev->udev, 0), | ||
175 | (void *)req, NULL, 0, dm_write_async_callback, req); | ||
176 | |||
177 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
178 | if (status < 0) { | ||
179 | deverr(dev, "Error submitting the control message: status=%d", | ||
180 | status); | ||
181 | kfree(req); | ||
182 | usb_free_urb(urb); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value) | ||
187 | { | ||
188 | int ret, i; | ||
189 | |||
190 | mutex_lock(&dev->phy_mutex); | ||
191 | |||
192 | dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); | ||
193 | dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4); | ||
194 | |||
195 | for (i = 0; i < DM_TIMEOUT; i++) { | ||
196 | u8 tmp; | ||
197 | |||
198 | udelay(1); | ||
199 | ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); | ||
200 | if (ret < 0) | ||
201 | goto out; | ||
202 | |||
203 | /* ready */ | ||
204 | if ((tmp & 1) == 0) | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | if (i == DM_TIMEOUT) { | ||
209 | deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom"); | ||
210 | ret = -EIO; | ||
211 | goto out; | ||
212 | } | ||
213 | |||
214 | dm_write_reg(dev, DM_SHARED_CTRL, 0x0); | ||
215 | ret = dm_read(dev, DM_SHARED_DATA, 2, value); | ||
216 | |||
217 | devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d", | ||
218 | phy, reg, *value, ret); | ||
219 | |||
220 | out: | ||
221 | mutex_unlock(&dev->phy_mutex); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value) | ||
226 | { | ||
227 | int ret, i; | ||
228 | |||
229 | mutex_lock(&dev->phy_mutex); | ||
230 | |||
231 | ret = dm_write(dev, DM_SHARED_DATA, 2, &value); | ||
232 | if (ret < 0) | ||
233 | goto out; | ||
234 | |||
235 | dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); | ||
236 | dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14); | ||
237 | |||
238 | for (i = 0; i < DM_TIMEOUT; i++) { | ||
239 | u8 tmp; | ||
240 | |||
241 | udelay(1); | ||
242 | ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); | ||
243 | if (ret < 0) | ||
244 | goto out; | ||
245 | |||
246 | /* ready */ | ||
247 | if ((tmp & 1) == 0) | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | if (i == DM_TIMEOUT) { | ||
252 | deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom"); | ||
253 | ret = -EIO; | ||
254 | goto out; | ||
255 | } | ||
256 | |||
257 | dm_write_reg(dev, DM_SHARED_CTRL, 0x0); | ||
258 | |||
259 | out: | ||
260 | mutex_unlock(&dev->phy_mutex); | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) | ||
265 | { | ||
266 | return dm_read_shared_word(dev, 0, offset, value); | ||
267 | } | ||
268 | |||
269 | |||
270 | |||
271 | static int dm9601_get_eeprom_len(struct net_device *dev) | ||
272 | { | ||
273 | return DM_EEPROM_LEN; | ||
274 | } | ||
275 | |||
276 | static int dm9601_get_eeprom(struct net_device *net, | ||
277 | struct ethtool_eeprom *eeprom, u8 * data) | ||
278 | { | ||
279 | struct usbnet *dev = netdev_priv(net); | ||
280 | u16 *ebuf = (u16 *) data; | ||
281 | int i; | ||
282 | |||
283 | /* access is 16bit */ | ||
284 | if ((eeprom->offset % 2) || (eeprom->len % 2)) | ||
285 | return -EINVAL; | ||
286 | |||
287 | for (i = 0; i < eeprom->len / 2; i++) { | ||
288 | if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i, | ||
289 | &ebuf[i]) < 0) | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc) | ||
296 | { | ||
297 | struct usbnet *dev = netdev_priv(netdev); | ||
298 | |||
299 | u16 res; | ||
300 | |||
301 | if (phy_id) { | ||
302 | devdbg(dev, "Only internal phy supported"); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | dm_read_shared_word(dev, 1, loc, &res); | ||
307 | |||
308 | devdbg(dev, | ||
309 | "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", | ||
310 | phy_id, loc, le16_to_cpu(res)); | ||
311 | |||
312 | return le16_to_cpu(res); | ||
313 | } | ||
314 | |||
315 | static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc, | ||
316 | int val) | ||
317 | { | ||
318 | struct usbnet *dev = netdev_priv(netdev); | ||
319 | u16 res = cpu_to_le16(val); | ||
320 | |||
321 | if (phy_id) { | ||
322 | devdbg(dev, "Only internal phy supported"); | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", | ||
327 | phy_id, loc, val); | ||
328 | |||
329 | dm_write_shared_word(dev, 1, loc, res); | ||
330 | } | ||
331 | |||
332 | static void dm9601_get_drvinfo(struct net_device *net, | ||
333 | struct ethtool_drvinfo *info) | ||
334 | { | ||
335 | /* Inherit standard device info */ | ||
336 | usbnet_get_drvinfo(net, info); | ||
337 | info->eedump_len = DM_EEPROM_LEN; | ||
338 | } | ||
339 | |||
340 | static u32 dm9601_get_link(struct net_device *net) | ||
341 | { | ||
342 | struct usbnet *dev = netdev_priv(net); | ||
343 | |||
344 | return mii_link_ok(&dev->mii); | ||
345 | } | ||
346 | |||
347 | static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | ||
348 | { | ||
349 | struct usbnet *dev = netdev_priv(net); | ||
350 | |||
351 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
352 | } | ||
353 | |||
354 | static struct ethtool_ops dm9601_ethtool_ops = { | ||
355 | .get_drvinfo = dm9601_get_drvinfo, | ||
356 | .get_link = dm9601_get_link, | ||
357 | .get_msglevel = usbnet_get_msglevel, | ||
358 | .set_msglevel = usbnet_set_msglevel, | ||
359 | .get_eeprom_len = dm9601_get_eeprom_len, | ||
360 | .get_eeprom = dm9601_get_eeprom, | ||
361 | .get_settings = usbnet_get_settings, | ||
362 | .set_settings = usbnet_set_settings, | ||
363 | .nway_reset = usbnet_nway_reset, | ||
364 | }; | ||
365 | |||
366 | static void dm9601_set_multicast(struct net_device *net) | ||
367 | { | ||
368 | struct usbnet *dev = netdev_priv(net); | ||
369 | /* We use the 20 byte dev->data for our 8 byte filter buffer | ||
370 | * to avoid allocating memory that is tricky to free later */ | ||
371 | u8 *hashes = (u8 *) & dev->data; | ||
372 | u8 rx_ctl = 0x01; | ||
373 | |||
374 | memset(hashes, 0x00, DM_MCAST_SIZE); | ||
375 | hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ | ||
376 | |||
377 | if (net->flags & IFF_PROMISC) { | ||
378 | rx_ctl |= 0x02; | ||
379 | } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) { | ||
380 | rx_ctl |= 0x04; | ||
381 | } else if (net->mc_count) { | ||
382 | struct dev_mc_list *mc_list = net->mc_list; | ||
383 | int i; | ||
384 | |||
385 | for (i = 0; i < net->mc_count; i++) { | ||
386 | u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; | ||
387 | hashes[crc >> 3] |= 1 << (crc & 0x7); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes); | ||
392 | dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); | ||
393 | } | ||
394 | |||
395 | static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) | ||
396 | { | ||
397 | int ret; | ||
398 | |||
399 | ret = usbnet_get_endpoints(dev, intf); | ||
400 | if (ret) | ||
401 | goto out; | ||
402 | |||
403 | dev->net->do_ioctl = dm9601_ioctl; | ||
404 | dev->net->set_multicast_list = dm9601_set_multicast; | ||
405 | dev->net->ethtool_ops = &dm9601_ethtool_ops; | ||
406 | dev->net->hard_header_len += DM_TX_OVERHEAD; | ||
407 | dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | ||
408 | dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD; | ||
409 | |||
410 | dev->mii.dev = dev->net; | ||
411 | dev->mii.mdio_read = dm9601_mdio_read; | ||
412 | dev->mii.mdio_write = dm9601_mdio_write; | ||
413 | dev->mii.phy_id_mask = 0x1f; | ||
414 | dev->mii.reg_num_mask = 0x1f; | ||
415 | |||
416 | /* reset */ | ||
417 | ret = dm_write_reg(dev, DM_NET_CTRL, 1); | ||
418 | udelay(20); | ||
419 | |||
420 | /* read MAC */ | ||
421 | ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr); | ||
422 | if (ret < 0) { | ||
423 | printk(KERN_ERR "Error reading MAC address\n"); | ||
424 | ret = -ENODEV; | ||
425 | goto out; | ||
426 | } | ||
427 | |||
428 | |||
429 | /* power up phy */ | ||
430 | dm_write_reg(dev, DM_GPR_CTRL, 1); | ||
431 | dm_write_reg(dev, DM_GPR_DATA, 0); | ||
432 | |||
433 | /* receive broadcast packets */ | ||
434 | dm9601_set_multicast(dev->net); | ||
435 | |||
436 | dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
437 | dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
438 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
439 | mii_nway_restart(&dev->mii); | ||
440 | |||
441 | out: | ||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
446 | { | ||
447 | u8 status; | ||
448 | int len; | ||
449 | |||
450 | /* format: | ||
451 | b0: rx status | ||
452 | b1: packet length (incl crc) low | ||
453 | b2: packet length (incl crc) high | ||
454 | b3..n-4: packet data | ||
455 | bn-3..bn: ethernet crc | ||
456 | */ | ||
457 | |||
458 | if (unlikely(skb->len < DM_RX_OVERHEAD)) { | ||
459 | dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | status = skb->data[0]; | ||
464 | len = (skb->data[1] | (skb->data[2] << 8)) - 4; | ||
465 | |||
466 | if (unlikely(status & 0xbf)) { | ||
467 | if (status & 0x01) dev->stats.rx_fifo_errors++; | ||
468 | if (status & 0x02) dev->stats.rx_crc_errors++; | ||
469 | if (status & 0x04) dev->stats.rx_frame_errors++; | ||
470 | if (status & 0x20) dev->stats.rx_missed_errors++; | ||
471 | if (status & 0x90) dev->stats.rx_length_errors++; | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | skb_pull(skb, 3); | ||
476 | skb_trim(skb, len); | ||
477 | |||
478 | return 1; | ||
479 | } | ||
480 | |||
481 | static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
482 | gfp_t flags) | ||
483 | { | ||
484 | int len; | ||
485 | |||
486 | /* format: | ||
487 | b0: packet length low | ||
488 | b1: packet length high | ||
489 | b3..n: packet data | ||
490 | */ | ||
491 | |||
492 | if (skb_headroom(skb) < DM_TX_OVERHEAD) { | ||
493 | struct sk_buff *skb2; | ||
494 | |||
495 | skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); | ||
496 | dev_kfree_skb_any(skb); | ||
497 | skb = skb2; | ||
498 | if (!skb) | ||
499 | return NULL; | ||
500 | } | ||
501 | |||
502 | __skb_push(skb, DM_TX_OVERHEAD); | ||
503 | |||
504 | len = skb->len; | ||
505 | /* usbnet adds padding if length is a multiple of packet size | ||
506 | if so, adjust length value in header */ | ||
507 | if ((len % dev->maxpacket) == 0) | ||
508 | len++; | ||
509 | |||
510 | skb->data[0] = len; | ||
511 | skb->data[1] = len >> 8; | ||
512 | |||
513 | return skb; | ||
514 | } | ||
515 | |||
516 | static void dm9601_status(struct usbnet *dev, struct urb *urb) | ||
517 | { | ||
518 | int link; | ||
519 | u8 *buf; | ||
520 | |||
521 | /* format: | ||
522 | b0: net status | ||
523 | b1: tx status 1 | ||
524 | b2: tx status 2 | ||
525 | b3: rx status | ||
526 | b4: rx overflow | ||
527 | b5: rx count | ||
528 | b6: tx count | ||
529 | b7: gpr | ||
530 | */ | ||
531 | |||
532 | if (urb->actual_length < 8) | ||
533 | return; | ||
534 | |||
535 | buf = urb->transfer_buffer; | ||
536 | |||
537 | link = !!(buf[0] & 0x40); | ||
538 | if (netif_carrier_ok(dev->net) != link) { | ||
539 | if (link) { | ||
540 | netif_carrier_on(dev->net); | ||
541 | usbnet_defer_kevent (dev, EVENT_LINK_RESET); | ||
542 | } | ||
543 | else | ||
544 | netif_carrier_off(dev->net); | ||
545 | devdbg(dev, "Link Status is: %d", link); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | static int dm9601_link_reset(struct usbnet *dev) | ||
550 | { | ||
551 | struct ethtool_cmd ecmd; | ||
552 | |||
553 | mii_check_media(&dev->mii, 1, 1); | ||
554 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
555 | |||
556 | devdbg(dev, "link_reset() speed: %d duplex: %d", | ||
557 | ecmd.speed, ecmd.duplex); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static const struct driver_info dm9601_info = { | ||
563 | .description = "Davicom DM9601 USB Ethernet", | ||
564 | .flags = FLAG_ETHER, | ||
565 | .bind = dm9601_bind, | ||
566 | .rx_fixup = dm9601_rx_fixup, | ||
567 | .tx_fixup = dm9601_tx_fixup, | ||
568 | .status = dm9601_status, | ||
569 | .link_reset = dm9601_link_reset, | ||
570 | .reset = dm9601_link_reset, | ||
571 | }; | ||
572 | |||
573 | static const struct usb_device_id products[] = { | ||
574 | { | ||
575 | USB_DEVICE(0x07aa, 0x9601), /* Corega FEther USB-TXC */ | ||
576 | .driver_info = (unsigned long)&dm9601_info, | ||
577 | }, | ||
578 | { | ||
579 | USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */ | ||
580 | .driver_info = (unsigned long)&dm9601_info, | ||
581 | }, | ||
582 | { | ||
583 | USB_DEVICE(0x0a46, 0x6688), /* ZT6688 USB NIC */ | ||
584 | .driver_info = (unsigned long)&dm9601_info, | ||
585 | }, | ||
586 | { | ||
587 | USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */ | ||
588 | .driver_info = (unsigned long)&dm9601_info, | ||
589 | }, | ||
590 | {}, // END | ||
591 | }; | ||
592 | |||
593 | MODULE_DEVICE_TABLE(usb, products); | ||
594 | |||
595 | static struct usb_driver dm9601_driver = { | ||
596 | .name = "dm9601", | ||
597 | .id_table = products, | ||
598 | .probe = usbnet_probe, | ||
599 | .disconnect = usbnet_disconnect, | ||
600 | .suspend = usbnet_suspend, | ||
601 | .resume = usbnet_resume, | ||
602 | }; | ||
603 | |||
604 | static int __init dm9601_init(void) | ||
605 | { | ||
606 | return usb_register(&dm9601_driver); | ||
607 | } | ||
608 | |||
609 | static void __exit dm9601_exit(void) | ||
610 | { | ||
611 | usb_deregister(&dm9601_driver); | ||
612 | } | ||
613 | |||
614 | module_init(dm9601_init); | ||
615 | module_exit(dm9601_exit); | ||
616 | |||
617 | MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); | ||
618 | MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices"); | ||
619 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c new file mode 100644 index 000000000000..031cf5ca4dbb --- /dev/null +++ b/drivers/net/usb/gl620a.c | |||
@@ -0,0 +1,245 @@ | |||
1 | /* | ||
2 | * GeneSys GL620USB-A based links | ||
3 | * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw> | ||
4 | * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (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, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | // #define DEBUG // error path messages, extra info | ||
22 | // #define VERBOSE // more; success messages | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/ethtool.h> | ||
29 | #include <linux/workqueue.h> | ||
30 | #include <linux/mii.h> | ||
31 | #include <linux/usb.h> | ||
32 | |||
33 | #include "usbnet.h" | ||
34 | |||
35 | |||
36 | /* | ||
37 | * GeneSys GL620USB-A (www.genesyslogic.com.tw) | ||
38 | * | ||
39 | * ... should partially interop with the Win32 driver for this hardware. | ||
40 | * The GeneSys docs imply there's some NDIS issue motivating this framing. | ||
41 | * | ||
42 | * Some info from GeneSys: | ||
43 | * - GL620USB-A is full duplex; GL620USB is only half duplex for bulk. | ||
44 | * (Some cables, like the BAFO-100c, use the half duplex version.) | ||
45 | * - For the full duplex model, the low bit of the version code says | ||
46 | * which side is which ("left/right"). | ||
47 | * - For the half duplex type, a control/interrupt handshake settles | ||
48 | * the transfer direction. (That's disabled here, partially coded.) | ||
49 | * A control URB would block until other side writes an interrupt. | ||
50 | * | ||
51 | * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw> | ||
52 | * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>. | ||
53 | */ | ||
54 | |||
55 | // control msg write command | ||
56 | #define GENELINK_CONNECT_WRITE 0xF0 | ||
57 | // interrupt pipe index | ||
58 | #define GENELINK_INTERRUPT_PIPE 0x03 | ||
59 | // interrupt read buffer size | ||
60 | #define INTERRUPT_BUFSIZE 0x08 | ||
61 | // interrupt pipe interval value | ||
62 | #define GENELINK_INTERRUPT_INTERVAL 0x10 | ||
63 | // max transmit packet number per transmit | ||
64 | #define GL_MAX_TRANSMIT_PACKETS 32 | ||
65 | // max packet length | ||
66 | #define GL_MAX_PACKET_LEN 1514 | ||
67 | // max receive buffer size | ||
68 | #define GL_RCV_BUF_SIZE \ | ||
69 | (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) | ||
70 | |||
71 | struct gl_packet { | ||
72 | __le32 packet_length; | ||
73 | char packet_data [1]; | ||
74 | }; | ||
75 | |||
76 | struct gl_header { | ||
77 | __le32 packet_count; | ||
78 | struct gl_packet packets; | ||
79 | }; | ||
80 | |||
81 | static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
82 | { | ||
83 | struct gl_header *header; | ||
84 | struct gl_packet *packet; | ||
85 | struct sk_buff *gl_skb; | ||
86 | u32 size; | ||
87 | u32 count; | ||
88 | |||
89 | header = (struct gl_header *) skb->data; | ||
90 | |||
91 | // get the packet count of the received skb | ||
92 | count = le32_to_cpu(header->packet_count); | ||
93 | if (count > GL_MAX_TRANSMIT_PACKETS) { | ||
94 | dbg("genelink: invalid received packet count %u", count); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | // set the current packet pointer to the first packet | ||
99 | packet = &header->packets; | ||
100 | |||
101 | // decrement the length for the packet count size 4 bytes | ||
102 | skb_pull(skb, 4); | ||
103 | |||
104 | while (count > 1) { | ||
105 | // get the packet length | ||
106 | size = le32_to_cpu(packet->packet_length); | ||
107 | |||
108 | // this may be a broken packet | ||
109 | if (size > GL_MAX_PACKET_LEN) { | ||
110 | dbg("genelink: invalid rx length %d", size); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | // allocate the skb for the individual packet | ||
115 | gl_skb = alloc_skb(size, GFP_ATOMIC); | ||
116 | if (gl_skb) { | ||
117 | |||
118 | // copy the packet data to the new skb | ||
119 | memcpy(skb_put(gl_skb, size), | ||
120 | packet->packet_data, size); | ||
121 | usbnet_skb_return(dev, gl_skb); | ||
122 | } | ||
123 | |||
124 | // advance to the next packet | ||
125 | packet = (struct gl_packet *)&packet->packet_data[size]; | ||
126 | count--; | ||
127 | |||
128 | // shift the data pointer to the next gl_packet | ||
129 | skb_pull(skb, size + 4); | ||
130 | } | ||
131 | |||
132 | // skip the packet length field 4 bytes | ||
133 | skb_pull(skb, 4); | ||
134 | |||
135 | if (skb->len > GL_MAX_PACKET_LEN) { | ||
136 | dbg("genelink: invalid rx length %d", skb->len); | ||
137 | return 0; | ||
138 | } | ||
139 | return 1; | ||
140 | } | ||
141 | |||
142 | static struct sk_buff * | ||
143 | genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | ||
144 | { | ||
145 | int padlen; | ||
146 | int length = skb->len; | ||
147 | int headroom = skb_headroom(skb); | ||
148 | int tailroom = skb_tailroom(skb); | ||
149 | __le32 *packet_count; | ||
150 | __le32 *packet_len; | ||
151 | |||
152 | // FIXME: magic numbers, bleech | ||
153 | padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; | ||
154 | |||
155 | if ((!skb_cloned(skb)) | ||
156 | && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { | ||
157 | if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { | ||
158 | skb->data = memmove(skb->head + (4 + 4*1), | ||
159 | skb->data, skb->len); | ||
160 | skb_set_tail_pointer(skb, skb->len); | ||
161 | } | ||
162 | } else { | ||
163 | struct sk_buff *skb2; | ||
164 | skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags); | ||
165 | dev_kfree_skb_any(skb); | ||
166 | skb = skb2; | ||
167 | if (!skb) | ||
168 | return NULL; | ||
169 | } | ||
170 | |||
171 | // attach the packet count to the header | ||
172 | packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); | ||
173 | packet_len = packet_count + 1; | ||
174 | |||
175 | *packet_count = cpu_to_le32(1); | ||
176 | *packet_len = cpu_to_le32(length); | ||
177 | |||
178 | // add padding byte | ||
179 | if ((skb->len % dev->maxpacket) == 0) | ||
180 | skb_put(skb, 1); | ||
181 | |||
182 | return skb; | ||
183 | } | ||
184 | |||
185 | static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) | ||
186 | { | ||
187 | dev->hard_mtu = GL_RCV_BUF_SIZE; | ||
188 | dev->net->hard_header_len += 4; | ||
189 | dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in); | ||
190 | dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static const struct driver_info genelink_info = { | ||
195 | .description = "Genesys GeneLink", | ||
196 | .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, | ||
197 | .bind = genelink_bind, | ||
198 | .rx_fixup = genelink_rx_fixup, | ||
199 | .tx_fixup = genelink_tx_fixup, | ||
200 | |||
201 | .in = 1, .out = 2, | ||
202 | |||
203 | #ifdef GENELINK_ACK | ||
204 | .check_connect =genelink_check_connect, | ||
205 | #endif | ||
206 | }; | ||
207 | |||
208 | static const struct usb_device_id products [] = { | ||
209 | |||
210 | { | ||
211 | USB_DEVICE(0x05e3, 0x0502), // GL620USB-A | ||
212 | .driver_info = (unsigned long) &genelink_info, | ||
213 | }, | ||
214 | /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB | ||
215 | * that's half duplex, not currently supported | ||
216 | */ | ||
217 | { }, // END | ||
218 | }; | ||
219 | MODULE_DEVICE_TABLE(usb, products); | ||
220 | |||
221 | static struct usb_driver gl620a_driver = { | ||
222 | .name = "gl620a", | ||
223 | .id_table = products, | ||
224 | .probe = usbnet_probe, | ||
225 | .disconnect = usbnet_disconnect, | ||
226 | .suspend = usbnet_suspend, | ||
227 | .resume = usbnet_resume, | ||
228 | }; | ||
229 | |||
230 | static int __init usbnet_init(void) | ||
231 | { | ||
232 | return usb_register(&gl620a_driver); | ||
233 | } | ||
234 | module_init(usbnet_init); | ||
235 | |||
236 | static void __exit usbnet_exit(void) | ||
237 | { | ||
238 | usb_deregister(&gl620a_driver); | ||
239 | } | ||
240 | module_exit(usbnet_exit); | ||
241 | |||
242 | MODULE_AUTHOR("Jiun-Jie Huang"); | ||
243 | MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables"); | ||
244 | MODULE_LICENSE("GPL"); | ||
245 | |||
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c new file mode 100644 index 000000000000..60d29440f316 --- /dev/null +++ b/drivers/net/usb/kaweth.c | |||
@@ -0,0 +1,1337 @@ | |||
1 | /**************************************************************** | ||
2 | * | ||
3 | * kaweth.c - driver for KL5KUSB101 based USB->Ethernet | ||
4 | * | ||
5 | * (c) 2000 Interlan Communications | ||
6 | * (c) 2000 Stephane Alnet | ||
7 | * (C) 2001 Brad Hards | ||
8 | * (C) 2002 Oliver Neukum | ||
9 | * | ||
10 | * Original author: The Zapman <zapman@interlan.net> | ||
11 | * Inspired by, and much credit goes to Michael Rothwell | ||
12 | * <rothwell@interlan.net> for the test equipment, help, and patience | ||
13 | * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. | ||
14 | * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki | ||
15 | * for providing the firmware and driver resources. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License as | ||
19 | * published by the Free Software Foundation; either version 2, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software Foundation, | ||
29 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
30 | * | ||
31 | ****************************************************************/ | ||
32 | |||
33 | /* TODO: | ||
34 | * Fix in_interrupt() problem | ||
35 | * Develop test procedures for USB net interfaces | ||
36 | * Run test procedures | ||
37 | * Fix bugs from previous two steps | ||
38 | * Snoop other OSs for any tricks we're not doing | ||
39 | * SMP locking | ||
40 | * Reduce arbitrary timeouts | ||
41 | * Smart multicast support | ||
42 | * Temporary MAC change support | ||
43 | * Tunable SOFs parameter - ioctl()? | ||
44 | * Ethernet stats collection | ||
45 | * Code formatting improvements | ||
46 | */ | ||
47 | |||
48 | #include <linux/module.h> | ||
49 | #include <linux/slab.h> | ||
50 | #include <linux/string.h> | ||
51 | #include <linux/init.h> | ||
52 | #include <linux/delay.h> | ||
53 | #include <linux/netdevice.h> | ||
54 | #include <linux/etherdevice.h> | ||
55 | #include <linux/usb.h> | ||
56 | #include <linux/types.h> | ||
57 | #include <linux/ethtool.h> | ||
58 | #include <linux/dma-mapping.h> | ||
59 | #include <linux/wait.h> | ||
60 | #include <asm/uaccess.h> | ||
61 | #include <asm/semaphore.h> | ||
62 | #include <asm/byteorder.h> | ||
63 | |||
64 | #undef DEBUG | ||
65 | |||
66 | #include "kawethfw.h" | ||
67 | |||
68 | #define KAWETH_MTU 1514 | ||
69 | #define KAWETH_BUF_SIZE 1664 | ||
70 | #define KAWETH_TX_TIMEOUT (5 * HZ) | ||
71 | #define KAWETH_SCRATCH_SIZE 32 | ||
72 | #define KAWETH_FIRMWARE_BUF_SIZE 4096 | ||
73 | #define KAWETH_CONTROL_TIMEOUT (30 * HZ) | ||
74 | |||
75 | #define KAWETH_STATUS_BROKEN 0x0000001 | ||
76 | #define KAWETH_STATUS_CLOSING 0x0000002 | ||
77 | #define KAWETH_STATUS_SUSPENDING 0x0000004 | ||
78 | |||
79 | #define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) | ||
80 | |||
81 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 | ||
82 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 | ||
83 | #define KAWETH_PACKET_FILTER_DIRECTED 0x04 | ||
84 | #define KAWETH_PACKET_FILTER_BROADCAST 0x08 | ||
85 | #define KAWETH_PACKET_FILTER_MULTICAST 0x10 | ||
86 | |||
87 | /* Table 7 */ | ||
88 | #define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 | ||
89 | #define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 | ||
90 | #define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 | ||
91 | #define KAWETH_COMMAND_STATISTICS 0x03 | ||
92 | #define KAWETH_COMMAND_SET_TEMP_MAC 0x06 | ||
93 | #define KAWETH_COMMAND_GET_TEMP_MAC 0x07 | ||
94 | #define KAWETH_COMMAND_SET_URB_SIZE 0x08 | ||
95 | #define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 | ||
96 | #define KAWETH_COMMAND_SCAN 0xFF | ||
97 | |||
98 | #define KAWETH_SOFS_TO_WAIT 0x05 | ||
99 | |||
100 | #define INTBUFFERSIZE 4 | ||
101 | |||
102 | #define STATE_OFFSET 0 | ||
103 | #define STATE_MASK 0x40 | ||
104 | #define STATE_SHIFT 5 | ||
105 | |||
106 | #define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) | ||
107 | |||
108 | |||
109 | MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); | ||
110 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); | ||
111 | MODULE_LICENSE("GPL"); | ||
112 | |||
113 | static const char driver_name[] = "kaweth"; | ||
114 | |||
115 | static int kaweth_probe( | ||
116 | struct usb_interface *intf, | ||
117 | const struct usb_device_id *id /* from id_table */ | ||
118 | ); | ||
119 | static void kaweth_disconnect(struct usb_interface *intf); | ||
120 | static int kaweth_internal_control_msg(struct usb_device *usb_dev, | ||
121 | unsigned int pipe, | ||
122 | struct usb_ctrlrequest *cmd, void *data, | ||
123 | int len, int timeout); | ||
124 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); | ||
125 | static int kaweth_resume(struct usb_interface *intf); | ||
126 | |||
127 | /**************************************************************** | ||
128 | * usb_device_id | ||
129 | ****************************************************************/ | ||
130 | static struct usb_device_id usb_klsi_table[] = { | ||
131 | { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ | ||
132 | { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ | ||
133 | { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ | ||
134 | { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */ | ||
135 | { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ | ||
136 | { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ | ||
137 | { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ | ||
138 | { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ | ||
139 | { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ | ||
140 | { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ | ||
141 | { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ | ||
142 | { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ | ||
143 | { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ | ||
144 | { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ | ||
145 | { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ | ||
146 | { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ | ||
147 | { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ | ||
148 | { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ | ||
149 | { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ | ||
150 | { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ | ||
151 | { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ | ||
152 | { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ | ||
153 | { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ | ||
154 | { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ | ||
155 | { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ | ||
156 | { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ | ||
157 | { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ | ||
158 | { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */ | ||
159 | { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */ | ||
160 | { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ | ||
161 | { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ | ||
162 | { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ | ||
163 | { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */ | ||
164 | { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ | ||
165 | {} /* Null terminator */ | ||
166 | }; | ||
167 | |||
168 | MODULE_DEVICE_TABLE (usb, usb_klsi_table); | ||
169 | |||
170 | /**************************************************************** | ||
171 | * kaweth_driver | ||
172 | ****************************************************************/ | ||
173 | static struct usb_driver kaweth_driver = { | ||
174 | .name = driver_name, | ||
175 | .probe = kaweth_probe, | ||
176 | .disconnect = kaweth_disconnect, | ||
177 | .suspend = kaweth_suspend, | ||
178 | .resume = kaweth_resume, | ||
179 | .id_table = usb_klsi_table, | ||
180 | .supports_autosuspend = 1, | ||
181 | }; | ||
182 | |||
183 | typedef __u8 eth_addr_t[6]; | ||
184 | |||
185 | /**************************************************************** | ||
186 | * usb_eth_dev | ||
187 | ****************************************************************/ | ||
188 | struct usb_eth_dev { | ||
189 | char *name; | ||
190 | __u16 vendor; | ||
191 | __u16 device; | ||
192 | void *pdata; | ||
193 | }; | ||
194 | |||
195 | /**************************************************************** | ||
196 | * kaweth_ethernet_configuration | ||
197 | * Refer Table 8 | ||
198 | ****************************************************************/ | ||
199 | struct kaweth_ethernet_configuration | ||
200 | { | ||
201 | __u8 size; | ||
202 | __u8 reserved1; | ||
203 | __u8 reserved2; | ||
204 | eth_addr_t hw_addr; | ||
205 | __u32 statistics_mask; | ||
206 | __le16 segment_size; | ||
207 | __u16 max_multicast_filters; | ||
208 | __u8 reserved3; | ||
209 | } __attribute__ ((packed)); | ||
210 | |||
211 | /**************************************************************** | ||
212 | * kaweth_device | ||
213 | ****************************************************************/ | ||
214 | struct kaweth_device | ||
215 | { | ||
216 | spinlock_t device_lock; | ||
217 | |||
218 | __u32 status; | ||
219 | int end; | ||
220 | int suspend_lowmem_rx; | ||
221 | int suspend_lowmem_ctrl; | ||
222 | int linkstate; | ||
223 | int opened; | ||
224 | struct delayed_work lowmem_work; | ||
225 | |||
226 | struct usb_device *dev; | ||
227 | struct usb_interface *intf; | ||
228 | struct net_device *net; | ||
229 | wait_queue_head_t term_wait; | ||
230 | |||
231 | struct urb *rx_urb; | ||
232 | struct urb *tx_urb; | ||
233 | struct urb *irq_urb; | ||
234 | |||
235 | dma_addr_t intbufferhandle; | ||
236 | __u8 *intbuffer; | ||
237 | dma_addr_t rxbufferhandle; | ||
238 | __u8 *rx_buf; | ||
239 | |||
240 | |||
241 | struct sk_buff *tx_skb; | ||
242 | |||
243 | __u8 *firmware_buf; | ||
244 | __u8 scratch[KAWETH_SCRATCH_SIZE]; | ||
245 | __u16 packet_filter_bitmap; | ||
246 | |||
247 | struct kaweth_ethernet_configuration configuration; | ||
248 | |||
249 | struct net_device_stats stats; | ||
250 | }; | ||
251 | |||
252 | |||
253 | /**************************************************************** | ||
254 | * kaweth_control | ||
255 | ****************************************************************/ | ||
256 | static int kaweth_control(struct kaweth_device *kaweth, | ||
257 | unsigned int pipe, | ||
258 | __u8 request, | ||
259 | __u8 requesttype, | ||
260 | __u16 value, | ||
261 | __u16 index, | ||
262 | void *data, | ||
263 | __u16 size, | ||
264 | int timeout) | ||
265 | { | ||
266 | struct usb_ctrlrequest *dr; | ||
267 | |||
268 | dbg("kaweth_control()"); | ||
269 | |||
270 | if(in_interrupt()) { | ||
271 | dbg("in_interrupt()"); | ||
272 | return -EBUSY; | ||
273 | } | ||
274 | |||
275 | dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
276 | |||
277 | if (!dr) { | ||
278 | dbg("kmalloc() failed"); | ||
279 | return -ENOMEM; | ||
280 | } | ||
281 | |||
282 | dr->bRequestType= requesttype; | ||
283 | dr->bRequest = request; | ||
284 | dr->wValue = cpu_to_le16p(&value); | ||
285 | dr->wIndex = cpu_to_le16p(&index); | ||
286 | dr->wLength = cpu_to_le16p(&size); | ||
287 | |||
288 | return kaweth_internal_control_msg(kaweth->dev, | ||
289 | pipe, | ||
290 | dr, | ||
291 | data, | ||
292 | size, | ||
293 | timeout); | ||
294 | } | ||
295 | |||
296 | /**************************************************************** | ||
297 | * kaweth_read_configuration | ||
298 | ****************************************************************/ | ||
299 | static int kaweth_read_configuration(struct kaweth_device *kaweth) | ||
300 | { | ||
301 | int retval; | ||
302 | |||
303 | dbg("Reading kaweth configuration"); | ||
304 | |||
305 | retval = kaweth_control(kaweth, | ||
306 | usb_rcvctrlpipe(kaweth->dev, 0), | ||
307 | KAWETH_COMMAND_GET_ETHERNET_DESC, | ||
308 | USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, | ||
309 | 0, | ||
310 | 0, | ||
311 | (void *)&kaweth->configuration, | ||
312 | sizeof(kaweth->configuration), | ||
313 | KAWETH_CONTROL_TIMEOUT); | ||
314 | |||
315 | return retval; | ||
316 | } | ||
317 | |||
318 | /**************************************************************** | ||
319 | * kaweth_set_urb_size | ||
320 | ****************************************************************/ | ||
321 | static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) | ||
322 | { | ||
323 | int retval; | ||
324 | |||
325 | dbg("Setting URB size to %d", (unsigned)urb_size); | ||
326 | |||
327 | retval = kaweth_control(kaweth, | ||
328 | usb_sndctrlpipe(kaweth->dev, 0), | ||
329 | KAWETH_COMMAND_SET_URB_SIZE, | ||
330 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
331 | urb_size, | ||
332 | 0, | ||
333 | (void *)&kaweth->scratch, | ||
334 | 0, | ||
335 | KAWETH_CONTROL_TIMEOUT); | ||
336 | |||
337 | return retval; | ||
338 | } | ||
339 | |||
340 | /**************************************************************** | ||
341 | * kaweth_set_sofs_wait | ||
342 | ****************************************************************/ | ||
343 | static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) | ||
344 | { | ||
345 | int retval; | ||
346 | |||
347 | dbg("Set SOFS wait to %d", (unsigned)sofs_wait); | ||
348 | |||
349 | retval = kaweth_control(kaweth, | ||
350 | usb_sndctrlpipe(kaweth->dev, 0), | ||
351 | KAWETH_COMMAND_SET_SOFS_WAIT, | ||
352 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
353 | sofs_wait, | ||
354 | 0, | ||
355 | (void *)&kaweth->scratch, | ||
356 | 0, | ||
357 | KAWETH_CONTROL_TIMEOUT); | ||
358 | |||
359 | return retval; | ||
360 | } | ||
361 | |||
362 | /**************************************************************** | ||
363 | * kaweth_set_receive_filter | ||
364 | ****************************************************************/ | ||
365 | static int kaweth_set_receive_filter(struct kaweth_device *kaweth, | ||
366 | __u16 receive_filter) | ||
367 | { | ||
368 | int retval; | ||
369 | |||
370 | dbg("Set receive filter to %d", (unsigned)receive_filter); | ||
371 | |||
372 | retval = kaweth_control(kaweth, | ||
373 | usb_sndctrlpipe(kaweth->dev, 0), | ||
374 | KAWETH_COMMAND_SET_PACKET_FILTER, | ||
375 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
376 | receive_filter, | ||
377 | 0, | ||
378 | (void *)&kaweth->scratch, | ||
379 | 0, | ||
380 | KAWETH_CONTROL_TIMEOUT); | ||
381 | |||
382 | return retval; | ||
383 | } | ||
384 | |||
385 | /**************************************************************** | ||
386 | * kaweth_download_firmware | ||
387 | ****************************************************************/ | ||
388 | static int kaweth_download_firmware(struct kaweth_device *kaweth, | ||
389 | __u8 *data, | ||
390 | __u16 data_len, | ||
391 | __u8 interrupt, | ||
392 | __u8 type) | ||
393 | { | ||
394 | if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { | ||
395 | err("Firmware too big: %d", data_len); | ||
396 | return -ENOSPC; | ||
397 | } | ||
398 | |||
399 | memcpy(kaweth->firmware_buf, data, data_len); | ||
400 | |||
401 | kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; | ||
402 | kaweth->firmware_buf[3] = data_len >> 8; | ||
403 | kaweth->firmware_buf[4] = type; | ||
404 | kaweth->firmware_buf[5] = interrupt; | ||
405 | |||
406 | dbg("High: %i, Low:%i", kaweth->firmware_buf[3], | ||
407 | kaweth->firmware_buf[2]); | ||
408 | |||
409 | dbg("Downloading firmware at %p to kaweth device at %p", | ||
410 | data, | ||
411 | kaweth); | ||
412 | dbg("Firmware length: %d", data_len); | ||
413 | |||
414 | return kaweth_control(kaweth, | ||
415 | usb_sndctrlpipe(kaweth->dev, 0), | ||
416 | KAWETH_COMMAND_SCAN, | ||
417 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
418 | 0, | ||
419 | 0, | ||
420 | (void *)kaweth->firmware_buf, | ||
421 | data_len, | ||
422 | KAWETH_CONTROL_TIMEOUT); | ||
423 | } | ||
424 | |||
425 | /**************************************************************** | ||
426 | * kaweth_trigger_firmware | ||
427 | ****************************************************************/ | ||
428 | static int kaweth_trigger_firmware(struct kaweth_device *kaweth, | ||
429 | __u8 interrupt) | ||
430 | { | ||
431 | kaweth->firmware_buf[0] = 0xB6; | ||
432 | kaweth->firmware_buf[1] = 0xC3; | ||
433 | kaweth->firmware_buf[2] = 0x01; | ||
434 | kaweth->firmware_buf[3] = 0x00; | ||
435 | kaweth->firmware_buf[4] = 0x06; | ||
436 | kaweth->firmware_buf[5] = interrupt; | ||
437 | kaweth->firmware_buf[6] = 0x00; | ||
438 | kaweth->firmware_buf[7] = 0x00; | ||
439 | |||
440 | dbg("Triggering firmware"); | ||
441 | |||
442 | return kaweth_control(kaweth, | ||
443 | usb_sndctrlpipe(kaweth->dev, 0), | ||
444 | KAWETH_COMMAND_SCAN, | ||
445 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
446 | 0, | ||
447 | 0, | ||
448 | (void *)kaweth->firmware_buf, | ||
449 | 8, | ||
450 | KAWETH_CONTROL_TIMEOUT); | ||
451 | } | ||
452 | |||
453 | /**************************************************************** | ||
454 | * kaweth_reset | ||
455 | ****************************************************************/ | ||
456 | static int kaweth_reset(struct kaweth_device *kaweth) | ||
457 | { | ||
458 | int result; | ||
459 | |||
460 | dbg("kaweth_reset(%p)", kaweth); | ||
461 | result = kaweth_control(kaweth, | ||
462 | usb_sndctrlpipe(kaweth->dev, 0), | ||
463 | USB_REQ_SET_CONFIGURATION, | ||
464 | 0, | ||
465 | kaweth->dev->config[0].desc.bConfigurationValue, | ||
466 | 0, | ||
467 | NULL, | ||
468 | 0, | ||
469 | KAWETH_CONTROL_TIMEOUT); | ||
470 | |||
471 | mdelay(10); | ||
472 | |||
473 | dbg("kaweth_reset() returns %d.",result); | ||
474 | |||
475 | return result; | ||
476 | } | ||
477 | |||
478 | static void kaweth_usb_receive(struct urb *); | ||
479 | static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); | ||
480 | |||
481 | /**************************************************************** | ||
482 | int_callback | ||
483 | *****************************************************************/ | ||
484 | |||
485 | static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) | ||
486 | { | ||
487 | int status; | ||
488 | |||
489 | status = usb_submit_urb (kaweth->irq_urb, mf); | ||
490 | if (unlikely(status == -ENOMEM)) { | ||
491 | kaweth->suspend_lowmem_ctrl = 1; | ||
492 | schedule_delayed_work(&kaweth->lowmem_work, HZ/4); | ||
493 | } else { | ||
494 | kaweth->suspend_lowmem_ctrl = 0; | ||
495 | } | ||
496 | |||
497 | if (status) | ||
498 | err ("can't resubmit intr, %s-%s, status %d", | ||
499 | kaweth->dev->bus->bus_name, | ||
500 | kaweth->dev->devpath, status); | ||
501 | } | ||
502 | |||
503 | static void int_callback(struct urb *u) | ||
504 | { | ||
505 | struct kaweth_device *kaweth = u->context; | ||
506 | int act_state; | ||
507 | |||
508 | switch (u->status) { | ||
509 | case 0: /* success */ | ||
510 | break; | ||
511 | case -ECONNRESET: /* unlink */ | ||
512 | case -ENOENT: | ||
513 | case -ESHUTDOWN: | ||
514 | return; | ||
515 | /* -EPIPE: should clear the halt */ | ||
516 | default: /* error */ | ||
517 | goto resubmit; | ||
518 | } | ||
519 | |||
520 | /* we check the link state to report changes */ | ||
521 | if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { | ||
522 | if (act_state) | ||
523 | netif_carrier_on(kaweth->net); | ||
524 | else | ||
525 | netif_carrier_off(kaweth->net); | ||
526 | |||
527 | kaweth->linkstate = act_state; | ||
528 | } | ||
529 | resubmit: | ||
530 | kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); | ||
531 | } | ||
532 | |||
533 | static void kaweth_resubmit_tl(struct work_struct *work) | ||
534 | { | ||
535 | struct kaweth_device *kaweth = | ||
536 | container_of(work, struct kaweth_device, lowmem_work.work); | ||
537 | |||
538 | if (IS_BLOCKED(kaweth->status)) | ||
539 | return; | ||
540 | |||
541 | if (kaweth->suspend_lowmem_rx) | ||
542 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | ||
543 | |||
544 | if (kaweth->suspend_lowmem_ctrl) | ||
545 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | ||
546 | } | ||
547 | |||
548 | |||
549 | /**************************************************************** | ||
550 | * kaweth_resubmit_rx_urb | ||
551 | ****************************************************************/ | ||
552 | static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, | ||
553 | gfp_t mem_flags) | ||
554 | { | ||
555 | int result; | ||
556 | |||
557 | usb_fill_bulk_urb(kaweth->rx_urb, | ||
558 | kaweth->dev, | ||
559 | usb_rcvbulkpipe(kaweth->dev, 1), | ||
560 | kaweth->rx_buf, | ||
561 | KAWETH_BUF_SIZE, | ||
562 | kaweth_usb_receive, | ||
563 | kaweth); | ||
564 | kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
565 | kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; | ||
566 | |||
567 | if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { | ||
568 | if (result == -ENOMEM) { | ||
569 | kaweth->suspend_lowmem_rx = 1; | ||
570 | schedule_delayed_work(&kaweth->lowmem_work, HZ/4); | ||
571 | } | ||
572 | err("resubmitting rx_urb %d failed", result); | ||
573 | } else { | ||
574 | kaweth->suspend_lowmem_rx = 0; | ||
575 | } | ||
576 | |||
577 | return result; | ||
578 | } | ||
579 | |||
580 | static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); | ||
581 | |||
582 | /**************************************************************** | ||
583 | * kaweth_usb_receive | ||
584 | ****************************************************************/ | ||
585 | static void kaweth_usb_receive(struct urb *urb) | ||
586 | { | ||
587 | struct kaweth_device *kaweth = urb->context; | ||
588 | struct net_device *net = kaweth->net; | ||
589 | |||
590 | int count = urb->actual_length; | ||
591 | int count2 = urb->transfer_buffer_length; | ||
592 | |||
593 | __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); | ||
594 | |||
595 | struct sk_buff *skb; | ||
596 | |||
597 | if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) | ||
598 | /* we are killed - set a flag and wake the disconnect handler */ | ||
599 | { | ||
600 | kaweth->end = 1; | ||
601 | wake_up(&kaweth->term_wait); | ||
602 | return; | ||
603 | } | ||
604 | |||
605 | spin_lock(&kaweth->device_lock); | ||
606 | if (IS_BLOCKED(kaweth->status)) { | ||
607 | spin_unlock(&kaweth->device_lock); | ||
608 | return; | ||
609 | } | ||
610 | spin_unlock(&kaweth->device_lock); | ||
611 | |||
612 | if(urb->status && urb->status != -EREMOTEIO && count != 1) { | ||
613 | err("%s RX status: %d count: %d packet_len: %d", | ||
614 | net->name, | ||
615 | urb->status, | ||
616 | count, | ||
617 | (int)pkt_len); | ||
618 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | ||
619 | return; | ||
620 | } | ||
621 | |||
622 | if(kaweth->net && (count > 2)) { | ||
623 | if(pkt_len > (count - 2)) { | ||
624 | err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); | ||
625 | err("Packet len & 2047: %x", pkt_len & 2047); | ||
626 | err("Count 2: %x", count2); | ||
627 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | ||
628 | return; | ||
629 | } | ||
630 | |||
631 | if(!(skb = dev_alloc_skb(pkt_len+2))) { | ||
632 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ | ||
637 | |||
638 | eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0); | ||
639 | |||
640 | skb_put(skb, pkt_len); | ||
641 | |||
642 | skb->protocol = eth_type_trans(skb, net); | ||
643 | |||
644 | netif_rx(skb); | ||
645 | |||
646 | kaweth->stats.rx_packets++; | ||
647 | kaweth->stats.rx_bytes += pkt_len; | ||
648 | } | ||
649 | |||
650 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | ||
651 | } | ||
652 | |||
653 | /**************************************************************** | ||
654 | * kaweth_open | ||
655 | ****************************************************************/ | ||
656 | static int kaweth_open(struct net_device *net) | ||
657 | { | ||
658 | struct kaweth_device *kaweth = netdev_priv(net); | ||
659 | int res; | ||
660 | |||
661 | dbg("Opening network device."); | ||
662 | |||
663 | res = usb_autopm_get_interface(kaweth->intf); | ||
664 | if (res) { | ||
665 | err("Interface cannot be resumed."); | ||
666 | return -EIO; | ||
667 | } | ||
668 | res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); | ||
669 | if (res) | ||
670 | goto err_out; | ||
671 | |||
672 | usb_fill_int_urb( | ||
673 | kaweth->irq_urb, | ||
674 | kaweth->dev, | ||
675 | usb_rcvintpipe(kaweth->dev, 3), | ||
676 | kaweth->intbuffer, | ||
677 | INTBUFFERSIZE, | ||
678 | int_callback, | ||
679 | kaweth, | ||
680 | 250); /* overriding the descriptor */ | ||
681 | kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; | ||
682 | kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
683 | |||
684 | res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); | ||
685 | if (res) { | ||
686 | usb_kill_urb(kaweth->rx_urb); | ||
687 | goto err_out; | ||
688 | } | ||
689 | kaweth->opened = 1; | ||
690 | |||
691 | netif_start_queue(net); | ||
692 | |||
693 | kaweth_async_set_rx_mode(kaweth); | ||
694 | return 0; | ||
695 | |||
696 | err_out: | ||
697 | usb_autopm_enable(kaweth->intf); | ||
698 | return -EIO; | ||
699 | } | ||
700 | |||
701 | /**************************************************************** | ||
702 | * kaweth_kill_urbs | ||
703 | ****************************************************************/ | ||
704 | static void kaweth_kill_urbs(struct kaweth_device *kaweth) | ||
705 | { | ||
706 | usb_kill_urb(kaweth->irq_urb); | ||
707 | usb_kill_urb(kaweth->rx_urb); | ||
708 | usb_kill_urb(kaweth->tx_urb); | ||
709 | |||
710 | flush_scheduled_work(); | ||
711 | |||
712 | /* a scheduled work may have resubmitted, | ||
713 | we hit them again */ | ||
714 | usb_kill_urb(kaweth->irq_urb); | ||
715 | usb_kill_urb(kaweth->rx_urb); | ||
716 | } | ||
717 | |||
718 | /**************************************************************** | ||
719 | * kaweth_close | ||
720 | ****************************************************************/ | ||
721 | static int kaweth_close(struct net_device *net) | ||
722 | { | ||
723 | struct kaweth_device *kaweth = netdev_priv(net); | ||
724 | |||
725 | netif_stop_queue(net); | ||
726 | kaweth->opened = 0; | ||
727 | |||
728 | kaweth->status |= KAWETH_STATUS_CLOSING; | ||
729 | |||
730 | kaweth_kill_urbs(kaweth); | ||
731 | |||
732 | kaweth->status &= ~KAWETH_STATUS_CLOSING; | ||
733 | |||
734 | usb_autopm_enable(kaweth->intf); | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
740 | { | ||
741 | struct kaweth_device *kaweth = netdev_priv(dev); | ||
742 | |||
743 | strlcpy(info->driver, driver_name, sizeof(info->driver)); | ||
744 | usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); | ||
745 | } | ||
746 | |||
747 | static u32 kaweth_get_link(struct net_device *dev) | ||
748 | { | ||
749 | struct kaweth_device *kaweth = netdev_priv(dev); | ||
750 | |||
751 | return kaweth->linkstate; | ||
752 | } | ||
753 | |||
754 | static struct ethtool_ops ops = { | ||
755 | .get_drvinfo = kaweth_get_drvinfo, | ||
756 | .get_link = kaweth_get_link | ||
757 | }; | ||
758 | |||
759 | /**************************************************************** | ||
760 | * kaweth_usb_transmit_complete | ||
761 | ****************************************************************/ | ||
762 | static void kaweth_usb_transmit_complete(struct urb *urb) | ||
763 | { | ||
764 | struct kaweth_device *kaweth = urb->context; | ||
765 | struct sk_buff *skb = kaweth->tx_skb; | ||
766 | |||
767 | if (unlikely(urb->status != 0)) | ||
768 | if (urb->status != -ENOENT) | ||
769 | dbg("%s: TX status %d.", kaweth->net->name, urb->status); | ||
770 | |||
771 | netif_wake_queue(kaweth->net); | ||
772 | dev_kfree_skb_irq(skb); | ||
773 | } | ||
774 | |||
775 | /**************************************************************** | ||
776 | * kaweth_start_xmit | ||
777 | ****************************************************************/ | ||
778 | static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) | ||
779 | { | ||
780 | struct kaweth_device *kaweth = netdev_priv(net); | ||
781 | __le16 *private_header; | ||
782 | |||
783 | int res; | ||
784 | |||
785 | spin_lock(&kaweth->device_lock); | ||
786 | |||
787 | kaweth_async_set_rx_mode(kaweth); | ||
788 | netif_stop_queue(net); | ||
789 | if (IS_BLOCKED(kaweth->status)) { | ||
790 | goto skip; | ||
791 | } | ||
792 | |||
793 | /* We now decide whether we can put our special header into the sk_buff */ | ||
794 | if (skb_cloned(skb) || skb_headroom(skb) < 2) { | ||
795 | /* no such luck - we make our own */ | ||
796 | struct sk_buff *copied_skb; | ||
797 | copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC); | ||
798 | dev_kfree_skb_irq(skb); | ||
799 | skb = copied_skb; | ||
800 | if (!copied_skb) { | ||
801 | kaweth->stats.tx_errors++; | ||
802 | netif_start_queue(net); | ||
803 | spin_unlock(&kaweth->device_lock); | ||
804 | return 0; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | private_header = (__le16 *)__skb_push(skb, 2); | ||
809 | *private_header = cpu_to_le16(skb->len-2); | ||
810 | kaweth->tx_skb = skb; | ||
811 | |||
812 | usb_fill_bulk_urb(kaweth->tx_urb, | ||
813 | kaweth->dev, | ||
814 | usb_sndbulkpipe(kaweth->dev, 2), | ||
815 | private_header, | ||
816 | skb->len, | ||
817 | kaweth_usb_transmit_complete, | ||
818 | kaweth); | ||
819 | kaweth->end = 0; | ||
820 | |||
821 | if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) | ||
822 | { | ||
823 | warn("kaweth failed tx_urb %d", res); | ||
824 | skip: | ||
825 | kaweth->stats.tx_errors++; | ||
826 | |||
827 | netif_start_queue(net); | ||
828 | dev_kfree_skb_irq(skb); | ||
829 | } | ||
830 | else | ||
831 | { | ||
832 | kaweth->stats.tx_packets++; | ||
833 | kaweth->stats.tx_bytes += skb->len; | ||
834 | net->trans_start = jiffies; | ||
835 | } | ||
836 | |||
837 | spin_unlock(&kaweth->device_lock); | ||
838 | |||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | /**************************************************************** | ||
843 | * kaweth_set_rx_mode | ||
844 | ****************************************************************/ | ||
845 | static void kaweth_set_rx_mode(struct net_device *net) | ||
846 | { | ||
847 | struct kaweth_device *kaweth = netdev_priv(net); | ||
848 | |||
849 | __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | | ||
850 | KAWETH_PACKET_FILTER_BROADCAST | | ||
851 | KAWETH_PACKET_FILTER_MULTICAST; | ||
852 | |||
853 | dbg("Setting Rx mode to %d", packet_filter_bitmap); | ||
854 | |||
855 | netif_stop_queue(net); | ||
856 | |||
857 | if (net->flags & IFF_PROMISC) { | ||
858 | packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; | ||
859 | } | ||
860 | else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { | ||
861 | packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; | ||
862 | } | ||
863 | |||
864 | kaweth->packet_filter_bitmap = packet_filter_bitmap; | ||
865 | netif_wake_queue(net); | ||
866 | } | ||
867 | |||
868 | /**************************************************************** | ||
869 | * kaweth_async_set_rx_mode | ||
870 | ****************************************************************/ | ||
871 | static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) | ||
872 | { | ||
873 | __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; | ||
874 | kaweth->packet_filter_bitmap = 0; | ||
875 | if (packet_filter_bitmap == 0) | ||
876 | return; | ||
877 | |||
878 | { | ||
879 | int result; | ||
880 | result = kaweth_control(kaweth, | ||
881 | usb_sndctrlpipe(kaweth->dev, 0), | ||
882 | KAWETH_COMMAND_SET_PACKET_FILTER, | ||
883 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
884 | packet_filter_bitmap, | ||
885 | 0, | ||
886 | (void *)&kaweth->scratch, | ||
887 | 0, | ||
888 | KAWETH_CONTROL_TIMEOUT); | ||
889 | |||
890 | if(result < 0) { | ||
891 | err("Failed to set Rx mode: %d", result); | ||
892 | } | ||
893 | else { | ||
894 | dbg("Set Rx mode to %d", packet_filter_bitmap); | ||
895 | } | ||
896 | } | ||
897 | } | ||
898 | |||
899 | /**************************************************************** | ||
900 | * kaweth_netdev_stats | ||
901 | ****************************************************************/ | ||
902 | static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev) | ||
903 | { | ||
904 | struct kaweth_device *kaweth = netdev_priv(dev); | ||
905 | return &kaweth->stats; | ||
906 | } | ||
907 | |||
908 | /**************************************************************** | ||
909 | * kaweth_tx_timeout | ||
910 | ****************************************************************/ | ||
911 | static void kaweth_tx_timeout(struct net_device *net) | ||
912 | { | ||
913 | struct kaweth_device *kaweth = netdev_priv(net); | ||
914 | |||
915 | warn("%s: Tx timed out. Resetting.", net->name); | ||
916 | kaweth->stats.tx_errors++; | ||
917 | net->trans_start = jiffies; | ||
918 | |||
919 | usb_unlink_urb(kaweth->tx_urb); | ||
920 | } | ||
921 | |||
922 | /**************************************************************** | ||
923 | * kaweth_suspend | ||
924 | ****************************************************************/ | ||
925 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) | ||
926 | { | ||
927 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
928 | unsigned long flags; | ||
929 | |||
930 | dbg("Suspending device"); | ||
931 | spin_lock_irqsave(&kaweth->device_lock, flags); | ||
932 | kaweth->status |= KAWETH_STATUS_SUSPENDING; | ||
933 | spin_unlock_irqrestore(&kaweth->device_lock, flags); | ||
934 | |||
935 | kaweth_kill_urbs(kaweth); | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | /**************************************************************** | ||
940 | * kaweth_resume | ||
941 | ****************************************************************/ | ||
942 | static int kaweth_resume(struct usb_interface *intf) | ||
943 | { | ||
944 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
945 | unsigned long flags; | ||
946 | |||
947 | dbg("Resuming device"); | ||
948 | spin_lock_irqsave(&kaweth->device_lock, flags); | ||
949 | kaweth->status &= ~KAWETH_STATUS_SUSPENDING; | ||
950 | spin_unlock_irqrestore(&kaweth->device_lock, flags); | ||
951 | |||
952 | if (!kaweth->opened) | ||
953 | return 0; | ||
954 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | ||
955 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | /**************************************************************** | ||
961 | * kaweth_probe | ||
962 | ****************************************************************/ | ||
963 | static int kaweth_probe( | ||
964 | struct usb_interface *intf, | ||
965 | const struct usb_device_id *id /* from id_table */ | ||
966 | ) | ||
967 | { | ||
968 | struct usb_device *dev = interface_to_usbdev(intf); | ||
969 | struct kaweth_device *kaweth; | ||
970 | struct net_device *netdev; | ||
971 | const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
972 | int result = 0; | ||
973 | |||
974 | dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", | ||
975 | dev->devnum, | ||
976 | le16_to_cpu(dev->descriptor.idVendor), | ||
977 | le16_to_cpu(dev->descriptor.idProduct), | ||
978 | le16_to_cpu(dev->descriptor.bcdDevice)); | ||
979 | |||
980 | dbg("Device at %p", dev); | ||
981 | |||
982 | dbg("Descriptor length: %x type: %x", | ||
983 | (int)dev->descriptor.bLength, | ||
984 | (int)dev->descriptor.bDescriptorType); | ||
985 | |||
986 | netdev = alloc_etherdev(sizeof(*kaweth)); | ||
987 | if (!netdev) | ||
988 | return -ENOMEM; | ||
989 | |||
990 | kaweth = netdev_priv(netdev); | ||
991 | kaweth->dev = dev; | ||
992 | kaweth->net = netdev; | ||
993 | |||
994 | spin_lock_init(&kaweth->device_lock); | ||
995 | init_waitqueue_head(&kaweth->term_wait); | ||
996 | |||
997 | dbg("Resetting."); | ||
998 | |||
999 | kaweth_reset(kaweth); | ||
1000 | |||
1001 | /* | ||
1002 | * If high byte of bcdDevice is nonzero, firmware is already | ||
1003 | * downloaded. Don't try to do it again, or we'll hang the device. | ||
1004 | */ | ||
1005 | |||
1006 | if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { | ||
1007 | info("Firmware present in device."); | ||
1008 | } else { | ||
1009 | /* Download the firmware */ | ||
1010 | info("Downloading firmware..."); | ||
1011 | kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); | ||
1012 | if ((result = kaweth_download_firmware(kaweth, | ||
1013 | kaweth_new_code, | ||
1014 | len_kaweth_new_code, | ||
1015 | 100, | ||
1016 | 2)) < 0) { | ||
1017 | err("Error downloading firmware (%d)", result); | ||
1018 | goto err_fw; | ||
1019 | } | ||
1020 | |||
1021 | if ((result = kaweth_download_firmware(kaweth, | ||
1022 | kaweth_new_code_fix, | ||
1023 | len_kaweth_new_code_fix, | ||
1024 | 100, | ||
1025 | 3)) < 0) { | ||
1026 | err("Error downloading firmware fix (%d)", result); | ||
1027 | goto err_fw; | ||
1028 | } | ||
1029 | |||
1030 | if ((result = kaweth_download_firmware(kaweth, | ||
1031 | kaweth_trigger_code, | ||
1032 | len_kaweth_trigger_code, | ||
1033 | 126, | ||
1034 | 2)) < 0) { | ||
1035 | err("Error downloading trigger code (%d)", result); | ||
1036 | goto err_fw; | ||
1037 | |||
1038 | } | ||
1039 | |||
1040 | if ((result = kaweth_download_firmware(kaweth, | ||
1041 | kaweth_trigger_code_fix, | ||
1042 | len_kaweth_trigger_code_fix, | ||
1043 | 126, | ||
1044 | 3)) < 0) { | ||
1045 | err("Error downloading trigger code fix (%d)", result); | ||
1046 | goto err_fw; | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { | ||
1051 | err("Error triggering firmware (%d)", result); | ||
1052 | goto err_fw; | ||
1053 | } | ||
1054 | |||
1055 | /* Device will now disappear for a moment... */ | ||
1056 | info("Firmware loaded. I'll be back..."); | ||
1057 | err_fw: | ||
1058 | free_page((unsigned long)kaweth->firmware_buf); | ||
1059 | free_netdev(netdev); | ||
1060 | return -EIO; | ||
1061 | } | ||
1062 | |||
1063 | result = kaweth_read_configuration(kaweth); | ||
1064 | |||
1065 | if(result < 0) { | ||
1066 | err("Error reading configuration (%d), no net device created", result); | ||
1067 | goto err_free_netdev; | ||
1068 | } | ||
1069 | |||
1070 | info("Statistics collection: %x", kaweth->configuration.statistics_mask); | ||
1071 | info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); | ||
1072 | info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); | ||
1073 | info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", | ||
1074 | (int)kaweth->configuration.hw_addr[0], | ||
1075 | (int)kaweth->configuration.hw_addr[1], | ||
1076 | (int)kaweth->configuration.hw_addr[2], | ||
1077 | (int)kaweth->configuration.hw_addr[3], | ||
1078 | (int)kaweth->configuration.hw_addr[4], | ||
1079 | (int)kaweth->configuration.hw_addr[5]); | ||
1080 | |||
1081 | if(!memcmp(&kaweth->configuration.hw_addr, | ||
1082 | &bcast_addr, | ||
1083 | sizeof(bcast_addr))) { | ||
1084 | err("Firmware not functioning properly, no net device created"); | ||
1085 | goto err_free_netdev; | ||
1086 | } | ||
1087 | |||
1088 | if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { | ||
1089 | dbg("Error setting URB size"); | ||
1090 | goto err_free_netdev; | ||
1091 | } | ||
1092 | |||
1093 | if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { | ||
1094 | err("Error setting SOFS wait"); | ||
1095 | goto err_free_netdev; | ||
1096 | } | ||
1097 | |||
1098 | result = kaweth_set_receive_filter(kaweth, | ||
1099 | KAWETH_PACKET_FILTER_DIRECTED | | ||
1100 | KAWETH_PACKET_FILTER_BROADCAST | | ||
1101 | KAWETH_PACKET_FILTER_MULTICAST); | ||
1102 | |||
1103 | if(result < 0) { | ||
1104 | err("Error setting receive filter"); | ||
1105 | goto err_free_netdev; | ||
1106 | } | ||
1107 | |||
1108 | dbg("Initializing net device."); | ||
1109 | |||
1110 | kaweth->intf = intf; | ||
1111 | |||
1112 | kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1113 | if (!kaweth->tx_urb) | ||
1114 | goto err_free_netdev; | ||
1115 | kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1116 | if (!kaweth->rx_urb) | ||
1117 | goto err_only_tx; | ||
1118 | kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1119 | if (!kaweth->irq_urb) | ||
1120 | goto err_tx_and_rx; | ||
1121 | |||
1122 | kaweth->intbuffer = usb_buffer_alloc( kaweth->dev, | ||
1123 | INTBUFFERSIZE, | ||
1124 | GFP_KERNEL, | ||
1125 | &kaweth->intbufferhandle); | ||
1126 | if (!kaweth->intbuffer) | ||
1127 | goto err_tx_and_rx_and_irq; | ||
1128 | kaweth->rx_buf = usb_buffer_alloc( kaweth->dev, | ||
1129 | KAWETH_BUF_SIZE, | ||
1130 | GFP_KERNEL, | ||
1131 | &kaweth->rxbufferhandle); | ||
1132 | if (!kaweth->rx_buf) | ||
1133 | goto err_all_but_rxbuf; | ||
1134 | |||
1135 | memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr)); | ||
1136 | memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr, | ||
1137 | sizeof(kaweth->configuration.hw_addr)); | ||
1138 | |||
1139 | netdev->open = kaweth_open; | ||
1140 | netdev->stop = kaweth_close; | ||
1141 | |||
1142 | netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; | ||
1143 | netdev->tx_timeout = kaweth_tx_timeout; | ||
1144 | |||
1145 | netdev->hard_start_xmit = kaweth_start_xmit; | ||
1146 | netdev->set_multicast_list = kaweth_set_rx_mode; | ||
1147 | netdev->get_stats = kaweth_netdev_stats; | ||
1148 | netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size); | ||
1149 | SET_ETHTOOL_OPS(netdev, &ops); | ||
1150 | |||
1151 | /* kaweth is zeroed as part of alloc_netdev */ | ||
1152 | |||
1153 | INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); | ||
1154 | |||
1155 | SET_MODULE_OWNER(netdev); | ||
1156 | |||
1157 | usb_set_intfdata(intf, kaweth); | ||
1158 | |||
1159 | #if 0 | ||
1160 | // dma_supported() is deeply broken on almost all architectures | ||
1161 | if (dma_supported (&intf->dev, 0xffffffffffffffffULL)) | ||
1162 | kaweth->net->features |= NETIF_F_HIGHDMA; | ||
1163 | #endif | ||
1164 | |||
1165 | SET_NETDEV_DEV(netdev, &intf->dev); | ||
1166 | if (register_netdev(netdev) != 0) { | ||
1167 | err("Error registering netdev."); | ||
1168 | goto err_intfdata; | ||
1169 | } | ||
1170 | |||
1171 | info("kaweth interface created at %s", kaweth->net->name); | ||
1172 | |||
1173 | dbg("Kaweth probe returning."); | ||
1174 | |||
1175 | return 0; | ||
1176 | |||
1177 | err_intfdata: | ||
1178 | usb_set_intfdata(intf, NULL); | ||
1179 | usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); | ||
1180 | err_all_but_rxbuf: | ||
1181 | usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); | ||
1182 | err_tx_and_rx_and_irq: | ||
1183 | usb_free_urb(kaweth->irq_urb); | ||
1184 | err_tx_and_rx: | ||
1185 | usb_free_urb(kaweth->rx_urb); | ||
1186 | err_only_tx: | ||
1187 | usb_free_urb(kaweth->tx_urb); | ||
1188 | err_free_netdev: | ||
1189 | free_netdev(netdev); | ||
1190 | |||
1191 | return -EIO; | ||
1192 | } | ||
1193 | |||
1194 | /**************************************************************** | ||
1195 | * kaweth_disconnect | ||
1196 | ****************************************************************/ | ||
1197 | static void kaweth_disconnect(struct usb_interface *intf) | ||
1198 | { | ||
1199 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
1200 | struct net_device *netdev; | ||
1201 | |||
1202 | info("Unregistering"); | ||
1203 | |||
1204 | usb_set_intfdata(intf, NULL); | ||
1205 | if (!kaweth) { | ||
1206 | warn("unregistering non-existant device"); | ||
1207 | return; | ||
1208 | } | ||
1209 | netdev = kaweth->net; | ||
1210 | |||
1211 | dbg("Unregistering net device"); | ||
1212 | unregister_netdev(netdev); | ||
1213 | |||
1214 | usb_free_urb(kaweth->rx_urb); | ||
1215 | usb_free_urb(kaweth->tx_urb); | ||
1216 | usb_free_urb(kaweth->irq_urb); | ||
1217 | |||
1218 | usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); | ||
1219 | usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); | ||
1220 | |||
1221 | free_netdev(netdev); | ||
1222 | } | ||
1223 | |||
1224 | |||
1225 | // FIXME this completion stuff is a modified clone of | ||
1226 | // an OLD version of some stuff in usb.c ... | ||
1227 | struct usb_api_data { | ||
1228 | wait_queue_head_t wqh; | ||
1229 | int done; | ||
1230 | }; | ||
1231 | |||
1232 | /*-------------------------------------------------------------------* | ||
1233 | * completion handler for compatibility wrappers (sync control/bulk) * | ||
1234 | *-------------------------------------------------------------------*/ | ||
1235 | static void usb_api_blocking_completion(struct urb *urb) | ||
1236 | { | ||
1237 | struct usb_api_data *awd = (struct usb_api_data *)urb->context; | ||
1238 | |||
1239 | awd->done=1; | ||
1240 | wake_up(&awd->wqh); | ||
1241 | } | ||
1242 | |||
1243 | /*-------------------------------------------------------------------* | ||
1244 | * COMPATIBILITY STUFF * | ||
1245 | *-------------------------------------------------------------------*/ | ||
1246 | |||
1247 | // Starts urb and waits for completion or timeout | ||
1248 | static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) | ||
1249 | { | ||
1250 | struct usb_api_data awd; | ||
1251 | int status; | ||
1252 | |||
1253 | init_waitqueue_head(&awd.wqh); | ||
1254 | awd.done = 0; | ||
1255 | |||
1256 | urb->context = &awd; | ||
1257 | status = usb_submit_urb(urb, GFP_NOIO); | ||
1258 | if (status) { | ||
1259 | // something went wrong | ||
1260 | usb_free_urb(urb); | ||
1261 | return status; | ||
1262 | } | ||
1263 | |||
1264 | if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { | ||
1265 | // timeout | ||
1266 | warn("usb_control/bulk_msg: timeout"); | ||
1267 | usb_kill_urb(urb); // remove urb safely | ||
1268 | status = -ETIMEDOUT; | ||
1269 | } | ||
1270 | else { | ||
1271 | status = urb->status; | ||
1272 | } | ||
1273 | |||
1274 | if (actual_length) { | ||
1275 | *actual_length = urb->actual_length; | ||
1276 | } | ||
1277 | |||
1278 | usb_free_urb(urb); | ||
1279 | return status; | ||
1280 | } | ||
1281 | |||
1282 | /*-------------------------------------------------------------------*/ | ||
1283 | // returns status (negative) or length (positive) | ||
1284 | static int kaweth_internal_control_msg(struct usb_device *usb_dev, | ||
1285 | unsigned int pipe, | ||
1286 | struct usb_ctrlrequest *cmd, void *data, | ||
1287 | int len, int timeout) | ||
1288 | { | ||
1289 | struct urb *urb; | ||
1290 | int retv; | ||
1291 | int length = 0; /* shut up GCC */ | ||
1292 | |||
1293 | urb = usb_alloc_urb(0, GFP_NOIO); | ||
1294 | if (!urb) | ||
1295 | return -ENOMEM; | ||
1296 | |||
1297 | usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, | ||
1298 | len, usb_api_blocking_completion, NULL); | ||
1299 | |||
1300 | retv = usb_start_wait_urb(urb, timeout, &length); | ||
1301 | if (retv < 0) { | ||
1302 | return retv; | ||
1303 | } | ||
1304 | else { | ||
1305 | return length; | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | |||
1310 | /**************************************************************** | ||
1311 | * kaweth_init | ||
1312 | ****************************************************************/ | ||
1313 | static int __init kaweth_init(void) | ||
1314 | { | ||
1315 | dbg("Driver loading"); | ||
1316 | return usb_register(&kaweth_driver); | ||
1317 | } | ||
1318 | |||
1319 | /**************************************************************** | ||
1320 | * kaweth_exit | ||
1321 | ****************************************************************/ | ||
1322 | static void __exit kaweth_exit(void) | ||
1323 | { | ||
1324 | usb_deregister(&kaweth_driver); | ||
1325 | } | ||
1326 | |||
1327 | module_init(kaweth_init); | ||
1328 | module_exit(kaweth_exit); | ||
1329 | |||
1330 | |||
1331 | |||
1332 | |||
1333 | |||
1334 | |||
1335 | |||
1336 | |||
1337 | |||
diff --git a/drivers/net/usb/kawethfw.h b/drivers/net/usb/kawethfw.h new file mode 100644 index 000000000000..cf85fcb0d1a6 --- /dev/null +++ b/drivers/net/usb/kawethfw.h | |||
@@ -0,0 +1,557 @@ | |||
1 | /******************************************/ | ||
2 | /* NOTE: B6/C3 is data header signature */ | ||
3 | /* 0xAA/0xBB is data length = total */ | ||
4 | /* bytes - 7, 0xCC is type, 0xDD is */ | ||
5 | /* interrupt to use. */ | ||
6 | /******************************************/ | ||
7 | |||
8 | /**************************************************************** | ||
9 | * kaweth_trigger_code | ||
10 | ****************************************************************/ | ||
11 | static __u8 kaweth_trigger_code[] = | ||
12 | { | ||
13 | 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, | ||
14 | 0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00, | ||
15 | 0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00, | ||
16 | 0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07, | ||
17 | 0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, | ||
18 | 0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0, | ||
19 | 0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87, | ||
20 | 0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09, | ||
21 | 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00, | ||
22 | 0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8, | ||
23 | 0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00, | ||
24 | 0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05, | ||
25 | 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf, | ||
26 | 0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf, | ||
27 | 0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c, | ||
28 | 0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00, | ||
29 | 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07, | ||
30 | 0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c, | ||
31 | 0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00, | ||
32 | 0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07, | ||
33 | 0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf, | ||
34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
35 | 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, | ||
36 | 0x00, 0x00 | ||
37 | }; | ||
38 | /**************************************************************** | ||
39 | * kaweth_trigger_code_fix | ||
40 | ****************************************************************/ | ||
41 | static __u8 kaweth_trigger_code_fix[] = | ||
42 | { | ||
43 | 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, | ||
44 | 0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00, | ||
45 | 0x80, 0x00, 0x98, 0x00, 0xaa, 0x00, | ||
46 | 0x00, 0x00 | ||
47 | }; | ||
48 | |||
49 | /**************************************************************** | ||
50 | * kaweth_new_code | ||
51 | ****************************************************************/ | ||
52 | static __u8 kaweth_new_code[] = | ||
53 | { | ||
54 | 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, | ||
55 | 0x9f, 0xcf, 0xde, 0x06, 0xe7, 0x57, 0x00, 0x00, | ||
56 | 0xc4, 0x06, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f, | ||
57 | 0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0, | ||
58 | 0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf, | ||
59 | 0xd7, 0x09, 0x00, 0xc0, 0xe7, 0x09, 0xa2, 0xc0, | ||
60 | 0xbe, 0x06, 0x9f, 0xaf, 0x36, 0x00, 0xe7, 0x05, | ||
61 | 0x00, 0xc0, 0xa7, 0xcf, 0xbc, 0x06, 0x97, 0xcf, | ||
62 | 0xe7, 0x57, 0x00, 0x00, 0xb8, 0x06, 0xa7, 0xa1, | ||
63 | 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, | ||
64 | 0x14, 0x08, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00, | ||
65 | 0xa4, 0xc0, 0xa7, 0xc0, 0x7a, 0x06, 0x9f, 0xaf, | ||
66 | 0x92, 0x07, 0xe7, 0x07, 0x00, 0x00, 0x14, 0x08, | ||
67 | 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, 0x9f, 0xa0, | ||
68 | 0x38, 0x00, 0xe7, 0x59, 0xba, 0x06, 0xbe, 0x06, | ||
69 | 0x9f, 0xa0, 0x38, 0x00, 0xc8, 0x09, 0xca, 0x06, | ||
70 | 0x08, 0x62, 0x9f, 0xa1, 0x36, 0x08, 0xc0, 0x09, | ||
71 | 0x76, 0x06, 0x00, 0x60, 0xa7, 0xc0, 0x7a, 0x06, | ||
72 | 0x9f, 0xaf, 0xcc, 0x02, 0xe7, 0x57, 0x00, 0x00, | ||
73 | 0xb8, 0x06, 0xa7, 0xc1, 0x7a, 0x06, 0x9f, 0xaf, | ||
74 | 0x04, 0x00, 0xe7, 0x57, 0x00, 0x00, 0x8e, 0x06, | ||
75 | 0x0a, 0xc1, 0xe7, 0x09, 0x20, 0xc0, 0x10, 0x08, | ||
76 | 0xe7, 0xd0, 0x10, 0x08, 0xe7, 0x67, 0x40, 0x00, | ||
77 | 0x10, 0x08, 0x9f, 0xaf, 0x92, 0x0c, 0xc0, 0x09, | ||
78 | 0xd0, 0x06, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59, | ||
79 | 0xbe, 0x06, 0x02, 0xc0, 0x9f, 0xaf, 0xec, 0x00, | ||
80 | 0x9f, 0xaf, 0x34, 0x02, 0xe7, 0x57, 0x00, 0x00, | ||
81 | 0xa6, 0x06, 0x9f, 0xa0, 0x7a, 0x02, 0xa7, 0xcf, | ||
82 | 0x7a, 0x06, 0x48, 0x02, 0xe7, 0x09, 0xbe, 0x06, | ||
83 | 0xd0, 0x06, 0xc8, 0x37, 0x04, 0x00, 0x9f, 0xaf, | ||
84 | 0x08, 0x03, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, | ||
85 | 0xce, 0x06, 0x97, 0xc0, 0xd7, 0x09, 0x00, 0xc0, | ||
86 | 0xc1, 0xdf, 0xc8, 0x09, 0xc6, 0x06, 0x08, 0x62, | ||
87 | 0x14, 0xc0, 0x27, 0x04, 0xc6, 0x06, 0x10, 0x94, | ||
88 | 0xf0, 0x07, 0x10, 0x08, 0x02, 0x00, 0xc1, 0x07, | ||
89 | 0x01, 0x00, 0x70, 0x00, 0x04, 0x00, 0xf0, 0x07, | ||
90 | 0x30, 0x01, 0x06, 0x00, 0x50, 0xaf, 0xe7, 0x07, | ||
91 | 0xff, 0xff, 0xd0, 0x06, 0xe7, 0x07, 0x00, 0x00, | ||
92 | 0xce, 0x06, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, | ||
93 | 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x48, 0x02, | ||
94 | 0xd0, 0x09, 0xc6, 0x06, 0x27, 0x02, 0xc6, 0x06, | ||
95 | 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02, | ||
96 | 0xc8, 0x37, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00, | ||
97 | 0x00, 0x60, 0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00, | ||
98 | 0x23, 0xc9, 0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8, | ||
99 | 0xc0, 0x17, 0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff, | ||
100 | 0x30, 0x00, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, | ||
101 | 0x04, 0x00, 0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00, | ||
102 | 0x30, 0x00, 0x06, 0x00, 0xf0, 0x07, 0xa0, 0x01, | ||
103 | 0x0a, 0x00, 0x48, 0x02, 0xc1, 0x07, 0x02, 0x00, | ||
104 | 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf, | ||
105 | 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf, | ||
106 | 0x08, 0x03, 0x9f, 0xaf, 0x7a, 0x02, 0x97, 0xcf, | ||
107 | 0x9f, 0xaf, 0x7a, 0x02, 0xc9, 0x37, 0x04, 0x00, | ||
108 | 0xc1, 0xdf, 0xc8, 0x09, 0xa2, 0x06, 0x50, 0x02, | ||
109 | 0x67, 0x02, 0xa2, 0x06, 0xd1, 0x07, 0x00, 0x00, | ||
110 | 0x27, 0xd8, 0xaa, 0x06, 0xc0, 0xdf, 0x9f, 0xaf, | ||
111 | 0xc4, 0x01, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, | ||
112 | 0xd2, 0x06, 0x97, 0xc1, 0xe7, 0x57, 0x01, 0x00, | ||
113 | 0xa8, 0x06, 0x97, 0xc0, 0xc8, 0x09, 0xa0, 0x06, | ||
114 | 0x08, 0x62, 0x97, 0xc0, 0x00, 0x02, 0xc0, 0x17, | ||
115 | 0x0e, 0x00, 0x27, 0x00, 0x34, 0x01, 0x27, 0x0c, | ||
116 | 0x0c, 0x00, 0x36, 0x01, 0xe7, 0x07, 0x50, 0xc3, | ||
117 | 0x12, 0xc0, 0xe7, 0x07, 0xcc, 0x0b, 0x02, 0x00, | ||
118 | 0xe7, 0x07, 0x01, 0x00, 0xa8, 0x06, 0xe7, 0x07, | ||
119 | 0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf, 0xc8, 0x09, | ||
120 | 0xa4, 0x06, 0x08, 0x62, 0x02, 0xc0, 0x10, 0x64, | ||
121 | 0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00, 0x9e, 0x06, | ||
122 | 0xe7, 0x07, 0x72, 0x04, 0x24, 0x00, 0x97, 0xcf, | ||
123 | 0x27, 0x04, 0xa4, 0x06, 0xc8, 0x17, 0x0e, 0x00, | ||
124 | 0x27, 0x02, 0x9e, 0x06, 0xe7, 0x07, 0x80, 0x04, | ||
125 | 0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, | ||
126 | 0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, | ||
127 | 0x13, 0xc1, 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x57, | ||
128 | 0x00, 0x00, 0x9e, 0x06, 0x13, 0xc0, 0xe7, 0x09, | ||
129 | 0x9e, 0x06, 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, | ||
130 | 0x32, 0x01, 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, | ||
131 | 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, 0x04, 0xcf, | ||
132 | 0xe7, 0x57, 0x00, 0x00, 0x9e, 0x06, 0x02, 0xc1, | ||
133 | 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x05, 0x00, 0xc0, | ||
134 | 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, | ||
135 | 0x08, 0x92, 0xe7, 0x57, 0x02, 0x00, 0xaa, 0x06, | ||
136 | 0x02, 0xc3, 0xc8, 0x09, 0xa4, 0x06, 0x27, 0x02, | ||
137 | 0xa6, 0x06, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05, | ||
138 | 0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0xa4, 0x06, | ||
139 | 0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00, | ||
140 | 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, | ||
141 | 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00, | ||
142 | 0x06, 0x00, 0xf0, 0x07, 0x46, 0x01, 0x0a, 0x00, | ||
143 | 0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00, | ||
144 | 0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, | ||
145 | 0x96, 0x06, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09, | ||
146 | 0x96, 0x06, 0x27, 0x04, 0x96, 0x06, 0x27, 0x52, | ||
147 | 0x98, 0x06, 0x03, 0xc1, 0xe7, 0x07, 0x96, 0x06, | ||
148 | 0x98, 0x06, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17, | ||
149 | 0x0e, 0x00, 0x9f, 0xaf, 0xba, 0x03, 0xc8, 0x05, | ||
150 | 0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x24, 0x03, | ||
151 | 0x97, 0xcf, 0x9f, 0xaf, 0x08, 0x03, 0x97, 0xcf, | ||
152 | 0x57, 0x02, 0xc9, 0x07, 0xa4, 0x06, 0xd7, 0x09, | ||
153 | 0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62, 0x1b, 0xc0, | ||
154 | 0x50, 0x04, 0x11, 0x02, 0xe7, 0x05, 0x00, 0xc0, | ||
155 | 0xc9, 0x05, 0x97, 0xcf, 0x97, 0x02, 0xca, 0x09, | ||
156 | 0xd6, 0x06, 0xf2, 0x17, 0x01, 0x00, 0x04, 0x00, | ||
157 | 0xf2, 0x27, 0x00, 0x00, 0x06, 0x00, 0xca, 0x17, | ||
158 | 0x2c, 0x00, 0xf8, 0x77, 0x01, 0x00, 0x0e, 0x00, | ||
159 | 0x06, 0xc0, 0xca, 0xd9, 0xf8, 0x57, 0xff, 0x00, | ||
160 | 0x0e, 0x00, 0x01, 0xc1, 0xca, 0xd9, 0x22, 0x1c, | ||
161 | 0x0c, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17, | ||
162 | 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xca, 0x05, | ||
163 | 0x00, 0x0c, 0x0c, 0x00, 0xc0, 0x17, 0x41, 0x00, | ||
164 | 0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00, 0x08, 0x00, | ||
165 | 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00, | ||
166 | 0x06, 0x00, 0xf0, 0x07, 0xda, 0x00, 0x0a, 0x00, | ||
167 | 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0c, | ||
168 | 0x08, 0x00, 0x40, 0xd1, 0x01, 0x00, 0xc0, 0x19, | ||
169 | 0xce, 0x06, 0xc0, 0x59, 0xc2, 0x06, 0x04, 0xc9, | ||
170 | 0x49, 0xaf, 0x9f, 0xaf, 0xec, 0x00, 0x4a, 0xaf, | ||
171 | 0x67, 0x10, 0xce, 0x06, 0xc8, 0x17, 0x04, 0x00, | ||
172 | 0xc1, 0x07, 0x01, 0x00, 0xd7, 0x09, 0x00, 0xc0, | ||
173 | 0xc1, 0xdf, 0x50, 0xaf, 0xe7, 0x05, 0x00, 0xc0, | ||
174 | 0x97, 0xcf, 0xc0, 0x07, 0x01, 0x00, 0xc1, 0x09, | ||
175 | 0xac, 0x06, 0xc1, 0x77, 0x01, 0x00, 0x97, 0xc1, | ||
176 | 0xd8, 0x77, 0x01, 0x00, 0x12, 0xc0, 0xc9, 0x07, | ||
177 | 0x6a, 0x06, 0x9f, 0xaf, 0x08, 0x04, 0x04, 0xc1, | ||
178 | 0xc1, 0x77, 0x08, 0x00, 0x13, 0xc0, 0x97, 0xcf, | ||
179 | 0xc1, 0x77, 0x02, 0x00, 0x97, 0xc1, 0xc1, 0x77, | ||
180 | 0x10, 0x00, 0x0c, 0xc0, 0x9f, 0xaf, 0x2c, 0x04, | ||
181 | 0x97, 0xcf, 0xc1, 0x77, 0x04, 0x00, 0x06, 0xc0, | ||
182 | 0xc9, 0x07, 0x70, 0x06, 0x9f, 0xaf, 0x08, 0x04, | ||
183 | 0x97, 0xc0, 0x00, 0xcf, 0x00, 0x90, 0x97, 0xcf, | ||
184 | 0x50, 0x54, 0x97, 0xc1, 0x70, 0x5c, 0x02, 0x00, | ||
185 | 0x02, 0x00, 0x97, 0xc1, 0x70, 0x5c, 0x04, 0x00, | ||
186 | 0x04, 0x00, 0x97, 0xcf, 0x80, 0x01, 0xc0, 0x00, | ||
187 | 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00, | ||
188 | 0x06, 0x00, 0x00, 0x00, 0xcb, 0x09, 0xb2, 0x06, | ||
189 | 0xcc, 0x09, 0xb4, 0x06, 0x0b, 0x53, 0x11, 0xc0, | ||
190 | 0xc9, 0x02, 0xca, 0x07, 0x1c, 0x04, 0x9f, 0xaf, | ||
191 | 0x08, 0x04, 0x97, 0xc0, 0x0a, 0xc8, 0x82, 0x08, | ||
192 | 0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf, 0x08, 0x04, | ||
193 | 0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30, 0x82, 0x60, | ||
194 | 0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf, 0x89, 0x10, | ||
195 | 0x09, 0x53, 0x79, 0xc2, 0x89, 0x30, 0x82, 0x08, | ||
196 | 0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf, 0xc0, 0xdf, | ||
197 | 0x97, 0xcf, 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, | ||
198 | 0xe7, 0x09, 0x98, 0xc0, 0x94, 0x06, 0x0f, 0xcf, | ||
199 | 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, 0xe7, 0x09, | ||
200 | 0x98, 0xc0, 0x94, 0x06, 0xe7, 0x09, 0x9e, 0x06, | ||
201 | 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01, | ||
202 | 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09, | ||
203 | 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0x90, 0x06, | ||
204 | 0xc8, 0x37, 0x0e, 0x00, 0xe7, 0x77, 0x2a, 0x00, | ||
205 | 0x92, 0x06, 0x30, 0xc0, 0x97, 0x02, 0xca, 0x09, | ||
206 | 0xd6, 0x06, 0xe7, 0x77, 0x20, 0x00, 0x92, 0x06, | ||
207 | 0x0e, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x10, 0x00, | ||
208 | 0xf2, 0x27, 0x00, 0x00, 0x12, 0x00, 0xe7, 0x77, | ||
209 | 0x0a, 0x00, 0x92, 0x06, 0xca, 0x05, 0x1e, 0xc0, | ||
210 | 0x97, 0x02, 0xca, 0x09, 0xd6, 0x06, 0xf2, 0x17, | ||
211 | 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00, | ||
212 | 0x0e, 0x00, 0xe7, 0x77, 0x02, 0x00, 0x92, 0x06, | ||
213 | 0x07, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x44, 0x00, | ||
214 | 0xf2, 0x27, 0x00, 0x00, 0x46, 0x00, 0x06, 0xcf, | ||
215 | 0xf2, 0x17, 0x01, 0x00, 0x60, 0x00, 0xf2, 0x27, | ||
216 | 0x00, 0x00, 0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf, | ||
217 | 0x08, 0x03, 0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02, | ||
218 | 0xf1, 0x09, 0x94, 0x06, 0x0c, 0x00, 0xf1, 0xda, | ||
219 | 0x0c, 0x00, 0xc8, 0x09, 0x98, 0x06, 0x50, 0x02, | ||
220 | 0x67, 0x02, 0x98, 0x06, 0xd1, 0x07, 0x00, 0x00, | ||
221 | 0xc9, 0x05, 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, | ||
222 | 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, 0x02, 0xc0, | ||
223 | 0x9f, 0xaf, 0x06, 0x02, 0xc8, 0x05, 0xe7, 0x05, | ||
224 | 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09, | ||
225 | 0x00, 0xc0, 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, | ||
226 | 0xc0, 0x09, 0x92, 0xc0, 0xe7, 0x07, 0x04, 0x00, | ||
227 | 0x90, 0xc0, 0xca, 0x09, 0xd6, 0x06, 0xe7, 0x07, | ||
228 | 0x00, 0x00, 0xa8, 0x06, 0xe7, 0x07, 0x6a, 0x04, | ||
229 | 0x02, 0x00, 0xc0, 0x77, 0x02, 0x00, 0x08, 0xc0, | ||
230 | 0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27, | ||
231 | 0x00, 0x00, 0x52, 0x00, 0x9f, 0xcf, 0x24, 0x06, | ||
232 | 0xc0, 0x77, 0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17, | ||
233 | 0x01, 0x00, 0x58, 0x00, 0xf2, 0x27, 0x00, 0x00, | ||
234 | 0x5a, 0x00, 0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0, | ||
235 | 0xf2, 0x17, 0x01, 0x00, 0x70, 0x00, 0xf2, 0x27, | ||
236 | 0x00, 0x00, 0x72, 0x00, 0xc0, 0x77, 0x08, 0x00, | ||
237 | 0x1d, 0xc1, 0xf2, 0x17, 0x01, 0x00, 0x08, 0x00, | ||
238 | 0xf2, 0x27, 0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77, | ||
239 | 0x00, 0x02, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00, | ||
240 | 0x64, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x66, 0x00, | ||
241 | 0xc0, 0x77, 0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17, | ||
242 | 0x01, 0x00, 0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00, | ||
243 | 0x5e, 0x00, 0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0, | ||
244 | 0x1b, 0xcf, 0x1a, 0xcf, 0xf2, 0x17, 0x01, 0x00, | ||
245 | 0x00, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x02, 0x00, | ||
246 | 0xc8, 0x09, 0x34, 0x01, 0xca, 0x17, 0x14, 0x00, | ||
247 | 0xd8, 0x77, 0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9, | ||
248 | 0xd8, 0x57, 0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9, | ||
249 | 0xe2, 0x19, 0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00, | ||
250 | 0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, | ||
251 | 0x9f, 0xaf, 0x40, 0x06, 0x9f, 0xaf, 0xc4, 0x01, | ||
252 | 0xe7, 0x57, 0x00, 0x00, 0xd2, 0x06, 0x9f, 0xa1, | ||
253 | 0x0e, 0x0a, 0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05, | ||
254 | 0xe7, 0x05, 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, | ||
255 | 0xc8, 0x09, 0xa0, 0x06, 0x08, 0x62, 0x97, 0xc0, | ||
256 | 0x27, 0x04, 0xa0, 0x06, 0x27, 0x52, 0xa2, 0x06, | ||
257 | 0x03, 0xc1, 0xe7, 0x07, 0xa0, 0x06, 0xa2, 0x06, | ||
258 | 0x9f, 0xaf, 0x08, 0x03, 0xe7, 0x57, 0x00, 0x00, | ||
259 | 0xaa, 0x06, 0x02, 0xc0, 0x27, 0xda, 0xaa, 0x06, | ||
260 | 0x97, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
261 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
262 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
263 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
264 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
266 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
267 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
268 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
270 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
271 | 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
272 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
273 | 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
274 | 0x00, 0x00, 0xff, 0xff, 0xfb, 0x13, 0xe7, 0x57, | ||
275 | 0x00, 0x80, 0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07, | ||
276 | 0xee, 0x0b, 0x12, 0x00, 0xe7, 0x07, 0x34, 0x0c, | ||
277 | 0xb2, 0x00, 0xe7, 0x07, 0xc6, 0x07, 0xf2, 0x02, | ||
278 | 0xc8, 0x09, 0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00, | ||
279 | 0x0d, 0x00, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07, | ||
280 | 0x00, 0x00, 0x0e, 0xc0, 0xc8, 0x09, 0xde, 0x00, | ||
281 | 0xc8, 0x17, 0x09, 0x00, 0xc9, 0x07, 0xda, 0x06, | ||
282 | 0xc0, 0x07, 0x04, 0x00, 0x68, 0x0a, 0x00, 0xda, | ||
283 | 0x7d, 0xc1, 0xe7, 0x09, 0xc0, 0x00, 0x7c, 0x06, | ||
284 | 0xe7, 0x09, 0xbe, 0x00, 0x78, 0x06, 0xe7, 0x09, | ||
285 | 0x10, 0x00, 0xbc, 0x06, 0xc8, 0x07, 0xd6, 0x07, | ||
286 | 0x9f, 0xaf, 0xae, 0x07, 0x9f, 0xaf, 0x00, 0x0a, | ||
287 | 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, 0x0f, 0x00, | ||
288 | 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, 0x44, 0xaf, | ||
289 | 0x27, 0x00, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06, | ||
290 | 0x27, 0x00, 0xb6, 0x06, 0xc0, 0x07, 0x74, 0x00, | ||
291 | 0x44, 0xaf, 0x27, 0x00, 0xd6, 0x06, 0x08, 0x00, | ||
292 | 0x00, 0x90, 0xc1, 0x07, 0x3a, 0x00, 0x20, 0x00, | ||
293 | 0x01, 0xda, 0x7d, 0xc1, 0x9f, 0xaf, 0xba, 0x09, | ||
294 | 0xc0, 0x07, 0x44, 0x00, 0x48, 0xaf, 0x27, 0x00, | ||
295 | 0x7a, 0x06, 0x9f, 0xaf, 0x96, 0x0a, 0xe7, 0x07, | ||
296 | 0x01, 0x00, 0xc0, 0x06, 0xe7, 0x05, 0x0e, 0xc0, | ||
297 | 0x97, 0xcf, 0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00, | ||
298 | 0x0e, 0xc0, 0xe7, 0x07, 0xff, 0xff, 0xbe, 0x06, | ||
299 | 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, 0x01, 0x00, | ||
300 | 0x60, 0xaf, 0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08, | ||
301 | 0x09, 0x08, 0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1, | ||
302 | 0x97, 0xcf, 0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf, | ||
303 | 0x51, 0x94, 0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf, | ||
304 | 0xc9, 0x09, 0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1, | ||
305 | 0xc0, 0xdf, 0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00, | ||
306 | 0x24, 0x00, 0x80, 0x04, 0x22, 0x00, 0x4e, 0x05, | ||
307 | 0xd0, 0x00, 0x0e, 0x0a, 0xaa, 0x00, 0x30, 0x08, | ||
308 | 0xbe, 0x00, 0x4a, 0x0a, 0x10, 0x00, 0x20, 0x00, | ||
309 | 0x04, 0x00, 0x6e, 0x04, 0x02, 0x00, 0x6a, 0x04, | ||
310 | 0x06, 0x00, 0x00, 0x00, 0x24, 0xc0, 0x04, 0x04, | ||
311 | 0x28, 0xc0, 0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04, | ||
312 | 0x22, 0xc0, 0xff, 0xf4, 0xc0, 0x00, 0x90, 0x09, | ||
313 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0x08, | ||
314 | 0x60, 0x08, 0xd0, 0x08, 0xda, 0x08, 0x00, 0x09, | ||
315 | 0x04, 0x09, 0x08, 0x09, 0x32, 0x09, 0x42, 0x09, | ||
316 | 0x50, 0x09, 0x52, 0x09, 0x5a, 0x09, 0x5a, 0x09, | ||
317 | 0x27, 0x02, 0xca, 0x06, 0x97, 0xcf, 0xe7, 0x07, | ||
318 | 0x00, 0x00, 0xca, 0x06, 0x0a, 0x0e, 0x01, 0x00, | ||
319 | 0xca, 0x57, 0x0e, 0x00, 0x9f, 0xc3, 0x5a, 0x09, | ||
320 | 0xca, 0x37, 0x00, 0x00, 0x9f, 0xc2, 0x5a, 0x09, | ||
321 | 0x0a, 0xd2, 0xb2, 0xcf, 0x16, 0x08, 0xc8, 0x09, | ||
322 | 0xde, 0x00, 0x07, 0x06, 0x9f, 0xcf, 0x6c, 0x09, | ||
323 | 0x17, 0x02, 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, | ||
324 | 0x0f, 0x00, 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, | ||
325 | 0xc8, 0x05, 0x30, 0x50, 0x06, 0x00, 0x9f, 0xc8, | ||
326 | 0x5a, 0x09, 0x27, 0x0c, 0x02, 0x00, 0xb0, 0x06, | ||
327 | 0xc0, 0x09, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06, | ||
328 | 0xe7, 0x07, 0x00, 0x00, 0xae, 0x06, 0x27, 0x00, | ||
329 | 0x80, 0x06, 0x00, 0x1c, 0x06, 0x00, 0x27, 0x00, | ||
330 | 0xb6, 0x06, 0x41, 0x90, 0x67, 0x50, 0xb0, 0x06, | ||
331 | 0x0d, 0xc0, 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, | ||
332 | 0x06, 0x00, 0x82, 0x06, 0xe7, 0x07, 0xbc, 0x08, | ||
333 | 0x84, 0x06, 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, | ||
334 | 0x51, 0xaf, 0x97, 0xcf, 0x9f, 0xaf, 0x48, 0x0c, | ||
335 | 0xe7, 0x09, 0xb6, 0x06, 0xb4, 0x06, 0xe7, 0x09, | ||
336 | 0xb0, 0x06, 0xae, 0x06, 0x59, 0xaf, 0x97, 0xcf, | ||
337 | 0x27, 0x0c, 0x02, 0x00, 0xac, 0x06, 0x59, 0xaf, | ||
338 | 0x97, 0xcf, 0x09, 0x0c, 0x02, 0x00, 0x09, 0xda, | ||
339 | 0x49, 0xd2, 0xc9, 0x19, 0xd6, 0x06, 0xc8, 0x07, | ||
340 | 0x7e, 0x06, 0xe0, 0x07, 0x00, 0x00, 0x60, 0x02, | ||
341 | 0xe0, 0x07, 0x04, 0x00, 0xd0, 0x07, 0xcc, 0x08, | ||
342 | 0x48, 0xdb, 0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf, | ||
343 | 0x59, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, | ||
344 | 0xf0, 0x57, 0x06, 0x00, 0x06, 0x00, 0x25, 0xc1, | ||
345 | 0xe7, 0x07, 0x70, 0x06, 0x80, 0x06, 0x41, 0x90, | ||
346 | 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, 0x06, 0x00, | ||
347 | 0x82, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06, | ||
348 | 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, 0x51, 0xaf, | ||
349 | 0x97, 0xcf, 0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57, | ||
350 | 0x06, 0x00, 0x0f, 0xc1, 0xc8, 0x07, 0x70, 0x06, | ||
351 | 0x15, 0xcf, 0x00, 0x0c, 0x02, 0x00, 0x00, 0xda, | ||
352 | 0x40, 0xd1, 0x27, 0x00, 0xc2, 0x06, 0x1e, 0xcf, | ||
353 | 0x1d, 0xcf, 0x27, 0x0c, 0x02, 0x00, 0xcc, 0x06, | ||
354 | 0x19, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07, | ||
355 | 0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00, | ||
356 | 0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00, | ||
357 | 0x7e, 0x06, 0xe7, 0x01, 0x82, 0x06, 0x27, 0x02, | ||
358 | 0x80, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06, | ||
359 | 0xc8, 0x07, 0x7e, 0x06, 0xc1, 0x07, 0x00, 0x80, | ||
360 | 0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, | ||
361 | 0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00, | ||
362 | 0xc4, 0x06, 0xa7, 0xcf, 0x7c, 0x06, 0x9f, 0xaf, | ||
363 | 0x00, 0x0a, 0xe7, 0x07, 0x01, 0x00, 0xc4, 0x06, | ||
364 | 0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf, | ||
365 | 0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf, | ||
366 | 0x7c, 0x06, 0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf, | ||
367 | 0x40, 0x00, 0xc0, 0x37, 0x00, 0x01, 0x41, 0x90, | ||
368 | 0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde, 0x50, 0x06, | ||
369 | 0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2, 0xc0, 0x07, | ||
370 | 0x10, 0x00, 0x27, 0x00, 0x9a, 0x06, 0x41, 0x90, | ||
371 | 0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf, 0x27, 0x00, | ||
372 | 0x9c, 0x06, 0xc0, 0x09, 0x9a, 0x06, 0x41, 0x90, | ||
373 | 0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde, 0x08, 0x00, | ||
374 | 0x44, 0xaf, 0x27, 0x00, 0xc8, 0x06, 0x97, 0xcf, | ||
375 | 0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0, 0xe7, 0x67, | ||
376 | 0xff, 0xfb, 0x24, 0xc0, 0x97, 0xcf, 0xe7, 0x87, | ||
377 | 0x01, 0x00, 0xd2, 0x06, 0xe7, 0x57, 0x00, 0x00, | ||
378 | 0xa8, 0x06, 0x97, 0xc1, 0x9f, 0xaf, 0x00, 0x0a, | ||
379 | 0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0, 0xe7, 0x07, | ||
380 | 0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67, 0xfe, 0xff, | ||
381 | 0x3e, 0xc0, 0xe7, 0x07, 0x26, 0x00, 0x0a, 0xc0, | ||
382 | 0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0, 0xe7, 0x07, | ||
383 | 0xff, 0xff, 0xbe, 0x06, 0x9f, 0xaf, 0x10, 0x0b, | ||
384 | 0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf, 0x78, 0x06, | ||
385 | 0xc0, 0x05, 0x27, 0x00, 0x76, 0x06, 0xe7, 0x87, | ||
386 | 0x01, 0x00, 0xd2, 0x06, 0x9f, 0xaf, 0x00, 0x0a, | ||
387 | 0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0, 0x9f, 0xaf, | ||
388 | 0x10, 0x0b, 0x00, 0x90, 0x27, 0x00, 0xa6, 0x06, | ||
389 | 0x27, 0x00, 0xaa, 0x06, 0xe7, 0x09, 0xb2, 0x06, | ||
390 | 0xb4, 0x06, 0x27, 0x00, 0xae, 0x06, 0x27, 0x00, | ||
391 | 0xac, 0x06, 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, | ||
392 | 0x00, 0x00, 0x27, 0x00, 0xb2, 0x02, 0x27, 0x00, | ||
393 | 0xb4, 0x02, 0x27, 0x00, 0x8e, 0x06, 0xc0, 0x07, | ||
394 | 0x06, 0x00, 0xc8, 0x09, 0xde, 0x00, 0xc8, 0x17, | ||
395 | 0x03, 0x00, 0xc9, 0x07, 0x70, 0x06, 0x29, 0x0a, | ||
396 | 0x00, 0xda, 0x7d, 0xc1, 0x97, 0xcf, 0xd7, 0x09, | ||
397 | 0x00, 0xc0, 0xc1, 0xdf, 0x00, 0x90, 0x27, 0x00, | ||
398 | 0x96, 0x06, 0xe7, 0x07, 0x96, 0x06, 0x98, 0x06, | ||
399 | 0x27, 0x00, 0xa0, 0x06, 0xe7, 0x07, 0xa0, 0x06, | ||
400 | 0xa2, 0x06, 0x27, 0x00, 0xa6, 0x06, 0x27, 0x00, | ||
401 | 0x90, 0x06, 0x27, 0x00, 0x9e, 0x06, 0xc8, 0x09, | ||
402 | 0x9c, 0x06, 0xc1, 0x09, 0x9a, 0x06, 0xc9, 0x07, | ||
403 | 0xa4, 0x06, 0x11, 0x02, 0x09, 0x02, 0xc8, 0x17, | ||
404 | 0x40, 0x06, 0x01, 0xda, 0x7a, 0xc1, 0x51, 0x94, | ||
405 | 0xc8, 0x09, 0xc8, 0x06, 0xc9, 0x07, 0xc6, 0x06, | ||
406 | 0xc1, 0x09, 0x9a, 0x06, 0x11, 0x02, 0x09, 0x02, | ||
407 | 0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1, | ||
408 | 0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, | ||
409 | 0xe7, 0x57, 0x00, 0x00, 0x76, 0x06, 0x97, 0xc0, | ||
410 | 0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0xbe, 0x06, | ||
411 | 0xba, 0x06, 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, | ||
412 | 0x04, 0xc1, 0xe7, 0x07, 0x10, 0x0b, 0xb8, 0x06, | ||
413 | 0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0xba, 0x06, | ||
414 | 0xe7, 0x67, 0xff, 0x07, 0xba, 0x06, 0xe7, 0x07, | ||
415 | 0x46, 0x0b, 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, | ||
416 | 0x00, 0x00, 0xc0, 0x06, 0x23, 0xc0, 0xe7, 0x07, | ||
417 | 0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x80, | ||
418 | 0x80, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, | ||
419 | 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07, | ||
420 | 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, | ||
421 | 0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, | ||
422 | 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07, | ||
423 | 0x00, 0x80, 0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00, | ||
424 | 0xe7, 0x07, 0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07, | ||
425 | 0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00, | ||
426 | 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0, | ||
427 | 0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07, | ||
428 | 0x00, 0x00, 0xc0, 0x06, 0xe7, 0x07, 0x00, 0x00, | ||
429 | 0xb8, 0x06, 0xe7, 0x07, 0x00, 0x00, 0xd2, 0x06, | ||
430 | 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf, | ||
431 | 0x34, 0x02, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf, | ||
432 | 0xc4, 0x01, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, | ||
433 | 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xe7, 0x57, | ||
434 | 0x00, 0x00, 0xa8, 0x06, 0x06, 0xc0, 0xc0, 0x09, | ||
435 | 0x92, 0xc0, 0xc0, 0x77, 0x09, 0x02, 0x9f, 0xc1, | ||
436 | 0x5c, 0x05, 0x9f, 0xcf, 0x32, 0x06, 0xd7, 0x09, | ||
437 | 0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x0e, 0xc0, | ||
438 | 0x9f, 0xaf, 0x02, 0x0c, 0xe7, 0x05, 0x0e, 0xc0, | ||
439 | 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0x17, 0x02, | ||
440 | 0xc8, 0x09, 0xb0, 0xc0, 0xe7, 0x67, 0xfe, 0x7f, | ||
441 | 0xb0, 0xc0, 0xc8, 0x77, 0x00, 0x20, 0x9f, 0xc1, | ||
442 | 0x64, 0xeb, 0xe7, 0x57, 0x00, 0x00, 0xc8, 0x02, | ||
443 | 0x9f, 0xc1, 0x80, 0xeb, 0xc8, 0x99, 0xca, 0x02, | ||
444 | 0xc8, 0x67, 0x04, 0x00, 0x9f, 0xc1, 0x96, 0xeb, | ||
445 | 0x9f, 0xcf, 0x4c, 0xeb, 0xe7, 0x07, 0x00, 0x00, | ||
446 | 0xa6, 0xc0, 0xe7, 0x09, 0xb0, 0xc0, 0xc8, 0x02, | ||
447 | 0xe7, 0x07, 0x03, 0x00, 0xb0, 0xc0, 0x97, 0xcf, | ||
448 | 0xc0, 0x09, 0xb0, 0x06, 0xc0, 0x37, 0x01, 0x00, | ||
449 | 0x97, 0xc9, 0xc9, 0x09, 0xb2, 0x06, 0x02, 0x00, | ||
450 | 0x41, 0x90, 0x48, 0x02, 0xc9, 0x17, 0x06, 0x00, | ||
451 | 0x9f, 0xaf, 0x08, 0x04, 0x9f, 0xa2, 0x72, 0x0c, | ||
452 | 0x02, 0xda, 0x77, 0xc1, 0x41, 0x60, 0x71, 0xc1, | ||
453 | 0x97, 0xcf, 0x17, 0x02, 0x57, 0x02, 0x43, 0x04, | ||
454 | 0x21, 0x04, 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, | ||
455 | 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00, | ||
456 | 0xc1, 0x07, 0x01, 0x00, 0xc9, 0x05, 0xc8, 0x05, | ||
457 | 0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00, 0x8e, 0x06, | ||
458 | 0xc8, 0x07, 0x86, 0x06, 0xe7, 0x07, 0x00, 0x00, | ||
459 | 0x86, 0x06, 0xe7, 0x07, 0x10, 0x08, 0x88, 0x06, | ||
460 | 0xe7, 0x07, 0x04, 0x00, 0x8a, 0x06, 0xe7, 0x07, | ||
461 | 0xbc, 0x0c, 0x8c, 0x06, 0xc1, 0x07, 0x03, 0x80, | ||
462 | 0x50, 0xaf, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00, | ||
463 | 0x8e, 0x06, 0x97, 0xcf, | ||
464 | 0x00, 0x00 | ||
465 | }; | ||
466 | |||
467 | /**************************************************************** | ||
468 | * kaweth_new_code_fix | ||
469 | ****************************************************************/ | ||
470 | static __u8 kaweth_new_code_fix[] = | ||
471 | { | ||
472 | 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, | ||
473 | 0x02, 0x00, 0x08, 0x00, 0x28, 0x00, 0x2c, 0x00, | ||
474 | 0x34, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x48, 0x00, | ||
475 | 0x54, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x64, 0x00, | ||
476 | 0x68, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x72, 0x00, | ||
477 | 0x76, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x86, 0x00, | ||
478 | 0x8a, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, | ||
479 | 0x9e, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xb0, 0x00, | ||
480 | 0xb4, 0x00, 0xb8, 0x00, 0xc0, 0x00, 0xc6, 0x00, | ||
481 | 0xca, 0x00, 0xd0, 0x00, 0xd4, 0x00, 0xd8, 0x00, | ||
482 | 0xe0, 0x00, 0xde, 0x00, 0xe8, 0x00, 0xf0, 0x00, | ||
483 | 0xfc, 0x00, 0x04, 0x01, 0x0a, 0x01, 0x18, 0x01, | ||
484 | 0x22, 0x01, 0x28, 0x01, 0x3a, 0x01, 0x3e, 0x01, | ||
485 | 0x7e, 0x01, 0x98, 0x01, 0x9c, 0x01, 0xa2, 0x01, | ||
486 | 0xac, 0x01, 0xb2, 0x01, 0xba, 0x01, 0xc0, 0x01, | ||
487 | 0xc8, 0x01, 0xd0, 0x01, 0xd6, 0x01, 0xf4, 0x01, | ||
488 | 0xfc, 0x01, 0x08, 0x02, 0x16, 0x02, 0x1a, 0x02, | ||
489 | 0x22, 0x02, 0x2a, 0x02, 0x2e, 0x02, 0x3e, 0x02, | ||
490 | 0x44, 0x02, 0x4a, 0x02, 0x50, 0x02, 0x64, 0x02, | ||
491 | 0x62, 0x02, 0x6c, 0x02, 0x72, 0x02, 0x86, 0x02, | ||
492 | 0x8c, 0x02, 0x90, 0x02, 0x9e, 0x02, 0xbc, 0x02, | ||
493 | 0xd0, 0x02, 0xd8, 0x02, 0xdc, 0x02, 0xe0, 0x02, | ||
494 | 0xe8, 0x02, 0xe6, 0x02, 0xf4, 0x02, 0xfe, 0x02, | ||
495 | 0x04, 0x03, 0x0c, 0x03, 0x28, 0x03, 0x7c, 0x03, | ||
496 | 0x90, 0x03, 0x94, 0x03, 0x9c, 0x03, 0xa2, 0x03, | ||
497 | 0xc0, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xee, 0x03, | ||
498 | 0xfa, 0x03, 0xfe, 0x03, 0x2e, 0x04, 0x32, 0x04, | ||
499 | 0x3c, 0x04, 0x40, 0x04, 0x4e, 0x04, 0x76, 0x04, | ||
500 | 0x7c, 0x04, 0x84, 0x04, 0x8a, 0x04, 0x8e, 0x04, | ||
501 | 0xa6, 0x04, 0xb0, 0x04, 0xb8, 0x04, 0xbe, 0x04, | ||
502 | 0xd2, 0x04, 0xdc, 0x04, 0xee, 0x04, 0x10, 0x05, | ||
503 | 0x1a, 0x05, 0x24, 0x05, 0x2a, 0x05, 0x36, 0x05, | ||
504 | 0x34, 0x05, 0x3c, 0x05, 0x42, 0x05, 0x64, 0x05, | ||
505 | 0x6a, 0x05, 0x6e, 0x05, 0x86, 0x05, 0x22, 0x06, | ||
506 | 0x26, 0x06, 0x2c, 0x06, 0x30, 0x06, 0x42, 0x06, | ||
507 | 0x4a, 0x06, 0x4e, 0x06, 0x56, 0x06, 0x54, 0x06, | ||
508 | 0x5a, 0x06, 0x60, 0x06, 0x66, 0x06, 0xe8, 0x06, | ||
509 | 0xee, 0x06, 0xf4, 0x06, 0x16, 0x07, 0x26, 0x07, | ||
510 | 0x2c, 0x07, 0x32, 0x07, 0x36, 0x07, 0x3a, 0x07, | ||
511 | 0x3e, 0x07, 0x52, 0x07, 0x56, 0x07, 0x5a, 0x07, | ||
512 | 0x64, 0x07, 0x76, 0x07, 0x7a, 0x07, 0x80, 0x07, | ||
513 | 0x84, 0x07, 0x8a, 0x07, 0x9e, 0x07, 0xa2, 0x07, | ||
514 | 0xda, 0x07, 0xde, 0x07, 0xe2, 0x07, 0xe6, 0x07, | ||
515 | 0xea, 0x07, 0xee, 0x07, 0xf2, 0x07, 0xf6, 0x07, | ||
516 | 0x0e, 0x08, 0x16, 0x08, 0x18, 0x08, 0x1a, 0x08, | ||
517 | 0x1c, 0x08, 0x1e, 0x08, 0x20, 0x08, 0x22, 0x08, | ||
518 | 0x24, 0x08, 0x26, 0x08, 0x28, 0x08, 0x2a, 0x08, | ||
519 | 0x2c, 0x08, 0x2e, 0x08, 0x32, 0x08, 0x3a, 0x08, | ||
520 | 0x46, 0x08, 0x4e, 0x08, 0x54, 0x08, 0x5e, 0x08, | ||
521 | 0x78, 0x08, 0x7e, 0x08, 0x82, 0x08, 0x86, 0x08, | ||
522 | 0x8c, 0x08, 0x90, 0x08, 0x98, 0x08, 0x9e, 0x08, | ||
523 | 0xa4, 0x08, 0xaa, 0x08, 0xb0, 0x08, 0xae, 0x08, | ||
524 | 0xb4, 0x08, 0xbe, 0x08, 0xc4, 0x08, 0xc2, 0x08, | ||
525 | 0xca, 0x08, 0xc8, 0x08, 0xd4, 0x08, 0xe4, 0x08, | ||
526 | 0xe8, 0x08, 0xf6, 0x08, 0x14, 0x09, 0x12, 0x09, | ||
527 | 0x1a, 0x09, 0x20, 0x09, 0x26, 0x09, 0x24, 0x09, | ||
528 | 0x2a, 0x09, 0x3e, 0x09, 0x4c, 0x09, 0x56, 0x09, | ||
529 | 0x70, 0x09, 0x74, 0x09, 0x78, 0x09, 0x7e, 0x09, | ||
530 | 0x7c, 0x09, 0x82, 0x09, 0x98, 0x09, 0x9c, 0x09, | ||
531 | 0xa0, 0x09, 0xa6, 0x09, 0xb8, 0x09, 0xdc, 0x09, | ||
532 | 0xe8, 0x09, 0xec, 0x09, 0xfc, 0x09, 0x12, 0x0a, | ||
533 | 0x18, 0x0a, 0x1e, 0x0a, 0x42, 0x0a, 0x46, 0x0a, | ||
534 | 0x4e, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a, | ||
535 | 0x68, 0x0a, 0x6e, 0x0a, 0x72, 0x0a, 0x78, 0x0a, | ||
536 | 0x76, 0x0a, 0x7c, 0x0a, 0x80, 0x0a, 0x84, 0x0a, | ||
537 | 0x94, 0x0a, 0xa4, 0x0a, 0xb8, 0x0a, 0xbe, 0x0a, | ||
538 | 0xbc, 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc6, 0x0a, | ||
539 | 0xcc, 0x0a, 0xd0, 0x0a, 0xd4, 0x0a, 0xd8, 0x0a, | ||
540 | 0xdc, 0x0a, 0xe0, 0x0a, 0xf2, 0x0a, 0xf6, 0x0a, | ||
541 | 0xfa, 0x0a, 0x14, 0x0b, 0x1a, 0x0b, 0x20, 0x0b, | ||
542 | 0x1e, 0x0b, 0x26, 0x0b, 0x2e, 0x0b, 0x2c, 0x0b, | ||
543 | 0x36, 0x0b, 0x3c, 0x0b, 0x42, 0x0b, 0x40, 0x0b, | ||
544 | 0x4a, 0x0b, 0xaa, 0x0b, 0xb0, 0x0b, 0xb6, 0x0b, | ||
545 | 0xc0, 0x0b, 0xc8, 0x0b, 0xda, 0x0b, 0xe8, 0x0b, | ||
546 | 0xec, 0x0b, 0xfa, 0x0b, 0x4a, 0x0c, 0x54, 0x0c, | ||
547 | 0x62, 0x0c, 0x66, 0x0c, 0x96, 0x0c, 0x9a, 0x0c, | ||
548 | 0xa0, 0x0c, 0xa6, 0x0c, 0xa4, 0x0c, 0xac, 0x0c, | ||
549 | 0xb2, 0x0c, 0xb0, 0x0c, 0xc0, 0x0c, | ||
550 | 0x00, 0x00 | ||
551 | }; | ||
552 | |||
553 | |||
554 | static const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code); | ||
555 | static const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix); | ||
556 | static const int len_kaweth_new_code = sizeof(kaweth_new_code); | ||
557 | static const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix); | ||
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c new file mode 100644 index 000000000000..6240b978fe3d --- /dev/null +++ b/drivers/net/usb/mcs7830.c | |||
@@ -0,0 +1,534 @@ | |||
1 | /* | ||
2 | * MosChips MCS7830 based USB 2.0 Ethernet Devices | ||
3 | * | ||
4 | * based on usbnet.c, asix.c and the vendor provided mcs7830 driver | ||
5 | * | ||
6 | * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de> | ||
7 | * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> | ||
8 | * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | ||
9 | * Copyright (c) 2002-2003 TiVo Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/crc32.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/ethtool.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/mii.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/netdevice.h> | ||
33 | #include <linux/usb.h> | ||
34 | |||
35 | #include "usbnet.h" | ||
36 | |||
37 | /* requests */ | ||
38 | #define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ | ||
39 | USB_RECIP_DEVICE) | ||
40 | #define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ | ||
41 | USB_RECIP_DEVICE) | ||
42 | #define MCS7830_RD_BREQ 0x0E | ||
43 | #define MCS7830_WR_BREQ 0x0D | ||
44 | |||
45 | #define MCS7830_CTRL_TIMEOUT 1000 | ||
46 | #define MCS7830_MAX_MCAST 64 | ||
47 | |||
48 | #define MCS7830_VENDOR_ID 0x9710 | ||
49 | #define MCS7830_PRODUCT_ID 0x7830 | ||
50 | |||
51 | #define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ | ||
52 | ADVERTISE_100HALF | ADVERTISE_10FULL | \ | ||
53 | ADVERTISE_10HALF | ADVERTISE_CSMA) | ||
54 | |||
55 | /* HIF_REG_XX coressponding index value */ | ||
56 | enum { | ||
57 | HIF_REG_MULTICAST_HASH = 0x00, | ||
58 | HIF_REG_PACKET_GAP1 = 0x08, | ||
59 | HIF_REG_PACKET_GAP2 = 0x09, | ||
60 | HIF_REG_PHY_DATA = 0x0a, | ||
61 | HIF_REG_PHY_CMD1 = 0x0c, | ||
62 | HIF_REG_PHY_CMD1_READ = 0x40, | ||
63 | HIF_REG_PHY_CMD1_WRITE = 0x20, | ||
64 | HIF_REG_PHY_CMD1_PHYADDR = 0x01, | ||
65 | HIF_REG_PHY_CMD2 = 0x0d, | ||
66 | HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, | ||
67 | HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, | ||
68 | HIF_REG_CONFIG = 0x0e, | ||
69 | HIF_REG_CONFIG_CFG = 0x80, | ||
70 | HIF_REG_CONFIG_SPEED100 = 0x40, | ||
71 | HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, | ||
72 | HIF_REG_CONFIG_RXENABLE = 0x10, | ||
73 | HIF_REG_CONFIG_TXENABLE = 0x08, | ||
74 | HIF_REG_CONFIG_SLEEPMODE = 0x04, | ||
75 | HIF_REG_CONFIG_ALLMULTICAST = 0x02, | ||
76 | HIF_REG_CONFIG_PROMISCIOUS = 0x01, | ||
77 | HIF_REG_ETHERNET_ADDR = 0x0f, | ||
78 | HIF_REG_22 = 0x15, | ||
79 | HIF_REG_PAUSE_THRESHOLD = 0x16, | ||
80 | HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, | ||
81 | }; | ||
82 | |||
83 | struct mcs7830_data { | ||
84 | u8 multi_filter[8]; | ||
85 | u8 config; | ||
86 | }; | ||
87 | |||
88 | static const char driver_name[] = "MOSCHIP usb-ethernet driver"; | ||
89 | |||
90 | static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) | ||
91 | { | ||
92 | struct usb_device *xdev = dev->udev; | ||
93 | int ret; | ||
94 | |||
95 | ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, | ||
96 | MCS7830_RD_BMREQ, 0x0000, index, data, | ||
97 | size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) | ||
102 | { | ||
103 | struct usb_device *xdev = dev->udev; | ||
104 | int ret; | ||
105 | |||
106 | ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, | ||
107 | MCS7830_WR_BMREQ, 0x0000, index, data, | ||
108 | size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static void mcs7830_async_cmd_callback(struct urb *urb) | ||
113 | { | ||
114 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
115 | |||
116 | if (urb->status < 0) | ||
117 | printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d", | ||
118 | urb->status); | ||
119 | |||
120 | kfree(req); | ||
121 | usb_free_urb(urb); | ||
122 | } | ||
123 | |||
124 | static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) | ||
125 | { | ||
126 | struct usb_ctrlrequest *req; | ||
127 | int ret; | ||
128 | struct urb *urb; | ||
129 | |||
130 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
131 | if (!urb) { | ||
132 | dev_dbg(&dev->udev->dev, "Error allocating URB " | ||
133 | "in write_cmd_async!"); | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | req = kmalloc(sizeof *req, GFP_ATOMIC); | ||
138 | if (!req) { | ||
139 | dev_err(&dev->udev->dev, "Failed to allocate memory for " | ||
140 | "control request"); | ||
141 | goto out; | ||
142 | } | ||
143 | req->bRequestType = MCS7830_WR_BMREQ; | ||
144 | req->bRequest = MCS7830_WR_BREQ; | ||
145 | req->wValue = 0; | ||
146 | req->wIndex = cpu_to_le16(index); | ||
147 | req->wLength = cpu_to_le16(size); | ||
148 | |||
149 | usb_fill_control_urb(urb, dev->udev, | ||
150 | usb_sndctrlpipe(dev->udev, 0), | ||
151 | (void *)req, data, size, | ||
152 | mcs7830_async_cmd_callback, req); | ||
153 | |||
154 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
155 | if (ret < 0) { | ||
156 | dev_err(&dev->udev->dev, "Error submitting the control " | ||
157 | "message: ret=%d", ret); | ||
158 | goto out; | ||
159 | } | ||
160 | return; | ||
161 | out: | ||
162 | kfree(req); | ||
163 | usb_free_urb(urb); | ||
164 | } | ||
165 | |||
166 | static int mcs7830_get_address(struct usbnet *dev) | ||
167 | { | ||
168 | int ret; | ||
169 | ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, | ||
170 | dev->net->dev_addr); | ||
171 | if (ret < 0) | ||
172 | return ret; | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int mcs7830_read_phy(struct usbnet *dev, u8 index) | ||
177 | { | ||
178 | int ret; | ||
179 | int i; | ||
180 | __le16 val; | ||
181 | |||
182 | u8 cmd[2] = { | ||
183 | HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, | ||
184 | HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, | ||
185 | }; | ||
186 | |||
187 | mutex_lock(&dev->phy_mutex); | ||
188 | /* write the MII command */ | ||
189 | ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
190 | if (ret < 0) | ||
191 | goto out; | ||
192 | |||
193 | /* wait for the data to become valid, should be within < 1ms */ | ||
194 | for (i = 0; i < 10; i++) { | ||
195 | ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
196 | if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) | ||
197 | break; | ||
198 | ret = -EIO; | ||
199 | msleep(1); | ||
200 | } | ||
201 | if (ret < 0) | ||
202 | goto out; | ||
203 | |||
204 | /* read actual register contents */ | ||
205 | ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); | ||
206 | if (ret < 0) | ||
207 | goto out; | ||
208 | ret = le16_to_cpu(val); | ||
209 | dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", | ||
210 | index, val, i); | ||
211 | out: | ||
212 | mutex_unlock(&dev->phy_mutex); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) | ||
217 | { | ||
218 | int ret; | ||
219 | int i; | ||
220 | __le16 le_val; | ||
221 | |||
222 | u8 cmd[2] = { | ||
223 | HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, | ||
224 | HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), | ||
225 | }; | ||
226 | |||
227 | mutex_lock(&dev->phy_mutex); | ||
228 | |||
229 | /* write the new register contents */ | ||
230 | le_val = cpu_to_le16(val); | ||
231 | ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); | ||
232 | if (ret < 0) | ||
233 | goto out; | ||
234 | |||
235 | /* write the MII command */ | ||
236 | ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
237 | if (ret < 0) | ||
238 | goto out; | ||
239 | |||
240 | /* wait for the command to be accepted by the PHY */ | ||
241 | for (i = 0; i < 10; i++) { | ||
242 | ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
243 | if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) | ||
244 | break; | ||
245 | ret = -EIO; | ||
246 | msleep(1); | ||
247 | } | ||
248 | if (ret < 0) | ||
249 | goto out; | ||
250 | |||
251 | ret = 0; | ||
252 | dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", | ||
253 | index, val, i); | ||
254 | out: | ||
255 | mutex_unlock(&dev->phy_mutex); | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * This algorithm comes from the original mcs7830 version 1.4 driver, | ||
261 | * not sure if it is needed. | ||
262 | */ | ||
263 | static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) | ||
264 | { | ||
265 | int ret; | ||
266 | /* Enable all media types */ | ||
267 | ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); | ||
268 | |||
269 | /* First reset BMCR */ | ||
270 | if (!ret) | ||
271 | ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); | ||
272 | /* Enable Auto Neg */ | ||
273 | if (!ret) | ||
274 | ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); | ||
275 | /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ | ||
276 | if (!ret) | ||
277 | ret = mcs7830_write_phy(dev, MII_BMCR, | ||
278 | BMCR_ANENABLE | BMCR_ANRESTART ); | ||
279 | return ret < 0 ? : 0; | ||
280 | } | ||
281 | |||
282 | |||
283 | /* | ||
284 | * if we can read register 22, the chip revision is C or higher | ||
285 | */ | ||
286 | static int mcs7830_get_rev(struct usbnet *dev) | ||
287 | { | ||
288 | u8 dummy[2]; | ||
289 | int ret; | ||
290 | ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); | ||
291 | if (ret > 0) | ||
292 | return 2; /* Rev C or later */ | ||
293 | return 1; /* earlier revision */ | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * On rev. C we need to set the pause threshold | ||
298 | */ | ||
299 | static void mcs7830_rev_C_fixup(struct usbnet *dev) | ||
300 | { | ||
301 | u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; | ||
302 | int retry; | ||
303 | |||
304 | for (retry = 0; retry < 2; retry++) { | ||
305 | if (mcs7830_get_rev(dev) == 2) { | ||
306 | dev_info(&dev->udev->dev, "applying rev.C fixup\n"); | ||
307 | mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, | ||
308 | 1, &pause_threshold); | ||
309 | } | ||
310 | msleep(1); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static int mcs7830_init_dev(struct usbnet *dev) | ||
315 | { | ||
316 | int ret; | ||
317 | int retry; | ||
318 | |||
319 | /* Read MAC address from EEPROM */ | ||
320 | ret = -EINVAL; | ||
321 | for (retry = 0; retry < 5 && ret; retry++) | ||
322 | ret = mcs7830_get_address(dev); | ||
323 | if (ret) { | ||
324 | dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | /* Set up PHY */ | ||
329 | ret = mcs7830_set_autoneg(dev, 0); | ||
330 | if (ret) { | ||
331 | dev_info(&dev->udev->dev, "Cannot set autoneg\n"); | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | mcs7830_rev_C_fixup(dev); | ||
336 | ret = 0; | ||
337 | out: | ||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, | ||
342 | int location) | ||
343 | { | ||
344 | struct usbnet *dev = netdev->priv; | ||
345 | return mcs7830_read_phy(dev, location); | ||
346 | } | ||
347 | |||
348 | static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, | ||
349 | int location, int val) | ||
350 | { | ||
351 | struct usbnet *dev = netdev->priv; | ||
352 | mcs7830_write_phy(dev, location, val); | ||
353 | } | ||
354 | |||
355 | static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | ||
356 | { | ||
357 | struct usbnet *dev = netdev_priv(net); | ||
358 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
359 | } | ||
360 | |||
361 | /* credits go to asix_set_multicast */ | ||
362 | static void mcs7830_set_multicast(struct net_device *net) | ||
363 | { | ||
364 | struct usbnet *dev = netdev_priv(net); | ||
365 | struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; | ||
366 | |||
367 | data->config = HIF_REG_CONFIG_TXENABLE; | ||
368 | |||
369 | /* this should not be needed, but it doesn't work otherwise */ | ||
370 | data->config |= HIF_REG_CONFIG_ALLMULTICAST; | ||
371 | |||
372 | if (net->flags & IFF_PROMISC) { | ||
373 | data->config |= HIF_REG_CONFIG_PROMISCIOUS; | ||
374 | } else if (net->flags & IFF_ALLMULTI | ||
375 | || net->mc_count > MCS7830_MAX_MCAST) { | ||
376 | data->config |= HIF_REG_CONFIG_ALLMULTICAST; | ||
377 | } else if (net->mc_count == 0) { | ||
378 | /* just broadcast and directed */ | ||
379 | } else { | ||
380 | /* We use the 20 byte dev->data | ||
381 | * for our 8 byte filter buffer | ||
382 | * to avoid allocating memory that | ||
383 | * is tricky to free later */ | ||
384 | struct dev_mc_list *mc_list = net->mc_list; | ||
385 | u32 crc_bits; | ||
386 | int i; | ||
387 | |||
388 | memset(data->multi_filter, 0, sizeof data->multi_filter); | ||
389 | |||
390 | /* Build the multicast hash filter. */ | ||
391 | for (i = 0; i < net->mc_count; i++) { | ||
392 | crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; | ||
393 | data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); | ||
394 | mc_list = mc_list->next; | ||
395 | } | ||
396 | |||
397 | mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, | ||
398 | sizeof data->multi_filter, | ||
399 | data->multi_filter); | ||
400 | } | ||
401 | |||
402 | mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); | ||
403 | } | ||
404 | |||
405 | static int mcs7830_get_regs_len(struct net_device *net) | ||
406 | { | ||
407 | struct usbnet *dev = netdev_priv(net); | ||
408 | |||
409 | switch (mcs7830_get_rev(dev)) { | ||
410 | case 1: | ||
411 | return 21; | ||
412 | case 2: | ||
413 | return 32; | ||
414 | } | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) | ||
419 | { | ||
420 | usbnet_get_drvinfo(net, drvinfo); | ||
421 | drvinfo->regdump_len = mcs7830_get_regs_len(net); | ||
422 | } | ||
423 | |||
424 | static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) | ||
425 | { | ||
426 | struct usbnet *dev = netdev_priv(net); | ||
427 | |||
428 | regs->version = mcs7830_get_rev(dev); | ||
429 | mcs7830_get_reg(dev, 0, regs->len, data); | ||
430 | } | ||
431 | |||
432 | static struct ethtool_ops mcs7830_ethtool_ops = { | ||
433 | .get_drvinfo = mcs7830_get_drvinfo, | ||
434 | .get_regs_len = mcs7830_get_regs_len, | ||
435 | .get_regs = mcs7830_get_regs, | ||
436 | |||
437 | /* common usbnet calls */ | ||
438 | .get_link = usbnet_get_link, | ||
439 | .get_msglevel = usbnet_get_msglevel, | ||
440 | .set_msglevel = usbnet_set_msglevel, | ||
441 | .get_settings = usbnet_get_settings, | ||
442 | .set_settings = usbnet_set_settings, | ||
443 | .nway_reset = usbnet_nway_reset, | ||
444 | }; | ||
445 | |||
446 | static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) | ||
447 | { | ||
448 | struct net_device *net = dev->net; | ||
449 | int ret; | ||
450 | |||
451 | ret = mcs7830_init_dev(dev); | ||
452 | if (ret) | ||
453 | goto out; | ||
454 | |||
455 | net->do_ioctl = mcs7830_ioctl; | ||
456 | net->ethtool_ops = &mcs7830_ethtool_ops; | ||
457 | net->set_multicast_list = mcs7830_set_multicast; | ||
458 | mcs7830_set_multicast(net); | ||
459 | |||
460 | /* reserve space for the status byte on rx */ | ||
461 | dev->rx_urb_size = ETH_FRAME_LEN + 1; | ||
462 | |||
463 | dev->mii.mdio_read = mcs7830_mdio_read; | ||
464 | dev->mii.mdio_write = mcs7830_mdio_write; | ||
465 | dev->mii.dev = net; | ||
466 | dev->mii.phy_id_mask = 0x3f; | ||
467 | dev->mii.reg_num_mask = 0x1f; | ||
468 | dev->mii.phy_id = *((u8 *) net->dev_addr + 1); | ||
469 | |||
470 | ret = usbnet_get_endpoints(dev, udev); | ||
471 | out: | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | /* The chip always appends a status bytes that we need to strip */ | ||
476 | static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
477 | { | ||
478 | u8 status; | ||
479 | |||
480 | if (skb->len == 0) { | ||
481 | dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | skb_trim(skb, skb->len - 1); | ||
486 | status = skb->data[skb->len]; | ||
487 | |||
488 | if (status != 0x20) | ||
489 | dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); | ||
490 | |||
491 | return skb->len > 0; | ||
492 | } | ||
493 | |||
494 | static const struct driver_info moschip_info = { | ||
495 | .description = "MOSCHIP 7830 usb-NET adapter", | ||
496 | .bind = mcs7830_bind, | ||
497 | .rx_fixup = mcs7830_rx_fixup, | ||
498 | .flags = FLAG_ETHER, | ||
499 | .in = 1, | ||
500 | .out = 2, | ||
501 | }; | ||
502 | |||
503 | static const struct usb_device_id products[] = { | ||
504 | { | ||
505 | USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), | ||
506 | .driver_info = (unsigned long) &moschip_info, | ||
507 | }, | ||
508 | {}, | ||
509 | }; | ||
510 | MODULE_DEVICE_TABLE(usb, products); | ||
511 | |||
512 | static struct usb_driver mcs7830_driver = { | ||
513 | .name = driver_name, | ||
514 | .id_table = products, | ||
515 | .probe = usbnet_probe, | ||
516 | .disconnect = usbnet_disconnect, | ||
517 | .suspend = usbnet_suspend, | ||
518 | .resume = usbnet_resume, | ||
519 | }; | ||
520 | |||
521 | static int __init mcs7830_init(void) | ||
522 | { | ||
523 | return usb_register(&mcs7830_driver); | ||
524 | } | ||
525 | module_init(mcs7830_init); | ||
526 | |||
527 | static void __exit mcs7830_exit(void) | ||
528 | { | ||
529 | usb_deregister(&mcs7830_driver); | ||
530 | } | ||
531 | module_exit(mcs7830_exit); | ||
532 | |||
533 | MODULE_DESCRIPTION("USB to network adapter MCS7830)"); | ||
534 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c new file mode 100644 index 000000000000..19bf8dae70c9 --- /dev/null +++ b/drivers/net/usb/net1080.c | |||
@@ -0,0 +1,615 @@ | |||
1 | /* | ||
2 | * Net1080 based USB host-to-host cables | ||
3 | * Copyright (C) 2000-2005 by David Brownell | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | // #define DEBUG // error path messages, extra info | ||
21 | // #define VERBOSE // more; success messages | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/ethtool.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/mii.h> | ||
30 | #include <linux/usb.h> | ||
31 | |||
32 | #include <asm/unaligned.h> | ||
33 | |||
34 | #include "usbnet.h" | ||
35 | |||
36 | |||
37 | /* | ||
38 | * Netchip 1080 driver ... http://www.netchip.com | ||
39 | * (Sept 2004: End-of-life announcement has been sent.) | ||
40 | * Used in (some) LapLink cables | ||
41 | */ | ||
42 | |||
43 | #define frame_errors data[1] | ||
44 | |||
45 | /* | ||
46 | * NetChip framing of ethernet packets, supporting additional error | ||
47 | * checks for links that may drop bulk packets from inside messages. | ||
48 | * Odd USB length == always short read for last usb packet. | ||
49 | * - nc_header | ||
50 | * - Ethernet header (14 bytes) | ||
51 | * - payload | ||
52 | * - (optional padding byte, if needed so length becomes odd) | ||
53 | * - nc_trailer | ||
54 | * | ||
55 | * This framing is to be avoided for non-NetChip devices. | ||
56 | */ | ||
57 | |||
58 | struct nc_header { // packed: | ||
59 | __le16 hdr_len; // sizeof nc_header (LE, all) | ||
60 | __le16 packet_len; // payload size (including ethhdr) | ||
61 | __le16 packet_id; // detects dropped packets | ||
62 | #define MIN_HEADER 6 | ||
63 | |||
64 | // all else is optional, and must start with: | ||
65 | // __le16 vendorId; // from usb-if | ||
66 | // __le16 productId; | ||
67 | } __attribute__((__packed__)); | ||
68 | |||
69 | #define PAD_BYTE ((unsigned char)0xAC) | ||
70 | |||
71 | struct nc_trailer { | ||
72 | __le16 packet_id; | ||
73 | } __attribute__((__packed__)); | ||
74 | |||
75 | // packets may use FLAG_FRAMING_NC and optional pad | ||
76 | #define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ | ||
77 | + sizeof (struct ethhdr) \ | ||
78 | + (mtu) \ | ||
79 | + 1 \ | ||
80 | + sizeof (struct nc_trailer)) | ||
81 | |||
82 | #define MIN_FRAMED FRAMED_SIZE(0) | ||
83 | |||
84 | /* packets _could_ be up to 64KB... */ | ||
85 | #define NC_MAX_PACKET 32767 | ||
86 | |||
87 | |||
88 | /* | ||
89 | * Zero means no timeout; else, how long a 64 byte bulk packet may be queued | ||
90 | * before the hardware drops it. If that's done, the driver will need to | ||
91 | * frame network packets to guard against the dropped USB packets. The win32 | ||
92 | * driver sets this for both sides of the link. | ||
93 | */ | ||
94 | #define NC_READ_TTL_MS ((u8)255) // ms | ||
95 | |||
96 | /* | ||
97 | * We ignore most registers and EEPROM contents. | ||
98 | */ | ||
99 | #define REG_USBCTL ((u8)0x04) | ||
100 | #define REG_TTL ((u8)0x10) | ||
101 | #define REG_STATUS ((u8)0x11) | ||
102 | |||
103 | /* | ||
104 | * Vendor specific requests to read/write data | ||
105 | */ | ||
106 | #define REQUEST_REGISTER ((u8)0x10) | ||
107 | #define REQUEST_EEPROM ((u8)0x11) | ||
108 | |||
109 | static int | ||
110 | nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr) | ||
111 | { | ||
112 | int status = usb_control_msg(dev->udev, | ||
113 | usb_rcvctrlpipe(dev->udev, 0), | ||
114 | req, | ||
115 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
116 | 0, regnum, | ||
117 | retval_ptr, sizeof *retval_ptr, | ||
118 | USB_CTRL_GET_TIMEOUT); | ||
119 | if (status > 0) | ||
120 | status = 0; | ||
121 | if (!status) | ||
122 | le16_to_cpus(retval_ptr); | ||
123 | return status; | ||
124 | } | ||
125 | |||
126 | static inline int | ||
127 | nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr) | ||
128 | { | ||
129 | return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr); | ||
130 | } | ||
131 | |||
132 | // no retval ... can become async, usable in_interrupt() | ||
133 | static void | ||
134 | nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value) | ||
135 | { | ||
136 | usb_control_msg(dev->udev, | ||
137 | usb_sndctrlpipe(dev->udev, 0), | ||
138 | req, | ||
139 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
140 | value, regnum, | ||
141 | NULL, 0, // data is in setup packet | ||
142 | USB_CTRL_SET_TIMEOUT); | ||
143 | } | ||
144 | |||
145 | static inline void | ||
146 | nc_register_write(struct usbnet *dev, u8 regnum, u16 value) | ||
147 | { | ||
148 | nc_vendor_write(dev, REQUEST_REGISTER, regnum, value); | ||
149 | } | ||
150 | |||
151 | |||
152 | #if 0 | ||
153 | static void nc_dump_registers(struct usbnet *dev) | ||
154 | { | ||
155 | u8 reg; | ||
156 | u16 *vp = kmalloc(sizeof (u16)); | ||
157 | |||
158 | if (!vp) { | ||
159 | dbg("no memory?"); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | dbg("%s registers:", dev->net->name); | ||
164 | for (reg = 0; reg < 0x20; reg++) { | ||
165 | int retval; | ||
166 | |||
167 | // reading some registers is trouble | ||
168 | if (reg >= 0x08 && reg <= 0xf) | ||
169 | continue; | ||
170 | if (reg >= 0x12 && reg <= 0x1e) | ||
171 | continue; | ||
172 | |||
173 | retval = nc_register_read(dev, reg, vp); | ||
174 | if (retval < 0) | ||
175 | dbg("%s reg [0x%x] ==> error %d", | ||
176 | dev->net->name, reg, retval); | ||
177 | else | ||
178 | dbg("%s reg [0x%x] = 0x%x", | ||
179 | dev->net->name, reg, *vp); | ||
180 | } | ||
181 | kfree(vp); | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | |||
186 | /*-------------------------------------------------------------------------*/ | ||
187 | |||
188 | /* | ||
189 | * Control register | ||
190 | */ | ||
191 | |||
192 | #define USBCTL_WRITABLE_MASK 0x1f0f | ||
193 | // bits 15-13 reserved, r/o | ||
194 | #define USBCTL_ENABLE_LANG (1 << 12) | ||
195 | #define USBCTL_ENABLE_MFGR (1 << 11) | ||
196 | #define USBCTL_ENABLE_PROD (1 << 10) | ||
197 | #define USBCTL_ENABLE_SERIAL (1 << 9) | ||
198 | #define USBCTL_ENABLE_DEFAULTS (1 << 8) | ||
199 | // bits 7-4 reserved, r/o | ||
200 | #define USBCTL_FLUSH_OTHER (1 << 3) | ||
201 | #define USBCTL_FLUSH_THIS (1 << 2) | ||
202 | #define USBCTL_DISCONN_OTHER (1 << 1) | ||
203 | #define USBCTL_DISCONN_THIS (1 << 0) | ||
204 | |||
205 | static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl) | ||
206 | { | ||
207 | if (!netif_msg_link(dev)) | ||
208 | return; | ||
209 | devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;" | ||
210 | " this%s%s;" | ||
211 | " other%s%s; r/o 0x%x", | ||
212 | dev->udev->bus->bus_name, dev->udev->devpath, | ||
213 | usbctl, | ||
214 | (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", | ||
215 | (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", | ||
216 | (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", | ||
217 | (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", | ||
218 | (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", | ||
219 | |||
220 | (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", | ||
221 | (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", | ||
222 | (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", | ||
223 | (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", | ||
224 | usbctl & ~USBCTL_WRITABLE_MASK | ||
225 | ); | ||
226 | } | ||
227 | |||
228 | /*-------------------------------------------------------------------------*/ | ||
229 | |||
230 | /* | ||
231 | * Status register | ||
232 | */ | ||
233 | |||
234 | #define STATUS_PORT_A (1 << 15) | ||
235 | |||
236 | #define STATUS_CONN_OTHER (1 << 14) | ||
237 | #define STATUS_SUSPEND_OTHER (1 << 13) | ||
238 | #define STATUS_MAILBOX_OTHER (1 << 12) | ||
239 | #define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03) | ||
240 | |||
241 | #define STATUS_CONN_THIS (1 << 6) | ||
242 | #define STATUS_SUSPEND_THIS (1 << 5) | ||
243 | #define STATUS_MAILBOX_THIS (1 << 4) | ||
244 | #define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03) | ||
245 | |||
246 | #define STATUS_UNSPEC_MASK 0x0c8c | ||
247 | #define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) | ||
248 | |||
249 | |||
250 | static inline void nc_dump_status(struct usbnet *dev, u16 status) | ||
251 | { | ||
252 | if (!netif_msg_link(dev)) | ||
253 | return; | ||
254 | devdbg(dev, "net1080 %s-%s status 0x%x:" | ||
255 | " this (%c) PKT=%d%s%s%s;" | ||
256 | " other PKT=%d%s%s%s; unspec 0x%x", | ||
257 | dev->udev->bus->bus_name, dev->udev->devpath, | ||
258 | status, | ||
259 | |||
260 | // XXX the packet counts don't seem right | ||
261 | // (1 at reset, not 0); maybe UNSPEC too | ||
262 | |||
263 | (status & STATUS_PORT_A) ? 'A' : 'B', | ||
264 | STATUS_PACKETS_THIS(status), | ||
265 | (status & STATUS_CONN_THIS) ? " CON" : "", | ||
266 | (status & STATUS_SUSPEND_THIS) ? " SUS" : "", | ||
267 | (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", | ||
268 | |||
269 | STATUS_PACKETS_OTHER(status), | ||
270 | (status & STATUS_CONN_OTHER) ? " CON" : "", | ||
271 | (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", | ||
272 | (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", | ||
273 | |||
274 | status & STATUS_UNSPEC_MASK | ||
275 | ); | ||
276 | } | ||
277 | |||
278 | /*-------------------------------------------------------------------------*/ | ||
279 | |||
280 | /* | ||
281 | * TTL register | ||
282 | */ | ||
283 | |||
284 | #define TTL_THIS(ttl) (0x00ff & ttl) | ||
285 | #define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) | ||
286 | #define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) | ||
287 | |||
288 | static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) | ||
289 | { | ||
290 | if (netif_msg_link(dev)) | ||
291 | devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d", | ||
292 | dev->udev->bus->bus_name, dev->udev->devpath, | ||
293 | ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); | ||
294 | } | ||
295 | |||
296 | /*-------------------------------------------------------------------------*/ | ||
297 | |||
298 | static int net1080_reset(struct usbnet *dev) | ||
299 | { | ||
300 | u16 usbctl, status, ttl; | ||
301 | u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); | ||
302 | int retval; | ||
303 | |||
304 | if (!vp) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | // nc_dump_registers(dev); | ||
308 | |||
309 | if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) { | ||
310 | dbg("can't read %s-%s status: %d", | ||
311 | dev->udev->bus->bus_name, dev->udev->devpath, retval); | ||
312 | goto done; | ||
313 | } | ||
314 | status = *vp; | ||
315 | nc_dump_status(dev, status); | ||
316 | |||
317 | if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) { | ||
318 | dbg("can't read USBCTL, %d", retval); | ||
319 | goto done; | ||
320 | } | ||
321 | usbctl = *vp; | ||
322 | nc_dump_usbctl(dev, usbctl); | ||
323 | |||
324 | nc_register_write(dev, REG_USBCTL, | ||
325 | USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); | ||
326 | |||
327 | if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) { | ||
328 | dbg("can't read TTL, %d", retval); | ||
329 | goto done; | ||
330 | } | ||
331 | ttl = *vp; | ||
332 | // nc_dump_ttl(dev, ttl); | ||
333 | |||
334 | nc_register_write(dev, REG_TTL, | ||
335 | MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); | ||
336 | dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS); | ||
337 | |||
338 | if (netif_msg_link(dev)) | ||
339 | devinfo(dev, "port %c, peer %sconnected", | ||
340 | (status & STATUS_PORT_A) ? 'A' : 'B', | ||
341 | (status & STATUS_CONN_OTHER) ? "" : "dis" | ||
342 | ); | ||
343 | retval = 0; | ||
344 | |||
345 | done: | ||
346 | kfree(vp); | ||
347 | return retval; | ||
348 | } | ||
349 | |||
350 | static int net1080_check_connect(struct usbnet *dev) | ||
351 | { | ||
352 | int retval; | ||
353 | u16 status; | ||
354 | u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); | ||
355 | |||
356 | if (!vp) | ||
357 | return -ENOMEM; | ||
358 | retval = nc_register_read(dev, REG_STATUS, vp); | ||
359 | status = *vp; | ||
360 | kfree(vp); | ||
361 | if (retval != 0) { | ||
362 | dbg("%s net1080_check_conn read - %d", dev->net->name, retval); | ||
363 | return retval; | ||
364 | } | ||
365 | if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) | ||
366 | return -ENOLINK; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static void nc_flush_complete(struct urb *urb) | ||
371 | { | ||
372 | kfree(urb->context); | ||
373 | usb_free_urb(urb); | ||
374 | } | ||
375 | |||
376 | static void nc_ensure_sync(struct usbnet *dev) | ||
377 | { | ||
378 | dev->frame_errors++; | ||
379 | if (dev->frame_errors > 5) { | ||
380 | struct urb *urb; | ||
381 | struct usb_ctrlrequest *req; | ||
382 | int status; | ||
383 | |||
384 | /* Send a flush */ | ||
385 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
386 | if (!urb) | ||
387 | return; | ||
388 | |||
389 | req = kmalloc(sizeof *req, GFP_ATOMIC); | ||
390 | if (!req) { | ||
391 | usb_free_urb(urb); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | req->bRequestType = USB_DIR_OUT | ||
396 | | USB_TYPE_VENDOR | ||
397 | | USB_RECIP_DEVICE; | ||
398 | req->bRequest = REQUEST_REGISTER; | ||
399 | req->wValue = cpu_to_le16(USBCTL_FLUSH_THIS | ||
400 | | USBCTL_FLUSH_OTHER); | ||
401 | req->wIndex = cpu_to_le16(REG_USBCTL); | ||
402 | req->wLength = cpu_to_le16(0); | ||
403 | |||
404 | /* queue an async control request, we don't need | ||
405 | * to do anything when it finishes except clean up. | ||
406 | */ | ||
407 | usb_fill_control_urb(urb, dev->udev, | ||
408 | usb_sndctrlpipe(dev->udev, 0), | ||
409 | (unsigned char *) req, | ||
410 | NULL, 0, | ||
411 | nc_flush_complete, req); | ||
412 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
413 | if (status) { | ||
414 | kfree(req); | ||
415 | usb_free_urb(urb); | ||
416 | return; | ||
417 | } | ||
418 | |||
419 | if (netif_msg_rx_err(dev)) | ||
420 | devdbg(dev, "flush net1080; too many framing errors"); | ||
421 | dev->frame_errors = 0; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
426 | { | ||
427 | struct nc_header *header; | ||
428 | struct nc_trailer *trailer; | ||
429 | u16 hdr_len, packet_len; | ||
430 | |||
431 | if (!(skb->len & 0x01)) { | ||
432 | #ifdef DEBUG | ||
433 | struct net_device *net = dev->net; | ||
434 | dbg("rx framesize %d range %d..%d mtu %d", skb->len, | ||
435 | net->hard_header_len, dev->hard_mtu, net->mtu); | ||
436 | #endif | ||
437 | dev->stats.rx_frame_errors++; | ||
438 | nc_ensure_sync(dev); | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | header = (struct nc_header *) skb->data; | ||
443 | hdr_len = le16_to_cpup(&header->hdr_len); | ||
444 | packet_len = le16_to_cpup(&header->packet_len); | ||
445 | if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) { | ||
446 | dev->stats.rx_frame_errors++; | ||
447 | dbg("packet too big, %d", packet_len); | ||
448 | nc_ensure_sync(dev); | ||
449 | return 0; | ||
450 | } else if (hdr_len < MIN_HEADER) { | ||
451 | dev->stats.rx_frame_errors++; | ||
452 | dbg("header too short, %d", hdr_len); | ||
453 | nc_ensure_sync(dev); | ||
454 | return 0; | ||
455 | } else if (hdr_len > MIN_HEADER) { | ||
456 | // out of band data for us? | ||
457 | dbg("header OOB, %d bytes", hdr_len - MIN_HEADER); | ||
458 | nc_ensure_sync(dev); | ||
459 | // switch (vendor/product ids) { ... } | ||
460 | } | ||
461 | skb_pull(skb, hdr_len); | ||
462 | |||
463 | trailer = (struct nc_trailer *) | ||
464 | (skb->data + skb->len - sizeof *trailer); | ||
465 | skb_trim(skb, skb->len - sizeof *trailer); | ||
466 | |||
467 | if ((packet_len & 0x01) == 0) { | ||
468 | if (skb->data [packet_len] != PAD_BYTE) { | ||
469 | dev->stats.rx_frame_errors++; | ||
470 | dbg("bad pad"); | ||
471 | return 0; | ||
472 | } | ||
473 | skb_trim(skb, skb->len - 1); | ||
474 | } | ||
475 | if (skb->len != packet_len) { | ||
476 | dev->stats.rx_frame_errors++; | ||
477 | dbg("bad packet len %d (expected %d)", | ||
478 | skb->len, packet_len); | ||
479 | nc_ensure_sync(dev); | ||
480 | return 0; | ||
481 | } | ||
482 | if (header->packet_id != get_unaligned(&trailer->packet_id)) { | ||
483 | dev->stats.rx_fifo_errors++; | ||
484 | dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", | ||
485 | le16_to_cpu(header->packet_id), | ||
486 | le16_to_cpu(trailer->packet_id)); | ||
487 | return 0; | ||
488 | } | ||
489 | #if 0 | ||
490 | devdbg(dev, "frame <rx h %d p %d id %d", header->hdr_len, | ||
491 | header->packet_len, header->packet_id); | ||
492 | #endif | ||
493 | dev->frame_errors = 0; | ||
494 | return 1; | ||
495 | } | ||
496 | |||
497 | static struct sk_buff * | ||
498 | net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | ||
499 | { | ||
500 | struct sk_buff *skb2; | ||
501 | struct nc_header *header = NULL; | ||
502 | struct nc_trailer *trailer = NULL; | ||
503 | int padlen = sizeof (struct nc_trailer); | ||
504 | int len = skb->len; | ||
505 | |||
506 | if (!((len + padlen + sizeof (struct nc_header)) & 0x01)) | ||
507 | padlen++; | ||
508 | if (!skb_cloned(skb)) { | ||
509 | int headroom = skb_headroom(skb); | ||
510 | int tailroom = skb_tailroom(skb); | ||
511 | |||
512 | if (padlen <= tailroom && | ||
513 | sizeof(struct nc_header) <= headroom) | ||
514 | /* There's enough head and tail room */ | ||
515 | goto encapsulate; | ||
516 | |||
517 | if ((sizeof (struct nc_header) + padlen) < | ||
518 | (headroom + tailroom)) { | ||
519 | /* There's enough total room, so just readjust */ | ||
520 | skb->data = memmove(skb->head | ||
521 | + sizeof (struct nc_header), | ||
522 | skb->data, skb->len); | ||
523 | skb_set_tail_pointer(skb, len); | ||
524 | goto encapsulate; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | /* Create a new skb to use with the correct size */ | ||
529 | skb2 = skb_copy_expand(skb, | ||
530 | sizeof (struct nc_header), | ||
531 | padlen, | ||
532 | flags); | ||
533 | dev_kfree_skb_any(skb); | ||
534 | if (!skb2) | ||
535 | return skb2; | ||
536 | skb = skb2; | ||
537 | |||
538 | encapsulate: | ||
539 | /* header first */ | ||
540 | header = (struct nc_header *) skb_push(skb, sizeof *header); | ||
541 | header->hdr_len = cpu_to_le16(sizeof (*header)); | ||
542 | header->packet_len = cpu_to_le16(len); | ||
543 | header->packet_id = cpu_to_le16((u16)dev->xid++); | ||
544 | |||
545 | /* maybe pad; then trailer */ | ||
546 | if (!((skb->len + sizeof *trailer) & 0x01)) | ||
547 | *skb_put(skb, 1) = PAD_BYTE; | ||
548 | trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer); | ||
549 | put_unaligned(header->packet_id, &trailer->packet_id); | ||
550 | #if 0 | ||
551 | devdbg(dev, "frame >tx h %d p %d id %d", | ||
552 | header->hdr_len, header->packet_len, | ||
553 | header->packet_id); | ||
554 | #endif | ||
555 | return skb; | ||
556 | } | ||
557 | |||
558 | static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) | ||
559 | { | ||
560 | unsigned extra = sizeof (struct nc_header) | ||
561 | + 1 | ||
562 | + sizeof (struct nc_trailer); | ||
563 | |||
564 | dev->net->hard_header_len += extra; | ||
565 | dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; | ||
566 | dev->hard_mtu = NC_MAX_PACKET; | ||
567 | return usbnet_get_endpoints (dev, intf); | ||
568 | } | ||
569 | |||
570 | static const struct driver_info net1080_info = { | ||
571 | .description = "NetChip TurboCONNECT", | ||
572 | .flags = FLAG_FRAMING_NC, | ||
573 | .bind = net1080_bind, | ||
574 | .reset = net1080_reset, | ||
575 | .check_connect = net1080_check_connect, | ||
576 | .rx_fixup = net1080_rx_fixup, | ||
577 | .tx_fixup = net1080_tx_fixup, | ||
578 | }; | ||
579 | |||
580 | static const struct usb_device_id products [] = { | ||
581 | { | ||
582 | USB_DEVICE(0x0525, 0x1080), // NetChip ref design | ||
583 | .driver_info = (unsigned long) &net1080_info, | ||
584 | }, { | ||
585 | USB_DEVICE(0x06D0, 0x0622), // Laplink Gold | ||
586 | .driver_info = (unsigned long) &net1080_info, | ||
587 | }, | ||
588 | { }, // END | ||
589 | }; | ||
590 | MODULE_DEVICE_TABLE(usb, products); | ||
591 | |||
592 | static struct usb_driver net1080_driver = { | ||
593 | .name = "net1080", | ||
594 | .id_table = products, | ||
595 | .probe = usbnet_probe, | ||
596 | .disconnect = usbnet_disconnect, | ||
597 | .suspend = usbnet_suspend, | ||
598 | .resume = usbnet_resume, | ||
599 | }; | ||
600 | |||
601 | static int __init net1080_init(void) | ||
602 | { | ||
603 | return usb_register(&net1080_driver); | ||
604 | } | ||
605 | module_init(net1080_init); | ||
606 | |||
607 | static void __exit net1080_exit(void) | ||
608 | { | ||
609 | usb_deregister(&net1080_driver); | ||
610 | } | ||
611 | module_exit(net1080_exit); | ||
612 | |||
613 | MODULE_AUTHOR("David Brownell"); | ||
614 | MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links"); | ||
615 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c new file mode 100644 index 000000000000..a05fd97e5bc2 --- /dev/null +++ b/drivers/net/usb/pegasus.c | |||
@@ -0,0 +1,1504 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net) | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * ChangeLog: | ||
9 | * .... Most of the time spent on reading sources & docs. | ||
10 | * v0.2.x First official release for the Linux kernel. | ||
11 | * v0.3.0 Beutified and structured, some bugs fixed. | ||
12 | * v0.3.x URBifying bulk requests and bugfixing. First relatively | ||
13 | * stable release. Still can touch device's registers only | ||
14 | * from top-halves. | ||
15 | * v0.4.0 Control messages remained unurbified are now URBs. | ||
16 | * Now we can touch the HW at any time. | ||
17 | * v0.4.9 Control urbs again use process context to wait. Argh... | ||
18 | * Some long standing bugs (enable_net_traffic) fixed. | ||
19 | * Also nasty trick about resubmiting control urb from | ||
20 | * interrupt context used. Please let me know how it | ||
21 | * behaves. Pegasus II support added since this version. | ||
22 | * TODO: suppressing HCD warnings spewage on disconnect. | ||
23 | * v0.4.13 Ethernet address is now set at probe(), not at open() | ||
24 | * time as this seems to break dhcpd. | ||
25 | * v0.5.0 branch to 2.5.x kernels | ||
26 | * v0.5.1 ethtool support added | ||
27 | * v0.5.5 rx socket buffers are in a pool and the their allocation | ||
28 | * is out of the interrupt routine. | ||
29 | */ | ||
30 | |||
31 | #include <linux/sched.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/netdevice.h> | ||
36 | #include <linux/etherdevice.h> | ||
37 | #include <linux/ethtool.h> | ||
38 | #include <linux/mii.h> | ||
39 | #include <linux/usb.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <asm/byteorder.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include "pegasus.h" | ||
44 | |||
45 | /* | ||
46 | * Version Information | ||
47 | */ | ||
48 | #define DRIVER_VERSION "v0.6.14 (2006/09/27)" | ||
49 | #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" | ||
50 | #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" | ||
51 | |||
52 | static const char driver_name[] = "pegasus"; | ||
53 | |||
54 | #undef PEGASUS_WRITE_EEPROM | ||
55 | #define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ | ||
56 | BMSR_100FULL | BMSR_ANEGCAPABLE) | ||
57 | |||
58 | static int loopback = 0; | ||
59 | static int mii_mode = 0; | ||
60 | static char *devid=NULL; | ||
61 | |||
62 | static struct usb_eth_dev usb_dev_id[] = { | ||
63 | #define PEGASUS_DEV(pn, vid, pid, flags) \ | ||
64 | {.name = pn, .vendor = vid, .device = pid, .private = flags}, | ||
65 | #include "pegasus.h" | ||
66 | #undef PEGASUS_DEV | ||
67 | {NULL, 0, 0, 0}, | ||
68 | {NULL, 0, 0, 0} | ||
69 | }; | ||
70 | |||
71 | static struct usb_device_id pegasus_ids[] = { | ||
72 | #define PEGASUS_DEV(pn, vid, pid, flags) \ | ||
73 | {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid}, | ||
74 | #include "pegasus.h" | ||
75 | #undef PEGASUS_DEV | ||
76 | {}, | ||
77 | {} | ||
78 | }; | ||
79 | |||
80 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
81 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
82 | MODULE_LICENSE("GPL"); | ||
83 | module_param(loopback, bool, 0); | ||
84 | module_param(mii_mode, bool, 0); | ||
85 | module_param(devid, charp, 0); | ||
86 | MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); | ||
87 | MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); | ||
88 | MODULE_PARM_DESC(devid, "The format is: 'DEV_name:VendorID:DeviceID:Flags'"); | ||
89 | |||
90 | /* use ethtool to change the level for any given device */ | ||
91 | static int msg_level = -1; | ||
92 | module_param (msg_level, int, 0); | ||
93 | MODULE_PARM_DESC (msg_level, "Override default message level"); | ||
94 | |||
95 | MODULE_DEVICE_TABLE(usb, pegasus_ids); | ||
96 | |||
97 | static int update_eth_regs_async(pegasus_t *); | ||
98 | /* Aargh!!! I _really_ hate such tweaks */ | ||
99 | static void ctrl_callback(struct urb *urb) | ||
100 | { | ||
101 | pegasus_t *pegasus = urb->context; | ||
102 | |||
103 | if (!pegasus) | ||
104 | return; | ||
105 | |||
106 | switch (urb->status) { | ||
107 | case 0: | ||
108 | if (pegasus->flags & ETH_REGS_CHANGE) { | ||
109 | pegasus->flags &= ~ETH_REGS_CHANGE; | ||
110 | pegasus->flags |= ETH_REGS_CHANGED; | ||
111 | update_eth_regs_async(pegasus); | ||
112 | return; | ||
113 | } | ||
114 | break; | ||
115 | case -EINPROGRESS: | ||
116 | return; | ||
117 | case -ENOENT: | ||
118 | break; | ||
119 | default: | ||
120 | if (netif_msg_drv(pegasus)) | ||
121 | dev_dbg(&pegasus->intf->dev, "%s, status %d\n", | ||
122 | __FUNCTION__, urb->status); | ||
123 | } | ||
124 | pegasus->flags &= ~ETH_REGS_CHANGED; | ||
125 | wake_up(&pegasus->ctrl_wait); | ||
126 | } | ||
127 | |||
128 | static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, | ||
129 | void *data) | ||
130 | { | ||
131 | int ret; | ||
132 | char *buffer; | ||
133 | DECLARE_WAITQUEUE(wait, current); | ||
134 | |||
135 | buffer = kmalloc(size, GFP_KERNEL); | ||
136 | if (!buffer) { | ||
137 | if (netif_msg_drv(pegasus)) | ||
138 | dev_warn(&pegasus->intf->dev, "out of memory in %s\n", | ||
139 | __FUNCTION__); | ||
140 | return -ENOMEM; | ||
141 | } | ||
142 | add_wait_queue(&pegasus->ctrl_wait, &wait); | ||
143 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
144 | while (pegasus->flags & ETH_REGS_CHANGED) | ||
145 | schedule(); | ||
146 | remove_wait_queue(&pegasus->ctrl_wait, &wait); | ||
147 | set_current_state(TASK_RUNNING); | ||
148 | |||
149 | pegasus->dr.bRequestType = PEGASUS_REQT_READ; | ||
150 | pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; | ||
151 | pegasus->dr.wValue = cpu_to_le16(0); | ||
152 | pegasus->dr.wIndex = cpu_to_le16p(&indx); | ||
153 | pegasus->dr.wLength = cpu_to_le16p(&size); | ||
154 | pegasus->ctrl_urb->transfer_buffer_length = size; | ||
155 | |||
156 | usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, | ||
157 | usb_rcvctrlpipe(pegasus->usb, 0), | ||
158 | (char *) &pegasus->dr, | ||
159 | buffer, size, ctrl_callback, pegasus); | ||
160 | |||
161 | add_wait_queue(&pegasus->ctrl_wait, &wait); | ||
162 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
163 | |||
164 | /* using ATOMIC, we'd never wake up if we slept */ | ||
165 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | ||
166 | set_current_state(TASK_RUNNING); | ||
167 | if (ret == -ENODEV) | ||
168 | netif_device_detach(pegasus->net); | ||
169 | if (netif_msg_drv(pegasus)) | ||
170 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | ||
171 | __FUNCTION__, ret); | ||
172 | goto out; | ||
173 | } | ||
174 | |||
175 | schedule(); | ||
176 | out: | ||
177 | remove_wait_queue(&pegasus->ctrl_wait, &wait); | ||
178 | memcpy(data, buffer, size); | ||
179 | kfree(buffer); | ||
180 | |||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, | ||
185 | void *data) | ||
186 | { | ||
187 | int ret; | ||
188 | char *buffer; | ||
189 | DECLARE_WAITQUEUE(wait, current); | ||
190 | |||
191 | buffer = kmalloc(size, GFP_KERNEL); | ||
192 | if (!buffer) { | ||
193 | if (netif_msg_drv(pegasus)) | ||
194 | dev_warn(&pegasus->intf->dev, "out of memory in %s\n", | ||
195 | __FUNCTION__); | ||
196 | return -ENOMEM; | ||
197 | } | ||
198 | memcpy(buffer, data, size); | ||
199 | |||
200 | add_wait_queue(&pegasus->ctrl_wait, &wait); | ||
201 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
202 | while (pegasus->flags & ETH_REGS_CHANGED) | ||
203 | schedule(); | ||
204 | remove_wait_queue(&pegasus->ctrl_wait, &wait); | ||
205 | set_current_state(TASK_RUNNING); | ||
206 | |||
207 | pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; | ||
208 | pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; | ||
209 | pegasus->dr.wValue = cpu_to_le16(0); | ||
210 | pegasus->dr.wIndex = cpu_to_le16p(&indx); | ||
211 | pegasus->dr.wLength = cpu_to_le16p(&size); | ||
212 | pegasus->ctrl_urb->transfer_buffer_length = size; | ||
213 | |||
214 | usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, | ||
215 | usb_sndctrlpipe(pegasus->usb, 0), | ||
216 | (char *) &pegasus->dr, | ||
217 | buffer, size, ctrl_callback, pegasus); | ||
218 | |||
219 | add_wait_queue(&pegasus->ctrl_wait, &wait); | ||
220 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
221 | |||
222 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | ||
223 | if (ret == -ENODEV) | ||
224 | netif_device_detach(pegasus->net); | ||
225 | if (netif_msg_drv(pegasus)) | ||
226 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | ||
227 | __FUNCTION__, ret); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | schedule(); | ||
232 | out: | ||
233 | remove_wait_queue(&pegasus->ctrl_wait, &wait); | ||
234 | kfree(buffer); | ||
235 | |||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) | ||
240 | { | ||
241 | int ret; | ||
242 | char *tmp; | ||
243 | DECLARE_WAITQUEUE(wait, current); | ||
244 | |||
245 | tmp = kmalloc(1, GFP_KERNEL); | ||
246 | if (!tmp) { | ||
247 | if (netif_msg_drv(pegasus)) | ||
248 | dev_warn(&pegasus->intf->dev, "out of memory in %s\n", | ||
249 | __FUNCTION__); | ||
250 | return -ENOMEM; | ||
251 | } | ||
252 | memcpy(tmp, &data, 1); | ||
253 | add_wait_queue(&pegasus->ctrl_wait, &wait); | ||
254 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
255 | while (pegasus->flags & ETH_REGS_CHANGED) | ||
256 | schedule(); | ||
257 | remove_wait_queue(&pegasus->ctrl_wait, &wait); | ||
258 | set_current_state(TASK_RUNNING); | ||
259 | |||
260 | pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; | ||
261 | pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; | ||
262 | pegasus->dr.wValue = cpu_to_le16(data); | ||
263 | pegasus->dr.wIndex = cpu_to_le16p(&indx); | ||
264 | pegasus->dr.wLength = cpu_to_le16(1); | ||
265 | pegasus->ctrl_urb->transfer_buffer_length = 1; | ||
266 | |||
267 | usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, | ||
268 | usb_sndctrlpipe(pegasus->usb, 0), | ||
269 | (char *) &pegasus->dr, | ||
270 | tmp, 1, ctrl_callback, pegasus); | ||
271 | |||
272 | add_wait_queue(&pegasus->ctrl_wait, &wait); | ||
273 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
274 | |||
275 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | ||
276 | if (ret == -ENODEV) | ||
277 | netif_device_detach(pegasus->net); | ||
278 | if (netif_msg_drv(pegasus)) | ||
279 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | ||
280 | __FUNCTION__, ret); | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | schedule(); | ||
285 | out: | ||
286 | remove_wait_queue(&pegasus->ctrl_wait, &wait); | ||
287 | kfree(tmp); | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static int update_eth_regs_async(pegasus_t * pegasus) | ||
293 | { | ||
294 | int ret; | ||
295 | |||
296 | pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; | ||
297 | pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; | ||
298 | pegasus->dr.wValue = 0; | ||
299 | pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); | ||
300 | pegasus->dr.wLength = cpu_to_le16(3); | ||
301 | pegasus->ctrl_urb->transfer_buffer_length = 3; | ||
302 | |||
303 | usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, | ||
304 | usb_sndctrlpipe(pegasus->usb, 0), | ||
305 | (char *) &pegasus->dr, | ||
306 | pegasus->eth_regs, 3, ctrl_callback, pegasus); | ||
307 | |||
308 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | ||
309 | if (ret == -ENODEV) | ||
310 | netif_device_detach(pegasus->net); | ||
311 | if (netif_msg_drv(pegasus)) | ||
312 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | ||
313 | __FUNCTION__, ret); | ||
314 | } | ||
315 | |||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | /* Returns 0 on success, error on failure */ | ||
320 | static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) | ||
321 | { | ||
322 | int i; | ||
323 | __u8 data[4] = { phy, 0, 0, indx }; | ||
324 | __le16 regdi; | ||
325 | int ret; | ||
326 | |||
327 | set_register(pegasus, PhyCtrl, 0); | ||
328 | set_registers(pegasus, PhyAddr, sizeof (data), data); | ||
329 | set_register(pegasus, PhyCtrl, (indx | PHY_READ)); | ||
330 | for (i = 0; i < REG_TIMEOUT; i++) { | ||
331 | ret = get_registers(pegasus, PhyCtrl, 1, data); | ||
332 | if (ret == -ESHUTDOWN) | ||
333 | goto fail; | ||
334 | if (data[0] & PHY_DONE) | ||
335 | break; | ||
336 | } | ||
337 | if (i < REG_TIMEOUT) { | ||
338 | ret = get_registers(pegasus, PhyData, 2, ®di); | ||
339 | *regd = le16_to_cpu(regdi); | ||
340 | return ret; | ||
341 | } | ||
342 | fail: | ||
343 | if (netif_msg_drv(pegasus)) | ||
344 | dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); | ||
345 | |||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static int mdio_read(struct net_device *dev, int phy_id, int loc) | ||
350 | { | ||
351 | pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); | ||
352 | u16 res; | ||
353 | |||
354 | read_mii_word(pegasus, phy_id, loc, &res); | ||
355 | return (int)res; | ||
356 | } | ||
357 | |||
358 | static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) | ||
359 | { | ||
360 | int i; | ||
361 | __u8 data[4] = { phy, 0, 0, indx }; | ||
362 | int ret; | ||
363 | |||
364 | data[1] = (u8) regd; | ||
365 | data[2] = (u8) (regd >> 8); | ||
366 | set_register(pegasus, PhyCtrl, 0); | ||
367 | set_registers(pegasus, PhyAddr, sizeof(data), data); | ||
368 | set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); | ||
369 | for (i = 0; i < REG_TIMEOUT; i++) { | ||
370 | ret = get_registers(pegasus, PhyCtrl, 1, data); | ||
371 | if (ret == -ESHUTDOWN) | ||
372 | goto fail; | ||
373 | if (data[0] & PHY_DONE) | ||
374 | break; | ||
375 | } | ||
376 | if (i < REG_TIMEOUT) | ||
377 | return ret; | ||
378 | |||
379 | fail: | ||
380 | if (netif_msg_drv(pegasus)) | ||
381 | dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); | ||
382 | return -ETIMEDOUT; | ||
383 | } | ||
384 | |||
385 | static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) | ||
386 | { | ||
387 | pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); | ||
388 | |||
389 | write_mii_word(pegasus, phy_id, loc, val); | ||
390 | } | ||
391 | |||
392 | static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) | ||
393 | { | ||
394 | int i; | ||
395 | __u8 tmp; | ||
396 | __le16 retdatai; | ||
397 | int ret; | ||
398 | |||
399 | set_register(pegasus, EpromCtrl, 0); | ||
400 | set_register(pegasus, EpromOffset, index); | ||
401 | set_register(pegasus, EpromCtrl, EPROM_READ); | ||
402 | |||
403 | for (i = 0; i < REG_TIMEOUT; i++) { | ||
404 | ret = get_registers(pegasus, EpromCtrl, 1, &tmp); | ||
405 | if (tmp & EPROM_DONE) | ||
406 | break; | ||
407 | if (ret == -ESHUTDOWN) | ||
408 | goto fail; | ||
409 | } | ||
410 | if (i < REG_TIMEOUT) { | ||
411 | ret = get_registers(pegasus, EpromData, 2, &retdatai); | ||
412 | *retdata = le16_to_cpu(retdatai); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | fail: | ||
417 | if (netif_msg_drv(pegasus)) | ||
418 | dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); | ||
419 | return -ETIMEDOUT; | ||
420 | } | ||
421 | |||
422 | #ifdef PEGASUS_WRITE_EEPROM | ||
423 | static inline void enable_eprom_write(pegasus_t * pegasus) | ||
424 | { | ||
425 | __u8 tmp; | ||
426 | int ret; | ||
427 | |||
428 | get_registers(pegasus, EthCtrl2, 1, &tmp); | ||
429 | set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); | ||
430 | } | ||
431 | |||
432 | static inline void disable_eprom_write(pegasus_t * pegasus) | ||
433 | { | ||
434 | __u8 tmp; | ||
435 | int ret; | ||
436 | |||
437 | get_registers(pegasus, EthCtrl2, 1, &tmp); | ||
438 | set_register(pegasus, EpromCtrl, 0); | ||
439 | set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE); | ||
440 | } | ||
441 | |||
442 | static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) | ||
443 | { | ||
444 | int i; | ||
445 | __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE }; | ||
446 | int ret; | ||
447 | |||
448 | set_registers(pegasus, EpromOffset, 4, d); | ||
449 | enable_eprom_write(pegasus); | ||
450 | set_register(pegasus, EpromOffset, index); | ||
451 | set_registers(pegasus, EpromData, 2, &data); | ||
452 | set_register(pegasus, EpromCtrl, EPROM_WRITE); | ||
453 | |||
454 | for (i = 0; i < REG_TIMEOUT; i++) { | ||
455 | ret = get_registers(pegasus, EpromCtrl, 1, &tmp); | ||
456 | if (ret == -ESHUTDOWN) | ||
457 | goto fail; | ||
458 | if (tmp & EPROM_DONE) | ||
459 | break; | ||
460 | } | ||
461 | disable_eprom_write(pegasus); | ||
462 | if (i < REG_TIMEOUT) | ||
463 | return ret; | ||
464 | fail: | ||
465 | if (netif_msg_drv(pegasus)) | ||
466 | dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); | ||
467 | return -ETIMEDOUT; | ||
468 | } | ||
469 | #endif /* PEGASUS_WRITE_EEPROM */ | ||
470 | |||
471 | static inline void get_node_id(pegasus_t * pegasus, __u8 * id) | ||
472 | { | ||
473 | int i; | ||
474 | __u16 w16; | ||
475 | |||
476 | for (i = 0; i < 3; i++) { | ||
477 | read_eprom_word(pegasus, i, &w16); | ||
478 | ((__le16 *) id)[i] = cpu_to_le16p(&w16); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | static void set_ethernet_addr(pegasus_t * pegasus) | ||
483 | { | ||
484 | __u8 node_id[6]; | ||
485 | |||
486 | if (pegasus->features & PEGASUS_II) { | ||
487 | get_registers(pegasus, 0x10, sizeof(node_id), node_id); | ||
488 | } else { | ||
489 | get_node_id(pegasus, node_id); | ||
490 | set_registers(pegasus, EthID, sizeof (node_id), node_id); | ||
491 | } | ||
492 | memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id)); | ||
493 | } | ||
494 | |||
495 | static inline int reset_mac(pegasus_t * pegasus) | ||
496 | { | ||
497 | __u8 data = 0x8; | ||
498 | int i; | ||
499 | |||
500 | set_register(pegasus, EthCtrl1, data); | ||
501 | for (i = 0; i < REG_TIMEOUT; i++) { | ||
502 | get_registers(pegasus, EthCtrl1, 1, &data); | ||
503 | if (~data & 0x08) { | ||
504 | if (loopback & 1) | ||
505 | break; | ||
506 | if (mii_mode && (pegasus->features & HAS_HOME_PNA)) | ||
507 | set_register(pegasus, Gpio1, 0x34); | ||
508 | else | ||
509 | set_register(pegasus, Gpio1, 0x26); | ||
510 | set_register(pegasus, Gpio0, pegasus->features); | ||
511 | set_register(pegasus, Gpio0, DEFAULT_GPIO_SET); | ||
512 | break; | ||
513 | } | ||
514 | } | ||
515 | if (i == REG_TIMEOUT) | ||
516 | return -ETIMEDOUT; | ||
517 | |||
518 | if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || | ||
519 | usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { | ||
520 | set_register(pegasus, Gpio0, 0x24); | ||
521 | set_register(pegasus, Gpio0, 0x26); | ||
522 | } | ||
523 | if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { | ||
524 | __u16 auxmode; | ||
525 | read_mii_word(pegasus, 3, 0x1b, &auxmode); | ||
526 | write_mii_word(pegasus, 3, 0x1b, auxmode | 4); | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) | ||
533 | { | ||
534 | __u16 linkpart; | ||
535 | __u8 data[4]; | ||
536 | pegasus_t *pegasus = netdev_priv(dev); | ||
537 | int ret; | ||
538 | |||
539 | read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); | ||
540 | data[0] = 0xc9; | ||
541 | data[1] = 0; | ||
542 | if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL)) | ||
543 | data[1] |= 0x20; /* set full duplex */ | ||
544 | if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF)) | ||
545 | data[1] |= 0x10; /* set 100 Mbps */ | ||
546 | if (mii_mode) | ||
547 | data[1] = 0; | ||
548 | data[2] = (loopback & 1) ? 0x09 : 0x01; | ||
549 | |||
550 | memcpy(pegasus->eth_regs, data, sizeof (data)); | ||
551 | ret = set_registers(pegasus, EthCtrl0, 3, data); | ||
552 | |||
553 | if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || | ||
554 | usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || | ||
555 | usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { | ||
556 | u16 auxmode; | ||
557 | read_mii_word(pegasus, 0, 0x1b, &auxmode); | ||
558 | write_mii_word(pegasus, 0, 0x1b, auxmode | 4); | ||
559 | } | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | static void fill_skb_pool(pegasus_t * pegasus) | ||
565 | { | ||
566 | int i; | ||
567 | |||
568 | for (i = 0; i < RX_SKBS; i++) { | ||
569 | if (pegasus->rx_pool[i]) | ||
570 | continue; | ||
571 | pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); | ||
572 | /* | ||
573 | ** we give up if the allocation fail. the tasklet will be | ||
574 | ** rescheduled again anyway... | ||
575 | */ | ||
576 | if (pegasus->rx_pool[i] == NULL) | ||
577 | return; | ||
578 | skb_reserve(pegasus->rx_pool[i], 2); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | static void free_skb_pool(pegasus_t * pegasus) | ||
583 | { | ||
584 | int i; | ||
585 | |||
586 | for (i = 0; i < RX_SKBS; i++) { | ||
587 | if (pegasus->rx_pool[i]) { | ||
588 | dev_kfree_skb(pegasus->rx_pool[i]); | ||
589 | pegasus->rx_pool[i] = NULL; | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | static inline struct sk_buff *pull_skb(pegasus_t * pegasus) | ||
595 | { | ||
596 | int i; | ||
597 | struct sk_buff *skb; | ||
598 | |||
599 | for (i = 0; i < RX_SKBS; i++) { | ||
600 | if (likely(pegasus->rx_pool[i] != NULL)) { | ||
601 | skb = pegasus->rx_pool[i]; | ||
602 | pegasus->rx_pool[i] = NULL; | ||
603 | return skb; | ||
604 | } | ||
605 | } | ||
606 | return NULL; | ||
607 | } | ||
608 | |||
609 | static void read_bulk_callback(struct urb *urb) | ||
610 | { | ||
611 | pegasus_t *pegasus = urb->context; | ||
612 | struct net_device *net; | ||
613 | int rx_status, count = urb->actual_length; | ||
614 | u8 *buf = urb->transfer_buffer; | ||
615 | __u16 pkt_len; | ||
616 | |||
617 | if (!pegasus) | ||
618 | return; | ||
619 | |||
620 | net = pegasus->net; | ||
621 | if (!netif_device_present(net) || !netif_running(net)) | ||
622 | return; | ||
623 | |||
624 | switch (urb->status) { | ||
625 | case 0: | ||
626 | break; | ||
627 | case -ETIME: | ||
628 | if (netif_msg_rx_err(pegasus)) | ||
629 | pr_debug("%s: reset MAC\n", net->name); | ||
630 | pegasus->flags &= ~PEGASUS_RX_BUSY; | ||
631 | break; | ||
632 | case -EPIPE: /* stall, or disconnect from TT */ | ||
633 | /* FIXME schedule work to clear the halt */ | ||
634 | if (netif_msg_rx_err(pegasus)) | ||
635 | printk(KERN_WARNING "%s: no rx stall recovery\n", | ||
636 | net->name); | ||
637 | return; | ||
638 | case -ENOENT: | ||
639 | case -ECONNRESET: | ||
640 | case -ESHUTDOWN: | ||
641 | if (netif_msg_ifdown(pegasus)) | ||
642 | pr_debug("%s: rx unlink, %d\n", net->name, urb->status); | ||
643 | return; | ||
644 | default: | ||
645 | if (netif_msg_rx_err(pegasus)) | ||
646 | pr_debug("%s: RX status %d\n", net->name, urb->status); | ||
647 | goto goon; | ||
648 | } | ||
649 | |||
650 | if (!count || count < 4) | ||
651 | goto goon; | ||
652 | |||
653 | rx_status = buf[count - 2]; | ||
654 | if (rx_status & 0x1e) { | ||
655 | if (netif_msg_rx_err(pegasus)) | ||
656 | pr_debug("%s: RX packet error %x\n", | ||
657 | net->name, rx_status); | ||
658 | pegasus->stats.rx_errors++; | ||
659 | if (rx_status & 0x06) // long or runt | ||
660 | pegasus->stats.rx_length_errors++; | ||
661 | if (rx_status & 0x08) | ||
662 | pegasus->stats.rx_crc_errors++; | ||
663 | if (rx_status & 0x10) // extra bits | ||
664 | pegasus->stats.rx_frame_errors++; | ||
665 | goto goon; | ||
666 | } | ||
667 | if (pegasus->chip == 0x8513) { | ||
668 | pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); | ||
669 | pkt_len &= 0x0fff; | ||
670 | pegasus->rx_skb->data += 2; | ||
671 | } else { | ||
672 | pkt_len = buf[count - 3] << 8; | ||
673 | pkt_len += buf[count - 4]; | ||
674 | pkt_len &= 0xfff; | ||
675 | pkt_len -= 8; | ||
676 | } | ||
677 | |||
678 | /* | ||
679 | * If the packet is unreasonably long, quietly drop it rather than | ||
680 | * kernel panicing by calling skb_put. | ||
681 | */ | ||
682 | if (pkt_len > PEGASUS_MTU) | ||
683 | goto goon; | ||
684 | |||
685 | /* | ||
686 | * at this point we are sure pegasus->rx_skb != NULL | ||
687 | * so we go ahead and pass up the packet. | ||
688 | */ | ||
689 | skb_put(pegasus->rx_skb, pkt_len); | ||
690 | pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net); | ||
691 | netif_rx(pegasus->rx_skb); | ||
692 | pegasus->stats.rx_packets++; | ||
693 | pegasus->stats.rx_bytes += pkt_len; | ||
694 | |||
695 | if (pegasus->flags & PEGASUS_UNPLUG) | ||
696 | return; | ||
697 | |||
698 | spin_lock(&pegasus->rx_pool_lock); | ||
699 | pegasus->rx_skb = pull_skb(pegasus); | ||
700 | spin_unlock(&pegasus->rx_pool_lock); | ||
701 | |||
702 | if (pegasus->rx_skb == NULL) | ||
703 | goto tl_sched; | ||
704 | goon: | ||
705 | usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, | ||
706 | usb_rcvbulkpipe(pegasus->usb, 1), | ||
707 | pegasus->rx_skb->data, PEGASUS_MTU + 8, | ||
708 | read_bulk_callback, pegasus); | ||
709 | rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); | ||
710 | if (rx_status == -ENODEV) | ||
711 | netif_device_detach(pegasus->net); | ||
712 | else if (rx_status) { | ||
713 | pegasus->flags |= PEGASUS_RX_URB_FAIL; | ||
714 | goto tl_sched; | ||
715 | } else { | ||
716 | pegasus->flags &= ~PEGASUS_RX_URB_FAIL; | ||
717 | } | ||
718 | |||
719 | return; | ||
720 | |||
721 | tl_sched: | ||
722 | tasklet_schedule(&pegasus->rx_tl); | ||
723 | } | ||
724 | |||
725 | static void rx_fixup(unsigned long data) | ||
726 | { | ||
727 | pegasus_t *pegasus; | ||
728 | unsigned long flags; | ||
729 | int status; | ||
730 | |||
731 | pegasus = (pegasus_t *) data; | ||
732 | if (pegasus->flags & PEGASUS_UNPLUG) | ||
733 | return; | ||
734 | |||
735 | spin_lock_irqsave(&pegasus->rx_pool_lock, flags); | ||
736 | fill_skb_pool(pegasus); | ||
737 | if (pegasus->flags & PEGASUS_RX_URB_FAIL) | ||
738 | if (pegasus->rx_skb) | ||
739 | goto try_again; | ||
740 | if (pegasus->rx_skb == NULL) { | ||
741 | pegasus->rx_skb = pull_skb(pegasus); | ||
742 | } | ||
743 | if (pegasus->rx_skb == NULL) { | ||
744 | if (netif_msg_rx_err(pegasus)) | ||
745 | printk(KERN_WARNING "%s: low on memory\n", | ||
746 | pegasus->net->name); | ||
747 | tasklet_schedule(&pegasus->rx_tl); | ||
748 | goto done; | ||
749 | } | ||
750 | usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, | ||
751 | usb_rcvbulkpipe(pegasus->usb, 1), | ||
752 | pegasus->rx_skb->data, PEGASUS_MTU + 8, | ||
753 | read_bulk_callback, pegasus); | ||
754 | try_again: | ||
755 | status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); | ||
756 | if (status == -ENODEV) | ||
757 | netif_device_detach(pegasus->net); | ||
758 | else if (status) { | ||
759 | pegasus->flags |= PEGASUS_RX_URB_FAIL; | ||
760 | tasklet_schedule(&pegasus->rx_tl); | ||
761 | } else { | ||
762 | pegasus->flags &= ~PEGASUS_RX_URB_FAIL; | ||
763 | } | ||
764 | done: | ||
765 | spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags); | ||
766 | } | ||
767 | |||
768 | static void write_bulk_callback(struct urb *urb) | ||
769 | { | ||
770 | pegasus_t *pegasus = urb->context; | ||
771 | struct net_device *net = pegasus->net; | ||
772 | |||
773 | if (!pegasus) | ||
774 | return; | ||
775 | |||
776 | if (!netif_device_present(net) || !netif_running(net)) | ||
777 | return; | ||
778 | |||
779 | switch (urb->status) { | ||
780 | case -EPIPE: | ||
781 | /* FIXME schedule_work() to clear the tx halt */ | ||
782 | netif_stop_queue(net); | ||
783 | if (netif_msg_tx_err(pegasus)) | ||
784 | printk(KERN_WARNING "%s: no tx stall recovery\n", | ||
785 | net->name); | ||
786 | return; | ||
787 | case -ENOENT: | ||
788 | case -ECONNRESET: | ||
789 | case -ESHUTDOWN: | ||
790 | if (netif_msg_ifdown(pegasus)) | ||
791 | pr_debug("%s: tx unlink, %d\n", net->name, urb->status); | ||
792 | return; | ||
793 | default: | ||
794 | if (netif_msg_tx_err(pegasus)) | ||
795 | pr_info("%s: TX status %d\n", net->name, urb->status); | ||
796 | /* FALL THROUGH */ | ||
797 | case 0: | ||
798 | break; | ||
799 | } | ||
800 | |||
801 | net->trans_start = jiffies; | ||
802 | netif_wake_queue(net); | ||
803 | } | ||
804 | |||
805 | static void intr_callback(struct urb *urb) | ||
806 | { | ||
807 | pegasus_t *pegasus = urb->context; | ||
808 | struct net_device *net; | ||
809 | int status; | ||
810 | |||
811 | if (!pegasus) | ||
812 | return; | ||
813 | net = pegasus->net; | ||
814 | |||
815 | switch (urb->status) { | ||
816 | case 0: | ||
817 | break; | ||
818 | case -ECONNRESET: /* unlink */ | ||
819 | case -ENOENT: | ||
820 | case -ESHUTDOWN: | ||
821 | return; | ||
822 | default: | ||
823 | /* some Pegasus-I products report LOTS of data | ||
824 | * toggle errors... avoid log spamming | ||
825 | */ | ||
826 | if (netif_msg_timer(pegasus)) | ||
827 | pr_debug("%s: intr status %d\n", net->name, | ||
828 | urb->status); | ||
829 | } | ||
830 | |||
831 | if (urb->actual_length >= 6) { | ||
832 | u8 * d = urb->transfer_buffer; | ||
833 | |||
834 | /* byte 0 == tx_status1, reg 2B */ | ||
835 | if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL | ||
836 | |LATE_COL|JABBER_TIMEOUT)) { | ||
837 | pegasus->stats.tx_errors++; | ||
838 | if (d[0] & TX_UNDERRUN) | ||
839 | pegasus->stats.tx_fifo_errors++; | ||
840 | if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT)) | ||
841 | pegasus->stats.tx_aborted_errors++; | ||
842 | if (d[0] & LATE_COL) | ||
843 | pegasus->stats.tx_window_errors++; | ||
844 | } | ||
845 | |||
846 | /* d[5].LINK_STATUS lies on some adapters. | ||
847 | * d[0].NO_CARRIER kicks in only with failed TX. | ||
848 | * ... so monitoring with MII may be safest. | ||
849 | */ | ||
850 | |||
851 | /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ | ||
852 | pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; | ||
853 | } | ||
854 | |||
855 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
856 | if (status == -ENODEV) | ||
857 | netif_device_detach(pegasus->net); | ||
858 | if (status && netif_msg_timer(pegasus)) | ||
859 | printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", | ||
860 | net->name, status); | ||
861 | } | ||
862 | |||
863 | static void pegasus_tx_timeout(struct net_device *net) | ||
864 | { | ||
865 | pegasus_t *pegasus = netdev_priv(net); | ||
866 | if (netif_msg_timer(pegasus)) | ||
867 | printk(KERN_WARNING "%s: tx timeout\n", net->name); | ||
868 | usb_unlink_urb(pegasus->tx_urb); | ||
869 | pegasus->stats.tx_errors++; | ||
870 | } | ||
871 | |||
872 | static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) | ||
873 | { | ||
874 | pegasus_t *pegasus = netdev_priv(net); | ||
875 | int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; | ||
876 | int res; | ||
877 | __u16 l16 = skb->len; | ||
878 | |||
879 | netif_stop_queue(net); | ||
880 | |||
881 | ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); | ||
882 | skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len); | ||
883 | usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, | ||
884 | usb_sndbulkpipe(pegasus->usb, 2), | ||
885 | pegasus->tx_buff, count, | ||
886 | write_bulk_callback, pegasus); | ||
887 | if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) { | ||
888 | if (netif_msg_tx_err(pegasus)) | ||
889 | printk(KERN_WARNING "%s: fail tx, %d\n", | ||
890 | net->name, res); | ||
891 | switch (res) { | ||
892 | case -EPIPE: /* stall, or disconnect from TT */ | ||
893 | /* cleanup should already have been scheduled */ | ||
894 | break; | ||
895 | case -ENODEV: /* disconnect() upcoming */ | ||
896 | netif_device_detach(pegasus->net); | ||
897 | break; | ||
898 | default: | ||
899 | pegasus->stats.tx_errors++; | ||
900 | netif_start_queue(net); | ||
901 | } | ||
902 | } else { | ||
903 | pegasus->stats.tx_packets++; | ||
904 | pegasus->stats.tx_bytes += skb->len; | ||
905 | net->trans_start = jiffies; | ||
906 | } | ||
907 | dev_kfree_skb(skb); | ||
908 | |||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) | ||
913 | { | ||
914 | return &((pegasus_t *) netdev_priv(dev))->stats; | ||
915 | } | ||
916 | |||
917 | static inline void disable_net_traffic(pegasus_t * pegasus) | ||
918 | { | ||
919 | int tmp = 0; | ||
920 | |||
921 | set_registers(pegasus, EthCtrl0, 2, &tmp); | ||
922 | } | ||
923 | |||
924 | static inline void get_interrupt_interval(pegasus_t * pegasus) | ||
925 | { | ||
926 | __u8 data[2]; | ||
927 | |||
928 | read_eprom_word(pegasus, 4, (__u16 *) data); | ||
929 | if (pegasus->usb->speed != USB_SPEED_HIGH) { | ||
930 | if (data[1] < 0x80) { | ||
931 | if (netif_msg_timer(pegasus)) | ||
932 | dev_info(&pegasus->intf->dev, "intr interval " | ||
933 | "changed from %ums to %ums\n", | ||
934 | data[1], 0x80); | ||
935 | data[1] = 0x80; | ||
936 | #ifdef PEGASUS_WRITE_EEPROM | ||
937 | write_eprom_word(pegasus, 4, *(__u16 *) data); | ||
938 | #endif | ||
939 | } | ||
940 | } | ||
941 | pegasus->intr_interval = data[1]; | ||
942 | } | ||
943 | |||
944 | static void set_carrier(struct net_device *net) | ||
945 | { | ||
946 | pegasus_t *pegasus = netdev_priv(net); | ||
947 | u16 tmp; | ||
948 | |||
949 | if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) | ||
950 | return; | ||
951 | |||
952 | if (tmp & BMSR_LSTATUS) | ||
953 | netif_carrier_on(net); | ||
954 | else | ||
955 | netif_carrier_off(net); | ||
956 | } | ||
957 | |||
958 | static void free_all_urbs(pegasus_t * pegasus) | ||
959 | { | ||
960 | usb_free_urb(pegasus->intr_urb); | ||
961 | usb_free_urb(pegasus->tx_urb); | ||
962 | usb_free_urb(pegasus->rx_urb); | ||
963 | usb_free_urb(pegasus->ctrl_urb); | ||
964 | } | ||
965 | |||
966 | static void unlink_all_urbs(pegasus_t * pegasus) | ||
967 | { | ||
968 | usb_kill_urb(pegasus->intr_urb); | ||
969 | usb_kill_urb(pegasus->tx_urb); | ||
970 | usb_kill_urb(pegasus->rx_urb); | ||
971 | usb_kill_urb(pegasus->ctrl_urb); | ||
972 | } | ||
973 | |||
974 | static int alloc_urbs(pegasus_t * pegasus) | ||
975 | { | ||
976 | pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
977 | if (!pegasus->ctrl_urb) { | ||
978 | return 0; | ||
979 | } | ||
980 | pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
981 | if (!pegasus->rx_urb) { | ||
982 | usb_free_urb(pegasus->ctrl_urb); | ||
983 | return 0; | ||
984 | } | ||
985 | pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
986 | if (!pegasus->tx_urb) { | ||
987 | usb_free_urb(pegasus->rx_urb); | ||
988 | usb_free_urb(pegasus->ctrl_urb); | ||
989 | return 0; | ||
990 | } | ||
991 | pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
992 | if (!pegasus->intr_urb) { | ||
993 | usb_free_urb(pegasus->tx_urb); | ||
994 | usb_free_urb(pegasus->rx_urb); | ||
995 | usb_free_urb(pegasus->ctrl_urb); | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | return 1; | ||
1000 | } | ||
1001 | |||
1002 | static int pegasus_open(struct net_device *net) | ||
1003 | { | ||
1004 | pegasus_t *pegasus = netdev_priv(net); | ||
1005 | int res; | ||
1006 | |||
1007 | if (pegasus->rx_skb == NULL) | ||
1008 | pegasus->rx_skb = pull_skb(pegasus); | ||
1009 | /* | ||
1010 | ** Note: no point to free the pool. it is empty :-) | ||
1011 | */ | ||
1012 | if (!pegasus->rx_skb) | ||
1013 | return -ENOMEM; | ||
1014 | |||
1015 | res = set_registers(pegasus, EthID, 6, net->dev_addr); | ||
1016 | |||
1017 | usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, | ||
1018 | usb_rcvbulkpipe(pegasus->usb, 1), | ||
1019 | pegasus->rx_skb->data, PEGASUS_MTU + 8, | ||
1020 | read_bulk_callback, pegasus); | ||
1021 | if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { | ||
1022 | if (res == -ENODEV) | ||
1023 | netif_device_detach(pegasus->net); | ||
1024 | if (netif_msg_ifup(pegasus)) | ||
1025 | pr_debug("%s: failed rx_urb, %d", net->name, res); | ||
1026 | goto exit; | ||
1027 | } | ||
1028 | |||
1029 | usb_fill_int_urb(pegasus->intr_urb, pegasus->usb, | ||
1030 | usb_rcvintpipe(pegasus->usb, 3), | ||
1031 | pegasus->intr_buff, sizeof (pegasus->intr_buff), | ||
1032 | intr_callback, pegasus, pegasus->intr_interval); | ||
1033 | if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) { | ||
1034 | if (res == -ENODEV) | ||
1035 | netif_device_detach(pegasus->net); | ||
1036 | if (netif_msg_ifup(pegasus)) | ||
1037 | pr_debug("%s: failed intr_urb, %d\n", net->name, res); | ||
1038 | usb_kill_urb(pegasus->rx_urb); | ||
1039 | goto exit; | ||
1040 | } | ||
1041 | if ((res = enable_net_traffic(net, pegasus->usb))) { | ||
1042 | if (netif_msg_ifup(pegasus)) | ||
1043 | pr_debug("%s: can't enable_net_traffic() - %d\n", | ||
1044 | net->name, res); | ||
1045 | res = -EIO; | ||
1046 | usb_kill_urb(pegasus->rx_urb); | ||
1047 | usb_kill_urb(pegasus->intr_urb); | ||
1048 | free_skb_pool(pegasus); | ||
1049 | goto exit; | ||
1050 | } | ||
1051 | set_carrier(net); | ||
1052 | netif_start_queue(net); | ||
1053 | if (netif_msg_ifup(pegasus)) | ||
1054 | pr_debug("%s: open\n", net->name); | ||
1055 | res = 0; | ||
1056 | exit: | ||
1057 | return res; | ||
1058 | } | ||
1059 | |||
1060 | static int pegasus_close(struct net_device *net) | ||
1061 | { | ||
1062 | pegasus_t *pegasus = netdev_priv(net); | ||
1063 | |||
1064 | netif_stop_queue(net); | ||
1065 | if (!(pegasus->flags & PEGASUS_UNPLUG)) | ||
1066 | disable_net_traffic(pegasus); | ||
1067 | tasklet_kill(&pegasus->rx_tl); | ||
1068 | unlink_all_urbs(pegasus); | ||
1069 | |||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | static void pegasus_get_drvinfo(struct net_device *dev, | ||
1074 | struct ethtool_drvinfo *info) | ||
1075 | { | ||
1076 | pegasus_t *pegasus = netdev_priv(dev); | ||
1077 | strncpy(info->driver, driver_name, sizeof (info->driver) - 1); | ||
1078 | strncpy(info->version, DRIVER_VERSION, sizeof (info->version) - 1); | ||
1079 | usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info)); | ||
1080 | } | ||
1081 | |||
1082 | /* also handles three patterns of some kind in hardware */ | ||
1083 | #define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY) | ||
1084 | |||
1085 | static void | ||
1086 | pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
1087 | { | ||
1088 | pegasus_t *pegasus = netdev_priv(dev); | ||
1089 | |||
1090 | wol->supported = WAKE_MAGIC | WAKE_PHY; | ||
1091 | wol->wolopts = pegasus->wolopts; | ||
1092 | } | ||
1093 | |||
1094 | static int | ||
1095 | pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
1096 | { | ||
1097 | pegasus_t *pegasus = netdev_priv(dev); | ||
1098 | u8 reg78 = 0x04; | ||
1099 | |||
1100 | if (wol->wolopts & ~WOL_SUPPORTED) | ||
1101 | return -EINVAL; | ||
1102 | |||
1103 | if (wol->wolopts & WAKE_MAGIC) | ||
1104 | reg78 |= 0x80; | ||
1105 | if (wol->wolopts & WAKE_PHY) | ||
1106 | reg78 |= 0x40; | ||
1107 | /* FIXME this 0x10 bit still needs to get set in the chip... */ | ||
1108 | if (wol->wolopts) | ||
1109 | pegasus->eth_regs[0] |= 0x10; | ||
1110 | else | ||
1111 | pegasus->eth_regs[0] &= ~0x10; | ||
1112 | pegasus->wolopts = wol->wolopts; | ||
1113 | return set_register(pegasus, WakeupControl, reg78); | ||
1114 | } | ||
1115 | |||
1116 | static inline void pegasus_reset_wol(struct net_device *dev) | ||
1117 | { | ||
1118 | struct ethtool_wolinfo wol; | ||
1119 | |||
1120 | memset(&wol, 0, sizeof wol); | ||
1121 | (void) pegasus_set_wol(dev, &wol); | ||
1122 | } | ||
1123 | |||
1124 | static int | ||
1125 | pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | ||
1126 | { | ||
1127 | pegasus_t *pegasus; | ||
1128 | |||
1129 | if (in_atomic()) | ||
1130 | return 0; | ||
1131 | |||
1132 | pegasus = netdev_priv(dev); | ||
1133 | mii_ethtool_gset(&pegasus->mii, ecmd); | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static int | ||
1139 | pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | ||
1140 | { | ||
1141 | pegasus_t *pegasus = netdev_priv(dev); | ||
1142 | return mii_ethtool_sset(&pegasus->mii, ecmd); | ||
1143 | } | ||
1144 | |||
1145 | static int pegasus_nway_reset(struct net_device *dev) | ||
1146 | { | ||
1147 | pegasus_t *pegasus = netdev_priv(dev); | ||
1148 | return mii_nway_restart(&pegasus->mii); | ||
1149 | } | ||
1150 | |||
1151 | static u32 pegasus_get_link(struct net_device *dev) | ||
1152 | { | ||
1153 | pegasus_t *pegasus = netdev_priv(dev); | ||
1154 | return mii_link_ok(&pegasus->mii); | ||
1155 | } | ||
1156 | |||
1157 | static u32 pegasus_get_msglevel(struct net_device *dev) | ||
1158 | { | ||
1159 | pegasus_t *pegasus = netdev_priv(dev); | ||
1160 | return pegasus->msg_enable; | ||
1161 | } | ||
1162 | |||
1163 | static void pegasus_set_msglevel(struct net_device *dev, u32 v) | ||
1164 | { | ||
1165 | pegasus_t *pegasus = netdev_priv(dev); | ||
1166 | pegasus->msg_enable = v; | ||
1167 | } | ||
1168 | |||
1169 | static struct ethtool_ops ops = { | ||
1170 | .get_drvinfo = pegasus_get_drvinfo, | ||
1171 | .get_settings = pegasus_get_settings, | ||
1172 | .set_settings = pegasus_set_settings, | ||
1173 | .nway_reset = pegasus_nway_reset, | ||
1174 | .get_link = pegasus_get_link, | ||
1175 | .get_msglevel = pegasus_get_msglevel, | ||
1176 | .set_msglevel = pegasus_set_msglevel, | ||
1177 | .get_wol = pegasus_get_wol, | ||
1178 | .set_wol = pegasus_set_wol, | ||
1179 | }; | ||
1180 | |||
1181 | static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | ||
1182 | { | ||
1183 | __u16 *data = (__u16 *) & rq->ifr_ifru; | ||
1184 | pegasus_t *pegasus = netdev_priv(net); | ||
1185 | int res; | ||
1186 | |||
1187 | switch (cmd) { | ||
1188 | case SIOCDEVPRIVATE: | ||
1189 | data[0] = pegasus->phy; | ||
1190 | case SIOCDEVPRIVATE + 1: | ||
1191 | read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]); | ||
1192 | res = 0; | ||
1193 | break; | ||
1194 | case SIOCDEVPRIVATE + 2: | ||
1195 | if (!capable(CAP_NET_ADMIN)) | ||
1196 | return -EPERM; | ||
1197 | write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); | ||
1198 | res = 0; | ||
1199 | break; | ||
1200 | default: | ||
1201 | res = -EOPNOTSUPP; | ||
1202 | } | ||
1203 | return res; | ||
1204 | } | ||
1205 | |||
1206 | static void pegasus_set_multicast(struct net_device *net) | ||
1207 | { | ||
1208 | pegasus_t *pegasus = netdev_priv(net); | ||
1209 | |||
1210 | if (net->flags & IFF_PROMISC) { | ||
1211 | pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; | ||
1212 | if (netif_msg_link(pegasus)) | ||
1213 | pr_info("%s: Promiscuous mode enabled.\n", net->name); | ||
1214 | } else if (net->mc_count || | ||
1215 | (net->flags & IFF_ALLMULTI)) { | ||
1216 | pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; | ||
1217 | pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; | ||
1218 | if (netif_msg_link(pegasus)) | ||
1219 | pr_info("%s: set allmulti\n", net->name); | ||
1220 | } else { | ||
1221 | pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; | ||
1222 | pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; | ||
1223 | } | ||
1224 | |||
1225 | pegasus->flags |= ETH_REGS_CHANGE; | ||
1226 | ctrl_callback(pegasus->ctrl_urb); | ||
1227 | } | ||
1228 | |||
1229 | static __u8 mii_phy_probe(pegasus_t * pegasus) | ||
1230 | { | ||
1231 | int i; | ||
1232 | __u16 tmp; | ||
1233 | |||
1234 | for (i = 0; i < 32; i++) { | ||
1235 | read_mii_word(pegasus, i, MII_BMSR, &tmp); | ||
1236 | if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0) | ||
1237 | continue; | ||
1238 | else | ||
1239 | return i; | ||
1240 | } | ||
1241 | |||
1242 | return 0xff; | ||
1243 | } | ||
1244 | |||
1245 | static inline void setup_pegasus_II(pegasus_t * pegasus) | ||
1246 | { | ||
1247 | __u8 data = 0xa5; | ||
1248 | |||
1249 | set_register(pegasus, Reg1d, 0); | ||
1250 | set_register(pegasus, Reg7b, 1); | ||
1251 | mdelay(100); | ||
1252 | if ((pegasus->features & HAS_HOME_PNA) && mii_mode) | ||
1253 | set_register(pegasus, Reg7b, 0); | ||
1254 | else | ||
1255 | set_register(pegasus, Reg7b, 2); | ||
1256 | |||
1257 | set_register(pegasus, 0x83, data); | ||
1258 | get_registers(pegasus, 0x83, 1, &data); | ||
1259 | |||
1260 | if (data == 0xa5) { | ||
1261 | pegasus->chip = 0x8513; | ||
1262 | } else { | ||
1263 | pegasus->chip = 0; | ||
1264 | } | ||
1265 | |||
1266 | set_register(pegasus, 0x80, 0xc0); | ||
1267 | set_register(pegasus, 0x83, 0xff); | ||
1268 | set_register(pegasus, 0x84, 0x01); | ||
1269 | |||
1270 | if (pegasus->features & HAS_HOME_PNA && mii_mode) | ||
1271 | set_register(pegasus, Reg81, 6); | ||
1272 | else | ||
1273 | set_register(pegasus, Reg81, 2); | ||
1274 | } | ||
1275 | |||
1276 | |||
1277 | static struct workqueue_struct *pegasus_workqueue = NULL; | ||
1278 | #define CARRIER_CHECK_DELAY (2 * HZ) | ||
1279 | |||
1280 | static void check_carrier(struct work_struct *work) | ||
1281 | { | ||
1282 | pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); | ||
1283 | set_carrier(pegasus->net); | ||
1284 | if (!(pegasus->flags & PEGASUS_UNPLUG)) { | ||
1285 | queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, | ||
1286 | CARRIER_CHECK_DELAY); | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | static int pegasus_probe(struct usb_interface *intf, | ||
1291 | const struct usb_device_id *id) | ||
1292 | { | ||
1293 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1294 | struct net_device *net; | ||
1295 | pegasus_t *pegasus; | ||
1296 | int dev_index = id - pegasus_ids; | ||
1297 | int res = -ENOMEM; | ||
1298 | |||
1299 | usb_get_dev(dev); | ||
1300 | net = alloc_etherdev(sizeof(struct pegasus)); | ||
1301 | if (!net) { | ||
1302 | dev_err(&intf->dev, "can't allocate %s\n", "device"); | ||
1303 | goto out; | ||
1304 | } | ||
1305 | |||
1306 | pegasus = netdev_priv(net); | ||
1307 | memset(pegasus, 0, sizeof (struct pegasus)); | ||
1308 | pegasus->dev_index = dev_index; | ||
1309 | init_waitqueue_head(&pegasus->ctrl_wait); | ||
1310 | |||
1311 | if (!alloc_urbs(pegasus)) { | ||
1312 | dev_err(&intf->dev, "can't allocate %s\n", "urbs"); | ||
1313 | goto out1; | ||
1314 | } | ||
1315 | |||
1316 | tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); | ||
1317 | |||
1318 | INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); | ||
1319 | |||
1320 | pegasus->intf = intf; | ||
1321 | pegasus->usb = dev; | ||
1322 | pegasus->net = net; | ||
1323 | SET_MODULE_OWNER(net); | ||
1324 | net->open = pegasus_open; | ||
1325 | net->stop = pegasus_close; | ||
1326 | net->watchdog_timeo = PEGASUS_TX_TIMEOUT; | ||
1327 | net->tx_timeout = pegasus_tx_timeout; | ||
1328 | net->do_ioctl = pegasus_ioctl; | ||
1329 | net->hard_start_xmit = pegasus_start_xmit; | ||
1330 | net->set_multicast_list = pegasus_set_multicast; | ||
1331 | net->get_stats = pegasus_netdev_stats; | ||
1332 | SET_ETHTOOL_OPS(net, &ops); | ||
1333 | pegasus->mii.dev = net; | ||
1334 | pegasus->mii.mdio_read = mdio_read; | ||
1335 | pegasus->mii.mdio_write = mdio_write; | ||
1336 | pegasus->mii.phy_id_mask = 0x1f; | ||
1337 | pegasus->mii.reg_num_mask = 0x1f; | ||
1338 | spin_lock_init(&pegasus->rx_pool_lock); | ||
1339 | pegasus->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV | ||
1340 | | NETIF_MSG_PROBE | NETIF_MSG_LINK); | ||
1341 | |||
1342 | pegasus->features = usb_dev_id[dev_index].private; | ||
1343 | get_interrupt_interval(pegasus); | ||
1344 | if (reset_mac(pegasus)) { | ||
1345 | dev_err(&intf->dev, "can't reset MAC\n"); | ||
1346 | res = -EIO; | ||
1347 | goto out2; | ||
1348 | } | ||
1349 | set_ethernet_addr(pegasus); | ||
1350 | fill_skb_pool(pegasus); | ||
1351 | if (pegasus->features & PEGASUS_II) { | ||
1352 | dev_info(&intf->dev, "setup Pegasus II specific registers\n"); | ||
1353 | setup_pegasus_II(pegasus); | ||
1354 | } | ||
1355 | pegasus->phy = mii_phy_probe(pegasus); | ||
1356 | if (pegasus->phy == 0xff) { | ||
1357 | dev_warn(&intf->dev, "can't locate MII phy, using default\n"); | ||
1358 | pegasus->phy = 1; | ||
1359 | } | ||
1360 | pegasus->mii.phy_id = pegasus->phy; | ||
1361 | usb_set_intfdata(intf, pegasus); | ||
1362 | SET_NETDEV_DEV(net, &intf->dev); | ||
1363 | pegasus_reset_wol(net); | ||
1364 | res = register_netdev(net); | ||
1365 | if (res) | ||
1366 | goto out3; | ||
1367 | queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, | ||
1368 | CARRIER_CHECK_DELAY); | ||
1369 | |||
1370 | dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1371 | net->name, | ||
1372 | usb_dev_id[dev_index].name, | ||
1373 | net->dev_addr [0], net->dev_addr [1], | ||
1374 | net->dev_addr [2], net->dev_addr [3], | ||
1375 | net->dev_addr [4], net->dev_addr [5]); | ||
1376 | return 0; | ||
1377 | |||
1378 | out3: | ||
1379 | usb_set_intfdata(intf, NULL); | ||
1380 | free_skb_pool(pegasus); | ||
1381 | out2: | ||
1382 | free_all_urbs(pegasus); | ||
1383 | out1: | ||
1384 | free_netdev(net); | ||
1385 | out: | ||
1386 | usb_put_dev(dev); | ||
1387 | return res; | ||
1388 | } | ||
1389 | |||
1390 | static void pegasus_disconnect(struct usb_interface *intf) | ||
1391 | { | ||
1392 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
1393 | |||
1394 | usb_set_intfdata(intf, NULL); | ||
1395 | if (!pegasus) { | ||
1396 | dev_dbg(&intf->dev, "unregistering non-bound device?\n"); | ||
1397 | return; | ||
1398 | } | ||
1399 | |||
1400 | pegasus->flags |= PEGASUS_UNPLUG; | ||
1401 | cancel_delayed_work(&pegasus->carrier_check); | ||
1402 | unregister_netdev(pegasus->net); | ||
1403 | usb_put_dev(interface_to_usbdev(intf)); | ||
1404 | unlink_all_urbs(pegasus); | ||
1405 | free_all_urbs(pegasus); | ||
1406 | free_skb_pool(pegasus); | ||
1407 | if (pegasus->rx_skb != NULL) { | ||
1408 | dev_kfree_skb(pegasus->rx_skb); | ||
1409 | pegasus->rx_skb = NULL; | ||
1410 | } | ||
1411 | free_netdev(pegasus->net); | ||
1412 | } | ||
1413 | |||
1414 | static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) | ||
1415 | { | ||
1416 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
1417 | |||
1418 | netif_device_detach (pegasus->net); | ||
1419 | cancel_delayed_work(&pegasus->carrier_check); | ||
1420 | if (netif_running(pegasus->net)) { | ||
1421 | usb_kill_urb(pegasus->rx_urb); | ||
1422 | usb_kill_urb(pegasus->intr_urb); | ||
1423 | } | ||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static int pegasus_resume (struct usb_interface *intf) | ||
1428 | { | ||
1429 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
1430 | |||
1431 | netif_device_attach (pegasus->net); | ||
1432 | if (netif_running(pegasus->net)) { | ||
1433 | pegasus->rx_urb->status = 0; | ||
1434 | pegasus->rx_urb->actual_length = 0; | ||
1435 | read_bulk_callback(pegasus->rx_urb); | ||
1436 | |||
1437 | pegasus->intr_urb->status = 0; | ||
1438 | pegasus->intr_urb->actual_length = 0; | ||
1439 | intr_callback(pegasus->intr_urb); | ||
1440 | } | ||
1441 | queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, | ||
1442 | CARRIER_CHECK_DELAY); | ||
1443 | return 0; | ||
1444 | } | ||
1445 | |||
1446 | static struct usb_driver pegasus_driver = { | ||
1447 | .name = driver_name, | ||
1448 | .probe = pegasus_probe, | ||
1449 | .disconnect = pegasus_disconnect, | ||
1450 | .id_table = pegasus_ids, | ||
1451 | .suspend = pegasus_suspend, | ||
1452 | .resume = pegasus_resume, | ||
1453 | }; | ||
1454 | |||
1455 | static void parse_id(char *id) | ||
1456 | { | ||
1457 | unsigned int vendor_id=0, device_id=0, flags=0, i=0; | ||
1458 | char *token, *name=NULL; | ||
1459 | |||
1460 | if ((token = strsep(&id, ":")) != NULL) | ||
1461 | name = token; | ||
1462 | /* name now points to a null terminated string*/ | ||
1463 | if ((token = strsep(&id, ":")) != NULL) | ||
1464 | vendor_id = simple_strtoul(token, NULL, 16); | ||
1465 | if ((token = strsep(&id, ":")) != NULL) | ||
1466 | device_id = simple_strtoul(token, NULL, 16); | ||
1467 | flags = simple_strtoul(id, NULL, 16); | ||
1468 | pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n", | ||
1469 | driver_name, name, vendor_id, device_id, flags); | ||
1470 | |||
1471 | if (vendor_id > 0x10000 || vendor_id == 0) | ||
1472 | return; | ||
1473 | if (device_id > 0x10000 || device_id == 0) | ||
1474 | return; | ||
1475 | |||
1476 | for (i=0; usb_dev_id[i].name; i++); | ||
1477 | usb_dev_id[i].name = name; | ||
1478 | usb_dev_id[i].vendor = vendor_id; | ||
1479 | usb_dev_id[i].device = device_id; | ||
1480 | usb_dev_id[i].private = flags; | ||
1481 | pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; | ||
1482 | pegasus_ids[i].idVendor = vendor_id; | ||
1483 | pegasus_ids[i].idProduct = device_id; | ||
1484 | } | ||
1485 | |||
1486 | static int __init pegasus_init(void) | ||
1487 | { | ||
1488 | pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); | ||
1489 | if (devid) | ||
1490 | parse_id(devid); | ||
1491 | pegasus_workqueue = create_singlethread_workqueue("pegasus"); | ||
1492 | if (!pegasus_workqueue) | ||
1493 | return -ENOMEM; | ||
1494 | return usb_register(&pegasus_driver); | ||
1495 | } | ||
1496 | |||
1497 | static void __exit pegasus_exit(void) | ||
1498 | { | ||
1499 | destroy_workqueue(pegasus_workqueue); | ||
1500 | usb_deregister(&pegasus_driver); | ||
1501 | } | ||
1502 | |||
1503 | module_init(pegasus_init); | ||
1504 | module_exit(pegasus_exit); | ||
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h new file mode 100644 index 000000000000..c7467823cd1c --- /dev/null +++ b/drivers/net/usb/pegasus.h | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net) | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as published | ||
6 | * by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #ifndef PEGASUS_DEV | ||
11 | |||
12 | #define PEGASUS_II 0x80000000 | ||
13 | #define HAS_HOME_PNA 0x40000000 | ||
14 | |||
15 | #define PEGASUS_MTU 1536 | ||
16 | #define RX_SKBS 4 | ||
17 | |||
18 | #define EPROM_WRITE 0x01 | ||
19 | #define EPROM_READ 0x02 | ||
20 | #define EPROM_DONE 0x04 | ||
21 | #define EPROM_WR_ENABLE 0x10 | ||
22 | #define EPROM_LOAD 0x20 | ||
23 | |||
24 | #define PHY_DONE 0x80 | ||
25 | #define PHY_READ 0x40 | ||
26 | #define PHY_WRITE 0x20 | ||
27 | #define DEFAULT_GPIO_RESET 0x24 | ||
28 | #define DEFAULT_GPIO_SET 0x26 | ||
29 | |||
30 | #define PEGASUS_PRESENT 0x00000001 | ||
31 | #define PEGASUS_TX_BUSY 0x00000004 | ||
32 | #define PEGASUS_RX_BUSY 0x00000008 | ||
33 | #define CTRL_URB_RUNNING 0x00000010 | ||
34 | #define CTRL_URB_SLEEP 0x00000020 | ||
35 | #define PEGASUS_UNPLUG 0x00000040 | ||
36 | #define PEGASUS_RX_URB_FAIL 0x00000080 | ||
37 | #define ETH_REGS_CHANGE 0x40000000 | ||
38 | #define ETH_REGS_CHANGED 0x80000000 | ||
39 | |||
40 | #define RX_MULTICAST 2 | ||
41 | #define RX_PROMISCUOUS 4 | ||
42 | |||
43 | #define REG_TIMEOUT (HZ) | ||
44 | #define PEGASUS_TX_TIMEOUT (HZ*10) | ||
45 | |||
46 | #define TX_UNDERRUN 0x80 | ||
47 | #define EXCESSIVE_COL 0x40 | ||
48 | #define LATE_COL 0x20 | ||
49 | #define NO_CARRIER 0x10 | ||
50 | #define LOSS_CARRIER 0x08 | ||
51 | #define JABBER_TIMEOUT 0x04 | ||
52 | |||
53 | #define LINK_STATUS 0x01 | ||
54 | |||
55 | #define PEGASUS_REQT_READ 0xc0 | ||
56 | #define PEGASUS_REQT_WRITE 0x40 | ||
57 | #define PEGASUS_REQ_GET_REGS 0xf0 | ||
58 | #define PEGASUS_REQ_SET_REGS 0xf1 | ||
59 | #define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS | ||
60 | |||
61 | enum pegasus_registers { | ||
62 | EthCtrl0 = 0, | ||
63 | EthCtrl1 = 1, | ||
64 | EthCtrl2 = 2, | ||
65 | EthID = 0x10, | ||
66 | Reg1d = 0x1d, | ||
67 | EpromOffset = 0x20, | ||
68 | EpromData = 0x21, /* 0x21 low, 0x22 high byte */ | ||
69 | EpromCtrl = 0x23, | ||
70 | PhyAddr = 0x25, | ||
71 | PhyData = 0x26, /* 0x26 low, 0x27 high byte */ | ||
72 | PhyCtrl = 0x28, | ||
73 | UsbStst = 0x2a, | ||
74 | EthTxStat0 = 0x2b, | ||
75 | EthTxStat1 = 0x2c, | ||
76 | EthRxStat = 0x2d, | ||
77 | WakeupControl = 0x78, | ||
78 | Reg7b = 0x7b, | ||
79 | Gpio0 = 0x7e, | ||
80 | Gpio1 = 0x7f, | ||
81 | Reg81 = 0x81, | ||
82 | }; | ||
83 | |||
84 | |||
85 | typedef struct pegasus { | ||
86 | struct usb_device *usb; | ||
87 | struct usb_interface *intf; | ||
88 | struct net_device *net; | ||
89 | struct net_device_stats stats; | ||
90 | struct mii_if_info mii; | ||
91 | unsigned flags; | ||
92 | unsigned features; | ||
93 | u32 msg_enable; | ||
94 | u32 wolopts; | ||
95 | int dev_index; | ||
96 | int intr_interval; | ||
97 | struct tasklet_struct rx_tl; | ||
98 | struct delayed_work carrier_check; | ||
99 | struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; | ||
100 | struct sk_buff *rx_pool[RX_SKBS]; | ||
101 | struct sk_buff *rx_skb; | ||
102 | struct usb_ctrlrequest dr; | ||
103 | wait_queue_head_t ctrl_wait; | ||
104 | spinlock_t rx_pool_lock; | ||
105 | int chip; | ||
106 | unsigned char intr_buff[8]; | ||
107 | __u8 tx_buff[PEGASUS_MTU]; | ||
108 | __u8 eth_regs[4]; | ||
109 | __u8 phy; | ||
110 | __u8 gpio_res; | ||
111 | } pegasus_t; | ||
112 | |||
113 | |||
114 | struct usb_eth_dev { | ||
115 | char *name; | ||
116 | __u16 vendor; | ||
117 | __u16 device; | ||
118 | __u32 private; /* LSB is gpio reset value */ | ||
119 | }; | ||
120 | |||
121 | #define VENDOR_3COM 0x0506 | ||
122 | #define VENDOR_ABOCOM 0x07b8 | ||
123 | #define VENDOR_ACCTON 0x083a | ||
124 | #define VENDOR_ADMTEK 0x07a6 | ||
125 | #define VENDOR_AEILAB 0x3334 | ||
126 | #define VENDOR_ALLIEDTEL 0x07c9 | ||
127 | #define VENDOR_ATEN 0x0557 | ||
128 | #define VENDOR_BELKIN 0x050d | ||
129 | #define VENDOR_BILLIONTON 0x08dd | ||
130 | #define VENDOR_COMPAQ 0x049f | ||
131 | #define VENDOR_COREGA 0x07aa | ||
132 | #define VENDOR_DLINK 0x2001 | ||
133 | #define VENDOR_ELCON 0x0db7 | ||
134 | #define VENDOR_ELECOM 0x056e | ||
135 | #define VENDOR_ELSA 0x05cc | ||
136 | #define VENDOR_GIGABYTE 0x1044 | ||
137 | #define VENDOR_HAWKING 0x0e66 | ||
138 | #define VENDOR_HP 0x03f0 | ||
139 | #define VENDOR_IODATA 0x04bb | ||
140 | #define VENDOR_KINGSTON 0x0951 | ||
141 | #define VENDOR_LANEED 0x056e | ||
142 | #define VENDOR_LINKSYS 0x066b | ||
143 | #define VENDOR_LINKSYS2 0x077b | ||
144 | #define VENDOR_MELCO 0x0411 | ||
145 | #define VENDOR_MICROSOFT 0x045e | ||
146 | #define VENDOR_MOBILITY 0x1342 | ||
147 | #define VENDOR_NETGEAR 0x0846 | ||
148 | #define VENDOR_OCT 0x0b39 | ||
149 | #define VENDOR_SMARTBRIDGES 0x08d1 | ||
150 | #define VENDOR_SMC 0x0707 | ||
151 | #define VENDOR_SOHOWARE 0x15e8 | ||
152 | #define VENDOR_SIEMENS 0x067c | ||
153 | |||
154 | |||
155 | #else /* PEGASUS_DEV */ | ||
156 | |||
157 | PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601, | ||
158 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
159 | PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007, | ||
160 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
161 | PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c, | ||
162 | DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) | ||
163 | PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104, | ||
164 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
165 | PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004, | ||
166 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
167 | PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007, | ||
168 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
169 | PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102, | ||
170 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
171 | PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002, | ||
172 | DEFAULT_GPIO_RESET ) | ||
173 | PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b, | ||
174 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
175 | PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c, | ||
176 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
177 | PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1, | ||
178 | DEFAULT_GPIO_RESET ) | ||
179 | PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c, | ||
180 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
181 | PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, | ||
182 | DEFAULT_GPIO_RESET ) | ||
183 | PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, | ||
184 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
185 | PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004, | ||
186 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
187 | PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", | ||
188 | VENDOR_ADMTEK, 0x8511, | ||
189 | DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) | ||
190 | PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet", | ||
191 | VENDOR_ADMTEK, 0x8513, | ||
192 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
193 | PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet", | ||
194 | VENDOR_ADMTEK, 0x8515, | ||
195 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
196 | PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)", | ||
197 | VENDOR_ADMTEK, 0x0986, | ||
198 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
199 | PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986, | ||
200 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
201 | PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701, | ||
202 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
203 | PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100, | ||
204 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
205 | PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, | ||
206 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
207 | PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986, | ||
208 | DEFAULT_GPIO_RESET ) | ||
209 | PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987, | ||
210 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
211 | PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511, | ||
212 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
213 | PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988, | ||
214 | DEFAULT_GPIO_RESET ) | ||
215 | PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, | ||
216 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
217 | PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004, | ||
218 | DEFAULT_GPIO_RESET ) | ||
219 | PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d, | ||
220 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
221 | PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, | ||
222 | DEFAULT_GPIO_RESET ) | ||
223 | PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002, | ||
224 | DEFAULT_GPIO_RESET ) | ||
225 | PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102, | ||
226 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
227 | PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b, | ||
228 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
229 | PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c, | ||
230 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
231 | PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003, | ||
232 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
233 | PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1, | ||
234 | DEFAULT_GPIO_RESET ) | ||
235 | PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002, | ||
236 | DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) | ||
237 | PEGASUS_DEV( "ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010, | ||
238 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
239 | PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304, | ||
240 | DEFAULT_GPIO_RESET ) | ||
241 | PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, | ||
242 | DEFAULT_GPIO_RESET ) | ||
243 | PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, | ||
244 | DEFAULT_GPIO_RESET ) | ||
245 | PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, | ||
246 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
247 | PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c, | ||
248 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
249 | PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, | ||
250 | DEFAULT_GPIO_RESET ) | ||
251 | PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913, | ||
252 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
253 | PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a, | ||
254 | DEFAULT_GPIO_RESET) | ||
255 | PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002, | ||
256 | DEFAULT_GPIO_RESET ) | ||
257 | PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005, | ||
258 | DEFAULT_GPIO_RESET | PEGASUS_II) | ||
259 | PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b, | ||
260 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
261 | PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1, | ||
262 | DEFAULT_GPIO_RESET ) | ||
263 | PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c, | ||
264 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
265 | PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202, | ||
266 | DEFAULT_GPIO_RESET ) | ||
267 | PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203, | ||
268 | DEFAULT_GPIO_RESET ) | ||
269 | PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204, | ||
270 | DEFAULT_GPIO_RESET | HAS_HOME_PNA ) | ||
271 | PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206, | ||
272 | DEFAULT_GPIO_RESET | PEGASUS_II) | ||
273 | PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4, | ||
274 | DEFAULT_GPIO_RESET ) | ||
275 | PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b, | ||
276 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
277 | PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c, | ||
278 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
279 | PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001, | ||
280 | DEFAULT_GPIO_RESET ) | ||
281 | PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, | ||
282 | DEFAULT_GPIO_RESET ) | ||
283 | PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009, | ||
284 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
285 | PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a, | ||
286 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
287 | PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020, | ||
288 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
289 | PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, | ||
290 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
291 | PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901, | ||
292 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
293 | PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, | ||
294 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
295 | PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, | ||
296 | DEFAULT_GPIO_RESET ) | ||
297 | PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201, | ||
298 | DEFAULT_GPIO_RESET | PEGASUS_II) | ||
299 | PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100, | ||
300 | DEFAULT_GPIO_RESET ) | ||
301 | PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110, | ||
302 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
303 | PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001, | ||
304 | DEFAULT_GPIO_RESET | PEGASUS_II ) | ||
305 | |||
306 | |||
307 | #endif /* PEGASUS_DEV */ | ||
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c new file mode 100644 index 000000000000..45300939d185 --- /dev/null +++ b/drivers/net/usb/plusb.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * PL-2301/2302 USB host-to-host link cables | ||
3 | * Copyright (C) 2000-2005 by David Brownell | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | // #define DEBUG // error path messages, extra info | ||
21 | // #define VERBOSE // more; success messages | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/ethtool.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/mii.h> | ||
30 | #include <linux/usb.h> | ||
31 | |||
32 | #include "usbnet.h" | ||
33 | |||
34 | |||
35 | /* | ||
36 | * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com | ||
37 | * | ||
38 | * The protocol and handshaking used here should be bug-compatible | ||
39 | * with the Linux 2.2 "plusb" driver, by Deti Fliegl. | ||
40 | * | ||
41 | * HEADS UP: this handshaking isn't all that robust. This driver | ||
42 | * gets confused easily if you unplug one end of the cable then | ||
43 | * try to connect it again; you'll need to restart both ends. The | ||
44 | * "naplink" software (used by some PlayStation/2 deveopers) does | ||
45 | * the handshaking much better! Also, sometimes this hardware | ||
46 | * seems to get wedged under load. Prolific docs are weak, and | ||
47 | * don't identify differences between PL2301 and PL2302, much less | ||
48 | * anything to explain the different PL2302 versions observed. | ||
49 | */ | ||
50 | |||
51 | /* | ||
52 | * Bits 0-4 can be used for software handshaking; they're set from | ||
53 | * one end, cleared from the other, "read" with the interrupt byte. | ||
54 | */ | ||
55 | #define PL_S_EN (1<<7) /* (feature only) suspend enable */ | ||
56 | /* reserved bit -- rx ready (6) ? */ | ||
57 | #define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */ | ||
58 | #define PL_RESET_OUT (1<<4) /* reset output pipe */ | ||
59 | #define PL_RESET_IN (1<<3) /* reset input pipe */ | ||
60 | #define PL_TX_C (1<<2) /* transmission complete */ | ||
61 | #define PL_TX_REQ (1<<1) /* transmission received */ | ||
62 | #define PL_PEER_E (1<<0) /* peer exists */ | ||
63 | |||
64 | static inline int | ||
65 | pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index) | ||
66 | { | ||
67 | return usb_control_msg(dev->udev, | ||
68 | usb_rcvctrlpipe(dev->udev, 0), | ||
69 | req, | ||
70 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
71 | val, index, | ||
72 | NULL, 0, | ||
73 | USB_CTRL_GET_TIMEOUT); | ||
74 | } | ||
75 | |||
76 | static inline int | ||
77 | pl_clear_QuickLink_features(struct usbnet *dev, int val) | ||
78 | { | ||
79 | return pl_vendor_req(dev, 1, (u8) val, 0); | ||
80 | } | ||
81 | |||
82 | static inline int | ||
83 | pl_set_QuickLink_features(struct usbnet *dev, int val) | ||
84 | { | ||
85 | return pl_vendor_req(dev, 3, (u8) val, 0); | ||
86 | } | ||
87 | |||
88 | static int pl_reset(struct usbnet *dev) | ||
89 | { | ||
90 | /* some units seem to need this reset, others reject it utterly. | ||
91 | * FIXME be more like "naplink" or windows drivers. | ||
92 | */ | ||
93 | (void) pl_set_QuickLink_features(dev, | ||
94 | PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static const struct driver_info prolific_info = { | ||
99 | .description = "Prolific PL-2301/PL-2302", | ||
100 | .flags = FLAG_NO_SETINT, | ||
101 | /* some PL-2302 versions seem to fail usb_set_interface() */ | ||
102 | .reset = pl_reset, | ||
103 | }; | ||
104 | |||
105 | |||
106 | /*-------------------------------------------------------------------------*/ | ||
107 | |||
108 | /* | ||
109 | * Proilific's name won't normally be on the cables, and | ||
110 | * may not be on the device. | ||
111 | */ | ||
112 | |||
113 | static const struct usb_device_id products [] = { | ||
114 | |||
115 | { | ||
116 | USB_DEVICE(0x067b, 0x0000), // PL-2301 | ||
117 | .driver_info = (unsigned long) &prolific_info, | ||
118 | }, { | ||
119 | USB_DEVICE(0x067b, 0x0001), // PL-2302 | ||
120 | .driver_info = (unsigned long) &prolific_info, | ||
121 | }, | ||
122 | |||
123 | { }, // END | ||
124 | }; | ||
125 | MODULE_DEVICE_TABLE(usb, products); | ||
126 | |||
127 | static struct usb_driver plusb_driver = { | ||
128 | .name = "plusb", | ||
129 | .id_table = products, | ||
130 | .probe = usbnet_probe, | ||
131 | .disconnect = usbnet_disconnect, | ||
132 | .suspend = usbnet_suspend, | ||
133 | .resume = usbnet_resume, | ||
134 | }; | ||
135 | |||
136 | static int __init plusb_init(void) | ||
137 | { | ||
138 | return usb_register(&plusb_driver); | ||
139 | } | ||
140 | module_init(plusb_init); | ||
141 | |||
142 | static void __exit plusb_exit(void) | ||
143 | { | ||
144 | usb_deregister(&plusb_driver); | ||
145 | } | ||
146 | module_exit(plusb_exit); | ||
147 | |||
148 | MODULE_AUTHOR("David Brownell"); | ||
149 | MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); | ||
150 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c new file mode 100644 index 000000000000..980e4aaa97aa --- /dev/null +++ b/drivers/net/usb/rndis_host.c | |||
@@ -0,0 +1,727 @@ | |||
1 | /* | ||
2 | * Host Side support for RNDIS Networking Links | ||
3 | * Copyright (C) 2005 by David Brownell | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | // #define DEBUG // error path messages, extra info | ||
21 | // #define VERBOSE // more; success messages | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/ethtool.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/mii.h> | ||
30 | #include <linux/usb.h> | ||
31 | #include <linux/usb/cdc.h> | ||
32 | |||
33 | #include "usbnet.h" | ||
34 | |||
35 | |||
36 | /* | ||
37 | * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of | ||
38 | * course ACM was intended for modems, not Ethernet links! USB's standard | ||
39 | * for Ethernet links is "CDC Ethernet", which is significantly simpler. | ||
40 | * | ||
41 | * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues | ||
42 | * include: | ||
43 | * - Power management in particular relies on information that's scattered | ||
44 | * through other documentation, and which is incomplete or incorrect even | ||
45 | * there. | ||
46 | * - There are various undocumented protocol requirements, such as the | ||
47 | * need to send unused garbage in control-OUT messages. | ||
48 | * - In some cases, MS-Windows will emit undocumented requests; this | ||
49 | * matters more to peripheral implementations than host ones. | ||
50 | * | ||
51 | * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". | ||
52 | * | ||
53 | * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in | ||
54 | * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and | ||
55 | * currently rare) "Ethernet Emulation Model" (EEM). | ||
56 | */ | ||
57 | |||
58 | /* | ||
59 | * CONTROL uses CDC "encapsulated commands" with funky notifications. | ||
60 | * - control-out: SEND_ENCAPSULATED | ||
61 | * - interrupt-in: RESPONSE_AVAILABLE | ||
62 | * - control-in: GET_ENCAPSULATED | ||
63 | * | ||
64 | * We'll try to ignore the RESPONSE_AVAILABLE notifications. | ||
65 | * | ||
66 | * REVISIT some RNDIS implementations seem to have curious issues still | ||
67 | * to be resolved. | ||
68 | */ | ||
69 | struct rndis_msg_hdr { | ||
70 | __le32 msg_type; /* RNDIS_MSG_* */ | ||
71 | __le32 msg_len; | ||
72 | // followed by data that varies between messages | ||
73 | __le32 request_id; | ||
74 | __le32 status; | ||
75 | // ... and more | ||
76 | } __attribute__ ((packed)); | ||
77 | |||
78 | /* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */ | ||
79 | #define CONTROL_BUFFER_SIZE 1025 | ||
80 | |||
81 | /* RNDIS defines an (absurdly huge) 10 second control timeout, | ||
82 | * but ActiveSync seems to use a more usual 5 second timeout | ||
83 | * (which matches the USB 2.0 spec). | ||
84 | */ | ||
85 | #define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000) | ||
86 | |||
87 | |||
88 | #define ccpu2 __constant_cpu_to_le32 | ||
89 | |||
90 | #define RNDIS_MSG_COMPLETION ccpu2(0x80000000) | ||
91 | |||
92 | /* codes for "msg_type" field of rndis messages; | ||
93 | * only the data channel uses packet messages (maybe batched); | ||
94 | * everything else goes on the control channel. | ||
95 | */ | ||
96 | #define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */ | ||
97 | #define RNDIS_MSG_INIT ccpu2(0x00000002) | ||
98 | #define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) | ||
99 | #define RNDIS_MSG_HALT ccpu2(0x00000003) | ||
100 | #define RNDIS_MSG_QUERY ccpu2(0x00000004) | ||
101 | #define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) | ||
102 | #define RNDIS_MSG_SET ccpu2(0x00000005) | ||
103 | #define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) | ||
104 | #define RNDIS_MSG_RESET ccpu2(0x00000006) | ||
105 | #define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) | ||
106 | #define RNDIS_MSG_INDICATE ccpu2(0x00000007) | ||
107 | #define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008) | ||
108 | #define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) | ||
109 | |||
110 | /* codes for "status" field of completion messages */ | ||
111 | #define RNDIS_STATUS_SUCCESS ccpu2(0x00000000) | ||
112 | #define RNDIS_STATUS_FAILURE ccpu2(0xc0000001) | ||
113 | #define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015) | ||
114 | #define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb) | ||
115 | #define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b) | ||
116 | #define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c) | ||
117 | |||
118 | |||
119 | struct rndis_data_hdr { | ||
120 | __le32 msg_type; /* RNDIS_MSG_PACKET */ | ||
121 | __le32 msg_len; // rndis_data_hdr + data_len + pad | ||
122 | __le32 data_offset; // 36 -- right after header | ||
123 | __le32 data_len; // ... real packet size | ||
124 | |||
125 | __le32 oob_data_offset; // zero | ||
126 | __le32 oob_data_len; // zero | ||
127 | __le32 num_oob; // zero | ||
128 | __le32 packet_data_offset; // zero | ||
129 | |||
130 | __le32 packet_data_len; // zero | ||
131 | __le32 vc_handle; // zero | ||
132 | __le32 reserved; // zero | ||
133 | } __attribute__ ((packed)); | ||
134 | |||
135 | struct rndis_init { /* OUT */ | ||
136 | // header and: | ||
137 | __le32 msg_type; /* RNDIS_MSG_INIT */ | ||
138 | __le32 msg_len; // 24 | ||
139 | __le32 request_id; | ||
140 | __le32 major_version; // of rndis (1.0) | ||
141 | __le32 minor_version; | ||
142 | __le32 max_transfer_size; | ||
143 | } __attribute__ ((packed)); | ||
144 | |||
145 | struct rndis_init_c { /* IN */ | ||
146 | // header and: | ||
147 | __le32 msg_type; /* RNDIS_MSG_INIT_C */ | ||
148 | __le32 msg_len; | ||
149 | __le32 request_id; | ||
150 | __le32 status; | ||
151 | __le32 major_version; // of rndis (1.0) | ||
152 | __le32 minor_version; | ||
153 | __le32 device_flags; | ||
154 | __le32 medium; // zero == 802.3 | ||
155 | __le32 max_packets_per_message; | ||
156 | __le32 max_transfer_size; | ||
157 | __le32 packet_alignment; // max 7; (1<<n) bytes | ||
158 | __le32 af_list_offset; // zero | ||
159 | __le32 af_list_size; // zero | ||
160 | } __attribute__ ((packed)); | ||
161 | |||
162 | struct rndis_halt { /* OUT (no reply) */ | ||
163 | // header and: | ||
164 | __le32 msg_type; /* RNDIS_MSG_HALT */ | ||
165 | __le32 msg_len; | ||
166 | __le32 request_id; | ||
167 | } __attribute__ ((packed)); | ||
168 | |||
169 | struct rndis_query { /* OUT */ | ||
170 | // header and: | ||
171 | __le32 msg_type; /* RNDIS_MSG_QUERY */ | ||
172 | __le32 msg_len; | ||
173 | __le32 request_id; | ||
174 | __le32 oid; | ||
175 | __le32 len; | ||
176 | __le32 offset; | ||
177 | /*?*/ __le32 handle; // zero | ||
178 | } __attribute__ ((packed)); | ||
179 | |||
180 | struct rndis_query_c { /* IN */ | ||
181 | // header and: | ||
182 | __le32 msg_type; /* RNDIS_MSG_QUERY_C */ | ||
183 | __le32 msg_len; | ||
184 | __le32 request_id; | ||
185 | __le32 status; | ||
186 | __le32 len; | ||
187 | __le32 offset; | ||
188 | } __attribute__ ((packed)); | ||
189 | |||
190 | struct rndis_set { /* OUT */ | ||
191 | // header and: | ||
192 | __le32 msg_type; /* RNDIS_MSG_SET */ | ||
193 | __le32 msg_len; | ||
194 | __le32 request_id; | ||
195 | __le32 oid; | ||
196 | __le32 len; | ||
197 | __le32 offset; | ||
198 | /*?*/ __le32 handle; // zero | ||
199 | } __attribute__ ((packed)); | ||
200 | |||
201 | struct rndis_set_c { /* IN */ | ||
202 | // header and: | ||
203 | __le32 msg_type; /* RNDIS_MSG_SET_C */ | ||
204 | __le32 msg_len; | ||
205 | __le32 request_id; | ||
206 | __le32 status; | ||
207 | } __attribute__ ((packed)); | ||
208 | |||
209 | struct rndis_reset { /* IN */ | ||
210 | // header and: | ||
211 | __le32 msg_type; /* RNDIS_MSG_RESET */ | ||
212 | __le32 msg_len; | ||
213 | __le32 reserved; | ||
214 | } __attribute__ ((packed)); | ||
215 | |||
216 | struct rndis_reset_c { /* OUT */ | ||
217 | // header and: | ||
218 | __le32 msg_type; /* RNDIS_MSG_RESET_C */ | ||
219 | __le32 msg_len; | ||
220 | __le32 status; | ||
221 | __le32 addressing_lost; | ||
222 | } __attribute__ ((packed)); | ||
223 | |||
224 | struct rndis_indicate { /* IN (unrequested) */ | ||
225 | // header and: | ||
226 | __le32 msg_type; /* RNDIS_MSG_INDICATE */ | ||
227 | __le32 msg_len; | ||
228 | __le32 status; | ||
229 | __le32 length; | ||
230 | __le32 offset; | ||
231 | /**/ __le32 diag_status; | ||
232 | __le32 error_offset; | ||
233 | /**/ __le32 message; | ||
234 | } __attribute__ ((packed)); | ||
235 | |||
236 | struct rndis_keepalive { /* OUT (optionally IN) */ | ||
237 | // header and: | ||
238 | __le32 msg_type; /* RNDIS_MSG_KEEPALIVE */ | ||
239 | __le32 msg_len; | ||
240 | __le32 request_id; | ||
241 | } __attribute__ ((packed)); | ||
242 | |||
243 | struct rndis_keepalive_c { /* IN (optionally OUT) */ | ||
244 | // header and: | ||
245 | __le32 msg_type; /* RNDIS_MSG_KEEPALIVE_C */ | ||
246 | __le32 msg_len; | ||
247 | __le32 request_id; | ||
248 | __le32 status; | ||
249 | } __attribute__ ((packed)); | ||
250 | |||
251 | /* NOTE: about 30 OIDs are "mandatory" for peripherals to support ... and | ||
252 | * there are gobs more that may optionally be supported. We'll avoid as much | ||
253 | * of that mess as possible. | ||
254 | */ | ||
255 | #define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101) | ||
256 | #define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106) | ||
257 | #define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e) | ||
258 | |||
259 | /* | ||
260 | * RNDIS notifications from device: command completion; "reverse" | ||
261 | * keepalives; etc | ||
262 | */ | ||
263 | static void rndis_status(struct usbnet *dev, struct urb *urb) | ||
264 | { | ||
265 | devdbg(dev, "rndis status urb, len %d stat %d", | ||
266 | urb->actual_length, urb->status); | ||
267 | // FIXME for keepalives, respond immediately (asynchronously) | ||
268 | // if not an RNDIS status, do like cdc_status(dev,urb) does | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * RPC done RNDIS-style. Caller guarantees: | ||
273 | * - message is properly byteswapped | ||
274 | * - there's no other request pending | ||
275 | * - buf can hold up to 1KB response (required by RNDIS spec) | ||
276 | * On return, the first few entries are already byteswapped. | ||
277 | * | ||
278 | * Call context is likely probe(), before interface name is known, | ||
279 | * which is why we won't try to use it in the diagnostics. | ||
280 | */ | ||
281 | static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) | ||
282 | { | ||
283 | struct cdc_state *info = (void *) &dev->data; | ||
284 | int master_ifnum; | ||
285 | int retval; | ||
286 | unsigned count; | ||
287 | __le32 rsp; | ||
288 | u32 xid = 0, msg_len, request_id; | ||
289 | |||
290 | /* REVISIT when this gets called from contexts other than probe() or | ||
291 | * disconnect(): either serialize, or dispatch responses on xid | ||
292 | */ | ||
293 | |||
294 | /* Issue the request; xid is unique, don't bother byteswapping it */ | ||
295 | if (likely(buf->msg_type != RNDIS_MSG_HALT | ||
296 | && buf->msg_type != RNDIS_MSG_RESET)) { | ||
297 | xid = dev->xid++; | ||
298 | if (!xid) | ||
299 | xid = dev->xid++; | ||
300 | buf->request_id = (__force __le32) xid; | ||
301 | } | ||
302 | master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; | ||
303 | retval = usb_control_msg(dev->udev, | ||
304 | usb_sndctrlpipe(dev->udev, 0), | ||
305 | USB_CDC_SEND_ENCAPSULATED_COMMAND, | ||
306 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
307 | 0, master_ifnum, | ||
308 | buf, le32_to_cpu(buf->msg_len), | ||
309 | RNDIS_CONTROL_TIMEOUT_MS); | ||
310 | if (unlikely(retval < 0 || xid == 0)) | ||
311 | return retval; | ||
312 | |||
313 | // FIXME Seems like some devices discard responses when | ||
314 | // we time out and cancel our "get response" requests... | ||
315 | // so, this is fragile. Probably need to poll for status. | ||
316 | |||
317 | /* ignore status endpoint, just poll the control channel; | ||
318 | * the request probably completed immediately | ||
319 | */ | ||
320 | rsp = buf->msg_type | RNDIS_MSG_COMPLETION; | ||
321 | for (count = 0; count < 10; count++) { | ||
322 | memset(buf, 0, CONTROL_BUFFER_SIZE); | ||
323 | retval = usb_control_msg(dev->udev, | ||
324 | usb_rcvctrlpipe(dev->udev, 0), | ||
325 | USB_CDC_GET_ENCAPSULATED_RESPONSE, | ||
326 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
327 | 0, master_ifnum, | ||
328 | buf, CONTROL_BUFFER_SIZE, | ||
329 | RNDIS_CONTROL_TIMEOUT_MS); | ||
330 | if (likely(retval >= 8)) { | ||
331 | msg_len = le32_to_cpu(buf->msg_len); | ||
332 | request_id = (__force u32) buf->request_id; | ||
333 | if (likely(buf->msg_type == rsp)) { | ||
334 | if (likely(request_id == xid)) { | ||
335 | if (unlikely(rsp == RNDIS_MSG_RESET_C)) | ||
336 | return 0; | ||
337 | if (likely(RNDIS_STATUS_SUCCESS | ||
338 | == buf->status)) | ||
339 | return 0; | ||
340 | dev_dbg(&info->control->dev, | ||
341 | "rndis reply status %08x\n", | ||
342 | le32_to_cpu(buf->status)); | ||
343 | return -EL3RST; | ||
344 | } | ||
345 | dev_dbg(&info->control->dev, | ||
346 | "rndis reply id %d expected %d\n", | ||
347 | request_id, xid); | ||
348 | /* then likely retry */ | ||
349 | } else switch (buf->msg_type) { | ||
350 | case RNDIS_MSG_INDICATE: { /* fault */ | ||
351 | // struct rndis_indicate *msg = (void *)buf; | ||
352 | dev_info(&info->control->dev, | ||
353 | "rndis fault indication\n"); | ||
354 | } | ||
355 | break; | ||
356 | case RNDIS_MSG_KEEPALIVE: { /* ping */ | ||
357 | struct rndis_keepalive_c *msg = (void *)buf; | ||
358 | |||
359 | msg->msg_type = RNDIS_MSG_KEEPALIVE_C; | ||
360 | msg->msg_len = ccpu2(sizeof *msg); | ||
361 | msg->status = RNDIS_STATUS_SUCCESS; | ||
362 | retval = usb_control_msg(dev->udev, | ||
363 | usb_sndctrlpipe(dev->udev, 0), | ||
364 | USB_CDC_SEND_ENCAPSULATED_COMMAND, | ||
365 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
366 | 0, master_ifnum, | ||
367 | msg, sizeof *msg, | ||
368 | RNDIS_CONTROL_TIMEOUT_MS); | ||
369 | if (unlikely(retval < 0)) | ||
370 | dev_dbg(&info->control->dev, | ||
371 | "rndis keepalive err %d\n", | ||
372 | retval); | ||
373 | } | ||
374 | break; | ||
375 | default: | ||
376 | dev_dbg(&info->control->dev, | ||
377 | "unexpected rndis msg %08x len %d\n", | ||
378 | le32_to_cpu(buf->msg_type), msg_len); | ||
379 | } | ||
380 | } else { | ||
381 | /* device probably issued a protocol stall; ignore */ | ||
382 | dev_dbg(&info->control->dev, | ||
383 | "rndis response error, code %d\n", retval); | ||
384 | } | ||
385 | msleep(2); | ||
386 | } | ||
387 | dev_dbg(&info->control->dev, "rndis response timeout\n"); | ||
388 | return -ETIMEDOUT; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * rndis_query: | ||
393 | * | ||
394 | * Performs a query for @oid along with 0 or more bytes of payload as | ||
395 | * specified by @in_len. If @reply_len is not set to -1 then the reply | ||
396 | * length is checked against this value, resulting in an error if it | ||
397 | * doesn't match. | ||
398 | * | ||
399 | * NOTE: Adding a payload exactly or greater than the size of the expected | ||
400 | * response payload is an evident requirement MSFT added for ActiveSync. | ||
401 | * | ||
402 | * The only exception is for OIDs that return a variably sized response, | ||
403 | * in which case no payload should be added. This undocumented (and | ||
404 | * nonsensical!) issue was found by sniffing protocol requests from the | ||
405 | * ActiveSync 4.1 Windows driver. | ||
406 | */ | ||
407 | static int rndis_query(struct usbnet *dev, struct usb_interface *intf, | ||
408 | void *buf, u32 oid, u32 in_len, | ||
409 | void **reply, int *reply_len) | ||
410 | { | ||
411 | int retval; | ||
412 | union { | ||
413 | void *buf; | ||
414 | struct rndis_msg_hdr *header; | ||
415 | struct rndis_query *get; | ||
416 | struct rndis_query_c *get_c; | ||
417 | } u; | ||
418 | u32 off, len; | ||
419 | |||
420 | u.buf = buf; | ||
421 | |||
422 | memset(u.get, 0, sizeof *u.get + in_len); | ||
423 | u.get->msg_type = RNDIS_MSG_QUERY; | ||
424 | u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); | ||
425 | u.get->oid = oid; | ||
426 | u.get->len = cpu_to_le32(in_len); | ||
427 | u.get->offset = ccpu2(20); | ||
428 | |||
429 | retval = rndis_command(dev, u.header); | ||
430 | if (unlikely(retval < 0)) { | ||
431 | dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", | ||
432 | oid, retval); | ||
433 | return retval; | ||
434 | } | ||
435 | |||
436 | off = le32_to_cpu(u.get_c->offset); | ||
437 | len = le32_to_cpu(u.get_c->len); | ||
438 | if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) | ||
439 | goto response_error; | ||
440 | |||
441 | if (*reply_len != -1 && len != *reply_len) | ||
442 | goto response_error; | ||
443 | |||
444 | *reply = (unsigned char *) &u.get_c->request_id + off; | ||
445 | *reply_len = len; | ||
446 | |||
447 | return retval; | ||
448 | |||
449 | response_error: | ||
450 | dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) " | ||
451 | "invalid response - off %d len %d\n", | ||
452 | oid, off, len); | ||
453 | return -EDOM; | ||
454 | } | ||
455 | |||
456 | static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) | ||
457 | { | ||
458 | int retval; | ||
459 | struct net_device *net = dev->net; | ||
460 | struct cdc_state *info = (void *) &dev->data; | ||
461 | union { | ||
462 | void *buf; | ||
463 | struct rndis_msg_hdr *header; | ||
464 | struct rndis_init *init; | ||
465 | struct rndis_init_c *init_c; | ||
466 | struct rndis_query *get; | ||
467 | struct rndis_query_c *get_c; | ||
468 | struct rndis_set *set; | ||
469 | struct rndis_set_c *set_c; | ||
470 | } u; | ||
471 | u32 tmp; | ||
472 | int reply_len; | ||
473 | unsigned char *bp; | ||
474 | |||
475 | /* we can't rely on i/o from stack working, or stack allocation */ | ||
476 | u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); | ||
477 | if (!u.buf) | ||
478 | return -ENOMEM; | ||
479 | retval = usbnet_generic_cdc_bind(dev, intf); | ||
480 | if (retval < 0) | ||
481 | goto fail; | ||
482 | |||
483 | u.init->msg_type = RNDIS_MSG_INIT; | ||
484 | u.init->msg_len = ccpu2(sizeof *u.init); | ||
485 | u.init->major_version = ccpu2(1); | ||
486 | u.init->minor_version = ccpu2(0); | ||
487 | |||
488 | /* max transfer (in spec) is 0x4000 at full speed, but for | ||
489 | * TX we'll stick to one Ethernet packet plus RNDIS framing. | ||
490 | * For RX we handle drivers that zero-pad to end-of-packet. | ||
491 | * Don't let userspace change these settings. | ||
492 | * | ||
493 | * NOTE: there still seems to be wierdness here, as if we need | ||
494 | * to do some more things to make sure WinCE targets accept this. | ||
495 | * They default to jumbograms of 8KB or 16KB, which is absurd | ||
496 | * for such low data rates and which is also more than Linux | ||
497 | * can usually expect to allocate for SKB data... | ||
498 | */ | ||
499 | net->hard_header_len += sizeof (struct rndis_data_hdr); | ||
500 | dev->hard_mtu = net->mtu + net->hard_header_len; | ||
501 | |||
502 | dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); | ||
503 | dev->rx_urb_size &= ~(dev->maxpacket - 1); | ||
504 | u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); | ||
505 | |||
506 | net->change_mtu = NULL; | ||
507 | retval = rndis_command(dev, u.header); | ||
508 | if (unlikely(retval < 0)) { | ||
509 | /* it might not even be an RNDIS device!! */ | ||
510 | dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); | ||
511 | goto fail_and_release; | ||
512 | } | ||
513 | tmp = le32_to_cpu(u.init_c->max_transfer_size); | ||
514 | if (tmp < dev->hard_mtu) { | ||
515 | dev_err(&intf->dev, | ||
516 | "dev can't take %u byte packets (max %u)\n", | ||
517 | dev->hard_mtu, tmp); | ||
518 | goto fail_and_release; | ||
519 | } | ||
520 | |||
521 | /* REVISIT: peripheral "alignment" request is ignored ... */ | ||
522 | dev_dbg(&intf->dev, | ||
523 | "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", | ||
524 | dev->hard_mtu, tmp, dev->rx_urb_size, | ||
525 | 1 << le32_to_cpu(u.init_c->packet_alignment)); | ||
526 | |||
527 | /* Get designated host ethernet address */ | ||
528 | reply_len = ETH_ALEN; | ||
529 | retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, | ||
530 | 48, (void **) &bp, &reply_len); | ||
531 | if (unlikely(retval< 0)) { | ||
532 | dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); | ||
533 | goto fail_and_release; | ||
534 | } | ||
535 | memcpy(net->dev_addr, bp, ETH_ALEN); | ||
536 | |||
537 | /* set a nonzero filter to enable data transfers */ | ||
538 | memset(u.set, 0, sizeof *u.set); | ||
539 | u.set->msg_type = RNDIS_MSG_SET; | ||
540 | u.set->msg_len = ccpu2(4 + sizeof *u.set); | ||
541 | u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; | ||
542 | u.set->len = ccpu2(4); | ||
543 | u.set->offset = ccpu2((sizeof *u.set) - 8); | ||
544 | *(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER); | ||
545 | |||
546 | retval = rndis_command(dev, u.header); | ||
547 | if (unlikely(retval < 0)) { | ||
548 | dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); | ||
549 | goto fail_and_release; | ||
550 | } | ||
551 | |||
552 | retval = 0; | ||
553 | |||
554 | kfree(u.buf); | ||
555 | return retval; | ||
556 | |||
557 | fail_and_release: | ||
558 | usb_set_intfdata(info->data, NULL); | ||
559 | usb_driver_release_interface(driver_of(intf), info->data); | ||
560 | info->data = NULL; | ||
561 | fail: | ||
562 | kfree(u.buf); | ||
563 | return retval; | ||
564 | } | ||
565 | |||
566 | static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
567 | { | ||
568 | struct rndis_halt *halt; | ||
569 | |||
570 | /* try to clear any rndis state/activity (no i/o from stack!) */ | ||
571 | halt = kzalloc(sizeof *halt, GFP_KERNEL); | ||
572 | if (halt) { | ||
573 | halt->msg_type = RNDIS_MSG_HALT; | ||
574 | halt->msg_len = ccpu2(sizeof *halt); | ||
575 | (void) rndis_command(dev, (void *)halt); | ||
576 | kfree(halt); | ||
577 | } | ||
578 | |||
579 | return usbnet_cdc_unbind(dev, intf); | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * DATA -- host must not write zlps | ||
584 | */ | ||
585 | static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
586 | { | ||
587 | /* peripheral may have batched packets to us... */ | ||
588 | while (likely(skb->len)) { | ||
589 | struct rndis_data_hdr *hdr = (void *)skb->data; | ||
590 | struct sk_buff *skb2; | ||
591 | u32 msg_len, data_offset, data_len; | ||
592 | |||
593 | msg_len = le32_to_cpu(hdr->msg_len); | ||
594 | data_offset = le32_to_cpu(hdr->data_offset); | ||
595 | data_len = le32_to_cpu(hdr->data_len); | ||
596 | |||
597 | /* don't choke if we see oob, per-packet data, etc */ | ||
598 | if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET | ||
599 | || skb->len < msg_len | ||
600 | || (data_offset + data_len + 8) > msg_len)) { | ||
601 | dev->stats.rx_frame_errors++; | ||
602 | devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d", | ||
603 | le32_to_cpu(hdr->msg_type), | ||
604 | msg_len, data_offset, data_len, skb->len); | ||
605 | return 0; | ||
606 | } | ||
607 | skb_pull(skb, 8 + data_offset); | ||
608 | |||
609 | /* at most one packet left? */ | ||
610 | if (likely((data_len - skb->len) <= sizeof *hdr)) { | ||
611 | skb_trim(skb, data_len); | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | /* try to return all the packets in the batch */ | ||
616 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
617 | if (unlikely(!skb2)) | ||
618 | break; | ||
619 | skb_pull(skb, msg_len - sizeof *hdr); | ||
620 | skb_trim(skb2, data_len); | ||
621 | usbnet_skb_return(dev, skb2); | ||
622 | } | ||
623 | |||
624 | /* caller will usbnet_skb_return the remaining packet */ | ||
625 | return 1; | ||
626 | } | ||
627 | |||
628 | static struct sk_buff * | ||
629 | rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | ||
630 | { | ||
631 | struct rndis_data_hdr *hdr; | ||
632 | struct sk_buff *skb2; | ||
633 | unsigned len = skb->len; | ||
634 | |||
635 | if (likely(!skb_cloned(skb))) { | ||
636 | int room = skb_headroom(skb); | ||
637 | |||
638 | /* enough head room as-is? */ | ||
639 | if (unlikely((sizeof *hdr) <= room)) | ||
640 | goto fill; | ||
641 | |||
642 | /* enough room, but needs to be readjusted? */ | ||
643 | room += skb_tailroom(skb); | ||
644 | if (likely((sizeof *hdr) <= room)) { | ||
645 | skb->data = memmove(skb->head + sizeof *hdr, | ||
646 | skb->data, len); | ||
647 | skb_set_tail_pointer(skb, len); | ||
648 | goto fill; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | /* create a new skb, with the correct size (and tailpad) */ | ||
653 | skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); | ||
654 | dev_kfree_skb_any(skb); | ||
655 | if (unlikely(!skb2)) | ||
656 | return skb2; | ||
657 | skb = skb2; | ||
658 | |||
659 | /* fill out the RNDIS header. we won't bother trying to batch | ||
660 | * packets; Linux minimizes wasted bandwidth through tx queues. | ||
661 | */ | ||
662 | fill: | ||
663 | hdr = (void *) __skb_push(skb, sizeof *hdr); | ||
664 | memset(hdr, 0, sizeof *hdr); | ||
665 | hdr->msg_type = RNDIS_MSG_PACKET; | ||
666 | hdr->msg_len = cpu_to_le32(skb->len); | ||
667 | hdr->data_offset = ccpu2(sizeof(*hdr) - 8); | ||
668 | hdr->data_len = cpu_to_le32(len); | ||
669 | |||
670 | /* FIXME make the last packet always be short ... */ | ||
671 | return skb; | ||
672 | } | ||
673 | |||
674 | |||
675 | static const struct driver_info rndis_info = { | ||
676 | .description = "RNDIS device", | ||
677 | .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, | ||
678 | .bind = rndis_bind, | ||
679 | .unbind = rndis_unbind, | ||
680 | .status = rndis_status, | ||
681 | .rx_fixup = rndis_rx_fixup, | ||
682 | .tx_fixup = rndis_tx_fixup, | ||
683 | }; | ||
684 | |||
685 | #undef ccpu2 | ||
686 | |||
687 | |||
688 | /*-------------------------------------------------------------------------*/ | ||
689 | |||
690 | static const struct usb_device_id products [] = { | ||
691 | { | ||
692 | /* RNDIS is MSFT's un-official variant of CDC ACM */ | ||
693 | USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), | ||
694 | .driver_info = (unsigned long) &rndis_info, | ||
695 | }, { | ||
696 | /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ | ||
697 | USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), | ||
698 | .driver_info = (unsigned long) &rndis_info, | ||
699 | }, | ||
700 | { }, // END | ||
701 | }; | ||
702 | MODULE_DEVICE_TABLE(usb, products); | ||
703 | |||
704 | static struct usb_driver rndis_driver = { | ||
705 | .name = "rndis_host", | ||
706 | .id_table = products, | ||
707 | .probe = usbnet_probe, | ||
708 | .disconnect = usbnet_disconnect, | ||
709 | .suspend = usbnet_suspend, | ||
710 | .resume = usbnet_resume, | ||
711 | }; | ||
712 | |||
713 | static int __init rndis_init(void) | ||
714 | { | ||
715 | return usb_register(&rndis_driver); | ||
716 | } | ||
717 | module_init(rndis_init); | ||
718 | |||
719 | static void __exit rndis_exit(void) | ||
720 | { | ||
721 | usb_deregister(&rndis_driver); | ||
722 | } | ||
723 | module_exit(rndis_exit); | ||
724 | |||
725 | MODULE_AUTHOR("David Brownell"); | ||
726 | MODULE_DESCRIPTION("USB Host side RNDIS driver"); | ||
727 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c new file mode 100644 index 000000000000..fa598f0340cf --- /dev/null +++ b/drivers/net/usb/rtl8150.c | |||
@@ -0,0 +1,1004 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * version 2 as published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/signal.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/netdevice.h> | ||
14 | #include <linux/etherdevice.h> | ||
15 | #include <linux/mii.h> | ||
16 | #include <linux/ethtool.h> | ||
17 | #include <linux/usb.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | |||
20 | /* Version Information */ | ||
21 | #define DRIVER_VERSION "v0.6.2 (2004/08/27)" | ||
22 | #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" | ||
23 | #define DRIVER_DESC "rtl8150 based usb-ethernet driver" | ||
24 | |||
25 | #define IDR 0x0120 | ||
26 | #define MAR 0x0126 | ||
27 | #define CR 0x012e | ||
28 | #define TCR 0x012f | ||
29 | #define RCR 0x0130 | ||
30 | #define TSR 0x0132 | ||
31 | #define RSR 0x0133 | ||
32 | #define CON0 0x0135 | ||
33 | #define CON1 0x0136 | ||
34 | #define MSR 0x0137 | ||
35 | #define PHYADD 0x0138 | ||
36 | #define PHYDAT 0x0139 | ||
37 | #define PHYCNT 0x013b | ||
38 | #define GPPC 0x013d | ||
39 | #define BMCR 0x0140 | ||
40 | #define BMSR 0x0142 | ||
41 | #define ANAR 0x0144 | ||
42 | #define ANLP 0x0146 | ||
43 | #define AER 0x0148 | ||
44 | #define CSCR 0x014C /* This one has the link status */ | ||
45 | #define CSCR_LINK_STATUS (1 << 3) | ||
46 | |||
47 | #define IDR_EEPROM 0x1202 | ||
48 | |||
49 | #define PHY_READ 0 | ||
50 | #define PHY_WRITE 0x20 | ||
51 | #define PHY_GO 0x40 | ||
52 | |||
53 | #define MII_TIMEOUT 10 | ||
54 | #define INTBUFSIZE 8 | ||
55 | |||
56 | #define RTL8150_REQT_READ 0xc0 | ||
57 | #define RTL8150_REQT_WRITE 0x40 | ||
58 | #define RTL8150_REQ_GET_REGS 0x05 | ||
59 | #define RTL8150_REQ_SET_REGS 0x05 | ||
60 | |||
61 | |||
62 | /* Transmit status register errors */ | ||
63 | #define TSR_ECOL (1<<5) | ||
64 | #define TSR_LCOL (1<<4) | ||
65 | #define TSR_LOSS_CRS (1<<3) | ||
66 | #define TSR_JBR (1<<2) | ||
67 | #define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) | ||
68 | /* Receive status register errors */ | ||
69 | #define RSR_CRC (1<<2) | ||
70 | #define RSR_FAE (1<<1) | ||
71 | #define RSR_ERRORS (RSR_CRC | RSR_FAE) | ||
72 | |||
73 | /* Media status register definitions */ | ||
74 | #define MSR_DUPLEX (1<<4) | ||
75 | #define MSR_SPEED (1<<3) | ||
76 | #define MSR_LINK (1<<2) | ||
77 | |||
78 | /* Interrupt pipe data */ | ||
79 | #define INT_TSR 0x00 | ||
80 | #define INT_RSR 0x01 | ||
81 | #define INT_MSR 0x02 | ||
82 | #define INT_WAKSR 0x03 | ||
83 | #define INT_TXOK_CNT 0x04 | ||
84 | #define INT_RXLOST_CNT 0x05 | ||
85 | #define INT_CRERR_CNT 0x06 | ||
86 | #define INT_COL_CNT 0x07 | ||
87 | |||
88 | /* Transmit status register errors */ | ||
89 | #define TSR_ECOL (1<<5) | ||
90 | #define TSR_LCOL (1<<4) | ||
91 | #define TSR_LOSS_CRS (1<<3) | ||
92 | #define TSR_JBR (1<<2) | ||
93 | #define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) | ||
94 | /* Receive status register errors */ | ||
95 | #define RSR_CRC (1<<2) | ||
96 | #define RSR_FAE (1<<1) | ||
97 | #define RSR_ERRORS (RSR_CRC | RSR_FAE) | ||
98 | |||
99 | /* Media status register definitions */ | ||
100 | #define MSR_DUPLEX (1<<4) | ||
101 | #define MSR_SPEED (1<<3) | ||
102 | #define MSR_LINK (1<<2) | ||
103 | |||
104 | /* Interrupt pipe data */ | ||
105 | #define INT_TSR 0x00 | ||
106 | #define INT_RSR 0x01 | ||
107 | #define INT_MSR 0x02 | ||
108 | #define INT_WAKSR 0x03 | ||
109 | #define INT_TXOK_CNT 0x04 | ||
110 | #define INT_RXLOST_CNT 0x05 | ||
111 | #define INT_CRERR_CNT 0x06 | ||
112 | #define INT_COL_CNT 0x07 | ||
113 | |||
114 | |||
115 | #define RTL8150_MTU 1540 | ||
116 | #define RTL8150_TX_TIMEOUT (HZ) | ||
117 | #define RX_SKB_POOL_SIZE 4 | ||
118 | |||
119 | /* rtl8150 flags */ | ||
120 | #define RTL8150_HW_CRC 0 | ||
121 | #define RX_REG_SET 1 | ||
122 | #define RTL8150_UNPLUG 2 | ||
123 | #define RX_URB_FAIL 3 | ||
124 | |||
125 | /* Define these values to match your device */ | ||
126 | #define VENDOR_ID_REALTEK 0x0bda | ||
127 | #define VENDOR_ID_MELCO 0x0411 | ||
128 | #define VENDOR_ID_MICRONET 0x3980 | ||
129 | #define VENDOR_ID_LONGSHINE 0x07b8 | ||
130 | #define VENDOR_ID_OQO 0x1557 | ||
131 | #define VENDOR_ID_ZYXEL 0x0586 | ||
132 | |||
133 | #define PRODUCT_ID_RTL8150 0x8150 | ||
134 | #define PRODUCT_ID_LUAKTX 0x0012 | ||
135 | #define PRODUCT_ID_LCS8138TX 0x401a | ||
136 | #define PRODUCT_ID_SP128AR 0x0003 | ||
137 | #define PRODUCT_ID_PRESTIGE 0x401a | ||
138 | |||
139 | #undef EEPROM_WRITE | ||
140 | |||
141 | /* table of devices that work with this driver */ | ||
142 | static struct usb_device_id rtl8150_table[] = { | ||
143 | {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, | ||
144 | {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, | ||
145 | {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, | ||
146 | {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, | ||
147 | {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)}, | ||
148 | {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)}, | ||
149 | {} | ||
150 | }; | ||
151 | |||
152 | MODULE_DEVICE_TABLE(usb, rtl8150_table); | ||
153 | |||
154 | struct rtl8150 { | ||
155 | unsigned long flags; | ||
156 | struct usb_device *udev; | ||
157 | struct tasklet_struct tl; | ||
158 | struct net_device_stats stats; | ||
159 | struct net_device *netdev; | ||
160 | struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb; | ||
161 | struct sk_buff *tx_skb, *rx_skb; | ||
162 | struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE]; | ||
163 | spinlock_t rx_pool_lock; | ||
164 | struct usb_ctrlrequest dr; | ||
165 | int intr_interval; | ||
166 | __le16 rx_creg; | ||
167 | u8 *intr_buff; | ||
168 | u8 phy; | ||
169 | }; | ||
170 | |||
171 | typedef struct rtl8150 rtl8150_t; | ||
172 | |||
173 | static void fill_skb_pool(rtl8150_t *); | ||
174 | static void free_skb_pool(rtl8150_t *); | ||
175 | static inline struct sk_buff *pull_skb(rtl8150_t *); | ||
176 | static void rtl8150_disconnect(struct usb_interface *intf); | ||
177 | static int rtl8150_probe(struct usb_interface *intf, | ||
178 | const struct usb_device_id *id); | ||
179 | static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message); | ||
180 | static int rtl8150_resume(struct usb_interface *intf); | ||
181 | |||
182 | static const char driver_name [] = "rtl8150"; | ||
183 | |||
184 | static struct usb_driver rtl8150_driver = { | ||
185 | .name = driver_name, | ||
186 | .probe = rtl8150_probe, | ||
187 | .disconnect = rtl8150_disconnect, | ||
188 | .id_table = rtl8150_table, | ||
189 | .suspend = rtl8150_suspend, | ||
190 | .resume = rtl8150_resume | ||
191 | }; | ||
192 | |||
193 | /* | ||
194 | ** | ||
195 | ** device related part of the code | ||
196 | ** | ||
197 | */ | ||
198 | static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) | ||
199 | { | ||
200 | return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), | ||
201 | RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, | ||
202 | indx, 0, data, size, 500); | ||
203 | } | ||
204 | |||
205 | static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) | ||
206 | { | ||
207 | return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), | ||
208 | RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, | ||
209 | indx, 0, data, size, 500); | ||
210 | } | ||
211 | |||
212 | static void ctrl_callback(struct urb *urb) | ||
213 | { | ||
214 | rtl8150_t *dev; | ||
215 | |||
216 | switch (urb->status) { | ||
217 | case 0: | ||
218 | break; | ||
219 | case -EINPROGRESS: | ||
220 | break; | ||
221 | case -ENOENT: | ||
222 | break; | ||
223 | default: | ||
224 | warn("ctrl urb status %d", urb->status); | ||
225 | } | ||
226 | dev = urb->context; | ||
227 | clear_bit(RX_REG_SET, &dev->flags); | ||
228 | } | ||
229 | |||
230 | static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) | ||
231 | { | ||
232 | int ret; | ||
233 | |||
234 | if (test_bit(RX_REG_SET, &dev->flags)) | ||
235 | return -EAGAIN; | ||
236 | |||
237 | dev->dr.bRequestType = RTL8150_REQT_WRITE; | ||
238 | dev->dr.bRequest = RTL8150_REQ_SET_REGS; | ||
239 | dev->dr.wValue = cpu_to_le16(indx); | ||
240 | dev->dr.wIndex = 0; | ||
241 | dev->dr.wLength = cpu_to_le16(size); | ||
242 | dev->ctrl_urb->transfer_buffer_length = size; | ||
243 | usb_fill_control_urb(dev->ctrl_urb, dev->udev, | ||
244 | usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, | ||
245 | &dev->rx_creg, size, ctrl_callback, dev); | ||
246 | if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) { | ||
247 | if (ret == -ENODEV) | ||
248 | netif_device_detach(dev->netdev); | ||
249 | err("control request submission failed: %d", ret); | ||
250 | } else | ||
251 | set_bit(RX_REG_SET, &dev->flags); | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg) | ||
257 | { | ||
258 | int i; | ||
259 | u8 data[3], tmp; | ||
260 | |||
261 | data[0] = phy; | ||
262 | data[1] = data[2] = 0; | ||
263 | tmp = indx | PHY_READ | PHY_GO; | ||
264 | i = 0; | ||
265 | |||
266 | set_registers(dev, PHYADD, sizeof(data), data); | ||
267 | set_registers(dev, PHYCNT, 1, &tmp); | ||
268 | do { | ||
269 | get_registers(dev, PHYCNT, 1, data); | ||
270 | } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); | ||
271 | |||
272 | if (i < MII_TIMEOUT) { | ||
273 | get_registers(dev, PHYDAT, 2, data); | ||
274 | *reg = data[0] | (data[1] << 8); | ||
275 | return 0; | ||
276 | } else | ||
277 | return 1; | ||
278 | } | ||
279 | |||
280 | static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg) | ||
281 | { | ||
282 | int i; | ||
283 | u8 data[3], tmp; | ||
284 | |||
285 | data[0] = phy; | ||
286 | data[1] = reg & 0xff; | ||
287 | data[2] = (reg >> 8) & 0xff; | ||
288 | tmp = indx | PHY_WRITE | PHY_GO; | ||
289 | i = 0; | ||
290 | |||
291 | set_registers(dev, PHYADD, sizeof(data), data); | ||
292 | set_registers(dev, PHYCNT, 1, &tmp); | ||
293 | do { | ||
294 | get_registers(dev, PHYCNT, 1, data); | ||
295 | } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); | ||
296 | |||
297 | if (i < MII_TIMEOUT) | ||
298 | return 0; | ||
299 | else | ||
300 | return 1; | ||
301 | } | ||
302 | |||
303 | static inline void set_ethernet_addr(rtl8150_t * dev) | ||
304 | { | ||
305 | u8 node_id[6]; | ||
306 | |||
307 | get_registers(dev, IDR, sizeof(node_id), node_id); | ||
308 | memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id)); | ||
309 | } | ||
310 | |||
311 | static int rtl8150_set_mac_address(struct net_device *netdev, void *p) | ||
312 | { | ||
313 | struct sockaddr *addr = p; | ||
314 | rtl8150_t *dev = netdev_priv(netdev); | ||
315 | int i; | ||
316 | |||
317 | if (netif_running(netdev)) | ||
318 | return -EBUSY; | ||
319 | |||
320 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | ||
321 | dbg("%s: Setting MAC address to ", netdev->name); | ||
322 | for (i = 0; i < 5; i++) | ||
323 | dbg("%02X:", netdev->dev_addr[i]); | ||
324 | dbg("%02X\n", netdev->dev_addr[i]); | ||
325 | /* Set the IDR registers. */ | ||
326 | set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr); | ||
327 | #ifdef EEPROM_WRITE | ||
328 | { | ||
329 | u8 cr; | ||
330 | /* Get the CR contents. */ | ||
331 | get_registers(dev, CR, 1, &cr); | ||
332 | /* Set the WEPROM bit (eeprom write enable). */ | ||
333 | cr |= 0x20; | ||
334 | set_registers(dev, CR, 1, &cr); | ||
335 | /* Write the MAC address into eeprom. Eeprom writes must be word-sized, | ||
336 | so we need to split them up. */ | ||
337 | for (i = 0; i * 2 < netdev->addr_len; i++) { | ||
338 | set_registers(dev, IDR_EEPROM + (i * 2), 2, | ||
339 | netdev->dev_addr + (i * 2)); | ||
340 | } | ||
341 | /* Clear the WEPROM bit (preventing accidental eeprom writes). */ | ||
342 | cr &= 0xdf; | ||
343 | set_registers(dev, CR, 1, &cr); | ||
344 | } | ||
345 | #endif | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int rtl8150_reset(rtl8150_t * dev) | ||
350 | { | ||
351 | u8 data = 0x10; | ||
352 | int i = HZ; | ||
353 | |||
354 | set_registers(dev, CR, 1, &data); | ||
355 | do { | ||
356 | get_registers(dev, CR, 1, &data); | ||
357 | } while ((data & 0x10) && --i); | ||
358 | |||
359 | return (i > 0) ? 1 : 0; | ||
360 | } | ||
361 | |||
362 | static int alloc_all_urbs(rtl8150_t * dev) | ||
363 | { | ||
364 | dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
365 | if (!dev->rx_urb) | ||
366 | return 0; | ||
367 | dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
368 | if (!dev->tx_urb) { | ||
369 | usb_free_urb(dev->rx_urb); | ||
370 | return 0; | ||
371 | } | ||
372 | dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
373 | if (!dev->intr_urb) { | ||
374 | usb_free_urb(dev->rx_urb); | ||
375 | usb_free_urb(dev->tx_urb); | ||
376 | return 0; | ||
377 | } | ||
378 | dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
379 | if (!dev->intr_urb) { | ||
380 | usb_free_urb(dev->rx_urb); | ||
381 | usb_free_urb(dev->tx_urb); | ||
382 | usb_free_urb(dev->intr_urb); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | return 1; | ||
387 | } | ||
388 | |||
389 | static void free_all_urbs(rtl8150_t * dev) | ||
390 | { | ||
391 | usb_free_urb(dev->rx_urb); | ||
392 | usb_free_urb(dev->tx_urb); | ||
393 | usb_free_urb(dev->intr_urb); | ||
394 | usb_free_urb(dev->ctrl_urb); | ||
395 | } | ||
396 | |||
397 | static void unlink_all_urbs(rtl8150_t * dev) | ||
398 | { | ||
399 | usb_kill_urb(dev->rx_urb); | ||
400 | usb_kill_urb(dev->tx_urb); | ||
401 | usb_kill_urb(dev->intr_urb); | ||
402 | usb_kill_urb(dev->ctrl_urb); | ||
403 | } | ||
404 | |||
405 | static inline struct sk_buff *pull_skb(rtl8150_t *dev) | ||
406 | { | ||
407 | struct sk_buff *skb; | ||
408 | int i; | ||
409 | |||
410 | for (i = 0; i < RX_SKB_POOL_SIZE; i++) { | ||
411 | if (dev->rx_skb_pool[i]) { | ||
412 | skb = dev->rx_skb_pool[i]; | ||
413 | dev->rx_skb_pool[i] = NULL; | ||
414 | return skb; | ||
415 | } | ||
416 | } | ||
417 | return NULL; | ||
418 | } | ||
419 | |||
420 | static void read_bulk_callback(struct urb *urb) | ||
421 | { | ||
422 | rtl8150_t *dev; | ||
423 | unsigned pkt_len, res; | ||
424 | struct sk_buff *skb; | ||
425 | struct net_device *netdev; | ||
426 | u16 rx_stat; | ||
427 | int status; | ||
428 | |||
429 | dev = urb->context; | ||
430 | if (!dev) | ||
431 | return; | ||
432 | if (test_bit(RTL8150_UNPLUG, &dev->flags)) | ||
433 | return; | ||
434 | netdev = dev->netdev; | ||
435 | if (!netif_device_present(netdev)) | ||
436 | return; | ||
437 | |||
438 | switch (urb->status) { | ||
439 | case 0: | ||
440 | break; | ||
441 | case -ENOENT: | ||
442 | return; /* the urb is in unlink state */ | ||
443 | case -ETIME: | ||
444 | warn("may be reset is needed?.."); | ||
445 | goto goon; | ||
446 | default: | ||
447 | warn("Rx status %d", urb->status); | ||
448 | goto goon; | ||
449 | } | ||
450 | |||
451 | if (!dev->rx_skb) | ||
452 | goto resched; | ||
453 | /* protect against short packets (tell me why we got some?!?) */ | ||
454 | if (urb->actual_length < 4) | ||
455 | goto goon; | ||
456 | |||
457 | res = urb->actual_length; | ||
458 | rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4)); | ||
459 | pkt_len = res - 4; | ||
460 | |||
461 | skb_put(dev->rx_skb, pkt_len); | ||
462 | dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev); | ||
463 | netif_rx(dev->rx_skb); | ||
464 | dev->stats.rx_packets++; | ||
465 | dev->stats.rx_bytes += pkt_len; | ||
466 | |||
467 | spin_lock(&dev->rx_pool_lock); | ||
468 | skb = pull_skb(dev); | ||
469 | spin_unlock(&dev->rx_pool_lock); | ||
470 | if (!skb) | ||
471 | goto resched; | ||
472 | |||
473 | dev->rx_skb = skb; | ||
474 | goon: | ||
475 | usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), | ||
476 | dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); | ||
477 | status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); | ||
478 | if (status == -ENODEV) | ||
479 | netif_device_detach(dev->netdev); | ||
480 | else if (status) { | ||
481 | set_bit(RX_URB_FAIL, &dev->flags); | ||
482 | goto resched; | ||
483 | } else { | ||
484 | clear_bit(RX_URB_FAIL, &dev->flags); | ||
485 | } | ||
486 | |||
487 | return; | ||
488 | resched: | ||
489 | tasklet_schedule(&dev->tl); | ||
490 | } | ||
491 | |||
492 | static void rx_fixup(unsigned long data) | ||
493 | { | ||
494 | rtl8150_t *dev; | ||
495 | struct sk_buff *skb; | ||
496 | int status; | ||
497 | |||
498 | dev = (rtl8150_t *)data; | ||
499 | |||
500 | spin_lock_irq(&dev->rx_pool_lock); | ||
501 | fill_skb_pool(dev); | ||
502 | spin_unlock_irq(&dev->rx_pool_lock); | ||
503 | if (test_bit(RX_URB_FAIL, &dev->flags)) | ||
504 | if (dev->rx_skb) | ||
505 | goto try_again; | ||
506 | spin_lock_irq(&dev->rx_pool_lock); | ||
507 | skb = pull_skb(dev); | ||
508 | spin_unlock_irq(&dev->rx_pool_lock); | ||
509 | if (skb == NULL) | ||
510 | goto tlsched; | ||
511 | dev->rx_skb = skb; | ||
512 | usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), | ||
513 | dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); | ||
514 | try_again: | ||
515 | status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); | ||
516 | if (status == -ENODEV) { | ||
517 | netif_device_detach(dev->netdev); | ||
518 | } else if (status) { | ||
519 | set_bit(RX_URB_FAIL, &dev->flags); | ||
520 | goto tlsched; | ||
521 | } else { | ||
522 | clear_bit(RX_URB_FAIL, &dev->flags); | ||
523 | } | ||
524 | |||
525 | return; | ||
526 | tlsched: | ||
527 | tasklet_schedule(&dev->tl); | ||
528 | } | ||
529 | |||
530 | static void write_bulk_callback(struct urb *urb) | ||
531 | { | ||
532 | rtl8150_t *dev; | ||
533 | |||
534 | dev = urb->context; | ||
535 | if (!dev) | ||
536 | return; | ||
537 | dev_kfree_skb_irq(dev->tx_skb); | ||
538 | if (!netif_device_present(dev->netdev)) | ||
539 | return; | ||
540 | if (urb->status) | ||
541 | info("%s: Tx status %d", dev->netdev->name, urb->status); | ||
542 | dev->netdev->trans_start = jiffies; | ||
543 | netif_wake_queue(dev->netdev); | ||
544 | } | ||
545 | |||
546 | static void intr_callback(struct urb *urb) | ||
547 | { | ||
548 | rtl8150_t *dev; | ||
549 | __u8 *d; | ||
550 | int status; | ||
551 | |||
552 | dev = urb->context; | ||
553 | if (!dev) | ||
554 | return; | ||
555 | switch (urb->status) { | ||
556 | case 0: /* success */ | ||
557 | break; | ||
558 | case -ECONNRESET: /* unlink */ | ||
559 | case -ENOENT: | ||
560 | case -ESHUTDOWN: | ||
561 | return; | ||
562 | /* -EPIPE: should clear the halt */ | ||
563 | default: | ||
564 | info("%s: intr status %d", dev->netdev->name, urb->status); | ||
565 | goto resubmit; | ||
566 | } | ||
567 | |||
568 | d = urb->transfer_buffer; | ||
569 | if (d[0] & TSR_ERRORS) { | ||
570 | dev->stats.tx_errors++; | ||
571 | if (d[INT_TSR] & (TSR_ECOL | TSR_JBR)) | ||
572 | dev->stats.tx_aborted_errors++; | ||
573 | if (d[INT_TSR] & TSR_LCOL) | ||
574 | dev->stats.tx_window_errors++; | ||
575 | if (d[INT_TSR] & TSR_LOSS_CRS) | ||
576 | dev->stats.tx_carrier_errors++; | ||
577 | } | ||
578 | /* Report link status changes to the network stack */ | ||
579 | if ((d[INT_MSR] & MSR_LINK) == 0) { | ||
580 | if (netif_carrier_ok(dev->netdev)) { | ||
581 | netif_carrier_off(dev->netdev); | ||
582 | dbg("%s: LINK LOST\n", __func__); | ||
583 | } | ||
584 | } else { | ||
585 | if (!netif_carrier_ok(dev->netdev)) { | ||
586 | netif_carrier_on(dev->netdev); | ||
587 | dbg("%s: LINK CAME BACK\n", __func__); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | resubmit: | ||
592 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
593 | if (status == -ENODEV) | ||
594 | netif_device_detach(dev->netdev); | ||
595 | else if (status) | ||
596 | err ("can't resubmit intr, %s-%s/input0, status %d", | ||
597 | dev->udev->bus->bus_name, | ||
598 | dev->udev->devpath, status); | ||
599 | } | ||
600 | |||
601 | static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) | ||
602 | { | ||
603 | rtl8150_t *dev = usb_get_intfdata(intf); | ||
604 | |||
605 | netif_device_detach(dev->netdev); | ||
606 | |||
607 | if (netif_running(dev->netdev)) { | ||
608 | usb_kill_urb(dev->rx_urb); | ||
609 | usb_kill_urb(dev->intr_urb); | ||
610 | } | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static int rtl8150_resume(struct usb_interface *intf) | ||
615 | { | ||
616 | rtl8150_t *dev = usb_get_intfdata(intf); | ||
617 | |||
618 | netif_device_attach(dev->netdev); | ||
619 | if (netif_running(dev->netdev)) { | ||
620 | dev->rx_urb->status = 0; | ||
621 | dev->rx_urb->actual_length = 0; | ||
622 | read_bulk_callback(dev->rx_urb); | ||
623 | |||
624 | dev->intr_urb->status = 0; | ||
625 | dev->intr_urb->actual_length = 0; | ||
626 | intr_callback(dev->intr_urb); | ||
627 | } | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | /* | ||
632 | ** | ||
633 | ** network related part of the code | ||
634 | ** | ||
635 | */ | ||
636 | |||
637 | static void fill_skb_pool(rtl8150_t *dev) | ||
638 | { | ||
639 | struct sk_buff *skb; | ||
640 | int i; | ||
641 | |||
642 | for (i = 0; i < RX_SKB_POOL_SIZE; i++) { | ||
643 | if (dev->rx_skb_pool[i]) | ||
644 | continue; | ||
645 | skb = dev_alloc_skb(RTL8150_MTU + 2); | ||
646 | if (!skb) { | ||
647 | return; | ||
648 | } | ||
649 | skb_reserve(skb, 2); | ||
650 | dev->rx_skb_pool[i] = skb; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | static void free_skb_pool(rtl8150_t *dev) | ||
655 | { | ||
656 | int i; | ||
657 | |||
658 | for (i = 0; i < RX_SKB_POOL_SIZE; i++) | ||
659 | if (dev->rx_skb_pool[i]) | ||
660 | dev_kfree_skb(dev->rx_skb_pool[i]); | ||
661 | } | ||
662 | |||
663 | static int enable_net_traffic(rtl8150_t * dev) | ||
664 | { | ||
665 | u8 cr, tcr, rcr, msr; | ||
666 | |||
667 | if (!rtl8150_reset(dev)) { | ||
668 | warn("%s - device reset failed", __FUNCTION__); | ||
669 | } | ||
670 | /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ | ||
671 | rcr = 0x9e; | ||
672 | dev->rx_creg = cpu_to_le16(rcr); | ||
673 | tcr = 0xd8; | ||
674 | cr = 0x0c; | ||
675 | if (!(rcr & 0x80)) | ||
676 | set_bit(RTL8150_HW_CRC, &dev->flags); | ||
677 | set_registers(dev, RCR, 1, &rcr); | ||
678 | set_registers(dev, TCR, 1, &tcr); | ||
679 | set_registers(dev, CR, 1, &cr); | ||
680 | get_registers(dev, MSR, 1, &msr); | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static void disable_net_traffic(rtl8150_t * dev) | ||
686 | { | ||
687 | u8 cr; | ||
688 | |||
689 | get_registers(dev, CR, 1, &cr); | ||
690 | cr &= 0xf3; | ||
691 | set_registers(dev, CR, 1, &cr); | ||
692 | } | ||
693 | |||
694 | static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev) | ||
695 | { | ||
696 | return &((rtl8150_t *)netdev_priv(dev))->stats; | ||
697 | } | ||
698 | |||
699 | static void rtl8150_tx_timeout(struct net_device *netdev) | ||
700 | { | ||
701 | rtl8150_t *dev = netdev_priv(netdev); | ||
702 | warn("%s: Tx timeout.", netdev->name); | ||
703 | usb_unlink_urb(dev->tx_urb); | ||
704 | dev->stats.tx_errors++; | ||
705 | } | ||
706 | |||
707 | static void rtl8150_set_multicast(struct net_device *netdev) | ||
708 | { | ||
709 | rtl8150_t *dev = netdev_priv(netdev); | ||
710 | netif_stop_queue(netdev); | ||
711 | if (netdev->flags & IFF_PROMISC) { | ||
712 | dev->rx_creg |= cpu_to_le16(0x0001); | ||
713 | info("%s: promiscuous mode", netdev->name); | ||
714 | } else if (netdev->mc_count || | ||
715 | (netdev->flags & IFF_ALLMULTI)) { | ||
716 | dev->rx_creg &= cpu_to_le16(0xfffe); | ||
717 | dev->rx_creg |= cpu_to_le16(0x0002); | ||
718 | info("%s: allmulti set", netdev->name); | ||
719 | } else { | ||
720 | /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ | ||
721 | dev->rx_creg &= cpu_to_le16(0x00fc); | ||
722 | } | ||
723 | async_set_registers(dev, RCR, 2); | ||
724 | netif_wake_queue(netdev); | ||
725 | } | ||
726 | |||
727 | static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) | ||
728 | { | ||
729 | rtl8150_t *dev = netdev_priv(netdev); | ||
730 | int count, res; | ||
731 | |||
732 | netif_stop_queue(netdev); | ||
733 | count = (skb->len < 60) ? 60 : skb->len; | ||
734 | count = (count & 0x3f) ? count : count + 1; | ||
735 | dev->tx_skb = skb; | ||
736 | usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), | ||
737 | skb->data, count, write_bulk_callback, dev); | ||
738 | if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { | ||
739 | /* Can we get/handle EPIPE here? */ | ||
740 | if (res == -ENODEV) | ||
741 | netif_device_detach(dev->netdev); | ||
742 | else { | ||
743 | warn("failed tx_urb %d\n", res); | ||
744 | dev->stats.tx_errors++; | ||
745 | netif_start_queue(netdev); | ||
746 | } | ||
747 | } else { | ||
748 | dev->stats.tx_packets++; | ||
749 | dev->stats.tx_bytes += skb->len; | ||
750 | netdev->trans_start = jiffies; | ||
751 | } | ||
752 | |||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | |||
757 | static void set_carrier(struct net_device *netdev) | ||
758 | { | ||
759 | rtl8150_t *dev = netdev_priv(netdev); | ||
760 | short tmp; | ||
761 | |||
762 | get_registers(dev, CSCR, 2, &tmp); | ||
763 | if (tmp & CSCR_LINK_STATUS) | ||
764 | netif_carrier_on(netdev); | ||
765 | else | ||
766 | netif_carrier_off(netdev); | ||
767 | } | ||
768 | |||
769 | static int rtl8150_open(struct net_device *netdev) | ||
770 | { | ||
771 | rtl8150_t *dev = netdev_priv(netdev); | ||
772 | int res; | ||
773 | |||
774 | if (dev->rx_skb == NULL) | ||
775 | dev->rx_skb = pull_skb(dev); | ||
776 | if (!dev->rx_skb) | ||
777 | return -ENOMEM; | ||
778 | |||
779 | set_registers(dev, IDR, 6, netdev->dev_addr); | ||
780 | |||
781 | usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), | ||
782 | dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); | ||
783 | if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) { | ||
784 | if (res == -ENODEV) | ||
785 | netif_device_detach(dev->netdev); | ||
786 | warn("%s: rx_urb submit failed: %d", __FUNCTION__, res); | ||
787 | return res; | ||
788 | } | ||
789 | usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3), | ||
790 | dev->intr_buff, INTBUFSIZE, intr_callback, | ||
791 | dev, dev->intr_interval); | ||
792 | if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) { | ||
793 | if (res == -ENODEV) | ||
794 | netif_device_detach(dev->netdev); | ||
795 | warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); | ||
796 | usb_kill_urb(dev->rx_urb); | ||
797 | return res; | ||
798 | } | ||
799 | enable_net_traffic(dev); | ||
800 | set_carrier(netdev); | ||
801 | netif_start_queue(netdev); | ||
802 | |||
803 | return res; | ||
804 | } | ||
805 | |||
806 | static int rtl8150_close(struct net_device *netdev) | ||
807 | { | ||
808 | rtl8150_t *dev = netdev_priv(netdev); | ||
809 | int res = 0; | ||
810 | |||
811 | netif_stop_queue(netdev); | ||
812 | if (!test_bit(RTL8150_UNPLUG, &dev->flags)) | ||
813 | disable_net_traffic(dev); | ||
814 | unlink_all_urbs(dev); | ||
815 | |||
816 | return res; | ||
817 | } | ||
818 | |||
819 | static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) | ||
820 | { | ||
821 | rtl8150_t *dev = netdev_priv(netdev); | ||
822 | |||
823 | strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); | ||
824 | strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); | ||
825 | usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info); | ||
826 | } | ||
827 | |||
828 | static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | ||
829 | { | ||
830 | rtl8150_t *dev = netdev_priv(netdev); | ||
831 | short lpa, bmcr; | ||
832 | |||
833 | ecmd->supported = (SUPPORTED_10baseT_Half | | ||
834 | SUPPORTED_10baseT_Full | | ||
835 | SUPPORTED_100baseT_Half | | ||
836 | SUPPORTED_100baseT_Full | | ||
837 | SUPPORTED_Autoneg | | ||
838 | SUPPORTED_TP | SUPPORTED_MII); | ||
839 | ecmd->port = PORT_TP; | ||
840 | ecmd->transceiver = XCVR_INTERNAL; | ||
841 | ecmd->phy_address = dev->phy; | ||
842 | get_registers(dev, BMCR, 2, &bmcr); | ||
843 | get_registers(dev, ANLP, 2, &lpa); | ||
844 | if (bmcr & BMCR_ANENABLE) { | ||
845 | ecmd->autoneg = AUTONEG_ENABLE; | ||
846 | ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ? | ||
847 | SPEED_100 : SPEED_10; | ||
848 | if (ecmd->speed == SPEED_100) | ||
849 | ecmd->duplex = (lpa & LPA_100FULL) ? | ||
850 | DUPLEX_FULL : DUPLEX_HALF; | ||
851 | else | ||
852 | ecmd->duplex = (lpa & LPA_10FULL) ? | ||
853 | DUPLEX_FULL : DUPLEX_HALF; | ||
854 | } else { | ||
855 | ecmd->autoneg = AUTONEG_DISABLE; | ||
856 | ecmd->speed = (bmcr & BMCR_SPEED100) ? | ||
857 | SPEED_100 : SPEED_10; | ||
858 | ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? | ||
859 | DUPLEX_FULL : DUPLEX_HALF; | ||
860 | } | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static struct ethtool_ops ops = { | ||
865 | .get_drvinfo = rtl8150_get_drvinfo, | ||
866 | .get_settings = rtl8150_get_settings, | ||
867 | .get_link = ethtool_op_get_link | ||
868 | }; | ||
869 | |||
870 | static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | ||
871 | { | ||
872 | rtl8150_t *dev = netdev_priv(netdev); | ||
873 | u16 *data = (u16 *) & rq->ifr_ifru; | ||
874 | int res = 0; | ||
875 | |||
876 | switch (cmd) { | ||
877 | case SIOCDEVPRIVATE: | ||
878 | data[0] = dev->phy; | ||
879 | case SIOCDEVPRIVATE + 1: | ||
880 | read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]); | ||
881 | break; | ||
882 | case SIOCDEVPRIVATE + 2: | ||
883 | if (!capable(CAP_NET_ADMIN)) | ||
884 | return -EPERM; | ||
885 | write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]); | ||
886 | break; | ||
887 | default: | ||
888 | res = -EOPNOTSUPP; | ||
889 | } | ||
890 | |||
891 | return res; | ||
892 | } | ||
893 | |||
894 | static int rtl8150_probe(struct usb_interface *intf, | ||
895 | const struct usb_device_id *id) | ||
896 | { | ||
897 | struct usb_device *udev = interface_to_usbdev(intf); | ||
898 | rtl8150_t *dev; | ||
899 | struct net_device *netdev; | ||
900 | |||
901 | netdev = alloc_etherdev(sizeof(rtl8150_t)); | ||
902 | if (!netdev) { | ||
903 | err("Out of memory"); | ||
904 | return -ENOMEM; | ||
905 | } | ||
906 | |||
907 | dev = netdev_priv(netdev); | ||
908 | memset(dev, 0, sizeof(rtl8150_t)); | ||
909 | |||
910 | dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); | ||
911 | if (!dev->intr_buff) { | ||
912 | free_netdev(netdev); | ||
913 | return -ENOMEM; | ||
914 | } | ||
915 | |||
916 | tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev); | ||
917 | spin_lock_init(&dev->rx_pool_lock); | ||
918 | |||
919 | dev->udev = udev; | ||
920 | dev->netdev = netdev; | ||
921 | SET_MODULE_OWNER(netdev); | ||
922 | netdev->open = rtl8150_open; | ||
923 | netdev->stop = rtl8150_close; | ||
924 | netdev->do_ioctl = rtl8150_ioctl; | ||
925 | netdev->watchdog_timeo = RTL8150_TX_TIMEOUT; | ||
926 | netdev->tx_timeout = rtl8150_tx_timeout; | ||
927 | netdev->hard_start_xmit = rtl8150_start_xmit; | ||
928 | netdev->set_multicast_list = rtl8150_set_multicast; | ||
929 | netdev->set_mac_address = rtl8150_set_mac_address; | ||
930 | netdev->get_stats = rtl8150_netdev_stats; | ||
931 | netdev->mtu = RTL8150_MTU; | ||
932 | SET_ETHTOOL_OPS(netdev, &ops); | ||
933 | dev->intr_interval = 100; /* 100ms */ | ||
934 | |||
935 | if (!alloc_all_urbs(dev)) { | ||
936 | err("out of memory"); | ||
937 | goto out; | ||
938 | } | ||
939 | if (!rtl8150_reset(dev)) { | ||
940 | err("couldn't reset the device"); | ||
941 | goto out1; | ||
942 | } | ||
943 | fill_skb_pool(dev); | ||
944 | set_ethernet_addr(dev); | ||
945 | |||
946 | usb_set_intfdata(intf, dev); | ||
947 | SET_NETDEV_DEV(netdev, &intf->dev); | ||
948 | if (register_netdev(netdev) != 0) { | ||
949 | err("couldn't register the device"); | ||
950 | goto out2; | ||
951 | } | ||
952 | |||
953 | info("%s: rtl8150 is detected", netdev->name); | ||
954 | |||
955 | return 0; | ||
956 | |||
957 | out2: | ||
958 | usb_set_intfdata(intf, NULL); | ||
959 | free_skb_pool(dev); | ||
960 | out1: | ||
961 | free_all_urbs(dev); | ||
962 | out: | ||
963 | kfree(dev->intr_buff); | ||
964 | free_netdev(netdev); | ||
965 | return -EIO; | ||
966 | } | ||
967 | |||
968 | static void rtl8150_disconnect(struct usb_interface *intf) | ||
969 | { | ||
970 | rtl8150_t *dev = usb_get_intfdata(intf); | ||
971 | |||
972 | usb_set_intfdata(intf, NULL); | ||
973 | if (dev) { | ||
974 | set_bit(RTL8150_UNPLUG, &dev->flags); | ||
975 | tasklet_disable(&dev->tl); | ||
976 | tasklet_kill(&dev->tl); | ||
977 | unregister_netdev(dev->netdev); | ||
978 | unlink_all_urbs(dev); | ||
979 | free_all_urbs(dev); | ||
980 | free_skb_pool(dev); | ||
981 | if (dev->rx_skb) | ||
982 | dev_kfree_skb(dev->rx_skb); | ||
983 | kfree(dev->intr_buff); | ||
984 | free_netdev(dev->netdev); | ||
985 | } | ||
986 | } | ||
987 | |||
988 | static int __init usb_rtl8150_init(void) | ||
989 | { | ||
990 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
991 | return usb_register(&rtl8150_driver); | ||
992 | } | ||
993 | |||
994 | static void __exit usb_rtl8150_exit(void) | ||
995 | { | ||
996 | usb_deregister(&rtl8150_driver); | ||
997 | } | ||
998 | |||
999 | module_init(usb_rtl8150_init); | ||
1000 | module_exit(usb_rtl8150_exit); | ||
1001 | |||
1002 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1003 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1004 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c new file mode 100644 index 000000000000..f9cd42d058b0 --- /dev/null +++ b/drivers/net/usb/usbnet.c | |||
@@ -0,0 +1,1304 @@ | |||
1 | /* | ||
2 | * USB Network driver infrastructure | ||
3 | * Copyright (C) 2000-2005 by David Brownell | ||
4 | * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (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, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * This is a generic "USB networking" framework that works with several | ||
23 | * kinds of full and high speed networking devices: host-to-host cables, | ||
24 | * smart usb peripherals, and actual Ethernet adapters. | ||
25 | * | ||
26 | * These devices usually differ in terms of control protocols (if they | ||
27 | * even have one!) and sometimes they define new framing to wrap or batch | ||
28 | * Ethernet packets. Otherwise, they talk to USB pretty much the same, | ||
29 | * so interface (un)binding, endpoint I/O queues, fault handling, and other | ||
30 | * issues can usefully be addressed by this framework. | ||
31 | */ | ||
32 | |||
33 | // #define DEBUG // error path messages, extra info | ||
34 | // #define VERBOSE // more; success messages | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/netdevice.h> | ||
39 | #include <linux/etherdevice.h> | ||
40 | #include <linux/ethtool.h> | ||
41 | #include <linux/workqueue.h> | ||
42 | #include <linux/mii.h> | ||
43 | #include <linux/usb.h> | ||
44 | |||
45 | #include "usbnet.h" | ||
46 | |||
47 | #define DRIVER_VERSION "22-Aug-2005" | ||
48 | |||
49 | |||
50 | /*-------------------------------------------------------------------------*/ | ||
51 | |||
52 | /* | ||
53 | * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. | ||
54 | * Several dozen bytes of IPv4 data can fit in two such transactions. | ||
55 | * One maximum size Ethernet packet takes twenty four of them. | ||
56 | * For high speed, each frame comfortably fits almost 36 max size | ||
57 | * Ethernet packets (so queues should be bigger). | ||
58 | * | ||
59 | * REVISIT qlens should be members of 'struct usbnet'; the goal is to | ||
60 | * let the USB host controller be busy for 5msec or more before an irq | ||
61 | * is required, under load. Jumbograms change the equation. | ||
62 | */ | ||
63 | #define RX_MAX_QUEUE_MEMORY (60 * 1518) | ||
64 | #define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ | ||
65 | (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4) | ||
66 | #define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ | ||
67 | (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4) | ||
68 | |||
69 | // reawaken network queue this soon after stopping; else watchdog barks | ||
70 | #define TX_TIMEOUT_JIFFIES (5*HZ) | ||
71 | |||
72 | // throttle rx/tx briefly after some faults, so khubd might disconnect() | ||
73 | // us (it polls at HZ/4 usually) before we report too many false errors. | ||
74 | #define THROTTLE_JIFFIES (HZ/8) | ||
75 | |||
76 | // between wakeups | ||
77 | #define UNLINK_TIMEOUT_MS 3 | ||
78 | |||
79 | /*-------------------------------------------------------------------------*/ | ||
80 | |||
81 | // randomly generated ethernet address | ||
82 | static u8 node_id [ETH_ALEN]; | ||
83 | |||
84 | static const char driver_name [] = "usbnet"; | ||
85 | |||
86 | /* use ethtool to change the level for any given device */ | ||
87 | static int msg_level = -1; | ||
88 | module_param (msg_level, int, 0); | ||
89 | MODULE_PARM_DESC (msg_level, "Override default message level"); | ||
90 | |||
91 | /*-------------------------------------------------------------------------*/ | ||
92 | |||
93 | /* handles CDC Ethernet and many other network "bulk data" interfaces */ | ||
94 | int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) | ||
95 | { | ||
96 | int tmp; | ||
97 | struct usb_host_interface *alt = NULL; | ||
98 | struct usb_host_endpoint *in = NULL, *out = NULL; | ||
99 | struct usb_host_endpoint *status = NULL; | ||
100 | |||
101 | for (tmp = 0; tmp < intf->num_altsetting; tmp++) { | ||
102 | unsigned ep; | ||
103 | |||
104 | in = out = status = NULL; | ||
105 | alt = intf->altsetting + tmp; | ||
106 | |||
107 | /* take the first altsetting with in-bulk + out-bulk; | ||
108 | * remember any status endpoint, just in case; | ||
109 | * ignore other endpoints and altsetttings. | ||
110 | */ | ||
111 | for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { | ||
112 | struct usb_host_endpoint *e; | ||
113 | int intr = 0; | ||
114 | |||
115 | e = alt->endpoint + ep; | ||
116 | switch (e->desc.bmAttributes) { | ||
117 | case USB_ENDPOINT_XFER_INT: | ||
118 | if (!usb_endpoint_dir_in(&e->desc)) | ||
119 | continue; | ||
120 | intr = 1; | ||
121 | /* FALLTHROUGH */ | ||
122 | case USB_ENDPOINT_XFER_BULK: | ||
123 | break; | ||
124 | default: | ||
125 | continue; | ||
126 | } | ||
127 | if (usb_endpoint_dir_in(&e->desc)) { | ||
128 | if (!intr && !in) | ||
129 | in = e; | ||
130 | else if (intr && !status) | ||
131 | status = e; | ||
132 | } else { | ||
133 | if (!out) | ||
134 | out = e; | ||
135 | } | ||
136 | } | ||
137 | if (in && out) | ||
138 | break; | ||
139 | } | ||
140 | if (!alt || !in || !out) | ||
141 | return -EINVAL; | ||
142 | |||
143 | if (alt->desc.bAlternateSetting != 0 | ||
144 | || !(dev->driver_info->flags & FLAG_NO_SETINT)) { | ||
145 | tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, | ||
146 | alt->desc.bAlternateSetting); | ||
147 | if (tmp < 0) | ||
148 | return tmp; | ||
149 | } | ||
150 | |||
151 | dev->in = usb_rcvbulkpipe (dev->udev, | ||
152 | in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | ||
153 | dev->out = usb_sndbulkpipe (dev->udev, | ||
154 | out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | ||
155 | dev->status = status; | ||
156 | return 0; | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(usbnet_get_endpoints); | ||
159 | |||
160 | static void intr_complete (struct urb *urb); | ||
161 | |||
162 | static int init_status (struct usbnet *dev, struct usb_interface *intf) | ||
163 | { | ||
164 | char *buf = NULL; | ||
165 | unsigned pipe = 0; | ||
166 | unsigned maxp; | ||
167 | unsigned period; | ||
168 | |||
169 | if (!dev->driver_info->status) | ||
170 | return 0; | ||
171 | |||
172 | pipe = usb_rcvintpipe (dev->udev, | ||
173 | dev->status->desc.bEndpointAddress | ||
174 | & USB_ENDPOINT_NUMBER_MASK); | ||
175 | maxp = usb_maxpacket (dev->udev, pipe, 0); | ||
176 | |||
177 | /* avoid 1 msec chatter: min 8 msec poll rate */ | ||
178 | period = max ((int) dev->status->desc.bInterval, | ||
179 | (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); | ||
180 | |||
181 | buf = kmalloc (maxp, GFP_KERNEL); | ||
182 | if (buf) { | ||
183 | dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); | ||
184 | if (!dev->interrupt) { | ||
185 | kfree (buf); | ||
186 | return -ENOMEM; | ||
187 | } else { | ||
188 | usb_fill_int_urb(dev->interrupt, dev->udev, pipe, | ||
189 | buf, maxp, intr_complete, dev, period); | ||
190 | dev_dbg(&intf->dev, | ||
191 | "status ep%din, %d bytes period %d\n", | ||
192 | usb_pipeendpoint(pipe), maxp, period); | ||
193 | } | ||
194 | } | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* Passes this packet up the stack, updating its accounting. | ||
199 | * Some link protocols batch packets, so their rx_fixup paths | ||
200 | * can return clones as well as just modify the original skb. | ||
201 | */ | ||
202 | void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) | ||
203 | { | ||
204 | int status; | ||
205 | |||
206 | skb->protocol = eth_type_trans (skb, dev->net); | ||
207 | dev->stats.rx_packets++; | ||
208 | dev->stats.rx_bytes += skb->len; | ||
209 | |||
210 | if (netif_msg_rx_status (dev)) | ||
211 | devdbg (dev, "< rx, len %zu, type 0x%x", | ||
212 | skb->len + sizeof (struct ethhdr), skb->protocol); | ||
213 | memset (skb->cb, 0, sizeof (struct skb_data)); | ||
214 | status = netif_rx (skb); | ||
215 | if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev)) | ||
216 | devdbg (dev, "netif_rx status %d", status); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(usbnet_skb_return); | ||
219 | |||
220 | |||
221 | /*------------------------------------------------------------------------- | ||
222 | * | ||
223 | * Network Device Driver (peer link to "Host Device", from USB host) | ||
224 | * | ||
225 | *-------------------------------------------------------------------------*/ | ||
226 | |||
227 | static int usbnet_change_mtu (struct net_device *net, int new_mtu) | ||
228 | { | ||
229 | struct usbnet *dev = netdev_priv(net); | ||
230 | int ll_mtu = new_mtu + net->hard_header_len; | ||
231 | int old_hard_mtu = dev->hard_mtu; | ||
232 | int old_rx_urb_size = dev->rx_urb_size; | ||
233 | |||
234 | if (new_mtu <= 0) | ||
235 | return -EINVAL; | ||
236 | // no second zero-length packet read wanted after mtu-sized packets | ||
237 | if ((ll_mtu % dev->maxpacket) == 0) | ||
238 | return -EDOM; | ||
239 | net->mtu = new_mtu; | ||
240 | |||
241 | dev->hard_mtu = net->mtu + net->hard_header_len; | ||
242 | if (dev->rx_urb_size == old_hard_mtu) { | ||
243 | dev->rx_urb_size = dev->hard_mtu; | ||
244 | if (dev->rx_urb_size > old_rx_urb_size) | ||
245 | usbnet_unlink_rx_urbs(dev); | ||
246 | } | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | /*-------------------------------------------------------------------------*/ | ||
252 | |||
253 | static struct net_device_stats *usbnet_get_stats (struct net_device *net) | ||
254 | { | ||
255 | struct usbnet *dev = netdev_priv(net); | ||
256 | return &dev->stats; | ||
257 | } | ||
258 | |||
259 | /*-------------------------------------------------------------------------*/ | ||
260 | |||
261 | /* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from | ||
262 | * completion callbacks. 2.5 should have fixed those bugs... | ||
263 | */ | ||
264 | |||
265 | static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) | ||
266 | { | ||
267 | unsigned long flags; | ||
268 | |||
269 | spin_lock_irqsave(&list->lock, flags); | ||
270 | __skb_unlink(skb, list); | ||
271 | spin_unlock(&list->lock); | ||
272 | spin_lock(&dev->done.lock); | ||
273 | __skb_queue_tail(&dev->done, skb); | ||
274 | if (dev->done.qlen == 1) | ||
275 | tasklet_schedule(&dev->bh); | ||
276 | spin_unlock_irqrestore(&dev->done.lock, flags); | ||
277 | } | ||
278 | |||
279 | /* some work can't be done in tasklets, so we use keventd | ||
280 | * | ||
281 | * NOTE: annoying asymmetry: if it's active, schedule_work() fails, | ||
282 | * but tasklet_schedule() doesn't. hope the failure is rare. | ||
283 | */ | ||
284 | void usbnet_defer_kevent (struct usbnet *dev, int work) | ||
285 | { | ||
286 | set_bit (work, &dev->flags); | ||
287 | if (!schedule_work (&dev->kevent)) | ||
288 | deverr (dev, "kevent %d may have been dropped", work); | ||
289 | else | ||
290 | devdbg (dev, "kevent %d scheduled", work); | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(usbnet_defer_kevent); | ||
293 | |||
294 | /*-------------------------------------------------------------------------*/ | ||
295 | |||
296 | static void rx_complete (struct urb *urb); | ||
297 | |||
298 | static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) | ||
299 | { | ||
300 | struct sk_buff *skb; | ||
301 | struct skb_data *entry; | ||
302 | int retval = 0; | ||
303 | unsigned long lockflags; | ||
304 | size_t size = dev->rx_urb_size; | ||
305 | |||
306 | if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { | ||
307 | if (netif_msg_rx_err (dev)) | ||
308 | devdbg (dev, "no rx skb"); | ||
309 | usbnet_defer_kevent (dev, EVENT_RX_MEMORY); | ||
310 | usb_free_urb (urb); | ||
311 | return; | ||
312 | } | ||
313 | skb_reserve (skb, NET_IP_ALIGN); | ||
314 | |||
315 | entry = (struct skb_data *) skb->cb; | ||
316 | entry->urb = urb; | ||
317 | entry->dev = dev; | ||
318 | entry->state = rx_start; | ||
319 | entry->length = 0; | ||
320 | |||
321 | usb_fill_bulk_urb (urb, dev->udev, dev->in, | ||
322 | skb->data, size, rx_complete, skb); | ||
323 | |||
324 | spin_lock_irqsave (&dev->rxq.lock, lockflags); | ||
325 | |||
326 | if (netif_running (dev->net) | ||
327 | && netif_device_present (dev->net) | ||
328 | && !test_bit (EVENT_RX_HALT, &dev->flags)) { | ||
329 | switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ | ||
330 | case -EPIPE: | ||
331 | usbnet_defer_kevent (dev, EVENT_RX_HALT); | ||
332 | break; | ||
333 | case -ENOMEM: | ||
334 | usbnet_defer_kevent (dev, EVENT_RX_MEMORY); | ||
335 | break; | ||
336 | case -ENODEV: | ||
337 | if (netif_msg_ifdown (dev)) | ||
338 | devdbg (dev, "device gone"); | ||
339 | netif_device_detach (dev->net); | ||
340 | break; | ||
341 | default: | ||
342 | if (netif_msg_rx_err (dev)) | ||
343 | devdbg (dev, "rx submit, %d", retval); | ||
344 | tasklet_schedule (&dev->bh); | ||
345 | break; | ||
346 | case 0: | ||
347 | __skb_queue_tail (&dev->rxq, skb); | ||
348 | } | ||
349 | } else { | ||
350 | if (netif_msg_ifdown (dev)) | ||
351 | devdbg (dev, "rx: stopped"); | ||
352 | retval = -ENOLINK; | ||
353 | } | ||
354 | spin_unlock_irqrestore (&dev->rxq.lock, lockflags); | ||
355 | if (retval) { | ||
356 | dev_kfree_skb_any (skb); | ||
357 | usb_free_urb (urb); | ||
358 | } | ||
359 | } | ||
360 | |||
361 | |||
362 | /*-------------------------------------------------------------------------*/ | ||
363 | |||
364 | static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) | ||
365 | { | ||
366 | if (dev->driver_info->rx_fixup | ||
367 | && !dev->driver_info->rx_fixup (dev, skb)) | ||
368 | goto error; | ||
369 | // else network stack removes extra byte if we forced a short packet | ||
370 | |||
371 | if (skb->len) | ||
372 | usbnet_skb_return (dev, skb); | ||
373 | else { | ||
374 | if (netif_msg_rx_err (dev)) | ||
375 | devdbg (dev, "drop"); | ||
376 | error: | ||
377 | dev->stats.rx_errors++; | ||
378 | skb_queue_tail (&dev->done, skb); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | /*-------------------------------------------------------------------------*/ | ||
383 | |||
384 | static void rx_complete (struct urb *urb) | ||
385 | { | ||
386 | struct sk_buff *skb = (struct sk_buff *) urb->context; | ||
387 | struct skb_data *entry = (struct skb_data *) skb->cb; | ||
388 | struct usbnet *dev = entry->dev; | ||
389 | int urb_status = urb->status; | ||
390 | |||
391 | skb_put (skb, urb->actual_length); | ||
392 | entry->state = rx_done; | ||
393 | entry->urb = NULL; | ||
394 | |||
395 | switch (urb_status) { | ||
396 | // success | ||
397 | case 0: | ||
398 | if (skb->len < dev->net->hard_header_len) { | ||
399 | entry->state = rx_cleanup; | ||
400 | dev->stats.rx_errors++; | ||
401 | dev->stats.rx_length_errors++; | ||
402 | if (netif_msg_rx_err (dev)) | ||
403 | devdbg (dev, "rx length %d", skb->len); | ||
404 | } | ||
405 | break; | ||
406 | |||
407 | // stalls need manual reset. this is rare ... except that | ||
408 | // when going through USB 2.0 TTs, unplug appears this way. | ||
409 | // we avoid the highspeed version of the ETIMEOUT/EILSEQ | ||
410 | // storm, recovering as needed. | ||
411 | case -EPIPE: | ||
412 | dev->stats.rx_errors++; | ||
413 | usbnet_defer_kevent (dev, EVENT_RX_HALT); | ||
414 | // FALLTHROUGH | ||
415 | |||
416 | // software-driven interface shutdown | ||
417 | case -ECONNRESET: // async unlink | ||
418 | case -ESHUTDOWN: // hardware gone | ||
419 | if (netif_msg_ifdown (dev)) | ||
420 | devdbg (dev, "rx shutdown, code %d", urb_status); | ||
421 | goto block; | ||
422 | |||
423 | // we get controller i/o faults during khubd disconnect() delays. | ||
424 | // throttle down resubmits, to avoid log floods; just temporarily, | ||
425 | // so we still recover when the fault isn't a khubd delay. | ||
426 | case -EPROTO: | ||
427 | case -ETIME: | ||
428 | case -EILSEQ: | ||
429 | dev->stats.rx_errors++; | ||
430 | if (!timer_pending (&dev->delay)) { | ||
431 | mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); | ||
432 | if (netif_msg_link (dev)) | ||
433 | devdbg (dev, "rx throttle %d", urb_status); | ||
434 | } | ||
435 | block: | ||
436 | entry->state = rx_cleanup; | ||
437 | entry->urb = urb; | ||
438 | urb = NULL; | ||
439 | break; | ||
440 | |||
441 | // data overrun ... flush fifo? | ||
442 | case -EOVERFLOW: | ||
443 | dev->stats.rx_over_errors++; | ||
444 | // FALLTHROUGH | ||
445 | |||
446 | default: | ||
447 | entry->state = rx_cleanup; | ||
448 | dev->stats.rx_errors++; | ||
449 | if (netif_msg_rx_err (dev)) | ||
450 | devdbg (dev, "rx status %d", urb_status); | ||
451 | break; | ||
452 | } | ||
453 | |||
454 | defer_bh(dev, skb, &dev->rxq); | ||
455 | |||
456 | if (urb) { | ||
457 | if (netif_running (dev->net) | ||
458 | && !test_bit (EVENT_RX_HALT, &dev->flags)) { | ||
459 | rx_submit (dev, urb, GFP_ATOMIC); | ||
460 | return; | ||
461 | } | ||
462 | usb_free_urb (urb); | ||
463 | } | ||
464 | if (netif_msg_rx_err (dev)) | ||
465 | devdbg (dev, "no read resubmitted"); | ||
466 | } | ||
467 | |||
468 | static void intr_complete (struct urb *urb) | ||
469 | { | ||
470 | struct usbnet *dev = urb->context; | ||
471 | int status = urb->status; | ||
472 | |||
473 | switch (status) { | ||
474 | /* success */ | ||
475 | case 0: | ||
476 | dev->driver_info->status(dev, urb); | ||
477 | break; | ||
478 | |||
479 | /* software-driven interface shutdown */ | ||
480 | case -ENOENT: // urb killed | ||
481 | case -ESHUTDOWN: // hardware gone | ||
482 | if (netif_msg_ifdown (dev)) | ||
483 | devdbg (dev, "intr shutdown, code %d", status); | ||
484 | return; | ||
485 | |||
486 | /* NOTE: not throttling like RX/TX, since this endpoint | ||
487 | * already polls infrequently | ||
488 | */ | ||
489 | default: | ||
490 | devdbg (dev, "intr status %d", status); | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | if (!netif_running (dev->net)) | ||
495 | return; | ||
496 | |||
497 | memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); | ||
498 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
499 | if (status != 0 && netif_msg_timer (dev)) | ||
500 | deverr(dev, "intr resubmit --> %d", status); | ||
501 | } | ||
502 | |||
503 | /*-------------------------------------------------------------------------*/ | ||
504 | |||
505 | // unlink pending rx/tx; completion handlers do all other cleanup | ||
506 | |||
507 | static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) | ||
508 | { | ||
509 | unsigned long flags; | ||
510 | struct sk_buff *skb, *skbnext; | ||
511 | int count = 0; | ||
512 | |||
513 | spin_lock_irqsave (&q->lock, flags); | ||
514 | for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) { | ||
515 | struct skb_data *entry; | ||
516 | struct urb *urb; | ||
517 | int retval; | ||
518 | |||
519 | entry = (struct skb_data *) skb->cb; | ||
520 | urb = entry->urb; | ||
521 | skbnext = skb->next; | ||
522 | |||
523 | // during some PM-driven resume scenarios, | ||
524 | // these (async) unlinks complete immediately | ||
525 | retval = usb_unlink_urb (urb); | ||
526 | if (retval != -EINPROGRESS && retval != 0) | ||
527 | devdbg (dev, "unlink urb err, %d", retval); | ||
528 | else | ||
529 | count++; | ||
530 | } | ||
531 | spin_unlock_irqrestore (&q->lock, flags); | ||
532 | return count; | ||
533 | } | ||
534 | |||
535 | // Flush all pending rx urbs | ||
536 | // minidrivers may need to do this when the MTU changes | ||
537 | |||
538 | void usbnet_unlink_rx_urbs(struct usbnet *dev) | ||
539 | { | ||
540 | if (netif_running(dev->net)) { | ||
541 | (void) unlink_urbs (dev, &dev->rxq); | ||
542 | tasklet_schedule(&dev->bh); | ||
543 | } | ||
544 | } | ||
545 | EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); | ||
546 | |||
547 | /*-------------------------------------------------------------------------*/ | ||
548 | |||
549 | // precondition: never called in_interrupt | ||
550 | |||
551 | static int usbnet_stop (struct net_device *net) | ||
552 | { | ||
553 | struct usbnet *dev = netdev_priv(net); | ||
554 | int temp; | ||
555 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); | ||
556 | DECLARE_WAITQUEUE (wait, current); | ||
557 | |||
558 | netif_stop_queue (net); | ||
559 | |||
560 | if (netif_msg_ifdown (dev)) | ||
561 | devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", | ||
562 | dev->stats.rx_packets, dev->stats.tx_packets, | ||
563 | dev->stats.rx_errors, dev->stats.tx_errors | ||
564 | ); | ||
565 | |||
566 | // ensure there are no more active urbs | ||
567 | add_wait_queue (&unlink_wakeup, &wait); | ||
568 | dev->wait = &unlink_wakeup; | ||
569 | temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); | ||
570 | |||
571 | // maybe wait for deletions to finish. | ||
572 | while (!skb_queue_empty(&dev->rxq) && | ||
573 | !skb_queue_empty(&dev->txq) && | ||
574 | !skb_queue_empty(&dev->done)) { | ||
575 | msleep(UNLINK_TIMEOUT_MS); | ||
576 | if (netif_msg_ifdown (dev)) | ||
577 | devdbg (dev, "waited for %d urb completions", temp); | ||
578 | } | ||
579 | dev->wait = NULL; | ||
580 | remove_wait_queue (&unlink_wakeup, &wait); | ||
581 | |||
582 | usb_kill_urb(dev->interrupt); | ||
583 | |||
584 | /* deferred work (task, timer, softirq) must also stop. | ||
585 | * can't flush_scheduled_work() until we drop rtnl (later), | ||
586 | * else workers could deadlock; so make workers a NOP. | ||
587 | */ | ||
588 | dev->flags = 0; | ||
589 | del_timer_sync (&dev->delay); | ||
590 | tasklet_kill (&dev->bh); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | /*-------------------------------------------------------------------------*/ | ||
596 | |||
597 | // posts reads, and enables write queuing | ||
598 | |||
599 | // precondition: never called in_interrupt | ||
600 | |||
601 | static int usbnet_open (struct net_device *net) | ||
602 | { | ||
603 | struct usbnet *dev = netdev_priv(net); | ||
604 | int retval = 0; | ||
605 | struct driver_info *info = dev->driver_info; | ||
606 | |||
607 | // put into "known safe" state | ||
608 | if (info->reset && (retval = info->reset (dev)) < 0) { | ||
609 | if (netif_msg_ifup (dev)) | ||
610 | devinfo (dev, | ||
611 | "open reset fail (%d) usbnet usb-%s-%s, %s", | ||
612 | retval, | ||
613 | dev->udev->bus->bus_name, dev->udev->devpath, | ||
614 | info->description); | ||
615 | goto done; | ||
616 | } | ||
617 | |||
618 | // insist peer be connected | ||
619 | if (info->check_connect && (retval = info->check_connect (dev)) < 0) { | ||
620 | if (netif_msg_ifup (dev)) | ||
621 | devdbg (dev, "can't open; %d", retval); | ||
622 | goto done; | ||
623 | } | ||
624 | |||
625 | /* start any status interrupt transfer */ | ||
626 | if (dev->interrupt) { | ||
627 | retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); | ||
628 | if (retval < 0) { | ||
629 | if (netif_msg_ifup (dev)) | ||
630 | deverr (dev, "intr submit %d", retval); | ||
631 | goto done; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | netif_start_queue (net); | ||
636 | if (netif_msg_ifup (dev)) { | ||
637 | char *framing; | ||
638 | |||
639 | if (dev->driver_info->flags & FLAG_FRAMING_NC) | ||
640 | framing = "NetChip"; | ||
641 | else if (dev->driver_info->flags & FLAG_FRAMING_GL) | ||
642 | framing = "GeneSys"; | ||
643 | else if (dev->driver_info->flags & FLAG_FRAMING_Z) | ||
644 | framing = "Zaurus"; | ||
645 | else if (dev->driver_info->flags & FLAG_FRAMING_RN) | ||
646 | framing = "RNDIS"; | ||
647 | else if (dev->driver_info->flags & FLAG_FRAMING_AX) | ||
648 | framing = "ASIX"; | ||
649 | else | ||
650 | framing = "simple"; | ||
651 | |||
652 | devinfo (dev, "open: enable queueing " | ||
653 | "(rx %d, tx %d) mtu %d %s framing", | ||
654 | (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu, | ||
655 | framing); | ||
656 | } | ||
657 | |||
658 | // delay posting reads until we're fully open | ||
659 | tasklet_schedule (&dev->bh); | ||
660 | done: | ||
661 | return retval; | ||
662 | } | ||
663 | |||
664 | /*-------------------------------------------------------------------------*/ | ||
665 | |||
666 | /* ethtool methods; minidrivers may need to add some more, but | ||
667 | * they'll probably want to use this base set. | ||
668 | */ | ||
669 | |||
670 | #if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE) | ||
671 | #define HAVE_MII | ||
672 | |||
673 | int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) | ||
674 | { | ||
675 | struct usbnet *dev = netdev_priv(net); | ||
676 | |||
677 | if (!dev->mii.mdio_read) | ||
678 | return -EOPNOTSUPP; | ||
679 | |||
680 | return mii_ethtool_gset(&dev->mii, cmd); | ||
681 | } | ||
682 | EXPORT_SYMBOL_GPL(usbnet_get_settings); | ||
683 | |||
684 | int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) | ||
685 | { | ||
686 | struct usbnet *dev = netdev_priv(net); | ||
687 | int retval; | ||
688 | |||
689 | if (!dev->mii.mdio_write) | ||
690 | return -EOPNOTSUPP; | ||
691 | |||
692 | retval = mii_ethtool_sset(&dev->mii, cmd); | ||
693 | |||
694 | /* link speed/duplex might have changed */ | ||
695 | if (dev->driver_info->link_reset) | ||
696 | dev->driver_info->link_reset(dev); | ||
697 | |||
698 | return retval; | ||
699 | |||
700 | } | ||
701 | EXPORT_SYMBOL_GPL(usbnet_set_settings); | ||
702 | |||
703 | u32 usbnet_get_link (struct net_device *net) | ||
704 | { | ||
705 | struct usbnet *dev = netdev_priv(net); | ||
706 | |||
707 | /* If a check_connect is defined, return its result */ | ||
708 | if (dev->driver_info->check_connect) | ||
709 | return dev->driver_info->check_connect (dev) == 0; | ||
710 | |||
711 | /* if the device has mii operations, use those */ | ||
712 | if (dev->mii.mdio_read) | ||
713 | return mii_link_ok(&dev->mii); | ||
714 | |||
715 | /* Otherwise, say we're up (to avoid breaking scripts) */ | ||
716 | return 1; | ||
717 | } | ||
718 | EXPORT_SYMBOL_GPL(usbnet_get_link); | ||
719 | |||
720 | int usbnet_nway_reset(struct net_device *net) | ||
721 | { | ||
722 | struct usbnet *dev = netdev_priv(net); | ||
723 | |||
724 | if (!dev->mii.mdio_write) | ||
725 | return -EOPNOTSUPP; | ||
726 | |||
727 | return mii_nway_restart(&dev->mii); | ||
728 | } | ||
729 | EXPORT_SYMBOL_GPL(usbnet_nway_reset); | ||
730 | |||
731 | #endif /* HAVE_MII */ | ||
732 | |||
733 | void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) | ||
734 | { | ||
735 | struct usbnet *dev = netdev_priv(net); | ||
736 | |||
737 | strncpy (info->driver, dev->driver_name, sizeof info->driver); | ||
738 | strncpy (info->version, DRIVER_VERSION, sizeof info->version); | ||
739 | strncpy (info->fw_version, dev->driver_info->description, | ||
740 | sizeof info->fw_version); | ||
741 | usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); | ||
742 | } | ||
743 | EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); | ||
744 | |||
745 | u32 usbnet_get_msglevel (struct net_device *net) | ||
746 | { | ||
747 | struct usbnet *dev = netdev_priv(net); | ||
748 | |||
749 | return dev->msg_enable; | ||
750 | } | ||
751 | EXPORT_SYMBOL_GPL(usbnet_get_msglevel); | ||
752 | |||
753 | void usbnet_set_msglevel (struct net_device *net, u32 level) | ||
754 | { | ||
755 | struct usbnet *dev = netdev_priv(net); | ||
756 | |||
757 | dev->msg_enable = level; | ||
758 | } | ||
759 | EXPORT_SYMBOL_GPL(usbnet_set_msglevel); | ||
760 | |||
761 | /* drivers may override default ethtool_ops in their bind() routine */ | ||
762 | static struct ethtool_ops usbnet_ethtool_ops = { | ||
763 | #ifdef HAVE_MII | ||
764 | .get_settings = usbnet_get_settings, | ||
765 | .set_settings = usbnet_set_settings, | ||
766 | .get_link = usbnet_get_link, | ||
767 | .nway_reset = usbnet_nway_reset, | ||
768 | #endif | ||
769 | .get_drvinfo = usbnet_get_drvinfo, | ||
770 | .get_msglevel = usbnet_get_msglevel, | ||
771 | .set_msglevel = usbnet_set_msglevel, | ||
772 | }; | ||
773 | |||
774 | /*-------------------------------------------------------------------------*/ | ||
775 | |||
776 | /* work that cannot be done in interrupt context uses keventd. | ||
777 | * | ||
778 | * NOTE: with 2.5 we could do more of this using completion callbacks, | ||
779 | * especially now that control transfers can be queued. | ||
780 | */ | ||
781 | static void | ||
782 | kevent (struct work_struct *work) | ||
783 | { | ||
784 | struct usbnet *dev = | ||
785 | container_of(work, struct usbnet, kevent); | ||
786 | int status; | ||
787 | |||
788 | /* usb_clear_halt() needs a thread context */ | ||
789 | if (test_bit (EVENT_TX_HALT, &dev->flags)) { | ||
790 | unlink_urbs (dev, &dev->txq); | ||
791 | status = usb_clear_halt (dev->udev, dev->out); | ||
792 | if (status < 0 | ||
793 | && status != -EPIPE | ||
794 | && status != -ESHUTDOWN) { | ||
795 | if (netif_msg_tx_err (dev)) | ||
796 | deverr (dev, "can't clear tx halt, status %d", | ||
797 | status); | ||
798 | } else { | ||
799 | clear_bit (EVENT_TX_HALT, &dev->flags); | ||
800 | if (status != -ESHUTDOWN) | ||
801 | netif_wake_queue (dev->net); | ||
802 | } | ||
803 | } | ||
804 | if (test_bit (EVENT_RX_HALT, &dev->flags)) { | ||
805 | unlink_urbs (dev, &dev->rxq); | ||
806 | status = usb_clear_halt (dev->udev, dev->in); | ||
807 | if (status < 0 | ||
808 | && status != -EPIPE | ||
809 | && status != -ESHUTDOWN) { | ||
810 | if (netif_msg_rx_err (dev)) | ||
811 | deverr (dev, "can't clear rx halt, status %d", | ||
812 | status); | ||
813 | } else { | ||
814 | clear_bit (EVENT_RX_HALT, &dev->flags); | ||
815 | tasklet_schedule (&dev->bh); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | /* tasklet could resubmit itself forever if memory is tight */ | ||
820 | if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { | ||
821 | struct urb *urb = NULL; | ||
822 | |||
823 | if (netif_running (dev->net)) | ||
824 | urb = usb_alloc_urb (0, GFP_KERNEL); | ||
825 | else | ||
826 | clear_bit (EVENT_RX_MEMORY, &dev->flags); | ||
827 | if (urb != NULL) { | ||
828 | clear_bit (EVENT_RX_MEMORY, &dev->flags); | ||
829 | rx_submit (dev, urb, GFP_KERNEL); | ||
830 | tasklet_schedule (&dev->bh); | ||
831 | } | ||
832 | } | ||
833 | |||
834 | if (test_bit (EVENT_LINK_RESET, &dev->flags)) { | ||
835 | struct driver_info *info = dev->driver_info; | ||
836 | int retval = 0; | ||
837 | |||
838 | clear_bit (EVENT_LINK_RESET, &dev->flags); | ||
839 | if(info->link_reset && (retval = info->link_reset(dev)) < 0) { | ||
840 | devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", | ||
841 | retval, | ||
842 | dev->udev->bus->bus_name, dev->udev->devpath, | ||
843 | info->description); | ||
844 | } | ||
845 | } | ||
846 | |||
847 | if (dev->flags) | ||
848 | devdbg (dev, "kevent done, flags = 0x%lx", | ||
849 | dev->flags); | ||
850 | } | ||
851 | |||
852 | /*-------------------------------------------------------------------------*/ | ||
853 | |||
854 | static void tx_complete (struct urb *urb) | ||
855 | { | ||
856 | struct sk_buff *skb = (struct sk_buff *) urb->context; | ||
857 | struct skb_data *entry = (struct skb_data *) skb->cb; | ||
858 | struct usbnet *dev = entry->dev; | ||
859 | |||
860 | if (urb->status == 0) { | ||
861 | dev->stats.tx_packets++; | ||
862 | dev->stats.tx_bytes += entry->length; | ||
863 | } else { | ||
864 | dev->stats.tx_errors++; | ||
865 | |||
866 | switch (urb->status) { | ||
867 | case -EPIPE: | ||
868 | usbnet_defer_kevent (dev, EVENT_TX_HALT); | ||
869 | break; | ||
870 | |||
871 | /* software-driven interface shutdown */ | ||
872 | case -ECONNRESET: // async unlink | ||
873 | case -ESHUTDOWN: // hardware gone | ||
874 | break; | ||
875 | |||
876 | // like rx, tx gets controller i/o faults during khubd delays | ||
877 | // and so it uses the same throttling mechanism. | ||
878 | case -EPROTO: | ||
879 | case -ETIME: | ||
880 | case -EILSEQ: | ||
881 | if (!timer_pending (&dev->delay)) { | ||
882 | mod_timer (&dev->delay, | ||
883 | jiffies + THROTTLE_JIFFIES); | ||
884 | if (netif_msg_link (dev)) | ||
885 | devdbg (dev, "tx throttle %d", | ||
886 | urb->status); | ||
887 | } | ||
888 | netif_stop_queue (dev->net); | ||
889 | break; | ||
890 | default: | ||
891 | if (netif_msg_tx_err (dev)) | ||
892 | devdbg (dev, "tx err %d", entry->urb->status); | ||
893 | break; | ||
894 | } | ||
895 | } | ||
896 | |||
897 | urb->dev = NULL; | ||
898 | entry->state = tx_done; | ||
899 | defer_bh(dev, skb, &dev->txq); | ||
900 | } | ||
901 | |||
902 | /*-------------------------------------------------------------------------*/ | ||
903 | |||
904 | static void usbnet_tx_timeout (struct net_device *net) | ||
905 | { | ||
906 | struct usbnet *dev = netdev_priv(net); | ||
907 | |||
908 | unlink_urbs (dev, &dev->txq); | ||
909 | tasklet_schedule (&dev->bh); | ||
910 | |||
911 | // FIXME: device recovery -- reset? | ||
912 | } | ||
913 | |||
914 | /*-------------------------------------------------------------------------*/ | ||
915 | |||
916 | static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) | ||
917 | { | ||
918 | struct usbnet *dev = netdev_priv(net); | ||
919 | int length; | ||
920 | int retval = NET_XMIT_SUCCESS; | ||
921 | struct urb *urb = NULL; | ||
922 | struct skb_data *entry; | ||
923 | struct driver_info *info = dev->driver_info; | ||
924 | unsigned long flags; | ||
925 | |||
926 | // some devices want funky USB-level framing, for | ||
927 | // win32 driver (usually) and/or hardware quirks | ||
928 | if (info->tx_fixup) { | ||
929 | skb = info->tx_fixup (dev, skb, GFP_ATOMIC); | ||
930 | if (!skb) { | ||
931 | if (netif_msg_tx_err (dev)) | ||
932 | devdbg (dev, "can't tx_fixup skb"); | ||
933 | goto drop; | ||
934 | } | ||
935 | } | ||
936 | length = skb->len; | ||
937 | |||
938 | if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { | ||
939 | if (netif_msg_tx_err (dev)) | ||
940 | devdbg (dev, "no urb"); | ||
941 | goto drop; | ||
942 | } | ||
943 | |||
944 | entry = (struct skb_data *) skb->cb; | ||
945 | entry->urb = urb; | ||
946 | entry->dev = dev; | ||
947 | entry->state = tx_start; | ||
948 | entry->length = length; | ||
949 | |||
950 | usb_fill_bulk_urb (urb, dev->udev, dev->out, | ||
951 | skb->data, skb->len, tx_complete, skb); | ||
952 | |||
953 | /* don't assume the hardware handles USB_ZERO_PACKET | ||
954 | * NOTE: strictly conforming cdc-ether devices should expect | ||
955 | * the ZLP here, but ignore the one-byte packet. | ||
956 | * | ||
957 | * FIXME zero that byte, if it doesn't require a new skb. | ||
958 | */ | ||
959 | if ((length % dev->maxpacket) == 0) | ||
960 | urb->transfer_buffer_length++; | ||
961 | |||
962 | spin_lock_irqsave (&dev->txq.lock, flags); | ||
963 | |||
964 | switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { | ||
965 | case -EPIPE: | ||
966 | netif_stop_queue (net); | ||
967 | usbnet_defer_kevent (dev, EVENT_TX_HALT); | ||
968 | break; | ||
969 | default: | ||
970 | if (netif_msg_tx_err (dev)) | ||
971 | devdbg (dev, "tx: submit urb err %d", retval); | ||
972 | break; | ||
973 | case 0: | ||
974 | net->trans_start = jiffies; | ||
975 | __skb_queue_tail (&dev->txq, skb); | ||
976 | if (dev->txq.qlen >= TX_QLEN (dev)) | ||
977 | netif_stop_queue (net); | ||
978 | } | ||
979 | spin_unlock_irqrestore (&dev->txq.lock, flags); | ||
980 | |||
981 | if (retval) { | ||
982 | if (netif_msg_tx_err (dev)) | ||
983 | devdbg (dev, "drop, code %d", retval); | ||
984 | drop: | ||
985 | retval = NET_XMIT_SUCCESS; | ||
986 | dev->stats.tx_dropped++; | ||
987 | if (skb) | ||
988 | dev_kfree_skb_any (skb); | ||
989 | usb_free_urb (urb); | ||
990 | } else if (netif_msg_tx_queued (dev)) { | ||
991 | devdbg (dev, "> tx, len %d, type 0x%x", | ||
992 | length, skb->protocol); | ||
993 | } | ||
994 | return retval; | ||
995 | } | ||
996 | |||
997 | |||
998 | /*-------------------------------------------------------------------------*/ | ||
999 | |||
1000 | // tasklet (work deferred from completions, in_irq) or timer | ||
1001 | |||
1002 | static void usbnet_bh (unsigned long param) | ||
1003 | { | ||
1004 | struct usbnet *dev = (struct usbnet *) param; | ||
1005 | struct sk_buff *skb; | ||
1006 | struct skb_data *entry; | ||
1007 | |||
1008 | while ((skb = skb_dequeue (&dev->done))) { | ||
1009 | entry = (struct skb_data *) skb->cb; | ||
1010 | switch (entry->state) { | ||
1011 | case rx_done: | ||
1012 | entry->state = rx_cleanup; | ||
1013 | rx_process (dev, skb); | ||
1014 | continue; | ||
1015 | case tx_done: | ||
1016 | case rx_cleanup: | ||
1017 | usb_free_urb (entry->urb); | ||
1018 | dev_kfree_skb (skb); | ||
1019 | continue; | ||
1020 | default: | ||
1021 | devdbg (dev, "bogus skb state %d", entry->state); | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | // waiting for all pending urbs to complete? | ||
1026 | if (dev->wait) { | ||
1027 | if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { | ||
1028 | wake_up (dev->wait); | ||
1029 | } | ||
1030 | |||
1031 | // or are we maybe short a few urbs? | ||
1032 | } else if (netif_running (dev->net) | ||
1033 | && netif_device_present (dev->net) | ||
1034 | && !timer_pending (&dev->delay) | ||
1035 | && !test_bit (EVENT_RX_HALT, &dev->flags)) { | ||
1036 | int temp = dev->rxq.qlen; | ||
1037 | int qlen = RX_QLEN (dev); | ||
1038 | |||
1039 | if (temp < qlen) { | ||
1040 | struct urb *urb; | ||
1041 | int i; | ||
1042 | |||
1043 | // don't refill the queue all at once | ||
1044 | for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { | ||
1045 | urb = usb_alloc_urb (0, GFP_ATOMIC); | ||
1046 | if (urb != NULL) | ||
1047 | rx_submit (dev, urb, GFP_ATOMIC); | ||
1048 | } | ||
1049 | if (temp != dev->rxq.qlen && netif_msg_link (dev)) | ||
1050 | devdbg (dev, "rxqlen %d --> %d", | ||
1051 | temp, dev->rxq.qlen); | ||
1052 | if (dev->rxq.qlen < qlen) | ||
1053 | tasklet_schedule (&dev->bh); | ||
1054 | } | ||
1055 | if (dev->txq.qlen < TX_QLEN (dev)) | ||
1056 | netif_wake_queue (dev->net); | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | |||
1061 | |||
1062 | /*------------------------------------------------------------------------- | ||
1063 | * | ||
1064 | * USB Device Driver support | ||
1065 | * | ||
1066 | *-------------------------------------------------------------------------*/ | ||
1067 | |||
1068 | // precondition: never called in_interrupt | ||
1069 | |||
1070 | void usbnet_disconnect (struct usb_interface *intf) | ||
1071 | { | ||
1072 | struct usbnet *dev; | ||
1073 | struct usb_device *xdev; | ||
1074 | struct net_device *net; | ||
1075 | |||
1076 | dev = usb_get_intfdata(intf); | ||
1077 | usb_set_intfdata(intf, NULL); | ||
1078 | if (!dev) | ||
1079 | return; | ||
1080 | |||
1081 | xdev = interface_to_usbdev (intf); | ||
1082 | |||
1083 | if (netif_msg_probe (dev)) | ||
1084 | devinfo (dev, "unregister '%s' usb-%s-%s, %s", | ||
1085 | intf->dev.driver->name, | ||
1086 | xdev->bus->bus_name, xdev->devpath, | ||
1087 | dev->driver_info->description); | ||
1088 | |||
1089 | net = dev->net; | ||
1090 | unregister_netdev (net); | ||
1091 | |||
1092 | /* we don't hold rtnl here ... */ | ||
1093 | flush_scheduled_work (); | ||
1094 | |||
1095 | if (dev->driver_info->unbind) | ||
1096 | dev->driver_info->unbind (dev, intf); | ||
1097 | |||
1098 | free_netdev(net); | ||
1099 | usb_put_dev (xdev); | ||
1100 | } | ||
1101 | EXPORT_SYMBOL_GPL(usbnet_disconnect); | ||
1102 | |||
1103 | |||
1104 | /*-------------------------------------------------------------------------*/ | ||
1105 | |||
1106 | // precondition: never called in_interrupt | ||
1107 | |||
1108 | int | ||
1109 | usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | ||
1110 | { | ||
1111 | struct usbnet *dev; | ||
1112 | struct net_device *net; | ||
1113 | struct usb_host_interface *interface; | ||
1114 | struct driver_info *info; | ||
1115 | struct usb_device *xdev; | ||
1116 | int status; | ||
1117 | const char *name; | ||
1118 | |||
1119 | name = udev->dev.driver->name; | ||
1120 | info = (struct driver_info *) prod->driver_info; | ||
1121 | if (!info) { | ||
1122 | dev_dbg (&udev->dev, "blacklisted by %s\n", name); | ||
1123 | return -ENODEV; | ||
1124 | } | ||
1125 | xdev = interface_to_usbdev (udev); | ||
1126 | interface = udev->cur_altsetting; | ||
1127 | |||
1128 | usb_get_dev (xdev); | ||
1129 | |||
1130 | status = -ENOMEM; | ||
1131 | |||
1132 | // set up our own records | ||
1133 | net = alloc_etherdev(sizeof(*dev)); | ||
1134 | if (!net) { | ||
1135 | dbg ("can't kmalloc dev"); | ||
1136 | goto out; | ||
1137 | } | ||
1138 | |||
1139 | dev = netdev_priv(net); | ||
1140 | dev->udev = xdev; | ||
1141 | dev->driver_info = info; | ||
1142 | dev->driver_name = name; | ||
1143 | dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV | ||
1144 | | NETIF_MSG_PROBE | NETIF_MSG_LINK); | ||
1145 | skb_queue_head_init (&dev->rxq); | ||
1146 | skb_queue_head_init (&dev->txq); | ||
1147 | skb_queue_head_init (&dev->done); | ||
1148 | dev->bh.func = usbnet_bh; | ||
1149 | dev->bh.data = (unsigned long) dev; | ||
1150 | INIT_WORK (&dev->kevent, kevent); | ||
1151 | dev->delay.function = usbnet_bh; | ||
1152 | dev->delay.data = (unsigned long) dev; | ||
1153 | init_timer (&dev->delay); | ||
1154 | mutex_init (&dev->phy_mutex); | ||
1155 | |||
1156 | SET_MODULE_OWNER (net); | ||
1157 | dev->net = net; | ||
1158 | strcpy (net->name, "usb%d"); | ||
1159 | memcpy (net->dev_addr, node_id, sizeof node_id); | ||
1160 | |||
1161 | /* rx and tx sides can use different message sizes; | ||
1162 | * bind() should set rx_urb_size in that case. | ||
1163 | */ | ||
1164 | dev->hard_mtu = net->mtu + net->hard_header_len; | ||
1165 | #if 0 | ||
1166 | // dma_supported() is deeply broken on almost all architectures | ||
1167 | // possible with some EHCI controllers | ||
1168 | if (dma_supported (&udev->dev, DMA_64BIT_MASK)) | ||
1169 | net->features |= NETIF_F_HIGHDMA; | ||
1170 | #endif | ||
1171 | |||
1172 | net->change_mtu = usbnet_change_mtu; | ||
1173 | net->get_stats = usbnet_get_stats; | ||
1174 | net->hard_start_xmit = usbnet_start_xmit; | ||
1175 | net->open = usbnet_open; | ||
1176 | net->stop = usbnet_stop; | ||
1177 | net->watchdog_timeo = TX_TIMEOUT_JIFFIES; | ||
1178 | net->tx_timeout = usbnet_tx_timeout; | ||
1179 | net->ethtool_ops = &usbnet_ethtool_ops; | ||
1180 | |||
1181 | // allow device-specific bind/init procedures | ||
1182 | // NOTE net->name still not usable ... | ||
1183 | if (info->bind) { | ||
1184 | status = info->bind (dev, udev); | ||
1185 | if (status < 0) | ||
1186 | goto out1; | ||
1187 | |||
1188 | // heuristic: "usb%d" for links we know are two-host, | ||
1189 | // else "eth%d" when there's reasonable doubt. userspace | ||
1190 | // can rename the link if it knows better. | ||
1191 | if ((dev->driver_info->flags & FLAG_ETHER) != 0 | ||
1192 | && (net->dev_addr [0] & 0x02) == 0) | ||
1193 | strcpy (net->name, "eth%d"); | ||
1194 | |||
1195 | /* maybe the remote can't receive an Ethernet MTU */ | ||
1196 | if (net->mtu > (dev->hard_mtu - net->hard_header_len)) | ||
1197 | net->mtu = dev->hard_mtu - net->hard_header_len; | ||
1198 | } else if (!info->in || !info->out) | ||
1199 | status = usbnet_get_endpoints (dev, udev); | ||
1200 | else { | ||
1201 | dev->in = usb_rcvbulkpipe (xdev, info->in); | ||
1202 | dev->out = usb_sndbulkpipe (xdev, info->out); | ||
1203 | if (!(info->flags & FLAG_NO_SETINT)) | ||
1204 | status = usb_set_interface (xdev, | ||
1205 | interface->desc.bInterfaceNumber, | ||
1206 | interface->desc.bAlternateSetting); | ||
1207 | else | ||
1208 | status = 0; | ||
1209 | |||
1210 | } | ||
1211 | if (status == 0 && dev->status) | ||
1212 | status = init_status (dev, udev); | ||
1213 | if (status < 0) | ||
1214 | goto out3; | ||
1215 | |||
1216 | if (!dev->rx_urb_size) | ||
1217 | dev->rx_urb_size = dev->hard_mtu; | ||
1218 | dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); | ||
1219 | |||
1220 | SET_NETDEV_DEV(net, &udev->dev); | ||
1221 | status = register_netdev (net); | ||
1222 | if (status) | ||
1223 | goto out3; | ||
1224 | if (netif_msg_probe (dev)) | ||
1225 | devinfo (dev, "register '%s' at usb-%s-%s, %s, " | ||
1226 | "%02x:%02x:%02x:%02x:%02x:%02x", | ||
1227 | udev->dev.driver->name, | ||
1228 | xdev->bus->bus_name, xdev->devpath, | ||
1229 | dev->driver_info->description, | ||
1230 | net->dev_addr [0], net->dev_addr [1], | ||
1231 | net->dev_addr [2], net->dev_addr [3], | ||
1232 | net->dev_addr [4], net->dev_addr [5]); | ||
1233 | |||
1234 | // ok, it's ready to go. | ||
1235 | usb_set_intfdata (udev, dev); | ||
1236 | |||
1237 | // start as if the link is up | ||
1238 | netif_device_attach (net); | ||
1239 | |||
1240 | return 0; | ||
1241 | |||
1242 | out3: | ||
1243 | if (info->unbind) | ||
1244 | info->unbind (dev, udev); | ||
1245 | out1: | ||
1246 | free_netdev(net); | ||
1247 | out: | ||
1248 | usb_put_dev(xdev); | ||
1249 | return status; | ||
1250 | } | ||
1251 | EXPORT_SYMBOL_GPL(usbnet_probe); | ||
1252 | |||
1253 | /*-------------------------------------------------------------------------*/ | ||
1254 | |||
1255 | /* FIXME these suspend/resume methods assume non-CDC style | ||
1256 | * devices, with only one interface. | ||
1257 | */ | ||
1258 | |||
1259 | int usbnet_suspend (struct usb_interface *intf, pm_message_t message) | ||
1260 | { | ||
1261 | struct usbnet *dev = usb_get_intfdata(intf); | ||
1262 | |||
1263 | /* accelerate emptying of the rx and queues, to avoid | ||
1264 | * having everything error out. | ||
1265 | */ | ||
1266 | netif_device_detach (dev->net); | ||
1267 | (void) unlink_urbs (dev, &dev->rxq); | ||
1268 | (void) unlink_urbs (dev, &dev->txq); | ||
1269 | return 0; | ||
1270 | } | ||
1271 | EXPORT_SYMBOL_GPL(usbnet_suspend); | ||
1272 | |||
1273 | int usbnet_resume (struct usb_interface *intf) | ||
1274 | { | ||
1275 | struct usbnet *dev = usb_get_intfdata(intf); | ||
1276 | |||
1277 | netif_device_attach (dev->net); | ||
1278 | tasklet_schedule (&dev->bh); | ||
1279 | return 0; | ||
1280 | } | ||
1281 | EXPORT_SYMBOL_GPL(usbnet_resume); | ||
1282 | |||
1283 | |||
1284 | /*-------------------------------------------------------------------------*/ | ||
1285 | |||
1286 | static int __init usbnet_init(void) | ||
1287 | { | ||
1288 | /* compiler should optimize this out */ | ||
1289 | BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) | ||
1290 | < sizeof (struct skb_data)); | ||
1291 | |||
1292 | random_ether_addr(node_id); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | module_init(usbnet_init); | ||
1296 | |||
1297 | static void __exit usbnet_exit(void) | ||
1298 | { | ||
1299 | } | ||
1300 | module_exit(usbnet_exit); | ||
1301 | |||
1302 | MODULE_AUTHOR("David Brownell"); | ||
1303 | MODULE_DESCRIPTION("USB network driver framework"); | ||
1304 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h new file mode 100644 index 000000000000..82db5a8e528e --- /dev/null +++ b/drivers/net/usb/usbnet.h | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * USB Networking Link Interface | ||
3 | * | ||
4 | * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net> | ||
5 | * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | |||
23 | #ifndef __USBNET_H | ||
24 | #define __USBNET_H | ||
25 | |||
26 | |||
27 | /* interface from usbnet core to each USB networking link we handle */ | ||
28 | struct usbnet { | ||
29 | /* housekeeping */ | ||
30 | struct usb_device *udev; | ||
31 | struct driver_info *driver_info; | ||
32 | const char *driver_name; | ||
33 | wait_queue_head_t *wait; | ||
34 | struct mutex phy_mutex; | ||
35 | |||
36 | /* i/o info: pipes etc */ | ||
37 | unsigned in, out; | ||
38 | struct usb_host_endpoint *status; | ||
39 | unsigned maxpacket; | ||
40 | struct timer_list delay; | ||
41 | |||
42 | /* protocol/interface state */ | ||
43 | struct net_device *net; | ||
44 | struct net_device_stats stats; | ||
45 | int msg_enable; | ||
46 | unsigned long data [5]; | ||
47 | u32 xid; | ||
48 | u32 hard_mtu; /* count any extra framing */ | ||
49 | size_t rx_urb_size; /* size for rx urbs */ | ||
50 | struct mii_if_info mii; | ||
51 | |||
52 | /* various kinds of pending driver work */ | ||
53 | struct sk_buff_head rxq; | ||
54 | struct sk_buff_head txq; | ||
55 | struct sk_buff_head done; | ||
56 | struct urb *interrupt; | ||
57 | struct tasklet_struct bh; | ||
58 | |||
59 | struct work_struct kevent; | ||
60 | unsigned long flags; | ||
61 | # define EVENT_TX_HALT 0 | ||
62 | # define EVENT_RX_HALT 1 | ||
63 | # define EVENT_RX_MEMORY 2 | ||
64 | # define EVENT_STS_SPLIT 3 | ||
65 | # define EVENT_LINK_RESET 4 | ||
66 | }; | ||
67 | |||
68 | static inline struct usb_driver *driver_of(struct usb_interface *intf) | ||
69 | { | ||
70 | return to_usb_driver(intf->dev.driver); | ||
71 | } | ||
72 | |||
73 | /* interface from the device/framing level "minidriver" to core */ | ||
74 | struct driver_info { | ||
75 | char *description; | ||
76 | |||
77 | int flags; | ||
78 | /* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ | ||
79 | #define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ | ||
80 | #define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ | ||
81 | #define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ | ||
82 | #define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ | ||
83 | |||
84 | #define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ | ||
85 | #define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ | ||
86 | |||
87 | #define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ | ||
88 | |||
89 | /* init device ... can sleep, or cause probe() failure */ | ||
90 | int (*bind)(struct usbnet *, struct usb_interface *); | ||
91 | |||
92 | /* cleanup device ... can sleep, but can't fail */ | ||
93 | void (*unbind)(struct usbnet *, struct usb_interface *); | ||
94 | |||
95 | /* reset device ... can sleep */ | ||
96 | int (*reset)(struct usbnet *); | ||
97 | |||
98 | /* see if peer is connected ... can sleep */ | ||
99 | int (*check_connect)(struct usbnet *); | ||
100 | |||
101 | /* for status polling */ | ||
102 | void (*status)(struct usbnet *, struct urb *); | ||
103 | |||
104 | /* link reset handling, called from defer_kevent */ | ||
105 | int (*link_reset)(struct usbnet *); | ||
106 | |||
107 | /* fixup rx packet (strip framing) */ | ||
108 | int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); | ||
109 | |||
110 | /* fixup tx packet (add framing) */ | ||
111 | struct sk_buff *(*tx_fixup)(struct usbnet *dev, | ||
112 | struct sk_buff *skb, gfp_t flags); | ||
113 | |||
114 | /* for new devices, use the descriptor-reading code instead */ | ||
115 | int in; /* rx endpoint */ | ||
116 | int out; /* tx endpoint */ | ||
117 | |||
118 | unsigned long data; /* Misc driver specific data */ | ||
119 | }; | ||
120 | |||
121 | /* Minidrivers are just drivers using the "usbnet" core as a powerful | ||
122 | * network-specific subroutine library ... that happens to do pretty | ||
123 | * much everything except custom framing and chip-specific stuff. | ||
124 | */ | ||
125 | extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *); | ||
126 | extern int usbnet_suspend (struct usb_interface *, pm_message_t ); | ||
127 | extern int usbnet_resume (struct usb_interface *); | ||
128 | extern void usbnet_disconnect(struct usb_interface *); | ||
129 | |||
130 | |||
131 | /* Drivers that reuse some of the standard USB CDC infrastructure | ||
132 | * (notably, using multiple interfaces according to the CDC | ||
133 | * union descriptor) get some helper code. | ||
134 | */ | ||
135 | struct cdc_state { | ||
136 | struct usb_cdc_header_desc *header; | ||
137 | struct usb_cdc_union_desc *u; | ||
138 | struct usb_cdc_ether_desc *ether; | ||
139 | struct usb_interface *control; | ||
140 | struct usb_interface *data; | ||
141 | }; | ||
142 | |||
143 | extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *); | ||
144 | extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *); | ||
145 | |||
146 | /* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ | ||
147 | #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ | ||
148 | |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ | ||
149 | |USB_CDC_PACKET_TYPE_PROMISCUOUS \ | ||
150 | |USB_CDC_PACKET_TYPE_DIRECTED) | ||
151 | |||
152 | |||
153 | /* we record the state for each of our queued skbs */ | ||
154 | enum skb_state { | ||
155 | illegal = 0, | ||
156 | tx_start, tx_done, | ||
157 | rx_start, rx_done, rx_cleanup | ||
158 | }; | ||
159 | |||
160 | struct skb_data { /* skb->cb is one of these */ | ||
161 | struct urb *urb; | ||
162 | struct usbnet *dev; | ||
163 | enum skb_state state; | ||
164 | size_t length; | ||
165 | }; | ||
166 | |||
167 | |||
168 | extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *); | ||
169 | extern void usbnet_defer_kevent (struct usbnet *, int); | ||
170 | extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); | ||
171 | extern void usbnet_unlink_rx_urbs(struct usbnet *); | ||
172 | |||
173 | extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); | ||
174 | extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); | ||
175 | extern u32 usbnet_get_link (struct net_device *net); | ||
176 | extern u32 usbnet_get_msglevel (struct net_device *); | ||
177 | extern void usbnet_set_msglevel (struct net_device *, u32); | ||
178 | extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); | ||
179 | extern int usbnet_nway_reset(struct net_device *net); | ||
180 | |||
181 | /* messaging support includes the interface name, so it must not be | ||
182 | * used before it has one ... notably, in minidriver bind() calls. | ||
183 | */ | ||
184 | #ifdef DEBUG | ||
185 | #define devdbg(usbnet, fmt, arg...) \ | ||
186 | printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg) | ||
187 | #else | ||
188 | #define devdbg(usbnet, fmt, arg...) do {} while(0) | ||
189 | #endif | ||
190 | |||
191 | #define deverr(usbnet, fmt, arg...) \ | ||
192 | printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) | ||
193 | #define devwarn(usbnet, fmt, arg...) \ | ||
194 | printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) | ||
195 | |||
196 | #define devinfo(usbnet, fmt, arg...) \ | ||
197 | printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ | ||
198 | |||
199 | |||
200 | #endif /* __USBNET_H */ | ||
diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c new file mode 100644 index 000000000000..9f98e8ce487a --- /dev/null +++ b/drivers/net/usb/zaurus.c | |||
@@ -0,0 +1,385 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz> | ||
3 | * Copyright (C) 2002-2005 by David Brownell | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | // #define DEBUG // error path messages, extra info | ||
21 | // #define VERBOSE // more; success messages | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/ethtool.h> | ||
27 | #include <linux/workqueue.h> | ||
28 | #include <linux/mii.h> | ||
29 | #include <linux/crc32.h> | ||
30 | #include <linux/usb.h> | ||
31 | #include <linux/usb/cdc.h> | ||
32 | |||
33 | #include "usbnet.h" | ||
34 | |||
35 | |||
36 | /* | ||
37 | * All known Zaurii lie about their standards conformance. At least | ||
38 | * the earliest SA-1100 models lie by saying they support CDC Ethernet. | ||
39 | * Some later models (especially PXA-25x and PXA-27x based ones) lie | ||
40 | * and say they support CDC MDLM (for access to cell phone modems). | ||
41 | * | ||
42 | * There are non-Zaurus products that use these same protocols too. | ||
43 | * | ||
44 | * The annoying thing is that at the same time Sharp was developing | ||
45 | * that annoying standards-breaking software, the Linux community had | ||
46 | * a simple "CDC Subset" working reliably on the same SA-1100 hardware. | ||
47 | * That is, the same functionality but not violating standards. | ||
48 | * | ||
49 | * The CDC Ethernet nonconformance points are troublesome to hosts | ||
50 | * with a true CDC Ethernet implementation: | ||
51 | * - Framing appends a CRC, which the spec says drivers "must not" do; | ||
52 | * - Transfers data in altsetting zero, instead of altsetting 1; | ||
53 | * - All these peripherals use the same ethernet address. | ||
54 | * | ||
55 | * The CDC MDLM nonconformance is less immediately troublesome, since all | ||
56 | * MDLM implementations are quasi-proprietary anyway. | ||
57 | */ | ||
58 | |||
59 | static struct sk_buff * | ||
60 | zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | ||
61 | { | ||
62 | int padlen; | ||
63 | struct sk_buff *skb2; | ||
64 | |||
65 | padlen = 2; | ||
66 | if (!skb_cloned(skb)) { | ||
67 | int tailroom = skb_tailroom(skb); | ||
68 | if ((padlen + 4) <= tailroom) | ||
69 | goto done; | ||
70 | } | ||
71 | skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags); | ||
72 | dev_kfree_skb_any(skb); | ||
73 | skb = skb2; | ||
74 | if (skb) { | ||
75 | u32 fcs; | ||
76 | done: | ||
77 | fcs = crc32_le(~0, skb->data, skb->len); | ||
78 | fcs = ~fcs; | ||
79 | |||
80 | *skb_put (skb, 1) = fcs & 0xff; | ||
81 | *skb_put (skb, 1) = (fcs>> 8) & 0xff; | ||
82 | *skb_put (skb, 1) = (fcs>>16) & 0xff; | ||
83 | *skb_put (skb, 1) = (fcs>>24) & 0xff; | ||
84 | } | ||
85 | return skb; | ||
86 | } | ||
87 | |||
88 | static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf) | ||
89 | { | ||
90 | /* Belcarra's funky framing has other options; mostly | ||
91 | * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes. | ||
92 | */ | ||
93 | dev->net->hard_header_len += 6; | ||
94 | dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; | ||
95 | return usbnet_generic_cdc_bind(dev, intf); | ||
96 | } | ||
97 | |||
98 | /* PDA style devices are always connected if present */ | ||
99 | static int always_connected (struct usbnet *dev) | ||
100 | { | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static const struct driver_info zaurus_sl5x00_info = { | ||
105 | .description = "Sharp Zaurus SL-5x00", | ||
106 | .flags = FLAG_FRAMING_Z, | ||
107 | .check_connect = always_connected, | ||
108 | .bind = zaurus_bind, | ||
109 | .unbind = usbnet_cdc_unbind, | ||
110 | .tx_fixup = zaurus_tx_fixup, | ||
111 | }; | ||
112 | #define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) | ||
113 | |||
114 | static const struct driver_info zaurus_pxa_info = { | ||
115 | .description = "Sharp Zaurus, PXA-2xx based", | ||
116 | .flags = FLAG_FRAMING_Z, | ||
117 | .check_connect = always_connected, | ||
118 | .bind = zaurus_bind, | ||
119 | .unbind = usbnet_cdc_unbind, | ||
120 | .tx_fixup = zaurus_tx_fixup, | ||
121 | }; | ||
122 | #define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) | ||
123 | |||
124 | static const struct driver_info olympus_mxl_info = { | ||
125 | .description = "Olympus R1000", | ||
126 | .flags = FLAG_FRAMING_Z, | ||
127 | .check_connect = always_connected, | ||
128 | .bind = zaurus_bind, | ||
129 | .unbind = usbnet_cdc_unbind, | ||
130 | .tx_fixup = zaurus_tx_fixup, | ||
131 | }; | ||
132 | #define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) | ||
133 | |||
134 | |||
135 | /* Some more recent products using Lineo/Belcarra code will wrongly claim | ||
136 | * CDC MDLM conformance. They aren't conformant: data endpoints live | ||
137 | * in the control interface, there's no data interface, and it's not used | ||
138 | * to talk to a cell phone radio. But at least we can detect these two | ||
139 | * pseudo-classes, rather than growing this product list with entries for | ||
140 | * each new nonconformant product (sigh). | ||
141 | */ | ||
142 | static const u8 safe_guid[16] = { | ||
143 | 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, | ||
144 | 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, | ||
145 | }; | ||
146 | static const u8 blan_guid[16] = { | ||
147 | 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, | ||
148 | 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, | ||
149 | }; | ||
150 | |||
151 | static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf) | ||
152 | { | ||
153 | u8 *buf = intf->cur_altsetting->extra; | ||
154 | int len = intf->cur_altsetting->extralen; | ||
155 | struct usb_cdc_mdlm_desc *desc = NULL; | ||
156 | struct usb_cdc_mdlm_detail_desc *detail = NULL; | ||
157 | |||
158 | while (len > 3) { | ||
159 | if (buf [1] != USB_DT_CS_INTERFACE) | ||
160 | goto next_desc; | ||
161 | |||
162 | /* use bDescriptorSubType, and just verify that we get a | ||
163 | * "BLAN" (or "SAFE") descriptor. | ||
164 | */ | ||
165 | switch (buf [2]) { | ||
166 | case USB_CDC_MDLM_TYPE: | ||
167 | if (desc) { | ||
168 | dev_dbg(&intf->dev, "extra MDLM\n"); | ||
169 | goto bad_desc; | ||
170 | } | ||
171 | desc = (void *) buf; | ||
172 | if (desc->bLength != sizeof *desc) { | ||
173 | dev_dbg(&intf->dev, "MDLM len %u\n", | ||
174 | desc->bLength); | ||
175 | goto bad_desc; | ||
176 | } | ||
177 | /* expect bcdVersion 1.0, ignore */ | ||
178 | if (memcmp(&desc->bGUID, blan_guid, 16) | ||
179 | && memcmp(&desc->bGUID, safe_guid, 16) ) { | ||
180 | /* hey, this one might _really_ be MDLM! */ | ||
181 | dev_dbg(&intf->dev, "MDLM guid\n"); | ||
182 | goto bad_desc; | ||
183 | } | ||
184 | break; | ||
185 | case USB_CDC_MDLM_DETAIL_TYPE: | ||
186 | if (detail) { | ||
187 | dev_dbg(&intf->dev, "extra MDLM detail\n"); | ||
188 | goto bad_desc; | ||
189 | } | ||
190 | detail = (void *) buf; | ||
191 | switch (detail->bGuidDescriptorType) { | ||
192 | case 0: /* "SAFE" */ | ||
193 | if (detail->bLength != (sizeof *detail + 2)) | ||
194 | goto bad_detail; | ||
195 | break; | ||
196 | case 1: /* "BLAN" */ | ||
197 | if (detail->bLength != (sizeof *detail + 3)) | ||
198 | goto bad_detail; | ||
199 | break; | ||
200 | default: | ||
201 | goto bad_detail; | ||
202 | } | ||
203 | |||
204 | /* assuming we either noticed BLAN already, or will | ||
205 | * find it soon, there are some data bytes here: | ||
206 | * - bmNetworkCapabilities (unused) | ||
207 | * - bmDataCapabilities (bits, see below) | ||
208 | * - bPad (ignored, for PADAFTER -- BLAN-only) | ||
209 | * bits are: | ||
210 | * - 0x01 -- Zaurus framing (add CRC) | ||
211 | * - 0x02 -- PADBEFORE (CRC includes some padding) | ||
212 | * - 0x04 -- PADAFTER (some padding after CRC) | ||
213 | * - 0x08 -- "fermat" packet mangling (for hw bugs) | ||
214 | * the PADBEFORE appears not to matter; we interop | ||
215 | * with devices that use it and those that don't. | ||
216 | */ | ||
217 | if ((detail->bDetailData[1] & ~0x02) != 0x01) { | ||
218 | /* bmDataCapabilities == 0 would be fine too, | ||
219 | * but framing is minidriver-coupled for now. | ||
220 | */ | ||
221 | bad_detail: | ||
222 | dev_dbg(&intf->dev, | ||
223 | "bad MDLM detail, %d %d %d\n", | ||
224 | detail->bLength, | ||
225 | detail->bDetailData[0], | ||
226 | detail->bDetailData[2]); | ||
227 | goto bad_desc; | ||
228 | } | ||
229 | |||
230 | /* same extra framing as for non-BLAN mode */ | ||
231 | dev->net->hard_header_len += 6; | ||
232 | dev->rx_urb_size = dev->net->hard_header_len | ||
233 | + dev->net->mtu; | ||
234 | break; | ||
235 | } | ||
236 | next_desc: | ||
237 | len -= buf [0]; /* bLength */ | ||
238 | buf += buf [0]; | ||
239 | } | ||
240 | |||
241 | if (!desc || !detail) { | ||
242 | dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n", | ||
243 | desc ? "" : "func ", | ||
244 | detail ? "" : "detail "); | ||
245 | goto bad_desc; | ||
246 | } | ||
247 | |||
248 | /* There's probably a CDC Ethernet descriptor there, but we can't | ||
249 | * rely on the Ethernet address it provides since not all vendors | ||
250 | * bother to make it unique. Likewise there's no point in tracking | ||
251 | * of the CDC event notifications. | ||
252 | */ | ||
253 | return usbnet_get_endpoints(dev, intf); | ||
254 | |||
255 | bad_desc: | ||
256 | dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n"); | ||
257 | return -ENODEV; | ||
258 | } | ||
259 | |||
260 | static const struct driver_info bogus_mdlm_info = { | ||
261 | .description = "pseudo-MDLM (BLAN) device", | ||
262 | .flags = FLAG_FRAMING_Z, | ||
263 | .check_connect = always_connected, | ||
264 | .tx_fixup = zaurus_tx_fixup, | ||
265 | .bind = blan_mdlm_bind, | ||
266 | }; | ||
267 | |||
268 | static const struct usb_device_id products [] = { | ||
269 | #define ZAURUS_MASTER_INTERFACE \ | ||
270 | .bInterfaceClass = USB_CLASS_COMM, \ | ||
271 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ | ||
272 | .bInterfaceProtocol = USB_CDC_PROTO_NONE | ||
273 | |||
274 | /* SA-1100 based Sharp Zaurus ("collie"), or compatible. */ | ||
275 | { | ||
276 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
277 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
278 | .idVendor = 0x04DD, | ||
279 | .idProduct = 0x8004, | ||
280 | ZAURUS_MASTER_INTERFACE, | ||
281 | .driver_info = ZAURUS_STRONGARM_INFO, | ||
282 | }, | ||
283 | |||
284 | /* PXA-2xx based models are also lying-about-cdc. If you add any | ||
285 | * more devices that claim to be CDC Ethernet, make sure they get | ||
286 | * added to the blacklist in cdc_ether too. | ||
287 | * | ||
288 | * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries, | ||
289 | * unlike the older ones with 2.4 "embedix" kernels. | ||
290 | */ | ||
291 | { | ||
292 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
293 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
294 | .idVendor = 0x04DD, | ||
295 | .idProduct = 0x8005, /* A-300 */ | ||
296 | ZAURUS_MASTER_INTERFACE, | ||
297 | .driver_info = ZAURUS_PXA_INFO, | ||
298 | }, { | ||
299 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
300 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
301 | .idVendor = 0x04DD, | ||
302 | .idProduct = 0x8006, /* B-500/SL-5600 */ | ||
303 | ZAURUS_MASTER_INTERFACE, | ||
304 | .driver_info = ZAURUS_PXA_INFO, | ||
305 | }, { | ||
306 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
307 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
308 | .idVendor = 0x04DD, | ||
309 | .idProduct = 0x8007, /* C-700 */ | ||
310 | ZAURUS_MASTER_INTERFACE, | ||
311 | .driver_info = ZAURUS_PXA_INFO, | ||
312 | }, { | ||
313 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
314 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
315 | .idVendor = 0x04DD, | ||
316 | .idProduct = 0x9031, /* C-750 C-760 */ | ||
317 | ZAURUS_MASTER_INTERFACE, | ||
318 | .driver_info = ZAURUS_PXA_INFO, | ||
319 | }, { | ||
320 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
321 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
322 | .idVendor = 0x04DD, | ||
323 | .idProduct = 0x9032, /* SL-6000 */ | ||
324 | ZAURUS_MASTER_INTERFACE, | ||
325 | .driver_info = ZAURUS_PXA_INFO, | ||
326 | }, { | ||
327 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
328 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
329 | .idVendor = 0x04DD, | ||
330 | /* reported with some C860 units */ | ||
331 | .idProduct = 0x9050, /* C-860 */ | ||
332 | ZAURUS_MASTER_INTERFACE, | ||
333 | .driver_info = ZAURUS_PXA_INFO, | ||
334 | }, | ||
335 | |||
336 | |||
337 | /* At least some of the newest PXA units have very different lies about | ||
338 | * their standards support: they claim to be cell phones offering | ||
339 | * direct access to their radios! (No, they don't conform to CDC MDLM.) | ||
340 | */ | ||
341 | { | ||
342 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, | ||
343 | USB_CDC_PROTO_NONE), | ||
344 | .driver_info = (unsigned long) &bogus_mdlm_info, | ||
345 | }, | ||
346 | |||
347 | /* Olympus has some models with a Zaurus-compatible option. | ||
348 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) | ||
349 | */ | ||
350 | { | ||
351 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
352 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
353 | .idVendor = 0x07B4, | ||
354 | .idProduct = 0x0F02, /* R-1000 */ | ||
355 | ZAURUS_MASTER_INTERFACE, | ||
356 | .driver_info = OLYMPUS_MXL_INFO, | ||
357 | }, | ||
358 | { }, // END | ||
359 | }; | ||
360 | MODULE_DEVICE_TABLE(usb, products); | ||
361 | |||
362 | static struct usb_driver zaurus_driver = { | ||
363 | .name = "zaurus", | ||
364 | .id_table = products, | ||
365 | .probe = usbnet_probe, | ||
366 | .disconnect = usbnet_disconnect, | ||
367 | .suspend = usbnet_suspend, | ||
368 | .resume = usbnet_resume, | ||
369 | }; | ||
370 | |||
371 | static int __init zaurus_init(void) | ||
372 | { | ||
373 | return usb_register(&zaurus_driver); | ||
374 | } | ||
375 | module_init(zaurus_init); | ||
376 | |||
377 | static void __exit zaurus_exit(void) | ||
378 | { | ||
379 | usb_deregister(&zaurus_driver); | ||
380 | } | ||
381 | module_exit(zaurus_exit); | ||
382 | |||
383 | MODULE_AUTHOR("Pavel Machek, David Brownell"); | ||
384 | MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products"); | ||
385 | MODULE_LICENSE("GPL"); | ||