diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/wireless |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/wireless')
55 files changed, 56285 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig new file mode 100644 index 000000000000..0aaa12c0c098 --- /dev/null +++ b/drivers/net/wireless/Kconfig | |||
@@ -0,0 +1,365 @@ | |||
1 | # | ||
2 | # Wireless LAN device configuration | ||
3 | # | ||
4 | |||
5 | menu "Wireless LAN (non-hamradio)" | ||
6 | depends on NETDEVICES | ||
7 | |||
8 | config NET_RADIO | ||
9 | bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions" | ||
10 | ---help--- | ||
11 | Support for wireless LANs and everything having to do with radio, | ||
12 | but not with amateur radio or FM broadcasting. | ||
13 | |||
14 | Saying Y here also enables the Wireless Extensions (creates | ||
15 | /proc/net/wireless and enables iwconfig access). The Wireless | ||
16 | Extension is a generic API allowing a driver to expose to the user | ||
17 | space configuration and statistics specific to common Wireless LANs. | ||
18 | The beauty of it is that a single set of tool can support all the | ||
19 | variations of Wireless LANs, regardless of their type (as long as | ||
20 | the driver supports Wireless Extension). Another advantage is that | ||
21 | these parameters may be changed on the fly without restarting the | ||
22 | driver (or Linux). If you wish to use Wireless Extensions with | ||
23 | wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch | ||
24 | the tools from | ||
25 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. | ||
26 | |||
27 | Some user-level drivers for scarab devices which don't require | ||
28 | special kernel support are available from | ||
29 | <ftp://shadow.cabi.net/pub/Linux/>. | ||
30 | |||
31 | # Note : the cards are obsolete (can't buy them anymore), but the drivers | ||
32 | # are not, as people are still using them... | ||
33 | comment "Obsolete Wireless cards support (pre-802.11)" | ||
34 | depends on NET_RADIO && (INET || ISA || PCMCIA) | ||
35 | |||
36 | config STRIP | ||
37 | tristate "STRIP (Metricom starmode radio IP)" | ||
38 | depends on NET_RADIO && INET | ||
39 | ---help--- | ||
40 | Say Y if you have a Metricom radio and intend to use Starmode Radio | ||
41 | IP. STRIP is a radio protocol developed for the MosquitoNet project | ||
42 | (on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet | ||
43 | traffic using Metricom radios. Metricom radios are small, battery | ||
44 | powered, 100kbit/sec packet radio transceivers, about the size and | ||
45 | weight of a cellular telephone. (You may also have heard them called | ||
46 | "Metricom modems" but we avoid the term "modem" because it misleads | ||
47 | many people into thinking that you can plug a Metricom modem into a | ||
48 | phone line and use it as a modem.) | ||
49 | |||
50 | You can use STRIP on any Linux machine with a serial port, although | ||
51 | it is obviously most useful for people with laptop computers. If you | ||
52 | think you might get a Metricom radio in the future, there is no harm | ||
53 | in saying Y to STRIP now, except that it makes the kernel a bit | ||
54 | bigger. | ||
55 | |||
56 | To compile this as a module, choose M here: the module will be | ||
57 | called strip. | ||
58 | |||
59 | config ARLAN | ||
60 | tristate "Aironet Arlan 655 & IC2200 DS support" | ||
61 | depends on NET_RADIO && ISA && !64BIT | ||
62 | ---help--- | ||
63 | Aironet makes Arlan, a class of wireless LAN adapters. These use the | ||
64 | www.Telxon.com chip, which is also used on several similar cards. | ||
65 | This driver is tested on the 655 and IC2200 series cards. Look at | ||
66 | <http://www.ylenurme.ee/~elmer/655/> for the latest information. | ||
67 | |||
68 | The driver is built as two modules, arlan and arlan-proc. The latter | ||
69 | is the /proc interface and is not needed most of time. | ||
70 | |||
71 | On some computers the card ends up in non-valid state after some | ||
72 | time. Use a ping-reset script to clear it. | ||
73 | |||
74 | config WAVELAN | ||
75 | tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" | ||
76 | depends on NET_RADIO && ISA | ||
77 | ---help--- | ||
78 | The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is | ||
79 | a Radio LAN (wireless Ethernet-like Local Area Network) using the | ||
80 | radio frequencies 900 MHz and 2.4 GHz. | ||
81 | |||
82 | This driver support the ISA version of the WaveLAN card. A separate | ||
83 | driver for the PCMCIA (PC-card) hardware is available in David | ||
84 | Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | ||
85 | for location). | ||
86 | |||
87 | If you want to use an ISA WaveLAN card under Linux, say Y and read | ||
88 | the Ethernet-HOWTO, available from | ||
89 | <http://www.tldp.org/docs.html#howto>. Some more specific | ||
90 | information is contained in | ||
91 | <file:Documentation/networking/wavelan.txt> and in the source code | ||
92 | <file:drivers/net/wavelan.p.h>. | ||
93 | |||
94 | You will also need the wireless tools package available from | ||
95 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. | ||
96 | Please read the man pages contained therein. | ||
97 | |||
98 | To compile this driver as a module, choose M here: the module will be | ||
99 | called wavelan. | ||
100 | |||
101 | config PCMCIA_WAVELAN | ||
102 | tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" | ||
103 | depends on NET_RADIO && PCMCIA | ||
104 | help | ||
105 | Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA | ||
106 | (PC-card) wireless Ethernet networking card to your computer. This | ||
107 | driver is for the non-IEEE-802.11 Wavelan cards. | ||
108 | |||
109 | To compile this driver as a module, choose M here: the module will be | ||
110 | called wavelan_cs. If unsure, say N. | ||
111 | |||
112 | config PCMCIA_NETWAVE | ||
113 | tristate "Xircom Netwave AirSurfer Pcmcia wireless support" | ||
114 | depends on NET_RADIO && PCMCIA | ||
115 | help | ||
116 | Say Y here if you intend to attach this type of PCMCIA (PC-card) | ||
117 | wireless Ethernet networking card to your computer. | ||
118 | |||
119 | To compile this driver as a module, choose M here: the module will be | ||
120 | called netwave_cs. If unsure, say N. | ||
121 | |||
122 | comment "Wireless 802.11 Frequency Hopping cards support" | ||
123 | depends on NET_RADIO && PCMCIA | ||
124 | |||
125 | config PCMCIA_RAYCS | ||
126 | tristate "Aviator/Raytheon 2.4MHz wireless support" | ||
127 | depends on NET_RADIO && PCMCIA | ||
128 | ---help--- | ||
129 | Say Y here if you intend to attach an Aviator/Raytheon PCMCIA | ||
130 | (PC-card) wireless Ethernet networking card to your computer. | ||
131 | Please read the file <file:Documentation/networking/ray_cs.txt> for | ||
132 | details. | ||
133 | |||
134 | To compile this driver as a module, choose M here: the module will be | ||
135 | called ray_cs. If unsure, say N. | ||
136 | |||
137 | comment "Wireless 802.11b ISA/PCI cards support" | ||
138 | depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) | ||
139 | |||
140 | config AIRO | ||
141 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" | ||
142 | depends on NET_RADIO && ISA && (PCI || BROKEN) | ||
143 | ---help--- | ||
144 | This is the standard Linux driver to support Cisco/Aironet ISA and | ||
145 | PCI 802.11 wireless cards. | ||
146 | It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X | ||
147 | - with or without encryption) as well as card before the Cisco | ||
148 | aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). | ||
149 | |||
150 | This driver support both the standard Linux Wireless Extensions | ||
151 | and Cisco proprietary API, so both the Linux Wireless Tools and the | ||
152 | Cisco Linux utilities can be used to configure the card. | ||
153 | |||
154 | The driver can be compiled as a module and will be named "airo". | ||
155 | |||
156 | config HERMES | ||
157 | tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" | ||
158 | depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA) | ||
159 | ---help--- | ||
160 | A driver for 802.11b wireless cards based based on the "Hermes" or | ||
161 | Intersil HFA384x (Prism 2) MAC controller. This includes the vast | ||
162 | majority of the PCMCIA 802.11b cards (which are nearly all rebadges) | ||
163 | - except for the Cisco/Aironet cards. Cards supported include the | ||
164 | Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco, | ||
165 | Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya, | ||
166 | IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear | ||
167 | MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel | ||
168 | PRO/Wireless, and Symbol Spectrum24 High Rate amongst others. | ||
169 | |||
170 | This option includes the guts of the driver, but in order to | ||
171 | actually use a card you will also need to enable support for PCMCIA | ||
172 | Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. | ||
173 | |||
174 | You will also very likely also need the Wireless Tools in order to | ||
175 | configure your card and that /etc/pcmcia/wireless.opts works : | ||
176 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> | ||
177 | |||
178 | config APPLE_AIRPORT | ||
179 | tristate "Apple Airport support (built-in)" | ||
180 | depends on PPC_PMAC && HERMES | ||
181 | help | ||
182 | Say Y here to support the Airport 802.11b wireless Ethernet hardware | ||
183 | built into the Macintosh iBook and other recent PowerPC-based | ||
184 | Macintosh machines. This is essentially a Lucent Orinoco card with | ||
185 | a non-standard interface | ||
186 | |||
187 | config PLX_HERMES | ||
188 | tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)" | ||
189 | depends on PCI && HERMES && EXPERIMENTAL | ||
190 | help | ||
191 | Enable support for PCMCIA cards supported by the "Hermes" (aka | ||
192 | orinoco) driver when used in PLX9052 based PCI adaptors. These | ||
193 | adaptors are not a full PCMCIA controller but act as a more limited | ||
194 | PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that | ||
195 | 802.11b PCMCIA cards can be used in desktop machines. The Netgear | ||
196 | MA301 is such an adaptor. | ||
197 | |||
198 | Support for these adaptors is so far still incomplete and buggy. | ||
199 | You have been warned. | ||
200 | |||
201 | config TMD_HERMES | ||
202 | tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)" | ||
203 | depends on PCI && HERMES && EXPERIMENTAL | ||
204 | help | ||
205 | Enable support for PCMCIA cards supported by the "Hermes" (aka | ||
206 | orinoco) driver when used in TMD7160 based PCI adaptors. These | ||
207 | adaptors are not a full PCMCIA controller but act as a more limited | ||
208 | PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that | ||
209 | 802.11b PCMCIA cards can be used in desktop machines. | ||
210 | |||
211 | Support for these adaptors is so far still incomplete and buggy. | ||
212 | You have been warned. | ||
213 | |||
214 | config PCI_HERMES | ||
215 | tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)" | ||
216 | depends on PCI && HERMES && EXPERIMENTAL | ||
217 | help | ||
218 | Enable support for PCI and mini-PCI 802.11b wireless NICs based on | ||
219 | the Prism 2.5 chipset. These are true PCI cards, not the 802.11b | ||
220 | PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also | ||
221 | common. Some of the built-in wireless adaptors in laptops are of | ||
222 | this variety. | ||
223 | |||
224 | config ATMEL | ||
225 | tristate "Atmel at76c50x chipset 802.11b support" | ||
226 | depends on NET_RADIO && EXPERIMENTAL | ||
227 | select FW_LOADER | ||
228 | select CRC32 | ||
229 | ---help--- | ||
230 | A driver 802.11b wireless cards based on the Atmel fast-vnet | ||
231 | chips. This driver supports standard Linux wireless extensions. | ||
232 | |||
233 | Many cards based on this chipset do not have flash memory | ||
234 | and need their firmware loaded at start-up. If yours is | ||
235 | one of these, you will need to provide a firmware image | ||
236 | to be loaded into the card by the driver. The Atmel | ||
237 | firmware package can be downloaded from | ||
238 | <http://www.thekelleys.org.uk/atmel> | ||
239 | |||
240 | config PCI_ATMEL | ||
241 | tristate "Atmel at76c506 PCI cards" | ||
242 | depends on ATMEL && PCI | ||
243 | ---help--- | ||
244 | Enable support for PCI and mini-PCI cards containing the | ||
245 | Atmel at76c506 chip. | ||
246 | |||
247 | # If Pcmcia is compiled in, offer Pcmcia cards... | ||
248 | comment "Wireless 802.11b Pcmcia/Cardbus cards support" | ||
249 | depends on NET_RADIO && PCMCIA | ||
250 | |||
251 | config PCMCIA_HERMES | ||
252 | tristate "Hermes PCMCIA card support" | ||
253 | depends on NET_RADIO && PCMCIA && HERMES | ||
254 | ---help--- | ||
255 | A driver for "Hermes" chipset based PCMCIA wireless adaptors, such | ||
256 | as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ | ||
257 | EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and | ||
258 | others). It should also be usable on various Prism II based cards | ||
259 | such as the Linksys, D-Link and Farallon Skyline. It should also | ||
260 | work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. | ||
261 | |||
262 | To use your PC-cards, you will need supporting software from David | ||
263 | Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | ||
264 | for location). You also want to check out the PCMCIA-HOWTO, | ||
265 | available from <http://www.tldp.org/docs.html#howto>. | ||
266 | |||
267 | You will also very likely also need the Wireless Tools in order to | ||
268 | configure your card and that /etc/pcmcia/wireless.opts works: | ||
269 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. | ||
270 | |||
271 | config AIRO_CS | ||
272 | tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" | ||
273 | depends on NET_RADIO && PCMCIA | ||
274 | ---help--- | ||
275 | This is the standard Linux driver to support Cisco/Aironet PCMCIA | ||
276 | 802.11 wireless cards. This driver is the same as the Aironet | ||
277 | driver part of the Linux Pcmcia package. | ||
278 | It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X | ||
279 | - with or without encryption) as well as card before the Cisco | ||
280 | aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also | ||
281 | supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom | ||
282 | 802.11b cards. | ||
283 | |||
284 | This driver support both the standard Linux Wireless Extensions | ||
285 | and Cisco proprietary API, so both the Linux Wireless Tools and the | ||
286 | Cisco Linux utilities can be used to configure the card. | ||
287 | |||
288 | To use your PC-cards, you will need supporting software from David | ||
289 | Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | ||
290 | for location). You also want to check out the PCMCIA-HOWTO, | ||
291 | available from <http://www.tldp.org/docs.html#howto>. | ||
292 | |||
293 | config PCMCIA_ATMEL | ||
294 | tristate "Atmel at76c502/at76c504 PCMCIA cards" | ||
295 | depends on NET_RADIO && ATMEL && PCMCIA | ||
296 | select FW_LOADER | ||
297 | select CRC32 | ||
298 | ---help--- | ||
299 | Enable support for PCMCIA cards containing the | ||
300 | Atmel at76c502 and at76c504 chips. | ||
301 | |||
302 | config PCMCIA_WL3501 | ||
303 | tristate "Planet WL3501 PCMCIA cards" | ||
304 | depends on NET_RADIO && EXPERIMENTAL && PCMCIA | ||
305 | ---help--- | ||
306 | A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. | ||
307 | It has basic support for Linux wireless extensions and initial | ||
308 | micro support for ethtool. | ||
309 | |||
310 | comment "Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support" | ||
311 | depends on NET_RADIO && PCI | ||
312 | config PRISM54 | ||
313 | tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' | ||
314 | depends on PCI && NET_RADIO && EXPERIMENTAL | ||
315 | select FW_LOADER | ||
316 | ---help--- | ||
317 | Enable PCI and Cardbus support for the following chipset based cards: | ||
318 | |||
319 | ISL3880 - Prism GT 802.11 b/g | ||
320 | ISL3877 - Prism Indigo 802.11 a | ||
321 | ISL3890 - Prism Duette 802.11 a/b/g | ||
322 | |||
323 | For a complete list of supported cards visit <http://prism54.org>. | ||
324 | Here is the latest confirmed list of supported cards: | ||
325 | |||
326 | 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 | ||
327 | Allnet ALL0271 PCI Card | ||
328 | Compex WL54G Cardbus Card | ||
329 | Corega CG-WLCB54GT Cardbus Card | ||
330 | D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 | ||
331 | I-O Data WN-G54/CB Cardbus Card | ||
332 | Kobishi XG-300 aka Z-Com Cardbus Card | ||
333 | Netgear WG511 Cardbus Card | ||
334 | Ovislink WL-5400PCI PCI Card | ||
335 | Peabird WLG-PCI PCI Card | ||
336 | Sitecom WL-100i Cardbus Card | ||
337 | Sitecom WL-110i PCI Card | ||
338 | SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card | ||
339 | SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card | ||
340 | SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card | ||
341 | Z-Com XG-900 PCI Card | ||
342 | Zyxel G-100 Cardbus Card | ||
343 | |||
344 | If you enable this you will need a firmware file as well. | ||
345 | You will need to copy this to /usr/lib/hotplug/firmware/isl3890. | ||
346 | You can get this non-GPL'd firmware file from the Prism54 project page: | ||
347 | <http://prism54.org> | ||
348 | You will also need the /etc/hotplug/firmware.agent script from | ||
349 | a current hotplug package. | ||
350 | |||
351 | Note: You need a motherboard with DMA support to use any of these cards | ||
352 | |||
353 | If you want to compile the driver as a module ( = code which can be | ||
354 | inserted in and removed from the running kernel whenever you want), | ||
355 | say M here and read <file:Documentation/modules.txt>. The module | ||
356 | will be called prism54.ko. | ||
357 | |||
358 | # yes, this works even when no drivers are selected | ||
359 | config NET_WIRELESS | ||
360 | bool | ||
361 | depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) | ||
362 | default y | ||
363 | |||
364 | endmenu | ||
365 | |||
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile new file mode 100644 index 000000000000..2b87841322cc --- /dev/null +++ b/drivers/net/wireless/Makefile | |||
@@ -0,0 +1,33 @@ | |||
1 | # | ||
2 | # Makefile for the Linux Wireless network device drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_STRIP) += strip.o | ||
6 | obj-$(CONFIG_ARLAN) += arlan.o | ||
7 | |||
8 | arlan-objs := arlan-main.o arlan-proc.o | ||
9 | |||
10 | # Obsolete cards | ||
11 | obj-$(CONFIG_WAVELAN) += wavelan.o | ||
12 | obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o | ||
13 | obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o | ||
14 | |||
15 | obj-$(CONFIG_HERMES) += orinoco.o hermes.o | ||
16 | obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o | ||
17 | obj-$(CONFIG_APPLE_AIRPORT) += airport.o | ||
18 | obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o | ||
19 | obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o | ||
20 | obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o | ||
21 | |||
22 | obj-$(CONFIG_AIRO) += airo.o | ||
23 | obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o | ||
24 | |||
25 | obj-$(CONFIG_ATMEL) += atmel.o | ||
26 | obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o | ||
27 | obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o | ||
28 | |||
29 | obj-$(CONFIG_PRISM54) += prism54/ | ||
30 | |||
31 | # 16-bit wireless PCMCIA client drivers | ||
32 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o | ||
33 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o | ||
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README new file mode 100644 index 000000000000..0c274bf6d45e --- /dev/null +++ b/drivers/net/wireless/README | |||
@@ -0,0 +1,25 @@ | |||
1 | README | ||
2 | ------ | ||
3 | |||
4 | This directory is mostly for Wireless LAN drivers, in their | ||
5 | various incarnations (ISA, PCI, Pcmcia...). | ||
6 | This separate directory is needed because a lot of driver work | ||
7 | on different bus (typically PCI + Pcmcia) and share 95% of the | ||
8 | code. This allow the code and the config options to be in one single | ||
9 | place instead of scattered all over the driver tree, which is never | ||
10 | 100% satisfactory. | ||
11 | |||
12 | Note : if you want more info on the topic of Wireless LANs, | ||
13 | you are kindly invited to have a look at the Wireless Howto : | ||
14 | http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ | ||
15 | Some Wireless LAN drivers, like orinoco_cs, require the use of | ||
16 | Wireless Tools to be configured : | ||
17 | http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html | ||
18 | |||
19 | Special notes for distribution maintainers : | ||
20 | 1) wvlan_cs will be discontinued soon in favor of orinoco_cs | ||
21 | 2) Please add Wireless Tools support in your scripts | ||
22 | |||
23 | Have fun... | ||
24 | |||
25 | Jean | ||
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c new file mode 100644 index 000000000000..2899144f2153 --- /dev/null +++ b/drivers/net/wireless/airo.c | |||
@@ -0,0 +1,7667 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Aironet driver for 4500 and 4800 series cards | ||
4 | |||
5 | This code is released under both the GPL version 2 and BSD licenses. | ||
6 | Either license may be used. The respective licenses are found at | ||
7 | the end of this file. | ||
8 | |||
9 | This code was developed by Benjamin Reed <breed@users.sourceforge.net> | ||
10 | including portions of which come from the Aironet PC4500 | ||
11 | Developer's Reference Manual and used with permission. Copyright | ||
12 | (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use | ||
13 | code in the Developer's manual was granted for this driver by | ||
14 | Aironet. Major code contributions were received from Javier Achirica | ||
15 | <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>. | ||
16 | Code was also integrated from the Cisco Aironet driver for Linux. | ||
17 | Support for MPI350 cards was added by Fabrice Bellet | ||
18 | <fabrice@bellet.info>. | ||
19 | |||
20 | ======================================================================*/ | ||
21 | |||
22 | #include <linux/config.h> | ||
23 | #include <linux/init.h> | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/proc_fs.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | |||
30 | #include <linux/sched.h> | ||
31 | #include <linux/ptrace.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/timer.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/in.h> | ||
37 | #include <linux/bitops.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <asm/system.h> | ||
40 | |||
41 | #include <linux/netdevice.h> | ||
42 | #include <linux/etherdevice.h> | ||
43 | #include <linux/skbuff.h> | ||
44 | #include <linux/if_arp.h> | ||
45 | #include <linux/ioport.h> | ||
46 | #include <linux/pci.h> | ||
47 | #include <asm/uaccess.h> | ||
48 | |||
49 | #ifdef CONFIG_PCI | ||
50 | static struct pci_device_id card_ids[] = { | ||
51 | { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, | ||
52 | { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, | ||
53 | { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, | ||
54 | { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, | ||
55 | { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, | ||
56 | { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, }, | ||
57 | { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, }, | ||
58 | { 0, } | ||
59 | }; | ||
60 | MODULE_DEVICE_TABLE(pci, card_ids); | ||
61 | |||
62 | static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); | ||
63 | static void airo_pci_remove(struct pci_dev *); | ||
64 | static int airo_pci_suspend(struct pci_dev *pdev, u32 state); | ||
65 | static int airo_pci_resume(struct pci_dev *pdev); | ||
66 | |||
67 | static struct pci_driver airo_driver = { | ||
68 | .name = "airo", | ||
69 | .id_table = card_ids, | ||
70 | .probe = airo_pci_probe, | ||
71 | .remove = __devexit_p(airo_pci_remove), | ||
72 | .suspend = airo_pci_suspend, | ||
73 | .resume = airo_pci_resume, | ||
74 | }; | ||
75 | #endif /* CONFIG_PCI */ | ||
76 | |||
77 | /* Include Wireless Extension definition and check version - Jean II */ | ||
78 | #include <linux/wireless.h> | ||
79 | #define WIRELESS_SPY // enable iwspy support | ||
80 | #include <net/iw_handler.h> // New driver API | ||
81 | |||
82 | #define CISCO_EXT // enable Cisco extensions | ||
83 | #ifdef CISCO_EXT | ||
84 | #include <linux/delay.h> | ||
85 | #endif | ||
86 | |||
87 | /* Support Cisco MIC feature */ | ||
88 | #define MICSUPPORT | ||
89 | |||
90 | #if defined(MICSUPPORT) && !defined(CONFIG_CRYPTO) | ||
91 | #warning MIC support requires Crypto API | ||
92 | #undef MICSUPPORT | ||
93 | #endif | ||
94 | |||
95 | /* Hack to do some power saving */ | ||
96 | #define POWER_ON_DOWN | ||
97 | |||
98 | /* As you can see this list is HUGH! | ||
99 | I really don't know what a lot of these counts are about, but they | ||
100 | are all here for completeness. If the IGNLABEL macro is put in | ||
101 | infront of the label, that statistic will not be included in the list | ||
102 | of statistics in the /proc filesystem */ | ||
103 | |||
104 | #define IGNLABEL(comment) NULL | ||
105 | static char *statsLabels[] = { | ||
106 | "RxOverrun", | ||
107 | IGNLABEL("RxPlcpCrcErr"), | ||
108 | IGNLABEL("RxPlcpFormatErr"), | ||
109 | IGNLABEL("RxPlcpLengthErr"), | ||
110 | "RxMacCrcErr", | ||
111 | "RxMacCrcOk", | ||
112 | "RxWepErr", | ||
113 | "RxWepOk", | ||
114 | "RetryLong", | ||
115 | "RetryShort", | ||
116 | "MaxRetries", | ||
117 | "NoAck", | ||
118 | "NoCts", | ||
119 | "RxAck", | ||
120 | "RxCts", | ||
121 | "TxAck", | ||
122 | "TxRts", | ||
123 | "TxCts", | ||
124 | "TxMc", | ||
125 | "TxBc", | ||
126 | "TxUcFrags", | ||
127 | "TxUcPackets", | ||
128 | "TxBeacon", | ||
129 | "RxBeacon", | ||
130 | "TxSinColl", | ||
131 | "TxMulColl", | ||
132 | "DefersNo", | ||
133 | "DefersProt", | ||
134 | "DefersEngy", | ||
135 | "DupFram", | ||
136 | "RxFragDisc", | ||
137 | "TxAged", | ||
138 | "RxAged", | ||
139 | "LostSync-MaxRetry", | ||
140 | "LostSync-MissedBeacons", | ||
141 | "LostSync-ArlExceeded", | ||
142 | "LostSync-Deauth", | ||
143 | "LostSync-Disassoced", | ||
144 | "LostSync-TsfTiming", | ||
145 | "HostTxMc", | ||
146 | "HostTxBc", | ||
147 | "HostTxUc", | ||
148 | "HostTxFail", | ||
149 | "HostRxMc", | ||
150 | "HostRxBc", | ||
151 | "HostRxUc", | ||
152 | "HostRxDiscard", | ||
153 | IGNLABEL("HmacTxMc"), | ||
154 | IGNLABEL("HmacTxBc"), | ||
155 | IGNLABEL("HmacTxUc"), | ||
156 | IGNLABEL("HmacTxFail"), | ||
157 | IGNLABEL("HmacRxMc"), | ||
158 | IGNLABEL("HmacRxBc"), | ||
159 | IGNLABEL("HmacRxUc"), | ||
160 | IGNLABEL("HmacRxDiscard"), | ||
161 | IGNLABEL("HmacRxAccepted"), | ||
162 | "SsidMismatch", | ||
163 | "ApMismatch", | ||
164 | "RatesMismatch", | ||
165 | "AuthReject", | ||
166 | "AuthTimeout", | ||
167 | "AssocReject", | ||
168 | "AssocTimeout", | ||
169 | IGNLABEL("ReasonOutsideTable"), | ||
170 | IGNLABEL("ReasonStatus1"), | ||
171 | IGNLABEL("ReasonStatus2"), | ||
172 | IGNLABEL("ReasonStatus3"), | ||
173 | IGNLABEL("ReasonStatus4"), | ||
174 | IGNLABEL("ReasonStatus5"), | ||
175 | IGNLABEL("ReasonStatus6"), | ||
176 | IGNLABEL("ReasonStatus7"), | ||
177 | IGNLABEL("ReasonStatus8"), | ||
178 | IGNLABEL("ReasonStatus9"), | ||
179 | IGNLABEL("ReasonStatus10"), | ||
180 | IGNLABEL("ReasonStatus11"), | ||
181 | IGNLABEL("ReasonStatus12"), | ||
182 | IGNLABEL("ReasonStatus13"), | ||
183 | IGNLABEL("ReasonStatus14"), | ||
184 | IGNLABEL("ReasonStatus15"), | ||
185 | IGNLABEL("ReasonStatus16"), | ||
186 | IGNLABEL("ReasonStatus17"), | ||
187 | IGNLABEL("ReasonStatus18"), | ||
188 | IGNLABEL("ReasonStatus19"), | ||
189 | "RxMan", | ||
190 | "TxMan", | ||
191 | "RxRefresh", | ||
192 | "TxRefresh", | ||
193 | "RxPoll", | ||
194 | "TxPoll", | ||
195 | "HostRetries", | ||
196 | "LostSync-HostReq", | ||
197 | "HostTxBytes", | ||
198 | "HostRxBytes", | ||
199 | "ElapsedUsec", | ||
200 | "ElapsedSec", | ||
201 | "LostSyncBetterAP", | ||
202 | "PrivacyMismatch", | ||
203 | "Jammed", | ||
204 | "DiscRxNotWepped", | ||
205 | "PhyEleMismatch", | ||
206 | (char*)-1 }; | ||
207 | #ifndef RUN_AT | ||
208 | #define RUN_AT(x) (jiffies+(x)) | ||
209 | #endif | ||
210 | |||
211 | |||
212 | /* These variables are for insmod, since it seems that the rates | ||
213 | can only be set in setup_card. Rates should be a comma separated | ||
214 | (no spaces) list of rates (up to 8). */ | ||
215 | |||
216 | static int rates[8]; | ||
217 | static int basic_rate; | ||
218 | static char *ssids[3]; | ||
219 | |||
220 | static int io[4]; | ||
221 | static int irq[4]; | ||
222 | |||
223 | static | ||
224 | int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at. | ||
225 | 0 means no limit. For old cards this was 4 */ | ||
226 | |||
227 | static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */ | ||
228 | static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read | ||
229 | the bap, needed on some older cards and buses. */ | ||
230 | static int adhoc; | ||
231 | |||
232 | static int probe = 1; | ||
233 | |||
234 | static int proc_uid /* = 0 */; | ||
235 | |||
236 | static int proc_gid /* = 0 */; | ||
237 | |||
238 | static int airo_perm = 0555; | ||
239 | |||
240 | static int proc_perm = 0644; | ||
241 | |||
242 | MODULE_AUTHOR("Benjamin Reed"); | ||
243 | MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ | ||
244 | cards. Direct support for ISA/PCI/MPI cards and support \ | ||
245 | for PCMCIA when used with airo_cs."); | ||
246 | MODULE_LICENSE("Dual BSD/GPL"); | ||
247 | MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350"); | ||
248 | module_param_array(io, int, NULL, 0); | ||
249 | module_param_array(irq, int, NULL, 0); | ||
250 | module_param(basic_rate, int, 0); | ||
251 | module_param_array(rates, int, NULL, 0); | ||
252 | module_param_array(ssids, charp, NULL, 0); | ||
253 | module_param(auto_wep, int, 0); | ||
254 | MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \ | ||
255 | the authentication options until an association is made. The value of \ | ||
256 | auto_wep is number of the wep keys to check. A value of 2 will try using \ | ||
257 | the key at index 0 and index 1."); | ||
258 | module_param(aux_bap, int, 0); | ||
259 | MODULE_PARM_DESC(aux_bap, "If non-zero, the driver will switch into a mode \ | ||
260 | than seems to work better for older cards with some older buses. Before \ | ||
261 | switching it checks that the switch is needed."); | ||
262 | module_param(maxencrypt, int, 0); | ||
263 | MODULE_PARM_DESC(maxencrypt, "The maximum speed that the card can do \ | ||
264 | encryption. Units are in 512kbs. Zero (default) means there is no limit. \ | ||
265 | Older cards used to be limited to 2mbs (4)."); | ||
266 | module_param(adhoc, int, 0); | ||
267 | MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); | ||
268 | module_param(probe, int, 0); | ||
269 | MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); | ||
270 | |||
271 | module_param(proc_uid, int, 0); | ||
272 | MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); | ||
273 | module_param(proc_gid, int, 0); | ||
274 | MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); | ||
275 | module_param(airo_perm, int, 0); | ||
276 | MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); | ||
277 | module_param(proc_perm, int, 0); | ||
278 | MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); | ||
279 | |||
280 | /* This is a kind of sloppy hack to get this information to OUT4500 and | ||
281 | IN4500. I would be extremely interested in the situation where this | ||
282 | doesn't work though!!! */ | ||
283 | static int do8bitIO = 0; | ||
284 | |||
285 | /* Return codes */ | ||
286 | #define SUCCESS 0 | ||
287 | #define ERROR -1 | ||
288 | #define NO_PACKET -2 | ||
289 | |||
290 | /* Commands */ | ||
291 | #define NOP2 0x0000 | ||
292 | #define MAC_ENABLE 0x0001 | ||
293 | #define MAC_DISABLE 0x0002 | ||
294 | #define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ | ||
295 | #define CMD_SOFTRESET 0x0004 | ||
296 | #define HOSTSLEEP 0x0005 | ||
297 | #define CMD_MAGIC_PKT 0x0006 | ||
298 | #define CMD_SETWAKEMASK 0x0007 | ||
299 | #define CMD_READCFG 0x0008 | ||
300 | #define CMD_SETMODE 0x0009 | ||
301 | #define CMD_ALLOCATETX 0x000a | ||
302 | #define CMD_TRANSMIT 0x000b | ||
303 | #define CMD_DEALLOCATETX 0x000c | ||
304 | #define NOP 0x0010 | ||
305 | #define CMD_WORKAROUND 0x0011 | ||
306 | #define CMD_ALLOCATEAUX 0x0020 | ||
307 | #define CMD_ACCESS 0x0021 | ||
308 | #define CMD_PCIBAP 0x0022 | ||
309 | #define CMD_PCIAUX 0x0023 | ||
310 | #define CMD_ALLOCBUF 0x0028 | ||
311 | #define CMD_GETTLV 0x0029 | ||
312 | #define CMD_PUTTLV 0x002a | ||
313 | #define CMD_DELTLV 0x002b | ||
314 | #define CMD_FINDNEXTTLV 0x002c | ||
315 | #define CMD_PSPNODES 0x0030 | ||
316 | #define CMD_SETCW 0x0031 | ||
317 | #define CMD_SETPCF 0x0032 | ||
318 | #define CMD_SETPHYREG 0x003e | ||
319 | #define CMD_TXTEST 0x003f | ||
320 | #define MAC_ENABLETX 0x0101 | ||
321 | #define CMD_LISTBSS 0x0103 | ||
322 | #define CMD_SAVECFG 0x0108 | ||
323 | #define CMD_ENABLEAUX 0x0111 | ||
324 | #define CMD_WRITERID 0x0121 | ||
325 | #define CMD_USEPSPNODES 0x0130 | ||
326 | #define MAC_ENABLERX 0x0201 | ||
327 | |||
328 | /* Command errors */ | ||
329 | #define ERROR_QUALIF 0x00 | ||
330 | #define ERROR_ILLCMD 0x01 | ||
331 | #define ERROR_ILLFMT 0x02 | ||
332 | #define ERROR_INVFID 0x03 | ||
333 | #define ERROR_INVRID 0x04 | ||
334 | #define ERROR_LARGE 0x05 | ||
335 | #define ERROR_NDISABL 0x06 | ||
336 | #define ERROR_ALLOCBSY 0x07 | ||
337 | #define ERROR_NORD 0x0B | ||
338 | #define ERROR_NOWR 0x0C | ||
339 | #define ERROR_INVFIDTX 0x0D | ||
340 | #define ERROR_TESTACT 0x0E | ||
341 | #define ERROR_TAGNFND 0x12 | ||
342 | #define ERROR_DECODE 0x20 | ||
343 | #define ERROR_DESCUNAV 0x21 | ||
344 | #define ERROR_BADLEN 0x22 | ||
345 | #define ERROR_MODE 0x80 | ||
346 | #define ERROR_HOP 0x81 | ||
347 | #define ERROR_BINTER 0x82 | ||
348 | #define ERROR_RXMODE 0x83 | ||
349 | #define ERROR_MACADDR 0x84 | ||
350 | #define ERROR_RATES 0x85 | ||
351 | #define ERROR_ORDER 0x86 | ||
352 | #define ERROR_SCAN 0x87 | ||
353 | #define ERROR_AUTH 0x88 | ||
354 | #define ERROR_PSMODE 0x89 | ||
355 | #define ERROR_RTYPE 0x8A | ||
356 | #define ERROR_DIVER 0x8B | ||
357 | #define ERROR_SSID 0x8C | ||
358 | #define ERROR_APLIST 0x8D | ||
359 | #define ERROR_AUTOWAKE 0x8E | ||
360 | #define ERROR_LEAP 0x8F | ||
361 | |||
362 | /* Registers */ | ||
363 | #define COMMAND 0x00 | ||
364 | #define PARAM0 0x02 | ||
365 | #define PARAM1 0x04 | ||
366 | #define PARAM2 0x06 | ||
367 | #define STATUS 0x08 | ||
368 | #define RESP0 0x0a | ||
369 | #define RESP1 0x0c | ||
370 | #define RESP2 0x0e | ||
371 | #define LINKSTAT 0x10 | ||
372 | #define SELECT0 0x18 | ||
373 | #define OFFSET0 0x1c | ||
374 | #define RXFID 0x20 | ||
375 | #define TXALLOCFID 0x22 | ||
376 | #define TXCOMPLFID 0x24 | ||
377 | #define DATA0 0x36 | ||
378 | #define EVSTAT 0x30 | ||
379 | #define EVINTEN 0x32 | ||
380 | #define EVACK 0x34 | ||
381 | #define SWS0 0x28 | ||
382 | #define SWS1 0x2a | ||
383 | #define SWS2 0x2c | ||
384 | #define SWS3 0x2e | ||
385 | #define AUXPAGE 0x3A | ||
386 | #define AUXOFF 0x3C | ||
387 | #define AUXDATA 0x3E | ||
388 | |||
389 | #define FID_TX 1 | ||
390 | #define FID_RX 2 | ||
391 | /* Offset into aux memory for descriptors */ | ||
392 | #define AUX_OFFSET 0x800 | ||
393 | /* Size of allocated packets */ | ||
394 | #define PKTSIZE 1840 | ||
395 | #define RIDSIZE 2048 | ||
396 | /* Size of the transmit queue */ | ||
397 | #define MAXTXQ 64 | ||
398 | |||
399 | /* BAP selectors */ | ||
400 | #define BAP0 0 // Used for receiving packets | ||
401 | #define BAP1 2 // Used for xmiting packets and working with RIDS | ||
402 | |||
403 | /* Flags */ | ||
404 | #define COMMAND_BUSY 0x8000 | ||
405 | |||
406 | #define BAP_BUSY 0x8000 | ||
407 | #define BAP_ERR 0x4000 | ||
408 | #define BAP_DONE 0x2000 | ||
409 | |||
410 | #define PROMISC 0xffff | ||
411 | #define NOPROMISC 0x0000 | ||
412 | |||
413 | #define EV_CMD 0x10 | ||
414 | #define EV_CLEARCOMMANDBUSY 0x4000 | ||
415 | #define EV_RX 0x01 | ||
416 | #define EV_TX 0x02 | ||
417 | #define EV_TXEXC 0x04 | ||
418 | #define EV_ALLOC 0x08 | ||
419 | #define EV_LINK 0x80 | ||
420 | #define EV_AWAKE 0x100 | ||
421 | #define EV_TXCPY 0x400 | ||
422 | #define EV_UNKNOWN 0x800 | ||
423 | #define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ | ||
424 | #define EV_AWAKEN 0x2000 | ||
425 | #define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC) | ||
426 | |||
427 | #ifdef CHECK_UNKNOWN_INTS | ||
428 | #define IGNORE_INTS ( EV_CMD | EV_UNKNOWN) | ||
429 | #else | ||
430 | #define IGNORE_INTS (~STATUS_INTS) | ||
431 | #endif | ||
432 | |||
433 | /* RID TYPES */ | ||
434 | #define RID_RW 0x20 | ||
435 | |||
436 | /* The RIDs */ | ||
437 | #define RID_CAPABILITIES 0xFF00 | ||
438 | #define RID_APINFO 0xFF01 | ||
439 | #define RID_RADIOINFO 0xFF02 | ||
440 | #define RID_UNKNOWN3 0xFF03 | ||
441 | #define RID_RSSI 0xFF04 | ||
442 | #define RID_CONFIG 0xFF10 | ||
443 | #define RID_SSID 0xFF11 | ||
444 | #define RID_APLIST 0xFF12 | ||
445 | #define RID_DRVNAME 0xFF13 | ||
446 | #define RID_ETHERENCAP 0xFF14 | ||
447 | #define RID_WEP_TEMP 0xFF15 | ||
448 | #define RID_WEP_PERM 0xFF16 | ||
449 | #define RID_MODULATION 0xFF17 | ||
450 | #define RID_OPTIONS 0xFF18 | ||
451 | #define RID_ACTUALCONFIG 0xFF20 /*readonly*/ | ||
452 | #define RID_FACTORYCONFIG 0xFF21 | ||
453 | #define RID_UNKNOWN22 0xFF22 | ||
454 | #define RID_LEAPUSERNAME 0xFF23 | ||
455 | #define RID_LEAPPASSWORD 0xFF24 | ||
456 | #define RID_STATUS 0xFF50 | ||
457 | #define RID_BEACON_HST 0xFF51 | ||
458 | #define RID_BUSY_HST 0xFF52 | ||
459 | #define RID_RETRIES_HST 0xFF53 | ||
460 | #define RID_UNKNOWN54 0xFF54 | ||
461 | #define RID_UNKNOWN55 0xFF55 | ||
462 | #define RID_UNKNOWN56 0xFF56 | ||
463 | #define RID_MIC 0xFF57 | ||
464 | #define RID_STATS16 0xFF60 | ||
465 | #define RID_STATS16DELTA 0xFF61 | ||
466 | #define RID_STATS16DELTACLEAR 0xFF62 | ||
467 | #define RID_STATS 0xFF68 | ||
468 | #define RID_STATSDELTA 0xFF69 | ||
469 | #define RID_STATSDELTACLEAR 0xFF6A | ||
470 | #define RID_ECHOTEST_RID 0xFF70 | ||
471 | #define RID_ECHOTEST_RESULTS 0xFF71 | ||
472 | #define RID_BSSLISTFIRST 0xFF72 | ||
473 | #define RID_BSSLISTNEXT 0xFF73 | ||
474 | |||
475 | typedef struct { | ||
476 | u16 cmd; | ||
477 | u16 parm0; | ||
478 | u16 parm1; | ||
479 | u16 parm2; | ||
480 | } Cmd; | ||
481 | |||
482 | typedef struct { | ||
483 | u16 status; | ||
484 | u16 rsp0; | ||
485 | u16 rsp1; | ||
486 | u16 rsp2; | ||
487 | } Resp; | ||
488 | |||
489 | /* | ||
490 | * Rids and endian-ness: The Rids will always be in cpu endian, since | ||
491 | * this all the patches from the big-endian guys end up doing that. | ||
492 | * so all rid access should use the read/writeXXXRid routines. | ||
493 | */ | ||
494 | |||
495 | /* This is redundant for x86 archs, but it seems necessary for ARM */ | ||
496 | #pragma pack(1) | ||
497 | |||
498 | /* This structure came from an email sent to me from an engineer at | ||
499 | aironet for inclusion into this driver */ | ||
500 | typedef struct { | ||
501 | u16 len; | ||
502 | u16 kindex; | ||
503 | u8 mac[ETH_ALEN]; | ||
504 | u16 klen; | ||
505 | u8 key[16]; | ||
506 | } WepKeyRid; | ||
507 | |||
508 | /* These structures are from the Aironet's PC4500 Developers Manual */ | ||
509 | typedef struct { | ||
510 | u16 len; | ||
511 | u8 ssid[32]; | ||
512 | } Ssid; | ||
513 | |||
514 | typedef struct { | ||
515 | u16 len; | ||
516 | Ssid ssids[3]; | ||
517 | } SsidRid; | ||
518 | |||
519 | typedef struct { | ||
520 | u16 len; | ||
521 | u16 modulation; | ||
522 | #define MOD_DEFAULT 0 | ||
523 | #define MOD_CCK 1 | ||
524 | #define MOD_MOK 2 | ||
525 | } ModulationRid; | ||
526 | |||
527 | typedef struct { | ||
528 | u16 len; /* sizeof(ConfigRid) */ | ||
529 | u16 opmode; /* operating mode */ | ||
530 | #define MODE_STA_IBSS 0 | ||
531 | #define MODE_STA_ESS 1 | ||
532 | #define MODE_AP 2 | ||
533 | #define MODE_AP_RPTR 3 | ||
534 | #define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */ | ||
535 | #define MODE_LLC_HOST (1<<8) /* rx payloads left as is */ | ||
536 | #define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */ | ||
537 | #define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */ | ||
538 | #define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */ | ||
539 | #define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */ | ||
540 | #define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */ | ||
541 | #define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */ | ||
542 | #define MODE_MIC (1<<15) /* enable MIC */ | ||
543 | u16 rmode; /* receive mode */ | ||
544 | #define RXMODE_BC_MC_ADDR 0 | ||
545 | #define RXMODE_BC_ADDR 1 /* ignore multicasts */ | ||
546 | #define RXMODE_ADDR 2 /* ignore multicast and broadcast */ | ||
547 | #define RXMODE_RFMON 3 /* wireless monitor mode */ | ||
548 | #define RXMODE_RFMON_ANYBSS 4 | ||
549 | #define RXMODE_LANMON 5 /* lan style monitor -- data packets only */ | ||
550 | #define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */ | ||
551 | #define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */ | ||
552 | u16 fragThresh; | ||
553 | u16 rtsThres; | ||
554 | u8 macAddr[ETH_ALEN]; | ||
555 | u8 rates[8]; | ||
556 | u16 shortRetryLimit; | ||
557 | u16 longRetryLimit; | ||
558 | u16 txLifetime; /* in kusec */ | ||
559 | u16 rxLifetime; /* in kusec */ | ||
560 | u16 stationary; | ||
561 | u16 ordering; | ||
562 | u16 u16deviceType; /* for overriding device type */ | ||
563 | u16 cfpRate; | ||
564 | u16 cfpDuration; | ||
565 | u16 _reserved1[3]; | ||
566 | /*---------- Scanning/Associating ----------*/ | ||
567 | u16 scanMode; | ||
568 | #define SCANMODE_ACTIVE 0 | ||
569 | #define SCANMODE_PASSIVE 1 | ||
570 | #define SCANMODE_AIROSCAN 2 | ||
571 | u16 probeDelay; /* in kusec */ | ||
572 | u16 probeEnergyTimeout; /* in kusec */ | ||
573 | u16 probeResponseTimeout; | ||
574 | u16 beaconListenTimeout; | ||
575 | u16 joinNetTimeout; | ||
576 | u16 authTimeout; | ||
577 | u16 authType; | ||
578 | #define AUTH_OPEN 0x1 | ||
579 | #define AUTH_ENCRYPT 0x101 | ||
580 | #define AUTH_SHAREDKEY 0x102 | ||
581 | #define AUTH_ALLOW_UNENCRYPTED 0x200 | ||
582 | u16 associationTimeout; | ||
583 | u16 specifiedApTimeout; | ||
584 | u16 offlineScanInterval; | ||
585 | u16 offlineScanDuration; | ||
586 | u16 linkLossDelay; | ||
587 | u16 maxBeaconLostTime; | ||
588 | u16 refreshInterval; | ||
589 | #define DISABLE_REFRESH 0xFFFF | ||
590 | u16 _reserved1a[1]; | ||
591 | /*---------- Power save operation ----------*/ | ||
592 | u16 powerSaveMode; | ||
593 | #define POWERSAVE_CAM 0 | ||
594 | #define POWERSAVE_PSP 1 | ||
595 | #define POWERSAVE_PSPCAM 2 | ||
596 | u16 sleepForDtims; | ||
597 | u16 listenInterval; | ||
598 | u16 fastListenInterval; | ||
599 | u16 listenDecay; | ||
600 | u16 fastListenDelay; | ||
601 | u16 _reserved2[2]; | ||
602 | /*---------- Ap/Ibss config items ----------*/ | ||
603 | u16 beaconPeriod; | ||
604 | u16 atimDuration; | ||
605 | u16 hopPeriod; | ||
606 | u16 channelSet; | ||
607 | u16 channel; | ||
608 | u16 dtimPeriod; | ||
609 | u16 bridgeDistance; | ||
610 | u16 radioID; | ||
611 | /*---------- Radio configuration ----------*/ | ||
612 | u16 radioType; | ||
613 | #define RADIOTYPE_DEFAULT 0 | ||
614 | #define RADIOTYPE_802_11 1 | ||
615 | #define RADIOTYPE_LEGACY 2 | ||
616 | u8 rxDiversity; | ||
617 | u8 txDiversity; | ||
618 | u16 txPower; | ||
619 | #define TXPOWER_DEFAULT 0 | ||
620 | u16 rssiThreshold; | ||
621 | #define RSSI_DEFAULT 0 | ||
622 | u16 modulation; | ||
623 | #define PREAMBLE_AUTO 0 | ||
624 | #define PREAMBLE_LONG 1 | ||
625 | #define PREAMBLE_SHORT 2 | ||
626 | u16 preamble; | ||
627 | u16 homeProduct; | ||
628 | u16 radioSpecific; | ||
629 | /*---------- Aironet Extensions ----------*/ | ||
630 | u8 nodeName[16]; | ||
631 | u16 arlThreshold; | ||
632 | u16 arlDecay; | ||
633 | u16 arlDelay; | ||
634 | u16 _reserved4[1]; | ||
635 | /*---------- Aironet Extensions ----------*/ | ||
636 | u8 magicAction; | ||
637 | #define MAGIC_ACTION_STSCHG 1 | ||
638 | #define MAGIC_ACTION_RESUME 2 | ||
639 | #define MAGIC_IGNORE_MCAST (1<<8) | ||
640 | #define MAGIC_IGNORE_BCAST (1<<9) | ||
641 | #define MAGIC_SWITCH_TO_PSP (0<<10) | ||
642 | #define MAGIC_STAY_IN_CAM (1<<10) | ||
643 | u8 magicControl; | ||
644 | u16 autoWake; | ||
645 | } ConfigRid; | ||
646 | |||
647 | typedef struct { | ||
648 | u16 len; | ||
649 | u8 mac[ETH_ALEN]; | ||
650 | u16 mode; | ||
651 | u16 errorCode; | ||
652 | u16 sigQuality; | ||
653 | u16 SSIDlen; | ||
654 | char SSID[32]; | ||
655 | char apName[16]; | ||
656 | u8 bssid[4][ETH_ALEN]; | ||
657 | u16 beaconPeriod; | ||
658 | u16 dimPeriod; | ||
659 | u16 atimDuration; | ||
660 | u16 hopPeriod; | ||
661 | u16 channelSet; | ||
662 | u16 channel; | ||
663 | u16 hopsToBackbone; | ||
664 | u16 apTotalLoad; | ||
665 | u16 generatedLoad; | ||
666 | u16 accumulatedArl; | ||
667 | u16 signalQuality; | ||
668 | u16 currentXmitRate; | ||
669 | u16 apDevExtensions; | ||
670 | u16 normalizedSignalStrength; | ||
671 | u16 shortPreamble; | ||
672 | u8 apIP[4]; | ||
673 | u8 noisePercent; /* Noise percent in last second */ | ||
674 | u8 noisedBm; /* Noise dBm in last second */ | ||
675 | u8 noiseAvePercent; /* Noise percent in last minute */ | ||
676 | u8 noiseAvedBm; /* Noise dBm in last minute */ | ||
677 | u8 noiseMaxPercent; /* Highest noise percent in last minute */ | ||
678 | u8 noiseMaxdBm; /* Highest noise dbm in last minute */ | ||
679 | u16 load; | ||
680 | u8 carrier[4]; | ||
681 | u16 assocStatus; | ||
682 | #define STAT_NOPACKETS 0 | ||
683 | #define STAT_NOCARRIERSET 10 | ||
684 | #define STAT_GOTCARRIERSET 11 | ||
685 | #define STAT_WRONGSSID 20 | ||
686 | #define STAT_BADCHANNEL 25 | ||
687 | #define STAT_BADBITRATES 30 | ||
688 | #define STAT_BADPRIVACY 35 | ||
689 | #define STAT_APFOUND 40 | ||
690 | #define STAT_APREJECTED 50 | ||
691 | #define STAT_AUTHENTICATING 60 | ||
692 | #define STAT_DEAUTHENTICATED 61 | ||
693 | #define STAT_AUTHTIMEOUT 62 | ||
694 | #define STAT_ASSOCIATING 70 | ||
695 | #define STAT_DEASSOCIATED 71 | ||
696 | #define STAT_ASSOCTIMEOUT 72 | ||
697 | #define STAT_NOTAIROAP 73 | ||
698 | #define STAT_ASSOCIATED 80 | ||
699 | #define STAT_LEAPING 90 | ||
700 | #define STAT_LEAPFAILED 91 | ||
701 | #define STAT_LEAPTIMEDOUT 92 | ||
702 | #define STAT_LEAPCOMPLETE 93 | ||
703 | } StatusRid; | ||
704 | |||
705 | typedef struct { | ||
706 | u16 len; | ||
707 | u16 spacer; | ||
708 | u32 vals[100]; | ||
709 | } StatsRid; | ||
710 | |||
711 | |||
712 | typedef struct { | ||
713 | u16 len; | ||
714 | u8 ap[4][ETH_ALEN]; | ||
715 | } APListRid; | ||
716 | |||
717 | typedef struct { | ||
718 | u16 len; | ||
719 | char oui[3]; | ||
720 | char zero; | ||
721 | u16 prodNum; | ||
722 | char manName[32]; | ||
723 | char prodName[16]; | ||
724 | char prodVer[8]; | ||
725 | char factoryAddr[ETH_ALEN]; | ||
726 | char aironetAddr[ETH_ALEN]; | ||
727 | u16 radioType; | ||
728 | u16 country; | ||
729 | char callid[ETH_ALEN]; | ||
730 | char supportedRates[8]; | ||
731 | char rxDiversity; | ||
732 | char txDiversity; | ||
733 | u16 txPowerLevels[8]; | ||
734 | u16 hardVer; | ||
735 | u16 hardCap; | ||
736 | u16 tempRange; | ||
737 | u16 softVer; | ||
738 | u16 softSubVer; | ||
739 | u16 interfaceVer; | ||
740 | u16 softCap; | ||
741 | u16 bootBlockVer; | ||
742 | u16 requiredHard; | ||
743 | u16 extSoftCap; | ||
744 | } CapabilityRid; | ||
745 | |||
746 | typedef struct { | ||
747 | u16 len; | ||
748 | u16 index; /* First is 0 and 0xffff means end of list */ | ||
749 | #define RADIO_FH 1 /* Frequency hopping radio type */ | ||
750 | #define RADIO_DS 2 /* Direct sequence radio type */ | ||
751 | #define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ | ||
752 | u16 radioType; | ||
753 | u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ | ||
754 | u8 zero; | ||
755 | u8 ssidLen; | ||
756 | u8 ssid[32]; | ||
757 | u16 rssi; | ||
758 | #define CAP_ESS (1<<0) | ||
759 | #define CAP_IBSS (1<<1) | ||
760 | #define CAP_PRIVACY (1<<4) | ||
761 | #define CAP_SHORTHDR (1<<5) | ||
762 | u16 cap; | ||
763 | u16 beaconInterval; | ||
764 | u8 rates[8]; /* Same as rates for config rid */ | ||
765 | struct { /* For frequency hopping only */ | ||
766 | u16 dwell; | ||
767 | u8 hopSet; | ||
768 | u8 hopPattern; | ||
769 | u8 hopIndex; | ||
770 | u8 fill; | ||
771 | } fh; | ||
772 | u16 dsChannel; | ||
773 | u16 atimWindow; | ||
774 | } BSSListRid; | ||
775 | |||
776 | typedef struct { | ||
777 | u8 rssipct; | ||
778 | u8 rssidBm; | ||
779 | } tdsRssiEntry; | ||
780 | |||
781 | typedef struct { | ||
782 | u16 len; | ||
783 | tdsRssiEntry x[256]; | ||
784 | } tdsRssiRid; | ||
785 | |||
786 | typedef struct { | ||
787 | u16 len; | ||
788 | u16 state; | ||
789 | u16 multicastValid; | ||
790 | u8 multicast[16]; | ||
791 | u16 unicastValid; | ||
792 | u8 unicast[16]; | ||
793 | } MICRid; | ||
794 | |||
795 | typedef struct { | ||
796 | u16 typelen; | ||
797 | |||
798 | union { | ||
799 | u8 snap[8]; | ||
800 | struct { | ||
801 | u8 dsap; | ||
802 | u8 ssap; | ||
803 | u8 control; | ||
804 | u8 orgcode[3]; | ||
805 | u8 fieldtype[2]; | ||
806 | } llc; | ||
807 | } u; | ||
808 | u32 mic; | ||
809 | u32 seq; | ||
810 | } MICBuffer; | ||
811 | |||
812 | typedef struct { | ||
813 | u8 da[ETH_ALEN]; | ||
814 | u8 sa[ETH_ALEN]; | ||
815 | } etherHead; | ||
816 | |||
817 | #pragma pack() | ||
818 | |||
819 | #define TXCTL_TXOK (1<<1) /* report if tx is ok */ | ||
820 | #define TXCTL_TXEX (1<<2) /* report if tx fails */ | ||
821 | #define TXCTL_802_3 (0<<3) /* 802.3 packet */ | ||
822 | #define TXCTL_802_11 (1<<3) /* 802.11 mac packet */ | ||
823 | #define TXCTL_ETHERNET (0<<4) /* payload has ethertype */ | ||
824 | #define TXCTL_LLC (1<<4) /* payload is llc */ | ||
825 | #define TXCTL_RELEASE (0<<5) /* release after completion */ | ||
826 | #define TXCTL_NORELEASE (1<<5) /* on completion returns to host */ | ||
827 | |||
828 | #define BUSY_FID 0x10000 | ||
829 | |||
830 | #ifdef CISCO_EXT | ||
831 | #define AIROMAGIC 0xa55a | ||
832 | /* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */ | ||
833 | #ifdef SIOCIWFIRSTPRIV | ||
834 | #ifdef SIOCDEVPRIVATE | ||
835 | #define AIROOLDIOCTL SIOCDEVPRIVATE | ||
836 | #define AIROOLDIDIFC AIROOLDIOCTL + 1 | ||
837 | #endif /* SIOCDEVPRIVATE */ | ||
838 | #else /* SIOCIWFIRSTPRIV */ | ||
839 | #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE | ||
840 | #endif /* SIOCIWFIRSTPRIV */ | ||
841 | /* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably | ||
842 | * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root | ||
843 | * only and don't return the modified struct ifreq to the application which | ||
844 | * is usually a problem. - Jean II */ | ||
845 | #define AIROIOCTL SIOCIWFIRSTPRIV | ||
846 | #define AIROIDIFC AIROIOCTL + 1 | ||
847 | |||
848 | /* Ioctl constants to be used in airo_ioctl.command */ | ||
849 | |||
850 | #define AIROGCAP 0 // Capability rid | ||
851 | #define AIROGCFG 1 // USED A LOT | ||
852 | #define AIROGSLIST 2 // System ID list | ||
853 | #define AIROGVLIST 3 // List of specified AP's | ||
854 | #define AIROGDRVNAM 4 // NOTUSED | ||
855 | #define AIROGEHTENC 5 // NOTUSED | ||
856 | #define AIROGWEPKTMP 6 | ||
857 | #define AIROGWEPKNV 7 | ||
858 | #define AIROGSTAT 8 | ||
859 | #define AIROGSTATSC32 9 | ||
860 | #define AIROGSTATSD32 10 | ||
861 | #define AIROGMICRID 11 | ||
862 | #define AIROGMICSTATS 12 | ||
863 | #define AIROGFLAGS 13 | ||
864 | #define AIROGID 14 | ||
865 | #define AIRORRID 15 | ||
866 | #define AIRORSWVERSION 17 | ||
867 | |||
868 | /* Leave gap of 40 commands after AIROGSTATSD32 for future */ | ||
869 | |||
870 | #define AIROPCAP AIROGSTATSD32 + 40 | ||
871 | #define AIROPVLIST AIROPCAP + 1 | ||
872 | #define AIROPSLIST AIROPVLIST + 1 | ||
873 | #define AIROPCFG AIROPSLIST + 1 | ||
874 | #define AIROPSIDS AIROPCFG + 1 | ||
875 | #define AIROPAPLIST AIROPSIDS + 1 | ||
876 | #define AIROPMACON AIROPAPLIST + 1 /* Enable mac */ | ||
877 | #define AIROPMACOFF AIROPMACON + 1 /* Disable mac */ | ||
878 | #define AIROPSTCLR AIROPMACOFF + 1 | ||
879 | #define AIROPWEPKEY AIROPSTCLR + 1 | ||
880 | #define AIROPWEPKEYNV AIROPWEPKEY + 1 | ||
881 | #define AIROPLEAPPWD AIROPWEPKEYNV + 1 | ||
882 | #define AIROPLEAPUSR AIROPLEAPPWD + 1 | ||
883 | |||
884 | /* Flash codes */ | ||
885 | |||
886 | #define AIROFLSHRST AIROPWEPKEYNV + 40 | ||
887 | #define AIROFLSHGCHR AIROFLSHRST + 1 | ||
888 | #define AIROFLSHSTFL AIROFLSHGCHR + 1 | ||
889 | #define AIROFLSHPCHR AIROFLSHSTFL + 1 | ||
890 | #define AIROFLPUTBUF AIROFLSHPCHR + 1 | ||
891 | #define AIRORESTART AIROFLPUTBUF + 1 | ||
892 | |||
893 | #define FLASHSIZE 32768 | ||
894 | #define AUXMEMSIZE (256 * 1024) | ||
895 | |||
896 | typedef struct aironet_ioctl { | ||
897 | unsigned short command; // What to do | ||
898 | unsigned short len; // Len of data | ||
899 | unsigned short ridnum; // rid number | ||
900 | unsigned char __user *data; // d-data | ||
901 | } aironet_ioctl; | ||
902 | |||
903 | static char *swversion = "2.1"; | ||
904 | #endif /* CISCO_EXT */ | ||
905 | |||
906 | #define NUM_MODULES 2 | ||
907 | #define MIC_MSGLEN_MAX 2400 | ||
908 | #define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX | ||
909 | |||
910 | typedef struct { | ||
911 | u32 size; // size | ||
912 | u8 enabled; // MIC enabled or not | ||
913 | u32 rxSuccess; // successful packets received | ||
914 | u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison | ||
915 | u32 rxNotMICed; // pkts dropped due to not being MIC'd | ||
916 | u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed | ||
917 | u32 rxWrongSequence; // pkts dropped due to sequence number violation | ||
918 | u32 reserve[32]; | ||
919 | } mic_statistics; | ||
920 | |||
921 | typedef struct { | ||
922 | u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2]; | ||
923 | u64 accum; // accumulated mic, reduced to u32 in final() | ||
924 | int position; // current position (byte offset) in message | ||
925 | union { | ||
926 | u8 d8[4]; | ||
927 | u32 d32; | ||
928 | } part; // saves partial message word across update() calls | ||
929 | } emmh32_context; | ||
930 | |||
931 | typedef struct { | ||
932 | emmh32_context seed; // Context - the seed | ||
933 | u32 rx; // Received sequence number | ||
934 | u32 tx; // Tx sequence number | ||
935 | u32 window; // Start of window | ||
936 | u8 valid; // Flag to say if context is valid or not | ||
937 | u8 key[16]; | ||
938 | } miccntx; | ||
939 | |||
940 | typedef struct { | ||
941 | miccntx mCtx; // Multicast context | ||
942 | miccntx uCtx; // Unicast context | ||
943 | } mic_module; | ||
944 | |||
945 | typedef struct { | ||
946 | unsigned int rid: 16; | ||
947 | unsigned int len: 15; | ||
948 | unsigned int valid: 1; | ||
949 | dma_addr_t host_addr; | ||
950 | } Rid; | ||
951 | |||
952 | typedef struct { | ||
953 | unsigned int offset: 15; | ||
954 | unsigned int eoc: 1; | ||
955 | unsigned int len: 15; | ||
956 | unsigned int valid: 1; | ||
957 | dma_addr_t host_addr; | ||
958 | } TxFid; | ||
959 | |||
960 | typedef struct { | ||
961 | unsigned int ctl: 15; | ||
962 | unsigned int rdy: 1; | ||
963 | unsigned int len: 15; | ||
964 | unsigned int valid: 1; | ||
965 | dma_addr_t host_addr; | ||
966 | } RxFid; | ||
967 | |||
968 | /* | ||
969 | * Host receive descriptor | ||
970 | */ | ||
971 | typedef struct { | ||
972 | unsigned char __iomem *card_ram_off; /* offset into card memory of the | ||
973 | desc */ | ||
974 | RxFid rx_desc; /* card receive descriptor */ | ||
975 | char *virtual_host_addr; /* virtual address of host receive | ||
976 | buffer */ | ||
977 | int pending; | ||
978 | } HostRxDesc; | ||
979 | |||
980 | /* | ||
981 | * Host transmit descriptor | ||
982 | */ | ||
983 | typedef struct { | ||
984 | unsigned char __iomem *card_ram_off; /* offset into card memory of the | ||
985 | desc */ | ||
986 | TxFid tx_desc; /* card transmit descriptor */ | ||
987 | char *virtual_host_addr; /* virtual address of host receive | ||
988 | buffer */ | ||
989 | int pending; | ||
990 | } HostTxDesc; | ||
991 | |||
992 | /* | ||
993 | * Host RID descriptor | ||
994 | */ | ||
995 | typedef struct { | ||
996 | unsigned char __iomem *card_ram_off; /* offset into card memory of the | ||
997 | descriptor */ | ||
998 | Rid rid_desc; /* card RID descriptor */ | ||
999 | char *virtual_host_addr; /* virtual address of host receive | ||
1000 | buffer */ | ||
1001 | } HostRidDesc; | ||
1002 | |||
1003 | typedef struct { | ||
1004 | u16 sw0; | ||
1005 | u16 sw1; | ||
1006 | u16 status; | ||
1007 | u16 len; | ||
1008 | #define HOST_SET (1 << 0) | ||
1009 | #define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */ | ||
1010 | #define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */ | ||
1011 | #define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */ | ||
1012 | #define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */ | ||
1013 | #define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */ | ||
1014 | #define HOST_CLR_AID (1 << 7) /* clear AID failure */ | ||
1015 | #define HOST_RTS (1 << 9) /* Force RTS use */ | ||
1016 | #define HOST_SHORT (1 << 10) /* Do short preamble */ | ||
1017 | u16 ctl; | ||
1018 | u16 aid; | ||
1019 | u16 retries; | ||
1020 | u16 fill; | ||
1021 | } TxCtlHdr; | ||
1022 | |||
1023 | typedef struct { | ||
1024 | u16 ctl; | ||
1025 | u16 duration; | ||
1026 | char addr1[6]; | ||
1027 | char addr2[6]; | ||
1028 | char addr3[6]; | ||
1029 | u16 seq; | ||
1030 | char addr4[6]; | ||
1031 | } WifiHdr; | ||
1032 | |||
1033 | |||
1034 | typedef struct { | ||
1035 | TxCtlHdr ctlhdr; | ||
1036 | u16 fill1; | ||
1037 | u16 fill2; | ||
1038 | WifiHdr wifihdr; | ||
1039 | u16 gaplen; | ||
1040 | u16 status; | ||
1041 | } WifiCtlHdr; | ||
1042 | |||
1043 | WifiCtlHdr wifictlhdr8023 = { | ||
1044 | .ctlhdr = { | ||
1045 | .ctl = HOST_DONT_RLSE, | ||
1046 | } | ||
1047 | }; | ||
1048 | |||
1049 | #ifdef WIRELESS_EXT | ||
1050 | // Frequency list (map channels to frequencies) | ||
1051 | static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, | ||
1052 | 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; | ||
1053 | |||
1054 | // A few details needed for WEP (Wireless Equivalent Privacy) | ||
1055 | #define MAX_KEY_SIZE 13 // 128 (?) bits | ||
1056 | #define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP | ||
1057 | typedef struct wep_key_t { | ||
1058 | u16 len; | ||
1059 | u8 key[16]; /* 40-bit and 104-bit keys */ | ||
1060 | } wep_key_t; | ||
1061 | |||
1062 | /* Backward compatibility */ | ||
1063 | #ifndef IW_ENCODE_NOKEY | ||
1064 | #define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ | ||
1065 | #define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN) | ||
1066 | #endif /* IW_ENCODE_NOKEY */ | ||
1067 | |||
1068 | /* List of Wireless Handlers (new API) */ | ||
1069 | static const struct iw_handler_def airo_handler_def; | ||
1070 | #endif /* WIRELESS_EXT */ | ||
1071 | |||
1072 | static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; | ||
1073 | |||
1074 | struct airo_info; | ||
1075 | |||
1076 | static int get_dec_u16( char *buffer, int *start, int limit ); | ||
1077 | static void OUT4500( struct airo_info *, u16 register, u16 value ); | ||
1078 | static unsigned short IN4500( struct airo_info *, u16 register ); | ||
1079 | static u16 setup_card(struct airo_info*, u8 *mac, int lock); | ||
1080 | static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ); | ||
1081 | static void disable_MAC(struct airo_info *ai, int lock); | ||
1082 | static void enable_interrupts(struct airo_info*); | ||
1083 | static void disable_interrupts(struct airo_info*); | ||
1084 | static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp); | ||
1085 | static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); | ||
1086 | static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, | ||
1087 | int whichbap); | ||
1088 | static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, | ||
1089 | int whichbap); | ||
1090 | static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen, | ||
1091 | int whichbap); | ||
1092 | static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); | ||
1093 | static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); | ||
1094 | static int PC4500_writerid(struct airo_info*, u16 rid, const void | ||
1095 | *pBuf, int len, int lock); | ||
1096 | static int do_writerid( struct airo_info*, u16 rid, const void *rid_data, | ||
1097 | int len, int dummy ); | ||
1098 | static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); | ||
1099 | static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket); | ||
1100 | static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket); | ||
1101 | |||
1102 | static int mpi_send_packet (struct net_device *dev); | ||
1103 | static void mpi_unmap_card(struct pci_dev *pci); | ||
1104 | static void mpi_receive_802_3(struct airo_info *ai); | ||
1105 | static void mpi_receive_802_11(struct airo_info *ai); | ||
1106 | static int waitbusy (struct airo_info *ai); | ||
1107 | |||
1108 | static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs | ||
1109 | *regs); | ||
1110 | static int airo_thread(void *data); | ||
1111 | static void timer_func( struct net_device *dev ); | ||
1112 | static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | ||
1113 | #ifdef WIRELESS_EXT | ||
1114 | struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); | ||
1115 | static void airo_read_wireless_stats (struct airo_info *local); | ||
1116 | #endif /* WIRELESS_EXT */ | ||
1117 | #ifdef CISCO_EXT | ||
1118 | static int readrids(struct net_device *dev, aironet_ioctl *comp); | ||
1119 | static int writerids(struct net_device *dev, aironet_ioctl *comp); | ||
1120 | int flashcard(struct net_device *dev, aironet_ioctl *comp); | ||
1121 | #endif /* CISCO_EXT */ | ||
1122 | #ifdef MICSUPPORT | ||
1123 | static void micinit(struct airo_info *ai); | ||
1124 | static int micsetup(struct airo_info *ai); | ||
1125 | static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); | ||
1126 | static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); | ||
1127 | |||
1128 | #include <linux/crypto.h> | ||
1129 | #endif | ||
1130 | |||
1131 | struct airo_info { | ||
1132 | struct net_device_stats stats; | ||
1133 | struct net_device *dev; | ||
1134 | /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we | ||
1135 | use the high bit to mark whether it is in use. */ | ||
1136 | #define MAX_FIDS 6 | ||
1137 | #define MPI_MAX_FIDS 1 | ||
1138 | int fids[MAX_FIDS]; | ||
1139 | ConfigRid config; | ||
1140 | char keyindex; // Used with auto wep | ||
1141 | char defindex; // Used with auto wep | ||
1142 | struct proc_dir_entry *proc_entry; | ||
1143 | spinlock_t aux_lock; | ||
1144 | unsigned long flags; | ||
1145 | #define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */ | ||
1146 | #define FLAG_RADIO_OFF 0 /* User disabling of MAC */ | ||
1147 | #define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ | ||
1148 | #define FLAG_RADIO_MASK 0x03 | ||
1149 | #define FLAG_ENABLED 2 | ||
1150 | #define FLAG_ADHOC 3 /* Needed by MIC */ | ||
1151 | #define FLAG_MIC_CAPABLE 4 | ||
1152 | #define FLAG_UPDATE_MULTI 5 | ||
1153 | #define FLAG_UPDATE_UNI 6 | ||
1154 | #define FLAG_802_11 7 | ||
1155 | #define FLAG_PENDING_XMIT 9 | ||
1156 | #define FLAG_PENDING_XMIT11 10 | ||
1157 | #define FLAG_MPI 11 | ||
1158 | #define FLAG_REGISTERED 12 | ||
1159 | #define FLAG_COMMIT 13 | ||
1160 | #define FLAG_RESET 14 | ||
1161 | #define FLAG_FLASHING 15 | ||
1162 | #define JOB_MASK 0x1ff0000 | ||
1163 | #define JOB_DIE 16 | ||
1164 | #define JOB_XMIT 17 | ||
1165 | #define JOB_XMIT11 18 | ||
1166 | #define JOB_STATS 19 | ||
1167 | #define JOB_PROMISC 20 | ||
1168 | #define JOB_MIC 21 | ||
1169 | #define JOB_EVENT 22 | ||
1170 | #define JOB_AUTOWEP 23 | ||
1171 | #define JOB_WSTATS 24 | ||
1172 | int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, | ||
1173 | int whichbap); | ||
1174 | unsigned short *flash; | ||
1175 | tdsRssiEntry *rssi; | ||
1176 | struct task_struct *task; | ||
1177 | struct semaphore sem; | ||
1178 | pid_t thr_pid; | ||
1179 | wait_queue_head_t thr_wait; | ||
1180 | struct completion thr_exited; | ||
1181 | unsigned long expires; | ||
1182 | struct { | ||
1183 | struct sk_buff *skb; | ||
1184 | int fid; | ||
1185 | } xmit, xmit11; | ||
1186 | struct net_device *wifidev; | ||
1187 | #ifdef WIRELESS_EXT | ||
1188 | struct iw_statistics wstats; // wireless stats | ||
1189 | unsigned long scan_timestamp; /* Time started to scan */ | ||
1190 | struct iw_spy_data spy_data; | ||
1191 | struct iw_public_data wireless_data; | ||
1192 | #endif /* WIRELESS_EXT */ | ||
1193 | #ifdef MICSUPPORT | ||
1194 | /* MIC stuff */ | ||
1195 | struct crypto_tfm *tfm; | ||
1196 | mic_module mod[2]; | ||
1197 | mic_statistics micstats; | ||
1198 | #endif | ||
1199 | HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors | ||
1200 | HostTxDesc txfids[MPI_MAX_FIDS]; | ||
1201 | HostRidDesc config_desc; | ||
1202 | unsigned long ridbus; // phys addr of config_desc | ||
1203 | struct sk_buff_head txq;// tx queue used by mpi350 code | ||
1204 | struct pci_dev *pci; | ||
1205 | unsigned char __iomem *pcimem; | ||
1206 | unsigned char __iomem *pciaux; | ||
1207 | unsigned char *shared; | ||
1208 | dma_addr_t shared_dma; | ||
1209 | int power; | ||
1210 | SsidRid *SSID; | ||
1211 | APListRid *APList; | ||
1212 | #define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE | ||
1213 | char proc_name[IFNAMSIZ]; | ||
1214 | }; | ||
1215 | |||
1216 | static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, | ||
1217 | int whichbap) { | ||
1218 | return ai->bap_read(ai, pu16Dst, bytelen, whichbap); | ||
1219 | } | ||
1220 | |||
1221 | static int setup_proc_entry( struct net_device *dev, | ||
1222 | struct airo_info *apriv ); | ||
1223 | static int takedown_proc_entry( struct net_device *dev, | ||
1224 | struct airo_info *apriv ); | ||
1225 | |||
1226 | #ifdef MICSUPPORT | ||
1227 | /*********************************************************************** | ||
1228 | * MIC ROUTINES * | ||
1229 | *********************************************************************** | ||
1230 | */ | ||
1231 | |||
1232 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); | ||
1233 | static void MoveWindow(miccntx *context, u32 micSeq); | ||
1234 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); | ||
1235 | void emmh32_init(emmh32_context *context); | ||
1236 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len); | ||
1237 | void emmh32_final(emmh32_context *context, u8 digest[4]); | ||
1238 | |||
1239 | /* micinit - Initialize mic seed */ | ||
1240 | |||
1241 | static void micinit(struct airo_info *ai) | ||
1242 | { | ||
1243 | MICRid mic_rid; | ||
1244 | |||
1245 | clear_bit(JOB_MIC, &ai->flags); | ||
1246 | PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); | ||
1247 | up(&ai->sem); | ||
1248 | |||
1249 | ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0; | ||
1250 | |||
1251 | if (ai->micstats.enabled) { | ||
1252 | /* Key must be valid and different */ | ||
1253 | if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid || | ||
1254 | (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast, | ||
1255 | sizeof(ai->mod[0].mCtx.key)) != 0))) { | ||
1256 | /* Age current mic Context */ | ||
1257 | memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx)); | ||
1258 | /* Initialize new context */ | ||
1259 | memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast)); | ||
1260 | ai->mod[0].mCtx.window = 33; //Window always points to the middle | ||
1261 | ai->mod[0].mCtx.rx = 0; //Rx Sequence numbers | ||
1262 | ai->mod[0].mCtx.tx = 0; //Tx sequence numbers | ||
1263 | ai->mod[0].mCtx.valid = 1; //Key is now valid | ||
1264 | |||
1265 | /* Give key to mic seed */ | ||
1266 | emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm); | ||
1267 | } | ||
1268 | |||
1269 | /* Key must be valid and different */ | ||
1270 | if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid || | ||
1271 | (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast, | ||
1272 | sizeof(ai->mod[0].uCtx.key)) != 0))) { | ||
1273 | /* Age current mic Context */ | ||
1274 | memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx)); | ||
1275 | /* Initialize new context */ | ||
1276 | memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast)); | ||
1277 | |||
1278 | ai->mod[0].uCtx.window = 33; //Window always points to the middle | ||
1279 | ai->mod[0].uCtx.rx = 0; //Rx Sequence numbers | ||
1280 | ai->mod[0].uCtx.tx = 0; //Tx sequence numbers | ||
1281 | ai->mod[0].uCtx.valid = 1; //Key is now valid | ||
1282 | |||
1283 | //Give key to mic seed | ||
1284 | emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm); | ||
1285 | } | ||
1286 | } else { | ||
1287 | /* So next time we have a valid key and mic is enabled, we will update | ||
1288 | * the sequence number if the key is the same as before. | ||
1289 | */ | ||
1290 | ai->mod[0].uCtx.valid = 0; | ||
1291 | ai->mod[0].mCtx.valid = 0; | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | /* micsetup - Get ready for business */ | ||
1296 | |||
1297 | static int micsetup(struct airo_info *ai) { | ||
1298 | int i; | ||
1299 | |||
1300 | if (ai->tfm == NULL) | ||
1301 | ai->tfm = crypto_alloc_tfm("aes", 0); | ||
1302 | |||
1303 | if (ai->tfm == NULL) { | ||
1304 | printk(KERN_ERR "airo: failed to load transform for AES\n"); | ||
1305 | return ERROR; | ||
1306 | } | ||
1307 | |||
1308 | for (i=0; i < NUM_MODULES; i++) { | ||
1309 | memset(&ai->mod[i].mCtx,0,sizeof(miccntx)); | ||
1310 | memset(&ai->mod[i].uCtx,0,sizeof(miccntx)); | ||
1311 | } | ||
1312 | return SUCCESS; | ||
1313 | } | ||
1314 | |||
1315 | char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; | ||
1316 | |||
1317 | /*=========================================================================== | ||
1318 | * Description: Mic a packet | ||
1319 | * | ||
1320 | * Inputs: etherHead * pointer to an 802.3 frame | ||
1321 | * | ||
1322 | * Returns: BOOLEAN if successful, otherwise false. | ||
1323 | * PacketTxLen will be updated with the mic'd packets size. | ||
1324 | * | ||
1325 | * Caveats: It is assumed that the frame buffer will already | ||
1326 | * be big enough to hold the largets mic message possible. | ||
1327 | * (No memory allocation is done here). | ||
1328 | * | ||
1329 | * Author: sbraneky (10/15/01) | ||
1330 | * Merciless hacks by rwilcher (1/14/02) | ||
1331 | */ | ||
1332 | |||
1333 | static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen) | ||
1334 | { | ||
1335 | miccntx *context; | ||
1336 | |||
1337 | // Determine correct context | ||
1338 | // If not adhoc, always use unicast key | ||
1339 | |||
1340 | if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1)) | ||
1341 | context = &ai->mod[0].mCtx; | ||
1342 | else | ||
1343 | context = &ai->mod[0].uCtx; | ||
1344 | |||
1345 | if (!context->valid) | ||
1346 | return ERROR; | ||
1347 | |||
1348 | mic->typelen = htons(payLen + 16); //Length of Mic'd packet | ||
1349 | |||
1350 | memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap | ||
1351 | |||
1352 | // Add Tx sequence | ||
1353 | mic->seq = htonl(context->tx); | ||
1354 | context->tx += 2; | ||
1355 | |||
1356 | emmh32_init(&context->seed); // Mic the packet | ||
1357 | emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA | ||
1358 | emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap | ||
1359 | emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ | ||
1360 | emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload | ||
1361 | emmh32_final(&context->seed, (u8*)&mic->mic); | ||
1362 | |||
1363 | /* New Type/length ?????????? */ | ||
1364 | mic->typelen = 0; //Let NIC know it could be an oversized packet | ||
1365 | return SUCCESS; | ||
1366 | } | ||
1367 | |||
1368 | typedef enum { | ||
1369 | NONE, | ||
1370 | NOMIC, | ||
1371 | NOMICPLUMMED, | ||
1372 | SEQUENCE, | ||
1373 | INCORRECTMIC, | ||
1374 | } mic_error; | ||
1375 | |||
1376 | /*=========================================================================== | ||
1377 | * Description: Decapsulates a MIC'd packet and returns the 802.3 packet | ||
1378 | * (removes the MIC stuff) if packet is a valid packet. | ||
1379 | * | ||
1380 | * Inputs: etherHead pointer to the 802.3 packet | ||
1381 | * | ||
1382 | * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE | ||
1383 | * | ||
1384 | * Author: sbraneky (10/15/01) | ||
1385 | * Merciless hacks by rwilcher (1/14/02) | ||
1386 | *--------------------------------------------------------------------------- | ||
1387 | */ | ||
1388 | |||
1389 | static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen) | ||
1390 | { | ||
1391 | int i; | ||
1392 | u32 micSEQ; | ||
1393 | miccntx *context; | ||
1394 | u8 digest[4]; | ||
1395 | mic_error micError = NONE; | ||
1396 | |||
1397 | // Check if the packet is a Mic'd packet | ||
1398 | |||
1399 | if (!ai->micstats.enabled) { | ||
1400 | //No Mic set or Mic OFF but we received a MIC'd packet. | ||
1401 | if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) { | ||
1402 | ai->micstats.rxMICPlummed++; | ||
1403 | return ERROR; | ||
1404 | } | ||
1405 | return SUCCESS; | ||
1406 | } | ||
1407 | |||
1408 | if (ntohs(mic->typelen) == 0x888E) | ||
1409 | return SUCCESS; | ||
1410 | |||
1411 | if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) { | ||
1412 | // Mic enabled but packet isn't Mic'd | ||
1413 | ai->micstats.rxMICPlummed++; | ||
1414 | return ERROR; | ||
1415 | } | ||
1416 | |||
1417 | micSEQ = ntohl(mic->seq); //store SEQ as CPU order | ||
1418 | |||
1419 | //At this point we a have a mic'd packet and mic is enabled | ||
1420 | //Now do the mic error checking. | ||
1421 | |||
1422 | //Receive seq must be odd | ||
1423 | if ( (micSEQ & 1) == 0 ) { | ||
1424 | ai->micstats.rxWrongSequence++; | ||
1425 | return ERROR; | ||
1426 | } | ||
1427 | |||
1428 | for (i = 0; i < NUM_MODULES; i++) { | ||
1429 | int mcast = eth->da[0] & 1; | ||
1430 | //Determine proper context | ||
1431 | context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx; | ||
1432 | |||
1433 | //Make sure context is valid | ||
1434 | if (!context->valid) { | ||
1435 | if (i == 0) | ||
1436 | micError = NOMICPLUMMED; | ||
1437 | continue; | ||
1438 | } | ||
1439 | //DeMic it | ||
1440 | |||
1441 | if (!mic->typelen) | ||
1442 | mic->typelen = htons(payLen + sizeof(MICBuffer) - 2); | ||
1443 | |||
1444 | emmh32_init(&context->seed); | ||
1445 | emmh32_update(&context->seed, eth->da, ETH_ALEN*2); | ||
1446 | emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); | ||
1447 | emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq)); | ||
1448 | emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen); | ||
1449 | //Calculate MIC | ||
1450 | emmh32_final(&context->seed, digest); | ||
1451 | |||
1452 | if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match | ||
1453 | //Invalid Mic | ||
1454 | if (i == 0) | ||
1455 | micError = INCORRECTMIC; | ||
1456 | continue; | ||
1457 | } | ||
1458 | |||
1459 | //Check Sequence number if mics pass | ||
1460 | if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) { | ||
1461 | ai->micstats.rxSuccess++; | ||
1462 | return SUCCESS; | ||
1463 | } | ||
1464 | if (i == 0) | ||
1465 | micError = SEQUENCE; | ||
1466 | } | ||
1467 | |||
1468 | // Update statistics | ||
1469 | switch (micError) { | ||
1470 | case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break; | ||
1471 | case SEQUENCE: ai->micstats.rxWrongSequence++; break; | ||
1472 | case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break; | ||
1473 | case NONE: break; | ||
1474 | case NOMIC: break; | ||
1475 | } | ||
1476 | return ERROR; | ||
1477 | } | ||
1478 | |||
1479 | /*=========================================================================== | ||
1480 | * Description: Checks the Rx Seq number to make sure it is valid | ||
1481 | * and hasn't already been received | ||
1482 | * | ||
1483 | * Inputs: miccntx - mic context to check seq against | ||
1484 | * micSeq - the Mic seq number | ||
1485 | * | ||
1486 | * Returns: TRUE if valid otherwise FALSE. | ||
1487 | * | ||
1488 | * Author: sbraneky (10/15/01) | ||
1489 | * Merciless hacks by rwilcher (1/14/02) | ||
1490 | *--------------------------------------------------------------------------- | ||
1491 | */ | ||
1492 | |||
1493 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq) | ||
1494 | { | ||
1495 | u32 seq,index; | ||
1496 | |||
1497 | //Allow for the ap being rebooted - if it is then use the next | ||
1498 | //sequence number of the current sequence number - might go backwards | ||
1499 | |||
1500 | if (mcast) { | ||
1501 | if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) { | ||
1502 | clear_bit (FLAG_UPDATE_MULTI, &ai->flags); | ||
1503 | context->window = (micSeq > 33) ? micSeq : 33; | ||
1504 | context->rx = 0; // Reset rx | ||
1505 | } | ||
1506 | } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) { | ||
1507 | clear_bit (FLAG_UPDATE_UNI, &ai->flags); | ||
1508 | context->window = (micSeq > 33) ? micSeq : 33; // Move window | ||
1509 | context->rx = 0; // Reset rx | ||
1510 | } | ||
1511 | |||
1512 | //Make sequence number relative to START of window | ||
1513 | seq = micSeq - (context->window - 33); | ||
1514 | |||
1515 | //Too old of a SEQ number to check. | ||
1516 | if ((s32)seq < 0) | ||
1517 | return ERROR; | ||
1518 | |||
1519 | if ( seq > 64 ) { | ||
1520 | //Window is infinite forward | ||
1521 | MoveWindow(context,micSeq); | ||
1522 | return SUCCESS; | ||
1523 | } | ||
1524 | |||
1525 | // We are in the window. Now check the context rx bit to see if it was already sent | ||
1526 | seq >>= 1; //divide by 2 because we only have odd numbers | ||
1527 | index = 1 << seq; //Get an index number | ||
1528 | |||
1529 | if (!(context->rx & index)) { | ||
1530 | //micSEQ falls inside the window. | ||
1531 | //Add seqence number to the list of received numbers. | ||
1532 | context->rx |= index; | ||
1533 | |||
1534 | MoveWindow(context,micSeq); | ||
1535 | |||
1536 | return SUCCESS; | ||
1537 | } | ||
1538 | return ERROR; | ||
1539 | } | ||
1540 | |||
1541 | static void MoveWindow(miccntx *context, u32 micSeq) | ||
1542 | { | ||
1543 | u32 shift; | ||
1544 | |||
1545 | //Move window if seq greater than the middle of the window | ||
1546 | if (micSeq > context->window) { | ||
1547 | shift = (micSeq - context->window) >> 1; | ||
1548 | |||
1549 | //Shift out old | ||
1550 | if (shift < 32) | ||
1551 | context->rx >>= shift; | ||
1552 | else | ||
1553 | context->rx = 0; | ||
1554 | |||
1555 | context->window = micSeq; //Move window | ||
1556 | } | ||
1557 | } | ||
1558 | |||
1559 | /*==============================================*/ | ||
1560 | /*========== EMMH ROUTINES ====================*/ | ||
1561 | /*==============================================*/ | ||
1562 | |||
1563 | /* mic accumulate */ | ||
1564 | #define MIC_ACCUM(val) \ | ||
1565 | context->accum += (u64)(val) * context->coeff[coeff_position++]; | ||
1566 | |||
1567 | static unsigned char aes_counter[16]; | ||
1568 | |||
1569 | /* expand the key to fill the MMH coefficient array */ | ||
1570 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) | ||
1571 | { | ||
1572 | /* take the keying material, expand if necessary, truncate at 16-bytes */ | ||
1573 | /* run through AES counter mode to generate context->coeff[] */ | ||
1574 | |||
1575 | int i,j; | ||
1576 | u32 counter; | ||
1577 | u8 *cipher, plain[16]; | ||
1578 | struct scatterlist sg[1]; | ||
1579 | |||
1580 | crypto_cipher_setkey(tfm, pkey, 16); | ||
1581 | counter = 0; | ||
1582 | for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) { | ||
1583 | aes_counter[15] = (u8)(counter >> 0); | ||
1584 | aes_counter[14] = (u8)(counter >> 8); | ||
1585 | aes_counter[13] = (u8)(counter >> 16); | ||
1586 | aes_counter[12] = (u8)(counter >> 24); | ||
1587 | counter++; | ||
1588 | memcpy (plain, aes_counter, 16); | ||
1589 | sg[0].page = virt_to_page(plain); | ||
1590 | sg[0].offset = ((long) plain & ~PAGE_MASK); | ||
1591 | sg[0].length = 16; | ||
1592 | crypto_cipher_encrypt(tfm, sg, sg, 16); | ||
1593 | cipher = kmap(sg[0].page) + sg[0].offset; | ||
1594 | for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) { | ||
1595 | context->coeff[i++] = ntohl(*(u32 *)&cipher[j]); | ||
1596 | j += 4; | ||
1597 | } | ||
1598 | } | ||
1599 | } | ||
1600 | |||
1601 | /* prepare for calculation of a new mic */ | ||
1602 | void emmh32_init(emmh32_context *context) | ||
1603 | { | ||
1604 | /* prepare for new mic calculation */ | ||
1605 | context->accum = 0; | ||
1606 | context->position = 0; | ||
1607 | } | ||
1608 | |||
1609 | /* add some bytes to the mic calculation */ | ||
1610 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | ||
1611 | { | ||
1612 | int coeff_position, byte_position; | ||
1613 | |||
1614 | if (len == 0) return; | ||
1615 | |||
1616 | coeff_position = context->position >> 2; | ||
1617 | |||
1618 | /* deal with partial 32-bit word left over from last update */ | ||
1619 | byte_position = context->position & 3; | ||
1620 | if (byte_position) { | ||
1621 | /* have a partial word in part to deal with */ | ||
1622 | do { | ||
1623 | if (len == 0) return; | ||
1624 | context->part.d8[byte_position++] = *pOctets++; | ||
1625 | context->position++; | ||
1626 | len--; | ||
1627 | } while (byte_position < 4); | ||
1628 | MIC_ACCUM(htonl(context->part.d32)); | ||
1629 | } | ||
1630 | |||
1631 | /* deal with full 32-bit words */ | ||
1632 | while (len >= 4) { | ||
1633 | MIC_ACCUM(htonl(*(u32 *)pOctets)); | ||
1634 | context->position += 4; | ||
1635 | pOctets += 4; | ||
1636 | len -= 4; | ||
1637 | } | ||
1638 | |||
1639 | /* deal with partial 32-bit word that will be left over from this update */ | ||
1640 | byte_position = 0; | ||
1641 | while (len > 0) { | ||
1642 | context->part.d8[byte_position++] = *pOctets++; | ||
1643 | context->position++; | ||
1644 | len--; | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | /* mask used to zero empty bytes for final partial word */ | ||
1649 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; | ||
1650 | |||
1651 | /* calculate the mic */ | ||
1652 | void emmh32_final(emmh32_context *context, u8 digest[4]) | ||
1653 | { | ||
1654 | int coeff_position, byte_position; | ||
1655 | u32 val; | ||
1656 | |||
1657 | u64 sum, utmp; | ||
1658 | s64 stmp; | ||
1659 | |||
1660 | coeff_position = context->position >> 2; | ||
1661 | |||
1662 | /* deal with partial 32-bit word left over from last update */ | ||
1663 | byte_position = context->position & 3; | ||
1664 | if (byte_position) { | ||
1665 | /* have a partial word in part to deal with */ | ||
1666 | val = htonl(context->part.d32); | ||
1667 | MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ | ||
1668 | } | ||
1669 | |||
1670 | /* reduce the accumulated u64 to a 32-bit MIC */ | ||
1671 | sum = context->accum; | ||
1672 | stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15); | ||
1673 | utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15); | ||
1674 | sum = utmp & 0xffffffffLL; | ||
1675 | if (utmp > 0x10000000fLL) | ||
1676 | sum -= 15; | ||
1677 | |||
1678 | val = (u32)sum; | ||
1679 | digest[0] = (val>>24) & 0xFF; | ||
1680 | digest[1] = (val>>16) & 0xFF; | ||
1681 | digest[2] = (val>>8) & 0xFF; | ||
1682 | digest[3] = val & 0xFF; | ||
1683 | } | ||
1684 | #endif | ||
1685 | |||
1686 | static int readBSSListRid(struct airo_info *ai, int first, | ||
1687 | BSSListRid *list) { | ||
1688 | int rc; | ||
1689 | Cmd cmd; | ||
1690 | Resp rsp; | ||
1691 | |||
1692 | if (first == 1) { | ||
1693 | if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; | ||
1694 | memset(&cmd, 0, sizeof(cmd)); | ||
1695 | cmd.cmd=CMD_LISTBSS; | ||
1696 | if (down_interruptible(&ai->sem)) | ||
1697 | return -ERESTARTSYS; | ||
1698 | issuecommand(ai, &cmd, &rsp); | ||
1699 | up(&ai->sem); | ||
1700 | /* Let the command take effect */ | ||
1701 | ai->task = current; | ||
1702 | ssleep(3); | ||
1703 | ai->task = NULL; | ||
1704 | } | ||
1705 | rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT, | ||
1706 | list, sizeof(*list), 1); | ||
1707 | |||
1708 | list->len = le16_to_cpu(list->len); | ||
1709 | list->index = le16_to_cpu(list->index); | ||
1710 | list->radioType = le16_to_cpu(list->radioType); | ||
1711 | list->cap = le16_to_cpu(list->cap); | ||
1712 | list->beaconInterval = le16_to_cpu(list->beaconInterval); | ||
1713 | list->fh.dwell = le16_to_cpu(list->fh.dwell); | ||
1714 | list->dsChannel = le16_to_cpu(list->dsChannel); | ||
1715 | list->atimWindow = le16_to_cpu(list->atimWindow); | ||
1716 | return rc; | ||
1717 | } | ||
1718 | |||
1719 | static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) { | ||
1720 | int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, | ||
1721 | wkr, sizeof(*wkr), lock); | ||
1722 | |||
1723 | wkr->len = le16_to_cpu(wkr->len); | ||
1724 | wkr->kindex = le16_to_cpu(wkr->kindex); | ||
1725 | wkr->klen = le16_to_cpu(wkr->klen); | ||
1726 | return rc; | ||
1727 | } | ||
1728 | /* In the writeXXXRid routines we copy the rids so that we don't screwup | ||
1729 | * the originals when we endian them... */ | ||
1730 | static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) { | ||
1731 | int rc; | ||
1732 | WepKeyRid wkr = *pwkr; | ||
1733 | |||
1734 | wkr.len = cpu_to_le16(wkr.len); | ||
1735 | wkr.kindex = cpu_to_le16(wkr.kindex); | ||
1736 | wkr.klen = cpu_to_le16(wkr.klen); | ||
1737 | rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock); | ||
1738 | if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc); | ||
1739 | if (perm) { | ||
1740 | rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock); | ||
1741 | if (rc!=SUCCESS) { | ||
1742 | printk(KERN_ERR "airo: WEP_PERM set %x\n", rc); | ||
1743 | } | ||
1744 | } | ||
1745 | return rc; | ||
1746 | } | ||
1747 | |||
1748 | static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) { | ||
1749 | int i; | ||
1750 | int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); | ||
1751 | |||
1752 | ssidr->len = le16_to_cpu(ssidr->len); | ||
1753 | for(i = 0; i < 3; i++) { | ||
1754 | ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len); | ||
1755 | } | ||
1756 | return rc; | ||
1757 | } | ||
1758 | static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) { | ||
1759 | int rc; | ||
1760 | int i; | ||
1761 | SsidRid ssidr = *pssidr; | ||
1762 | |||
1763 | ssidr.len = cpu_to_le16(ssidr.len); | ||
1764 | for(i = 0; i < 3; i++) { | ||
1765 | ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len); | ||
1766 | } | ||
1767 | rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock); | ||
1768 | return rc; | ||
1769 | } | ||
1770 | static int readConfigRid(struct airo_info*ai, int lock) { | ||
1771 | int rc; | ||
1772 | u16 *s; | ||
1773 | ConfigRid cfg; | ||
1774 | |||
1775 | if (ai->config.len) | ||
1776 | return SUCCESS; | ||
1777 | |||
1778 | rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); | ||
1779 | if (rc != SUCCESS) | ||
1780 | return rc; | ||
1781 | |||
1782 | for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s); | ||
1783 | |||
1784 | for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++) | ||
1785 | *s = le16_to_cpu(*s); | ||
1786 | |||
1787 | for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++) | ||
1788 | *s = le16_to_cpu(*s); | ||
1789 | |||
1790 | for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++) | ||
1791 | *s = cpu_to_le16(*s); | ||
1792 | |||
1793 | for(s = &cfg.autoWake; s <= &cfg.autoWake; s++) | ||
1794 | *s = cpu_to_le16(*s); | ||
1795 | |||
1796 | ai->config = cfg; | ||
1797 | return SUCCESS; | ||
1798 | } | ||
1799 | static inline void checkThrottle(struct airo_info *ai) { | ||
1800 | int i; | ||
1801 | /* Old hardware had a limit on encryption speed */ | ||
1802 | if (ai->config.authType != AUTH_OPEN && maxencrypt) { | ||
1803 | for(i=0; i<8; i++) { | ||
1804 | if (ai->config.rates[i] > maxencrypt) { | ||
1805 | ai->config.rates[i] = 0; | ||
1806 | } | ||
1807 | } | ||
1808 | } | ||
1809 | } | ||
1810 | static int writeConfigRid(struct airo_info*ai, int lock) { | ||
1811 | u16 *s; | ||
1812 | ConfigRid cfgr; | ||
1813 | |||
1814 | if (!test_bit (FLAG_COMMIT, &ai->flags)) | ||
1815 | return SUCCESS; | ||
1816 | |||
1817 | clear_bit (FLAG_COMMIT, &ai->flags); | ||
1818 | clear_bit (FLAG_RESET, &ai->flags); | ||
1819 | checkThrottle(ai); | ||
1820 | cfgr = ai->config; | ||
1821 | |||
1822 | if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS) | ||
1823 | set_bit(FLAG_ADHOC, &ai->flags); | ||
1824 | else | ||
1825 | clear_bit(FLAG_ADHOC, &ai->flags); | ||
1826 | |||
1827 | for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s); | ||
1828 | |||
1829 | for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++) | ||
1830 | *s = cpu_to_le16(*s); | ||
1831 | |||
1832 | for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++) | ||
1833 | *s = cpu_to_le16(*s); | ||
1834 | |||
1835 | for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++) | ||
1836 | *s = cpu_to_le16(*s); | ||
1837 | |||
1838 | for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++) | ||
1839 | *s = cpu_to_le16(*s); | ||
1840 | |||
1841 | return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); | ||
1842 | } | ||
1843 | static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) { | ||
1844 | int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); | ||
1845 | u16 *s; | ||
1846 | |||
1847 | statr->len = le16_to_cpu(statr->len); | ||
1848 | for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s); | ||
1849 | |||
1850 | for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++) | ||
1851 | *s = le16_to_cpu(*s); | ||
1852 | statr->load = le16_to_cpu(statr->load); | ||
1853 | statr->assocStatus = le16_to_cpu(statr->assocStatus); | ||
1854 | return rc; | ||
1855 | } | ||
1856 | static int readAPListRid(struct airo_info*ai, APListRid *aplr) { | ||
1857 | int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1); | ||
1858 | aplr->len = le16_to_cpu(aplr->len); | ||
1859 | return rc; | ||
1860 | } | ||
1861 | static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) { | ||
1862 | int rc; | ||
1863 | aplr->len = cpu_to_le16(aplr->len); | ||
1864 | rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); | ||
1865 | return rc; | ||
1866 | } | ||
1867 | static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) { | ||
1868 | int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); | ||
1869 | u16 *s; | ||
1870 | |||
1871 | capr->len = le16_to_cpu(capr->len); | ||
1872 | capr->prodNum = le16_to_cpu(capr->prodNum); | ||
1873 | capr->radioType = le16_to_cpu(capr->radioType); | ||
1874 | capr->country = le16_to_cpu(capr->country); | ||
1875 | for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++) | ||
1876 | *s = le16_to_cpu(*s); | ||
1877 | return rc; | ||
1878 | } | ||
1879 | static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) { | ||
1880 | int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); | ||
1881 | u32 *i; | ||
1882 | |||
1883 | sr->len = le16_to_cpu(sr->len); | ||
1884 | for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i); | ||
1885 | return rc; | ||
1886 | } | ||
1887 | |||
1888 | static int airo_open(struct net_device *dev) { | ||
1889 | struct airo_info *info = dev->priv; | ||
1890 | Resp rsp; | ||
1891 | |||
1892 | if (test_bit(FLAG_FLASHING, &info->flags)) | ||
1893 | return -EIO; | ||
1894 | |||
1895 | /* Make sure the card is configured. | ||
1896 | * Wireless Extensions may postpone config changes until the card | ||
1897 | * is open (to pipeline changes and speed-up card setup). If | ||
1898 | * those changes are not yet commited, do it now - Jean II */ | ||
1899 | if (test_bit (FLAG_COMMIT, &info->flags)) { | ||
1900 | disable_MAC(info, 1); | ||
1901 | writeConfigRid(info, 1); | ||
1902 | } | ||
1903 | |||
1904 | if (info->wifidev != dev) { | ||
1905 | /* Power on the MAC controller (which may have been disabled) */ | ||
1906 | clear_bit(FLAG_RADIO_DOWN, &info->flags); | ||
1907 | enable_interrupts(info); | ||
1908 | } | ||
1909 | enable_MAC(info, &rsp, 1); | ||
1910 | |||
1911 | netif_start_queue(dev); | ||
1912 | return 0; | ||
1913 | } | ||
1914 | |||
1915 | static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { | ||
1916 | int npacks, pending; | ||
1917 | unsigned long flags; | ||
1918 | struct airo_info *ai = dev->priv; | ||
1919 | |||
1920 | if (!skb) { | ||
1921 | printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__); | ||
1922 | return 0; | ||
1923 | } | ||
1924 | npacks = skb_queue_len (&ai->txq); | ||
1925 | |||
1926 | if (npacks >= MAXTXQ - 1) { | ||
1927 | netif_stop_queue (dev); | ||
1928 | if (npacks > MAXTXQ) { | ||
1929 | ai->stats.tx_fifo_errors++; | ||
1930 | return 1; | ||
1931 | } | ||
1932 | skb_queue_tail (&ai->txq, skb); | ||
1933 | return 0; | ||
1934 | } | ||
1935 | |||
1936 | spin_lock_irqsave(&ai->aux_lock, flags); | ||
1937 | skb_queue_tail (&ai->txq, skb); | ||
1938 | pending = test_bit(FLAG_PENDING_XMIT, &ai->flags); | ||
1939 | spin_unlock_irqrestore(&ai->aux_lock,flags); | ||
1940 | netif_wake_queue (dev); | ||
1941 | |||
1942 | if (pending == 0) { | ||
1943 | set_bit(FLAG_PENDING_XMIT, &ai->flags); | ||
1944 | mpi_send_packet (dev); | ||
1945 | } | ||
1946 | return 0; | ||
1947 | } | ||
1948 | |||
1949 | /* | ||
1950 | * @mpi_send_packet | ||
1951 | * | ||
1952 | * Attempt to transmit a packet. Can be called from interrupt | ||
1953 | * or transmit . return number of packets we tried to send | ||
1954 | */ | ||
1955 | |||
1956 | static int mpi_send_packet (struct net_device *dev) | ||
1957 | { | ||
1958 | struct sk_buff *skb; | ||
1959 | unsigned char *buffer; | ||
1960 | s16 len, *payloadLen; | ||
1961 | struct airo_info *ai = dev->priv; | ||
1962 | u8 *sendbuf; | ||
1963 | |||
1964 | /* get a packet to send */ | ||
1965 | |||
1966 | if ((skb = skb_dequeue(&ai->txq)) == 0) { | ||
1967 | printk (KERN_ERR | ||
1968 | "airo: %s: Dequeue'd zero in send_packet()\n", | ||
1969 | __FUNCTION__); | ||
1970 | return 0; | ||
1971 | } | ||
1972 | |||
1973 | /* check min length*/ | ||
1974 | len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
1975 | buffer = skb->data; | ||
1976 | |||
1977 | ai->txfids[0].tx_desc.offset = 0; | ||
1978 | ai->txfids[0].tx_desc.valid = 1; | ||
1979 | ai->txfids[0].tx_desc.eoc = 1; | ||
1980 | ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); | ||
1981 | |||
1982 | /* | ||
1983 | * Magic, the cards firmware needs a length count (2 bytes) in the host buffer | ||
1984 | * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen | ||
1985 | * is immediatly after it. ------------------------------------------------ | ||
1986 | * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| | ||
1987 | * ------------------------------------------------ | ||
1988 | */ | ||
1989 | |||
1990 | memcpy((char *)ai->txfids[0].virtual_host_addr, | ||
1991 | (char *)&wifictlhdr8023, sizeof(wifictlhdr8023)); | ||
1992 | |||
1993 | payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr + | ||
1994 | sizeof(wifictlhdr8023)); | ||
1995 | sendbuf = ai->txfids[0].virtual_host_addr + | ||
1996 | sizeof(wifictlhdr8023) + 2 ; | ||
1997 | |||
1998 | /* | ||
1999 | * Firmware automaticly puts 802 header on so | ||
2000 | * we don't need to account for it in the length | ||
2001 | */ | ||
2002 | #ifdef MICSUPPORT | ||
2003 | if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && | ||
2004 | (ntohs(((u16 *)buffer)[6]) != 0x888E)) { | ||
2005 | MICBuffer pMic; | ||
2006 | |||
2007 | if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS) | ||
2008 | return ERROR; | ||
2009 | |||
2010 | *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); | ||
2011 | ai->txfids[0].tx_desc.len += sizeof(pMic); | ||
2012 | /* copy data into airo dma buffer */ | ||
2013 | memcpy (sendbuf, buffer, sizeof(etherHead)); | ||
2014 | buffer += sizeof(etherHead); | ||
2015 | sendbuf += sizeof(etherHead); | ||
2016 | memcpy (sendbuf, &pMic, sizeof(pMic)); | ||
2017 | sendbuf += sizeof(pMic); | ||
2018 | memcpy (sendbuf, buffer, len - sizeof(etherHead)); | ||
2019 | } else | ||
2020 | #endif | ||
2021 | { | ||
2022 | *payloadLen = cpu_to_le16(len - sizeof(etherHead)); | ||
2023 | |||
2024 | dev->trans_start = jiffies; | ||
2025 | |||
2026 | /* copy data into airo dma buffer */ | ||
2027 | memcpy(sendbuf, buffer, len); | ||
2028 | } | ||
2029 | |||
2030 | memcpy_toio(ai->txfids[0].card_ram_off, | ||
2031 | &ai->txfids[0].tx_desc, sizeof(TxFid)); | ||
2032 | |||
2033 | OUT4500(ai, EVACK, 8); | ||
2034 | |||
2035 | dev_kfree_skb_any(skb); | ||
2036 | return 1; | ||
2037 | } | ||
2038 | |||
2039 | static void get_tx_error(struct airo_info *ai, u32 fid) | ||
2040 | { | ||
2041 | u16 status; | ||
2042 | |||
2043 | if (fid < 0) | ||
2044 | status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status; | ||
2045 | else { | ||
2046 | if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS) | ||
2047 | return; | ||
2048 | bap_read(ai, &status, 2, BAP0); | ||
2049 | } | ||
2050 | if (le16_to_cpu(status) & 2) /* Too many retries */ | ||
2051 | ai->stats.tx_aborted_errors++; | ||
2052 | if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ | ||
2053 | ai->stats.tx_heartbeat_errors++; | ||
2054 | if (le16_to_cpu(status) & 8) /* Aid fail */ | ||
2055 | { } | ||
2056 | if (le16_to_cpu(status) & 0x10) /* MAC disabled */ | ||
2057 | ai->stats.tx_carrier_errors++; | ||
2058 | if (le16_to_cpu(status) & 0x20) /* Association lost */ | ||
2059 | { } | ||
2060 | /* We produce a TXDROP event only for retry or lifetime | ||
2061 | * exceeded, because that's the only status that really mean | ||
2062 | * that this particular node went away. | ||
2063 | * Other errors means that *we* screwed up. - Jean II */ | ||
2064 | if ((le16_to_cpu(status) & 2) || | ||
2065 | (le16_to_cpu(status) & 4)) { | ||
2066 | union iwreq_data wrqu; | ||
2067 | char junk[0x18]; | ||
2068 | |||
2069 | /* Faster to skip over useless data than to do | ||
2070 | * another bap_setup(). We are at offset 0x6 and | ||
2071 | * need to go to 0x18 and read 6 bytes - Jean II */ | ||
2072 | bap_read(ai, (u16 *) junk, 0x18, BAP0); | ||
2073 | |||
2074 | /* Copy 802.11 dest address. | ||
2075 | * We use the 802.11 header because the frame may | ||
2076 | * not be 802.3 or may be mangled... | ||
2077 | * In Ad-Hoc mode, it will be the node address. | ||
2078 | * In managed mode, it will be most likely the AP addr | ||
2079 | * User space will figure out how to convert it to | ||
2080 | * whatever it needs (IP address or else). | ||
2081 | * - Jean II */ | ||
2082 | memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN); | ||
2083 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
2084 | |||
2085 | /* Send event to user space */ | ||
2086 | wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); | ||
2087 | } | ||
2088 | } | ||
2089 | |||
2090 | static void airo_end_xmit(struct net_device *dev) { | ||
2091 | u16 status; | ||
2092 | int i; | ||
2093 | struct airo_info *priv = dev->priv; | ||
2094 | struct sk_buff *skb = priv->xmit.skb; | ||
2095 | int fid = priv->xmit.fid; | ||
2096 | u32 *fids = priv->fids; | ||
2097 | |||
2098 | clear_bit(JOB_XMIT, &priv->flags); | ||
2099 | clear_bit(FLAG_PENDING_XMIT, &priv->flags); | ||
2100 | status = transmit_802_3_packet (priv, fids[fid], skb->data); | ||
2101 | up(&priv->sem); | ||
2102 | |||
2103 | i = 0; | ||
2104 | if ( status == SUCCESS ) { | ||
2105 | dev->trans_start = jiffies; | ||
2106 | for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); | ||
2107 | } else { | ||
2108 | priv->fids[fid] &= 0xffff; | ||
2109 | priv->stats.tx_window_errors++; | ||
2110 | } | ||
2111 | if (i < MAX_FIDS / 2) | ||
2112 | netif_wake_queue(dev); | ||
2113 | dev_kfree_skb(skb); | ||
2114 | } | ||
2115 | |||
2116 | static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { | ||
2117 | s16 len; | ||
2118 | int i, j; | ||
2119 | struct airo_info *priv = dev->priv; | ||
2120 | u32 *fids = priv->fids; | ||
2121 | |||
2122 | if ( skb == NULL ) { | ||
2123 | printk( KERN_ERR "airo: skb == NULL!!!\n" ); | ||
2124 | return 0; | ||
2125 | } | ||
2126 | |||
2127 | /* Find a vacant FID */ | ||
2128 | for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ ); | ||
2129 | for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ ); | ||
2130 | |||
2131 | if ( j >= MAX_FIDS / 2 ) { | ||
2132 | netif_stop_queue(dev); | ||
2133 | |||
2134 | if (i == MAX_FIDS / 2) { | ||
2135 | priv->stats.tx_fifo_errors++; | ||
2136 | return 1; | ||
2137 | } | ||
2138 | } | ||
2139 | /* check min length*/ | ||
2140 | len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
2141 | /* Mark fid as used & save length for later */ | ||
2142 | fids[i] |= (len << 16); | ||
2143 | priv->xmit.skb = skb; | ||
2144 | priv->xmit.fid = i; | ||
2145 | if (down_trylock(&priv->sem) != 0) { | ||
2146 | set_bit(FLAG_PENDING_XMIT, &priv->flags); | ||
2147 | netif_stop_queue(dev); | ||
2148 | set_bit(JOB_XMIT, &priv->flags); | ||
2149 | wake_up_interruptible(&priv->thr_wait); | ||
2150 | } else | ||
2151 | airo_end_xmit(dev); | ||
2152 | return 0; | ||
2153 | } | ||
2154 | |||
2155 | static void airo_end_xmit11(struct net_device *dev) { | ||
2156 | u16 status; | ||
2157 | int i; | ||
2158 | struct airo_info *priv = dev->priv; | ||
2159 | struct sk_buff *skb = priv->xmit11.skb; | ||
2160 | int fid = priv->xmit11.fid; | ||
2161 | u32 *fids = priv->fids; | ||
2162 | |||
2163 | clear_bit(JOB_XMIT11, &priv->flags); | ||
2164 | clear_bit(FLAG_PENDING_XMIT11, &priv->flags); | ||
2165 | status = transmit_802_11_packet (priv, fids[fid], skb->data); | ||
2166 | up(&priv->sem); | ||
2167 | |||
2168 | i = MAX_FIDS / 2; | ||
2169 | if ( status == SUCCESS ) { | ||
2170 | dev->trans_start = jiffies; | ||
2171 | for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); | ||
2172 | } else { | ||
2173 | priv->fids[fid] &= 0xffff; | ||
2174 | priv->stats.tx_window_errors++; | ||
2175 | } | ||
2176 | if (i < MAX_FIDS) | ||
2177 | netif_wake_queue(dev); | ||
2178 | dev_kfree_skb(skb); | ||
2179 | } | ||
2180 | |||
2181 | static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { | ||
2182 | s16 len; | ||
2183 | int i, j; | ||
2184 | struct airo_info *priv = dev->priv; | ||
2185 | u32 *fids = priv->fids; | ||
2186 | |||
2187 | if (test_bit(FLAG_MPI, &priv->flags)) { | ||
2188 | /* Not implemented yet for MPI350 */ | ||
2189 | netif_stop_queue(dev); | ||
2190 | return -ENETDOWN; | ||
2191 | } | ||
2192 | |||
2193 | if ( skb == NULL ) { | ||
2194 | printk( KERN_ERR "airo: skb == NULL!!!\n" ); | ||
2195 | return 0; | ||
2196 | } | ||
2197 | |||
2198 | /* Find a vacant FID */ | ||
2199 | for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ ); | ||
2200 | for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ ); | ||
2201 | |||
2202 | if ( j >= MAX_FIDS ) { | ||
2203 | netif_stop_queue(dev); | ||
2204 | |||
2205 | if (i == MAX_FIDS) { | ||
2206 | priv->stats.tx_fifo_errors++; | ||
2207 | return 1; | ||
2208 | } | ||
2209 | } | ||
2210 | /* check min length*/ | ||
2211 | len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
2212 | /* Mark fid as used & save length for later */ | ||
2213 | fids[i] |= (len << 16); | ||
2214 | priv->xmit11.skb = skb; | ||
2215 | priv->xmit11.fid = i; | ||
2216 | if (down_trylock(&priv->sem) != 0) { | ||
2217 | set_bit(FLAG_PENDING_XMIT11, &priv->flags); | ||
2218 | netif_stop_queue(dev); | ||
2219 | set_bit(JOB_XMIT11, &priv->flags); | ||
2220 | wake_up_interruptible(&priv->thr_wait); | ||
2221 | } else | ||
2222 | airo_end_xmit11(dev); | ||
2223 | return 0; | ||
2224 | } | ||
2225 | |||
2226 | static void airo_read_stats(struct airo_info *ai) { | ||
2227 | StatsRid stats_rid; | ||
2228 | u32 *vals = stats_rid.vals; | ||
2229 | |||
2230 | clear_bit(JOB_STATS, &ai->flags); | ||
2231 | if (ai->power) { | ||
2232 | up(&ai->sem); | ||
2233 | return; | ||
2234 | } | ||
2235 | readStatsRid(ai, &stats_rid, RID_STATS, 0); | ||
2236 | up(&ai->sem); | ||
2237 | |||
2238 | ai->stats.rx_packets = vals[43] + vals[44] + vals[45]; | ||
2239 | ai->stats.tx_packets = vals[39] + vals[40] + vals[41]; | ||
2240 | ai->stats.rx_bytes = vals[92]; | ||
2241 | ai->stats.tx_bytes = vals[91]; | ||
2242 | ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4]; | ||
2243 | ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors; | ||
2244 | ai->stats.multicast = vals[43]; | ||
2245 | ai->stats.collisions = vals[89]; | ||
2246 | |||
2247 | /* detailed rx_errors: */ | ||
2248 | ai->stats.rx_length_errors = vals[3]; | ||
2249 | ai->stats.rx_crc_errors = vals[4]; | ||
2250 | ai->stats.rx_frame_errors = vals[2]; | ||
2251 | ai->stats.rx_fifo_errors = vals[0]; | ||
2252 | } | ||
2253 | |||
2254 | struct net_device_stats *airo_get_stats(struct net_device *dev) | ||
2255 | { | ||
2256 | struct airo_info *local = dev->priv; | ||
2257 | |||
2258 | if (!test_bit(JOB_STATS, &local->flags)) { | ||
2259 | /* Get stats out of the card if available */ | ||
2260 | if (down_trylock(&local->sem) != 0) { | ||
2261 | set_bit(JOB_STATS, &local->flags); | ||
2262 | wake_up_interruptible(&local->thr_wait); | ||
2263 | } else | ||
2264 | airo_read_stats(local); | ||
2265 | } | ||
2266 | |||
2267 | return &local->stats; | ||
2268 | } | ||
2269 | |||
2270 | static void airo_set_promisc(struct airo_info *ai) { | ||
2271 | Cmd cmd; | ||
2272 | Resp rsp; | ||
2273 | |||
2274 | memset(&cmd, 0, sizeof(cmd)); | ||
2275 | cmd.cmd=CMD_SETMODE; | ||
2276 | clear_bit(JOB_PROMISC, &ai->flags); | ||
2277 | cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; | ||
2278 | issuecommand(ai, &cmd, &rsp); | ||
2279 | up(&ai->sem); | ||
2280 | } | ||
2281 | |||
2282 | static void airo_set_multicast_list(struct net_device *dev) { | ||
2283 | struct airo_info *ai = dev->priv; | ||
2284 | |||
2285 | if ((dev->flags ^ ai->flags) & IFF_PROMISC) { | ||
2286 | change_bit(FLAG_PROMISC, &ai->flags); | ||
2287 | if (down_trylock(&ai->sem) != 0) { | ||
2288 | set_bit(JOB_PROMISC, &ai->flags); | ||
2289 | wake_up_interruptible(&ai->thr_wait); | ||
2290 | } else | ||
2291 | airo_set_promisc(ai); | ||
2292 | } | ||
2293 | |||
2294 | if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) { | ||
2295 | /* Turn on multicast. (Should be already setup...) */ | ||
2296 | } | ||
2297 | } | ||
2298 | |||
2299 | static int airo_set_mac_address(struct net_device *dev, void *p) | ||
2300 | { | ||
2301 | struct airo_info *ai = dev->priv; | ||
2302 | struct sockaddr *addr = p; | ||
2303 | Resp rsp; | ||
2304 | |||
2305 | readConfigRid(ai, 1); | ||
2306 | memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); | ||
2307 | set_bit (FLAG_COMMIT, &ai->flags); | ||
2308 | disable_MAC(ai, 1); | ||
2309 | writeConfigRid (ai, 1); | ||
2310 | enable_MAC(ai, &rsp, 1); | ||
2311 | memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len); | ||
2312 | if (ai->wifidev) | ||
2313 | memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len); | ||
2314 | return 0; | ||
2315 | } | ||
2316 | |||
2317 | static int airo_change_mtu(struct net_device *dev, int new_mtu) | ||
2318 | { | ||
2319 | if ((new_mtu < 68) || (new_mtu > 2400)) | ||
2320 | return -EINVAL; | ||
2321 | dev->mtu = new_mtu; | ||
2322 | return 0; | ||
2323 | } | ||
2324 | |||
2325 | |||
2326 | static int airo_close(struct net_device *dev) { | ||
2327 | struct airo_info *ai = dev->priv; | ||
2328 | |||
2329 | netif_stop_queue(dev); | ||
2330 | |||
2331 | if (ai->wifidev != dev) { | ||
2332 | #ifdef POWER_ON_DOWN | ||
2333 | /* Shut power to the card. The idea is that the user can save | ||
2334 | * power when he doesn't need the card with "ifconfig down". | ||
2335 | * That's the method that is most friendly towards the network | ||
2336 | * stack (i.e. the network stack won't try to broadcast | ||
2337 | * anything on the interface and routes are gone. Jean II */ | ||
2338 | set_bit(FLAG_RADIO_DOWN, &ai->flags); | ||
2339 | disable_MAC(ai, 1); | ||
2340 | #endif | ||
2341 | disable_interrupts( ai ); | ||
2342 | } | ||
2343 | return 0; | ||
2344 | } | ||
2345 | |||
2346 | static void del_airo_dev( struct net_device *dev ); | ||
2347 | |||
2348 | void stop_airo_card( struct net_device *dev, int freeres ) | ||
2349 | { | ||
2350 | struct airo_info *ai = dev->priv; | ||
2351 | |||
2352 | set_bit(FLAG_RADIO_DOWN, &ai->flags); | ||
2353 | disable_MAC(ai, 1); | ||
2354 | disable_interrupts(ai); | ||
2355 | free_irq( dev->irq, dev ); | ||
2356 | takedown_proc_entry( dev, ai ); | ||
2357 | if (test_bit(FLAG_REGISTERED, &ai->flags)) { | ||
2358 | unregister_netdev( dev ); | ||
2359 | if (ai->wifidev) { | ||
2360 | unregister_netdev(ai->wifidev); | ||
2361 | free_netdev(ai->wifidev); | ||
2362 | ai->wifidev = NULL; | ||
2363 | } | ||
2364 | clear_bit(FLAG_REGISTERED, &ai->flags); | ||
2365 | } | ||
2366 | set_bit(JOB_DIE, &ai->flags); | ||
2367 | kill_proc(ai->thr_pid, SIGTERM, 1); | ||
2368 | wait_for_completion(&ai->thr_exited); | ||
2369 | |||
2370 | /* | ||
2371 | * Clean out tx queue | ||
2372 | */ | ||
2373 | if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) { | ||
2374 | struct sk_buff *skb = NULL; | ||
2375 | for (;(skb = skb_dequeue(&ai->txq));) | ||
2376 | dev_kfree_skb(skb); | ||
2377 | } | ||
2378 | |||
2379 | if (ai->flash) | ||
2380 | kfree(ai->flash); | ||
2381 | if (ai->rssi) | ||
2382 | kfree(ai->rssi); | ||
2383 | if (ai->APList) | ||
2384 | kfree(ai->APList); | ||
2385 | if (ai->SSID) | ||
2386 | kfree(ai->SSID); | ||
2387 | if (freeres) { | ||
2388 | /* PCMCIA frees this stuff, so only for PCI and ISA */ | ||
2389 | release_region( dev->base_addr, 64 ); | ||
2390 | if (test_bit(FLAG_MPI, &ai->flags)) { | ||
2391 | if (ai->pci) | ||
2392 | mpi_unmap_card(ai->pci); | ||
2393 | if (ai->pcimem) | ||
2394 | iounmap(ai->pcimem); | ||
2395 | if (ai->pciaux) | ||
2396 | iounmap(ai->pciaux); | ||
2397 | pci_free_consistent(ai->pci, PCI_SHARED_LEN, | ||
2398 | ai->shared, ai->shared_dma); | ||
2399 | } | ||
2400 | } | ||
2401 | #ifdef MICSUPPORT | ||
2402 | if (ai->tfm) | ||
2403 | crypto_free_tfm(ai->tfm); | ||
2404 | #endif | ||
2405 | del_airo_dev( dev ); | ||
2406 | free_netdev( dev ); | ||
2407 | } | ||
2408 | |||
2409 | EXPORT_SYMBOL(stop_airo_card); | ||
2410 | |||
2411 | static int add_airo_dev( struct net_device *dev ); | ||
2412 | |||
2413 | int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
2414 | { | ||
2415 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); | ||
2416 | return ETH_ALEN; | ||
2417 | } | ||
2418 | |||
2419 | static void mpi_unmap_card(struct pci_dev *pci) | ||
2420 | { | ||
2421 | unsigned long mem_start = pci_resource_start(pci, 1); | ||
2422 | unsigned long mem_len = pci_resource_len(pci, 1); | ||
2423 | unsigned long aux_start = pci_resource_start(pci, 2); | ||
2424 | unsigned long aux_len = AUXMEMSIZE; | ||
2425 | |||
2426 | release_mem_region(aux_start, aux_len); | ||
2427 | release_mem_region(mem_start, mem_len); | ||
2428 | } | ||
2429 | |||
2430 | /************************************************************* | ||
2431 | * This routine assumes that descriptors have been setup . | ||
2432 | * Run at insmod time or after reset when the decriptors | ||
2433 | * have been initialized . Returns 0 if all is well nz | ||
2434 | * otherwise . Does not allocate memory but sets up card | ||
2435 | * using previously allocated descriptors. | ||
2436 | */ | ||
2437 | static int mpi_init_descriptors (struct airo_info *ai) | ||
2438 | { | ||
2439 | Cmd cmd; | ||
2440 | Resp rsp; | ||
2441 | int i; | ||
2442 | int rc = SUCCESS; | ||
2443 | |||
2444 | /* Alloc card RX descriptors */ | ||
2445 | netif_stop_queue(ai->dev); | ||
2446 | |||
2447 | memset(&rsp,0,sizeof(rsp)); | ||
2448 | memset(&cmd,0,sizeof(cmd)); | ||
2449 | |||
2450 | cmd.cmd = CMD_ALLOCATEAUX; | ||
2451 | cmd.parm0 = FID_RX; | ||
2452 | cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux); | ||
2453 | cmd.parm2 = MPI_MAX_FIDS; | ||
2454 | rc=issuecommand(ai, &cmd, &rsp); | ||
2455 | if (rc != SUCCESS) { | ||
2456 | printk(KERN_ERR "airo: Couldn't allocate RX FID\n"); | ||
2457 | return rc; | ||
2458 | } | ||
2459 | |||
2460 | for (i=0; i<MPI_MAX_FIDS; i++) { | ||
2461 | memcpy_toio(ai->rxfids[i].card_ram_off, | ||
2462 | &ai->rxfids[i].rx_desc, sizeof(RxFid)); | ||
2463 | } | ||
2464 | |||
2465 | /* Alloc card TX descriptors */ | ||
2466 | |||
2467 | memset(&rsp,0,sizeof(rsp)); | ||
2468 | memset(&cmd,0,sizeof(cmd)); | ||
2469 | |||
2470 | cmd.cmd = CMD_ALLOCATEAUX; | ||
2471 | cmd.parm0 = FID_TX; | ||
2472 | cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux); | ||
2473 | cmd.parm2 = MPI_MAX_FIDS; | ||
2474 | |||
2475 | for (i=0; i<MPI_MAX_FIDS; i++) { | ||
2476 | ai->txfids[i].tx_desc.valid = 1; | ||
2477 | memcpy_toio(ai->txfids[i].card_ram_off, | ||
2478 | &ai->txfids[i].tx_desc, sizeof(TxFid)); | ||
2479 | } | ||
2480 | ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ | ||
2481 | |||
2482 | rc=issuecommand(ai, &cmd, &rsp); | ||
2483 | if (rc != SUCCESS) { | ||
2484 | printk(KERN_ERR "airo: Couldn't allocate TX FID\n"); | ||
2485 | return rc; | ||
2486 | } | ||
2487 | |||
2488 | /* Alloc card Rid descriptor */ | ||
2489 | memset(&rsp,0,sizeof(rsp)); | ||
2490 | memset(&cmd,0,sizeof(cmd)); | ||
2491 | |||
2492 | cmd.cmd = CMD_ALLOCATEAUX; | ||
2493 | cmd.parm0 = RID_RW; | ||
2494 | cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux); | ||
2495 | cmd.parm2 = 1; /* Magic number... */ | ||
2496 | rc=issuecommand(ai, &cmd, &rsp); | ||
2497 | if (rc != SUCCESS) { | ||
2498 | printk(KERN_ERR "airo: Couldn't allocate RID\n"); | ||
2499 | return rc; | ||
2500 | } | ||
2501 | |||
2502 | memcpy_toio(ai->config_desc.card_ram_off, | ||
2503 | &ai->config_desc.rid_desc, sizeof(Rid)); | ||
2504 | |||
2505 | return rc; | ||
2506 | } | ||
2507 | |||
2508 | /* | ||
2509 | * We are setting up three things here: | ||
2510 | * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid. | ||
2511 | * 2) Map PCI memory for issueing commands. | ||
2512 | * 3) Allocate memory (shared) to send and receive ethernet frames. | ||
2513 | */ | ||
2514 | static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, | ||
2515 | const char *name) | ||
2516 | { | ||
2517 | unsigned long mem_start, mem_len, aux_start, aux_len; | ||
2518 | int rc = -1; | ||
2519 | int i; | ||
2520 | unsigned char *busaddroff,*vpackoff; | ||
2521 | unsigned char __iomem *pciaddroff; | ||
2522 | |||
2523 | mem_start = pci_resource_start(pci, 1); | ||
2524 | mem_len = pci_resource_len(pci, 1); | ||
2525 | aux_start = pci_resource_start(pci, 2); | ||
2526 | aux_len = AUXMEMSIZE; | ||
2527 | |||
2528 | if (!request_mem_region(mem_start, mem_len, name)) { | ||
2529 | printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n", | ||
2530 | (int)mem_start, (int)mem_len, name); | ||
2531 | goto out; | ||
2532 | } | ||
2533 | if (!request_mem_region(aux_start, aux_len, name)) { | ||
2534 | printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n", | ||
2535 | (int)aux_start, (int)aux_len, name); | ||
2536 | goto free_region1; | ||
2537 | } | ||
2538 | |||
2539 | ai->pcimem = ioremap(mem_start, mem_len); | ||
2540 | if (!ai->pcimem) { | ||
2541 | printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n", | ||
2542 | (int)mem_start, (int)mem_len, name); | ||
2543 | goto free_region2; | ||
2544 | } | ||
2545 | ai->pciaux = ioremap(aux_start, aux_len); | ||
2546 | if (!ai->pciaux) { | ||
2547 | printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n", | ||
2548 | (int)aux_start, (int)aux_len, name); | ||
2549 | goto free_memmap; | ||
2550 | } | ||
2551 | |||
2552 | /* Reserve PKTSIZE for each fid and 2K for the Rids */ | ||
2553 | ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma); | ||
2554 | if (!ai->shared) { | ||
2555 | printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n", | ||
2556 | PCI_SHARED_LEN); | ||
2557 | goto free_auxmap; | ||
2558 | } | ||
2559 | |||
2560 | /* | ||
2561 | * Setup descriptor RX, TX, CONFIG | ||
2562 | */ | ||
2563 | busaddroff = (unsigned char *)ai->shared_dma; | ||
2564 | pciaddroff = ai->pciaux + AUX_OFFSET; | ||
2565 | vpackoff = ai->shared; | ||
2566 | |||
2567 | /* RX descriptor setup */ | ||
2568 | for(i = 0; i < MPI_MAX_FIDS; i++) { | ||
2569 | ai->rxfids[i].pending = 0; | ||
2570 | ai->rxfids[i].card_ram_off = pciaddroff; | ||
2571 | ai->rxfids[i].virtual_host_addr = vpackoff; | ||
2572 | ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff; | ||
2573 | ai->rxfids[i].rx_desc.valid = 1; | ||
2574 | ai->rxfids[i].rx_desc.len = PKTSIZE; | ||
2575 | ai->rxfids[i].rx_desc.rdy = 0; | ||
2576 | |||
2577 | pciaddroff += sizeof(RxFid); | ||
2578 | busaddroff += PKTSIZE; | ||
2579 | vpackoff += PKTSIZE; | ||
2580 | } | ||
2581 | |||
2582 | /* TX descriptor setup */ | ||
2583 | for(i = 0; i < MPI_MAX_FIDS; i++) { | ||
2584 | ai->txfids[i].card_ram_off = pciaddroff; | ||
2585 | ai->txfids[i].virtual_host_addr = vpackoff; | ||
2586 | ai->txfids[i].tx_desc.valid = 1; | ||
2587 | ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff; | ||
2588 | memcpy(ai->txfids[i].virtual_host_addr, | ||
2589 | &wifictlhdr8023, sizeof(wifictlhdr8023)); | ||
2590 | |||
2591 | pciaddroff += sizeof(TxFid); | ||
2592 | busaddroff += PKTSIZE; | ||
2593 | vpackoff += PKTSIZE; | ||
2594 | } | ||
2595 | ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ | ||
2596 | |||
2597 | /* Rid descriptor setup */ | ||
2598 | ai->config_desc.card_ram_off = pciaddroff; | ||
2599 | ai->config_desc.virtual_host_addr = vpackoff; | ||
2600 | ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff; | ||
2601 | ai->ridbus = (dma_addr_t)busaddroff; | ||
2602 | ai->config_desc.rid_desc.rid = 0; | ||
2603 | ai->config_desc.rid_desc.len = RIDSIZE; | ||
2604 | ai->config_desc.rid_desc.valid = 1; | ||
2605 | pciaddroff += sizeof(Rid); | ||
2606 | busaddroff += RIDSIZE; | ||
2607 | vpackoff += RIDSIZE; | ||
2608 | |||
2609 | /* Tell card about descriptors */ | ||
2610 | if (mpi_init_descriptors (ai) != SUCCESS) | ||
2611 | goto free_shared; | ||
2612 | |||
2613 | return 0; | ||
2614 | free_shared: | ||
2615 | pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma); | ||
2616 | free_auxmap: | ||
2617 | iounmap(ai->pciaux); | ||
2618 | free_memmap: | ||
2619 | iounmap(ai->pcimem); | ||
2620 | free_region2: | ||
2621 | release_mem_region(aux_start, aux_len); | ||
2622 | free_region1: | ||
2623 | release_mem_region(mem_start, mem_len); | ||
2624 | out: | ||
2625 | return rc; | ||
2626 | } | ||
2627 | |||
2628 | static void wifi_setup(struct net_device *dev) | ||
2629 | { | ||
2630 | dev->hard_header = NULL; | ||
2631 | dev->rebuild_header = NULL; | ||
2632 | dev->hard_header_cache = NULL; | ||
2633 | dev->header_cache_update= NULL; | ||
2634 | |||
2635 | dev->hard_header_parse = wll_header_parse; | ||
2636 | dev->hard_start_xmit = &airo_start_xmit11; | ||
2637 | dev->get_stats = &airo_get_stats; | ||
2638 | dev->set_mac_address = &airo_set_mac_address; | ||
2639 | dev->do_ioctl = &airo_ioctl; | ||
2640 | #ifdef WIRELESS_EXT | ||
2641 | dev->wireless_handlers = &airo_handler_def; | ||
2642 | #endif /* WIRELESS_EXT */ | ||
2643 | dev->change_mtu = &airo_change_mtu; | ||
2644 | dev->open = &airo_open; | ||
2645 | dev->stop = &airo_close; | ||
2646 | |||
2647 | dev->type = ARPHRD_IEEE80211; | ||
2648 | dev->hard_header_len = ETH_HLEN; | ||
2649 | dev->mtu = 2312; | ||
2650 | dev->addr_len = ETH_ALEN; | ||
2651 | dev->tx_queue_len = 100; | ||
2652 | |||
2653 | memset(dev->broadcast,0xFF, ETH_ALEN); | ||
2654 | |||
2655 | dev->flags = IFF_BROADCAST|IFF_MULTICAST; | ||
2656 | } | ||
2657 | |||
2658 | static struct net_device *init_wifidev(struct airo_info *ai, | ||
2659 | struct net_device *ethdev) | ||
2660 | { | ||
2661 | int err; | ||
2662 | struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup); | ||
2663 | if (!dev) | ||
2664 | return NULL; | ||
2665 | dev->priv = ethdev->priv; | ||
2666 | dev->irq = ethdev->irq; | ||
2667 | dev->base_addr = ethdev->base_addr; | ||
2668 | #ifdef WIRELESS_EXT | ||
2669 | dev->wireless_data = ethdev->wireless_data; | ||
2670 | #endif /* WIRELESS_EXT */ | ||
2671 | memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); | ||
2672 | err = register_netdev(dev); | ||
2673 | if (err<0) { | ||
2674 | free_netdev(dev); | ||
2675 | return NULL; | ||
2676 | } | ||
2677 | return dev; | ||
2678 | } | ||
2679 | |||
2680 | int reset_card( struct net_device *dev , int lock) { | ||
2681 | struct airo_info *ai = dev->priv; | ||
2682 | |||
2683 | if (lock && down_interruptible(&ai->sem)) | ||
2684 | return -1; | ||
2685 | waitbusy (ai); | ||
2686 | OUT4500(ai,COMMAND,CMD_SOFTRESET); | ||
2687 | msleep(200); | ||
2688 | waitbusy (ai); | ||
2689 | msleep(200); | ||
2690 | if (lock) | ||
2691 | up(&ai->sem); | ||
2692 | return 0; | ||
2693 | } | ||
2694 | |||
2695 | struct net_device *_init_airo_card( unsigned short irq, int port, | ||
2696 | int is_pcmcia, struct pci_dev *pci, | ||
2697 | struct device *dmdev ) | ||
2698 | { | ||
2699 | struct net_device *dev; | ||
2700 | struct airo_info *ai; | ||
2701 | int i, rc; | ||
2702 | |||
2703 | /* Create the network device object. */ | ||
2704 | dev = alloc_etherdev(sizeof(*ai)); | ||
2705 | if (!dev) { | ||
2706 | printk(KERN_ERR "airo: Couldn't alloc_etherdev\n"); | ||
2707 | return NULL; | ||
2708 | } | ||
2709 | if (dev_alloc_name(dev, dev->name) < 0) { | ||
2710 | printk(KERN_ERR "airo: Couldn't get name!\n"); | ||
2711 | goto err_out_free; | ||
2712 | } | ||
2713 | |||
2714 | ai = dev->priv; | ||
2715 | ai->wifidev = NULL; | ||
2716 | ai->flags = 0; | ||
2717 | if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { | ||
2718 | printk(KERN_DEBUG "airo: Found an MPI350 card\n"); | ||
2719 | set_bit(FLAG_MPI, &ai->flags); | ||
2720 | } | ||
2721 | ai->dev = dev; | ||
2722 | spin_lock_init(&ai->aux_lock); | ||
2723 | sema_init(&ai->sem, 1); | ||
2724 | ai->config.len = 0; | ||
2725 | ai->pci = pci; | ||
2726 | init_waitqueue_head (&ai->thr_wait); | ||
2727 | init_completion (&ai->thr_exited); | ||
2728 | ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES); | ||
2729 | if (ai->thr_pid < 0) | ||
2730 | goto err_out_free; | ||
2731 | #ifdef MICSUPPORT | ||
2732 | ai->tfm = NULL; | ||
2733 | #endif | ||
2734 | rc = add_airo_dev( dev ); | ||
2735 | if (rc) | ||
2736 | goto err_out_thr; | ||
2737 | |||
2738 | /* The Airo-specific entries in the device structure. */ | ||
2739 | if (test_bit(FLAG_MPI,&ai->flags)) { | ||
2740 | skb_queue_head_init (&ai->txq); | ||
2741 | dev->hard_start_xmit = &mpi_start_xmit; | ||
2742 | } else | ||
2743 | dev->hard_start_xmit = &airo_start_xmit; | ||
2744 | dev->get_stats = &airo_get_stats; | ||
2745 | dev->set_multicast_list = &airo_set_multicast_list; | ||
2746 | dev->set_mac_address = &airo_set_mac_address; | ||
2747 | dev->do_ioctl = &airo_ioctl; | ||
2748 | #ifdef WIRELESS_EXT | ||
2749 | dev->wireless_handlers = &airo_handler_def; | ||
2750 | ai->wireless_data.spy_data = &ai->spy_data; | ||
2751 | dev->wireless_data = &ai->wireless_data; | ||
2752 | #endif /* WIRELESS_EXT */ | ||
2753 | dev->change_mtu = &airo_change_mtu; | ||
2754 | dev->open = &airo_open; | ||
2755 | dev->stop = &airo_close; | ||
2756 | dev->irq = irq; | ||
2757 | dev->base_addr = port; | ||
2758 | |||
2759 | SET_NETDEV_DEV(dev, dmdev); | ||
2760 | |||
2761 | |||
2762 | if (test_bit(FLAG_MPI,&ai->flags)) | ||
2763 | reset_card (dev, 1); | ||
2764 | |||
2765 | rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); | ||
2766 | if (rc) { | ||
2767 | printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc ); | ||
2768 | goto err_out_unlink; | ||
2769 | } | ||
2770 | if (!is_pcmcia) { | ||
2771 | if (!request_region( dev->base_addr, 64, dev->name )) { | ||
2772 | rc = -EBUSY; | ||
2773 | printk(KERN_ERR "airo: Couldn't request region\n"); | ||
2774 | goto err_out_irq; | ||
2775 | } | ||
2776 | } | ||
2777 | |||
2778 | if (test_bit(FLAG_MPI,&ai->flags)) { | ||
2779 | if (mpi_map_card(ai, pci, dev->name)) { | ||
2780 | printk(KERN_ERR "airo: Could not map memory\n"); | ||
2781 | goto err_out_res; | ||
2782 | } | ||
2783 | } | ||
2784 | |||
2785 | if (probe) { | ||
2786 | if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) { | ||
2787 | printk( KERN_ERR "airo: MAC could not be enabled\n" ); | ||
2788 | rc = -EIO; | ||
2789 | goto err_out_map; | ||
2790 | } | ||
2791 | } else if (!test_bit(FLAG_MPI,&ai->flags)) { | ||
2792 | ai->bap_read = fast_bap_read; | ||
2793 | set_bit(FLAG_FLASHING, &ai->flags); | ||
2794 | } | ||
2795 | |||
2796 | rc = register_netdev(dev); | ||
2797 | if (rc) { | ||
2798 | printk(KERN_ERR "airo: Couldn't register_netdev\n"); | ||
2799 | goto err_out_map; | ||
2800 | } | ||
2801 | ai->wifidev = init_wifidev(ai, dev); | ||
2802 | |||
2803 | set_bit(FLAG_REGISTERED,&ai->flags); | ||
2804 | printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", | ||
2805 | dev->name, | ||
2806 | dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], | ||
2807 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); | ||
2808 | |||
2809 | /* Allocate the transmit buffers */ | ||
2810 | if (probe && !test_bit(FLAG_MPI,&ai->flags)) | ||
2811 | for( i = 0; i < MAX_FIDS; i++ ) | ||
2812 | ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2); | ||
2813 | |||
2814 | setup_proc_entry( dev, dev->priv ); /* XXX check for failure */ | ||
2815 | netif_start_queue(dev); | ||
2816 | SET_MODULE_OWNER(dev); | ||
2817 | return dev; | ||
2818 | |||
2819 | err_out_map: | ||
2820 | if (test_bit(FLAG_MPI,&ai->flags) && pci) { | ||
2821 | pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma); | ||
2822 | iounmap(ai->pciaux); | ||
2823 | iounmap(ai->pcimem); | ||
2824 | mpi_unmap_card(ai->pci); | ||
2825 | } | ||
2826 | err_out_res: | ||
2827 | if (!is_pcmcia) | ||
2828 | release_region( dev->base_addr, 64 ); | ||
2829 | err_out_irq: | ||
2830 | free_irq(dev->irq, dev); | ||
2831 | err_out_unlink: | ||
2832 | del_airo_dev(dev); | ||
2833 | err_out_thr: | ||
2834 | set_bit(JOB_DIE, &ai->flags); | ||
2835 | kill_proc(ai->thr_pid, SIGTERM, 1); | ||
2836 | wait_for_completion(&ai->thr_exited); | ||
2837 | err_out_free: | ||
2838 | free_netdev(dev); | ||
2839 | return NULL; | ||
2840 | } | ||
2841 | |||
2842 | struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia, | ||
2843 | struct device *dmdev) | ||
2844 | { | ||
2845 | return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev); | ||
2846 | } | ||
2847 | |||
2848 | EXPORT_SYMBOL(init_airo_card); | ||
2849 | |||
2850 | static int waitbusy (struct airo_info *ai) { | ||
2851 | int delay = 0; | ||
2852 | while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) { | ||
2853 | udelay (10); | ||
2854 | if ((++delay % 20) == 0) | ||
2855 | OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); | ||
2856 | } | ||
2857 | return delay < 10000; | ||
2858 | } | ||
2859 | |||
2860 | int reset_airo_card( struct net_device *dev ) | ||
2861 | { | ||
2862 | int i; | ||
2863 | struct airo_info *ai = dev->priv; | ||
2864 | |||
2865 | if (reset_card (dev, 1)) | ||
2866 | return -1; | ||
2867 | |||
2868 | if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) { | ||
2869 | printk( KERN_ERR "airo: MAC could not be enabled\n" ); | ||
2870 | return -1; | ||
2871 | } | ||
2872 | printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name, | ||
2873 | dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], | ||
2874 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); | ||
2875 | /* Allocate the transmit buffers if needed */ | ||
2876 | if (!test_bit(FLAG_MPI,&ai->flags)) | ||
2877 | for( i = 0; i < MAX_FIDS; i++ ) | ||
2878 | ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2); | ||
2879 | |||
2880 | enable_interrupts( ai ); | ||
2881 | netif_wake_queue(dev); | ||
2882 | return 0; | ||
2883 | } | ||
2884 | |||
2885 | EXPORT_SYMBOL(reset_airo_card); | ||
2886 | |||
2887 | static void airo_send_event(struct net_device *dev) { | ||
2888 | struct airo_info *ai = dev->priv; | ||
2889 | union iwreq_data wrqu; | ||
2890 | StatusRid status_rid; | ||
2891 | |||
2892 | clear_bit(JOB_EVENT, &ai->flags); | ||
2893 | PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); | ||
2894 | up(&ai->sem); | ||
2895 | wrqu.data.length = 0; | ||
2896 | wrqu.data.flags = 0; | ||
2897 | memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN); | ||
2898 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
2899 | |||
2900 | /* Send event to user space */ | ||
2901 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | ||
2902 | } | ||
2903 | |||
2904 | static int airo_thread(void *data) { | ||
2905 | struct net_device *dev = data; | ||
2906 | struct airo_info *ai = dev->priv; | ||
2907 | int locked; | ||
2908 | |||
2909 | daemonize("%s", dev->name); | ||
2910 | allow_signal(SIGTERM); | ||
2911 | |||
2912 | while(1) { | ||
2913 | if (signal_pending(current)) | ||
2914 | flush_signals(current); | ||
2915 | |||
2916 | /* make swsusp happy with our thread */ | ||
2917 | try_to_freeze(PF_FREEZE); | ||
2918 | |||
2919 | if (test_bit(JOB_DIE, &ai->flags)) | ||
2920 | break; | ||
2921 | |||
2922 | if (ai->flags & JOB_MASK) { | ||
2923 | locked = down_interruptible(&ai->sem); | ||
2924 | } else { | ||
2925 | wait_queue_t wait; | ||
2926 | |||
2927 | init_waitqueue_entry(&wait, current); | ||
2928 | add_wait_queue(&ai->thr_wait, &wait); | ||
2929 | for (;;) { | ||
2930 | set_current_state(TASK_INTERRUPTIBLE); | ||
2931 | if (ai->flags & JOB_MASK) | ||
2932 | break; | ||
2933 | if (ai->expires) { | ||
2934 | if (time_after_eq(jiffies,ai->expires)){ | ||
2935 | set_bit(JOB_AUTOWEP,&ai->flags); | ||
2936 | break; | ||
2937 | } | ||
2938 | if (!signal_pending(current)) { | ||
2939 | schedule_timeout(ai->expires - jiffies); | ||
2940 | continue; | ||
2941 | } | ||
2942 | } else if (!signal_pending(current)) { | ||
2943 | schedule(); | ||
2944 | continue; | ||
2945 | } | ||
2946 | break; | ||
2947 | } | ||
2948 | current->state = TASK_RUNNING; | ||
2949 | remove_wait_queue(&ai->thr_wait, &wait); | ||
2950 | locked = 1; | ||
2951 | } | ||
2952 | |||
2953 | if (locked) | ||
2954 | continue; | ||
2955 | |||
2956 | if (test_bit(JOB_DIE, &ai->flags)) { | ||
2957 | up(&ai->sem); | ||
2958 | break; | ||
2959 | } | ||
2960 | |||
2961 | if (ai->power || test_bit(FLAG_FLASHING, &ai->flags)) { | ||
2962 | up(&ai->sem); | ||
2963 | continue; | ||
2964 | } | ||
2965 | |||
2966 | if (test_bit(JOB_XMIT, &ai->flags)) | ||
2967 | airo_end_xmit(dev); | ||
2968 | else if (test_bit(JOB_XMIT11, &ai->flags)) | ||
2969 | airo_end_xmit11(dev); | ||
2970 | else if (test_bit(JOB_STATS, &ai->flags)) | ||
2971 | airo_read_stats(ai); | ||
2972 | else if (test_bit(JOB_WSTATS, &ai->flags)) | ||
2973 | airo_read_wireless_stats(ai); | ||
2974 | else if (test_bit(JOB_PROMISC, &ai->flags)) | ||
2975 | airo_set_promisc(ai); | ||
2976 | #ifdef MICSUPPORT | ||
2977 | else if (test_bit(JOB_MIC, &ai->flags)) | ||
2978 | micinit(ai); | ||
2979 | #endif | ||
2980 | else if (test_bit(JOB_EVENT, &ai->flags)) | ||
2981 | airo_send_event(dev); | ||
2982 | else if (test_bit(JOB_AUTOWEP, &ai->flags)) | ||
2983 | timer_func(dev); | ||
2984 | } | ||
2985 | complete_and_exit (&ai->thr_exited, 0); | ||
2986 | } | ||
2987 | |||
2988 | static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) { | ||
2989 | struct net_device *dev = (struct net_device *)dev_id; | ||
2990 | u16 status; | ||
2991 | u16 fid; | ||
2992 | struct airo_info *apriv = dev->priv; | ||
2993 | u16 savedInterrupts = 0; | ||
2994 | int handled = 0; | ||
2995 | |||
2996 | if (!netif_device_present(dev)) | ||
2997 | return IRQ_NONE; | ||
2998 | |||
2999 | for (;;) { | ||
3000 | status = IN4500( apriv, EVSTAT ); | ||
3001 | if ( !(status & STATUS_INTS) || status == 0xffff ) break; | ||
3002 | |||
3003 | handled = 1; | ||
3004 | |||
3005 | if ( status & EV_AWAKE ) { | ||
3006 | OUT4500( apriv, EVACK, EV_AWAKE ); | ||
3007 | OUT4500( apriv, EVACK, EV_AWAKE ); | ||
3008 | } | ||
3009 | |||
3010 | if (!savedInterrupts) { | ||
3011 | savedInterrupts = IN4500( apriv, EVINTEN ); | ||
3012 | OUT4500( apriv, EVINTEN, 0 ); | ||
3013 | } | ||
3014 | |||
3015 | if ( status & EV_MIC ) { | ||
3016 | OUT4500( apriv, EVACK, EV_MIC ); | ||
3017 | #ifdef MICSUPPORT | ||
3018 | if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) { | ||
3019 | set_bit(JOB_MIC, &apriv->flags); | ||
3020 | wake_up_interruptible(&apriv->thr_wait); | ||
3021 | } | ||
3022 | #endif | ||
3023 | } | ||
3024 | if ( status & EV_LINK ) { | ||
3025 | union iwreq_data wrqu; | ||
3026 | /* The link status has changed, if you want to put a | ||
3027 | monitor hook in, do it here. (Remember that | ||
3028 | interrupts are still disabled!) | ||
3029 | */ | ||
3030 | u16 newStatus = IN4500(apriv, LINKSTAT); | ||
3031 | OUT4500( apriv, EVACK, EV_LINK); | ||
3032 | /* Here is what newStatus means: */ | ||
3033 | #define NOBEACON 0x8000 /* Loss of sync - missed beacons */ | ||
3034 | #define MAXRETRIES 0x8001 /* Loss of sync - max retries */ | ||
3035 | #define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ | ||
3036 | #define FORCELOSS 0x8003 /* Loss of sync - host request */ | ||
3037 | #define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ | ||
3038 | #define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */ | ||
3039 | #define DISASS 0x8200 /* Disassociation (low byte is reason code) */ | ||
3040 | #define ASSFAIL 0x8400 /* Association failure (low byte is reason | ||
3041 | code) */ | ||
3042 | #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason | ||
3043 | code) */ | ||
3044 | #define ASSOCIATED 0x0400 /* Assocatied */ | ||
3045 | #define RC_RESERVED 0 /* Reserved return code */ | ||
3046 | #define RC_NOREASON 1 /* Unspecified reason */ | ||
3047 | #define RC_AUTHINV 2 /* Previous authentication invalid */ | ||
3048 | #define RC_DEAUTH 3 /* Deauthenticated because sending station is | ||
3049 | leaving */ | ||
3050 | #define RC_NOACT 4 /* Disassociated due to inactivity */ | ||
3051 | #define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle | ||
3052 | all currently associated stations */ | ||
3053 | #define RC_BADCLASS2 6 /* Class 2 frame received from | ||
3054 | non-Authenticated station */ | ||
3055 | #define RC_BADCLASS3 7 /* Class 3 frame received from | ||
3056 | non-Associated station */ | ||
3057 | #define RC_STATLEAVE 8 /* Disassociated because sending station is | ||
3058 | leaving BSS */ | ||
3059 | #define RC_NOAUTH 9 /* Station requesting (Re)Association is not | ||
3060 | Authenticated with the responding station */ | ||
3061 | if (newStatus != ASSOCIATED) { | ||
3062 | if (auto_wep && !apriv->expires) { | ||
3063 | apriv->expires = RUN_AT(3*HZ); | ||
3064 | wake_up_interruptible(&apriv->thr_wait); | ||
3065 | } | ||
3066 | } else { | ||
3067 | struct task_struct *task = apriv->task; | ||
3068 | if (auto_wep) | ||
3069 | apriv->expires = 0; | ||
3070 | if (task) | ||
3071 | wake_up_process (task); | ||
3072 | set_bit(FLAG_UPDATE_UNI, &apriv->flags); | ||
3073 | set_bit(FLAG_UPDATE_MULTI, &apriv->flags); | ||
3074 | } | ||
3075 | /* Question : is ASSOCIATED the only status | ||
3076 | * that is valid ? We want to catch handover | ||
3077 | * and reassociations as valid status | ||
3078 | * Jean II */ | ||
3079 | if(newStatus == ASSOCIATED) { | ||
3080 | if (apriv->scan_timestamp) { | ||
3081 | /* Send an empty event to user space. | ||
3082 | * We don't send the received data on | ||
3083 | * the event because it would require | ||
3084 | * us to do complex transcoding, and | ||
3085 | * we want to minimise the work done in | ||
3086 | * the irq handler. Use a request to | ||
3087 | * extract the data - Jean II */ | ||
3088 | wrqu.data.length = 0; | ||
3089 | wrqu.data.flags = 0; | ||
3090 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
3091 | apriv->scan_timestamp = 0; | ||
3092 | } | ||
3093 | if (down_trylock(&apriv->sem) != 0) { | ||
3094 | set_bit(JOB_EVENT, &apriv->flags); | ||
3095 | wake_up_interruptible(&apriv->thr_wait); | ||
3096 | } else | ||
3097 | airo_send_event(dev); | ||
3098 | } else { | ||
3099 | memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); | ||
3100 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
3101 | |||
3102 | /* Send event to user space */ | ||
3103 | wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); | ||
3104 | } | ||
3105 | } | ||
3106 | |||
3107 | /* Check to see if there is something to receive */ | ||
3108 | if ( status & EV_RX ) { | ||
3109 | struct sk_buff *skb = NULL; | ||
3110 | u16 fc, len, hdrlen = 0; | ||
3111 | #pragma pack(1) | ||
3112 | struct { | ||
3113 | u16 status, len; | ||
3114 | u8 rssi[2]; | ||
3115 | u8 rate; | ||
3116 | u8 freq; | ||
3117 | u16 tmp[4]; | ||
3118 | } hdr; | ||
3119 | #pragma pack() | ||
3120 | u16 gap; | ||
3121 | u16 tmpbuf[4]; | ||
3122 | u16 *buffer; | ||
3123 | |||
3124 | if (test_bit(FLAG_MPI,&apriv->flags)) { | ||
3125 | if (test_bit(FLAG_802_11, &apriv->flags)) | ||
3126 | mpi_receive_802_11(apriv); | ||
3127 | else | ||
3128 | mpi_receive_802_3(apriv); | ||
3129 | OUT4500(apriv, EVACK, EV_RX); | ||
3130 | goto exitrx; | ||
3131 | } | ||
3132 | |||
3133 | fid = IN4500( apriv, RXFID ); | ||
3134 | |||
3135 | /* Get the packet length */ | ||
3136 | if (test_bit(FLAG_802_11, &apriv->flags)) { | ||
3137 | bap_setup (apriv, fid, 4, BAP0); | ||
3138 | bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0); | ||
3139 | /* Bad CRC. Ignore packet */ | ||
3140 | if (le16_to_cpu(hdr.status) & 2) | ||
3141 | hdr.len = 0; | ||
3142 | if (apriv->wifidev == NULL) | ||
3143 | hdr.len = 0; | ||
3144 | } else { | ||
3145 | bap_setup (apriv, fid, 0x36, BAP0); | ||
3146 | bap_read (apriv, (u16*)&hdr.len, 2, BAP0); | ||
3147 | } | ||
3148 | len = le16_to_cpu(hdr.len); | ||
3149 | |||
3150 | if (len > 2312) { | ||
3151 | printk( KERN_ERR "airo: Bad size %d\n", len ); | ||
3152 | goto badrx; | ||
3153 | } | ||
3154 | if (len == 0) | ||
3155 | goto badrx; | ||
3156 | |||
3157 | if (test_bit(FLAG_802_11, &apriv->flags)) { | ||
3158 | bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); | ||
3159 | fc = le16_to_cpu(fc); | ||
3160 | switch (fc & 0xc) { | ||
3161 | case 4: | ||
3162 | if ((fc & 0xe0) == 0xc0) | ||
3163 | hdrlen = 10; | ||
3164 | else | ||
3165 | hdrlen = 16; | ||
3166 | break; | ||
3167 | case 8: | ||
3168 | if ((fc&0x300)==0x300){ | ||
3169 | hdrlen = 30; | ||
3170 | break; | ||
3171 | } | ||
3172 | default: | ||
3173 | hdrlen = 24; | ||
3174 | } | ||
3175 | } else | ||
3176 | hdrlen = ETH_ALEN * 2; | ||
3177 | |||
3178 | skb = dev_alloc_skb( len + hdrlen + 2 + 2 ); | ||
3179 | if ( !skb ) { | ||
3180 | apriv->stats.rx_dropped++; | ||
3181 | goto badrx; | ||
3182 | } | ||
3183 | skb_reserve(skb, 2); /* This way the IP header is aligned */ | ||
3184 | buffer = (u16*)skb_put (skb, len + hdrlen); | ||
3185 | if (test_bit(FLAG_802_11, &apriv->flags)) { | ||
3186 | buffer[0] = fc; | ||
3187 | bap_read (apriv, buffer + 1, hdrlen - 2, BAP0); | ||
3188 | if (hdrlen == 24) | ||
3189 | bap_read (apriv, tmpbuf, 6, BAP0); | ||
3190 | |||
3191 | bap_read (apriv, &gap, sizeof(gap), BAP0); | ||
3192 | gap = le16_to_cpu(gap); | ||
3193 | if (gap) { | ||
3194 | if (gap <= 8) | ||
3195 | bap_read (apriv, tmpbuf, gap, BAP0); | ||
3196 | else | ||
3197 | printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n"); | ||
3198 | } | ||
3199 | bap_read (apriv, buffer + hdrlen/2, len, BAP0); | ||
3200 | } else { | ||
3201 | #ifdef MICSUPPORT | ||
3202 | MICBuffer micbuf; | ||
3203 | #endif | ||
3204 | bap_read (apriv, buffer, ETH_ALEN*2, BAP0); | ||
3205 | #ifdef MICSUPPORT | ||
3206 | if (apriv->micstats.enabled) { | ||
3207 | bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0); | ||
3208 | if (ntohs(micbuf.typelen) > 0x05DC) | ||
3209 | bap_setup (apriv, fid, 0x44, BAP0); | ||
3210 | else { | ||
3211 | if (len <= sizeof(micbuf)) | ||
3212 | goto badmic; | ||
3213 | |||
3214 | len -= sizeof(micbuf); | ||
3215 | skb_trim (skb, len + hdrlen); | ||
3216 | } | ||
3217 | } | ||
3218 | #endif | ||
3219 | bap_read(apriv,buffer+ETH_ALEN,len,BAP0); | ||
3220 | #ifdef MICSUPPORT | ||
3221 | if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) { | ||
3222 | badmic: | ||
3223 | dev_kfree_skb_irq (skb); | ||
3224 | #else | ||
3225 | if (0) { | ||
3226 | #endif | ||
3227 | badrx: | ||
3228 | OUT4500( apriv, EVACK, EV_RX); | ||
3229 | goto exitrx; | ||
3230 | } | ||
3231 | } | ||
3232 | #ifdef WIRELESS_SPY | ||
3233 | if (apriv->spy_data.spy_number > 0) { | ||
3234 | char *sa; | ||
3235 | struct iw_quality wstats; | ||
3236 | /* Prepare spy data : addr + qual */ | ||
3237 | if (!test_bit(FLAG_802_11, &apriv->flags)) { | ||
3238 | sa = (char*)buffer + 6; | ||
3239 | bap_setup (apriv, fid, 8, BAP0); | ||
3240 | bap_read (apriv, (u16*)hdr.rssi, 2, BAP0); | ||
3241 | } else | ||
3242 | sa = (char*)buffer + 10; | ||
3243 | wstats.qual = hdr.rssi[0]; | ||
3244 | if (apriv->rssi) | ||
3245 | wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; | ||
3246 | else | ||
3247 | wstats.level = (hdr.rssi[1] + 321) / 2; | ||
3248 | wstats.updated = 3; | ||
3249 | /* Update spy records */ | ||
3250 | wireless_spy_update(dev, sa, &wstats); | ||
3251 | } | ||
3252 | #endif /* WIRELESS_SPY */ | ||
3253 | OUT4500( apriv, EVACK, EV_RX); | ||
3254 | |||
3255 | if (test_bit(FLAG_802_11, &apriv->flags)) { | ||
3256 | skb->mac.raw = skb->data; | ||
3257 | skb->pkt_type = PACKET_OTHERHOST; | ||
3258 | skb->dev = apriv->wifidev; | ||
3259 | skb->protocol = htons(ETH_P_802_2); | ||
3260 | } else { | ||
3261 | skb->dev = dev; | ||
3262 | skb->protocol = eth_type_trans(skb,dev); | ||
3263 | } | ||
3264 | skb->dev->last_rx = jiffies; | ||
3265 | skb->ip_summed = CHECKSUM_NONE; | ||
3266 | |||
3267 | netif_rx( skb ); | ||
3268 | } | ||
3269 | exitrx: | ||
3270 | |||
3271 | /* Check to see if a packet has been transmitted */ | ||
3272 | if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) { | ||
3273 | int i; | ||
3274 | int len = 0; | ||
3275 | int index = -1; | ||
3276 | |||
3277 | if (test_bit(FLAG_MPI,&apriv->flags)) { | ||
3278 | unsigned long flags; | ||
3279 | |||
3280 | if (status & EV_TXEXC) | ||
3281 | get_tx_error(apriv, -1); | ||
3282 | spin_lock_irqsave(&apriv->aux_lock, flags); | ||
3283 | if (skb_queue_len (&apriv->txq)) { | ||
3284 | spin_unlock_irqrestore(&apriv->aux_lock,flags); | ||
3285 | mpi_send_packet (dev); | ||
3286 | } else { | ||
3287 | clear_bit(FLAG_PENDING_XMIT, &apriv->flags); | ||
3288 | spin_unlock_irqrestore(&apriv->aux_lock,flags); | ||
3289 | netif_wake_queue (dev); | ||
3290 | } | ||
3291 | OUT4500( apriv, EVACK, | ||
3292 | status & (EV_TX|EV_TXCPY|EV_TXEXC)); | ||
3293 | goto exittx; | ||
3294 | } | ||
3295 | |||
3296 | fid = IN4500(apriv, TXCOMPLFID); | ||
3297 | |||
3298 | for( i = 0; i < MAX_FIDS; i++ ) { | ||
3299 | if ( ( apriv->fids[i] & 0xffff ) == fid ) { | ||
3300 | len = apriv->fids[i] >> 16; | ||
3301 | index = i; | ||
3302 | } | ||
3303 | } | ||
3304 | if (index != -1) { | ||
3305 | if (status & EV_TXEXC) | ||
3306 | get_tx_error(apriv, index); | ||
3307 | OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); | ||
3308 | /* Set up to be used again */ | ||
3309 | apriv->fids[index] &= 0xffff; | ||
3310 | if (index < MAX_FIDS / 2) { | ||
3311 | if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags)) | ||
3312 | netif_wake_queue(dev); | ||
3313 | } else { | ||
3314 | if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags)) | ||
3315 | netif_wake_queue(apriv->wifidev); | ||
3316 | } | ||
3317 | } else { | ||
3318 | OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); | ||
3319 | printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); | ||
3320 | } | ||
3321 | } | ||
3322 | exittx: | ||
3323 | if ( status & ~STATUS_INTS & ~IGNORE_INTS ) | ||
3324 | printk( KERN_WARNING "airo: Got weird status %x\n", | ||
3325 | status & ~STATUS_INTS & ~IGNORE_INTS ); | ||
3326 | } | ||
3327 | |||
3328 | if (savedInterrupts) | ||
3329 | OUT4500( apriv, EVINTEN, savedInterrupts ); | ||
3330 | |||
3331 | /* done.. */ | ||
3332 | return IRQ_RETVAL(handled); | ||
3333 | } | ||
3334 | |||
3335 | /* | ||
3336 | * Routines to talk to the card | ||
3337 | */ | ||
3338 | |||
3339 | /* | ||
3340 | * This was originally written for the 4500, hence the name | ||
3341 | * NOTE: If use with 8bit mode and SMP bad things will happen! | ||
3342 | * Why would some one do 8 bit IO in an SMP machine?!? | ||
3343 | */ | ||
3344 | static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) { | ||
3345 | if (test_bit(FLAG_MPI,&ai->flags)) | ||
3346 | reg <<= 1; | ||
3347 | if ( !do8bitIO ) | ||
3348 | outw( val, ai->dev->base_addr + reg ); | ||
3349 | else { | ||
3350 | outb( val & 0xff, ai->dev->base_addr + reg ); | ||
3351 | outb( val >> 8, ai->dev->base_addr + reg + 1 ); | ||
3352 | } | ||
3353 | } | ||
3354 | |||
3355 | static u16 IN4500( struct airo_info *ai, u16 reg ) { | ||
3356 | unsigned short rc; | ||
3357 | |||
3358 | if (test_bit(FLAG_MPI,&ai->flags)) | ||
3359 | reg <<= 1; | ||
3360 | if ( !do8bitIO ) | ||
3361 | rc = inw( ai->dev->base_addr + reg ); | ||
3362 | else { | ||
3363 | rc = inb( ai->dev->base_addr + reg ); | ||
3364 | rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8; | ||
3365 | } | ||
3366 | return rc; | ||
3367 | } | ||
3368 | |||
3369 | static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { | ||
3370 | int rc; | ||
3371 | Cmd cmd; | ||
3372 | |||
3373 | /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions | ||
3374 | * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" | ||
3375 | * Note : we could try to use !netif_running(dev) in enable_MAC() | ||
3376 | * instead of this flag, but I don't trust it *within* the | ||
3377 | * open/close functions, and testing both flags together is | ||
3378 | * "cheaper" - Jean II */ | ||
3379 | if (ai->flags & FLAG_RADIO_MASK) return SUCCESS; | ||
3380 | |||
3381 | if (lock && down_interruptible(&ai->sem)) | ||
3382 | return -ERESTARTSYS; | ||
3383 | |||
3384 | if (!test_bit(FLAG_ENABLED, &ai->flags)) { | ||
3385 | memset(&cmd, 0, sizeof(cmd)); | ||
3386 | cmd.cmd = MAC_ENABLE; | ||
3387 | rc = issuecommand(ai, &cmd, rsp); | ||
3388 | if (rc == SUCCESS) | ||
3389 | set_bit(FLAG_ENABLED, &ai->flags); | ||
3390 | } else | ||
3391 | rc = SUCCESS; | ||
3392 | |||
3393 | if (lock) | ||
3394 | up(&ai->sem); | ||
3395 | |||
3396 | if (rc) | ||
3397 | printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n", | ||
3398 | __FUNCTION__,rc); | ||
3399 | return rc; | ||
3400 | } | ||
3401 | |||
3402 | static void disable_MAC( struct airo_info *ai, int lock ) { | ||
3403 | Cmd cmd; | ||
3404 | Resp rsp; | ||
3405 | |||
3406 | if (lock && down_interruptible(&ai->sem)) | ||
3407 | return; | ||
3408 | |||
3409 | if (test_bit(FLAG_ENABLED, &ai->flags)) { | ||
3410 | memset(&cmd, 0, sizeof(cmd)); | ||
3411 | cmd.cmd = MAC_DISABLE; // disable in case already enabled | ||
3412 | issuecommand(ai, &cmd, &rsp); | ||
3413 | clear_bit(FLAG_ENABLED, &ai->flags); | ||
3414 | } | ||
3415 | if (lock) | ||
3416 | up(&ai->sem); | ||
3417 | } | ||
3418 | |||
3419 | static void enable_interrupts( struct airo_info *ai ) { | ||
3420 | /* Enable the interrupts */ | ||
3421 | OUT4500( ai, EVINTEN, STATUS_INTS ); | ||
3422 | } | ||
3423 | |||
3424 | static void disable_interrupts( struct airo_info *ai ) { | ||
3425 | OUT4500( ai, EVINTEN, 0 ); | ||
3426 | } | ||
3427 | |||
3428 | static void mpi_receive_802_3(struct airo_info *ai) | ||
3429 | { | ||
3430 | RxFid rxd; | ||
3431 | int len = 0; | ||
3432 | struct sk_buff *skb; | ||
3433 | char *buffer; | ||
3434 | #ifdef MICSUPPORT | ||
3435 | int off = 0; | ||
3436 | MICBuffer micbuf; | ||
3437 | #endif | ||
3438 | |||
3439 | memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); | ||
3440 | /* Make sure we got something */ | ||
3441 | if (rxd.rdy && rxd.valid == 0) { | ||
3442 | len = rxd.len + 12; | ||
3443 | if (len < 12 || len > 2048) | ||
3444 | goto badrx; | ||
3445 | |||
3446 | skb = dev_alloc_skb(len); | ||
3447 | if (!skb) { | ||
3448 | ai->stats.rx_dropped++; | ||
3449 | goto badrx; | ||
3450 | } | ||
3451 | buffer = skb_put(skb,len); | ||
3452 | #ifdef MICSUPPORT | ||
3453 | memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); | ||
3454 | if (ai->micstats.enabled) { | ||
3455 | memcpy(&micbuf, | ||
3456 | ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2, | ||
3457 | sizeof(micbuf)); | ||
3458 | if (ntohs(micbuf.typelen) <= 0x05DC) { | ||
3459 | if (len <= sizeof(micbuf) + ETH_ALEN * 2) | ||
3460 | goto badmic; | ||
3461 | |||
3462 | off = sizeof(micbuf); | ||
3463 | skb_trim (skb, len - off); | ||
3464 | } | ||
3465 | } | ||
3466 | memcpy(buffer + ETH_ALEN * 2, | ||
3467 | ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, | ||
3468 | len - ETH_ALEN * 2 - off); | ||
3469 | if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { | ||
3470 | badmic: | ||
3471 | dev_kfree_skb_irq (skb); | ||
3472 | goto badrx; | ||
3473 | } | ||
3474 | #else | ||
3475 | memcpy(buffer, ai->rxfids[0].virtual_host_addr, len); | ||
3476 | #endif | ||
3477 | #ifdef WIRELESS_SPY | ||
3478 | if (ai->spy_data.spy_number > 0) { | ||
3479 | char *sa; | ||
3480 | struct iw_quality wstats; | ||
3481 | /* Prepare spy data : addr + qual */ | ||
3482 | sa = buffer + ETH_ALEN; | ||
3483 | wstats.qual = 0; /* XXX Where do I get that info from ??? */ | ||
3484 | wstats.level = 0; | ||
3485 | wstats.updated = 0; | ||
3486 | /* Update spy records */ | ||
3487 | wireless_spy_update(ai->dev, sa, &wstats); | ||
3488 | } | ||
3489 | #endif /* WIRELESS_SPY */ | ||
3490 | |||
3491 | skb->dev = ai->dev; | ||
3492 | skb->ip_summed = CHECKSUM_NONE; | ||
3493 | skb->protocol = eth_type_trans(skb, ai->dev); | ||
3494 | skb->dev->last_rx = jiffies; | ||
3495 | netif_rx(skb); | ||
3496 | } | ||
3497 | badrx: | ||
3498 | if (rxd.valid == 0) { | ||
3499 | rxd.valid = 1; | ||
3500 | rxd.rdy = 0; | ||
3501 | rxd.len = PKTSIZE; | ||
3502 | memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); | ||
3503 | } | ||
3504 | } | ||
3505 | |||
3506 | void mpi_receive_802_11 (struct airo_info *ai) | ||
3507 | { | ||
3508 | RxFid rxd; | ||
3509 | struct sk_buff *skb = NULL; | ||
3510 | u16 fc, len, hdrlen = 0; | ||
3511 | #pragma pack(1) | ||
3512 | struct { | ||
3513 | u16 status, len; | ||
3514 | u8 rssi[2]; | ||
3515 | u8 rate; | ||
3516 | u8 freq; | ||
3517 | u16 tmp[4]; | ||
3518 | } hdr; | ||
3519 | #pragma pack() | ||
3520 | u16 gap; | ||
3521 | u16 *buffer; | ||
3522 | char *ptr = ai->rxfids[0].virtual_host_addr+4; | ||
3523 | |||
3524 | memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); | ||
3525 | memcpy ((char *)&hdr, ptr, sizeof(hdr)); | ||
3526 | ptr += sizeof(hdr); | ||
3527 | /* Bad CRC. Ignore packet */ | ||
3528 | if (le16_to_cpu(hdr.status) & 2) | ||
3529 | hdr.len = 0; | ||
3530 | if (ai->wifidev == NULL) | ||
3531 | hdr.len = 0; | ||
3532 | len = le16_to_cpu(hdr.len); | ||
3533 | if (len > 2312) { | ||
3534 | printk( KERN_ERR "airo: Bad size %d\n", len ); | ||
3535 | goto badrx; | ||
3536 | } | ||
3537 | if (len == 0) | ||
3538 | goto badrx; | ||
3539 | |||
3540 | memcpy ((char *)&fc, ptr, sizeof(fc)); | ||
3541 | fc = le16_to_cpu(fc); | ||
3542 | switch (fc & 0xc) { | ||
3543 | case 4: | ||
3544 | if ((fc & 0xe0) == 0xc0) | ||
3545 | hdrlen = 10; | ||
3546 | else | ||
3547 | hdrlen = 16; | ||
3548 | break; | ||
3549 | case 8: | ||
3550 | if ((fc&0x300)==0x300){ | ||
3551 | hdrlen = 30; | ||
3552 | break; | ||
3553 | } | ||
3554 | default: | ||
3555 | hdrlen = 24; | ||
3556 | } | ||
3557 | |||
3558 | skb = dev_alloc_skb( len + hdrlen + 2 ); | ||
3559 | if ( !skb ) { | ||
3560 | ai->stats.rx_dropped++; | ||
3561 | goto badrx; | ||
3562 | } | ||
3563 | buffer = (u16*)skb_put (skb, len + hdrlen); | ||
3564 | memcpy ((char *)buffer, ptr, hdrlen); | ||
3565 | ptr += hdrlen; | ||
3566 | if (hdrlen == 24) | ||
3567 | ptr += 6; | ||
3568 | memcpy ((char *)&gap, ptr, sizeof(gap)); | ||
3569 | ptr += sizeof(gap); | ||
3570 | gap = le16_to_cpu(gap); | ||
3571 | if (gap) { | ||
3572 | if (gap <= 8) | ||
3573 | ptr += gap; | ||
3574 | else | ||
3575 | printk(KERN_ERR | ||
3576 | "airo: gaplen too big. Problems will follow...\n"); | ||
3577 | } | ||
3578 | memcpy ((char *)buffer + hdrlen, ptr, len); | ||
3579 | ptr += len; | ||
3580 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
3581 | if (ai->spy_data.spy_number > 0) { | ||
3582 | char *sa; | ||
3583 | struct iw_quality wstats; | ||
3584 | /* Prepare spy data : addr + qual */ | ||
3585 | sa = (char*)buffer + 10; | ||
3586 | wstats.qual = hdr.rssi[0]; | ||
3587 | if (ai->rssi) | ||
3588 | wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; | ||
3589 | else | ||
3590 | wstats.level = (hdr.rssi[1] + 321) / 2; | ||
3591 | wstats.updated = 3; | ||
3592 | /* Update spy records */ | ||
3593 | wireless_spy_update(ai->dev, sa, &wstats); | ||
3594 | } | ||
3595 | #endif /* IW_WIRELESS_SPY */ | ||
3596 | skb->mac.raw = skb->data; | ||
3597 | skb->pkt_type = PACKET_OTHERHOST; | ||
3598 | skb->dev = ai->wifidev; | ||
3599 | skb->protocol = htons(ETH_P_802_2); | ||
3600 | skb->dev->last_rx = jiffies; | ||
3601 | skb->ip_summed = CHECKSUM_NONE; | ||
3602 | netif_rx( skb ); | ||
3603 | badrx: | ||
3604 | if (rxd.valid == 0) { | ||
3605 | rxd.valid = 1; | ||
3606 | rxd.rdy = 0; | ||
3607 | rxd.len = PKTSIZE; | ||
3608 | memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); | ||
3609 | } | ||
3610 | } | ||
3611 | |||
3612 | static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) | ||
3613 | { | ||
3614 | Cmd cmd; | ||
3615 | Resp rsp; | ||
3616 | int status; | ||
3617 | int i; | ||
3618 | SsidRid mySsid; | ||
3619 | u16 lastindex; | ||
3620 | WepKeyRid wkr; | ||
3621 | int rc; | ||
3622 | |||
3623 | memset( &mySsid, 0, sizeof( mySsid ) ); | ||
3624 | if (ai->flash) { | ||
3625 | kfree (ai->flash); | ||
3626 | ai->flash = NULL; | ||
3627 | } | ||
3628 | |||
3629 | /* The NOP is the first step in getting the card going */ | ||
3630 | cmd.cmd = NOP; | ||
3631 | cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; | ||
3632 | if (lock && down_interruptible(&ai->sem)) | ||
3633 | return ERROR; | ||
3634 | if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) { | ||
3635 | if (lock) | ||
3636 | up(&ai->sem); | ||
3637 | return ERROR; | ||
3638 | } | ||
3639 | disable_MAC( ai, 0); | ||
3640 | |||
3641 | // Let's figure out if we need to use the AUX port | ||
3642 | if (!test_bit(FLAG_MPI,&ai->flags)) { | ||
3643 | cmd.cmd = CMD_ENABLEAUX; | ||
3644 | if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { | ||
3645 | if (lock) | ||
3646 | up(&ai->sem); | ||
3647 | printk(KERN_ERR "airo: Error checking for AUX port\n"); | ||
3648 | return ERROR; | ||
3649 | } | ||
3650 | if (!aux_bap || rsp.status & 0xff00) { | ||
3651 | ai->bap_read = fast_bap_read; | ||
3652 | printk(KERN_DEBUG "airo: Doing fast bap_reads\n"); | ||
3653 | } else { | ||
3654 | ai->bap_read = aux_bap_read; | ||
3655 | printk(KERN_DEBUG "airo: Doing AUX bap_reads\n"); | ||
3656 | } | ||
3657 | } | ||
3658 | if (lock) | ||
3659 | up(&ai->sem); | ||
3660 | if (ai->config.len == 0) { | ||
3661 | tdsRssiRid rssi_rid; | ||
3662 | CapabilityRid cap_rid; | ||
3663 | |||
3664 | if (ai->APList) { | ||
3665 | kfree(ai->APList); | ||
3666 | ai->APList = NULL; | ||
3667 | } | ||
3668 | if (ai->SSID) { | ||
3669 | kfree(ai->SSID); | ||
3670 | ai->SSID = NULL; | ||
3671 | } | ||
3672 | // general configuration (read/modify/write) | ||
3673 | status = readConfigRid(ai, lock); | ||
3674 | if ( status != SUCCESS ) return ERROR; | ||
3675 | |||
3676 | status = readCapabilityRid(ai, &cap_rid, lock); | ||
3677 | if ( status != SUCCESS ) return ERROR; | ||
3678 | |||
3679 | status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock); | ||
3680 | if ( status == SUCCESS ) { | ||
3681 | if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) | ||
3682 | memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); | ||
3683 | } | ||
3684 | else { | ||
3685 | if (ai->rssi) { | ||
3686 | kfree(ai->rssi); | ||
3687 | ai->rssi = NULL; | ||
3688 | } | ||
3689 | if (cap_rid.softCap & 8) | ||
3690 | ai->config.rmode |= RXMODE_NORMALIZED_RSSI; | ||
3691 | else | ||
3692 | printk(KERN_WARNING "airo: unknown received signal level scale\n"); | ||
3693 | } | ||
3694 | ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; | ||
3695 | ai->config.authType = AUTH_OPEN; | ||
3696 | ai->config.modulation = MOD_CCK; | ||
3697 | |||
3698 | #ifdef MICSUPPORT | ||
3699 | if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) && | ||
3700 | (micsetup(ai) == SUCCESS)) { | ||
3701 | ai->config.opmode |= MODE_MIC; | ||
3702 | set_bit(FLAG_MIC_CAPABLE, &ai->flags); | ||
3703 | } | ||
3704 | #endif | ||
3705 | |||
3706 | /* Save off the MAC */ | ||
3707 | for( i = 0; i < ETH_ALEN; i++ ) { | ||
3708 | mac[i] = ai->config.macAddr[i]; | ||
3709 | } | ||
3710 | |||
3711 | /* Check to see if there are any insmod configured | ||
3712 | rates to add */ | ||
3713 | if ( rates[0] ) { | ||
3714 | int i = 0; | ||
3715 | memset(ai->config.rates,0,sizeof(ai->config.rates)); | ||
3716 | for( i = 0; i < 8 && rates[i]; i++ ) { | ||
3717 | ai->config.rates[i] = rates[i]; | ||
3718 | } | ||
3719 | } | ||
3720 | if ( basic_rate > 0 ) { | ||
3721 | int i; | ||
3722 | for( i = 0; i < 8; i++ ) { | ||
3723 | if ( ai->config.rates[i] == basic_rate || | ||
3724 | !ai->config.rates ) { | ||
3725 | ai->config.rates[i] = basic_rate | 0x80; | ||
3726 | break; | ||
3727 | } | ||
3728 | } | ||
3729 | } | ||
3730 | set_bit (FLAG_COMMIT, &ai->flags); | ||
3731 | } | ||
3732 | |||
3733 | /* Setup the SSIDs if present */ | ||
3734 | if ( ssids[0] ) { | ||
3735 | int i; | ||
3736 | for( i = 0; i < 3 && ssids[i]; i++ ) { | ||
3737 | mySsid.ssids[i].len = strlen(ssids[i]); | ||
3738 | if ( mySsid.ssids[i].len > 32 ) | ||
3739 | mySsid.ssids[i].len = 32; | ||
3740 | memcpy(mySsid.ssids[i].ssid, ssids[i], | ||
3741 | mySsid.ssids[i].len); | ||
3742 | } | ||
3743 | mySsid.len = sizeof(mySsid); | ||
3744 | } | ||
3745 | |||
3746 | status = writeConfigRid(ai, lock); | ||
3747 | if ( status != SUCCESS ) return ERROR; | ||
3748 | |||
3749 | /* Set up the SSID list */ | ||
3750 | if ( ssids[0] ) { | ||
3751 | status = writeSsidRid(ai, &mySsid, lock); | ||
3752 | if ( status != SUCCESS ) return ERROR; | ||
3753 | } | ||
3754 | |||
3755 | status = enable_MAC(ai, &rsp, lock); | ||
3756 | if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { | ||
3757 | printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); | ||
3758 | return ERROR; | ||
3759 | } | ||
3760 | |||
3761 | /* Grab the initial wep key, we gotta save it for auto_wep */ | ||
3762 | rc = readWepKeyRid(ai, &wkr, 1, lock); | ||
3763 | if (rc == SUCCESS) do { | ||
3764 | lastindex = wkr.kindex; | ||
3765 | if (wkr.kindex == 0xffff) { | ||
3766 | ai->defindex = wkr.mac[0]; | ||
3767 | } | ||
3768 | rc = readWepKeyRid(ai, &wkr, 0, lock); | ||
3769 | } while(lastindex != wkr.kindex); | ||
3770 | |||
3771 | if (auto_wep) { | ||
3772 | ai->expires = RUN_AT(3*HZ); | ||
3773 | wake_up_interruptible(&ai->thr_wait); | ||
3774 | } | ||
3775 | |||
3776 | return SUCCESS; | ||
3777 | } | ||
3778 | |||
3779 | static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { | ||
3780 | // Im really paranoid about letting it run forever! | ||
3781 | int max_tries = 600000; | ||
3782 | |||
3783 | if (IN4500(ai, EVSTAT) & EV_CMD) | ||
3784 | OUT4500(ai, EVACK, EV_CMD); | ||
3785 | |||
3786 | OUT4500(ai, PARAM0, pCmd->parm0); | ||
3787 | OUT4500(ai, PARAM1, pCmd->parm1); | ||
3788 | OUT4500(ai, PARAM2, pCmd->parm2); | ||
3789 | OUT4500(ai, COMMAND, pCmd->cmd); | ||
3790 | |||
3791 | while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { | ||
3792 | if ((IN4500(ai, COMMAND)) == pCmd->cmd) | ||
3793 | // PC4500 didn't notice command, try again | ||
3794 | OUT4500(ai, COMMAND, pCmd->cmd); | ||
3795 | if (!in_atomic() && (max_tries & 255) == 0) | ||
3796 | schedule(); | ||
3797 | } | ||
3798 | |||
3799 | if ( max_tries == -1 ) { | ||
3800 | printk( KERN_ERR | ||
3801 | "airo: Max tries exceeded when issueing command\n" ); | ||
3802 | if (IN4500(ai, COMMAND) & COMMAND_BUSY) | ||
3803 | OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); | ||
3804 | return ERROR; | ||
3805 | } | ||
3806 | |||
3807 | // command completed | ||
3808 | pRsp->status = IN4500(ai, STATUS); | ||
3809 | pRsp->rsp0 = IN4500(ai, RESP0); | ||
3810 | pRsp->rsp1 = IN4500(ai, RESP1); | ||
3811 | pRsp->rsp2 = IN4500(ai, RESP2); | ||
3812 | if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) { | ||
3813 | printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd); | ||
3814 | printk (KERN_ERR "airo: status= %x\n", pRsp->status); | ||
3815 | printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0); | ||
3816 | printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1); | ||
3817 | printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2); | ||
3818 | } | ||
3819 | |||
3820 | // clear stuck command busy if necessary | ||
3821 | if (IN4500(ai, COMMAND) & COMMAND_BUSY) { | ||
3822 | OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); | ||
3823 | } | ||
3824 | // acknowledge processing the status/response | ||
3825 | OUT4500(ai, EVACK, EV_CMD); | ||
3826 | |||
3827 | return SUCCESS; | ||
3828 | } | ||
3829 | |||
3830 | /* Sets up the bap to start exchange data. whichbap should | ||
3831 | * be one of the BAP0 or BAP1 defines. Locks should be held before | ||
3832 | * calling! */ | ||
3833 | static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap ) | ||
3834 | { | ||
3835 | int timeout = 50; | ||
3836 | int max_tries = 3; | ||
3837 | |||
3838 | OUT4500(ai, SELECT0+whichbap, rid); | ||
3839 | OUT4500(ai, OFFSET0+whichbap, offset); | ||
3840 | while (1) { | ||
3841 | int status = IN4500(ai, OFFSET0+whichbap); | ||
3842 | if (status & BAP_BUSY) { | ||
3843 | /* This isn't really a timeout, but its kinda | ||
3844 | close */ | ||
3845 | if (timeout--) { | ||
3846 | continue; | ||
3847 | } | ||
3848 | } else if ( status & BAP_ERR ) { | ||
3849 | /* invalid rid or offset */ | ||
3850 | printk( KERN_ERR "airo: BAP error %x %d\n", | ||
3851 | status, whichbap ); | ||
3852 | return ERROR; | ||
3853 | } else if (status & BAP_DONE) { // success | ||
3854 | return SUCCESS; | ||
3855 | } | ||
3856 | if ( !(max_tries--) ) { | ||
3857 | printk( KERN_ERR | ||
3858 | "airo: BAP setup error too many retries\n" ); | ||
3859 | return ERROR; | ||
3860 | } | ||
3861 | // -- PC4500 missed it, try again | ||
3862 | OUT4500(ai, SELECT0+whichbap, rid); | ||
3863 | OUT4500(ai, OFFSET0+whichbap, offset); | ||
3864 | timeout = 50; | ||
3865 | } | ||
3866 | } | ||
3867 | |||
3868 | /* should only be called by aux_bap_read. This aux function and the | ||
3869 | following use concepts not documented in the developers guide. I | ||
3870 | got them from a patch given to my by Aironet */ | ||
3871 | static u16 aux_setup(struct airo_info *ai, u16 page, | ||
3872 | u16 offset, u16 *len) | ||
3873 | { | ||
3874 | u16 next; | ||
3875 | |||
3876 | OUT4500(ai, AUXPAGE, page); | ||
3877 | OUT4500(ai, AUXOFF, 0); | ||
3878 | next = IN4500(ai, AUXDATA); | ||
3879 | *len = IN4500(ai, AUXDATA)&0xff; | ||
3880 | if (offset != 4) OUT4500(ai, AUXOFF, offset); | ||
3881 | return next; | ||
3882 | } | ||
3883 | |||
3884 | /* requires call to bap_setup() first */ | ||
3885 | static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst, | ||
3886 | int bytelen, int whichbap) | ||
3887 | { | ||
3888 | u16 len; | ||
3889 | u16 page; | ||
3890 | u16 offset; | ||
3891 | u16 next; | ||
3892 | int words; | ||
3893 | int i; | ||
3894 | unsigned long flags; | ||
3895 | |||
3896 | spin_lock_irqsave(&ai->aux_lock, flags); | ||
3897 | page = IN4500(ai, SWS0+whichbap); | ||
3898 | offset = IN4500(ai, SWS2+whichbap); | ||
3899 | next = aux_setup(ai, page, offset, &len); | ||
3900 | words = (bytelen+1)>>1; | ||
3901 | |||
3902 | for (i=0; i<words;) { | ||
3903 | int count; | ||
3904 | count = (len>>1) < (words-i) ? (len>>1) : (words-i); | ||
3905 | if ( !do8bitIO ) | ||
3906 | insw( ai->dev->base_addr+DATA0+whichbap, | ||
3907 | pu16Dst+i,count ); | ||
3908 | else | ||
3909 | insb( ai->dev->base_addr+DATA0+whichbap, | ||
3910 | pu16Dst+i, count << 1 ); | ||
3911 | i += count; | ||
3912 | if (i<words) { | ||
3913 | next = aux_setup(ai, next, 4, &len); | ||
3914 | } | ||
3915 | } | ||
3916 | spin_unlock_irqrestore(&ai->aux_lock, flags); | ||
3917 | return SUCCESS; | ||
3918 | } | ||
3919 | |||
3920 | |||
3921 | /* requires call to bap_setup() first */ | ||
3922 | static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, | ||
3923 | int bytelen, int whichbap) | ||
3924 | { | ||
3925 | bytelen = (bytelen + 1) & (~1); // round up to even value | ||
3926 | if ( !do8bitIO ) | ||
3927 | insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 ); | ||
3928 | else | ||
3929 | insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen ); | ||
3930 | return SUCCESS; | ||
3931 | } | ||
3932 | |||
3933 | /* requires call to bap_setup() first */ | ||
3934 | static int bap_write(struct airo_info *ai, const u16 *pu16Src, | ||
3935 | int bytelen, int whichbap) | ||
3936 | { | ||
3937 | bytelen = (bytelen + 1) & (~1); // round up to even value | ||
3938 | if ( !do8bitIO ) | ||
3939 | outsw( ai->dev->base_addr+DATA0+whichbap, | ||
3940 | pu16Src, bytelen>>1 ); | ||
3941 | else | ||
3942 | outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen ); | ||
3943 | return SUCCESS; | ||
3944 | } | ||
3945 | |||
3946 | static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd) | ||
3947 | { | ||
3948 | Cmd cmd; /* for issuing commands */ | ||
3949 | Resp rsp; /* response from commands */ | ||
3950 | u16 status; | ||
3951 | |||
3952 | memset(&cmd, 0, sizeof(cmd)); | ||
3953 | cmd.cmd = accmd; | ||
3954 | cmd.parm0 = rid; | ||
3955 | status = issuecommand(ai, &cmd, &rsp); | ||
3956 | if (status != 0) return status; | ||
3957 | if ( (rsp.status & 0x7F00) != 0) { | ||
3958 | return (accmd << 8) + (rsp.rsp0 & 0xFF); | ||
3959 | } | ||
3960 | return 0; | ||
3961 | } | ||
3962 | |||
3963 | /* Note, that we are using BAP1 which is also used by transmit, so | ||
3964 | * we must get a lock. */ | ||
3965 | static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock) | ||
3966 | { | ||
3967 | u16 status; | ||
3968 | int rc = SUCCESS; | ||
3969 | |||
3970 | if (lock) { | ||
3971 | if (down_interruptible(&ai->sem)) | ||
3972 | return ERROR; | ||
3973 | } | ||
3974 | if (test_bit(FLAG_MPI,&ai->flags)) { | ||
3975 | Cmd cmd; | ||
3976 | Resp rsp; | ||
3977 | |||
3978 | memset(&cmd, 0, sizeof(cmd)); | ||
3979 | memset(&rsp, 0, sizeof(rsp)); | ||
3980 | ai->config_desc.rid_desc.valid = 1; | ||
3981 | ai->config_desc.rid_desc.len = RIDSIZE; | ||
3982 | ai->config_desc.rid_desc.rid = 0; | ||
3983 | ai->config_desc.rid_desc.host_addr = ai->ridbus; | ||
3984 | |||
3985 | cmd.cmd = CMD_ACCESS; | ||
3986 | cmd.parm0 = rid; | ||
3987 | |||
3988 | memcpy_toio(ai->config_desc.card_ram_off, | ||
3989 | &ai->config_desc.rid_desc, sizeof(Rid)); | ||
3990 | |||
3991 | rc = issuecommand(ai, &cmd, &rsp); | ||
3992 | |||
3993 | if (rsp.status & 0x7f00) | ||
3994 | rc = rsp.rsp0; | ||
3995 | if (!rc) | ||
3996 | memcpy(pBuf, ai->config_desc.virtual_host_addr, len); | ||
3997 | goto done; | ||
3998 | } else { | ||
3999 | if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) { | ||
4000 | rc = status; | ||
4001 | goto done; | ||
4002 | } | ||
4003 | if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { | ||
4004 | rc = ERROR; | ||
4005 | goto done; | ||
4006 | } | ||
4007 | // read the rid length field | ||
4008 | bap_read(ai, pBuf, 2, BAP1); | ||
4009 | // length for remaining part of rid | ||
4010 | len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2; | ||
4011 | |||
4012 | if ( len <= 2 ) { | ||
4013 | printk( KERN_ERR | ||
4014 | "airo: Rid %x has a length of %d which is too short\n", | ||
4015 | (int)rid, (int)len ); | ||
4016 | rc = ERROR; | ||
4017 | goto done; | ||
4018 | } | ||
4019 | // read remainder of the rid | ||
4020 | rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1); | ||
4021 | } | ||
4022 | done: | ||
4023 | if (lock) | ||
4024 | up(&ai->sem); | ||
4025 | return rc; | ||
4026 | } | ||
4027 | |||
4028 | /* Note, that we are using BAP1 which is also used by transmit, so | ||
4029 | * make sure this isnt called when a transmit is happening */ | ||
4030 | static int PC4500_writerid(struct airo_info *ai, u16 rid, | ||
4031 | const void *pBuf, int len, int lock) | ||
4032 | { | ||
4033 | u16 status; | ||
4034 | int rc = SUCCESS; | ||
4035 | |||
4036 | *(u16*)pBuf = cpu_to_le16((u16)len); | ||
4037 | |||
4038 | if (lock) { | ||
4039 | if (down_interruptible(&ai->sem)) | ||
4040 | return ERROR; | ||
4041 | } | ||
4042 | if (test_bit(FLAG_MPI,&ai->flags)) { | ||
4043 | Cmd cmd; | ||
4044 | Resp rsp; | ||
4045 | |||
4046 | if (test_bit(FLAG_ENABLED, &ai->flags)) | ||
4047 | printk(KERN_ERR | ||
4048 | "%s: MAC should be disabled (rid=%04x)\n", | ||
4049 | __FUNCTION__, rid); | ||
4050 | memset(&cmd, 0, sizeof(cmd)); | ||
4051 | memset(&rsp, 0, sizeof(rsp)); | ||
4052 | |||
4053 | ai->config_desc.rid_desc.valid = 1; | ||
4054 | ai->config_desc.rid_desc.len = *((u16 *)pBuf); | ||
4055 | ai->config_desc.rid_desc.rid = 0; | ||
4056 | |||
4057 | cmd.cmd = CMD_WRITERID; | ||
4058 | cmd.parm0 = rid; | ||
4059 | |||
4060 | memcpy_toio(ai->config_desc.card_ram_off, | ||
4061 | &ai->config_desc.rid_desc, sizeof(Rid)); | ||
4062 | |||
4063 | if (len < 4 || len > 2047) { | ||
4064 | printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len); | ||
4065 | rc = -1; | ||
4066 | } else { | ||
4067 | memcpy((char *)ai->config_desc.virtual_host_addr, | ||
4068 | pBuf, len); | ||
4069 | |||
4070 | rc = issuecommand(ai, &cmd, &rsp); | ||
4071 | if ((rc & 0xff00) != 0) { | ||
4072 | printk(KERN_ERR "%s: Write rid Error %d\n", | ||
4073 | __FUNCTION__,rc); | ||
4074 | printk(KERN_ERR "%s: Cmd=%04x\n", | ||
4075 | __FUNCTION__,cmd.cmd); | ||
4076 | } | ||
4077 | |||
4078 | if ((rsp.status & 0x7f00)) | ||
4079 | rc = rsp.rsp0; | ||
4080 | } | ||
4081 | } else { | ||
4082 | // --- first access so that we can write the rid data | ||
4083 | if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { | ||
4084 | rc = status; | ||
4085 | goto done; | ||
4086 | } | ||
4087 | // --- now write the rid data | ||
4088 | if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { | ||
4089 | rc = ERROR; | ||
4090 | goto done; | ||
4091 | } | ||
4092 | bap_write(ai, pBuf, len, BAP1); | ||
4093 | // ---now commit the rid data | ||
4094 | rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); | ||
4095 | } | ||
4096 | done: | ||
4097 | if (lock) | ||
4098 | up(&ai->sem); | ||
4099 | return rc; | ||
4100 | } | ||
4101 | |||
4102 | /* Allocates a FID to be used for transmitting packets. We only use | ||
4103 | one for now. */ | ||
4104 | static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) | ||
4105 | { | ||
4106 | unsigned int loop = 3000; | ||
4107 | Cmd cmd; | ||
4108 | Resp rsp; | ||
4109 | u16 txFid; | ||
4110 | u16 txControl; | ||
4111 | |||
4112 | cmd.cmd = CMD_ALLOCATETX; | ||
4113 | cmd.parm0 = lenPayload; | ||
4114 | if (down_interruptible(&ai->sem)) | ||
4115 | return ERROR; | ||
4116 | if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { | ||
4117 | txFid = ERROR; | ||
4118 | goto done; | ||
4119 | } | ||
4120 | if ( (rsp.status & 0xFF00) != 0) { | ||
4121 | txFid = ERROR; | ||
4122 | goto done; | ||
4123 | } | ||
4124 | /* wait for the allocate event/indication | ||
4125 | * It makes me kind of nervous that this can just sit here and spin, | ||
4126 | * but in practice it only loops like four times. */ | ||
4127 | while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop); | ||
4128 | if (!loop) { | ||
4129 | txFid = ERROR; | ||
4130 | goto done; | ||
4131 | } | ||
4132 | |||
4133 | // get the allocated fid and acknowledge | ||
4134 | txFid = IN4500(ai, TXALLOCFID); | ||
4135 | OUT4500(ai, EVACK, EV_ALLOC); | ||
4136 | |||
4137 | /* The CARD is pretty cool since it converts the ethernet packet | ||
4138 | * into 802.11. Also note that we don't release the FID since we | ||
4139 | * will be using the same one over and over again. */ | ||
4140 | /* We only have to setup the control once since we are not | ||
4141 | * releasing the fid. */ | ||
4142 | if (raw) | ||
4143 | txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11 | ||
4144 | | TXCTL_ETHERNET | TXCTL_NORELEASE); | ||
4145 | else | ||
4146 | txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 | ||
4147 | | TXCTL_ETHERNET | TXCTL_NORELEASE); | ||
4148 | if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) | ||
4149 | txFid = ERROR; | ||
4150 | else | ||
4151 | bap_write(ai, &txControl, sizeof(txControl), BAP1); | ||
4152 | |||
4153 | done: | ||
4154 | up(&ai->sem); | ||
4155 | |||
4156 | return txFid; | ||
4157 | } | ||
4158 | |||
4159 | /* In general BAP1 is dedicated to transmiting packets. However, | ||
4160 | since we need a BAP when accessing RIDs, we also use BAP1 for that. | ||
4161 | Make sure the BAP1 spinlock is held when this is called. */ | ||
4162 | static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) | ||
4163 | { | ||
4164 | u16 payloadLen; | ||
4165 | Cmd cmd; | ||
4166 | Resp rsp; | ||
4167 | int miclen = 0; | ||
4168 | u16 txFid = len; | ||
4169 | MICBuffer pMic; | ||
4170 | |||
4171 | len >>= 16; | ||
4172 | |||
4173 | if (len <= ETH_ALEN * 2) { | ||
4174 | printk( KERN_WARNING "Short packet %d\n", len ); | ||
4175 | return ERROR; | ||
4176 | } | ||
4177 | len -= ETH_ALEN * 2; | ||
4178 | |||
4179 | #ifdef MICSUPPORT | ||
4180 | if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && | ||
4181 | (ntohs(((u16 *)pPacket)[6]) != 0x888E)) { | ||
4182 | if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS) | ||
4183 | return ERROR; | ||
4184 | miclen = sizeof(pMic); | ||
4185 | } | ||
4186 | #endif | ||
4187 | |||
4188 | // packet is destination[6], source[6], payload[len-12] | ||
4189 | // write the payload length and dst/src/payload | ||
4190 | if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; | ||
4191 | /* The hardware addresses aren't counted as part of the payload, so | ||
4192 | * we have to subtract the 12 bytes for the addresses off */ | ||
4193 | payloadLen = cpu_to_le16(len + miclen); | ||
4194 | bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); | ||
4195 | bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1); | ||
4196 | if (miclen) | ||
4197 | bap_write(ai, (const u16*)&pMic, miclen, BAP1); | ||
4198 | bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1); | ||
4199 | // issue the transmit command | ||
4200 | memset( &cmd, 0, sizeof( cmd ) ); | ||
4201 | cmd.cmd = CMD_TRANSMIT; | ||
4202 | cmd.parm0 = txFid; | ||
4203 | if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR; | ||
4204 | if ( (rsp.status & 0xFF00) != 0) return ERROR; | ||
4205 | return SUCCESS; | ||
4206 | } | ||
4207 | |||
4208 | static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) | ||
4209 | { | ||
4210 | u16 fc, payloadLen; | ||
4211 | Cmd cmd; | ||
4212 | Resp rsp; | ||
4213 | int hdrlen; | ||
4214 | struct { | ||
4215 | u8 addr4[ETH_ALEN]; | ||
4216 | u16 gaplen; | ||
4217 | u8 gap[6]; | ||
4218 | } gap; | ||
4219 | u16 txFid = len; | ||
4220 | len >>= 16; | ||
4221 | gap.gaplen = 6; | ||
4222 | |||
4223 | fc = le16_to_cpu(*(const u16*)pPacket); | ||
4224 | switch (fc & 0xc) { | ||
4225 | case 4: | ||
4226 | if ((fc & 0xe0) == 0xc0) | ||
4227 | hdrlen = 10; | ||
4228 | else | ||
4229 | hdrlen = 16; | ||
4230 | break; | ||
4231 | case 8: | ||
4232 | if ((fc&0x300)==0x300){ | ||
4233 | hdrlen = 30; | ||
4234 | break; | ||
4235 | } | ||
4236 | default: | ||
4237 | hdrlen = 24; | ||
4238 | } | ||
4239 | |||
4240 | if (len < hdrlen) { | ||
4241 | printk( KERN_WARNING "Short packet %d\n", len ); | ||
4242 | return ERROR; | ||
4243 | } | ||
4244 | |||
4245 | /* packet is 802.11 header + payload | ||
4246 | * write the payload length and dst/src/payload */ | ||
4247 | if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR; | ||
4248 | /* The 802.11 header aren't counted as part of the payload, so | ||
4249 | * we have to subtract the header bytes off */ | ||
4250 | payloadLen = cpu_to_le16(len-hdrlen); | ||
4251 | bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); | ||
4252 | if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR; | ||
4253 | bap_write(ai, (const u16*)pPacket, hdrlen, BAP1); | ||
4254 | bap_write(ai, hdrlen == 30 ? | ||
4255 | (const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1); | ||
4256 | |||
4257 | bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1); | ||
4258 | // issue the transmit command | ||
4259 | memset( &cmd, 0, sizeof( cmd ) ); | ||
4260 | cmd.cmd = CMD_TRANSMIT; | ||
4261 | cmd.parm0 = txFid; | ||
4262 | if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR; | ||
4263 | if ( (rsp.status & 0xFF00) != 0) return ERROR; | ||
4264 | return SUCCESS; | ||
4265 | } | ||
4266 | |||
4267 | /* | ||
4268 | * This is the proc_fs routines. It is a bit messier than I would | ||
4269 | * like! Feel free to clean it up! | ||
4270 | */ | ||
4271 | |||
4272 | static ssize_t proc_read( struct file *file, | ||
4273 | char __user *buffer, | ||
4274 | size_t len, | ||
4275 | loff_t *offset); | ||
4276 | |||
4277 | static ssize_t proc_write( struct file *file, | ||
4278 | const char __user *buffer, | ||
4279 | size_t len, | ||
4280 | loff_t *offset ); | ||
4281 | static int proc_close( struct inode *inode, struct file *file ); | ||
4282 | |||
4283 | static int proc_stats_open( struct inode *inode, struct file *file ); | ||
4284 | static int proc_statsdelta_open( struct inode *inode, struct file *file ); | ||
4285 | static int proc_status_open( struct inode *inode, struct file *file ); | ||
4286 | static int proc_SSID_open( struct inode *inode, struct file *file ); | ||
4287 | static int proc_APList_open( struct inode *inode, struct file *file ); | ||
4288 | static int proc_BSSList_open( struct inode *inode, struct file *file ); | ||
4289 | static int proc_config_open( struct inode *inode, struct file *file ); | ||
4290 | static int proc_wepkey_open( struct inode *inode, struct file *file ); | ||
4291 | |||
4292 | static struct file_operations proc_statsdelta_ops = { | ||
4293 | .read = proc_read, | ||
4294 | .open = proc_statsdelta_open, | ||
4295 | .release = proc_close | ||
4296 | }; | ||
4297 | |||
4298 | static struct file_operations proc_stats_ops = { | ||
4299 | .read = proc_read, | ||
4300 | .open = proc_stats_open, | ||
4301 | .release = proc_close | ||
4302 | }; | ||
4303 | |||
4304 | static struct file_operations proc_status_ops = { | ||
4305 | .read = proc_read, | ||
4306 | .open = proc_status_open, | ||
4307 | .release = proc_close | ||
4308 | }; | ||
4309 | |||
4310 | static struct file_operations proc_SSID_ops = { | ||
4311 | .read = proc_read, | ||
4312 | .write = proc_write, | ||
4313 | .open = proc_SSID_open, | ||
4314 | .release = proc_close | ||
4315 | }; | ||
4316 | |||
4317 | static struct file_operations proc_BSSList_ops = { | ||
4318 | .read = proc_read, | ||
4319 | .write = proc_write, | ||
4320 | .open = proc_BSSList_open, | ||
4321 | .release = proc_close | ||
4322 | }; | ||
4323 | |||
4324 | static struct file_operations proc_APList_ops = { | ||
4325 | .read = proc_read, | ||
4326 | .write = proc_write, | ||
4327 | .open = proc_APList_open, | ||
4328 | .release = proc_close | ||
4329 | }; | ||
4330 | |||
4331 | static struct file_operations proc_config_ops = { | ||
4332 | .read = proc_read, | ||
4333 | .write = proc_write, | ||
4334 | .open = proc_config_open, | ||
4335 | .release = proc_close | ||
4336 | }; | ||
4337 | |||
4338 | static struct file_operations proc_wepkey_ops = { | ||
4339 | .read = proc_read, | ||
4340 | .write = proc_write, | ||
4341 | .open = proc_wepkey_open, | ||
4342 | .release = proc_close | ||
4343 | }; | ||
4344 | |||
4345 | static struct proc_dir_entry *airo_entry; | ||
4346 | |||
4347 | struct proc_data { | ||
4348 | int release_buffer; | ||
4349 | int readlen; | ||
4350 | char *rbuffer; | ||
4351 | int writelen; | ||
4352 | int maxwritelen; | ||
4353 | char *wbuffer; | ||
4354 | void (*on_close) (struct inode *, struct file *); | ||
4355 | }; | ||
4356 | |||
4357 | #ifndef SETPROC_OPS | ||
4358 | #define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops) | ||
4359 | #endif | ||
4360 | |||
4361 | static int setup_proc_entry( struct net_device *dev, | ||
4362 | struct airo_info *apriv ) { | ||
4363 | struct proc_dir_entry *entry; | ||
4364 | /* First setup the device directory */ | ||
4365 | strcpy(apriv->proc_name,dev->name); | ||
4366 | apriv->proc_entry = create_proc_entry(apriv->proc_name, | ||
4367 | S_IFDIR|airo_perm, | ||
4368 | airo_entry); | ||
4369 | apriv->proc_entry->uid = proc_uid; | ||
4370 | apriv->proc_entry->gid = proc_gid; | ||
4371 | apriv->proc_entry->owner = THIS_MODULE; | ||
4372 | |||
4373 | /* Setup the StatsDelta */ | ||
4374 | entry = create_proc_entry("StatsDelta", | ||
4375 | S_IFREG | (S_IRUGO&proc_perm), | ||
4376 | apriv->proc_entry); | ||
4377 | entry->uid = proc_uid; | ||
4378 | entry->gid = proc_gid; | ||
4379 | entry->data = dev; | ||
4380 | entry->owner = THIS_MODULE; | ||
4381 | SETPROC_OPS(entry, proc_statsdelta_ops); | ||
4382 | |||
4383 | /* Setup the Stats */ | ||
4384 | entry = create_proc_entry("Stats", | ||
4385 | S_IFREG | (S_IRUGO&proc_perm), | ||
4386 | apriv->proc_entry); | ||
4387 | entry->uid = proc_uid; | ||
4388 | entry->gid = proc_gid; | ||
4389 | entry->data = dev; | ||
4390 | entry->owner = THIS_MODULE; | ||
4391 | SETPROC_OPS(entry, proc_stats_ops); | ||
4392 | |||
4393 | /* Setup the Status */ | ||
4394 | entry = create_proc_entry("Status", | ||
4395 | S_IFREG | (S_IRUGO&proc_perm), | ||
4396 | apriv->proc_entry); | ||
4397 | entry->uid = proc_uid; | ||
4398 | entry->gid = proc_gid; | ||
4399 | entry->data = dev; | ||
4400 | entry->owner = THIS_MODULE; | ||
4401 | SETPROC_OPS(entry, proc_status_ops); | ||
4402 | |||
4403 | /* Setup the Config */ | ||
4404 | entry = create_proc_entry("Config", | ||
4405 | S_IFREG | proc_perm, | ||
4406 | apriv->proc_entry); | ||
4407 | entry->uid = proc_uid; | ||
4408 | entry->gid = proc_gid; | ||
4409 | entry->data = dev; | ||
4410 | entry->owner = THIS_MODULE; | ||
4411 | SETPROC_OPS(entry, proc_config_ops); | ||
4412 | |||
4413 | /* Setup the SSID */ | ||
4414 | entry = create_proc_entry("SSID", | ||
4415 | S_IFREG | proc_perm, | ||
4416 | apriv->proc_entry); | ||
4417 | entry->uid = proc_uid; | ||
4418 | entry->gid = proc_gid; | ||
4419 | entry->data = dev; | ||
4420 | entry->owner = THIS_MODULE; | ||
4421 | SETPROC_OPS(entry, proc_SSID_ops); | ||
4422 | |||
4423 | /* Setup the APList */ | ||
4424 | entry = create_proc_entry("APList", | ||
4425 | S_IFREG | proc_perm, | ||
4426 | apriv->proc_entry); | ||
4427 | entry->uid = proc_uid; | ||
4428 | entry->gid = proc_gid; | ||
4429 | entry->data = dev; | ||
4430 | entry->owner = THIS_MODULE; | ||
4431 | SETPROC_OPS(entry, proc_APList_ops); | ||
4432 | |||
4433 | /* Setup the BSSList */ | ||
4434 | entry = create_proc_entry("BSSList", | ||
4435 | S_IFREG | proc_perm, | ||
4436 | apriv->proc_entry); | ||
4437 | entry->uid = proc_uid; | ||
4438 | entry->gid = proc_gid; | ||
4439 | entry->data = dev; | ||
4440 | entry->owner = THIS_MODULE; | ||
4441 | SETPROC_OPS(entry, proc_BSSList_ops); | ||
4442 | |||
4443 | /* Setup the WepKey */ | ||
4444 | entry = create_proc_entry("WepKey", | ||
4445 | S_IFREG | proc_perm, | ||
4446 | apriv->proc_entry); | ||
4447 | entry->uid = proc_uid; | ||
4448 | entry->gid = proc_gid; | ||
4449 | entry->data = dev; | ||
4450 | entry->owner = THIS_MODULE; | ||
4451 | SETPROC_OPS(entry, proc_wepkey_ops); | ||
4452 | |||
4453 | return 0; | ||
4454 | } | ||
4455 | |||
4456 | static int takedown_proc_entry( struct net_device *dev, | ||
4457 | struct airo_info *apriv ) { | ||
4458 | if ( !apriv->proc_entry->namelen ) return 0; | ||
4459 | remove_proc_entry("Stats",apriv->proc_entry); | ||
4460 | remove_proc_entry("StatsDelta",apriv->proc_entry); | ||
4461 | remove_proc_entry("Status",apriv->proc_entry); | ||
4462 | remove_proc_entry("Config",apriv->proc_entry); | ||
4463 | remove_proc_entry("SSID",apriv->proc_entry); | ||
4464 | remove_proc_entry("APList",apriv->proc_entry); | ||
4465 | remove_proc_entry("BSSList",apriv->proc_entry); | ||
4466 | remove_proc_entry("WepKey",apriv->proc_entry); | ||
4467 | remove_proc_entry(apriv->proc_name,airo_entry); | ||
4468 | return 0; | ||
4469 | } | ||
4470 | |||
4471 | /* | ||
4472 | * What we want from the proc_fs is to be able to efficiently read | ||
4473 | * and write the configuration. To do this, we want to read the | ||
4474 | * configuration when the file is opened and write it when the file is | ||
4475 | * closed. So basically we allocate a read buffer at open and fill it | ||
4476 | * with data, and allocate a write buffer and read it at close. | ||
4477 | */ | ||
4478 | |||
4479 | /* | ||
4480 | * The read routine is generic, it relies on the preallocated rbuffer | ||
4481 | * to supply the data. | ||
4482 | */ | ||
4483 | static ssize_t proc_read( struct file *file, | ||
4484 | char __user *buffer, | ||
4485 | size_t len, | ||
4486 | loff_t *offset ) | ||
4487 | { | ||
4488 | loff_t pos = *offset; | ||
4489 | struct proc_data *priv = (struct proc_data*)file->private_data; | ||
4490 | |||
4491 | if (!priv->rbuffer) | ||
4492 | return -EINVAL; | ||
4493 | |||
4494 | if (pos < 0) | ||
4495 | return -EINVAL; | ||
4496 | if (pos >= priv->readlen) | ||
4497 | return 0; | ||
4498 | if (len > priv->readlen - pos) | ||
4499 | len = priv->readlen - pos; | ||
4500 | if (copy_to_user(buffer, priv->rbuffer + pos, len)) | ||
4501 | return -EFAULT; | ||
4502 | *offset = pos + len; | ||
4503 | return len; | ||
4504 | } | ||
4505 | |||
4506 | /* | ||
4507 | * The write routine is generic, it fills in a preallocated rbuffer | ||
4508 | * to supply the data. | ||
4509 | */ | ||
4510 | static ssize_t proc_write( struct file *file, | ||
4511 | const char __user *buffer, | ||
4512 | size_t len, | ||
4513 | loff_t *offset ) | ||
4514 | { | ||
4515 | loff_t pos = *offset; | ||
4516 | struct proc_data *priv = (struct proc_data*)file->private_data; | ||
4517 | |||
4518 | if (!priv->wbuffer) | ||
4519 | return -EINVAL; | ||
4520 | |||
4521 | if (pos < 0) | ||
4522 | return -EINVAL; | ||
4523 | if (pos >= priv->maxwritelen) | ||
4524 | return 0; | ||
4525 | if (len > priv->maxwritelen - pos) | ||
4526 | len = priv->maxwritelen - pos; | ||
4527 | if (copy_from_user(priv->wbuffer + pos, buffer, len)) | ||
4528 | return -EFAULT; | ||
4529 | if ( pos + len > priv->writelen ) | ||
4530 | priv->writelen = len + file->f_pos; | ||
4531 | *offset = pos + len; | ||
4532 | return len; | ||
4533 | } | ||
4534 | |||
4535 | static int proc_status_open( struct inode *inode, struct file *file ) { | ||
4536 | struct proc_data *data; | ||
4537 | struct proc_dir_entry *dp = PDE(inode); | ||
4538 | struct net_device *dev = dp->data; | ||
4539 | struct airo_info *apriv = dev->priv; | ||
4540 | CapabilityRid cap_rid; | ||
4541 | StatusRid status_rid; | ||
4542 | int i; | ||
4543 | |||
4544 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
4545 | return -ENOMEM; | ||
4546 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
4547 | data = (struct proc_data *)file->private_data; | ||
4548 | if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { | ||
4549 | kfree (file->private_data); | ||
4550 | return -ENOMEM; | ||
4551 | } | ||
4552 | |||
4553 | readStatusRid(apriv, &status_rid, 1); | ||
4554 | readCapabilityRid(apriv, &cap_rid, 1); | ||
4555 | |||
4556 | i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", | ||
4557 | status_rid.mode & 1 ? "CFG ": "", | ||
4558 | status_rid.mode & 2 ? "ACT ": "", | ||
4559 | status_rid.mode & 0x10 ? "SYN ": "", | ||
4560 | status_rid.mode & 0x20 ? "LNK ": "", | ||
4561 | status_rid.mode & 0x40 ? "LEAP ": "", | ||
4562 | status_rid.mode & 0x80 ? "PRIV ": "", | ||
4563 | status_rid.mode & 0x100 ? "KEY ": "", | ||
4564 | status_rid.mode & 0x200 ? "WEP ": "", | ||
4565 | status_rid.mode & 0x8000 ? "ERR ": ""); | ||
4566 | sprintf( data->rbuffer+i, "Mode: %x\n" | ||
4567 | "Signal Strength: %d\n" | ||
4568 | "Signal Quality: %d\n" | ||
4569 | "SSID: %-.*s\n" | ||
4570 | "AP: %-.16s\n" | ||
4571 | "Freq: %d\n" | ||
4572 | "BitRate: %dmbs\n" | ||
4573 | "Driver Version: %s\n" | ||
4574 | "Device: %s\nManufacturer: %s\nFirmware Version: %s\n" | ||
4575 | "Radio type: %x\nCountry: %x\nHardware Version: %x\n" | ||
4576 | "Software Version: %x\nSoftware Subversion: %x\n" | ||
4577 | "Boot block version: %x\n", | ||
4578 | (int)status_rid.mode, | ||
4579 | (int)status_rid.normalizedSignalStrength, | ||
4580 | (int)status_rid.signalQuality, | ||
4581 | (int)status_rid.SSIDlen, | ||
4582 | status_rid.SSID, | ||
4583 | status_rid.apName, | ||
4584 | (int)status_rid.channel, | ||
4585 | (int)status_rid.currentXmitRate/2, | ||
4586 | version, | ||
4587 | cap_rid.prodName, | ||
4588 | cap_rid.manName, | ||
4589 | cap_rid.prodVer, | ||
4590 | cap_rid.radioType, | ||
4591 | cap_rid.country, | ||
4592 | cap_rid.hardVer, | ||
4593 | (int)cap_rid.softVer, | ||
4594 | (int)cap_rid.softSubVer, | ||
4595 | (int)cap_rid.bootBlockVer ); | ||
4596 | data->readlen = strlen( data->rbuffer ); | ||
4597 | return 0; | ||
4598 | } | ||
4599 | |||
4600 | static int proc_stats_rid_open(struct inode*, struct file*, u16); | ||
4601 | static int proc_statsdelta_open( struct inode *inode, | ||
4602 | struct file *file ) { | ||
4603 | if (file->f_mode&FMODE_WRITE) { | ||
4604 | return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR); | ||
4605 | } | ||
4606 | return proc_stats_rid_open(inode, file, RID_STATSDELTA); | ||
4607 | } | ||
4608 | |||
4609 | static int proc_stats_open( struct inode *inode, struct file *file ) { | ||
4610 | return proc_stats_rid_open(inode, file, RID_STATS); | ||
4611 | } | ||
4612 | |||
4613 | static int proc_stats_rid_open( struct inode *inode, | ||
4614 | struct file *file, | ||
4615 | u16 rid ) { | ||
4616 | struct proc_data *data; | ||
4617 | struct proc_dir_entry *dp = PDE(inode); | ||
4618 | struct net_device *dev = dp->data; | ||
4619 | struct airo_info *apriv = dev->priv; | ||
4620 | StatsRid stats; | ||
4621 | int i, j; | ||
4622 | u32 *vals = stats.vals; | ||
4623 | |||
4624 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
4625 | return -ENOMEM; | ||
4626 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
4627 | data = (struct proc_data *)file->private_data; | ||
4628 | if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) { | ||
4629 | kfree (file->private_data); | ||
4630 | return -ENOMEM; | ||
4631 | } | ||
4632 | |||
4633 | readStatsRid(apriv, &stats, rid, 1); | ||
4634 | |||
4635 | j = 0; | ||
4636 | for(i=0; statsLabels[i]!=(char *)-1 && | ||
4637 | i*4<stats.len; i++){ | ||
4638 | if (!statsLabels[i]) continue; | ||
4639 | if (j+strlen(statsLabels[i])+16>4096) { | ||
4640 | printk(KERN_WARNING | ||
4641 | "airo: Potentially disasterous buffer overflow averted!\n"); | ||
4642 | break; | ||
4643 | } | ||
4644 | j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]); | ||
4645 | } | ||
4646 | if (i*4>=stats.len){ | ||
4647 | printk(KERN_WARNING | ||
4648 | "airo: Got a short rid\n"); | ||
4649 | } | ||
4650 | data->readlen = j; | ||
4651 | return 0; | ||
4652 | } | ||
4653 | |||
4654 | static int get_dec_u16( char *buffer, int *start, int limit ) { | ||
4655 | u16 value; | ||
4656 | int valid = 0; | ||
4657 | for( value = 0; buffer[*start] >= '0' && | ||
4658 | buffer[*start] <= '9' && | ||
4659 | *start < limit; (*start)++ ) { | ||
4660 | valid = 1; | ||
4661 | value *= 10; | ||
4662 | value += buffer[*start] - '0'; | ||
4663 | } | ||
4664 | if ( !valid ) return -1; | ||
4665 | return value; | ||
4666 | } | ||
4667 | |||
4668 | static int airo_config_commit(struct net_device *dev, | ||
4669 | struct iw_request_info *info, void *zwrq, | ||
4670 | char *extra); | ||
4671 | |||
4672 | static void proc_config_on_close( struct inode *inode, struct file *file ) { | ||
4673 | struct proc_data *data = file->private_data; | ||
4674 | struct proc_dir_entry *dp = PDE(inode); | ||
4675 | struct net_device *dev = dp->data; | ||
4676 | struct airo_info *ai = dev->priv; | ||
4677 | char *line; | ||
4678 | |||
4679 | if ( !data->writelen ) return; | ||
4680 | |||
4681 | readConfigRid(ai, 1); | ||
4682 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4683 | |||
4684 | line = data->wbuffer; | ||
4685 | while( line[0] ) { | ||
4686 | /*** Mode processing */ | ||
4687 | if ( !strncmp( line, "Mode: ", 6 ) ) { | ||
4688 | line += 6; | ||
4689 | if ((ai->config.rmode & 0xff) >= RXMODE_RFMON) | ||
4690 | set_bit (FLAG_RESET, &ai->flags); | ||
4691 | ai->config.rmode &= 0xfe00; | ||
4692 | clear_bit (FLAG_802_11, &ai->flags); | ||
4693 | ai->config.opmode &= 0xFF00; | ||
4694 | ai->config.scanMode = SCANMODE_ACTIVE; | ||
4695 | if ( line[0] == 'a' ) { | ||
4696 | ai->config.opmode |= 0; | ||
4697 | } else { | ||
4698 | ai->config.opmode |= 1; | ||
4699 | if ( line[0] == 'r' ) { | ||
4700 | ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; | ||
4701 | ai->config.scanMode = SCANMODE_PASSIVE; | ||
4702 | set_bit (FLAG_802_11, &ai->flags); | ||
4703 | } else if ( line[0] == 'y' ) { | ||
4704 | ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER; | ||
4705 | ai->config.scanMode = SCANMODE_PASSIVE; | ||
4706 | set_bit (FLAG_802_11, &ai->flags); | ||
4707 | } else if ( line[0] == 'l' ) | ||
4708 | ai->config.rmode |= RXMODE_LANMON; | ||
4709 | } | ||
4710 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4711 | } | ||
4712 | |||
4713 | /*** Radio status */ | ||
4714 | else if (!strncmp(line,"Radio: ", 7)) { | ||
4715 | line += 7; | ||
4716 | if (!strncmp(line,"off",3)) { | ||
4717 | set_bit (FLAG_RADIO_OFF, &ai->flags); | ||
4718 | } else { | ||
4719 | clear_bit (FLAG_RADIO_OFF, &ai->flags); | ||
4720 | } | ||
4721 | } | ||
4722 | /*** NodeName processing */ | ||
4723 | else if ( !strncmp( line, "NodeName: ", 10 ) ) { | ||
4724 | int j; | ||
4725 | |||
4726 | line += 10; | ||
4727 | memset( ai->config.nodeName, 0, 16 ); | ||
4728 | /* Do the name, assume a space between the mode and node name */ | ||
4729 | for( j = 0; j < 16 && line[j] != '\n'; j++ ) { | ||
4730 | ai->config.nodeName[j] = line[j]; | ||
4731 | } | ||
4732 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4733 | } | ||
4734 | |||
4735 | /*** PowerMode processing */ | ||
4736 | else if ( !strncmp( line, "PowerMode: ", 11 ) ) { | ||
4737 | line += 11; | ||
4738 | if ( !strncmp( line, "PSPCAM", 6 ) ) { | ||
4739 | ai->config.powerSaveMode = POWERSAVE_PSPCAM; | ||
4740 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4741 | } else if ( !strncmp( line, "PSP", 3 ) ) { | ||
4742 | ai->config.powerSaveMode = POWERSAVE_PSP; | ||
4743 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4744 | } else { | ||
4745 | ai->config.powerSaveMode = POWERSAVE_CAM; | ||
4746 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4747 | } | ||
4748 | } else if ( !strncmp( line, "DataRates: ", 11 ) ) { | ||
4749 | int v, i = 0, k = 0; /* i is index into line, | ||
4750 | k is index to rates */ | ||
4751 | |||
4752 | line += 11; | ||
4753 | while((v = get_dec_u16(line, &i, 3))!=-1) { | ||
4754 | ai->config.rates[k++] = (u8)v; | ||
4755 | line += i + 1; | ||
4756 | i = 0; | ||
4757 | } | ||
4758 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4759 | } else if ( !strncmp( line, "Channel: ", 9 ) ) { | ||
4760 | int v, i = 0; | ||
4761 | line += 9; | ||
4762 | v = get_dec_u16(line, &i, i+3); | ||
4763 | if ( v != -1 ) { | ||
4764 | ai->config.channelSet = (u16)v; | ||
4765 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4766 | } | ||
4767 | } else if ( !strncmp( line, "XmitPower: ", 11 ) ) { | ||
4768 | int v, i = 0; | ||
4769 | line += 11; | ||
4770 | v = get_dec_u16(line, &i, i+3); | ||
4771 | if ( v != -1 ) { | ||
4772 | ai->config.txPower = (u16)v; | ||
4773 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4774 | } | ||
4775 | } else if ( !strncmp( line, "WEP: ", 5 ) ) { | ||
4776 | line += 5; | ||
4777 | switch( line[0] ) { | ||
4778 | case 's': | ||
4779 | ai->config.authType = (u16)AUTH_SHAREDKEY; | ||
4780 | break; | ||
4781 | case 'e': | ||
4782 | ai->config.authType = (u16)AUTH_ENCRYPT; | ||
4783 | break; | ||
4784 | default: | ||
4785 | ai->config.authType = (u16)AUTH_OPEN; | ||
4786 | break; | ||
4787 | } | ||
4788 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4789 | } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) { | ||
4790 | int v, i = 0; | ||
4791 | |||
4792 | line += 16; | ||
4793 | v = get_dec_u16(line, &i, 3); | ||
4794 | v = (v<0) ? 0 : ((v>255) ? 255 : v); | ||
4795 | ai->config.longRetryLimit = (u16)v; | ||
4796 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4797 | } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) { | ||
4798 | int v, i = 0; | ||
4799 | |||
4800 | line += 17; | ||
4801 | v = get_dec_u16(line, &i, 3); | ||
4802 | v = (v<0) ? 0 : ((v>255) ? 255 : v); | ||
4803 | ai->config.shortRetryLimit = (u16)v; | ||
4804 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4805 | } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) { | ||
4806 | int v, i = 0; | ||
4807 | |||
4808 | line += 14; | ||
4809 | v = get_dec_u16(line, &i, 4); | ||
4810 | v = (v<0) ? 0 : ((v>2312) ? 2312 : v); | ||
4811 | ai->config.rtsThres = (u16)v; | ||
4812 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4813 | } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) { | ||
4814 | int v, i = 0; | ||
4815 | |||
4816 | line += 16; | ||
4817 | v = get_dec_u16(line, &i, 5); | ||
4818 | v = (v<0) ? 0 : v; | ||
4819 | ai->config.txLifetime = (u16)v; | ||
4820 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4821 | } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) { | ||
4822 | int v, i = 0; | ||
4823 | |||
4824 | line += 16; | ||
4825 | v = get_dec_u16(line, &i, 5); | ||
4826 | v = (v<0) ? 0 : v; | ||
4827 | ai->config.rxLifetime = (u16)v; | ||
4828 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4829 | } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) { | ||
4830 | ai->config.txDiversity = | ||
4831 | (line[13]=='l') ? 1 : | ||
4832 | ((line[13]=='r')? 2: 3); | ||
4833 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4834 | } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) { | ||
4835 | ai->config.rxDiversity = | ||
4836 | (line[13]=='l') ? 1 : | ||
4837 | ((line[13]=='r')? 2: 3); | ||
4838 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4839 | } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) { | ||
4840 | int v, i = 0; | ||
4841 | |||
4842 | line += 15; | ||
4843 | v = get_dec_u16(line, &i, 4); | ||
4844 | v = (v<256) ? 256 : ((v>2312) ? 2312 : v); | ||
4845 | v = v & 0xfffe; /* Make sure its even */ | ||
4846 | ai->config.fragThresh = (u16)v; | ||
4847 | set_bit (FLAG_COMMIT, &ai->flags); | ||
4848 | } else if (!strncmp(line, "Modulation: ", 12)) { | ||
4849 | line += 12; | ||
4850 | switch(*line) { | ||
4851 | case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; | ||
4852 | case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break; | ||
4853 | case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break; | ||
4854 | default: | ||
4855 | printk( KERN_WARNING "airo: Unknown modulation\n" ); | ||
4856 | } | ||
4857 | } else if (!strncmp(line, "Preamble: ", 10)) { | ||
4858 | line += 10; | ||
4859 | switch(*line) { | ||
4860 | case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break; | ||
4861 | case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break; | ||
4862 | case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break; | ||
4863 | default: printk(KERN_WARNING "airo: Unknown preamble\n"); | ||
4864 | } | ||
4865 | } else { | ||
4866 | printk( KERN_WARNING "Couldn't figure out %s\n", line ); | ||
4867 | } | ||
4868 | while( line[0] && line[0] != '\n' ) line++; | ||
4869 | if ( line[0] ) line++; | ||
4870 | } | ||
4871 | airo_config_commit(dev, NULL, NULL, NULL); | ||
4872 | } | ||
4873 | |||
4874 | static char *get_rmode(u16 mode) { | ||
4875 | switch(mode&0xff) { | ||
4876 | case RXMODE_RFMON: return "rfmon"; | ||
4877 | case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon"; | ||
4878 | case RXMODE_LANMON: return "lanmon"; | ||
4879 | } | ||
4880 | return "ESS"; | ||
4881 | } | ||
4882 | |||
4883 | static int proc_config_open( struct inode *inode, struct file *file ) { | ||
4884 | struct proc_data *data; | ||
4885 | struct proc_dir_entry *dp = PDE(inode); | ||
4886 | struct net_device *dev = dp->data; | ||
4887 | struct airo_info *ai = dev->priv; | ||
4888 | int i; | ||
4889 | |||
4890 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
4891 | return -ENOMEM; | ||
4892 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
4893 | data = (struct proc_data *)file->private_data; | ||
4894 | if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { | ||
4895 | kfree (file->private_data); | ||
4896 | return -ENOMEM; | ||
4897 | } | ||
4898 | if ((data->wbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { | ||
4899 | kfree (data->rbuffer); | ||
4900 | kfree (file->private_data); | ||
4901 | return -ENOMEM; | ||
4902 | } | ||
4903 | memset( data->wbuffer, 0, 2048 ); | ||
4904 | data->maxwritelen = 2048; | ||
4905 | data->on_close = proc_config_on_close; | ||
4906 | |||
4907 | readConfigRid(ai, 1); | ||
4908 | |||
4909 | i = sprintf( data->rbuffer, | ||
4910 | "Mode: %s\n" | ||
4911 | "Radio: %s\n" | ||
4912 | "NodeName: %-16s\n" | ||
4913 | "PowerMode: %s\n" | ||
4914 | "DataRates: %d %d %d %d %d %d %d %d\n" | ||
4915 | "Channel: %d\n" | ||
4916 | "XmitPower: %d\n", | ||
4917 | (ai->config.opmode & 0xFF) == 0 ? "adhoc" : | ||
4918 | (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode): | ||
4919 | (ai->config.opmode & 0xFF) == 2 ? "AP" : | ||
4920 | (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error", | ||
4921 | test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on", | ||
4922 | ai->config.nodeName, | ||
4923 | ai->config.powerSaveMode == 0 ? "CAM" : | ||
4924 | ai->config.powerSaveMode == 1 ? "PSP" : | ||
4925 | ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error", | ||
4926 | (int)ai->config.rates[0], | ||
4927 | (int)ai->config.rates[1], | ||
4928 | (int)ai->config.rates[2], | ||
4929 | (int)ai->config.rates[3], | ||
4930 | (int)ai->config.rates[4], | ||
4931 | (int)ai->config.rates[5], | ||
4932 | (int)ai->config.rates[6], | ||
4933 | (int)ai->config.rates[7], | ||
4934 | (int)ai->config.channelSet, | ||
4935 | (int)ai->config.txPower | ||
4936 | ); | ||
4937 | sprintf( data->rbuffer + i, | ||
4938 | "LongRetryLimit: %d\n" | ||
4939 | "ShortRetryLimit: %d\n" | ||
4940 | "RTSThreshold: %d\n" | ||
4941 | "TXMSDULifetime: %d\n" | ||
4942 | "RXMSDULifetime: %d\n" | ||
4943 | "TXDiversity: %s\n" | ||
4944 | "RXDiversity: %s\n" | ||
4945 | "FragThreshold: %d\n" | ||
4946 | "WEP: %s\n" | ||
4947 | "Modulation: %s\n" | ||
4948 | "Preamble: %s\n", | ||
4949 | (int)ai->config.longRetryLimit, | ||
4950 | (int)ai->config.shortRetryLimit, | ||
4951 | (int)ai->config.rtsThres, | ||
4952 | (int)ai->config.txLifetime, | ||
4953 | (int)ai->config.rxLifetime, | ||
4954 | ai->config.txDiversity == 1 ? "left" : | ||
4955 | ai->config.txDiversity == 2 ? "right" : "both", | ||
4956 | ai->config.rxDiversity == 1 ? "left" : | ||
4957 | ai->config.rxDiversity == 2 ? "right" : "both", | ||
4958 | (int)ai->config.fragThresh, | ||
4959 | ai->config.authType == AUTH_ENCRYPT ? "encrypt" : | ||
4960 | ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open", | ||
4961 | ai->config.modulation == 0 ? "default" : | ||
4962 | ai->config.modulation == MOD_CCK ? "cck" : | ||
4963 | ai->config.modulation == MOD_MOK ? "mok" : "error", | ||
4964 | ai->config.preamble == PREAMBLE_AUTO ? "auto" : | ||
4965 | ai->config.preamble == PREAMBLE_LONG ? "long" : | ||
4966 | ai->config.preamble == PREAMBLE_SHORT ? "short" : "error" | ||
4967 | ); | ||
4968 | data->readlen = strlen( data->rbuffer ); | ||
4969 | return 0; | ||
4970 | } | ||
4971 | |||
4972 | static void proc_SSID_on_close( struct inode *inode, struct file *file ) { | ||
4973 | struct proc_data *data = (struct proc_data *)file->private_data; | ||
4974 | struct proc_dir_entry *dp = PDE(inode); | ||
4975 | struct net_device *dev = dp->data; | ||
4976 | struct airo_info *ai = dev->priv; | ||
4977 | SsidRid SSID_rid; | ||
4978 | Resp rsp; | ||
4979 | int i; | ||
4980 | int offset = 0; | ||
4981 | |||
4982 | if ( !data->writelen ) return; | ||
4983 | |||
4984 | memset( &SSID_rid, 0, sizeof( SSID_rid ) ); | ||
4985 | |||
4986 | for( i = 0; i < 3; i++ ) { | ||
4987 | int j; | ||
4988 | for( j = 0; j+offset < data->writelen && j < 32 && | ||
4989 | data->wbuffer[offset+j] != '\n'; j++ ) { | ||
4990 | SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j]; | ||
4991 | } | ||
4992 | if ( j == 0 ) break; | ||
4993 | SSID_rid.ssids[i].len = j; | ||
4994 | offset += j; | ||
4995 | while( data->wbuffer[offset] != '\n' && | ||
4996 | offset < data->writelen ) offset++; | ||
4997 | offset++; | ||
4998 | } | ||
4999 | if (i) | ||
5000 | SSID_rid.len = sizeof(SSID_rid); | ||
5001 | disable_MAC(ai, 1); | ||
5002 | writeSsidRid(ai, &SSID_rid, 1); | ||
5003 | enable_MAC(ai, &rsp, 1); | ||
5004 | } | ||
5005 | |||
5006 | inline static u8 hexVal(char c) { | ||
5007 | if (c>='0' && c<='9') return c -= '0'; | ||
5008 | if (c>='a' && c<='f') return c -= 'a'-10; | ||
5009 | if (c>='A' && c<='F') return c -= 'A'-10; | ||
5010 | return 0; | ||
5011 | } | ||
5012 | |||
5013 | static void proc_APList_on_close( struct inode *inode, struct file *file ) { | ||
5014 | struct proc_data *data = (struct proc_data *)file->private_data; | ||
5015 | struct proc_dir_entry *dp = PDE(inode); | ||
5016 | struct net_device *dev = dp->data; | ||
5017 | struct airo_info *ai = dev->priv; | ||
5018 | APListRid APList_rid; | ||
5019 | Resp rsp; | ||
5020 | int i; | ||
5021 | |||
5022 | if ( !data->writelen ) return; | ||
5023 | |||
5024 | memset( &APList_rid, 0, sizeof(APList_rid) ); | ||
5025 | APList_rid.len = sizeof(APList_rid); | ||
5026 | |||
5027 | for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) { | ||
5028 | int j; | ||
5029 | for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) { | ||
5030 | switch(j%3) { | ||
5031 | case 0: | ||
5032 | APList_rid.ap[i][j/3]= | ||
5033 | hexVal(data->wbuffer[j+i*6*3])<<4; | ||
5034 | break; | ||
5035 | case 1: | ||
5036 | APList_rid.ap[i][j/3]|= | ||
5037 | hexVal(data->wbuffer[j+i*6*3]); | ||
5038 | break; | ||
5039 | } | ||
5040 | } | ||
5041 | } | ||
5042 | disable_MAC(ai, 1); | ||
5043 | writeAPListRid(ai, &APList_rid, 1); | ||
5044 | enable_MAC(ai, &rsp, 1); | ||
5045 | } | ||
5046 | |||
5047 | /* This function wraps PC4500_writerid with a MAC disable */ | ||
5048 | static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data, | ||
5049 | int len, int dummy ) { | ||
5050 | int rc; | ||
5051 | Resp rsp; | ||
5052 | |||
5053 | disable_MAC(ai, 1); | ||
5054 | rc = PC4500_writerid(ai, rid, rid_data, len, 1); | ||
5055 | enable_MAC(ai, &rsp, 1); | ||
5056 | return rc; | ||
5057 | } | ||
5058 | |||
5059 | /* Returns the length of the key at the index. If index == 0xffff | ||
5060 | * the index of the transmit key is returned. If the key doesn't exist, | ||
5061 | * -1 will be returned. | ||
5062 | */ | ||
5063 | static int get_wep_key(struct airo_info *ai, u16 index) { | ||
5064 | WepKeyRid wkr; | ||
5065 | int rc; | ||
5066 | u16 lastindex; | ||
5067 | |||
5068 | rc = readWepKeyRid(ai, &wkr, 1, 1); | ||
5069 | if (rc == SUCCESS) do { | ||
5070 | lastindex = wkr.kindex; | ||
5071 | if (wkr.kindex == index) { | ||
5072 | if (index == 0xffff) { | ||
5073 | return wkr.mac[0]; | ||
5074 | } | ||
5075 | return wkr.klen; | ||
5076 | } | ||
5077 | readWepKeyRid(ai, &wkr, 0, 1); | ||
5078 | } while(lastindex != wkr.kindex); | ||
5079 | return -1; | ||
5080 | } | ||
5081 | |||
5082 | static int set_wep_key(struct airo_info *ai, u16 index, | ||
5083 | const char *key, u16 keylen, int perm, int lock ) { | ||
5084 | static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; | ||
5085 | WepKeyRid wkr; | ||
5086 | Resp rsp; | ||
5087 | |||
5088 | memset(&wkr, 0, sizeof(wkr)); | ||
5089 | if (keylen == 0) { | ||
5090 | // We are selecting which key to use | ||
5091 | wkr.len = sizeof(wkr); | ||
5092 | wkr.kindex = 0xffff; | ||
5093 | wkr.mac[0] = (char)index; | ||
5094 | if (perm) printk(KERN_INFO "Setting transmit key to %d\n", index); | ||
5095 | if (perm) ai->defindex = (char)index; | ||
5096 | } else { | ||
5097 | // We are actually setting the key | ||
5098 | wkr.len = sizeof(wkr); | ||
5099 | wkr.kindex = index; | ||
5100 | wkr.klen = keylen; | ||
5101 | memcpy( wkr.key, key, keylen ); | ||
5102 | memcpy( wkr.mac, macaddr, ETH_ALEN ); | ||
5103 | printk(KERN_INFO "Setting key %d\n", index); | ||
5104 | } | ||
5105 | |||
5106 | disable_MAC(ai, lock); | ||
5107 | writeWepKeyRid(ai, &wkr, perm, lock); | ||
5108 | enable_MAC(ai, &rsp, lock); | ||
5109 | return 0; | ||
5110 | } | ||
5111 | |||
5112 | static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { | ||
5113 | struct proc_data *data; | ||
5114 | struct proc_dir_entry *dp = PDE(inode); | ||
5115 | struct net_device *dev = dp->data; | ||
5116 | struct airo_info *ai = dev->priv; | ||
5117 | int i; | ||
5118 | char key[16]; | ||
5119 | u16 index = 0; | ||
5120 | int j = 0; | ||
5121 | |||
5122 | memset(key, 0, sizeof(key)); | ||
5123 | |||
5124 | data = (struct proc_data *)file->private_data; | ||
5125 | if ( !data->writelen ) return; | ||
5126 | |||
5127 | if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' && | ||
5128 | (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) { | ||
5129 | index = data->wbuffer[0] - '0'; | ||
5130 | if (data->wbuffer[1] == '\n') { | ||
5131 | set_wep_key(ai, index, NULL, 0, 1, 1); | ||
5132 | return; | ||
5133 | } | ||
5134 | j = 2; | ||
5135 | } else { | ||
5136 | printk(KERN_ERR "airo: WepKey passed invalid key index\n"); | ||
5137 | return; | ||
5138 | } | ||
5139 | |||
5140 | for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) { | ||
5141 | switch(i%3) { | ||
5142 | case 0: | ||
5143 | key[i/3] = hexVal(data->wbuffer[i+j])<<4; | ||
5144 | break; | ||
5145 | case 1: | ||
5146 | key[i/3] |= hexVal(data->wbuffer[i+j]); | ||
5147 | break; | ||
5148 | } | ||
5149 | } | ||
5150 | set_wep_key(ai, index, key, i/3, 1, 1); | ||
5151 | } | ||
5152 | |||
5153 | static int proc_wepkey_open( struct inode *inode, struct file *file ) { | ||
5154 | struct proc_data *data; | ||
5155 | struct proc_dir_entry *dp = PDE(inode); | ||
5156 | struct net_device *dev = dp->data; | ||
5157 | struct airo_info *ai = dev->priv; | ||
5158 | char *ptr; | ||
5159 | WepKeyRid wkr; | ||
5160 | u16 lastindex; | ||
5161 | int j=0; | ||
5162 | int rc; | ||
5163 | |||
5164 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
5165 | return -ENOMEM; | ||
5166 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
5167 | memset(&wkr, 0, sizeof(wkr)); | ||
5168 | data = (struct proc_data *)file->private_data; | ||
5169 | if ((data->rbuffer = kmalloc( 180, GFP_KERNEL )) == NULL) { | ||
5170 | kfree (file->private_data); | ||
5171 | return -ENOMEM; | ||
5172 | } | ||
5173 | memset(data->rbuffer, 0, 180); | ||
5174 | data->writelen = 0; | ||
5175 | data->maxwritelen = 80; | ||
5176 | if ((data->wbuffer = kmalloc( 80, GFP_KERNEL )) == NULL) { | ||
5177 | kfree (data->rbuffer); | ||
5178 | kfree (file->private_data); | ||
5179 | return -ENOMEM; | ||
5180 | } | ||
5181 | memset( data->wbuffer, 0, 80 ); | ||
5182 | data->on_close = proc_wepkey_on_close; | ||
5183 | |||
5184 | ptr = data->rbuffer; | ||
5185 | strcpy(ptr, "No wep keys\n"); | ||
5186 | rc = readWepKeyRid(ai, &wkr, 1, 1); | ||
5187 | if (rc == SUCCESS) do { | ||
5188 | lastindex = wkr.kindex; | ||
5189 | if (wkr.kindex == 0xffff) { | ||
5190 | j += sprintf(ptr+j, "Tx key = %d\n", | ||
5191 | (int)wkr.mac[0]); | ||
5192 | } else { | ||
5193 | j += sprintf(ptr+j, "Key %d set with length = %d\n", | ||
5194 | (int)wkr.kindex, (int)wkr.klen); | ||
5195 | } | ||
5196 | readWepKeyRid(ai, &wkr, 0, 1); | ||
5197 | } while((lastindex != wkr.kindex) && (j < 180-30)); | ||
5198 | |||
5199 | data->readlen = strlen( data->rbuffer ); | ||
5200 | return 0; | ||
5201 | } | ||
5202 | |||
5203 | static int proc_SSID_open( struct inode *inode, struct file *file ) { | ||
5204 | struct proc_data *data; | ||
5205 | struct proc_dir_entry *dp = PDE(inode); | ||
5206 | struct net_device *dev = dp->data; | ||
5207 | struct airo_info *ai = dev->priv; | ||
5208 | int i; | ||
5209 | char *ptr; | ||
5210 | SsidRid SSID_rid; | ||
5211 | |||
5212 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
5213 | return -ENOMEM; | ||
5214 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
5215 | data = (struct proc_data *)file->private_data; | ||
5216 | if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) { | ||
5217 | kfree (file->private_data); | ||
5218 | return -ENOMEM; | ||
5219 | } | ||
5220 | data->writelen = 0; | ||
5221 | data->maxwritelen = 33*3; | ||
5222 | if ((data->wbuffer = kmalloc( 33*3, GFP_KERNEL )) == NULL) { | ||
5223 | kfree (data->rbuffer); | ||
5224 | kfree (file->private_data); | ||
5225 | return -ENOMEM; | ||
5226 | } | ||
5227 | memset( data->wbuffer, 0, 33*3 ); | ||
5228 | data->on_close = proc_SSID_on_close; | ||
5229 | |||
5230 | readSsidRid(ai, &SSID_rid); | ||
5231 | ptr = data->rbuffer; | ||
5232 | for( i = 0; i < 3; i++ ) { | ||
5233 | int j; | ||
5234 | if ( !SSID_rid.ssids[i].len ) break; | ||
5235 | for( j = 0; j < 32 && | ||
5236 | j < SSID_rid.ssids[i].len && | ||
5237 | SSID_rid.ssids[i].ssid[j]; j++ ) { | ||
5238 | *ptr++ = SSID_rid.ssids[i].ssid[j]; | ||
5239 | } | ||
5240 | *ptr++ = '\n'; | ||
5241 | } | ||
5242 | *ptr = '\0'; | ||
5243 | data->readlen = strlen( data->rbuffer ); | ||
5244 | return 0; | ||
5245 | } | ||
5246 | |||
5247 | static int proc_APList_open( struct inode *inode, struct file *file ) { | ||
5248 | struct proc_data *data; | ||
5249 | struct proc_dir_entry *dp = PDE(inode); | ||
5250 | struct net_device *dev = dp->data; | ||
5251 | struct airo_info *ai = dev->priv; | ||
5252 | int i; | ||
5253 | char *ptr; | ||
5254 | APListRid APList_rid; | ||
5255 | |||
5256 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
5257 | return -ENOMEM; | ||
5258 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
5259 | data = (struct proc_data *)file->private_data; | ||
5260 | if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) { | ||
5261 | kfree (file->private_data); | ||
5262 | return -ENOMEM; | ||
5263 | } | ||
5264 | data->writelen = 0; | ||
5265 | data->maxwritelen = 4*6*3; | ||
5266 | if ((data->wbuffer = kmalloc( data->maxwritelen, GFP_KERNEL )) == NULL) { | ||
5267 | kfree (data->rbuffer); | ||
5268 | kfree (file->private_data); | ||
5269 | return -ENOMEM; | ||
5270 | } | ||
5271 | memset( data->wbuffer, 0, data->maxwritelen ); | ||
5272 | data->on_close = proc_APList_on_close; | ||
5273 | |||
5274 | readAPListRid(ai, &APList_rid); | ||
5275 | ptr = data->rbuffer; | ||
5276 | for( i = 0; i < 4; i++ ) { | ||
5277 | // We end when we find a zero MAC | ||
5278 | if ( !*(int*)APList_rid.ap[i] && | ||
5279 | !*(int*)&APList_rid.ap[i][2]) break; | ||
5280 | ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
5281 | (int)APList_rid.ap[i][0], | ||
5282 | (int)APList_rid.ap[i][1], | ||
5283 | (int)APList_rid.ap[i][2], | ||
5284 | (int)APList_rid.ap[i][3], | ||
5285 | (int)APList_rid.ap[i][4], | ||
5286 | (int)APList_rid.ap[i][5]); | ||
5287 | } | ||
5288 | if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); | ||
5289 | |||
5290 | *ptr = '\0'; | ||
5291 | data->readlen = strlen( data->rbuffer ); | ||
5292 | return 0; | ||
5293 | } | ||
5294 | |||
5295 | static int proc_BSSList_open( struct inode *inode, struct file *file ) { | ||
5296 | struct proc_data *data; | ||
5297 | struct proc_dir_entry *dp = PDE(inode); | ||
5298 | struct net_device *dev = dp->data; | ||
5299 | struct airo_info *ai = dev->priv; | ||
5300 | char *ptr; | ||
5301 | BSSListRid BSSList_rid; | ||
5302 | int rc; | ||
5303 | /* If doLoseSync is not 1, we won't do a Lose Sync */ | ||
5304 | int doLoseSync = -1; | ||
5305 | |||
5306 | if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | ||
5307 | return -ENOMEM; | ||
5308 | memset(file->private_data, 0, sizeof(struct proc_data)); | ||
5309 | data = (struct proc_data *)file->private_data; | ||
5310 | if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) { | ||
5311 | kfree (file->private_data); | ||
5312 | return -ENOMEM; | ||
5313 | } | ||
5314 | data->writelen = 0; | ||
5315 | data->maxwritelen = 0; | ||
5316 | data->wbuffer = NULL; | ||
5317 | data->on_close = NULL; | ||
5318 | |||
5319 | if (file->f_mode & FMODE_WRITE) { | ||
5320 | if (!(file->f_mode & FMODE_READ)) { | ||
5321 | Cmd cmd; | ||
5322 | Resp rsp; | ||
5323 | |||
5324 | if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; | ||
5325 | memset(&cmd, 0, sizeof(cmd)); | ||
5326 | cmd.cmd=CMD_LISTBSS; | ||
5327 | if (down_interruptible(&ai->sem)) | ||
5328 | return -ERESTARTSYS; | ||
5329 | issuecommand(ai, &cmd, &rsp); | ||
5330 | up(&ai->sem); | ||
5331 | data->readlen = 0; | ||
5332 | return 0; | ||
5333 | } | ||
5334 | doLoseSync = 1; | ||
5335 | } | ||
5336 | ptr = data->rbuffer; | ||
5337 | /* There is a race condition here if there are concurrent opens. | ||
5338 | Since it is a rare condition, we'll just live with it, otherwise | ||
5339 | we have to add a spin lock... */ | ||
5340 | rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); | ||
5341 | while(rc == 0 && BSSList_rid.index != 0xffff) { | ||
5342 | ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d", | ||
5343 | (int)BSSList_rid.bssid[0], | ||
5344 | (int)BSSList_rid.bssid[1], | ||
5345 | (int)BSSList_rid.bssid[2], | ||
5346 | (int)BSSList_rid.bssid[3], | ||
5347 | (int)BSSList_rid.bssid[4], | ||
5348 | (int)BSSList_rid.bssid[5], | ||
5349 | (int)BSSList_rid.ssidLen, | ||
5350 | BSSList_rid.ssid, | ||
5351 | (int)BSSList_rid.rssi); | ||
5352 | ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", | ||
5353 | (int)BSSList_rid.dsChannel, | ||
5354 | BSSList_rid.cap & CAP_ESS ? "ESS" : "", | ||
5355 | BSSList_rid.cap & CAP_IBSS ? "adhoc" : "", | ||
5356 | BSSList_rid.cap & CAP_PRIVACY ? "wep" : "", | ||
5357 | BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : ""); | ||
5358 | rc = readBSSListRid(ai, 0, &BSSList_rid); | ||
5359 | } | ||
5360 | *ptr = '\0'; | ||
5361 | data->readlen = strlen( data->rbuffer ); | ||
5362 | return 0; | ||
5363 | } | ||
5364 | |||
5365 | static int proc_close( struct inode *inode, struct file *file ) | ||
5366 | { | ||
5367 | struct proc_data *data = (struct proc_data *)file->private_data; | ||
5368 | if ( data->on_close != NULL ) data->on_close( inode, file ); | ||
5369 | if ( data->rbuffer ) kfree( data->rbuffer ); | ||
5370 | if ( data->wbuffer ) kfree( data->wbuffer ); | ||
5371 | kfree( data ); | ||
5372 | return 0; | ||
5373 | } | ||
5374 | |||
5375 | static struct net_device_list { | ||
5376 | struct net_device *dev; | ||
5377 | struct net_device_list *next; | ||
5378 | } *airo_devices; | ||
5379 | |||
5380 | /* Since the card doesn't automatically switch to the right WEP mode, | ||
5381 | we will make it do it. If the card isn't associated, every secs we | ||
5382 | will switch WEP modes to see if that will help. If the card is | ||
5383 | associated we will check every minute to see if anything has | ||
5384 | changed. */ | ||
5385 | static void timer_func( struct net_device *dev ) { | ||
5386 | struct airo_info *apriv = dev->priv; | ||
5387 | Resp rsp; | ||
5388 | |||
5389 | /* We don't have a link so try changing the authtype */ | ||
5390 | readConfigRid(apriv, 0); | ||
5391 | disable_MAC(apriv, 0); | ||
5392 | switch(apriv->config.authType) { | ||
5393 | case AUTH_ENCRYPT: | ||
5394 | /* So drop to OPEN */ | ||
5395 | apriv->config.authType = AUTH_OPEN; | ||
5396 | break; | ||
5397 | case AUTH_SHAREDKEY: | ||
5398 | if (apriv->keyindex < auto_wep) { | ||
5399 | set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0); | ||
5400 | apriv->config.authType = AUTH_SHAREDKEY; | ||
5401 | apriv->keyindex++; | ||
5402 | } else { | ||
5403 | /* Drop to ENCRYPT */ | ||
5404 | apriv->keyindex = 0; | ||
5405 | set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0); | ||
5406 | apriv->config.authType = AUTH_ENCRYPT; | ||
5407 | } | ||
5408 | break; | ||
5409 | default: /* We'll escalate to SHAREDKEY */ | ||
5410 | apriv->config.authType = AUTH_SHAREDKEY; | ||
5411 | } | ||
5412 | set_bit (FLAG_COMMIT, &apriv->flags); | ||
5413 | writeConfigRid(apriv, 0); | ||
5414 | enable_MAC(apriv, &rsp, 0); | ||
5415 | up(&apriv->sem); | ||
5416 | |||
5417 | /* Schedule check to see if the change worked */ | ||
5418 | clear_bit(JOB_AUTOWEP, &apriv->flags); | ||
5419 | apriv->expires = RUN_AT(HZ*3); | ||
5420 | } | ||
5421 | |||
5422 | static int add_airo_dev( struct net_device *dev ) { | ||
5423 | struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL ); | ||
5424 | if ( !node ) | ||
5425 | return -ENOMEM; | ||
5426 | |||
5427 | node->dev = dev; | ||
5428 | node->next = airo_devices; | ||
5429 | airo_devices = node; | ||
5430 | |||
5431 | return 0; | ||
5432 | } | ||
5433 | |||
5434 | static void del_airo_dev( struct net_device *dev ) { | ||
5435 | struct net_device_list **p = &airo_devices; | ||
5436 | while( *p && ( (*p)->dev != dev ) ) | ||
5437 | p = &(*p)->next; | ||
5438 | if ( *p && (*p)->dev == dev ) | ||
5439 | *p = (*p)->next; | ||
5440 | } | ||
5441 | |||
5442 | #ifdef CONFIG_PCI | ||
5443 | static int __devinit airo_pci_probe(struct pci_dev *pdev, | ||
5444 | const struct pci_device_id *pent) | ||
5445 | { | ||
5446 | struct net_device *dev; | ||
5447 | |||
5448 | if (pci_enable_device(pdev)) | ||
5449 | return -ENODEV; | ||
5450 | pci_set_master(pdev); | ||
5451 | |||
5452 | if (pdev->device == 0x5000 || pdev->device == 0xa504) | ||
5453 | dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); | ||
5454 | else | ||
5455 | dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); | ||
5456 | if (!dev) | ||
5457 | return -ENODEV; | ||
5458 | |||
5459 | pci_set_drvdata(pdev, dev); | ||
5460 | return 0; | ||
5461 | } | ||
5462 | |||
5463 | static void __devexit airo_pci_remove(struct pci_dev *pdev) | ||
5464 | { | ||
5465 | } | ||
5466 | |||
5467 | static int airo_pci_suspend(struct pci_dev *pdev, u32 state) | ||
5468 | { | ||
5469 | struct net_device *dev = pci_get_drvdata(pdev); | ||
5470 | struct airo_info *ai = dev->priv; | ||
5471 | Cmd cmd; | ||
5472 | Resp rsp; | ||
5473 | |||
5474 | if ((ai->APList == NULL) && | ||
5475 | (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL) | ||
5476 | return -ENOMEM; | ||
5477 | if ((ai->SSID == NULL) && | ||
5478 | (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL) | ||
5479 | return -ENOMEM; | ||
5480 | readAPListRid(ai, ai->APList); | ||
5481 | readSsidRid(ai, ai->SSID); | ||
5482 | memset(&cmd, 0, sizeof(cmd)); | ||
5483 | /* the lock will be released at the end of the resume callback */ | ||
5484 | if (down_interruptible(&ai->sem)) | ||
5485 | return -EAGAIN; | ||
5486 | disable_MAC(ai, 0); | ||
5487 | netif_device_detach(dev); | ||
5488 | ai->power = state; | ||
5489 | cmd.cmd=HOSTSLEEP; | ||
5490 | issuecommand(ai, &cmd, &rsp); | ||
5491 | |||
5492 | pci_enable_wake(pdev, state, 1); | ||
5493 | pci_save_state(pdev); | ||
5494 | return pci_set_power_state(pdev, state); | ||
5495 | } | ||
5496 | |||
5497 | static int airo_pci_resume(struct pci_dev *pdev) | ||
5498 | { | ||
5499 | struct net_device *dev = pci_get_drvdata(pdev); | ||
5500 | struct airo_info *ai = dev->priv; | ||
5501 | Resp rsp; | ||
5502 | |||
5503 | pci_set_power_state(pdev, 0); | ||
5504 | pci_restore_state(pdev); | ||
5505 | pci_enable_wake(pdev, ai->power, 0); | ||
5506 | |||
5507 | if (ai->power > 1) { | ||
5508 | reset_card(dev, 0); | ||
5509 | mpi_init_descriptors(ai); | ||
5510 | setup_card(ai, dev->dev_addr, 0); | ||
5511 | clear_bit(FLAG_RADIO_OFF, &ai->flags); | ||
5512 | clear_bit(FLAG_PENDING_XMIT, &ai->flags); | ||
5513 | } else { | ||
5514 | OUT4500(ai, EVACK, EV_AWAKEN); | ||
5515 | OUT4500(ai, EVACK, EV_AWAKEN); | ||
5516 | msleep(100); | ||
5517 | } | ||
5518 | |||
5519 | set_bit (FLAG_COMMIT, &ai->flags); | ||
5520 | disable_MAC(ai, 0); | ||
5521 | msleep(200); | ||
5522 | if (ai->SSID) { | ||
5523 | writeSsidRid(ai, ai->SSID, 0); | ||
5524 | kfree(ai->SSID); | ||
5525 | ai->SSID = NULL; | ||
5526 | } | ||
5527 | if (ai->APList) { | ||
5528 | writeAPListRid(ai, ai->APList, 0); | ||
5529 | kfree(ai->APList); | ||
5530 | ai->APList = NULL; | ||
5531 | } | ||
5532 | writeConfigRid(ai, 0); | ||
5533 | enable_MAC(ai, &rsp, 0); | ||
5534 | ai->power = 0; | ||
5535 | netif_device_attach(dev); | ||
5536 | netif_wake_queue(dev); | ||
5537 | enable_interrupts(ai); | ||
5538 | up(&ai->sem); | ||
5539 | return 0; | ||
5540 | } | ||
5541 | #endif | ||
5542 | |||
5543 | static int __init airo_init_module( void ) | ||
5544 | { | ||
5545 | int i, have_isa_dev = 0; | ||
5546 | |||
5547 | airo_entry = create_proc_entry("aironet", | ||
5548 | S_IFDIR | airo_perm, | ||
5549 | proc_root_driver); | ||
5550 | airo_entry->uid = proc_uid; | ||
5551 | airo_entry->gid = proc_gid; | ||
5552 | |||
5553 | for( i = 0; i < 4 && io[i] && irq[i]; i++ ) { | ||
5554 | printk( KERN_INFO | ||
5555 | "airo: Trying to configure ISA adapter at irq=%d io=0x%x\n", | ||
5556 | irq[i], io[i] ); | ||
5557 | if (init_airo_card( irq[i], io[i], 0, NULL )) | ||
5558 | have_isa_dev = 1; | ||
5559 | } | ||
5560 | |||
5561 | #ifdef CONFIG_PCI | ||
5562 | printk( KERN_INFO "airo: Probing for PCI adapters\n" ); | ||
5563 | pci_register_driver(&airo_driver); | ||
5564 | printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); | ||
5565 | #endif | ||
5566 | |||
5567 | /* Always exit with success, as we are a library module | ||
5568 | * as well as a driver module | ||
5569 | */ | ||
5570 | return 0; | ||
5571 | } | ||
5572 | |||
5573 | static void __exit airo_cleanup_module( void ) | ||
5574 | { | ||
5575 | while( airo_devices ) { | ||
5576 | printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); | ||
5577 | stop_airo_card( airo_devices->dev, 1 ); | ||
5578 | } | ||
5579 | #ifdef CONFIG_PCI | ||
5580 | pci_unregister_driver(&airo_driver); | ||
5581 | #endif | ||
5582 | remove_proc_entry("aironet", proc_root_driver); | ||
5583 | } | ||
5584 | |||
5585 | #ifdef WIRELESS_EXT | ||
5586 | /* | ||
5587 | * Initial Wireless Extension code for Aironet driver by : | ||
5588 | * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00 | ||
5589 | * Conversion to new driver API by : | ||
5590 | * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02 | ||
5591 | * Javier also did a good amount of work here, adding some new extensions | ||
5592 | * and fixing my code. Let's just say that without him this code just | ||
5593 | * would not work at all... - Jean II | ||
5594 | */ | ||
5595 | |||
5596 | static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) | ||
5597 | { | ||
5598 | int quality = 0; | ||
5599 | |||
5600 | if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) { | ||
5601 | if (memcmp(cap_rid->prodName, "350", 3)) | ||
5602 | if (status_rid->signalQuality > 0x20) | ||
5603 | quality = 0; | ||
5604 | else | ||
5605 | quality = 0x20 - status_rid->signalQuality; | ||
5606 | else | ||
5607 | if (status_rid->signalQuality > 0xb0) | ||
5608 | quality = 0; | ||
5609 | else if (status_rid->signalQuality < 0x10) | ||
5610 | quality = 0xa0; | ||
5611 | else | ||
5612 | quality = 0xb0 - status_rid->signalQuality; | ||
5613 | } | ||
5614 | return quality; | ||
5615 | } | ||
5616 | |||
5617 | #define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) | ||
5618 | #define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50); | ||
5619 | |||
5620 | /*------------------------------------------------------------------*/ | ||
5621 | /* | ||
5622 | * Wireless Handler : get protocol name | ||
5623 | */ | ||
5624 | static int airo_get_name(struct net_device *dev, | ||
5625 | struct iw_request_info *info, | ||
5626 | char *cwrq, | ||
5627 | char *extra) | ||
5628 | { | ||
5629 | strcpy(cwrq, "IEEE 802.11-DS"); | ||
5630 | return 0; | ||
5631 | } | ||
5632 | |||
5633 | /*------------------------------------------------------------------*/ | ||
5634 | /* | ||
5635 | * Wireless Handler : set frequency | ||
5636 | */ | ||
5637 | static int airo_set_freq(struct net_device *dev, | ||
5638 | struct iw_request_info *info, | ||
5639 | struct iw_freq *fwrq, | ||
5640 | char *extra) | ||
5641 | { | ||
5642 | struct airo_info *local = dev->priv; | ||
5643 | int rc = -EINPROGRESS; /* Call commit handler */ | ||
5644 | |||
5645 | /* If setting by frequency, convert to a channel */ | ||
5646 | if((fwrq->e == 1) && | ||
5647 | (fwrq->m >= (int) 2.412e8) && | ||
5648 | (fwrq->m <= (int) 2.487e8)) { | ||
5649 | int f = fwrq->m / 100000; | ||
5650 | int c = 0; | ||
5651 | while((c < 14) && (f != frequency_list[c])) | ||
5652 | c++; | ||
5653 | /* Hack to fall through... */ | ||
5654 | fwrq->e = 0; | ||
5655 | fwrq->m = c + 1; | ||
5656 | } | ||
5657 | /* Setting by channel number */ | ||
5658 | if((fwrq->m > 1000) || (fwrq->e > 0)) | ||
5659 | rc = -EOPNOTSUPP; | ||
5660 | else { | ||
5661 | int channel = fwrq->m; | ||
5662 | /* We should do a better check than that, | ||
5663 | * based on the card capability !!! */ | ||
5664 | if((channel < 1) || (channel > 16)) { | ||
5665 | printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); | ||
5666 | rc = -EINVAL; | ||
5667 | } else { | ||
5668 | readConfigRid(local, 1); | ||
5669 | /* Yes ! We can set it !!! */ | ||
5670 | local->config.channelSet = (u16)(channel - 1); | ||
5671 | set_bit (FLAG_COMMIT, &local->flags); | ||
5672 | } | ||
5673 | } | ||
5674 | return rc; | ||
5675 | } | ||
5676 | |||
5677 | /*------------------------------------------------------------------*/ | ||
5678 | /* | ||
5679 | * Wireless Handler : get frequency | ||
5680 | */ | ||
5681 | static int airo_get_freq(struct net_device *dev, | ||
5682 | struct iw_request_info *info, | ||
5683 | struct iw_freq *fwrq, | ||
5684 | char *extra) | ||
5685 | { | ||
5686 | struct airo_info *local = dev->priv; | ||
5687 | StatusRid status_rid; /* Card status info */ | ||
5688 | |||
5689 | readConfigRid(local, 1); | ||
5690 | if ((local->config.opmode & 0xFF) == MODE_STA_ESS) | ||
5691 | status_rid.channel = local->config.channelSet; | ||
5692 | else | ||
5693 | readStatusRid(local, &status_rid, 1); | ||
5694 | |||
5695 | #ifdef WEXT_USECHANNELS | ||
5696 | fwrq->m = ((int)status_rid.channel) + 1; | ||
5697 | fwrq->e = 0; | ||
5698 | #else | ||
5699 | { | ||
5700 | int f = (int)status_rid.channel; | ||
5701 | fwrq->m = frequency_list[f] * 100000; | ||
5702 | fwrq->e = 1; | ||
5703 | } | ||
5704 | #endif | ||
5705 | |||
5706 | return 0; | ||
5707 | } | ||
5708 | |||
5709 | /*------------------------------------------------------------------*/ | ||
5710 | /* | ||
5711 | * Wireless Handler : set ESSID | ||
5712 | */ | ||
5713 | static int airo_set_essid(struct net_device *dev, | ||
5714 | struct iw_request_info *info, | ||
5715 | struct iw_point *dwrq, | ||
5716 | char *extra) | ||
5717 | { | ||
5718 | struct airo_info *local = dev->priv; | ||
5719 | Resp rsp; | ||
5720 | SsidRid SSID_rid; /* SSIDs */ | ||
5721 | |||
5722 | /* Reload the list of current SSID */ | ||
5723 | readSsidRid(local, &SSID_rid); | ||
5724 | |||
5725 | /* Check if we asked for `any' */ | ||
5726 | if(dwrq->flags == 0) { | ||
5727 | /* Just send an empty SSID list */ | ||
5728 | memset(&SSID_rid, 0, sizeof(SSID_rid)); | ||
5729 | } else { | ||
5730 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
5731 | |||
5732 | /* Check the size of the string */ | ||
5733 | if(dwrq->length > IW_ESSID_MAX_SIZE+1) { | ||
5734 | return -E2BIG ; | ||
5735 | } | ||
5736 | /* Check if index is valid */ | ||
5737 | if((index < 0) || (index >= 4)) { | ||
5738 | return -EINVAL; | ||
5739 | } | ||
5740 | |||
5741 | /* Set the SSID */ | ||
5742 | memset(SSID_rid.ssids[index].ssid, 0, | ||
5743 | sizeof(SSID_rid.ssids[index].ssid)); | ||
5744 | memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); | ||
5745 | SSID_rid.ssids[index].len = dwrq->length - 1; | ||
5746 | } | ||
5747 | SSID_rid.len = sizeof(SSID_rid); | ||
5748 | /* Write it to the card */ | ||
5749 | disable_MAC(local, 1); | ||
5750 | writeSsidRid(local, &SSID_rid, 1); | ||
5751 | enable_MAC(local, &rsp, 1); | ||
5752 | |||
5753 | return 0; | ||
5754 | } | ||
5755 | |||
5756 | /*------------------------------------------------------------------*/ | ||
5757 | /* | ||
5758 | * Wireless Handler : get ESSID | ||
5759 | */ | ||
5760 | static int airo_get_essid(struct net_device *dev, | ||
5761 | struct iw_request_info *info, | ||
5762 | struct iw_point *dwrq, | ||
5763 | char *extra) | ||
5764 | { | ||
5765 | struct airo_info *local = dev->priv; | ||
5766 | StatusRid status_rid; /* Card status info */ | ||
5767 | |||
5768 | readStatusRid(local, &status_rid, 1); | ||
5769 | |||
5770 | /* Note : if dwrq->flags != 0, we should | ||
5771 | * get the relevant SSID from the SSID list... */ | ||
5772 | |||
5773 | /* Get the current SSID */ | ||
5774 | memcpy(extra, status_rid.SSID, status_rid.SSIDlen); | ||
5775 | extra[status_rid.SSIDlen] = '\0'; | ||
5776 | /* If none, we may want to get the one that was set */ | ||
5777 | |||
5778 | /* Push it out ! */ | ||
5779 | dwrq->length = status_rid.SSIDlen + 1; | ||
5780 | dwrq->flags = 1; /* active */ | ||
5781 | |||
5782 | return 0; | ||
5783 | } | ||
5784 | |||
5785 | /*------------------------------------------------------------------*/ | ||
5786 | /* | ||
5787 | * Wireless Handler : set AP address | ||
5788 | */ | ||
5789 | static int airo_set_wap(struct net_device *dev, | ||
5790 | struct iw_request_info *info, | ||
5791 | struct sockaddr *awrq, | ||
5792 | char *extra) | ||
5793 | { | ||
5794 | struct airo_info *local = dev->priv; | ||
5795 | Cmd cmd; | ||
5796 | Resp rsp; | ||
5797 | APListRid APList_rid; | ||
5798 | static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; | ||
5799 | |||
5800 | if (awrq->sa_family != ARPHRD_ETHER) | ||
5801 | return -EINVAL; | ||
5802 | else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) { | ||
5803 | memset(&cmd, 0, sizeof(cmd)); | ||
5804 | cmd.cmd=CMD_LOSE_SYNC; | ||
5805 | if (down_interruptible(&local->sem)) | ||
5806 | return -ERESTARTSYS; | ||
5807 | issuecommand(local, &cmd, &rsp); | ||
5808 | up(&local->sem); | ||
5809 | } else { | ||
5810 | memset(&APList_rid, 0, sizeof(APList_rid)); | ||
5811 | APList_rid.len = sizeof(APList_rid); | ||
5812 | memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN); | ||
5813 | disable_MAC(local, 1); | ||
5814 | writeAPListRid(local, &APList_rid, 1); | ||
5815 | enable_MAC(local, &rsp, 1); | ||
5816 | } | ||
5817 | return 0; | ||
5818 | } | ||
5819 | |||
5820 | /*------------------------------------------------------------------*/ | ||
5821 | /* | ||
5822 | * Wireless Handler : get AP address | ||
5823 | */ | ||
5824 | static int airo_get_wap(struct net_device *dev, | ||
5825 | struct iw_request_info *info, | ||
5826 | struct sockaddr *awrq, | ||
5827 | char *extra) | ||
5828 | { | ||
5829 | struct airo_info *local = dev->priv; | ||
5830 | StatusRid status_rid; /* Card status info */ | ||
5831 | |||
5832 | readStatusRid(local, &status_rid, 1); | ||
5833 | |||
5834 | /* Tentative. This seems to work, wow, I'm lucky !!! */ | ||
5835 | memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN); | ||
5836 | awrq->sa_family = ARPHRD_ETHER; | ||
5837 | |||
5838 | return 0; | ||
5839 | } | ||
5840 | |||
5841 | /*------------------------------------------------------------------*/ | ||
5842 | /* | ||
5843 | * Wireless Handler : set Nickname | ||
5844 | */ | ||
5845 | static int airo_set_nick(struct net_device *dev, | ||
5846 | struct iw_request_info *info, | ||
5847 | struct iw_point *dwrq, | ||
5848 | char *extra) | ||
5849 | { | ||
5850 | struct airo_info *local = dev->priv; | ||
5851 | |||
5852 | /* Check the size of the string */ | ||
5853 | if(dwrq->length > 16 + 1) { | ||
5854 | return -E2BIG; | ||
5855 | } | ||
5856 | readConfigRid(local, 1); | ||
5857 | memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); | ||
5858 | memcpy(local->config.nodeName, extra, dwrq->length); | ||
5859 | set_bit (FLAG_COMMIT, &local->flags); | ||
5860 | |||
5861 | return -EINPROGRESS; /* Call commit handler */ | ||
5862 | } | ||
5863 | |||
5864 | /*------------------------------------------------------------------*/ | ||
5865 | /* | ||
5866 | * Wireless Handler : get Nickname | ||
5867 | */ | ||
5868 | static int airo_get_nick(struct net_device *dev, | ||
5869 | struct iw_request_info *info, | ||
5870 | struct iw_point *dwrq, | ||
5871 | char *extra) | ||
5872 | { | ||
5873 | struct airo_info *local = dev->priv; | ||
5874 | |||
5875 | readConfigRid(local, 1); | ||
5876 | strncpy(extra, local->config.nodeName, 16); | ||
5877 | extra[16] = '\0'; | ||
5878 | dwrq->length = strlen(extra) + 1; | ||
5879 | |||
5880 | return 0; | ||
5881 | } | ||
5882 | |||
5883 | /*------------------------------------------------------------------*/ | ||
5884 | /* | ||
5885 | * Wireless Handler : set Bit-Rate | ||
5886 | */ | ||
5887 | static int airo_set_rate(struct net_device *dev, | ||
5888 | struct iw_request_info *info, | ||
5889 | struct iw_param *vwrq, | ||
5890 | char *extra) | ||
5891 | { | ||
5892 | struct airo_info *local = dev->priv; | ||
5893 | CapabilityRid cap_rid; /* Card capability info */ | ||
5894 | u8 brate = 0; | ||
5895 | int i; | ||
5896 | |||
5897 | /* First : get a valid bit rate value */ | ||
5898 | readCapabilityRid(local, &cap_rid, 1); | ||
5899 | |||
5900 | /* Which type of value ? */ | ||
5901 | if((vwrq->value < 8) && (vwrq->value >= 0)) { | ||
5902 | /* Setting by rate index */ | ||
5903 | /* Find value in the magic rate table */ | ||
5904 | brate = cap_rid.supportedRates[vwrq->value]; | ||
5905 | } else { | ||
5906 | /* Setting by frequency value */ | ||
5907 | u8 normvalue = (u8) (vwrq->value/500000); | ||
5908 | |||
5909 | /* Check if rate is valid */ | ||
5910 | for(i = 0 ; i < 8 ; i++) { | ||
5911 | if(normvalue == cap_rid.supportedRates[i]) { | ||
5912 | brate = normvalue; | ||
5913 | break; | ||
5914 | } | ||
5915 | } | ||
5916 | } | ||
5917 | /* -1 designed the max rate (mostly auto mode) */ | ||
5918 | if(vwrq->value == -1) { | ||
5919 | /* Get the highest available rate */ | ||
5920 | for(i = 0 ; i < 8 ; i++) { | ||
5921 | if(cap_rid.supportedRates[i] == 0) | ||
5922 | break; | ||
5923 | } | ||
5924 | if(i != 0) | ||
5925 | brate = cap_rid.supportedRates[i - 1]; | ||
5926 | } | ||
5927 | /* Check that it is valid */ | ||
5928 | if(brate == 0) { | ||
5929 | return -EINVAL; | ||
5930 | } | ||
5931 | |||
5932 | readConfigRid(local, 1); | ||
5933 | /* Now, check if we want a fixed or auto value */ | ||
5934 | if(vwrq->fixed == 0) { | ||
5935 | /* Fill all the rates up to this max rate */ | ||
5936 | memset(local->config.rates, 0, 8); | ||
5937 | for(i = 0 ; i < 8 ; i++) { | ||
5938 | local->config.rates[i] = cap_rid.supportedRates[i]; | ||
5939 | if(local->config.rates[i] == brate) | ||
5940 | break; | ||
5941 | } | ||
5942 | } else { | ||
5943 | /* Fixed mode */ | ||
5944 | /* One rate, fixed */ | ||
5945 | memset(local->config.rates, 0, 8); | ||
5946 | local->config.rates[0] = brate; | ||
5947 | } | ||
5948 | set_bit (FLAG_COMMIT, &local->flags); | ||
5949 | |||
5950 | return -EINPROGRESS; /* Call commit handler */ | ||
5951 | } | ||
5952 | |||
5953 | /*------------------------------------------------------------------*/ | ||
5954 | /* | ||
5955 | * Wireless Handler : get Bit-Rate | ||
5956 | */ | ||
5957 | static int airo_get_rate(struct net_device *dev, | ||
5958 | struct iw_request_info *info, | ||
5959 | struct iw_param *vwrq, | ||
5960 | char *extra) | ||
5961 | { | ||
5962 | struct airo_info *local = dev->priv; | ||
5963 | StatusRid status_rid; /* Card status info */ | ||
5964 | |||
5965 | readStatusRid(local, &status_rid, 1); | ||
5966 | |||
5967 | vwrq->value = status_rid.currentXmitRate * 500000; | ||
5968 | /* If more than one rate, set auto */ | ||
5969 | readConfigRid(local, 1); | ||
5970 | vwrq->fixed = (local->config.rates[1] == 0); | ||
5971 | |||
5972 | return 0; | ||
5973 | } | ||
5974 | |||
5975 | /*------------------------------------------------------------------*/ | ||
5976 | /* | ||
5977 | * Wireless Handler : set RTS threshold | ||
5978 | */ | ||
5979 | static int airo_set_rts(struct net_device *dev, | ||
5980 | struct iw_request_info *info, | ||
5981 | struct iw_param *vwrq, | ||
5982 | char *extra) | ||
5983 | { | ||
5984 | struct airo_info *local = dev->priv; | ||
5985 | int rthr = vwrq->value; | ||
5986 | |||
5987 | if(vwrq->disabled) | ||
5988 | rthr = 2312; | ||
5989 | if((rthr < 0) || (rthr > 2312)) { | ||
5990 | return -EINVAL; | ||
5991 | } | ||
5992 | readConfigRid(local, 1); | ||
5993 | local->config.rtsThres = rthr; | ||
5994 | set_bit (FLAG_COMMIT, &local->flags); | ||
5995 | |||
5996 | return -EINPROGRESS; /* Call commit handler */ | ||
5997 | } | ||
5998 | |||
5999 | /*------------------------------------------------------------------*/ | ||
6000 | /* | ||
6001 | * Wireless Handler : get RTS threshold | ||
6002 | */ | ||
6003 | static int airo_get_rts(struct net_device *dev, | ||
6004 | struct iw_request_info *info, | ||
6005 | struct iw_param *vwrq, | ||
6006 | char *extra) | ||
6007 | { | ||
6008 | struct airo_info *local = dev->priv; | ||
6009 | |||
6010 | readConfigRid(local, 1); | ||
6011 | vwrq->value = local->config.rtsThres; | ||
6012 | vwrq->disabled = (vwrq->value >= 2312); | ||
6013 | vwrq->fixed = 1; | ||
6014 | |||
6015 | return 0; | ||
6016 | } | ||
6017 | |||
6018 | /*------------------------------------------------------------------*/ | ||
6019 | /* | ||
6020 | * Wireless Handler : set Fragmentation threshold | ||
6021 | */ | ||
6022 | static int airo_set_frag(struct net_device *dev, | ||
6023 | struct iw_request_info *info, | ||
6024 | struct iw_param *vwrq, | ||
6025 | char *extra) | ||
6026 | { | ||
6027 | struct airo_info *local = dev->priv; | ||
6028 | int fthr = vwrq->value; | ||
6029 | |||
6030 | if(vwrq->disabled) | ||
6031 | fthr = 2312; | ||
6032 | if((fthr < 256) || (fthr > 2312)) { | ||
6033 | return -EINVAL; | ||
6034 | } | ||
6035 | fthr &= ~0x1; /* Get an even value - is it really needed ??? */ | ||
6036 | readConfigRid(local, 1); | ||
6037 | local->config.fragThresh = (u16)fthr; | ||
6038 | set_bit (FLAG_COMMIT, &local->flags); | ||
6039 | |||
6040 | return -EINPROGRESS; /* Call commit handler */ | ||
6041 | } | ||
6042 | |||
6043 | /*------------------------------------------------------------------*/ | ||
6044 | /* | ||
6045 | * Wireless Handler : get Fragmentation threshold | ||
6046 | */ | ||
6047 | static int airo_get_frag(struct net_device *dev, | ||
6048 | struct iw_request_info *info, | ||
6049 | struct iw_param *vwrq, | ||
6050 | char *extra) | ||
6051 | { | ||
6052 | struct airo_info *local = dev->priv; | ||
6053 | |||
6054 | readConfigRid(local, 1); | ||
6055 | vwrq->value = local->config.fragThresh; | ||
6056 | vwrq->disabled = (vwrq->value >= 2312); | ||
6057 | vwrq->fixed = 1; | ||
6058 | |||
6059 | return 0; | ||
6060 | } | ||
6061 | |||
6062 | /*------------------------------------------------------------------*/ | ||
6063 | /* | ||
6064 | * Wireless Handler : set Mode of Operation | ||
6065 | */ | ||
6066 | static int airo_set_mode(struct net_device *dev, | ||
6067 | struct iw_request_info *info, | ||
6068 | __u32 *uwrq, | ||
6069 | char *extra) | ||
6070 | { | ||
6071 | struct airo_info *local = dev->priv; | ||
6072 | int reset = 0; | ||
6073 | |||
6074 | readConfigRid(local, 1); | ||
6075 | if ((local->config.rmode & 0xff) >= RXMODE_RFMON) | ||
6076 | reset = 1; | ||
6077 | |||
6078 | switch(*uwrq) { | ||
6079 | case IW_MODE_ADHOC: | ||
6080 | local->config.opmode &= 0xFF00; | ||
6081 | local->config.opmode |= MODE_STA_IBSS; | ||
6082 | local->config.rmode &= 0xfe00; | ||
6083 | local->config.scanMode = SCANMODE_ACTIVE; | ||
6084 | clear_bit (FLAG_802_11, &local->flags); | ||
6085 | break; | ||
6086 | case IW_MODE_INFRA: | ||
6087 | local->config.opmode &= 0xFF00; | ||
6088 | local->config.opmode |= MODE_STA_ESS; | ||
6089 | local->config.rmode &= 0xfe00; | ||
6090 | local->config.scanMode = SCANMODE_ACTIVE; | ||
6091 | clear_bit (FLAG_802_11, &local->flags); | ||
6092 | break; | ||
6093 | case IW_MODE_MASTER: | ||
6094 | local->config.opmode &= 0xFF00; | ||
6095 | local->config.opmode |= MODE_AP; | ||
6096 | local->config.rmode &= 0xfe00; | ||
6097 | local->config.scanMode = SCANMODE_ACTIVE; | ||
6098 | clear_bit (FLAG_802_11, &local->flags); | ||
6099 | break; | ||
6100 | case IW_MODE_REPEAT: | ||
6101 | local->config.opmode &= 0xFF00; | ||
6102 | local->config.opmode |= MODE_AP_RPTR; | ||
6103 | local->config.rmode &= 0xfe00; | ||
6104 | local->config.scanMode = SCANMODE_ACTIVE; | ||
6105 | clear_bit (FLAG_802_11, &local->flags); | ||
6106 | break; | ||
6107 | case IW_MODE_MONITOR: | ||
6108 | local->config.opmode &= 0xFF00; | ||
6109 | local->config.opmode |= MODE_STA_ESS; | ||
6110 | local->config.rmode &= 0xfe00; | ||
6111 | local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; | ||
6112 | local->config.scanMode = SCANMODE_PASSIVE; | ||
6113 | set_bit (FLAG_802_11, &local->flags); | ||
6114 | break; | ||
6115 | default: | ||
6116 | return -EINVAL; | ||
6117 | } | ||
6118 | if (reset) | ||
6119 | set_bit (FLAG_RESET, &local->flags); | ||
6120 | set_bit (FLAG_COMMIT, &local->flags); | ||
6121 | |||
6122 | return -EINPROGRESS; /* Call commit handler */ | ||
6123 | } | ||
6124 | |||
6125 | /*------------------------------------------------------------------*/ | ||
6126 | /* | ||
6127 | * Wireless Handler : get Mode of Operation | ||
6128 | */ | ||
6129 | static int airo_get_mode(struct net_device *dev, | ||
6130 | struct iw_request_info *info, | ||
6131 | __u32 *uwrq, | ||
6132 | char *extra) | ||
6133 | { | ||
6134 | struct airo_info *local = dev->priv; | ||
6135 | |||
6136 | readConfigRid(local, 1); | ||
6137 | /* If not managed, assume it's ad-hoc */ | ||
6138 | switch (local->config.opmode & 0xFF) { | ||
6139 | case MODE_STA_ESS: | ||
6140 | *uwrq = IW_MODE_INFRA; | ||
6141 | break; | ||
6142 | case MODE_AP: | ||
6143 | *uwrq = IW_MODE_MASTER; | ||
6144 | break; | ||
6145 | case MODE_AP_RPTR: | ||
6146 | *uwrq = IW_MODE_REPEAT; | ||
6147 | break; | ||
6148 | default: | ||
6149 | *uwrq = IW_MODE_ADHOC; | ||
6150 | } | ||
6151 | |||
6152 | return 0; | ||
6153 | } | ||
6154 | |||
6155 | /*------------------------------------------------------------------*/ | ||
6156 | /* | ||
6157 | * Wireless Handler : set Encryption Key | ||
6158 | */ | ||
6159 | static int airo_set_encode(struct net_device *dev, | ||
6160 | struct iw_request_info *info, | ||
6161 | struct iw_point *dwrq, | ||
6162 | char *extra) | ||
6163 | { | ||
6164 | struct airo_info *local = dev->priv; | ||
6165 | CapabilityRid cap_rid; /* Card capability info */ | ||
6166 | |||
6167 | /* Is WEP supported ? */ | ||
6168 | readCapabilityRid(local, &cap_rid, 1); | ||
6169 | /* Older firmware doesn't support this... | ||
6170 | if(!(cap_rid.softCap & 2)) { | ||
6171 | return -EOPNOTSUPP; | ||
6172 | } */ | ||
6173 | readConfigRid(local, 1); | ||
6174 | |||
6175 | /* Basic checking: do we have a key to set ? | ||
6176 | * Note : with the new API, it's impossible to get a NULL pointer. | ||
6177 | * Therefore, we need to check a key size == 0 instead. | ||
6178 | * New version of iwconfig properly set the IW_ENCODE_NOKEY flag | ||
6179 | * when no key is present (only change flags), but older versions | ||
6180 | * don't do it. - Jean II */ | ||
6181 | if (dwrq->length > 0) { | ||
6182 | wep_key_t key; | ||
6183 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
6184 | int current_index = get_wep_key(local, 0xffff); | ||
6185 | /* Check the size of the key */ | ||
6186 | if (dwrq->length > MAX_KEY_SIZE) { | ||
6187 | return -EINVAL; | ||
6188 | } | ||
6189 | /* Check the index (none -> use current) */ | ||
6190 | if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1))) | ||
6191 | index = current_index; | ||
6192 | /* Set the length */ | ||
6193 | if (dwrq->length > MIN_KEY_SIZE) | ||
6194 | key.len = MAX_KEY_SIZE; | ||
6195 | else | ||
6196 | if (dwrq->length > 0) | ||
6197 | key.len = MIN_KEY_SIZE; | ||
6198 | else | ||
6199 | /* Disable the key */ | ||
6200 | key.len = 0; | ||
6201 | /* Check if the key is not marked as invalid */ | ||
6202 | if(!(dwrq->flags & IW_ENCODE_NOKEY)) { | ||
6203 | /* Cleanup */ | ||
6204 | memset(key.key, 0, MAX_KEY_SIZE); | ||
6205 | /* Copy the key in the driver */ | ||
6206 | memcpy(key.key, extra, dwrq->length); | ||
6207 | /* Send the key to the card */ | ||
6208 | set_wep_key(local, index, key.key, key.len, 1, 1); | ||
6209 | } | ||
6210 | /* WE specify that if a valid key is set, encryption | ||
6211 | * should be enabled (user may turn it off later) | ||
6212 | * This is also how "iwconfig ethX key on" works */ | ||
6213 | if((index == current_index) && (key.len > 0) && | ||
6214 | (local->config.authType == AUTH_OPEN)) { | ||
6215 | local->config.authType = AUTH_ENCRYPT; | ||
6216 | set_bit (FLAG_COMMIT, &local->flags); | ||
6217 | } | ||
6218 | } else { | ||
6219 | /* Do we want to just set the transmit key index ? */ | ||
6220 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
6221 | if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) { | ||
6222 | set_wep_key(local, index, NULL, 0, 1, 1); | ||
6223 | } else | ||
6224 | /* Don't complain if only change the mode */ | ||
6225 | if(!dwrq->flags & IW_ENCODE_MODE) { | ||
6226 | return -EINVAL; | ||
6227 | } | ||
6228 | } | ||
6229 | /* Read the flags */ | ||
6230 | if(dwrq->flags & IW_ENCODE_DISABLED) | ||
6231 | local->config.authType = AUTH_OPEN; // disable encryption | ||
6232 | if(dwrq->flags & IW_ENCODE_RESTRICTED) | ||
6233 | local->config.authType = AUTH_SHAREDKEY; // Only Both | ||
6234 | if(dwrq->flags & IW_ENCODE_OPEN) | ||
6235 | local->config.authType = AUTH_ENCRYPT; // Only Wep | ||
6236 | /* Commit the changes to flags if needed */ | ||
6237 | if(dwrq->flags & IW_ENCODE_MODE) | ||
6238 | set_bit (FLAG_COMMIT, &local->flags); | ||
6239 | return -EINPROGRESS; /* Call commit handler */ | ||
6240 | } | ||
6241 | |||
6242 | /*------------------------------------------------------------------*/ | ||
6243 | /* | ||
6244 | * Wireless Handler : get Encryption Key | ||
6245 | */ | ||
6246 | static int airo_get_encode(struct net_device *dev, | ||
6247 | struct iw_request_info *info, | ||
6248 | struct iw_point *dwrq, | ||
6249 | char *extra) | ||
6250 | { | ||
6251 | struct airo_info *local = dev->priv; | ||
6252 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
6253 | CapabilityRid cap_rid; /* Card capability info */ | ||
6254 | |||
6255 | /* Is it supported ? */ | ||
6256 | readCapabilityRid(local, &cap_rid, 1); | ||
6257 | if(!(cap_rid.softCap & 2)) { | ||
6258 | return -EOPNOTSUPP; | ||
6259 | } | ||
6260 | readConfigRid(local, 1); | ||
6261 | /* Check encryption mode */ | ||
6262 | switch(local->config.authType) { | ||
6263 | case AUTH_ENCRYPT: | ||
6264 | dwrq->flags = IW_ENCODE_OPEN; | ||
6265 | break; | ||
6266 | case AUTH_SHAREDKEY: | ||
6267 | dwrq->flags = IW_ENCODE_RESTRICTED; | ||
6268 | break; | ||
6269 | default: | ||
6270 | case AUTH_OPEN: | ||
6271 | dwrq->flags = IW_ENCODE_DISABLED; | ||
6272 | break; | ||
6273 | } | ||
6274 | /* We can't return the key, so set the proper flag and return zero */ | ||
6275 | dwrq->flags |= IW_ENCODE_NOKEY; | ||
6276 | memset(extra, 0, 16); | ||
6277 | |||
6278 | /* Which key do we want ? -1 -> tx index */ | ||
6279 | if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1))) | ||
6280 | index = get_wep_key(local, 0xffff); | ||
6281 | dwrq->flags |= index + 1; | ||
6282 | /* Copy the key to the user buffer */ | ||
6283 | dwrq->length = get_wep_key(local, index); | ||
6284 | if (dwrq->length > 16) { | ||
6285 | dwrq->length=0; | ||
6286 | } | ||
6287 | return 0; | ||
6288 | } | ||
6289 | |||
6290 | /*------------------------------------------------------------------*/ | ||
6291 | /* | ||
6292 | * Wireless Handler : set Tx-Power | ||
6293 | */ | ||
6294 | static int airo_set_txpow(struct net_device *dev, | ||
6295 | struct iw_request_info *info, | ||
6296 | struct iw_param *vwrq, | ||
6297 | char *extra) | ||
6298 | { | ||
6299 | struct airo_info *local = dev->priv; | ||
6300 | CapabilityRid cap_rid; /* Card capability info */ | ||
6301 | int i; | ||
6302 | int rc = -EINVAL; | ||
6303 | |||
6304 | readCapabilityRid(local, &cap_rid, 1); | ||
6305 | |||
6306 | if (vwrq->disabled) { | ||
6307 | set_bit (FLAG_RADIO_OFF, &local->flags); | ||
6308 | set_bit (FLAG_COMMIT, &local->flags); | ||
6309 | return -EINPROGRESS; /* Call commit handler */ | ||
6310 | } | ||
6311 | if (vwrq->flags != IW_TXPOW_MWATT) { | ||
6312 | return -EINVAL; | ||
6313 | } | ||
6314 | clear_bit (FLAG_RADIO_OFF, &local->flags); | ||
6315 | for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++) | ||
6316 | if ((vwrq->value==cap_rid.txPowerLevels[i])) { | ||
6317 | readConfigRid(local, 1); | ||
6318 | local->config.txPower = vwrq->value; | ||
6319 | set_bit (FLAG_COMMIT, &local->flags); | ||
6320 | rc = -EINPROGRESS; /* Call commit handler */ | ||
6321 | break; | ||
6322 | } | ||
6323 | return rc; | ||
6324 | } | ||
6325 | |||
6326 | /*------------------------------------------------------------------*/ | ||
6327 | /* | ||
6328 | * Wireless Handler : get Tx-Power | ||
6329 | */ | ||
6330 | static int airo_get_txpow(struct net_device *dev, | ||
6331 | struct iw_request_info *info, | ||
6332 | struct iw_param *vwrq, | ||
6333 | char *extra) | ||
6334 | { | ||
6335 | struct airo_info *local = dev->priv; | ||
6336 | |||
6337 | readConfigRid(local, 1); | ||
6338 | vwrq->value = local->config.txPower; | ||
6339 | vwrq->fixed = 1; /* No power control */ | ||
6340 | vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags); | ||
6341 | vwrq->flags = IW_TXPOW_MWATT; | ||
6342 | |||
6343 | return 0; | ||
6344 | } | ||
6345 | |||
6346 | /*------------------------------------------------------------------*/ | ||
6347 | /* | ||
6348 | * Wireless Handler : set Retry limits | ||
6349 | */ | ||
6350 | static int airo_set_retry(struct net_device *dev, | ||
6351 | struct iw_request_info *info, | ||
6352 | struct iw_param *vwrq, | ||
6353 | char *extra) | ||
6354 | { | ||
6355 | struct airo_info *local = dev->priv; | ||
6356 | int rc = -EINVAL; | ||
6357 | |||
6358 | if(vwrq->disabled) { | ||
6359 | return -EINVAL; | ||
6360 | } | ||
6361 | readConfigRid(local, 1); | ||
6362 | if(vwrq->flags & IW_RETRY_LIMIT) { | ||
6363 | if(vwrq->flags & IW_RETRY_MAX) | ||
6364 | local->config.longRetryLimit = vwrq->value; | ||
6365 | else if (vwrq->flags & IW_RETRY_MIN) | ||
6366 | local->config.shortRetryLimit = vwrq->value; | ||
6367 | else { | ||
6368 | /* No modifier : set both */ | ||
6369 | local->config.longRetryLimit = vwrq->value; | ||
6370 | local->config.shortRetryLimit = vwrq->value; | ||
6371 | } | ||
6372 | set_bit (FLAG_COMMIT, &local->flags); | ||
6373 | rc = -EINPROGRESS; /* Call commit handler */ | ||
6374 | } | ||
6375 | if(vwrq->flags & IW_RETRY_LIFETIME) { | ||
6376 | local->config.txLifetime = vwrq->value / 1024; | ||
6377 | set_bit (FLAG_COMMIT, &local->flags); | ||
6378 | rc = -EINPROGRESS; /* Call commit handler */ | ||
6379 | } | ||
6380 | return rc; | ||
6381 | } | ||
6382 | |||
6383 | /*------------------------------------------------------------------*/ | ||
6384 | /* | ||
6385 | * Wireless Handler : get Retry limits | ||
6386 | */ | ||
6387 | static int airo_get_retry(struct net_device *dev, | ||
6388 | struct iw_request_info *info, | ||
6389 | struct iw_param *vwrq, | ||
6390 | char *extra) | ||
6391 | { | ||
6392 | struct airo_info *local = dev->priv; | ||
6393 | |||
6394 | vwrq->disabled = 0; /* Can't be disabled */ | ||
6395 | |||
6396 | readConfigRid(local, 1); | ||
6397 | /* Note : by default, display the min retry number */ | ||
6398 | if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
6399 | vwrq->flags = IW_RETRY_LIFETIME; | ||
6400 | vwrq->value = (int)local->config.txLifetime * 1024; | ||
6401 | } else if((vwrq->flags & IW_RETRY_MAX)) { | ||
6402 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
6403 | vwrq->value = (int)local->config.longRetryLimit; | ||
6404 | } else { | ||
6405 | vwrq->flags = IW_RETRY_LIMIT; | ||
6406 | vwrq->value = (int)local->config.shortRetryLimit; | ||
6407 | if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit) | ||
6408 | vwrq->flags |= IW_RETRY_MIN; | ||
6409 | } | ||
6410 | |||
6411 | return 0; | ||
6412 | } | ||
6413 | |||
6414 | /*------------------------------------------------------------------*/ | ||
6415 | /* | ||
6416 | * Wireless Handler : get range info | ||
6417 | */ | ||
6418 | static int airo_get_range(struct net_device *dev, | ||
6419 | struct iw_request_info *info, | ||
6420 | struct iw_point *dwrq, | ||
6421 | char *extra) | ||
6422 | { | ||
6423 | struct airo_info *local = dev->priv; | ||
6424 | struct iw_range *range = (struct iw_range *) extra; | ||
6425 | CapabilityRid cap_rid; /* Card capability info */ | ||
6426 | int i; | ||
6427 | int k; | ||
6428 | |||
6429 | readCapabilityRid(local, &cap_rid, 1); | ||
6430 | |||
6431 | dwrq->length = sizeof(struct iw_range); | ||
6432 | memset(range, 0, sizeof(*range)); | ||
6433 | range->min_nwid = 0x0000; | ||
6434 | range->max_nwid = 0x0000; | ||
6435 | range->num_channels = 14; | ||
6436 | /* Should be based on cap_rid.country to give only | ||
6437 | * what the current card support */ | ||
6438 | k = 0; | ||
6439 | for(i = 0; i < 14; i++) { | ||
6440 | range->freq[k].i = i + 1; /* List index */ | ||
6441 | range->freq[k].m = frequency_list[i] * 100000; | ||
6442 | range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ | ||
6443 | } | ||
6444 | range->num_frequency = k; | ||
6445 | |||
6446 | /* Hum... Should put the right values there */ | ||
6447 | range->max_qual.qual = airo_get_max_quality(&cap_rid); | ||
6448 | range->max_qual.level = 0x100 - 120; /* -120 dBm */ | ||
6449 | range->max_qual.noise = 0; | ||
6450 | range->sensitivity = 65535; | ||
6451 | |||
6452 | for(i = 0 ; i < 8 ; i++) { | ||
6453 | range->bitrate[i] = cap_rid.supportedRates[i] * 500000; | ||
6454 | if(range->bitrate[i] == 0) | ||
6455 | break; | ||
6456 | } | ||
6457 | range->num_bitrates = i; | ||
6458 | |||
6459 | /* Set an indication of the max TCP throughput | ||
6460 | * in bit/s that we can expect using this interface. | ||
6461 | * May be use for QoS stuff... Jean II */ | ||
6462 | if(i > 2) | ||
6463 | range->throughput = 5000 * 1000; | ||
6464 | else | ||
6465 | range->throughput = 1500 * 1000; | ||
6466 | |||
6467 | range->min_rts = 0; | ||
6468 | range->max_rts = 2312; | ||
6469 | range->min_frag = 256; | ||
6470 | range->max_frag = 2312; | ||
6471 | |||
6472 | if(cap_rid.softCap & 2) { | ||
6473 | // WEP: RC4 40 bits | ||
6474 | range->encoding_size[0] = 5; | ||
6475 | // RC4 ~128 bits | ||
6476 | if (cap_rid.softCap & 0x100) { | ||
6477 | range->encoding_size[1] = 13; | ||
6478 | range->num_encoding_sizes = 2; | ||
6479 | } else | ||
6480 | range->num_encoding_sizes = 1; | ||
6481 | range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1; | ||
6482 | } else { | ||
6483 | range->num_encoding_sizes = 0; | ||
6484 | range->max_encoding_tokens = 0; | ||
6485 | } | ||
6486 | range->min_pmp = 0; | ||
6487 | range->max_pmp = 5000000; /* 5 secs */ | ||
6488 | range->min_pmt = 0; | ||
6489 | range->max_pmt = 65535 * 1024; /* ??? */ | ||
6490 | range->pmp_flags = IW_POWER_PERIOD; | ||
6491 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
6492 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; | ||
6493 | |||
6494 | /* Transmit Power - values are in mW */ | ||
6495 | for(i = 0 ; i < 8 ; i++) { | ||
6496 | range->txpower[i] = cap_rid.txPowerLevels[i]; | ||
6497 | if(range->txpower[i] == 0) | ||
6498 | break; | ||
6499 | } | ||
6500 | range->num_txpower = i; | ||
6501 | range->txpower_capa = IW_TXPOW_MWATT; | ||
6502 | range->we_version_source = 12; | ||
6503 | range->we_version_compiled = WIRELESS_EXT; | ||
6504 | range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; | ||
6505 | range->retry_flags = IW_RETRY_LIMIT; | ||
6506 | range->r_time_flags = IW_RETRY_LIFETIME; | ||
6507 | range->min_retry = 1; | ||
6508 | range->max_retry = 65535; | ||
6509 | range->min_r_time = 1024; | ||
6510 | range->max_r_time = 65535 * 1024; | ||
6511 | /* Experimental measurements - boundary 11/5.5 Mb/s */ | ||
6512 | /* Note : with or without the (local->rssi), results | ||
6513 | * are somewhat different. - Jean II */ | ||
6514 | range->avg_qual.qual = airo_get_avg_quality(&cap_rid); | ||
6515 | if (local->rssi) | ||
6516 | range->avg_qual.level = 186; /* -70 dBm */ | ||
6517 | else | ||
6518 | range->avg_qual.level = 176; /* -80 dBm */ | ||
6519 | range->avg_qual.noise = 0; | ||
6520 | |||
6521 | /* Event capability (kernel + driver) */ | ||
6522 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
6523 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | | ||
6524 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | ||
6525 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | ||
6526 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
6527 | range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP); | ||
6528 | return 0; | ||
6529 | } | ||
6530 | |||
6531 | /*------------------------------------------------------------------*/ | ||
6532 | /* | ||
6533 | * Wireless Handler : set Power Management | ||
6534 | */ | ||
6535 | static int airo_set_power(struct net_device *dev, | ||
6536 | struct iw_request_info *info, | ||
6537 | struct iw_param *vwrq, | ||
6538 | char *extra) | ||
6539 | { | ||
6540 | struct airo_info *local = dev->priv; | ||
6541 | |||
6542 | readConfigRid(local, 1); | ||
6543 | if (vwrq->disabled) { | ||
6544 | if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { | ||
6545 | return -EINVAL; | ||
6546 | } | ||
6547 | local->config.powerSaveMode = POWERSAVE_CAM; | ||
6548 | local->config.rmode &= 0xFF00; | ||
6549 | local->config.rmode |= RXMODE_BC_MC_ADDR; | ||
6550 | set_bit (FLAG_COMMIT, &local->flags); | ||
6551 | return -EINPROGRESS; /* Call commit handler */ | ||
6552 | } | ||
6553 | if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
6554 | local->config.fastListenDelay = (vwrq->value + 500) / 1024; | ||
6555 | local->config.powerSaveMode = POWERSAVE_PSPCAM; | ||
6556 | set_bit (FLAG_COMMIT, &local->flags); | ||
6557 | } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { | ||
6558 | local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024; | ||
6559 | local->config.powerSaveMode = POWERSAVE_PSPCAM; | ||
6560 | set_bit (FLAG_COMMIT, &local->flags); | ||
6561 | } | ||
6562 | switch (vwrq->flags & IW_POWER_MODE) { | ||
6563 | case IW_POWER_UNICAST_R: | ||
6564 | if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { | ||
6565 | return -EINVAL; | ||
6566 | } | ||
6567 | local->config.rmode &= 0xFF00; | ||
6568 | local->config.rmode |= RXMODE_ADDR; | ||
6569 | set_bit (FLAG_COMMIT, &local->flags); | ||
6570 | break; | ||
6571 | case IW_POWER_ALL_R: | ||
6572 | if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { | ||
6573 | return -EINVAL; | ||
6574 | } | ||
6575 | local->config.rmode &= 0xFF00; | ||
6576 | local->config.rmode |= RXMODE_BC_MC_ADDR; | ||
6577 | set_bit (FLAG_COMMIT, &local->flags); | ||
6578 | case IW_POWER_ON: | ||
6579 | break; | ||
6580 | default: | ||
6581 | return -EINVAL; | ||
6582 | } | ||
6583 | // Note : we may want to factor local->need_commit here | ||
6584 | // Note2 : may also want to factor RXMODE_RFMON test | ||
6585 | return -EINPROGRESS; /* Call commit handler */ | ||
6586 | } | ||
6587 | |||
6588 | /*------------------------------------------------------------------*/ | ||
6589 | /* | ||
6590 | * Wireless Handler : get Power Management | ||
6591 | */ | ||
6592 | static int airo_get_power(struct net_device *dev, | ||
6593 | struct iw_request_info *info, | ||
6594 | struct iw_param *vwrq, | ||
6595 | char *extra) | ||
6596 | { | ||
6597 | struct airo_info *local = dev->priv; | ||
6598 | int mode; | ||
6599 | |||
6600 | readConfigRid(local, 1); | ||
6601 | mode = local->config.powerSaveMode; | ||
6602 | if ((vwrq->disabled = (mode == POWERSAVE_CAM))) | ||
6603 | return 0; | ||
6604 | if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
6605 | vwrq->value = (int)local->config.fastListenDelay * 1024; | ||
6606 | vwrq->flags = IW_POWER_TIMEOUT; | ||
6607 | } else { | ||
6608 | vwrq->value = (int)local->config.fastListenInterval * 1024; | ||
6609 | vwrq->flags = IW_POWER_PERIOD; | ||
6610 | } | ||
6611 | if ((local->config.rmode & 0xFF) == RXMODE_ADDR) | ||
6612 | vwrq->flags |= IW_POWER_UNICAST_R; | ||
6613 | else | ||
6614 | vwrq->flags |= IW_POWER_ALL_R; | ||
6615 | |||
6616 | return 0; | ||
6617 | } | ||
6618 | |||
6619 | /*------------------------------------------------------------------*/ | ||
6620 | /* | ||
6621 | * Wireless Handler : set Sensitivity | ||
6622 | */ | ||
6623 | static int airo_set_sens(struct net_device *dev, | ||
6624 | struct iw_request_info *info, | ||
6625 | struct iw_param *vwrq, | ||
6626 | char *extra) | ||
6627 | { | ||
6628 | struct airo_info *local = dev->priv; | ||
6629 | |||
6630 | readConfigRid(local, 1); | ||
6631 | local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value; | ||
6632 | set_bit (FLAG_COMMIT, &local->flags); | ||
6633 | |||
6634 | return -EINPROGRESS; /* Call commit handler */ | ||
6635 | } | ||
6636 | |||
6637 | /*------------------------------------------------------------------*/ | ||
6638 | /* | ||
6639 | * Wireless Handler : get Sensitivity | ||
6640 | */ | ||
6641 | static int airo_get_sens(struct net_device *dev, | ||
6642 | struct iw_request_info *info, | ||
6643 | struct iw_param *vwrq, | ||
6644 | char *extra) | ||
6645 | { | ||
6646 | struct airo_info *local = dev->priv; | ||
6647 | |||
6648 | readConfigRid(local, 1); | ||
6649 | vwrq->value = local->config.rssiThreshold; | ||
6650 | vwrq->disabled = (vwrq->value == 0); | ||
6651 | vwrq->fixed = 1; | ||
6652 | |||
6653 | return 0; | ||
6654 | } | ||
6655 | |||
6656 | /*------------------------------------------------------------------*/ | ||
6657 | /* | ||
6658 | * Wireless Handler : get AP List | ||
6659 | * Note : this is deprecated in favor of IWSCAN | ||
6660 | */ | ||
6661 | static int airo_get_aplist(struct net_device *dev, | ||
6662 | struct iw_request_info *info, | ||
6663 | struct iw_point *dwrq, | ||
6664 | char *extra) | ||
6665 | { | ||
6666 | struct airo_info *local = dev->priv; | ||
6667 | struct sockaddr *address = (struct sockaddr *) extra; | ||
6668 | struct iw_quality qual[IW_MAX_AP]; | ||
6669 | BSSListRid BSSList; | ||
6670 | int i; | ||
6671 | int loseSync = capable(CAP_NET_ADMIN) ? 1: -1; | ||
6672 | |||
6673 | for (i = 0; i < IW_MAX_AP; i++) { | ||
6674 | if (readBSSListRid(local, loseSync, &BSSList)) | ||
6675 | break; | ||
6676 | loseSync = 0; | ||
6677 | memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); | ||
6678 | address[i].sa_family = ARPHRD_ETHER; | ||
6679 | if (local->rssi) | ||
6680 | qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm; | ||
6681 | else | ||
6682 | qual[i].level = (BSSList.rssi + 321) / 2; | ||
6683 | qual[i].qual = qual[i].noise = 0; | ||
6684 | qual[i].updated = 2; | ||
6685 | if (BSSList.index == 0xffff) | ||
6686 | break; | ||
6687 | } | ||
6688 | if (!i) { | ||
6689 | StatusRid status_rid; /* Card status info */ | ||
6690 | readStatusRid(local, &status_rid, 1); | ||
6691 | for (i = 0; | ||
6692 | i < min(IW_MAX_AP, 4) && | ||
6693 | (status_rid.bssid[i][0] | ||
6694 | & status_rid.bssid[i][1] | ||
6695 | & status_rid.bssid[i][2] | ||
6696 | & status_rid.bssid[i][3] | ||
6697 | & status_rid.bssid[i][4] | ||
6698 | & status_rid.bssid[i][5])!=0xff && | ||
6699 | (status_rid.bssid[i][0] | ||
6700 | | status_rid.bssid[i][1] | ||
6701 | | status_rid.bssid[i][2] | ||
6702 | | status_rid.bssid[i][3] | ||
6703 | | status_rid.bssid[i][4] | ||
6704 | | status_rid.bssid[i][5]); | ||
6705 | i++) { | ||
6706 | memcpy(address[i].sa_data, | ||
6707 | status_rid.bssid[i], ETH_ALEN); | ||
6708 | address[i].sa_family = ARPHRD_ETHER; | ||
6709 | } | ||
6710 | } else { | ||
6711 | dwrq->flags = 1; /* Should be define'd */ | ||
6712 | memcpy(extra + sizeof(struct sockaddr)*i, | ||
6713 | &qual, sizeof(struct iw_quality)*i); | ||
6714 | } | ||
6715 | dwrq->length = i; | ||
6716 | |||
6717 | return 0; | ||
6718 | } | ||
6719 | |||
6720 | /*------------------------------------------------------------------*/ | ||
6721 | /* | ||
6722 | * Wireless Handler : Initiate Scan | ||
6723 | */ | ||
6724 | static int airo_set_scan(struct net_device *dev, | ||
6725 | struct iw_request_info *info, | ||
6726 | struct iw_param *vwrq, | ||
6727 | char *extra) | ||
6728 | { | ||
6729 | struct airo_info *ai = dev->priv; | ||
6730 | Cmd cmd; | ||
6731 | Resp rsp; | ||
6732 | |||
6733 | /* Note : you may have realised that, as this is a SET operation, | ||
6734 | * this is privileged and therefore a normal user can't | ||
6735 | * perform scanning. | ||
6736 | * This is not an error, while the device perform scanning, | ||
6737 | * traffic doesn't flow, so it's a perfect DoS... | ||
6738 | * Jean II */ | ||
6739 | if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; | ||
6740 | |||
6741 | /* Initiate a scan command */ | ||
6742 | memset(&cmd, 0, sizeof(cmd)); | ||
6743 | cmd.cmd=CMD_LISTBSS; | ||
6744 | if (down_interruptible(&ai->sem)) | ||
6745 | return -ERESTARTSYS; | ||
6746 | issuecommand(ai, &cmd, &rsp); | ||
6747 | ai->scan_timestamp = jiffies; | ||
6748 | up(&ai->sem); | ||
6749 | |||
6750 | /* At this point, just return to the user. */ | ||
6751 | |||
6752 | return 0; | ||
6753 | } | ||
6754 | |||
6755 | /*------------------------------------------------------------------*/ | ||
6756 | /* | ||
6757 | * Translate scan data returned from the card to a card independent | ||
6758 | * format that the Wireless Tools will understand - Jean II | ||
6759 | */ | ||
6760 | static inline char *airo_translate_scan(struct net_device *dev, | ||
6761 | char *current_ev, | ||
6762 | char *end_buf, | ||
6763 | BSSListRid *list) | ||
6764 | { | ||
6765 | struct airo_info *ai = dev->priv; | ||
6766 | struct iw_event iwe; /* Temporary buffer */ | ||
6767 | u16 capabilities; | ||
6768 | char * current_val; /* For rates */ | ||
6769 | int i; | ||
6770 | |||
6771 | /* First entry *MUST* be the AP MAC address */ | ||
6772 | iwe.cmd = SIOCGIWAP; | ||
6773 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
6774 | memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN); | ||
6775 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); | ||
6776 | |||
6777 | /* Other entries will be displayed in the order we give them */ | ||
6778 | |||
6779 | /* Add the ESSID */ | ||
6780 | iwe.u.data.length = list->ssidLen; | ||
6781 | if(iwe.u.data.length > 32) | ||
6782 | iwe.u.data.length = 32; | ||
6783 | iwe.cmd = SIOCGIWESSID; | ||
6784 | iwe.u.data.flags = 1; | ||
6785 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid); | ||
6786 | |||
6787 | /* Add mode */ | ||
6788 | iwe.cmd = SIOCGIWMODE; | ||
6789 | capabilities = le16_to_cpu(list->cap); | ||
6790 | if(capabilities & (CAP_ESS | CAP_IBSS)) { | ||
6791 | if(capabilities & CAP_ESS) | ||
6792 | iwe.u.mode = IW_MODE_MASTER; | ||
6793 | else | ||
6794 | iwe.u.mode = IW_MODE_ADHOC; | ||
6795 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); | ||
6796 | } | ||
6797 | |||
6798 | /* Add frequency */ | ||
6799 | iwe.cmd = SIOCGIWFREQ; | ||
6800 | iwe.u.freq.m = le16_to_cpu(list->dsChannel); | ||
6801 | iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000; | ||
6802 | iwe.u.freq.e = 1; | ||
6803 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); | ||
6804 | |||
6805 | /* Add quality statistics */ | ||
6806 | iwe.cmd = IWEVQUAL; | ||
6807 | if (ai->rssi) | ||
6808 | iwe.u.qual.level = 0x100 - ai->rssi[list->rssi].rssidBm; | ||
6809 | else | ||
6810 | iwe.u.qual.level = (list->rssi + 321) / 2; | ||
6811 | iwe.u.qual.noise = 0; | ||
6812 | iwe.u.qual.qual = 0; | ||
6813 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); | ||
6814 | |||
6815 | /* Add encryption capability */ | ||
6816 | iwe.cmd = SIOCGIWENCODE; | ||
6817 | if(capabilities & CAP_PRIVACY) | ||
6818 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
6819 | else | ||
6820 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
6821 | iwe.u.data.length = 0; | ||
6822 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid); | ||
6823 | |||
6824 | /* Rate : stuffing multiple values in a single event require a bit | ||
6825 | * more of magic - Jean II */ | ||
6826 | current_val = current_ev + IW_EV_LCP_LEN; | ||
6827 | |||
6828 | iwe.cmd = SIOCGIWRATE; | ||
6829 | /* Those two flags are ignored... */ | ||
6830 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
6831 | /* Max 8 values */ | ||
6832 | for(i = 0 ; i < 8 ; i++) { | ||
6833 | /* NULL terminated */ | ||
6834 | if(list->rates[i] == 0) | ||
6835 | break; | ||
6836 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
6837 | iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000); | ||
6838 | /* Add new value to event */ | ||
6839 | current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); | ||
6840 | } | ||
6841 | /* Check if we added any event */ | ||
6842 | if((current_val - current_ev) > IW_EV_LCP_LEN) | ||
6843 | current_ev = current_val; | ||
6844 | |||
6845 | /* The other data in the scan result are not really | ||
6846 | * interesting, so for now drop it - Jean II */ | ||
6847 | return current_ev; | ||
6848 | } | ||
6849 | |||
6850 | /*------------------------------------------------------------------*/ | ||
6851 | /* | ||
6852 | * Wireless Handler : Read Scan Results | ||
6853 | */ | ||
6854 | static int airo_get_scan(struct net_device *dev, | ||
6855 | struct iw_request_info *info, | ||
6856 | struct iw_point *dwrq, | ||
6857 | char *extra) | ||
6858 | { | ||
6859 | struct airo_info *ai = dev->priv; | ||
6860 | BSSListRid BSSList; | ||
6861 | int rc; | ||
6862 | char *current_ev = extra; | ||
6863 | |||
6864 | /* When we are associated again, the scan has surely finished. | ||
6865 | * Just in case, let's make sure enough time has elapsed since | ||
6866 | * we started the scan. - Javier */ | ||
6867 | if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) { | ||
6868 | /* Important note : we don't want to block the caller | ||
6869 | * until results are ready for various reasons. | ||
6870 | * First, managing wait queues is complex and racy | ||
6871 | * (there may be multiple simultaneous callers). | ||
6872 | * Second, we grab some rtnetlink lock before comming | ||
6873 | * here (in dev_ioctl()). | ||
6874 | * Third, the caller can wait on the Wireless Event | ||
6875 | * - Jean II */ | ||
6876 | return -EAGAIN; | ||
6877 | } | ||
6878 | ai->scan_timestamp = 0; | ||
6879 | |||
6880 | /* There's only a race with proc_BSSList_open(), but its | ||
6881 | * consequences are begnign. So I don't bother fixing it - Javier */ | ||
6882 | |||
6883 | /* Try to read the first entry of the scan result */ | ||
6884 | rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1); | ||
6885 | if((rc) || (BSSList.index == 0xffff)) { | ||
6886 | /* Client error, no scan results... | ||
6887 | * The caller need to restart the scan. */ | ||
6888 | return -ENODATA; | ||
6889 | } | ||
6890 | |||
6891 | /* Read and parse all entries */ | ||
6892 | while((!rc) && (BSSList.index != 0xffff)) { | ||
6893 | /* Translate to WE format this entry */ | ||
6894 | current_ev = airo_translate_scan(dev, current_ev, | ||
6895 | extra + dwrq->length, | ||
6896 | &BSSList); | ||
6897 | |||
6898 | /* Check if there is space for one more entry */ | ||
6899 | if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { | ||
6900 | /* Ask user space to try again with a bigger buffer */ | ||
6901 | return -E2BIG; | ||
6902 | } | ||
6903 | |||
6904 | /* Read next entry */ | ||
6905 | rc = PC4500_readrid(ai, RID_BSSLISTNEXT, | ||
6906 | &BSSList, sizeof(BSSList), 1); | ||
6907 | } | ||
6908 | /* Length of data */ | ||
6909 | dwrq->length = (current_ev - extra); | ||
6910 | dwrq->flags = 0; /* todo */ | ||
6911 | |||
6912 | return 0; | ||
6913 | } | ||
6914 | |||
6915 | /*------------------------------------------------------------------*/ | ||
6916 | /* | ||
6917 | * Commit handler : called after a bunch of SET operations | ||
6918 | */ | ||
6919 | static int airo_config_commit(struct net_device *dev, | ||
6920 | struct iw_request_info *info, /* NULL */ | ||
6921 | void *zwrq, /* NULL */ | ||
6922 | char *extra) /* NULL */ | ||
6923 | { | ||
6924 | struct airo_info *local = dev->priv; | ||
6925 | Resp rsp; | ||
6926 | |||
6927 | if (!test_bit (FLAG_COMMIT, &local->flags)) | ||
6928 | return 0; | ||
6929 | |||
6930 | /* Some of the "SET" function may have modified some of the | ||
6931 | * parameters. It's now time to commit them in the card */ | ||
6932 | disable_MAC(local, 1); | ||
6933 | if (test_bit (FLAG_RESET, &local->flags)) { | ||
6934 | APListRid APList_rid; | ||
6935 | SsidRid SSID_rid; | ||
6936 | |||
6937 | readAPListRid(local, &APList_rid); | ||
6938 | readSsidRid(local, &SSID_rid); | ||
6939 | if (test_bit(FLAG_MPI,&local->flags)) | ||
6940 | setup_card(local, dev->dev_addr, 1 ); | ||
6941 | else | ||
6942 | reset_airo_card(dev); | ||
6943 | disable_MAC(local, 1); | ||
6944 | writeSsidRid(local, &SSID_rid, 1); | ||
6945 | writeAPListRid(local, &APList_rid, 1); | ||
6946 | } | ||
6947 | if (down_interruptible(&local->sem)) | ||
6948 | return -ERESTARTSYS; | ||
6949 | writeConfigRid(local, 0); | ||
6950 | enable_MAC(local, &rsp, 0); | ||
6951 | if (test_bit (FLAG_RESET, &local->flags)) | ||
6952 | airo_set_promisc(local); | ||
6953 | else | ||
6954 | up(&local->sem); | ||
6955 | |||
6956 | return 0; | ||
6957 | } | ||
6958 | |||
6959 | /*------------------------------------------------------------------*/ | ||
6960 | /* | ||
6961 | * Structures to export the Wireless Handlers | ||
6962 | */ | ||
6963 | |||
6964 | static const struct iw_priv_args airo_private_args[] = { | ||
6965 | /*{ cmd, set_args, get_args, name } */ | ||
6966 | { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), | ||
6967 | IW_PRIV_TYPE_BYTE | 2047, "airoioctl" }, | ||
6968 | { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), | ||
6969 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" }, | ||
6970 | }; | ||
6971 | |||
6972 | static const iw_handler airo_handler[] = | ||
6973 | { | ||
6974 | (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */ | ||
6975 | (iw_handler) airo_get_name, /* SIOCGIWNAME */ | ||
6976 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
6977 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
6978 | (iw_handler) airo_set_freq, /* SIOCSIWFREQ */ | ||
6979 | (iw_handler) airo_get_freq, /* SIOCGIWFREQ */ | ||
6980 | (iw_handler) airo_set_mode, /* SIOCSIWMODE */ | ||
6981 | (iw_handler) airo_get_mode, /* SIOCGIWMODE */ | ||
6982 | (iw_handler) airo_set_sens, /* SIOCSIWSENS */ | ||
6983 | (iw_handler) airo_get_sens, /* SIOCGIWSENS */ | ||
6984 | (iw_handler) NULL, /* SIOCSIWRANGE */ | ||
6985 | (iw_handler) airo_get_range, /* SIOCGIWRANGE */ | ||
6986 | (iw_handler) NULL, /* SIOCSIWPRIV */ | ||
6987 | (iw_handler) NULL, /* SIOCGIWPRIV */ | ||
6988 | (iw_handler) NULL, /* SIOCSIWSTATS */ | ||
6989 | (iw_handler) NULL, /* SIOCGIWSTATS */ | ||
6990 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
6991 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
6992 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
6993 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
6994 | (iw_handler) airo_set_wap, /* SIOCSIWAP */ | ||
6995 | (iw_handler) airo_get_wap, /* SIOCGIWAP */ | ||
6996 | (iw_handler) NULL, /* -- hole -- */ | ||
6997 | (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */ | ||
6998 | (iw_handler) airo_set_scan, /* SIOCSIWSCAN */ | ||
6999 | (iw_handler) airo_get_scan, /* SIOCGIWSCAN */ | ||
7000 | (iw_handler) airo_set_essid, /* SIOCSIWESSID */ | ||
7001 | (iw_handler) airo_get_essid, /* SIOCGIWESSID */ | ||
7002 | (iw_handler) airo_set_nick, /* SIOCSIWNICKN */ | ||
7003 | (iw_handler) airo_get_nick, /* SIOCGIWNICKN */ | ||
7004 | (iw_handler) NULL, /* -- hole -- */ | ||
7005 | (iw_handler) NULL, /* -- hole -- */ | ||
7006 | (iw_handler) airo_set_rate, /* SIOCSIWRATE */ | ||
7007 | (iw_handler) airo_get_rate, /* SIOCGIWRATE */ | ||
7008 | (iw_handler) airo_set_rts, /* SIOCSIWRTS */ | ||
7009 | (iw_handler) airo_get_rts, /* SIOCGIWRTS */ | ||
7010 | (iw_handler) airo_set_frag, /* SIOCSIWFRAG */ | ||
7011 | (iw_handler) airo_get_frag, /* SIOCGIWFRAG */ | ||
7012 | (iw_handler) airo_set_txpow, /* SIOCSIWTXPOW */ | ||
7013 | (iw_handler) airo_get_txpow, /* SIOCGIWTXPOW */ | ||
7014 | (iw_handler) airo_set_retry, /* SIOCSIWRETRY */ | ||
7015 | (iw_handler) airo_get_retry, /* SIOCGIWRETRY */ | ||
7016 | (iw_handler) airo_set_encode, /* SIOCSIWENCODE */ | ||
7017 | (iw_handler) airo_get_encode, /* SIOCGIWENCODE */ | ||
7018 | (iw_handler) airo_set_power, /* SIOCSIWPOWER */ | ||
7019 | (iw_handler) airo_get_power, /* SIOCGIWPOWER */ | ||
7020 | }; | ||
7021 | |||
7022 | /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. | ||
7023 | * We want to force the use of the ioctl code, because those can't be | ||
7024 | * won't work the iw_handler code (because they simultaneously read | ||
7025 | * and write data and iw_handler can't do that). | ||
7026 | * Note that it's perfectly legal to read/write on a single ioctl command, | ||
7027 | * you just can't use iwpriv and need to force it via the ioctl handler. | ||
7028 | * Jean II */ | ||
7029 | static const iw_handler airo_private_handler[] = | ||
7030 | { | ||
7031 | NULL, /* SIOCIWFIRSTPRIV */ | ||
7032 | }; | ||
7033 | |||
7034 | static const struct iw_handler_def airo_handler_def = | ||
7035 | { | ||
7036 | .num_standard = sizeof(airo_handler)/sizeof(iw_handler), | ||
7037 | .num_private = sizeof(airo_private_handler)/sizeof(iw_handler), | ||
7038 | .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args), | ||
7039 | .standard = airo_handler, | ||
7040 | .private = airo_private_handler, | ||
7041 | .private_args = airo_private_args, | ||
7042 | .get_wireless_stats = airo_get_wireless_stats, | ||
7043 | }; | ||
7044 | |||
7045 | #endif /* WIRELESS_EXT */ | ||
7046 | |||
7047 | /* | ||
7048 | * This defines the configuration part of the Wireless Extensions | ||
7049 | * Note : irq and spinlock protection will occur in the subroutines | ||
7050 | * | ||
7051 | * TODO : | ||
7052 | * o Check input value more carefully and fill correct values in range | ||
7053 | * o Test and shakeout the bugs (if any) | ||
7054 | * | ||
7055 | * Jean II | ||
7056 | * | ||
7057 | * Javier Achirica did a great job of merging code from the unnamed CISCO | ||
7058 | * developer that added support for flashing the card. | ||
7059 | */ | ||
7060 | static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
7061 | { | ||
7062 | int rc = 0; | ||
7063 | struct airo_info *ai = (struct airo_info *)dev->priv; | ||
7064 | |||
7065 | if (ai->power) | ||
7066 | return 0; | ||
7067 | |||
7068 | switch (cmd) { | ||
7069 | #ifdef CISCO_EXT | ||
7070 | case AIROIDIFC: | ||
7071 | #ifdef AIROOLDIDIFC | ||
7072 | case AIROOLDIDIFC: | ||
7073 | #endif | ||
7074 | { | ||
7075 | int val = AIROMAGIC; | ||
7076 | aironet_ioctl com; | ||
7077 | if (copy_from_user(&com,rq->ifr_data,sizeof(com))) | ||
7078 | rc = -EFAULT; | ||
7079 | else if (copy_to_user(com.data,(char *)&val,sizeof(val))) | ||
7080 | rc = -EFAULT; | ||
7081 | } | ||
7082 | break; | ||
7083 | |||
7084 | case AIROIOCTL: | ||
7085 | #ifdef AIROOLDIOCTL | ||
7086 | case AIROOLDIOCTL: | ||
7087 | #endif | ||
7088 | /* Get the command struct and hand it off for evaluation by | ||
7089 | * the proper subfunction | ||
7090 | */ | ||
7091 | { | ||
7092 | aironet_ioctl com; | ||
7093 | if (copy_from_user(&com,rq->ifr_data,sizeof(com))) { | ||
7094 | rc = -EFAULT; | ||
7095 | break; | ||
7096 | } | ||
7097 | |||
7098 | /* Separate R/W functions bracket legality here | ||
7099 | */ | ||
7100 | if ( com.command == AIRORSWVERSION ) { | ||
7101 | if (copy_to_user(com.data, swversion, sizeof(swversion))) | ||
7102 | rc = -EFAULT; | ||
7103 | else | ||
7104 | rc = 0; | ||
7105 | } | ||
7106 | else if ( com.command <= AIRORRID) | ||
7107 | rc = readrids(dev,&com); | ||
7108 | else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) ) | ||
7109 | rc = writerids(dev,&com); | ||
7110 | else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART ) | ||
7111 | rc = flashcard(dev,&com); | ||
7112 | else | ||
7113 | rc = -EINVAL; /* Bad command in ioctl */ | ||
7114 | } | ||
7115 | break; | ||
7116 | #endif /* CISCO_EXT */ | ||
7117 | |||
7118 | // All other calls are currently unsupported | ||
7119 | default: | ||
7120 | rc = -EOPNOTSUPP; | ||
7121 | } | ||
7122 | return rc; | ||
7123 | } | ||
7124 | |||
7125 | #ifdef WIRELESS_EXT | ||
7126 | /* | ||
7127 | * Get the Wireless stats out of the driver | ||
7128 | * Note : irq and spinlock protection will occur in the subroutines | ||
7129 | * | ||
7130 | * TODO : | ||
7131 | * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs) | ||
7132 | * | ||
7133 | * Jean | ||
7134 | */ | ||
7135 | static void airo_read_wireless_stats(struct airo_info *local) | ||
7136 | { | ||
7137 | StatusRid status_rid; | ||
7138 | StatsRid stats_rid; | ||
7139 | CapabilityRid cap_rid; | ||
7140 | u32 *vals = stats_rid.vals; | ||
7141 | |||
7142 | /* Get stats out of the card */ | ||
7143 | clear_bit(JOB_WSTATS, &local->flags); | ||
7144 | if (local->power) { | ||
7145 | up(&local->sem); | ||
7146 | return; | ||
7147 | } | ||
7148 | readCapabilityRid(local, &cap_rid, 0); | ||
7149 | readStatusRid(local, &status_rid, 0); | ||
7150 | readStatsRid(local, &stats_rid, RID_STATS, 0); | ||
7151 | up(&local->sem); | ||
7152 | |||
7153 | /* The status */ | ||
7154 | local->wstats.status = status_rid.mode; | ||
7155 | |||
7156 | /* Signal quality and co. But where is the noise level ??? */ | ||
7157 | local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); | ||
7158 | if (local->rssi) | ||
7159 | local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm; | ||
7160 | else | ||
7161 | local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2; | ||
7162 | if (status_rid.len >= 124) { | ||
7163 | local->wstats.qual.noise = 256 - status_rid.noisedBm; | ||
7164 | local->wstats.qual.updated = 7; | ||
7165 | } else { | ||
7166 | local->wstats.qual.noise = 0; | ||
7167 | local->wstats.qual.updated = 3; | ||
7168 | } | ||
7169 | |||
7170 | /* Packets discarded in the wireless adapter due to wireless | ||
7171 | * specific problems */ | ||
7172 | local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */ | ||
7173 | local->wstats.discard.code = vals[6];/* RxWepErr */ | ||
7174 | local->wstats.discard.fragment = vals[30]; | ||
7175 | local->wstats.discard.retries = vals[10]; | ||
7176 | local->wstats.discard.misc = vals[1] + vals[32]; | ||
7177 | local->wstats.miss.beacon = vals[34]; | ||
7178 | } | ||
7179 | |||
7180 | struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) | ||
7181 | { | ||
7182 | struct airo_info *local = dev->priv; | ||
7183 | |||
7184 | if (!test_bit(JOB_WSTATS, &local->flags)) { | ||
7185 | /* Get stats out of the card if available */ | ||
7186 | if (down_trylock(&local->sem) != 0) { | ||
7187 | set_bit(JOB_WSTATS, &local->flags); | ||
7188 | wake_up_interruptible(&local->thr_wait); | ||
7189 | } else | ||
7190 | airo_read_wireless_stats(local); | ||
7191 | } | ||
7192 | |||
7193 | return &local->wstats; | ||
7194 | } | ||
7195 | #endif /* WIRELESS_EXT */ | ||
7196 | |||
7197 | #ifdef CISCO_EXT | ||
7198 | /* | ||
7199 | * This just translates from driver IOCTL codes to the command codes to | ||
7200 | * feed to the radio's host interface. Things can be added/deleted | ||
7201 | * as needed. This represents the READ side of control I/O to | ||
7202 | * the card | ||
7203 | */ | ||
7204 | static int readrids(struct net_device *dev, aironet_ioctl *comp) { | ||
7205 | unsigned short ridcode; | ||
7206 | unsigned char *iobuf; | ||
7207 | int len; | ||
7208 | struct airo_info *ai = dev->priv; | ||
7209 | Resp rsp; | ||
7210 | |||
7211 | if (test_bit(FLAG_FLASHING, &ai->flags)) | ||
7212 | return -EIO; | ||
7213 | |||
7214 | switch(comp->command) | ||
7215 | { | ||
7216 | case AIROGCAP: ridcode = RID_CAPABILITIES; break; | ||
7217 | case AIROGCFG: ridcode = RID_CONFIG; | ||
7218 | if (test_bit(FLAG_COMMIT, &ai->flags)) { | ||
7219 | disable_MAC (ai, 1); | ||
7220 | writeConfigRid (ai, 1); | ||
7221 | enable_MAC (ai, &rsp, 1); | ||
7222 | } | ||
7223 | break; | ||
7224 | case AIROGSLIST: ridcode = RID_SSID; break; | ||
7225 | case AIROGVLIST: ridcode = RID_APLIST; break; | ||
7226 | case AIROGDRVNAM: ridcode = RID_DRVNAME; break; | ||
7227 | case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; | ||
7228 | case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; | ||
7229 | /* Only super-user can read WEP keys */ | ||
7230 | if (!capable(CAP_NET_ADMIN)) | ||
7231 | return -EPERM; | ||
7232 | break; | ||
7233 | case AIROGWEPKNV: ridcode = RID_WEP_PERM; | ||
7234 | /* Only super-user can read WEP keys */ | ||
7235 | if (!capable(CAP_NET_ADMIN)) | ||
7236 | return -EPERM; | ||
7237 | break; | ||
7238 | case AIROGSTAT: ridcode = RID_STATUS; break; | ||
7239 | case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; | ||
7240 | case AIROGSTATSC32: ridcode = RID_STATS; break; | ||
7241 | #ifdef MICSUPPORT | ||
7242 | case AIROGMICSTATS: | ||
7243 | if (copy_to_user(comp->data, &ai->micstats, | ||
7244 | min((int)comp->len,(int)sizeof(ai->micstats)))) | ||
7245 | return -EFAULT; | ||
7246 | return 0; | ||
7247 | #endif | ||
7248 | case AIRORRID: ridcode = comp->ridnum; break; | ||
7249 | default: | ||
7250 | return -EINVAL; | ||
7251 | break; | ||
7252 | } | ||
7253 | |||
7254 | if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) | ||
7255 | return -ENOMEM; | ||
7256 | |||
7257 | PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1); | ||
7258 | /* get the count of bytes in the rid docs say 1st 2 bytes is it. | ||
7259 | * then return it to the user | ||
7260 | * 9/22/2000 Honor user given length | ||
7261 | */ | ||
7262 | len = comp->len; | ||
7263 | |||
7264 | if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) { | ||
7265 | kfree (iobuf); | ||
7266 | return -EFAULT; | ||
7267 | } | ||
7268 | kfree (iobuf); | ||
7269 | return 0; | ||
7270 | } | ||
7271 | |||
7272 | /* | ||
7273 | * Danger Will Robinson write the rids here | ||
7274 | */ | ||
7275 | |||
7276 | static int writerids(struct net_device *dev, aironet_ioctl *comp) { | ||
7277 | struct airo_info *ai = dev->priv; | ||
7278 | int ridcode; | ||
7279 | #ifdef MICSUPPORT | ||
7280 | int enabled; | ||
7281 | #endif | ||
7282 | Resp rsp; | ||
7283 | static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); | ||
7284 | unsigned char *iobuf; | ||
7285 | |||
7286 | /* Only super-user can write RIDs */ | ||
7287 | if (!capable(CAP_NET_ADMIN)) | ||
7288 | return -EPERM; | ||
7289 | |||
7290 | if (test_bit(FLAG_FLASHING, &ai->flags)) | ||
7291 | return -EIO; | ||
7292 | |||
7293 | ridcode = 0; | ||
7294 | writer = do_writerid; | ||
7295 | |||
7296 | switch(comp->command) | ||
7297 | { | ||
7298 | case AIROPSIDS: ridcode = RID_SSID; break; | ||
7299 | case AIROPCAP: ridcode = RID_CAPABILITIES; break; | ||
7300 | case AIROPAPLIST: ridcode = RID_APLIST; break; | ||
7301 | case AIROPCFG: ai->config.len = 0; | ||
7302 | clear_bit(FLAG_COMMIT, &ai->flags); | ||
7303 | ridcode = RID_CONFIG; break; | ||
7304 | case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; | ||
7305 | case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; | ||
7306 | case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break; | ||
7307 | case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid; | ||
7308 | break; | ||
7309 | case AIROPLEAPUSR+1: ridcode = 0xFF2A; break; | ||
7310 | case AIROPLEAPUSR+2: ridcode = 0xFF2B; break; | ||
7311 | |||
7312 | /* this is not really a rid but a command given to the card | ||
7313 | * same with MAC off | ||
7314 | */ | ||
7315 | case AIROPMACON: | ||
7316 | if (enable_MAC(ai, &rsp, 1) != 0) | ||
7317 | return -EIO; | ||
7318 | return 0; | ||
7319 | |||
7320 | /* | ||
7321 | * Evidently this code in the airo driver does not get a symbol | ||
7322 | * as disable_MAC. it's probably so short the compiler does not gen one. | ||
7323 | */ | ||
7324 | case AIROPMACOFF: | ||
7325 | disable_MAC(ai, 1); | ||
7326 | return 0; | ||
7327 | |||
7328 | /* This command merely clears the counts does not actually store any data | ||
7329 | * only reads rid. But as it changes the cards state, I put it in the | ||
7330 | * writerid routines. | ||
7331 | */ | ||
7332 | case AIROPSTCLR: | ||
7333 | if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) | ||
7334 | return -ENOMEM; | ||
7335 | |||
7336 | PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1); | ||
7337 | |||
7338 | #ifdef MICSUPPORT | ||
7339 | enabled = ai->micstats.enabled; | ||
7340 | memset(&ai->micstats,0,sizeof(ai->micstats)); | ||
7341 | ai->micstats.enabled = enabled; | ||
7342 | #endif | ||
7343 | |||
7344 | if (copy_to_user(comp->data, iobuf, | ||
7345 | min((int)comp->len, (int)RIDSIZE))) { | ||
7346 | kfree (iobuf); | ||
7347 | return -EFAULT; | ||
7348 | } | ||
7349 | kfree (iobuf); | ||
7350 | return 0; | ||
7351 | |||
7352 | default: | ||
7353 | return -EOPNOTSUPP; /* Blarg! */ | ||
7354 | } | ||
7355 | if(comp->len > RIDSIZE) | ||
7356 | return -EINVAL; | ||
7357 | |||
7358 | if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) | ||
7359 | return -ENOMEM; | ||
7360 | |||
7361 | if (copy_from_user(iobuf,comp->data,comp->len)) { | ||
7362 | kfree (iobuf); | ||
7363 | return -EFAULT; | ||
7364 | } | ||
7365 | |||
7366 | if (comp->command == AIROPCFG) { | ||
7367 | ConfigRid *cfg = (ConfigRid *)iobuf; | ||
7368 | |||
7369 | if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) | ||
7370 | cfg->opmode |= MODE_MIC; | ||
7371 | |||
7372 | if ((cfg->opmode & 0xFF) == MODE_STA_IBSS) | ||
7373 | set_bit (FLAG_ADHOC, &ai->flags); | ||
7374 | else | ||
7375 | clear_bit (FLAG_ADHOC, &ai->flags); | ||
7376 | } | ||
7377 | |||
7378 | if((*writer)(ai, ridcode, iobuf,comp->len,1)) { | ||
7379 | kfree (iobuf); | ||
7380 | return -EIO; | ||
7381 | } | ||
7382 | kfree (iobuf); | ||
7383 | return 0; | ||
7384 | } | ||
7385 | |||
7386 | /***************************************************************************** | ||
7387 | * Ancillary flash / mod functions much black magic lurkes here * | ||
7388 | ***************************************************************************** | ||
7389 | */ | ||
7390 | |||
7391 | /* | ||
7392 | * Flash command switch table | ||
7393 | */ | ||
7394 | |||
7395 | int flashcard(struct net_device *dev, aironet_ioctl *comp) { | ||
7396 | int z; | ||
7397 | int cmdreset(struct airo_info *); | ||
7398 | int setflashmode(struct airo_info *); | ||
7399 | int flashgchar(struct airo_info *,int,int); | ||
7400 | int flashpchar(struct airo_info *,int,int); | ||
7401 | int flashputbuf(struct airo_info *); | ||
7402 | int flashrestart(struct airo_info *,struct net_device *); | ||
7403 | |||
7404 | /* Only super-user can modify flash */ | ||
7405 | if (!capable(CAP_NET_ADMIN)) | ||
7406 | return -EPERM; | ||
7407 | |||
7408 | switch(comp->command) | ||
7409 | { | ||
7410 | case AIROFLSHRST: | ||
7411 | return cmdreset((struct airo_info *)dev->priv); | ||
7412 | |||
7413 | case AIROFLSHSTFL: | ||
7414 | if (!((struct airo_info *)dev->priv)->flash && | ||
7415 | (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL) | ||
7416 | return -ENOMEM; | ||
7417 | return setflashmode((struct airo_info *)dev->priv); | ||
7418 | |||
7419 | case AIROFLSHGCHR: /* Get char from aux */ | ||
7420 | if(comp->len != sizeof(int)) | ||
7421 | return -EINVAL; | ||
7422 | if (copy_from_user(&z,comp->data,comp->len)) | ||
7423 | return -EFAULT; | ||
7424 | return flashgchar((struct airo_info *)dev->priv,z,8000); | ||
7425 | |||
7426 | case AIROFLSHPCHR: /* Send char to card. */ | ||
7427 | if(comp->len != sizeof(int)) | ||
7428 | return -EINVAL; | ||
7429 | if (copy_from_user(&z,comp->data,comp->len)) | ||
7430 | return -EFAULT; | ||
7431 | return flashpchar((struct airo_info *)dev->priv,z,8000); | ||
7432 | |||
7433 | case AIROFLPUTBUF: /* Send 32k to card */ | ||
7434 | if (!((struct airo_info *)dev->priv)->flash) | ||
7435 | return -ENOMEM; | ||
7436 | if(comp->len > FLASHSIZE) | ||
7437 | return -EINVAL; | ||
7438 | if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len)) | ||
7439 | return -EFAULT; | ||
7440 | |||
7441 | flashputbuf((struct airo_info *)dev->priv); | ||
7442 | return 0; | ||
7443 | |||
7444 | case AIRORESTART: | ||
7445 | if(flashrestart((struct airo_info *)dev->priv,dev)) | ||
7446 | return -EIO; | ||
7447 | return 0; | ||
7448 | } | ||
7449 | return -EINVAL; | ||
7450 | } | ||
7451 | |||
7452 | #define FLASH_COMMAND 0x7e7e | ||
7453 | |||
7454 | /* | ||
7455 | * STEP 1) | ||
7456 | * Disable MAC and do soft reset on | ||
7457 | * card. | ||
7458 | */ | ||
7459 | |||
7460 | int cmdreset(struct airo_info *ai) { | ||
7461 | disable_MAC(ai, 1); | ||
7462 | |||
7463 | if(!waitbusy (ai)){ | ||
7464 | printk(KERN_INFO "Waitbusy hang before RESET\n"); | ||
7465 | return -EBUSY; | ||
7466 | } | ||
7467 | |||
7468 | OUT4500(ai,COMMAND,CMD_SOFTRESET); | ||
7469 | |||
7470 | ssleep(1); /* WAS 600 12/7/00 */ | ||
7471 | |||
7472 | if(!waitbusy (ai)){ | ||
7473 | printk(KERN_INFO "Waitbusy hang AFTER RESET\n"); | ||
7474 | return -EBUSY; | ||
7475 | } | ||
7476 | return 0; | ||
7477 | } | ||
7478 | |||
7479 | /* STEP 2) | ||
7480 | * Put the card in legendary flash | ||
7481 | * mode | ||
7482 | */ | ||
7483 | |||
7484 | int setflashmode (struct airo_info *ai) { | ||
7485 | set_bit (FLAG_FLASHING, &ai->flags); | ||
7486 | |||
7487 | OUT4500(ai, SWS0, FLASH_COMMAND); | ||
7488 | OUT4500(ai, SWS1, FLASH_COMMAND); | ||
7489 | if (probe) { | ||
7490 | OUT4500(ai, SWS0, FLASH_COMMAND); | ||
7491 | OUT4500(ai, COMMAND,0x10); | ||
7492 | } else { | ||
7493 | OUT4500(ai, SWS2, FLASH_COMMAND); | ||
7494 | OUT4500(ai, SWS3, FLASH_COMMAND); | ||
7495 | OUT4500(ai, COMMAND,0); | ||
7496 | } | ||
7497 | msleep(500); /* 500ms delay */ | ||
7498 | |||
7499 | if(!waitbusy(ai)) { | ||
7500 | clear_bit (FLAG_FLASHING, &ai->flags); | ||
7501 | printk(KERN_INFO "Waitbusy hang after setflash mode\n"); | ||
7502 | return -EIO; | ||
7503 | } | ||
7504 | return 0; | ||
7505 | } | ||
7506 | |||
7507 | /* Put character to SWS0 wait for dwelltime | ||
7508 | * x 50us for echo . | ||
7509 | */ | ||
7510 | |||
7511 | int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | ||
7512 | int echo; | ||
7513 | int waittime; | ||
7514 | |||
7515 | byte |= 0x8000; | ||
7516 | |||
7517 | if(dwelltime == 0 ) | ||
7518 | dwelltime = 200; | ||
7519 | |||
7520 | waittime=dwelltime; | ||
7521 | |||
7522 | /* Wait for busy bit d15 to go false indicating buffer empty */ | ||
7523 | while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) { | ||
7524 | udelay (50); | ||
7525 | waittime -= 50; | ||
7526 | } | ||
7527 | |||
7528 | /* timeout for busy clear wait */ | ||
7529 | if(waittime <= 0 ){ | ||
7530 | printk(KERN_INFO "flash putchar busywait timeout! \n"); | ||
7531 | return -EBUSY; | ||
7532 | } | ||
7533 | |||
7534 | /* Port is clear now write byte and wait for it to echo back */ | ||
7535 | do { | ||
7536 | OUT4500(ai,SWS0,byte); | ||
7537 | udelay(50); | ||
7538 | dwelltime -= 50; | ||
7539 | echo = IN4500(ai,SWS1); | ||
7540 | } while (dwelltime >= 0 && echo != byte); | ||
7541 | |||
7542 | OUT4500(ai,SWS1,0); | ||
7543 | |||
7544 | return (echo == byte) ? 0 : -EIO; | ||
7545 | } | ||
7546 | |||
7547 | /* | ||
7548 | * Get a character from the card matching matchbyte | ||
7549 | * Step 3) | ||
7550 | */ | ||
7551 | int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | ||
7552 | int rchar; | ||
7553 | unsigned char rbyte=0; | ||
7554 | |||
7555 | do { | ||
7556 | rchar = IN4500(ai,SWS1); | ||
7557 | |||
7558 | if(dwelltime && !(0x8000 & rchar)){ | ||
7559 | dwelltime -= 10; | ||
7560 | mdelay(10); | ||
7561 | continue; | ||
7562 | } | ||
7563 | rbyte = 0xff & rchar; | ||
7564 | |||
7565 | if( (rbyte == matchbyte) && (0x8000 & rchar) ){ | ||
7566 | OUT4500(ai,SWS1,0); | ||
7567 | return 0; | ||
7568 | } | ||
7569 | if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) | ||
7570 | break; | ||
7571 | OUT4500(ai,SWS1,0); | ||
7572 | |||
7573 | }while(dwelltime > 0); | ||
7574 | return -EIO; | ||
7575 | } | ||
7576 | |||
7577 | /* | ||
7578 | * Transfer 32k of firmware data from user buffer to our buffer and | ||
7579 | * send to the card | ||
7580 | */ | ||
7581 | |||
7582 | int flashputbuf(struct airo_info *ai){ | ||
7583 | int nwords; | ||
7584 | |||
7585 | /* Write stuff */ | ||
7586 | if (test_bit(FLAG_MPI,&ai->flags)) | ||
7587 | memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE); | ||
7588 | else { | ||
7589 | OUT4500(ai,AUXPAGE,0x100); | ||
7590 | OUT4500(ai,AUXOFF,0); | ||
7591 | |||
7592 | for(nwords=0;nwords != FLASHSIZE / 2;nwords++){ | ||
7593 | OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff); | ||
7594 | } | ||
7595 | } | ||
7596 | OUT4500(ai,SWS0,0x8000); | ||
7597 | |||
7598 | return 0; | ||
7599 | } | ||
7600 | |||
7601 | /* | ||
7602 | * | ||
7603 | */ | ||
7604 | int flashrestart(struct airo_info *ai,struct net_device *dev){ | ||
7605 | int i,status; | ||
7606 | |||
7607 | ssleep(1); /* Added 12/7/00 */ | ||
7608 | clear_bit (FLAG_FLASHING, &ai->flags); | ||
7609 | if (test_bit(FLAG_MPI, &ai->flags)) { | ||
7610 | status = mpi_init_descriptors(ai); | ||
7611 | if (status != SUCCESS) | ||
7612 | return status; | ||
7613 | } | ||
7614 | status = setup_card(ai, dev->dev_addr, 1); | ||
7615 | |||
7616 | if (!test_bit(FLAG_MPI,&ai->flags)) | ||
7617 | for( i = 0; i < MAX_FIDS; i++ ) { | ||
7618 | ai->fids[i] = transmit_allocate | ||
7619 | ( ai, 2312, i >= MAX_FIDS / 2 ); | ||
7620 | } | ||
7621 | |||
7622 | ssleep(1); /* Added 12/7/00 */ | ||
7623 | return status; | ||
7624 | } | ||
7625 | #endif /* CISCO_EXT */ | ||
7626 | |||
7627 | /* | ||
7628 | This program is free software; you can redistribute it and/or | ||
7629 | modify it under the terms of the GNU General Public License | ||
7630 | as published by the Free Software Foundation; either version 2 | ||
7631 | of the License, or (at your option) any later version. | ||
7632 | |||
7633 | This program is distributed in the hope that it will be useful, | ||
7634 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
7635 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
7636 | GNU General Public License for more details. | ||
7637 | |||
7638 | In addition: | ||
7639 | |||
7640 | Redistribution and use in source and binary forms, with or without | ||
7641 | modification, are permitted provided that the following conditions | ||
7642 | are met: | ||
7643 | |||
7644 | 1. Redistributions of source code must retain the above copyright | ||
7645 | notice, this list of conditions and the following disclaimer. | ||
7646 | 2. Redistributions in binary form must reproduce the above copyright | ||
7647 | notice, this list of conditions and the following disclaimer in the | ||
7648 | documentation and/or other materials provided with the distribution. | ||
7649 | 3. The name of the author may not be used to endorse or promote | ||
7650 | products derived from this software without specific prior written | ||
7651 | permission. | ||
7652 | |||
7653 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
7654 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
7655 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
7656 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | ||
7657 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
7658 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
7659 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
7660 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
7661 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
7662 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
7663 | POSSIBILITY OF SUCH DAMAGE. | ||
7664 | */ | ||
7665 | |||
7666 | module_init(airo_init_module); | ||
7667 | module_exit(airo_cleanup_module); | ||
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c new file mode 100644 index 000000000000..fbf53af6cda4 --- /dev/null +++ b/drivers/net/wireless/airo_cs.c | |||
@@ -0,0 +1,622 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Aironet driver for 4500 and 4800 series cards | ||
4 | |||
5 | This code is released under both the GPL version 2 and BSD licenses. | ||
6 | Either license may be used. The respective licenses are found at | ||
7 | the end of this file. | ||
8 | |||
9 | This code was developed by Benjamin Reed <breed@users.sourceforge.net> | ||
10 | including portions of which come from the Aironet PC4500 | ||
11 | Developer's Reference Manual and used with permission. Copyright | ||
12 | (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use | ||
13 | code in the Developer's manual was granted for this driver by | ||
14 | Aironet. | ||
15 | |||
16 | In addition this module was derived from dummy_cs. | ||
17 | The initial developer of dummy_cs is David A. Hinds | ||
18 | <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
19 | are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
20 | |||
21 | ======================================================================*/ | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #ifdef __IN_PCMCIA_PACKAGE__ | ||
25 | #include <pcmcia/k_compat.h> | ||
26 | #endif | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/ptrace.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/timer.h> | ||
34 | #include <linux/netdevice.h> | ||
35 | |||
36 | #include <pcmcia/version.h> | ||
37 | #include <pcmcia/cs_types.h> | ||
38 | #include <pcmcia/cs.h> | ||
39 | #include <pcmcia/cistpl.h> | ||
40 | #include <pcmcia/cisreg.h> | ||
41 | #include <pcmcia/ds.h> | ||
42 | |||
43 | #include <asm/io.h> | ||
44 | #include <asm/system.h> | ||
45 | |||
46 | /* | ||
47 | All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If | ||
48 | you do not define PCMCIA_DEBUG at all, all the debug code will be | ||
49 | left out. If you compile with PCMCIA_DEBUG=0, the debug code will | ||
50 | be present but disabled -- but it can then be enabled for specific | ||
51 | modules at load time with a 'pc_debug=#' option to insmod. | ||
52 | */ | ||
53 | #ifdef PCMCIA_DEBUG | ||
54 | static int pc_debug = PCMCIA_DEBUG; | ||
55 | module_param(pc_debug, int, 0); | ||
56 | static char *version = "$Revision: 1.2 $"; | ||
57 | #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); | ||
58 | #else | ||
59 | #define DEBUG(n, args...) | ||
60 | #endif | ||
61 | |||
62 | /*====================================================================*/ | ||
63 | |||
64 | MODULE_AUTHOR("Benjamin Reed"); | ||
65 | MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ | ||
66 | cards. This is the module that links the PCMCIA card \ | ||
67 | with the airo module."); | ||
68 | MODULE_LICENSE("Dual BSD/GPL"); | ||
69 | MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards"); | ||
70 | |||
71 | /*====================================================================*/ | ||
72 | |||
73 | /* | ||
74 | The event() function is this driver's Card Services event handler. | ||
75 | It will be called by Card Services when an appropriate card status | ||
76 | event is received. The config() and release() entry points are | ||
77 | used to configure or release a socket, in response to card | ||
78 | insertion and ejection events. They are invoked from the airo_cs | ||
79 | event handler. | ||
80 | */ | ||
81 | |||
82 | struct net_device *init_airo_card( int, int, int, struct device * ); | ||
83 | void stop_airo_card( struct net_device *, int ); | ||
84 | int reset_airo_card( struct net_device * ); | ||
85 | |||
86 | static void airo_config(dev_link_t *link); | ||
87 | static void airo_release(dev_link_t *link); | ||
88 | static int airo_event(event_t event, int priority, | ||
89 | event_callback_args_t *args); | ||
90 | |||
91 | /* | ||
92 | The attach() and detach() entry points are used to create and destroy | ||
93 | "instances" of the driver, where each instance represents everything | ||
94 | needed to manage one actual PCMCIA card. | ||
95 | */ | ||
96 | |||
97 | static dev_link_t *airo_attach(void); | ||
98 | static void airo_detach(dev_link_t *); | ||
99 | |||
100 | /* | ||
101 | You'll also need to prototype all the functions that will actually | ||
102 | be used to talk to your device. See 'pcmem_cs' for a good example | ||
103 | of a fully self-sufficient driver; the other drivers rely more or | ||
104 | less on other parts of the kernel. | ||
105 | */ | ||
106 | |||
107 | /* | ||
108 | The dev_info variable is the "key" that is used to match up this | ||
109 | device driver with appropriate cards, through the card configuration | ||
110 | database. | ||
111 | */ | ||
112 | |||
113 | static dev_info_t dev_info = "airo_cs"; | ||
114 | |||
115 | /* | ||
116 | A linked list of "instances" of the aironet device. Each actual | ||
117 | PCMCIA card corresponds to one device instance, and is described | ||
118 | by one dev_link_t structure (defined in ds.h). | ||
119 | |||
120 | You may not want to use a linked list for this -- for example, the | ||
121 | memory card driver uses an array of dev_link_t pointers, where minor | ||
122 | device numbers are used to derive the corresponding array index. | ||
123 | */ | ||
124 | |||
125 | static dev_link_t *dev_list = NULL; | ||
126 | |||
127 | /* | ||
128 | A dev_link_t structure has fields for most things that are needed | ||
129 | to keep track of a socket, but there will usually be some device | ||
130 | specific information that also needs to be kept track of. The | ||
131 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
132 | a device-specific private data structure, like this. | ||
133 | |||
134 | A driver needs to provide a dev_node_t structure for each device | ||
135 | on a card. In some cases, there is only one device per card (for | ||
136 | example, ethernet cards, modems). In other cases, there may be | ||
137 | many actual or logical devices (SCSI adapters, memory cards with | ||
138 | multiple partitions). The dev_node_t structures need to be kept | ||
139 | in a linked list starting at the 'dev' field of a dev_link_t | ||
140 | structure. We allocate them in the card's private data structure, | ||
141 | because they generally shouldn't be allocated dynamically. | ||
142 | |||
143 | In this case, we also provide a flag to indicate if a device is | ||
144 | "stopped" due to a power management event, or card ejection. The | ||
145 | device IO routines can use a flag like this to throttle IO to a | ||
146 | card that is not ready to accept it. | ||
147 | */ | ||
148 | |||
149 | typedef struct local_info_t { | ||
150 | dev_node_t node; | ||
151 | struct net_device *eth_dev; | ||
152 | } local_info_t; | ||
153 | |||
154 | /*====================================================================== | ||
155 | |||
156 | airo_attach() creates an "instance" of the driver, allocating | ||
157 | local data structures for one device. The device is registered | ||
158 | with Card Services. | ||
159 | |||
160 | The dev_link structure is initialized, but we don't actually | ||
161 | configure the card at this point -- we wait until we receive a | ||
162 | card insertion event. | ||
163 | |||
164 | ======================================================================*/ | ||
165 | |||
166 | static dev_link_t *airo_attach(void) | ||
167 | { | ||
168 | client_reg_t client_reg; | ||
169 | dev_link_t *link; | ||
170 | local_info_t *local; | ||
171 | int ret; | ||
172 | |||
173 | DEBUG(0, "airo_attach()\n"); | ||
174 | |||
175 | /* Initialize the dev_link_t structure */ | ||
176 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
177 | if (!link) { | ||
178 | printk(KERN_ERR "airo_cs: no memory for new device\n"); | ||
179 | return NULL; | ||
180 | } | ||
181 | memset(link, 0, sizeof(struct dev_link_t)); | ||
182 | |||
183 | /* Interrupt setup */ | ||
184 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; | ||
185 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
186 | link->irq.Handler = NULL; | ||
187 | |||
188 | /* | ||
189 | General socket configuration defaults can go here. In this | ||
190 | client, we assume very little, and rely on the CIS for almost | ||
191 | everything. In most clients, many details (i.e., number, sizes, | ||
192 | and attributes of IO windows) are fixed by the nature of the | ||
193 | device, and can be hard-wired here. | ||
194 | */ | ||
195 | link->conf.Attributes = 0; | ||
196 | link->conf.Vcc = 50; | ||
197 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
198 | |||
199 | /* Allocate space for private device-specific data */ | ||
200 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | ||
201 | if (!local) { | ||
202 | printk(KERN_ERR "airo_cs: no memory for new device\n"); | ||
203 | kfree (link); | ||
204 | return NULL; | ||
205 | } | ||
206 | memset(local, 0, sizeof(local_info_t)); | ||
207 | link->priv = local; | ||
208 | |||
209 | /* Register with Card Services */ | ||
210 | link->next = dev_list; | ||
211 | dev_list = link; | ||
212 | client_reg.dev_info = &dev_info; | ||
213 | client_reg.EventMask = | ||
214 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
215 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
216 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
217 | client_reg.event_handler = &airo_event; | ||
218 | client_reg.Version = 0x0210; | ||
219 | client_reg.event_callback_args.client_data = link; | ||
220 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
221 | if (ret != 0) { | ||
222 | cs_error(link->handle, RegisterClient, ret); | ||
223 | airo_detach(link); | ||
224 | return NULL; | ||
225 | } | ||
226 | |||
227 | return link; | ||
228 | } /* airo_attach */ | ||
229 | |||
230 | /*====================================================================== | ||
231 | |||
232 | This deletes a driver "instance". The device is de-registered | ||
233 | with Card Services. If it has been released, all local data | ||
234 | structures are freed. Otherwise, the structures will be freed | ||
235 | when the device is released. | ||
236 | |||
237 | ======================================================================*/ | ||
238 | |||
239 | static void airo_detach(dev_link_t *link) | ||
240 | { | ||
241 | dev_link_t **linkp; | ||
242 | |||
243 | DEBUG(0, "airo_detach(0x%p)\n", link); | ||
244 | |||
245 | /* Locate device structure */ | ||
246 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
247 | if (*linkp == link) break; | ||
248 | if (*linkp == NULL) | ||
249 | return; | ||
250 | |||
251 | if (link->state & DEV_CONFIG) | ||
252 | airo_release(link); | ||
253 | |||
254 | if ( ((local_info_t*)link->priv)->eth_dev ) { | ||
255 | stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); | ||
256 | } | ||
257 | ((local_info_t*)link->priv)->eth_dev = NULL; | ||
258 | |||
259 | /* Break the link with Card Services */ | ||
260 | if (link->handle) | ||
261 | pcmcia_deregister_client(link->handle); | ||
262 | |||
263 | |||
264 | |||
265 | /* Unlink device structure, free pieces */ | ||
266 | *linkp = link->next; | ||
267 | if (link->priv) { | ||
268 | kfree(link->priv); | ||
269 | } | ||
270 | kfree(link); | ||
271 | |||
272 | } /* airo_detach */ | ||
273 | |||
274 | /*====================================================================== | ||
275 | |||
276 | airo_config() is scheduled to run after a CARD_INSERTION event | ||
277 | is received, to configure the PCMCIA socket, and to make the | ||
278 | device available to the system. | ||
279 | |||
280 | ======================================================================*/ | ||
281 | |||
282 | #define CS_CHECK(fn, ret) \ | ||
283 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
284 | |||
285 | static void airo_config(dev_link_t *link) | ||
286 | { | ||
287 | client_handle_t handle; | ||
288 | tuple_t tuple; | ||
289 | cisparse_t parse; | ||
290 | local_info_t *dev; | ||
291 | int last_fn, last_ret; | ||
292 | u_char buf[64]; | ||
293 | win_req_t req; | ||
294 | memreq_t map; | ||
295 | |||
296 | handle = link->handle; | ||
297 | dev = link->priv; | ||
298 | |||
299 | DEBUG(0, "airo_config(0x%p)\n", link); | ||
300 | |||
301 | /* | ||
302 | This reads the card's CONFIG tuple to find its configuration | ||
303 | registers. | ||
304 | */ | ||
305 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
306 | tuple.Attributes = 0; | ||
307 | tuple.TupleData = buf; | ||
308 | tuple.TupleDataMax = sizeof(buf); | ||
309 | tuple.TupleOffset = 0; | ||
310 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
311 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
312 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
313 | link->conf.ConfigBase = parse.config.base; | ||
314 | link->conf.Present = parse.config.rmask[0]; | ||
315 | |||
316 | /* Configure card */ | ||
317 | link->state |= DEV_CONFIG; | ||
318 | |||
319 | /* | ||
320 | In this loop, we scan the CIS for configuration table entries, | ||
321 | each of which describes a valid card configuration, including | ||
322 | voltage, IO window, memory window, and interrupt settings. | ||
323 | |||
324 | We make no assumptions about the card to be configured: we use | ||
325 | just the information available in the CIS. In an ideal world, | ||
326 | this would work for any PCMCIA card, but it requires a complete | ||
327 | and accurate CIS. In practice, a driver usually "knows" most of | ||
328 | these things without consulting the CIS, and most client drivers | ||
329 | will only use the CIS to fill in implementation-defined details. | ||
330 | */ | ||
331 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
332 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
333 | while (1) { | ||
334 | cistpl_cftable_entry_t dflt = { 0 }; | ||
335 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
336 | if (pcmcia_get_tuple_data(handle, &tuple) != 0 || | ||
337 | pcmcia_parse_tuple(handle, &tuple, &parse) != 0) | ||
338 | goto next_entry; | ||
339 | |||
340 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; | ||
341 | if (cfg->index == 0) goto next_entry; | ||
342 | link->conf.ConfigIndex = cfg->index; | ||
343 | |||
344 | /* Does this card need audio output? */ | ||
345 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
346 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
347 | link->conf.Status = CCSR_AUDIO_ENA; | ||
348 | } | ||
349 | |||
350 | /* Use power settings for Vcc and Vpp if present */ | ||
351 | /* Note that the CIS values need to be rescaled */ | ||
352 | if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) | ||
353 | link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; | ||
354 | else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) | ||
355 | link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; | ||
356 | |||
357 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
358 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
359 | cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
360 | else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
361 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
362 | dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
363 | |||
364 | /* Do we need to allocate an interrupt? */ | ||
365 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
366 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
367 | |||
368 | /* IO window settings */ | ||
369 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
370 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
371 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
372 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
373 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
374 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
375 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
376 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
377 | link->io.BasePort1 = io->win[0].base; | ||
378 | link->io.NumPorts1 = io->win[0].len; | ||
379 | if (io->nwin > 1) { | ||
380 | link->io.Attributes2 = link->io.Attributes1; | ||
381 | link->io.BasePort2 = io->win[1].base; | ||
382 | link->io.NumPorts2 = io->win[1].len; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /* This reserves IO space but doesn't actually enable it */ | ||
387 | if (pcmcia_request_io(link->handle, &link->io) != 0) | ||
388 | goto next_entry; | ||
389 | |||
390 | /* | ||
391 | Now set up a common memory window, if needed. There is room | ||
392 | in the dev_link_t structure for one memory window handle, | ||
393 | but if the base addresses need to be saved, or if multiple | ||
394 | windows are needed, the info should go in the private data | ||
395 | structure for this device. | ||
396 | |||
397 | Note that the memory window base is a physical address, and | ||
398 | needs to be mapped to virtual space with ioremap() before it | ||
399 | is used. | ||
400 | */ | ||
401 | if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { | ||
402 | cistpl_mem_t *mem = | ||
403 | (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; | ||
404 | req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; | ||
405 | req.Base = mem->win[0].host_addr; | ||
406 | req.Size = mem->win[0].len; | ||
407 | req.AccessSpeed = 0; | ||
408 | if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) | ||
409 | goto next_entry; | ||
410 | map.Page = 0; map.CardOffset = mem->win[0].card_addr; | ||
411 | if (pcmcia_map_mem_page(link->win, &map) != 0) | ||
412 | goto next_entry; | ||
413 | } | ||
414 | /* If we got this far, we're cool! */ | ||
415 | break; | ||
416 | |||
417 | next_entry: | ||
418 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | Allocate an interrupt line. Note that this does not assign a | ||
423 | handler to the interrupt, unless the 'Handler' member of the | ||
424 | irq structure is initialized. | ||
425 | */ | ||
426 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
427 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
428 | |||
429 | /* | ||
430 | This actually configures the PCMCIA socket -- setting up | ||
431 | the I/O windows and the interrupt mapping, and putting the | ||
432 | card and host interface into "Memory and IO" mode. | ||
433 | */ | ||
434 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
435 | ((local_info_t*)link->priv)->eth_dev = | ||
436 | init_airo_card( link->irq.AssignedIRQ, | ||
437 | link->io.BasePort1, 1, &handle_to_dev(handle) ); | ||
438 | if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; | ||
439 | |||
440 | /* | ||
441 | At this point, the dev_node_t structure(s) need to be | ||
442 | initialized and arranged in a linked list at link->dev. | ||
443 | */ | ||
444 | strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); | ||
445 | dev->node.major = dev->node.minor = 0; | ||
446 | link->dev = &dev->node; | ||
447 | |||
448 | /* Finally, report what we've done */ | ||
449 | printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", | ||
450 | dev->node.dev_name, link->conf.ConfigIndex, | ||
451 | link->conf.Vcc/10, link->conf.Vcc%10); | ||
452 | if (link->conf.Vpp1) | ||
453 | printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); | ||
454 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
455 | printk(", irq %d", link->irq.AssignedIRQ); | ||
456 | if (link->io.NumPorts1) | ||
457 | printk(", io 0x%04x-0x%04x", link->io.BasePort1, | ||
458 | link->io.BasePort1+link->io.NumPorts1-1); | ||
459 | if (link->io.NumPorts2) | ||
460 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | ||
461 | link->io.BasePort2+link->io.NumPorts2-1); | ||
462 | if (link->win) | ||
463 | printk(", mem 0x%06lx-0x%06lx", req.Base, | ||
464 | req.Base+req.Size-1); | ||
465 | printk("\n"); | ||
466 | |||
467 | link->state &= ~DEV_CONFIG_PENDING; | ||
468 | return; | ||
469 | |||
470 | cs_failed: | ||
471 | cs_error(link->handle, last_fn, last_ret); | ||
472 | airo_release(link); | ||
473 | |||
474 | } /* airo_config */ | ||
475 | |||
476 | /*====================================================================== | ||
477 | |||
478 | After a card is removed, airo_release() will unregister the | ||
479 | device, and release the PCMCIA configuration. If the device is | ||
480 | still open, this will be postponed until it is closed. | ||
481 | |||
482 | ======================================================================*/ | ||
483 | |||
484 | static void airo_release(dev_link_t *link) | ||
485 | { | ||
486 | DEBUG(0, "airo_release(0x%p)\n", link); | ||
487 | |||
488 | /* Unlink the device chain */ | ||
489 | link->dev = NULL; | ||
490 | |||
491 | /* | ||
492 | In a normal driver, additional code may be needed to release | ||
493 | other kernel data structures associated with this device. | ||
494 | */ | ||
495 | |||
496 | /* Don't bother checking to see if these succeed or not */ | ||
497 | if (link->win) | ||
498 | pcmcia_release_window(link->win); | ||
499 | pcmcia_release_configuration(link->handle); | ||
500 | if (link->io.NumPorts1) | ||
501 | pcmcia_release_io(link->handle, &link->io); | ||
502 | if (link->irq.AssignedIRQ) | ||
503 | pcmcia_release_irq(link->handle, &link->irq); | ||
504 | link->state &= ~DEV_CONFIG; | ||
505 | } | ||
506 | |||
507 | /*====================================================================== | ||
508 | |||
509 | The card status event handler. Mostly, this schedules other | ||
510 | stuff to run after an event is received. | ||
511 | |||
512 | When a CARD_REMOVAL event is received, we immediately set a | ||
513 | private flag to block future accesses to this device. All the | ||
514 | functions that actually access the device should check this flag | ||
515 | to make sure the card is still present. | ||
516 | |||
517 | ======================================================================*/ | ||
518 | |||
519 | static int airo_event(event_t event, int priority, | ||
520 | event_callback_args_t *args) | ||
521 | { | ||
522 | dev_link_t *link = args->client_data; | ||
523 | local_info_t *local = link->priv; | ||
524 | |||
525 | DEBUG(1, "airo_event(0x%06x)\n", event); | ||
526 | |||
527 | switch (event) { | ||
528 | case CS_EVENT_CARD_REMOVAL: | ||
529 | link->state &= ~DEV_PRESENT; | ||
530 | if (link->state & DEV_CONFIG) { | ||
531 | netif_device_detach(local->eth_dev); | ||
532 | airo_release(link); | ||
533 | } | ||
534 | break; | ||
535 | case CS_EVENT_CARD_INSERTION: | ||
536 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
537 | airo_config(link); | ||
538 | break; | ||
539 | case CS_EVENT_PM_SUSPEND: | ||
540 | link->state |= DEV_SUSPEND; | ||
541 | /* Fall through... */ | ||
542 | case CS_EVENT_RESET_PHYSICAL: | ||
543 | if (link->state & DEV_CONFIG) { | ||
544 | netif_device_detach(local->eth_dev); | ||
545 | pcmcia_release_configuration(link->handle); | ||
546 | } | ||
547 | break; | ||
548 | case CS_EVENT_PM_RESUME: | ||
549 | link->state &= ~DEV_SUSPEND; | ||
550 | /* Fall through... */ | ||
551 | case CS_EVENT_CARD_RESET: | ||
552 | if (link->state & DEV_CONFIG) { | ||
553 | pcmcia_request_configuration(link->handle, &link->conf); | ||
554 | reset_airo_card(local->eth_dev); | ||
555 | netif_device_attach(local->eth_dev); | ||
556 | } | ||
557 | break; | ||
558 | } | ||
559 | return 0; | ||
560 | } /* airo_event */ | ||
561 | |||
562 | static struct pcmcia_driver airo_driver = { | ||
563 | .owner = THIS_MODULE, | ||
564 | .drv = { | ||
565 | .name = "airo_cs", | ||
566 | }, | ||
567 | .attach = airo_attach, | ||
568 | .detach = airo_detach, | ||
569 | }; | ||
570 | |||
571 | static int airo_cs_init(void) | ||
572 | { | ||
573 | return pcmcia_register_driver(&airo_driver); | ||
574 | } | ||
575 | |||
576 | static void airo_cs_cleanup(void) | ||
577 | { | ||
578 | pcmcia_unregister_driver(&airo_driver); | ||
579 | BUG_ON(dev_list != NULL); | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | This program is free software; you can redistribute it and/or | ||
584 | modify it under the terms of the GNU General Public License | ||
585 | as published by the Free Software Foundation; either version 2 | ||
586 | of the License, or (at your option) any later version. | ||
587 | |||
588 | This program is distributed in the hope that it will be useful, | ||
589 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
590 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
591 | GNU General Public License for more details. | ||
592 | |||
593 | In addition: | ||
594 | |||
595 | Redistribution and use in source and binary forms, with or without | ||
596 | modification, are permitted provided that the following conditions | ||
597 | are met: | ||
598 | |||
599 | 1. Redistributions of source code must retain the above copyright | ||
600 | notice, this list of conditions and the following disclaimer. | ||
601 | 2. Redistributions in binary form must reproduce the above copyright | ||
602 | notice, this list of conditions and the following disclaimer in the | ||
603 | documentation and/or other materials provided with the distribution. | ||
604 | 3. The name of the author may not be used to endorse or promote | ||
605 | products derived from this software without specific prior written | ||
606 | permission. | ||
607 | |||
608 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
609 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
610 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
611 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | ||
612 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
613 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
614 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
615 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
616 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
617 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
618 | POSSIBILITY OF SUCH DAMAGE. | ||
619 | */ | ||
620 | |||
621 | module_init(airo_cs_init); | ||
622 | module_exit(airo_cs_cleanup); | ||
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c new file mode 100644 index 000000000000..a1dc2a196087 --- /dev/null +++ b/drivers/net/wireless/airport.c | |||
@@ -0,0 +1,304 @@ | |||
1 | /* airport.c | ||
2 | * | ||
3 | * A driver for "Hermes" chipset based Apple Airport wireless | ||
4 | * card. | ||
5 | * | ||
6 | * Copyright notice & release notes in file orinoco.c | ||
7 | * | ||
8 | * Note specific to airport stub: | ||
9 | * | ||
10 | * 0.05 : first version of the new split driver | ||
11 | * 0.06 : fix possible hang on powerup, add sleep support | ||
12 | */ | ||
13 | |||
14 | #define DRIVER_NAME "airport" | ||
15 | #define PFX DRIVER_NAME ": " | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/ptrace.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/if_arp.h> | ||
29 | #include <linux/etherdevice.h> | ||
30 | #include <linux/wireless.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/system.h> | ||
34 | #include <asm/current.h> | ||
35 | #include <asm/prom.h> | ||
36 | #include <asm/machdep.h> | ||
37 | #include <asm/pmac_feature.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #include "orinoco.h" | ||
42 | |||
43 | #define AIRPORT_IO_LEN (0x1000) /* one page */ | ||
44 | |||
45 | struct airport { | ||
46 | struct macio_dev *mdev; | ||
47 | void __iomem *vaddr; | ||
48 | int irq_requested; | ||
49 | int ndev_registered; | ||
50 | }; | ||
51 | |||
52 | static int | ||
53 | airport_suspend(struct macio_dev *mdev, u32 state) | ||
54 | { | ||
55 | struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); | ||
56 | struct orinoco_private *priv = netdev_priv(dev); | ||
57 | unsigned long flags; | ||
58 | int err; | ||
59 | |||
60 | printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); | ||
61 | |||
62 | err = orinoco_lock(priv, &flags); | ||
63 | if (err) { | ||
64 | printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", | ||
65 | dev->name); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | err = __orinoco_down(dev); | ||
70 | if (err) | ||
71 | printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", | ||
72 | dev->name, err); | ||
73 | |||
74 | netif_device_detach(dev); | ||
75 | |||
76 | priv->hw_unavailable++; | ||
77 | |||
78 | orinoco_unlock(priv, &flags); | ||
79 | |||
80 | disable_irq(dev->irq); | ||
81 | pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | airport_resume(struct macio_dev *mdev) | ||
88 | { | ||
89 | struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); | ||
90 | struct orinoco_private *priv = netdev_priv(dev); | ||
91 | unsigned long flags; | ||
92 | int err; | ||
93 | |||
94 | printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); | ||
95 | |||
96 | pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); | ||
97 | msleep(200); | ||
98 | |||
99 | enable_irq(dev->irq); | ||
100 | |||
101 | err = orinoco_reinit_firmware(dev); | ||
102 | if (err) { | ||
103 | printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", | ||
104 | dev->name, err); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | spin_lock_irqsave(&priv->lock, flags); | ||
109 | |||
110 | netif_device_attach(dev); | ||
111 | |||
112 | priv->hw_unavailable--; | ||
113 | |||
114 | if (priv->open && (! priv->hw_unavailable)) { | ||
115 | err = __orinoco_up(dev); | ||
116 | if (err) | ||
117 | printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", | ||
118 | dev->name, err); | ||
119 | } | ||
120 | |||
121 | |||
122 | spin_unlock_irqrestore(&priv->lock, flags); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int | ||
128 | airport_detach(struct macio_dev *mdev) | ||
129 | { | ||
130 | struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); | ||
131 | struct orinoco_private *priv = netdev_priv(dev); | ||
132 | struct airport *card = priv->card; | ||
133 | |||
134 | if (card->ndev_registered) | ||
135 | unregister_netdev(dev); | ||
136 | card->ndev_registered = 0; | ||
137 | |||
138 | if (card->irq_requested) | ||
139 | free_irq(dev->irq, dev); | ||
140 | card->irq_requested = 0; | ||
141 | |||
142 | if (card->vaddr) | ||
143 | iounmap(card->vaddr); | ||
144 | card->vaddr = NULL; | ||
145 | |||
146 | macio_release_resource(mdev, 0); | ||
147 | |||
148 | pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); | ||
149 | ssleep(1); | ||
150 | |||
151 | macio_set_drvdata(mdev, NULL); | ||
152 | free_orinocodev(dev); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int airport_hard_reset(struct orinoco_private *priv) | ||
158 | { | ||
159 | /* It would be nice to power cycle the Airport for a real hard | ||
160 | * reset, but for some reason although it appears to | ||
161 | * re-initialize properly, it falls in a screaming heap | ||
162 | * shortly afterwards. */ | ||
163 | #if 0 | ||
164 | struct net_device *dev = priv->ndev; | ||
165 | struct airport *card = priv->card; | ||
166 | |||
167 | /* Vitally important. If we don't do this it seems we get an | ||
168 | * interrupt somewhere during the power cycle, since | ||
169 | * hw_unavailable is already set it doesn't get ACKed, we get | ||
170 | * into an interrupt loop and the the PMU decides to turn us | ||
171 | * off. */ | ||
172 | disable_irq(dev->irq); | ||
173 | |||
174 | pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); | ||
175 | ssleep(1); | ||
176 | pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1); | ||
177 | ssleep(1); | ||
178 | |||
179 | enable_irq(dev->irq); | ||
180 | ssleep(1); | ||
181 | #endif | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int | ||
187 | airport_attach(struct macio_dev *mdev, const struct of_match *match) | ||
188 | { | ||
189 | struct orinoco_private *priv; | ||
190 | struct net_device *dev; | ||
191 | struct airport *card; | ||
192 | unsigned long phys_addr; | ||
193 | hermes_t *hw; | ||
194 | |||
195 | if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { | ||
196 | printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | /* Allocate space for private device-specific data */ | ||
201 | dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); | ||
202 | if (! dev) { | ||
203 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | ||
204 | return -ENODEV; | ||
205 | } | ||
206 | priv = netdev_priv(dev); | ||
207 | card = priv->card; | ||
208 | |||
209 | hw = &priv->hw; | ||
210 | card->mdev = mdev; | ||
211 | |||
212 | if (macio_request_resource(mdev, 0, "airport")) { | ||
213 | printk(KERN_ERR PFX "can't request IO resource !\n"); | ||
214 | free_orinocodev(dev); | ||
215 | return -EBUSY; | ||
216 | } | ||
217 | |||
218 | SET_MODULE_OWNER(dev); | ||
219 | SET_NETDEV_DEV(dev, &mdev->ofdev.dev); | ||
220 | |||
221 | macio_set_drvdata(mdev, dev); | ||
222 | |||
223 | /* Setup interrupts & base address */ | ||
224 | dev->irq = macio_irq(mdev, 0); | ||
225 | phys_addr = macio_resource_start(mdev, 0); /* Physical address */ | ||
226 | printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); | ||
227 | dev->base_addr = phys_addr; | ||
228 | card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); | ||
229 | if (!card->vaddr) { | ||
230 | printk(KERN_ERR PFX "ioremap() failed\n"); | ||
231 | goto failed; | ||
232 | } | ||
233 | |||
234 | hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); | ||
235 | |||
236 | /* Power up card */ | ||
237 | pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); | ||
238 | ssleep(1); | ||
239 | |||
240 | /* Reset it before we get the interrupt */ | ||
241 | hermes_init(hw); | ||
242 | |||
243 | if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) { | ||
244 | printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); | ||
245 | goto failed; | ||
246 | } | ||
247 | card->irq_requested = 1; | ||
248 | |||
249 | /* Tell the stack we exist */ | ||
250 | if (register_netdev(dev) != 0) { | ||
251 | printk(KERN_ERR PFX "register_netdev() failed\n"); | ||
252 | goto failed; | ||
253 | } | ||
254 | printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name); | ||
255 | card->ndev_registered = 1; | ||
256 | return 0; | ||
257 | failed: | ||
258 | airport_detach(mdev); | ||
259 | return -ENODEV; | ||
260 | } /* airport_attach */ | ||
261 | |||
262 | |||
263 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
264 | " (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; | ||
265 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
266 | MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); | ||
267 | MODULE_LICENSE("Dual MPL/GPL"); | ||
268 | |||
269 | static struct of_match airport_match[] = | ||
270 | { | ||
271 | { | ||
272 | .name = "radio", | ||
273 | .type = OF_ANY_MATCH, | ||
274 | .compatible = OF_ANY_MATCH | ||
275 | }, | ||
276 | {}, | ||
277 | }; | ||
278 | |||
279 | static struct macio_driver airport_driver = | ||
280 | { | ||
281 | .name = DRIVER_NAME, | ||
282 | .match_table = airport_match, | ||
283 | .probe = airport_attach, | ||
284 | .remove = airport_detach, | ||
285 | .suspend = airport_suspend, | ||
286 | .resume = airport_resume, | ||
287 | }; | ||
288 | |||
289 | static int __init | ||
290 | init_airport(void) | ||
291 | { | ||
292 | printk(KERN_DEBUG "%s\n", version); | ||
293 | |||
294 | return macio_register_driver(&airport_driver); | ||
295 | } | ||
296 | |||
297 | static void __exit | ||
298 | exit_airport(void) | ||
299 | { | ||
300 | return macio_unregister_driver(&airport_driver); | ||
301 | } | ||
302 | |||
303 | module_init(init_airport); | ||
304 | module_exit(exit_airport); | ||
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c new file mode 100644 index 000000000000..4f304c6e693a --- /dev/null +++ b/drivers/net/wireless/arlan-main.c | |||
@@ -0,0 +1,1896 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Cullen Jennings | ||
3 | * Copyright (C) 1998 Elmer Joandiu, elmer@ylenurme.ee | ||
4 | * GNU General Public License applies | ||
5 | * This module provides support for the Arlan 655 card made by Aironet | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include "arlan.h" | ||
10 | |||
11 | #if BITS_PER_LONG != 32 | ||
12 | # error FIXME: this driver requires a 32-bit platform | ||
13 | #endif | ||
14 | |||
15 | static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; | ||
16 | |||
17 | struct net_device *arlan_device[MAX_ARLANS]; | ||
18 | |||
19 | static int SID = SIDUNKNOWN; | ||
20 | static int radioNodeId = radioNodeIdUNKNOWN; | ||
21 | static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; | ||
22 | int arlan_debug = debugUNKNOWN; | ||
23 | static int spreadingCode = spreadingCodeUNKNOWN; | ||
24 | static int channelNumber = channelNumberUNKNOWN; | ||
25 | static int channelSet = channelSetUNKNOWN; | ||
26 | static int systemId = systemIdUNKNOWN; | ||
27 | static int registrationMode = registrationModeUNKNOWN; | ||
28 | static int keyStart; | ||
29 | static int tx_delay_ms; | ||
30 | static int retries = 5; | ||
31 | static int tx_queue_len = 1; | ||
32 | static int arlan_EEPROM_bad; | ||
33 | |||
34 | #ifdef ARLAN_DEBUGGING | ||
35 | |||
36 | static int arlan_entry_debug; | ||
37 | static int arlan_exit_debug; | ||
38 | static int testMemory = testMemoryUNKNOWN; | ||
39 | static int irq = irqUNKNOWN; | ||
40 | static int txScrambled = 1; | ||
41 | static int mdebug; | ||
42 | |||
43 | module_param(irq, int, 0); | ||
44 | module_param(mdebug, int, 0); | ||
45 | module_param(testMemory, int, 0); | ||
46 | module_param(arlan_entry_debug, int, 0); | ||
47 | module_param(arlan_exit_debug, int, 0); | ||
48 | module_param(txScrambled, int, 0); | ||
49 | MODULE_PARM_DESC(irq, "(unused)"); | ||
50 | MODULE_PARM_DESC(testMemory, "(unused)"); | ||
51 | MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)"); | ||
52 | #endif | ||
53 | |||
54 | module_param(arlan_debug, int, 0); | ||
55 | module_param(spreadingCode, int, 0); | ||
56 | module_param(channelNumber, int, 0); | ||
57 | module_param(channelSet, int, 0); | ||
58 | module_param(systemId, int, 0); | ||
59 | module_param(registrationMode, int, 0); | ||
60 | module_param(radioNodeId, int, 0); | ||
61 | module_param(SID, int, 0); | ||
62 | module_param(keyStart, int, 0); | ||
63 | module_param(tx_delay_ms, int, 0); | ||
64 | module_param(retries, int, 0); | ||
65 | module_param(tx_queue_len, int, 0); | ||
66 | module_param(arlan_EEPROM_bad, int, 0); | ||
67 | MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)"); | ||
68 | MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions"); | ||
69 | #ifdef ARLAN_ENTRY_EXIT_DEBUGGING | ||
70 | MODULE_PARM_DESC(arlan_entry_debug, "Arlan driver function entry debugging"); | ||
71 | MODULE_PARM_DESC(arlan_exit_debug, "Arlan driver function exit debugging"); | ||
72 | MODULE_PARM_DESC(arlan_entry_and_exit_debug, "Arlan driver function entry and exit debugging"); | ||
73 | #else | ||
74 | MODULE_PARM_DESC(arlan_entry_debug, "(ignored)"); | ||
75 | MODULE_PARM_DESC(arlan_exit_debug, "(ignored)"); | ||
76 | MODULE_PARM_DESC(arlan_entry_and_exit_debug, "(ignored)"); | ||
77 | #endif | ||
78 | |||
79 | struct arlan_conf_stru arlan_conf[MAX_ARLANS]; | ||
80 | static int arlans_found; | ||
81 | |||
82 | static int arlan_open(struct net_device *dev); | ||
83 | static int arlan_tx(struct sk_buff *skb, struct net_device *dev); | ||
84 | static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
85 | static int arlan_close(struct net_device *dev); | ||
86 | static struct net_device_stats * | ||
87 | arlan_statistics (struct net_device *dev); | ||
88 | static void arlan_set_multicast (struct net_device *dev); | ||
89 | static int arlan_hw_tx (struct net_device* dev, char *buf, int length ); | ||
90 | static int arlan_hw_config (struct net_device * dev); | ||
91 | static void arlan_tx_done_interrupt (struct net_device * dev, int status); | ||
92 | static void arlan_rx_interrupt (struct net_device * dev, u_char rxStatus, u_short, u_short); | ||
93 | static void arlan_process_interrupt (struct net_device * dev); | ||
94 | static void arlan_tx_timeout (struct net_device *dev); | ||
95 | |||
96 | static inline long us2ticks(int us) | ||
97 | { | ||
98 | return us * (1000000 / HZ); | ||
99 | } | ||
100 | |||
101 | |||
102 | #ifdef ARLAN_ENTRY_EXIT_DEBUGGING | ||
103 | #define ARLAN_DEBUG_ENTRY(name) \ | ||
104 | {\ | ||
105 | struct timeval timev;\ | ||
106 | do_gettimeofday(&timev);\ | ||
107 | if (arlan_entry_debug || arlan_entry_and_exit_debug)\ | ||
108 | printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ | ||
109 | } | ||
110 | #define ARLAN_DEBUG_EXIT(name) \ | ||
111 | {\ | ||
112 | struct timeval timev;\ | ||
113 | do_gettimeofday(&timev);\ | ||
114 | if (arlan_exit_debug || arlan_entry_and_exit_debug)\ | ||
115 | printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ | ||
116 | } | ||
117 | #else | ||
118 | #define ARLAN_DEBUG_ENTRY(name) | ||
119 | #define ARLAN_DEBUG_EXIT(name) | ||
120 | #endif | ||
121 | |||
122 | |||
123 | #define arlan_interrupt_ack(dev)\ | ||
124 | clearClearInterrupt(dev);\ | ||
125 | setClearInterrupt(dev); | ||
126 | |||
127 | static inline int arlan_drop_tx(struct net_device *dev) | ||
128 | { | ||
129 | struct arlan_private *priv = netdev_priv(dev); | ||
130 | |||
131 | priv->stats.tx_errors++; | ||
132 | if (priv->Conf->tx_delay_ms) | ||
133 | { | ||
134 | priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; | ||
135 | } | ||
136 | else | ||
137 | { | ||
138 | priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; | ||
139 | TXHEAD(dev).offset = 0; | ||
140 | TXTAIL(dev).offset = 0; | ||
141 | priv->txLast = 0; | ||
142 | priv->bad = 0; | ||
143 | if (!priv->under_reset && !priv->under_config) | ||
144 | netif_wake_queue (dev); | ||
145 | } | ||
146 | return 1; | ||
147 | } | ||
148 | |||
149 | |||
150 | int arlan_command(struct net_device *dev, int command_p) | ||
151 | { | ||
152 | struct arlan_private *priv = netdev_priv(dev); | ||
153 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
154 | struct arlan_conf_stru *conf = priv->Conf; | ||
155 | int udelayed = 0; | ||
156 | int i = 0; | ||
157 | unsigned long flags; | ||
158 | |||
159 | ARLAN_DEBUG_ENTRY("arlan_command"); | ||
160 | |||
161 | if (priv->card_polling_interval) | ||
162 | priv->card_polling_interval = 1; | ||
163 | |||
164 | if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) | ||
165 | printk(KERN_DEBUG "arlan_command, %lx commandByte %x waiting %lx incoming %x \n", | ||
166 | jiffies, READSHMB(arlan->commandByte), | ||
167 | priv->waiting_command_mask, command_p); | ||
168 | |||
169 | priv->waiting_command_mask |= command_p; | ||
170 | |||
171 | if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) | ||
172 | if (time_after(jiffies, priv->lastReset + 5 * HZ)) | ||
173 | priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; | ||
174 | |||
175 | if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) | ||
176 | { | ||
177 | arlan_interrupt_ack(dev); | ||
178 | priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; | ||
179 | } | ||
180 | if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) | ||
181 | { | ||
182 | setInterruptEnable(dev); | ||
183 | priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; | ||
184 | } | ||
185 | |||
186 | /* Card access serializing lock */ | ||
187 | spin_lock_irqsave(&priv->lock, flags); | ||
188 | |||
189 | /* Check cards status and waiting */ | ||
190 | |||
191 | if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) | ||
192 | { | ||
193 | while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) | ||
194 | { | ||
195 | if (READSHMB(arlan->resetFlag) || | ||
196 | READSHMB(arlan->commandByte)) /* || | ||
197 | (readControlRegister(dev) & ARLAN_ACCESS)) | ||
198 | */ | ||
199 | udelay(40); | ||
200 | else | ||
201 | priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); | ||
202 | |||
203 | udelayed++; | ||
204 | |||
205 | if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) | ||
206 | { | ||
207 | if (udelayed * 40 > 1000000) | ||
208 | { | ||
209 | printk(KERN_ERR "%s long wait too long \n", dev->name); | ||
210 | priv->waiting_command_mask |= ARLAN_COMMAND_RESET; | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) | ||
215 | { | ||
216 | if (udelayed * 40 > 1000) | ||
217 | { | ||
218 | printk(KERN_ERR "%s short wait too long \n", dev->name); | ||
219 | goto bad_end; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | i = 0; | ||
227 | while ((READSHMB(arlan->resetFlag) || | ||
228 | READSHMB(arlan->commandByte)) && | ||
229 | conf->pre_Command_Wait > (i++) * 10) | ||
230 | udelay(10); | ||
231 | |||
232 | |||
233 | if ((READSHMB(arlan->resetFlag) || | ||
234 | READSHMB(arlan->commandByte)) && | ||
235 | !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) | ||
236 | { | ||
237 | goto card_busy_end; | ||
238 | } | ||
239 | } | ||
240 | if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) | ||
241 | priv->under_reset = 1; | ||
242 | if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) | ||
243 | priv->under_config = 1; | ||
244 | |||
245 | /* Issuing command */ | ||
246 | arlan_lock_card_access(dev); | ||
247 | if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) | ||
248 | { | ||
249 | // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) | ||
250 | setPowerOn(dev); | ||
251 | arlan_interrupt_lancpu(dev); | ||
252 | priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; | ||
253 | priv->waiting_command_mask |= ARLAN_COMMAND_RESET; | ||
254 | priv->card_polling_interval = HZ / 10; | ||
255 | } | ||
256 | else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) | ||
257 | { | ||
258 | WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); | ||
259 | arlan_interrupt_lancpu(dev); | ||
260 | priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; | ||
261 | priv->card_polling_interval = HZ / 10; | ||
262 | } | ||
263 | else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) | ||
264 | { | ||
265 | if (priv->rx_command_given) | ||
266 | { | ||
267 | WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); | ||
268 | arlan_interrupt_lancpu(dev); | ||
269 | priv->rx_command_given = 0; | ||
270 | } | ||
271 | priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; | ||
272 | priv->card_polling_interval = 1; | ||
273 | } | ||
274 | else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) | ||
275 | { | ||
276 | if (priv->tx_command_given) | ||
277 | { | ||
278 | WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); | ||
279 | arlan_interrupt_lancpu(dev); | ||
280 | priv->tx_command_given = 0; | ||
281 | } | ||
282 | priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; | ||
283 | priv->card_polling_interval = 1; | ||
284 | } | ||
285 | else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) | ||
286 | { | ||
287 | priv->under_reset=1; | ||
288 | netif_stop_queue (dev); | ||
289 | |||
290 | arlan_drop_tx(dev); | ||
291 | if (priv->tx_command_given || priv->rx_command_given) | ||
292 | { | ||
293 | printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); | ||
294 | } | ||
295 | netif_stop_queue (dev); | ||
296 | if (arlan_debug & ARLAN_DEBUG_RESET) | ||
297 | printk(KERN_ERR "%s: Doing chip reset\n", dev->name); | ||
298 | priv->lastReset = jiffies; | ||
299 | WRITESHM(arlan->commandByte, 0, u_char); | ||
300 | /* hold card in reset state */ | ||
301 | setHardwareReset(dev); | ||
302 | /* set reset flag and then release reset */ | ||
303 | WRITESHM(arlan->resetFlag, 0xff, u_char); | ||
304 | clearChannelAttention(dev); | ||
305 | clearHardwareReset(dev); | ||
306 | priv->card_polling_interval = HZ / 4; | ||
307 | priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; | ||
308 | priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; | ||
309 | // priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; | ||
310 | // priv->waiting_command_mask |= ARLAN_COMMAND_RX; | ||
311 | } | ||
312 | else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) | ||
313 | { | ||
314 | clearHardwareReset(dev); | ||
315 | clearClearInterrupt(dev); | ||
316 | setClearInterrupt(dev); | ||
317 | setInterruptEnable(dev); | ||
318 | priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; | ||
319 | priv->waiting_command_mask |= ARLAN_COMMAND_CONF; | ||
320 | priv->under_config = 1; | ||
321 | priv->under_reset = 0; | ||
322 | } | ||
323 | else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) | ||
324 | { | ||
325 | setInterruptEnable(dev); | ||
326 | priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; | ||
327 | } | ||
328 | else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) | ||
329 | { | ||
330 | if (priv->tx_command_given || priv->rx_command_given) | ||
331 | { | ||
332 | printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); | ||
333 | } | ||
334 | arlan_drop_tx(dev); | ||
335 | setInterruptEnable(dev); | ||
336 | arlan_hw_config(dev); | ||
337 | arlan_interrupt_lancpu(dev); | ||
338 | priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; | ||
339 | priv->card_polling_interval = HZ / 10; | ||
340 | // priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; | ||
341 | // priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; | ||
342 | priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; | ||
343 | } | ||
344 | else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) | ||
345 | { | ||
346 | if (READSHMB(arlan->configuredStatusFlag) != 0 && | ||
347 | READSHMB(arlan->diagnosticInfo) == 0xff) | ||
348 | { | ||
349 | priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; | ||
350 | priv->waiting_command_mask |= ARLAN_COMMAND_RX; | ||
351 | priv->waiting_command_mask |= ARLAN_COMMAND_TBUSY_CLEAR; | ||
352 | priv->card_polling_interval = HZ / 10; | ||
353 | priv->tx_command_given = 0; | ||
354 | priv->under_config = 0; | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | priv->card_polling_interval = 1; | ||
359 | if (arlan_debug & ARLAN_DEBUG_TIMING) | ||
360 | printk(KERN_ERR "configure delayed \n"); | ||
361 | } | ||
362 | } | ||
363 | else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) | ||
364 | { | ||
365 | if (!registrationBad(dev)) | ||
366 | { | ||
367 | setInterruptEnable(dev); | ||
368 | memset_io(arlan->commandParameter, 0, 0xf); | ||
369 | WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); | ||
370 | WRITESHMB(arlan->commandParameter[0], conf->rxParameter); | ||
371 | arlan_interrupt_lancpu(dev); | ||
372 | priv->rx_command_given = 0; // mnjah, bad | ||
373 | priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; | ||
374 | priv->card_polling_interval = 1; | ||
375 | } | ||
376 | else | ||
377 | priv->card_polling_interval = 2; | ||
378 | } | ||
379 | else if (priv->waiting_command_mask & ARLAN_COMMAND_TBUSY_CLEAR) | ||
380 | { | ||
381 | if ( !registrationBad(dev) && | ||
382 | (netif_queue_stopped(dev) || !netif_running(dev)) ) | ||
383 | { | ||
384 | priv->waiting_command_mask &= ~ARLAN_COMMAND_TBUSY_CLEAR; | ||
385 | netif_wake_queue (dev); | ||
386 | } | ||
387 | } | ||
388 | else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) | ||
389 | { | ||
390 | if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) | ||
391 | { | ||
392 | if (time_after(jiffies, | ||
393 | priv->tx_last_sent + us2ticks(conf->rx_tweak1)) | ||
394 | || time_before(jiffies, | ||
395 | priv->last_rx_int_ack_time + us2ticks(conf->rx_tweak2))) | ||
396 | { | ||
397 | setInterruptEnable(dev); | ||
398 | memset_io(arlan->commandParameter, 0, 0xf); | ||
399 | WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); | ||
400 | memcpy_toio(arlan->commandParameter, &TXLAST(dev), 14); | ||
401 | // for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); | ||
402 | priv->tx_last_sent = jiffies; | ||
403 | arlan_interrupt_lancpu(dev); | ||
404 | priv->tx_command_given = 1; | ||
405 | priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; | ||
406 | priv->card_polling_interval = 1; | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | priv->tx_command_given = 0; | ||
411 | priv->card_polling_interval = 1; | ||
412 | } | ||
413 | } | ||
414 | else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) | ||
415 | printk(KERN_ERR "tx command when tx chain locked \n"); | ||
416 | } | ||
417 | else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) | ||
418 | { | ||
419 | { | ||
420 | WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); | ||
421 | } | ||
422 | arlan_interrupt_lancpu(dev); | ||
423 | priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; | ||
424 | priv->card_polling_interval = HZ / 3; | ||
425 | } | ||
426 | else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) | ||
427 | { | ||
428 | WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); | ||
429 | arlan_interrupt_lancpu(dev); | ||
430 | priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; | ||
431 | priv->card_polling_interval = HZ / 3; | ||
432 | } | ||
433 | else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) | ||
434 | { | ||
435 | WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); | ||
436 | arlan_interrupt_lancpu(dev); | ||
437 | priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; | ||
438 | priv->card_polling_interval = HZ / 3; | ||
439 | } | ||
440 | else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) | ||
441 | { | ||
442 | setPowerOff(dev); | ||
443 | if (arlan_debug & ARLAN_DEBUG_CARD_STATE) | ||
444 | printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); | ||
445 | priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; | ||
446 | priv->card_polling_interval = 3 * HZ; | ||
447 | } | ||
448 | arlan_unlock_card_access(dev); | ||
449 | for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) | ||
450 | udelay(10); | ||
451 | if (READSHMB(arlan->commandByte)) | ||
452 | if (arlan_debug & ARLAN_DEBUG_CARD_STATE) | ||
453 | printk(KERN_ERR "card busy leaving command %lx\n", priv->waiting_command_mask); | ||
454 | |||
455 | spin_unlock_irqrestore(&priv->lock, flags); | ||
456 | ARLAN_DEBUG_EXIT("arlan_command"); | ||
457 | priv->last_command_buff_free_time = jiffies; | ||
458 | return 0; | ||
459 | |||
460 | card_busy_end: | ||
461 | if (time_after(jiffies, priv->last_command_buff_free_time + HZ)) | ||
462 | priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET; | ||
463 | |||
464 | if (arlan_debug & ARLAN_DEBUG_CARD_STATE) | ||
465 | printk(KERN_ERR "%s arlan_command card busy end \n", dev->name); | ||
466 | spin_unlock_irqrestore(&priv->lock, flags); | ||
467 | ARLAN_DEBUG_EXIT("arlan_command"); | ||
468 | return 1; | ||
469 | |||
470 | bad_end: | ||
471 | printk(KERN_ERR "%s arlan_command bad end \n", dev->name); | ||
472 | |||
473 | spin_unlock_irqrestore(&priv->lock, flags); | ||
474 | ARLAN_DEBUG_EXIT("arlan_command"); | ||
475 | |||
476 | return -1; | ||
477 | } | ||
478 | |||
479 | static inline void arlan_command_process(struct net_device *dev) | ||
480 | { | ||
481 | struct arlan_private *priv = netdev_priv(dev); | ||
482 | |||
483 | int times = 0; | ||
484 | while (priv->waiting_command_mask && times < 8) | ||
485 | { | ||
486 | if (priv->waiting_command_mask) | ||
487 | { | ||
488 | if (arlan_command(dev, 0)) | ||
489 | break; | ||
490 | times++; | ||
491 | } | ||
492 | /* if long command, we won't repeat trying */ ; | ||
493 | if (priv->card_polling_interval > 1) | ||
494 | break; | ||
495 | times++; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | |||
500 | static inline void arlan_retransmit_now(struct net_device *dev) | ||
501 | { | ||
502 | struct arlan_private *priv = netdev_priv(dev); | ||
503 | |||
504 | |||
505 | ARLAN_DEBUG_ENTRY("arlan_retransmit_now"); | ||
506 | if (TXLAST(dev).offset == 0) | ||
507 | { | ||
508 | if (TXHEAD(dev).offset) | ||
509 | { | ||
510 | priv->txLast = 0; | ||
511 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n"); | ||
512 | |||
513 | } | ||
514 | else if (TXTAIL(dev).offset) | ||
515 | { | ||
516 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n"); | ||
517 | priv->txLast = 1; | ||
518 | } | ||
519 | else | ||
520 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty"); | ||
521 | netif_wake_queue (dev); | ||
522 | return; | ||
523 | |||
524 | } | ||
525 | arlan_command(dev, ARLAN_COMMAND_TX); | ||
526 | |||
527 | priv->Conf->driverRetransmissions++; | ||
528 | priv->retransmissions++; | ||
529 | |||
530 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length); | ||
531 | |||
532 | ARLAN_DEBUG_EXIT("arlan_retransmit_now"); | ||
533 | } | ||
534 | |||
535 | |||
536 | |||
537 | static void arlan_registration_timer(unsigned long data) | ||
538 | { | ||
539 | struct net_device *dev = (struct net_device *) data; | ||
540 | struct arlan_private *priv = netdev_priv(dev); | ||
541 | int bh_mark_needed = 0; | ||
542 | int next_tick = 1; | ||
543 | long lostTime = ((long)jiffies - (long)priv->registrationLastSeen) | ||
544 | * (1000/HZ); | ||
545 | |||
546 | if (registrationBad(dev)) | ||
547 | { | ||
548 | priv->registrationLostCount++; | ||
549 | if (lostTime > 7000 && lostTime < 7200) | ||
550 | { | ||
551 | printk(KERN_NOTICE "%s registration Lost \n", dev->name); | ||
552 | } | ||
553 | if (lostTime / priv->reRegisterExp > 2000) | ||
554 | arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); | ||
555 | if (lostTime / (priv->reRegisterExp) > 3500) | ||
556 | arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); | ||
557 | if (priv->reRegisterExp < 400) | ||
558 | priv->reRegisterExp += 2; | ||
559 | if (lostTime > 7200) | ||
560 | { | ||
561 | next_tick = HZ; | ||
562 | arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); | ||
563 | } | ||
564 | } | ||
565 | else | ||
566 | { | ||
567 | if (priv->Conf->registrationMode && lostTime > 10000 && | ||
568 | priv->registrationLostCount) | ||
569 | { | ||
570 | printk(KERN_NOTICE "%s registration is back after %ld milliseconds\n", | ||
571 | dev->name, lostTime); | ||
572 | } | ||
573 | priv->registrationLastSeen = jiffies; | ||
574 | priv->registrationLostCount = 0; | ||
575 | priv->reRegisterExp = 1; | ||
576 | if (!netif_running(dev) ) | ||
577 | netif_wake_queue(dev); | ||
578 | if (time_after(priv->tx_last_sent,priv->tx_last_cleared) && | ||
579 | time_after(jiffies, priv->tx_last_sent * 5*HZ) ){ | ||
580 | arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); | ||
581 | priv->tx_last_cleared = jiffies; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | |||
586 | if (!registrationBad(dev) && priv->ReTransmitRequested) | ||
587 | { | ||
588 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
589 | printk(KERN_ERR "Retransmit from timer \n"); | ||
590 | priv->ReTransmitRequested = 0; | ||
591 | arlan_retransmit_now(dev); | ||
592 | } | ||
593 | if (!registrationBad(dev) && | ||
594 | time_after(jiffies, priv->tx_done_delayed) && | ||
595 | priv->tx_done_delayed != 0) | ||
596 | { | ||
597 | TXLAST(dev).offset = 0; | ||
598 | if (priv->txLast) | ||
599 | priv->txLast = 0; | ||
600 | else if (TXTAIL(dev).offset) | ||
601 | priv->txLast = 1; | ||
602 | if (TXLAST(dev).offset) | ||
603 | { | ||
604 | arlan_retransmit_now(dev); | ||
605 | dev->trans_start = jiffies; | ||
606 | } | ||
607 | if (!(TXHEAD(dev).offset && TXTAIL(dev).offset)) | ||
608 | { | ||
609 | netif_wake_queue (dev); | ||
610 | } | ||
611 | priv->tx_done_delayed = 0; | ||
612 | bh_mark_needed = 1; | ||
613 | } | ||
614 | if (bh_mark_needed) | ||
615 | { | ||
616 | netif_wake_queue (dev); | ||
617 | } | ||
618 | arlan_process_interrupt(dev); | ||
619 | |||
620 | if (next_tick < priv->card_polling_interval) | ||
621 | next_tick = priv->card_polling_interval; | ||
622 | |||
623 | priv->timer.expires = jiffies + next_tick; | ||
624 | |||
625 | add_timer(&priv->timer); | ||
626 | } | ||
627 | |||
628 | |||
629 | #ifdef ARLAN_DEBUGGING | ||
630 | |||
631 | static void arlan_print_registers(struct net_device *dev, int line) | ||
632 | { | ||
633 | struct arlan_private *priv = netdev_priv(dev); | ||
634 | volatile struct arlan_shmem *arlan = priv->card; | ||
635 | |||
636 | u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage, | ||
637 | txStatus, rxStatus, interruptInProgress, commandByte; | ||
638 | |||
639 | |||
640 | ARLAN_DEBUG_ENTRY("arlan_print_registers"); | ||
641 | READSHM(interruptInProgress, arlan->interruptInProgress, u_char); | ||
642 | READSHM(hostcpuLock, arlan->hostcpuLock, u_char); | ||
643 | READSHM(lancpuLock, arlan->lancpuLock, u_char); | ||
644 | READSHM(controlRegister, arlan->controlRegister, u_char); | ||
645 | READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char); | ||
646 | READSHM(txStatus, arlan->txStatus, u_char); | ||
647 | READSHM(rxStatus, arlan->rxStatus, u_char); | ||
648 | READSHM(commandByte, arlan->commandByte, u_char); | ||
649 | |||
650 | printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n", | ||
651 | line, interruptInProgress, hostcpuLock, lancpuLock, commandByte, | ||
652 | controlRegister, cntrlRegImage, txStatus, rxStatus); | ||
653 | |||
654 | ARLAN_DEBUG_EXIT("arlan_print_registers"); | ||
655 | } | ||
656 | #endif | ||
657 | |||
658 | |||
659 | static int arlan_hw_tx(struct net_device *dev, char *buf, int length) | ||
660 | { | ||
661 | int i; | ||
662 | |||
663 | struct arlan_private *priv = netdev_priv(dev); | ||
664 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
665 | struct arlan_conf_stru *conf = priv->Conf; | ||
666 | |||
667 | int tailStarts = 0x800; | ||
668 | int headEnds = 0x0; | ||
669 | |||
670 | |||
671 | ARLAN_DEBUG_ENTRY("arlan_hw_tx"); | ||
672 | if (TXHEAD(dev).offset) | ||
673 | headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - offsetof(struct arlan_shmem, txBuffer)) / 64) + 1) * 64; | ||
674 | if (TXTAIL(dev).offset) | ||
675 | tailStarts = 0x800 - (((TXTAIL(dev).offset - offsetof(struct arlan_shmem, txBuffer)) / 64) + 2) * 64; | ||
676 | |||
677 | |||
678 | if (!TXHEAD(dev).offset && length < tailStarts) | ||
679 | { | ||
680 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
681 | printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts); | ||
682 | |||
683 | TXHEAD(dev).offset = | ||
684 | offsetof(struct arlan_shmem, txBuffer); | ||
685 | TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN; | ||
686 | for (i = 0; i < 6; i++) | ||
687 | TXHEAD(dev).dest[i] = buf[i]; | ||
688 | TXHEAD(dev).clear = conf->txClear; | ||
689 | TXHEAD(dev).retries = conf->txRetries; /* 0 is use default */ | ||
690 | TXHEAD(dev).routing = conf->txRouting; | ||
691 | TXHEAD(dev).scrambled = conf->txScrambled; | ||
692 | memcpy_toio((char __iomem *)arlan + TXHEAD(dev).offset, buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length); | ||
693 | } | ||
694 | else if (!TXTAIL(dev).offset && length < (0x800 - headEnds)) | ||
695 | { | ||
696 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
697 | printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds); | ||
698 | |||
699 | TXTAIL(dev).offset = | ||
700 | offsetof(struct arlan_shmem, txBuffer) + 0x800 - (length / 64 + 2) * 64; | ||
701 | TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN; | ||
702 | for (i = 0; i < 6; i++) | ||
703 | TXTAIL(dev).dest[i] = buf[i]; | ||
704 | TXTAIL(dev).clear = conf->txClear; | ||
705 | TXTAIL(dev).retries = conf->txRetries; | ||
706 | TXTAIL(dev).routing = conf->txRouting; | ||
707 | TXTAIL(dev).scrambled = conf->txScrambled; | ||
708 | memcpy_toio(((char __iomem *)arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length); | ||
709 | } | ||
710 | else | ||
711 | { | ||
712 | netif_stop_queue (dev); | ||
713 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
714 | printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds); | ||
715 | return -1; | ||
716 | } | ||
717 | priv->out_bytes += length; | ||
718 | priv->out_bytes10 += length; | ||
719 | if (conf->measure_rate < 1) | ||
720 | conf->measure_rate = 1; | ||
721 | if (time_after(jiffies, priv->out_time + conf->measure_rate * HZ)) | ||
722 | { | ||
723 | conf->out_speed = priv->out_bytes / conf->measure_rate; | ||
724 | priv->out_bytes = 0; | ||
725 | priv->out_time = jiffies; | ||
726 | } | ||
727 | if (time_after(jiffies, priv->out_time10 + conf->measure_rate * 10*HZ)) | ||
728 | { | ||
729 | conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate); | ||
730 | priv->out_bytes10 = 0; | ||
731 | priv->out_time10 = jiffies; | ||
732 | } | ||
733 | if (TXHEAD(dev).offset && TXTAIL(dev).offset) | ||
734 | { | ||
735 | netif_stop_queue (dev); | ||
736 | return 0; | ||
737 | } | ||
738 | else | ||
739 | netif_start_queue (dev); | ||
740 | |||
741 | |||
742 | IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) | ||
743 | printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, | ||
744 | (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3], | ||
745 | (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7], | ||
746 | (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]); | ||
747 | |||
748 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast); | ||
749 | |||
750 | arlan_command(dev, ARLAN_COMMAND_TX); | ||
751 | |||
752 | priv->tx_last_sent = jiffies; | ||
753 | |||
754 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length); | ||
755 | |||
756 | ARLAN_DEBUG_EXIT("arlan_hw_tx"); | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | |||
762 | static int arlan_hw_config(struct net_device *dev) | ||
763 | { | ||
764 | struct arlan_private *priv = netdev_priv(dev); | ||
765 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
766 | struct arlan_conf_stru *conf = priv->Conf; | ||
767 | |||
768 | ARLAN_DEBUG_ENTRY("arlan_hw_config"); | ||
769 | |||
770 | printk(KERN_NOTICE "%s arlan configure called \n", dev->name); | ||
771 | if (arlan_EEPROM_bad) | ||
772 | printk(KERN_NOTICE "arlan configure with eeprom bad option \n"); | ||
773 | |||
774 | |||
775 | WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char); | ||
776 | WRITESHM(arlan->channelSet, conf->channelSet, u_char); | ||
777 | |||
778 | if (arlan_EEPROM_bad) | ||
779 | WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char); | ||
780 | |||
781 | WRITESHM(arlan->channelNumber, conf->channelNumber, u_char); | ||
782 | |||
783 | WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char); | ||
784 | WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char); | ||
785 | |||
786 | WRITESHM(arlan->systemId, conf->systemId, u_int); | ||
787 | |||
788 | WRITESHM(arlan->maxRetries, conf->maxRetries, u_char); | ||
789 | WRITESHM(arlan->receiveMode, conf->receiveMode, u_char); | ||
790 | WRITESHM(arlan->priority, conf->priority, u_char); | ||
791 | WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char); | ||
792 | WRITESHM(arlan->SID, conf->SID, u_int); | ||
793 | |||
794 | WRITESHM(arlan->registrationMode, conf->registrationMode, u_char); | ||
795 | |||
796 | WRITESHM(arlan->registrationFill, conf->registrationFill, u_char); | ||
797 | WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char); | ||
798 | WRITESHM(arlan->codeFormat, conf->codeFormat, u_char); | ||
799 | WRITESHM(arlan->numChannels, conf->numChannels, u_char); | ||
800 | WRITESHM(arlan->channel1, conf->channel1, u_char); | ||
801 | WRITESHM(arlan->channel2, conf->channel2, u_char); | ||
802 | WRITESHM(arlan->channel3, conf->channel3, u_char); | ||
803 | WRITESHM(arlan->channel4, conf->channel4, u_char); | ||
804 | WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short); | ||
805 | WRITESHM(arlan->SID, conf->SID, u_int); | ||
806 | WRITESHM(arlan->waitTime, conf->waitTime, u_short); | ||
807 | WRITESHM(arlan->lParameter, conf->lParameter, u_short); | ||
808 | memcpy_toio(&(arlan->_15), &(conf->_15), 3); | ||
809 | WRITESHM(arlan->_15, conf->_15, u_short); | ||
810 | WRITESHM(arlan->headerSize, conf->headerSize, u_short); | ||
811 | if (arlan_EEPROM_bad) | ||
812 | WRITESHM(arlan->hardwareType, conf->hardwareType, u_char); | ||
813 | WRITESHM(arlan->radioType, conf->radioType, u_char); | ||
814 | if (arlan_EEPROM_bad) | ||
815 | WRITESHM(arlan->radioModule, conf->radioType, u_char); | ||
816 | |||
817 | memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8); | ||
818 | memcpy_toio(arlan->name, conf->siteName, 16); | ||
819 | |||
820 | WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF); /* do configure */ | ||
821 | memset_io(arlan->commandParameter, 0, 0xf); /* 0xf */ | ||
822 | memset_io(arlan->commandParameter + 1, 0, 2); | ||
823 | if (conf->writeEEPROM) | ||
824 | { | ||
825 | memset_io(arlan->commandParameter, conf->writeEEPROM, 1); | ||
826 | // conf->writeEEPROM=0; | ||
827 | } | ||
828 | if (conf->registrationMode && conf->registrationInterrupts) | ||
829 | memset_io(arlan->commandParameter + 3, 1, 1); | ||
830 | else | ||
831 | memset_io(arlan->commandParameter + 3, 0, 1); | ||
832 | |||
833 | priv->irq_test_done = 0; | ||
834 | |||
835 | if (conf->tx_queue_len) | ||
836 | dev->tx_queue_len = conf->tx_queue_len; | ||
837 | udelay(100); | ||
838 | |||
839 | ARLAN_DEBUG_EXIT("arlan_hw_config"); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | |||
844 | static int arlan_read_card_configuration(struct net_device *dev) | ||
845 | { | ||
846 | u_char tlx415; | ||
847 | struct arlan_private *priv = netdev_priv(dev); | ||
848 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
849 | struct arlan_conf_stru *conf = priv->Conf; | ||
850 | |||
851 | ARLAN_DEBUG_ENTRY("arlan_read_card_configuration"); | ||
852 | |||
853 | if (radioNodeId == radioNodeIdUNKNOWN) | ||
854 | { | ||
855 | READSHM(conf->radioNodeId, arlan->radioNodeId, u_short); | ||
856 | } | ||
857 | else | ||
858 | conf->radioNodeId = radioNodeId; | ||
859 | |||
860 | if (SID == SIDUNKNOWN) | ||
861 | { | ||
862 | READSHM(conf->SID, arlan->SID, u_int); | ||
863 | } | ||
864 | else conf->SID = SID; | ||
865 | |||
866 | if (spreadingCode == spreadingCodeUNKNOWN) | ||
867 | { | ||
868 | READSHM(conf->spreadingCode, arlan->spreadingCode, u_char); | ||
869 | } | ||
870 | else | ||
871 | conf->spreadingCode = spreadingCode; | ||
872 | |||
873 | if (channelSet == channelSetUNKNOWN) | ||
874 | { | ||
875 | READSHM(conf->channelSet, arlan->channelSet, u_char); | ||
876 | } | ||
877 | else conf->channelSet = channelSet; | ||
878 | |||
879 | if (channelNumber == channelNumberUNKNOWN) | ||
880 | { | ||
881 | READSHM(conf->channelNumber, arlan->channelNumber, u_char); | ||
882 | } | ||
883 | else conf->channelNumber = channelNumber; | ||
884 | |||
885 | READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char); | ||
886 | READSHM(conf->txAttenuation, arlan->txAttenuation, u_char); | ||
887 | |||
888 | if (systemId == systemIdUNKNOWN) | ||
889 | { | ||
890 | READSHM(conf->systemId, arlan->systemId, u_int); | ||
891 | } | ||
892 | else conf->systemId = systemId; | ||
893 | |||
894 | READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short); | ||
895 | READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short); | ||
896 | READSHM(conf->maxRetries, arlan->maxRetries, u_char); | ||
897 | READSHM(conf->receiveMode, arlan->receiveMode, u_char); | ||
898 | READSHM(conf->priority, arlan->priority, u_char); | ||
899 | READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char); | ||
900 | |||
901 | if (SID == SIDUNKNOWN) | ||
902 | { | ||
903 | READSHM(conf->SID, arlan->SID, u_int); | ||
904 | } | ||
905 | else conf->SID = SID; | ||
906 | |||
907 | if (registrationMode == registrationModeUNKNOWN) | ||
908 | { | ||
909 | READSHM(conf->registrationMode, arlan->registrationMode, u_char); | ||
910 | } | ||
911 | else conf->registrationMode = registrationMode; | ||
912 | |||
913 | READSHM(conf->registrationFill, arlan->registrationFill, u_char); | ||
914 | READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char); | ||
915 | READSHM(conf->codeFormat, arlan->codeFormat, u_char); | ||
916 | READSHM(conf->numChannels, arlan->numChannels, u_char); | ||
917 | READSHM(conf->channel1, arlan->channel1, u_char); | ||
918 | READSHM(conf->channel2, arlan->channel2, u_char); | ||
919 | READSHM(conf->channel3, arlan->channel3, u_char); | ||
920 | READSHM(conf->channel4, arlan->channel4, u_char); | ||
921 | READSHM(conf->waitTime, arlan->waitTime, u_short); | ||
922 | READSHM(conf->lParameter, arlan->lParameter, u_short); | ||
923 | READSHM(conf->_15, arlan->_15, u_short); | ||
924 | READSHM(conf->headerSize, arlan->headerSize, u_short); | ||
925 | READSHM(conf->hardwareType, arlan->hardwareType, u_char); | ||
926 | READSHM(conf->radioType, arlan->radioModule, u_char); | ||
927 | |||
928 | if (conf->radioType == 0) | ||
929 | conf->radioType = 0xc; | ||
930 | |||
931 | WRITESHM(arlan->configStatus, 0xA5, u_char); | ||
932 | READSHM(tlx415, arlan->configStatus, u_char); | ||
933 | |||
934 | if (tlx415 != 0xA5) | ||
935 | printk(KERN_INFO "%s tlx415 chip \n", dev->name); | ||
936 | |||
937 | conf->txClear = 0; | ||
938 | conf->txRetries = 1; | ||
939 | conf->txRouting = 1; | ||
940 | conf->txScrambled = 0; | ||
941 | conf->rxParameter = 1; | ||
942 | conf->txTimeoutMs = 4000; | ||
943 | conf->waitCardTimeout = 100000; | ||
944 | conf->receiveMode = ARLAN_RCV_CLEAN; | ||
945 | memcpy_fromio(conf->siteName, arlan->name, 16); | ||
946 | conf->siteName[16] = '\0'; | ||
947 | conf->retries = retries; | ||
948 | conf->tx_delay_ms = tx_delay_ms; | ||
949 | conf->ReTransmitPacketMaxSize = 200; | ||
950 | conf->waitReTransmitPacketMaxSize = 200; | ||
951 | conf->txAckTimeoutMs = 900; | ||
952 | conf->fastReTransCount = 3; | ||
953 | |||
954 | ARLAN_DEBUG_EXIT("arlan_read_card_configuration"); | ||
955 | |||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | |||
960 | static int lastFoundAt = 0xbe000; | ||
961 | |||
962 | |||
963 | /* | ||
964 | * This is the real probe routine. Linux has a history of friendly device | ||
965 | * probes on the ISA bus. A good device probes avoids doing writes, and | ||
966 | * verifies that the correct device exists and functions. | ||
967 | */ | ||
968 | #define ARLAN_SHMEM_SIZE 0x2000 | ||
969 | static int __init arlan_check_fingerprint(unsigned long memaddr) | ||
970 | { | ||
971 | static const char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; | ||
972 | volatile struct arlan_shmem __iomem *arlan = (struct arlan_shmem *) memaddr; | ||
973 | unsigned long paddr = virt_to_phys((void *) memaddr); | ||
974 | char tempBuf[49]; | ||
975 | |||
976 | ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); | ||
977 | |||
978 | if (!request_mem_region(paddr, ARLAN_SHMEM_SIZE, "arlan")) { | ||
979 | // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",paddr); | ||
980 | return -ENODEV; | ||
981 | } | ||
982 | |||
983 | memcpy_fromio(tempBuf, arlan->textRegion, 29); | ||
984 | tempBuf[30] = 0; | ||
985 | |||
986 | /* check for card at this address */ | ||
987 | if (0 != strncmp(tempBuf, probeText, 29)){ | ||
988 | release_mem_region(paddr, ARLAN_SHMEM_SIZE); | ||
989 | return -ENODEV; | ||
990 | } | ||
991 | |||
992 | // printk(KERN_INFO "arlan found at 0x%x \n",memaddr); | ||
993 | ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static int arlan_change_mtu(struct net_device *dev, int new_mtu) | ||
999 | { | ||
1000 | struct arlan_private *priv = netdev_priv(dev); | ||
1001 | struct arlan_conf_stru *conf = priv->Conf; | ||
1002 | |||
1003 | ARLAN_DEBUG_ENTRY("arlan_change_mtu"); | ||
1004 | if (new_mtu > 2032) | ||
1005 | return -EINVAL; | ||
1006 | dev->mtu = new_mtu; | ||
1007 | if (new_mtu < 256) | ||
1008 | new_mtu = 256; /* cards book suggests 1600 */ | ||
1009 | conf->maxDatagramSize = new_mtu; | ||
1010 | conf->maxFrameSize = new_mtu + 48; | ||
1011 | |||
1012 | arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); | ||
1013 | printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu); | ||
1014 | |||
1015 | ARLAN_DEBUG_EXIT("arlan_change_mtu"); | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static int arlan_mac_addr(struct net_device *dev, void *p) | ||
1021 | { | ||
1022 | struct sockaddr *addr = p; | ||
1023 | |||
1024 | |||
1025 | ARLAN_DEBUG_ENTRY("arlan_mac_addr"); | ||
1026 | return -EINVAL; | ||
1027 | |||
1028 | if (!netif_running(dev)) | ||
1029 | return -EBUSY; | ||
1030 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
1031 | |||
1032 | ARLAN_DEBUG_EXIT("arlan_mac_addr"); | ||
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | |||
1037 | |||
1038 | static int __init arlan_setup_device(struct net_device *dev, int num) | ||
1039 | { | ||
1040 | struct arlan_private *ap = netdev_priv(dev); | ||
1041 | int err; | ||
1042 | |||
1043 | ARLAN_DEBUG_ENTRY("arlan_setup_device"); | ||
1044 | |||
1045 | ap->conf = (struct arlan_shmem *)(ap+1); | ||
1046 | |||
1047 | dev->tx_queue_len = tx_queue_len; | ||
1048 | dev->open = arlan_open; | ||
1049 | dev->stop = arlan_close; | ||
1050 | dev->hard_start_xmit = arlan_tx; | ||
1051 | dev->get_stats = arlan_statistics; | ||
1052 | dev->set_multicast_list = arlan_set_multicast; | ||
1053 | dev->change_mtu = arlan_change_mtu; | ||
1054 | dev->set_mac_address = arlan_mac_addr; | ||
1055 | dev->tx_timeout = arlan_tx_timeout; | ||
1056 | dev->watchdog_timeo = 3*HZ; | ||
1057 | |||
1058 | ap->irq_test_done = 0; | ||
1059 | ap->Conf = &arlan_conf[num]; | ||
1060 | |||
1061 | ap->Conf->pre_Command_Wait = 40; | ||
1062 | ap->Conf->rx_tweak1 = 30; | ||
1063 | ap->Conf->rx_tweak2 = 0; | ||
1064 | |||
1065 | |||
1066 | err = register_netdev(dev); | ||
1067 | if (err) { | ||
1068 | release_mem_region(virt_to_phys((void *) dev->mem_start), | ||
1069 | ARLAN_SHMEM_SIZE); | ||
1070 | free_netdev(dev); | ||
1071 | return err; | ||
1072 | } | ||
1073 | arlan_device[num] = dev; | ||
1074 | ARLAN_DEBUG_EXIT("arlan_setup_device"); | ||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | static int __init arlan_probe_here(struct net_device *dev, | ||
1079 | unsigned long memaddr) | ||
1080 | { | ||
1081 | struct arlan_private *ap = netdev_priv(dev); | ||
1082 | |||
1083 | ARLAN_DEBUG_ENTRY("arlan_probe_here"); | ||
1084 | |||
1085 | if (arlan_check_fingerprint(memaddr)) | ||
1086 | return -ENODEV; | ||
1087 | |||
1088 | printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, | ||
1089 | (int) virt_to_phys((void*)memaddr)); | ||
1090 | |||
1091 | ap->card = (void *) memaddr; | ||
1092 | dev->mem_start = memaddr; | ||
1093 | dev->mem_end = memaddr + ARLAN_SHMEM_SIZE-1; | ||
1094 | |||
1095 | if (dev->irq < 2) | ||
1096 | { | ||
1097 | READSHM(dev->irq, ap->card->irqLevel, u_char); | ||
1098 | } else if (dev->irq == 2) | ||
1099 | dev->irq = 9; | ||
1100 | |||
1101 | arlan_read_card_configuration(dev); | ||
1102 | |||
1103 | ARLAN_DEBUG_EXIT("arlan_probe_here"); | ||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | static int arlan_open(struct net_device *dev) | ||
1109 | { | ||
1110 | struct arlan_private *priv = netdev_priv(dev); | ||
1111 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
1112 | int ret = 0; | ||
1113 | |||
1114 | ARLAN_DEBUG_ENTRY("arlan_open"); | ||
1115 | |||
1116 | ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev); | ||
1117 | if (ret) | ||
1118 | { | ||
1119 | printk(KERN_ERR "%s: unable to get IRQ %d .\n", | ||
1120 | dev->name, dev->irq); | ||
1121 | return ret; | ||
1122 | } | ||
1123 | |||
1124 | |||
1125 | priv->bad = 0; | ||
1126 | priv->lastReset = 0; | ||
1127 | priv->reset = 0; | ||
1128 | memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6); | ||
1129 | memset(dev->broadcast, 0xff, 6); | ||
1130 | dev->tx_queue_len = tx_queue_len; | ||
1131 | priv->interrupt_processing_active = 0; | ||
1132 | spin_lock_init(&priv->lock); | ||
1133 | |||
1134 | netif_start_queue (dev); | ||
1135 | |||
1136 | priv->registrationLostCount = 0; | ||
1137 | priv->registrationLastSeen = jiffies; | ||
1138 | priv->txLast = 0; | ||
1139 | priv->tx_command_given = 0; | ||
1140 | priv->rx_command_given = 0; | ||
1141 | |||
1142 | priv->reRegisterExp = 1; | ||
1143 | priv->tx_last_sent = jiffies - 1; | ||
1144 | priv->tx_last_cleared = jiffies; | ||
1145 | priv->Conf->writeEEPROM = 0; | ||
1146 | priv->Conf->registrationInterrupts = 1; | ||
1147 | |||
1148 | init_timer(&priv->timer); | ||
1149 | priv->timer.expires = jiffies + HZ / 10; | ||
1150 | priv->timer.data = (unsigned long) dev; | ||
1151 | priv->timer.function = &arlan_registration_timer; /* timer handler */ | ||
1152 | |||
1153 | arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); | ||
1154 | mdelay(200); | ||
1155 | add_timer(&priv->timer); | ||
1156 | |||
1157 | ARLAN_DEBUG_EXIT("arlan_open"); | ||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1161 | |||
1162 | static void arlan_tx_timeout (struct net_device *dev) | ||
1163 | { | ||
1164 | printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name); | ||
1165 | /* Try to restart the adaptor. */ | ||
1166 | arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); | ||
1167 | // dev->trans_start = jiffies; | ||
1168 | // netif_start_queue (dev); | ||
1169 | } | ||
1170 | |||
1171 | |||
1172 | static int arlan_tx(struct sk_buff *skb, struct net_device *dev) | ||
1173 | { | ||
1174 | short length; | ||
1175 | unsigned char *buf; | ||
1176 | |||
1177 | ARLAN_DEBUG_ENTRY("arlan_tx"); | ||
1178 | |||
1179 | length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
1180 | buf = skb->data; | ||
1181 | |||
1182 | if (length + 0x12 > 0x800) { | ||
1183 | printk(KERN_ERR "TX RING overflow \n"); | ||
1184 | netif_stop_queue (dev); | ||
1185 | } | ||
1186 | |||
1187 | if (arlan_hw_tx(dev, buf, length) == -1) | ||
1188 | goto bad_end; | ||
1189 | |||
1190 | dev->trans_start = jiffies; | ||
1191 | |||
1192 | dev_kfree_skb(skb); | ||
1193 | |||
1194 | arlan_process_interrupt(dev); | ||
1195 | ARLAN_DEBUG_EXIT("arlan_tx"); | ||
1196 | return 0; | ||
1197 | |||
1198 | bad_end: | ||
1199 | arlan_process_interrupt(dev); | ||
1200 | netif_stop_queue (dev); | ||
1201 | ARLAN_DEBUG_EXIT("arlan_tx"); | ||
1202 | return 1; | ||
1203 | } | ||
1204 | |||
1205 | |||
1206 | static inline int DoNotReTransmitCrap(struct net_device *dev) | ||
1207 | { | ||
1208 | struct arlan_private *priv = netdev_priv(dev); | ||
1209 | |||
1210 | if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize) | ||
1211 | return 1; | ||
1212 | return 0; | ||
1213 | |||
1214 | } | ||
1215 | |||
1216 | static inline int DoNotWaitReTransmitCrap(struct net_device *dev) | ||
1217 | { | ||
1218 | struct arlan_private *priv = netdev_priv(dev); | ||
1219 | |||
1220 | if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize) | ||
1221 | return 1; | ||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static inline void arlan_queue_retransmit(struct net_device *dev) | ||
1226 | { | ||
1227 | struct arlan_private *priv = netdev_priv(dev); | ||
1228 | |||
1229 | ARLAN_DEBUG_ENTRY("arlan_queue_retransmit"); | ||
1230 | |||
1231 | if (DoNotWaitReTransmitCrap(dev)) | ||
1232 | { | ||
1233 | arlan_drop_tx(dev); | ||
1234 | } else | ||
1235 | priv->ReTransmitRequested++; | ||
1236 | |||
1237 | ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); | ||
1238 | } | ||
1239 | |||
1240 | static inline void RetryOrFail(struct net_device *dev) | ||
1241 | { | ||
1242 | struct arlan_private *priv = netdev_priv(dev); | ||
1243 | |||
1244 | ARLAN_DEBUG_ENTRY("RetryOrFail"); | ||
1245 | |||
1246 | if (priv->retransmissions > priv->Conf->retries || | ||
1247 | DoNotReTransmitCrap(dev)) | ||
1248 | { | ||
1249 | arlan_drop_tx(dev); | ||
1250 | } | ||
1251 | else if (priv->bad <= priv->Conf->fastReTransCount) | ||
1252 | { | ||
1253 | arlan_retransmit_now(dev); | ||
1254 | } | ||
1255 | else arlan_queue_retransmit(dev); | ||
1256 | |||
1257 | ARLAN_DEBUG_EXIT("RetryOrFail"); | ||
1258 | } | ||
1259 | |||
1260 | |||
1261 | static void arlan_tx_done_interrupt(struct net_device *dev, int status) | ||
1262 | { | ||
1263 | struct arlan_private *priv = netdev_priv(dev); | ||
1264 | |||
1265 | ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt"); | ||
1266 | |||
1267 | priv->tx_last_cleared = jiffies; | ||
1268 | priv->tx_command_given = 0; | ||
1269 | switch (status) | ||
1270 | { | ||
1271 | case 1: | ||
1272 | { | ||
1273 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1274 | printk("arlan intr: transmit OK\n"); | ||
1275 | priv->stats.tx_packets++; | ||
1276 | priv->bad = 0; | ||
1277 | priv->reset = 0; | ||
1278 | priv->retransmissions = 0; | ||
1279 | if (priv->Conf->tx_delay_ms) | ||
1280 | { | ||
1281 | priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1; | ||
1282 | } | ||
1283 | else | ||
1284 | { | ||
1285 | TXLAST(dev).offset = 0; | ||
1286 | if (priv->txLast) | ||
1287 | priv->txLast = 0; | ||
1288 | else if (TXTAIL(dev).offset) | ||
1289 | priv->txLast = 1; | ||
1290 | if (TXLAST(dev).offset) | ||
1291 | { | ||
1292 | arlan_retransmit_now(dev); | ||
1293 | dev->trans_start = jiffies; | ||
1294 | } | ||
1295 | if (!TXHEAD(dev).offset || !TXTAIL(dev).offset) | ||
1296 | { | ||
1297 | netif_wake_queue (dev); | ||
1298 | } | ||
1299 | } | ||
1300 | } | ||
1301 | break; | ||
1302 | |||
1303 | case 2: | ||
1304 | { | ||
1305 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1306 | printk("arlan intr: transmit timed out\n"); | ||
1307 | priv->bad += 1; | ||
1308 | //arlan_queue_retransmit(dev); | ||
1309 | RetryOrFail(dev); | ||
1310 | } | ||
1311 | break; | ||
1312 | |||
1313 | case 3: | ||
1314 | { | ||
1315 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1316 | printk("arlan intr: transmit max retries\n"); | ||
1317 | priv->bad += 1; | ||
1318 | priv->reset = 0; | ||
1319 | //arlan_queue_retransmit(dev); | ||
1320 | RetryOrFail(dev); | ||
1321 | } | ||
1322 | break; | ||
1323 | |||
1324 | case 4: | ||
1325 | { | ||
1326 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1327 | printk("arlan intr: transmit aborted\n"); | ||
1328 | priv->bad += 1; | ||
1329 | arlan_queue_retransmit(dev); | ||
1330 | //RetryOrFail(dev); | ||
1331 | } | ||
1332 | break; | ||
1333 | |||
1334 | case 5: | ||
1335 | { | ||
1336 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1337 | printk("arlan intr: transmit not registered\n"); | ||
1338 | priv->bad += 1; | ||
1339 | //debug=101; | ||
1340 | arlan_queue_retransmit(dev); | ||
1341 | } | ||
1342 | break; | ||
1343 | |||
1344 | case 6: | ||
1345 | { | ||
1346 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1347 | printk("arlan intr: transmit destination full\n"); | ||
1348 | priv->bad += 1; | ||
1349 | priv->reset = 0; | ||
1350 | //arlan_drop_tx(dev); | ||
1351 | arlan_queue_retransmit(dev); | ||
1352 | } | ||
1353 | break; | ||
1354 | |||
1355 | case 7: | ||
1356 | { | ||
1357 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1358 | printk("arlan intr: transmit unknown ack\n"); | ||
1359 | priv->bad += 1; | ||
1360 | priv->reset = 0; | ||
1361 | arlan_queue_retransmit(dev); | ||
1362 | } | ||
1363 | break; | ||
1364 | |||
1365 | case 8: | ||
1366 | { | ||
1367 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1368 | printk("arlan intr: transmit dest mail box full\n"); | ||
1369 | priv->bad += 1; | ||
1370 | priv->reset = 0; | ||
1371 | //arlan_drop_tx(dev); | ||
1372 | arlan_queue_retransmit(dev); | ||
1373 | } | ||
1374 | break; | ||
1375 | |||
1376 | case 9: | ||
1377 | { | ||
1378 | IFDEBUG(ARLAN_DEBUG_TX_CHAIN) | ||
1379 | printk("arlan intr: transmit root dest not reg.\n"); | ||
1380 | priv->bad += 1; | ||
1381 | priv->reset = 1; | ||
1382 | //arlan_drop_tx(dev); | ||
1383 | arlan_queue_retransmit(dev); | ||
1384 | } | ||
1385 | break; | ||
1386 | |||
1387 | default: | ||
1388 | { | ||
1389 | printk(KERN_ERR "arlan intr: transmit status unknown\n"); | ||
1390 | priv->bad += 1; | ||
1391 | priv->reset = 1; | ||
1392 | arlan_drop_tx(dev); | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt"); | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len) | ||
1401 | { | ||
1402 | char *skbtmp; | ||
1403 | int i = 0; | ||
1404 | |||
1405 | struct arlan_private *priv = netdev_priv(dev); | ||
1406 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
1407 | struct arlan_conf_stru *conf = priv->Conf; | ||
1408 | |||
1409 | |||
1410 | ARLAN_DEBUG_ENTRY("arlan_rx_interrupt"); | ||
1411 | // by spec, not WRITESHMB(arlan->rxStatus,0x00); | ||
1412 | // prohibited here arlan_command(dev, ARLAN_COMMAND_RX); | ||
1413 | |||
1414 | if (pkt_len < 10 || pkt_len > 2048) | ||
1415 | { | ||
1416 | printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len); | ||
1417 | return; | ||
1418 | } | ||
1419 | if (rxOffset + pkt_len > 0x2000) | ||
1420 | { | ||
1421 | printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset); | ||
1422 | return; | ||
1423 | } | ||
1424 | priv->in_bytes += pkt_len; | ||
1425 | priv->in_bytes10 += pkt_len; | ||
1426 | if (conf->measure_rate < 1) | ||
1427 | conf->measure_rate = 1; | ||
1428 | if (time_after(jiffies, priv->in_time + conf->measure_rate * HZ)) | ||
1429 | { | ||
1430 | conf->in_speed = priv->in_bytes / conf->measure_rate; | ||
1431 | priv->in_bytes = 0; | ||
1432 | priv->in_time = jiffies; | ||
1433 | } | ||
1434 | if (time_after(jiffies, priv->in_time10 + conf->measure_rate * 10*HZ)) | ||
1435 | { | ||
1436 | conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate); | ||
1437 | priv->in_bytes10 = 0; | ||
1438 | priv->in_time10 = jiffies; | ||
1439 | } | ||
1440 | DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char); | ||
1441 | switch (rxStatus) | ||
1442 | { | ||
1443 | case 1: | ||
1444 | case 2: | ||
1445 | case 3: | ||
1446 | { | ||
1447 | /* Malloc up new buffer. */ | ||
1448 | struct sk_buff *skb; | ||
1449 | |||
1450 | DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short); | ||
1451 | DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char); | ||
1452 | DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char); | ||
1453 | |||
1454 | /* here we do multicast filtering to avoid slow 8-bit memcopy */ | ||
1455 | #ifdef ARLAN_MULTICAST | ||
1456 | if (!(dev->flags & IFF_ALLMULTI) && | ||
1457 | !(dev->flags & IFF_PROMISC) && | ||
1458 | dev->mc_list) | ||
1459 | { | ||
1460 | char hw_dst_addr[6]; | ||
1461 | struct dev_mc_list *dmi = dev->mc_list; | ||
1462 | int i; | ||
1463 | |||
1464 | memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6); | ||
1465 | if (hw_dst_addr[0] == 0x01) | ||
1466 | { | ||
1467 | if (mdebug) | ||
1468 | if (hw_dst_addr[1] == 0x00) | ||
1469 | printk(KERN_ERR "%s mcast 0x0100 \n", dev->name); | ||
1470 | else if (hw_dst_addr[1] == 0x40) | ||
1471 | printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); | ||
1472 | while (dmi) | ||
1473 | { if (dmi->dmi_addrlen == 6) | ||
1474 | { | ||
1475 | if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) | ||
1476 | printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, | ||
1477 | dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], | ||
1478 | dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); | ||
1479 | for (i = 0; i < 6; i++) | ||
1480 | if (dmi->dmi_addr[i] != hw_dst_addr[i]) | ||
1481 | break; | ||
1482 | if (i == 6) | ||
1483 | break; | ||
1484 | } | ||
1485 | else | ||
1486 | printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); | ||
1487 | dmi = dmi->next; | ||
1488 | } | ||
1489 | /* we reach here if multicast filtering is on and packet | ||
1490 | * is multicast and not for receive */ | ||
1491 | goto end_of_interrupt; | ||
1492 | } | ||
1493 | } | ||
1494 | #endif // ARLAN_MULTICAST | ||
1495 | /* multicast filtering ends here */ | ||
1496 | pkt_len += ARLAN_FAKE_HDR_LEN; | ||
1497 | |||
1498 | skb = dev_alloc_skb(pkt_len + 4); | ||
1499 | if (skb == NULL) | ||
1500 | { | ||
1501 | printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); | ||
1502 | priv->stats.rx_dropped++; | ||
1503 | break; | ||
1504 | } | ||
1505 | skb_reserve(skb, 2); | ||
1506 | skb->dev = dev; | ||
1507 | skbtmp = skb_put(skb, pkt_len); | ||
1508 | |||
1509 | memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); | ||
1510 | memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6); | ||
1511 | memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6); | ||
1512 | WRITESHMB(arlan->rxStatus, 0x00); | ||
1513 | arlan_command(dev, ARLAN_COMMAND_RX); | ||
1514 | |||
1515 | IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) | ||
1516 | { | ||
1517 | char immedDestAddress[6]; | ||
1518 | char immedSrcAddress[6]; | ||
1519 | memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); | ||
1520 | memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); | ||
1521 | |||
1522 | printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name, | ||
1523 | (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3], | ||
1524 | (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7], | ||
1525 | (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11], | ||
1526 | immedDestAddress[0], immedDestAddress[1], immedDestAddress[2], | ||
1527 | immedDestAddress[3], immedDestAddress[4], immedDestAddress[5], | ||
1528 | immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2], | ||
1529 | immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]); | ||
1530 | } | ||
1531 | skb->protocol = eth_type_trans(skb, dev); | ||
1532 | IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) | ||
1533 | if (skb->protocol != 0x608 && skb->protocol != 0x8) | ||
1534 | { | ||
1535 | for (i = 0; i <= 22; i++) | ||
1536 | printk("%02x:", (u_char) skbtmp[i + 12]); | ||
1537 | printk(KERN_ERR "\n"); | ||
1538 | printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); | ||
1539 | } | ||
1540 | netif_rx(skb); | ||
1541 | dev->last_rx = jiffies; | ||
1542 | priv->stats.rx_packets++; | ||
1543 | priv->stats.rx_bytes += pkt_len; | ||
1544 | } | ||
1545 | break; | ||
1546 | |||
1547 | default: | ||
1548 | printk(KERN_ERR "arlan intr: received unknown status\n"); | ||
1549 | priv->stats.rx_crc_errors++; | ||
1550 | break; | ||
1551 | } | ||
1552 | ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); | ||
1553 | } | ||
1554 | |||
1555 | static void arlan_process_interrupt(struct net_device *dev) | ||
1556 | { | ||
1557 | struct arlan_private *priv = netdev_priv(dev); | ||
1558 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
1559 | u_char rxStatus = READSHMB(arlan->rxStatus); | ||
1560 | u_char txStatus = READSHMB(arlan->txStatus); | ||
1561 | u_short rxOffset = READSHMS(arlan->rxOffset); | ||
1562 | u_short pkt_len = READSHMS(arlan->rxLength); | ||
1563 | int interrupt_count = 0; | ||
1564 | |||
1565 | ARLAN_DEBUG_ENTRY("arlan_process_interrupt"); | ||
1566 | |||
1567 | if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active)) | ||
1568 | { | ||
1569 | if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) | ||
1570 | printk(KERN_ERR "interrupt chain reentering \n"); | ||
1571 | goto end_int_process; | ||
1572 | } | ||
1573 | while ((rxStatus || txStatus || priv->interrupt_ack_requested) | ||
1574 | && (interrupt_count < 5)) | ||
1575 | { | ||
1576 | if (rxStatus) | ||
1577 | priv->last_rx_int_ack_time = jiffies; | ||
1578 | |||
1579 | arlan_command(dev, ARLAN_COMMAND_INT_ACK); | ||
1580 | arlan_command(dev, ARLAN_COMMAND_INT_ENABLE); | ||
1581 | |||
1582 | IFDEBUG(ARLAN_DEBUG_INTERRUPT) | ||
1583 | printk(KERN_ERR "%s: got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n", | ||
1584 | dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte), | ||
1585 | rxOffset, pkt_len); | ||
1586 | |||
1587 | if (rxStatus == 0 && txStatus == 0) | ||
1588 | { | ||
1589 | if (priv->irq_test_done) | ||
1590 | { | ||
1591 | if (!registrationBad(dev)) | ||
1592 | IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ", | ||
1593 | dev->name, txStatus, rxStatus); | ||
1594 | } else { | ||
1595 | IFDEBUG(ARLAN_DEBUG_INTERRUPT) | ||
1596 | printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq); | ||
1597 | |||
1598 | } | ||
1599 | priv->interrupt_ack_requested = 0; | ||
1600 | goto ends; | ||
1601 | } | ||
1602 | if (txStatus != 0) | ||
1603 | { | ||
1604 | WRITESHMB(arlan->txStatus, 0x00); | ||
1605 | arlan_tx_done_interrupt(dev, txStatus); | ||
1606 | goto ends; | ||
1607 | } | ||
1608 | if (rxStatus == 1 || rxStatus == 2) | ||
1609 | { /* a packet waiting */ | ||
1610 | arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len); | ||
1611 | goto ends; | ||
1612 | } | ||
1613 | if (rxStatus > 2 && rxStatus < 0xff) | ||
1614 | { | ||
1615 | WRITESHMB(arlan->rxStatus, 0x00); | ||
1616 | printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ", | ||
1617 | dev->name, txStatus, rxStatus); | ||
1618 | goto ends; | ||
1619 | } | ||
1620 | if (rxStatus == 0xff) | ||
1621 | { | ||
1622 | WRITESHMB(arlan->rxStatus, 0x00); | ||
1623 | arlan_command(dev, ARLAN_COMMAND_RX); | ||
1624 | if (registrationBad(dev)) | ||
1625 | netif_device_detach(dev); | ||
1626 | if (!registrationBad(dev)) | ||
1627 | { | ||
1628 | priv->registrationLastSeen = jiffies; | ||
1629 | if (!netif_queue_stopped(dev) && !priv->under_reset && !priv->under_config) | ||
1630 | netif_wake_queue (dev); | ||
1631 | } | ||
1632 | goto ends; | ||
1633 | } | ||
1634 | ends: | ||
1635 | |||
1636 | arlan_command_process(dev); | ||
1637 | |||
1638 | rxStatus = READSHMB(arlan->rxStatus); | ||
1639 | txStatus = READSHMB(arlan->txStatus); | ||
1640 | rxOffset = READSHMS(arlan->rxOffset); | ||
1641 | pkt_len = READSHMS(arlan->rxLength); | ||
1642 | |||
1643 | |||
1644 | priv->irq_test_done = 1; | ||
1645 | |||
1646 | interrupt_count++; | ||
1647 | } | ||
1648 | priv->interrupt_processing_active = 0; | ||
1649 | |||
1650 | end_int_process: | ||
1651 | arlan_command_process(dev); | ||
1652 | |||
1653 | ARLAN_DEBUG_EXIT("arlan_process_interrupt"); | ||
1654 | return; | ||
1655 | } | ||
1656 | |||
1657 | static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1658 | { | ||
1659 | struct net_device *dev = dev_id; | ||
1660 | struct arlan_private *priv = netdev_priv(dev); | ||
1661 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
1662 | u_char rxStatus = READSHMB(arlan->rxStatus); | ||
1663 | u_char txStatus = READSHMB(arlan->txStatus); | ||
1664 | |||
1665 | ARLAN_DEBUG_ENTRY("arlan_interrupt"); | ||
1666 | |||
1667 | |||
1668 | if (!rxStatus && !txStatus) | ||
1669 | priv->interrupt_ack_requested++; | ||
1670 | |||
1671 | arlan_process_interrupt(dev); | ||
1672 | |||
1673 | priv->irq_test_done = 1; | ||
1674 | |||
1675 | ARLAN_DEBUG_EXIT("arlan_interrupt"); | ||
1676 | return IRQ_HANDLED; | ||
1677 | |||
1678 | } | ||
1679 | |||
1680 | |||
1681 | static int arlan_close(struct net_device *dev) | ||
1682 | { | ||
1683 | struct arlan_private *priv = netdev_priv(dev); | ||
1684 | |||
1685 | ARLAN_DEBUG_ENTRY("arlan_close"); | ||
1686 | |||
1687 | del_timer_sync(&priv->timer); | ||
1688 | |||
1689 | arlan_command(dev, ARLAN_COMMAND_POWERDOWN); | ||
1690 | |||
1691 | IFDEBUG(ARLAN_DEBUG_STARTUP) | ||
1692 | printk(KERN_NOTICE "%s: Closing device\n", dev->name); | ||
1693 | |||
1694 | netif_stop_queue(dev); | ||
1695 | free_irq(dev->irq, dev); | ||
1696 | |||
1697 | ARLAN_DEBUG_EXIT("arlan_close"); | ||
1698 | return 0; | ||
1699 | } | ||
1700 | |||
1701 | #ifdef ARLAN_DEBUGGING | ||
1702 | static long alignLong(volatile u_char * ptr) | ||
1703 | { | ||
1704 | long ret; | ||
1705 | memcpy_fromio(&ret, (void *) ptr, 4); | ||
1706 | return ret; | ||
1707 | } | ||
1708 | #endif | ||
1709 | |||
1710 | /* | ||
1711 | * Get the current statistics. | ||
1712 | * This may be called with the card open or closed. | ||
1713 | */ | ||
1714 | |||
1715 | static struct net_device_stats *arlan_statistics(struct net_device *dev) | ||
1716 | { | ||
1717 | struct arlan_private *priv = netdev_priv(dev); | ||
1718 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
1719 | |||
1720 | |||
1721 | ARLAN_DEBUG_ENTRY("arlan_statistics"); | ||
1722 | |||
1723 | /* Update the statistics from the device registers. */ | ||
1724 | |||
1725 | READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); | ||
1726 | READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); | ||
1727 | READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); | ||
1728 | READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); | ||
1729 | READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); | ||
1730 | READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); | ||
1731 | READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); | ||
1732 | READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); | ||
1733 | READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); | ||
1734 | READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); | ||
1735 | READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); | ||
1736 | READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); | ||
1737 | READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); | ||
1738 | |||
1739 | ARLAN_DEBUG_EXIT("arlan_statistics"); | ||
1740 | |||
1741 | return &priv->stats; | ||
1742 | } | ||
1743 | |||
1744 | |||
1745 | static void arlan_set_multicast(struct net_device *dev) | ||
1746 | { | ||
1747 | struct arlan_private *priv = netdev_priv(dev); | ||
1748 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
1749 | struct arlan_conf_stru *conf = priv->Conf; | ||
1750 | int board_conf_needed = 0; | ||
1751 | |||
1752 | |||
1753 | ARLAN_DEBUG_ENTRY("arlan_set_multicast"); | ||
1754 | |||
1755 | if (dev->flags & IFF_PROMISC) | ||
1756 | { | ||
1757 | unsigned char recMode; | ||
1758 | READSHM(recMode, arlan->receiveMode, u_char); | ||
1759 | conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL); | ||
1760 | if (conf->receiveMode != recMode) | ||
1761 | board_conf_needed = 1; | ||
1762 | } | ||
1763 | else | ||
1764 | { | ||
1765 | /* turn off promiscuous mode */ | ||
1766 | unsigned char recMode; | ||
1767 | READSHM(recMode, arlan->receiveMode, u_char); | ||
1768 | conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL; | ||
1769 | if (conf->receiveMode != recMode) | ||
1770 | board_conf_needed = 1; | ||
1771 | } | ||
1772 | if (board_conf_needed) | ||
1773 | arlan_command(dev, ARLAN_COMMAND_CONF); | ||
1774 | |||
1775 | ARLAN_DEBUG_EXIT("arlan_set_multicast"); | ||
1776 | } | ||
1777 | |||
1778 | |||
1779 | struct net_device * __init arlan_probe(int unit) | ||
1780 | { | ||
1781 | struct net_device *dev; | ||
1782 | int err; | ||
1783 | int m; | ||
1784 | |||
1785 | ARLAN_DEBUG_ENTRY("arlan_probe"); | ||
1786 | |||
1787 | if (arlans_found == MAX_ARLANS) | ||
1788 | return ERR_PTR(-ENODEV); | ||
1789 | |||
1790 | /* | ||
1791 | * Reserve space for local data and a copy of the shared memory | ||
1792 | * that is used by the /proc interface. | ||
1793 | */ | ||
1794 | dev = alloc_etherdev(sizeof(struct arlan_private) | ||
1795 | + sizeof(struct arlan_shmem)); | ||
1796 | if (!dev) | ||
1797 | return ERR_PTR(-ENOMEM); | ||
1798 | |||
1799 | SET_MODULE_OWNER(dev); | ||
1800 | |||
1801 | if (unit >= 0) { | ||
1802 | sprintf(dev->name, "eth%d", unit); | ||
1803 | netdev_boot_setup_check(dev); | ||
1804 | |||
1805 | if (dev->mem_start) { | ||
1806 | if (arlan_probe_here(dev, dev->mem_start) == 0) | ||
1807 | goto found; | ||
1808 | goto not_found; | ||
1809 | } | ||
1810 | |||
1811 | } | ||
1812 | |||
1813 | |||
1814 | for (m = (int)phys_to_virt(lastFoundAt) + ARLAN_SHMEM_SIZE; | ||
1815 | m <= (int)phys_to_virt(0xDE000); | ||
1816 | m += ARLAN_SHMEM_SIZE) | ||
1817 | { | ||
1818 | if (arlan_probe_here(dev, m) == 0) | ||
1819 | { | ||
1820 | lastFoundAt = (int)virt_to_phys((void*)m); | ||
1821 | goto found; | ||
1822 | } | ||
1823 | } | ||
1824 | |||
1825 | if (lastFoundAt == 0xbe000) | ||
1826 | printk(KERN_ERR "arlan: No Arlan devices found \n"); | ||
1827 | |||
1828 | not_found: | ||
1829 | free_netdev(dev); | ||
1830 | return ERR_PTR(-ENODEV); | ||
1831 | |||
1832 | found: | ||
1833 | err = arlan_setup_device(dev, arlans_found); | ||
1834 | if (err) | ||
1835 | dev = ERR_PTR(err); | ||
1836 | else if (!arlans_found++) | ||
1837 | printk(KERN_INFO "Arlan driver %s\n", arlan_version); | ||
1838 | |||
1839 | return dev; | ||
1840 | } | ||
1841 | |||
1842 | #ifdef MODULE | ||
1843 | int init_module(void) | ||
1844 | { | ||
1845 | int i = 0; | ||
1846 | |||
1847 | ARLAN_DEBUG_ENTRY("init_module"); | ||
1848 | |||
1849 | if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) | ||
1850 | return -EINVAL; | ||
1851 | |||
1852 | for (i = 0; i < MAX_ARLANS; i++) { | ||
1853 | struct net_device *dev = arlan_probe(i); | ||
1854 | |||
1855 | if (IS_ERR(dev)) | ||
1856 | return PTR_ERR(dev); | ||
1857 | } | ||
1858 | init_arlan_proc(); | ||
1859 | printk(KERN_INFO "Arlan driver %s\n", arlan_version); | ||
1860 | ARLAN_DEBUG_EXIT("init_module"); | ||
1861 | return 0; | ||
1862 | } | ||
1863 | |||
1864 | |||
1865 | void cleanup_module(void) | ||
1866 | { | ||
1867 | int i = 0; | ||
1868 | struct net_device *dev; | ||
1869 | |||
1870 | ARLAN_DEBUG_ENTRY("cleanup_module"); | ||
1871 | |||
1872 | IFDEBUG(ARLAN_DEBUG_SHUTDOWN) | ||
1873 | printk(KERN_INFO "arlan: unloading module\n"); | ||
1874 | |||
1875 | cleanup_arlan_proc(); | ||
1876 | |||
1877 | for (i = 0; i < MAX_ARLANS; i++) | ||
1878 | { | ||
1879 | dev = arlan_device[i]; | ||
1880 | if (dev) { | ||
1881 | arlan_command(dev, ARLAN_COMMAND_POWERDOWN ); | ||
1882 | |||
1883 | unregister_netdev(dev); | ||
1884 | release_mem_region(virt_to_phys((void *) dev->mem_start), | ||
1885 | ARLAN_SHMEM_SIZE); | ||
1886 | free_netdev(dev); | ||
1887 | arlan_device[i] = NULL; | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | ARLAN_DEBUG_EXIT("cleanup_module"); | ||
1892 | } | ||
1893 | |||
1894 | |||
1895 | #endif | ||
1896 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c new file mode 100644 index 000000000000..a2cca521f444 --- /dev/null +++ b/drivers/net/wireless/arlan-proc.c | |||
@@ -0,0 +1,1262 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include "arlan.h" | ||
3 | |||
4 | #include <linux/sysctl.h> | ||
5 | |||
6 | #ifdef CONFIG_PROC_FS | ||
7 | |||
8 | /* void enableReceive(struct net_device* dev); | ||
9 | */ | ||
10 | |||
11 | |||
12 | |||
13 | #define ARLAN_STR_SIZE 0x2ff0 | ||
14 | #define DEV_ARLAN_INFO 1 | ||
15 | #define DEV_ARLAN 1 | ||
16 | #define SARLG(type,var) {\ | ||
17 | pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var)); \ | ||
18 | } | ||
19 | |||
20 | #define SARLBN(type,var,nn) {\ | ||
21 | pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\ | ||
22 | for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ | ||
23 | pos += sprintf(arlan_drive_info+pos, "\n"); \ | ||
24 | } | ||
25 | |||
26 | #define SARLBNpln(type,var,nn) {\ | ||
27 | for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ | ||
28 | } | ||
29 | |||
30 | #define SARLSTR(var,nn) {\ | ||
31 | char tmpStr[400];\ | ||
32 | int tmpLn = nn;\ | ||
33 | if (nn > 399 ) tmpLn = 399; \ | ||
34 | memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\ | ||
35 | tmpStr[tmpLn] = 0; \ | ||
36 | pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\ | ||
37 | } | ||
38 | |||
39 | #define SARLUC(var) SARLG(u_char, var) | ||
40 | #define SARLUCN(var,nn) SARLBN(u_char,var, nn) | ||
41 | #define SARLUS(var) SARLG(u_short, var) | ||
42 | #define SARLUSN(var,nn) SARLBN(u_short,var, nn) | ||
43 | #define SARLUI(var) SARLG(u_int, var) | ||
44 | |||
45 | #define SARLUSA(var) {\ | ||
46 | u_short tmpVar;\ | ||
47 | memcpy(&tmpVar, (short *) priva->conf->var,2); \ | ||
48 | pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ | ||
49 | } | ||
50 | |||
51 | #define SARLUIA(var) {\ | ||
52 | u_int tmpVar;\ | ||
53 | memcpy(&tmpVar, (int* )priva->conf->var,4); \ | ||
54 | pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ | ||
55 | } | ||
56 | |||
57 | |||
58 | static const char *arlan_diagnostic_info_string(struct net_device *dev) | ||
59 | { | ||
60 | |||
61 | struct arlan_private *priv = netdev_priv(dev); | ||
62 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
63 | u_char diagnosticInfo; | ||
64 | |||
65 | READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); | ||
66 | |||
67 | switch (diagnosticInfo) | ||
68 | { | ||
69 | case 0xFF: | ||
70 | return "Diagnostic info is OK"; | ||
71 | case 0xFE: | ||
72 | return "ERROR EPROM Checksum error "; | ||
73 | case 0xFD: | ||
74 | return "ERROR Local Ram Test Failed "; | ||
75 | case 0xFC: | ||
76 | return "ERROR SCC failure "; | ||
77 | case 0xFB: | ||
78 | return "ERROR BackBone failure "; | ||
79 | case 0xFA: | ||
80 | return "ERROR transceiver not found "; | ||
81 | case 0xF9: | ||
82 | return "ERROR no more address space "; | ||
83 | case 0xF8: | ||
84 | return "ERROR Checksum error "; | ||
85 | case 0xF7: | ||
86 | return "ERROR Missing SS Code"; | ||
87 | case 0xF6: | ||
88 | return "ERROR Invalid config format"; | ||
89 | case 0xF5: | ||
90 | return "ERROR Reserved errorcode F5"; | ||
91 | case 0xF4: | ||
92 | return "ERROR Invalid spreading code/channel number"; | ||
93 | case 0xF3: | ||
94 | return "ERROR Load Code Error"; | ||
95 | case 0xF2: | ||
96 | return "ERROR Reserver errorcode F2 "; | ||
97 | case 0xF1: | ||
98 | return "ERROR Invalid command receivec by LAN card "; | ||
99 | case 0xF0: | ||
100 | return "ERROR Invalid parameter found in command "; | ||
101 | case 0xEF: | ||
102 | return "ERROR On-chip timer failure "; | ||
103 | case 0xEE: | ||
104 | return "ERROR T410 timer failure "; | ||
105 | case 0xED: | ||
106 | return "ERROR Too Many TxEnable commands "; | ||
107 | case 0xEC: | ||
108 | return "ERROR EEPROM error on radio module "; | ||
109 | default: | ||
110 | return "ERROR unknown Diagnostic info reply code "; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | static const char *arlan_hardware_type_string(struct net_device *dev) | ||
115 | { | ||
116 | u_char hardwareType; | ||
117 | struct arlan_private *priv = netdev_priv(dev); | ||
118 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
119 | |||
120 | READSHM(hardwareType, arlan->hardwareType, u_char); | ||
121 | switch (hardwareType) | ||
122 | { | ||
123 | case 0x00: | ||
124 | return "type A450"; | ||
125 | case 0x01: | ||
126 | return "type A650 "; | ||
127 | case 0x04: | ||
128 | return "type TMA coproc"; | ||
129 | case 0x0D: | ||
130 | return "type A650E "; | ||
131 | case 0x18: | ||
132 | return "type TMA coproc Australian"; | ||
133 | case 0x19: | ||
134 | return "type A650A "; | ||
135 | case 0x26: | ||
136 | return "type TMA coproc European"; | ||
137 | case 0x2E: | ||
138 | return "type A655 "; | ||
139 | case 0x2F: | ||
140 | return "type A655A "; | ||
141 | case 0x30: | ||
142 | return "type A655E "; | ||
143 | case 0x0B: | ||
144 | return "type A670 "; | ||
145 | case 0x0C: | ||
146 | return "type A670E "; | ||
147 | case 0x2D: | ||
148 | return "type A670A "; | ||
149 | case 0x0F: | ||
150 | return "type A411T"; | ||
151 | case 0x16: | ||
152 | return "type A411TA"; | ||
153 | case 0x1B: | ||
154 | return "type A440T"; | ||
155 | case 0x1C: | ||
156 | return "type A412T"; | ||
157 | case 0x1E: | ||
158 | return "type A412TA"; | ||
159 | case 0x22: | ||
160 | return "type A411TE"; | ||
161 | case 0x24: | ||
162 | return "type A412TE"; | ||
163 | case 0x27: | ||
164 | return "type A671T "; | ||
165 | case 0x29: | ||
166 | return "type A671TA "; | ||
167 | case 0x2B: | ||
168 | return "type A671TE "; | ||
169 | case 0x31: | ||
170 | return "type A415T "; | ||
171 | case 0x33: | ||
172 | return "type A415TA "; | ||
173 | case 0x35: | ||
174 | return "type A415TE "; | ||
175 | case 0x37: | ||
176 | return "type A672"; | ||
177 | case 0x39: | ||
178 | return "type A672A "; | ||
179 | case 0x3B: | ||
180 | return "type A672T"; | ||
181 | case 0x6B: | ||
182 | return "type IC2200"; | ||
183 | default: | ||
184 | return "type A672T"; | ||
185 | } | ||
186 | } | ||
187 | #ifdef ARLAN_DEBUGGING | ||
188 | static void arlan_print_diagnostic_info(struct net_device *dev) | ||
189 | { | ||
190 | int i; | ||
191 | u_char diagnosticInfo; | ||
192 | u_short diagnosticOffset; | ||
193 | u_char hardwareType; | ||
194 | struct arlan_private *priv = netdev_priv(dev); | ||
195 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
196 | |||
197 | // ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info"); | ||
198 | |||
199 | if (READSHMB(arlan->configuredStatusFlag) == 0) | ||
200 | printk("Arlan: Card NOT configured\n"); | ||
201 | else | ||
202 | printk("Arlan: Card is configured\n"); | ||
203 | |||
204 | READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); | ||
205 | READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short); | ||
206 | |||
207 | printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev)); | ||
208 | |||
209 | if (diagnosticInfo != 0xff) | ||
210 | printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset); | ||
211 | |||
212 | printk("arlan: LAN CODE ID = "); | ||
213 | for (i = 0; i < 6; i++) | ||
214 | DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char); | ||
215 | printk("\n"); | ||
216 | |||
217 | printk("arlan: Arlan BroadCast address = "); | ||
218 | for (i = 0; i < 6; i++) | ||
219 | DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char); | ||
220 | printk("\n"); | ||
221 | |||
222 | READSHM(hardwareType, arlan->hardwareType, u_char); | ||
223 | printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev)); | ||
224 | |||
225 | |||
226 | DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char); | ||
227 | DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char); | ||
228 | DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char); | ||
229 | DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short); | ||
230 | DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short); | ||
231 | DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short); | ||
232 | |||
233 | DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char); | ||
234 | |||
235 | printk("arlan: name= "); | ||
236 | IFDEBUG(1) | ||
237 | |||
238 | for (i = 0; i < 16; i++) | ||
239 | { | ||
240 | char c; | ||
241 | READSHM(c, arlan->name[i], char); | ||
242 | if (c) | ||
243 | printk("%c", c); | ||
244 | } | ||
245 | printk("\n"); | ||
246 | |||
247 | // ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info"); | ||
248 | |||
249 | } | ||
250 | |||
251 | |||
252 | /****************************** TEST MEMORY **************/ | ||
253 | |||
254 | static int arlan_hw_test_memory(struct net_device *dev) | ||
255 | { | ||
256 | u_char *ptr; | ||
257 | int i; | ||
258 | int memlen = sizeof(struct arlan_shmem) - 0xF; /* avoid control register */ | ||
259 | volatile char *arlan_mem = (char *) (dev->mem_start); | ||
260 | struct arlan_private *priv = netdev_priv(dev); | ||
261 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
262 | char pattern; | ||
263 | |||
264 | ptr = NULL; | ||
265 | |||
266 | /* hold card in reset state */ | ||
267 | setHardwareReset(dev); | ||
268 | |||
269 | /* test memory */ | ||
270 | pattern = 0; | ||
271 | for (i = 0; i < memlen; i++) | ||
272 | WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char); | ||
273 | |||
274 | pattern = 0; | ||
275 | for (i = 0; i < memlen; i++) | ||
276 | { | ||
277 | char res; | ||
278 | READSHM(res, arlan_mem[i], char); | ||
279 | if (res != pattern++) | ||
280 | { | ||
281 | printk(KERN_ERR "Arlan driver memory test 1 failed \n"); | ||
282 | return -1; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | pattern = 0; | ||
287 | for (i = 0; i < memlen; i++) | ||
288 | WRITESHM(arlan_mem[i], ~(pattern++), char); | ||
289 | |||
290 | pattern = 0; | ||
291 | for (i = 0; i < memlen; i++) | ||
292 | { | ||
293 | char res; | ||
294 | READSHM(res, arlan_mem[i], char); | ||
295 | if (res != ~(pattern++)) | ||
296 | { | ||
297 | printk(KERN_ERR "Arlan driver memory test 2 failed \n"); | ||
298 | return -1; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | /* zero memory */ | ||
303 | for (i = 0; i < memlen; i++) | ||
304 | WRITESHM(arlan_mem[i], 0x00, char); | ||
305 | |||
306 | IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n"); | ||
307 | |||
308 | /* set reset flag and then release reset */ | ||
309 | WRITESHM(arlan->resetFlag, 0xff, u_char); | ||
310 | |||
311 | clearChannelAttention(dev); | ||
312 | clearHardwareReset(dev); | ||
313 | |||
314 | /* wait for reset flag to become zero, we'll wait for two seconds */ | ||
315 | if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW)) | ||
316 | { | ||
317 | printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name); | ||
318 | return -1; | ||
319 | } | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int arlan_setup_card_by_book(struct net_device *dev) | ||
324 | { | ||
325 | u_char irqLevel, configuredStatusFlag; | ||
326 | struct arlan_private *priv = netdev_priv(dev); | ||
327 | volatile struct arlan_shmem __iomem *arlan = priv->card; | ||
328 | |||
329 | // ARLAN_DEBUG_ENTRY("arlan_setup_card"); | ||
330 | |||
331 | READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); | ||
332 | |||
333 | IFDEBUG(10) | ||
334 | if (configuredStatusFlag != 0) | ||
335 | IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n"); | ||
336 | else | ||
337 | IFDEBUG(10) printk("arlan: card is NOT configured\n"); | ||
338 | |||
339 | if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff)) | ||
340 | if (arlan_hw_test_memory(dev)) | ||
341 | return -1; | ||
342 | |||
343 | DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); | ||
344 | DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); | ||
345 | |||
346 | /* issue nop command - no interrupt */ | ||
347 | arlan_command(dev, ARLAN_COMMAND_NOOP); | ||
348 | if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) | ||
349 | return -1; | ||
350 | |||
351 | IFDEBUG(50) printk("1st Noop successfully executed !!\n"); | ||
352 | |||
353 | /* try to turn on the arlan interrupts */ | ||
354 | clearClearInterrupt(dev); | ||
355 | setClearInterrupt(dev); | ||
356 | setInterruptEnable(dev); | ||
357 | |||
358 | /* issue nop command - with interrupt */ | ||
359 | |||
360 | arlan_command(dev, ARLAN_COMMAND_NOOPINT); | ||
361 | if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) | ||
362 | return -1; | ||
363 | |||
364 | |||
365 | IFDEBUG(50) printk("2nd Noop successfully executed !!\n"); | ||
366 | |||
367 | READSHM(irqLevel, arlan->irqLevel, u_char) | ||
368 | |||
369 | if (irqLevel != dev->irq) | ||
370 | { | ||
371 | IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel); | ||
372 | printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq); | ||
373 | dev->irq = irqLevel; | ||
374 | } | ||
375 | else | ||
376 | IFDEBUG(2) printk("irq level is OK\n"); | ||
377 | |||
378 | |||
379 | IFDEBUG(3) arlan_print_diagnostic_info(dev); | ||
380 | |||
381 | arlan_command(dev, ARLAN_COMMAND_CONF); | ||
382 | |||
383 | READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); | ||
384 | if (configuredStatusFlag == 0) | ||
385 | { | ||
386 | printk(KERN_WARNING "arlan configure failed\n"); | ||
387 | return -1; | ||
388 | } | ||
389 | arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); | ||
390 | arlan_command(dev, ARLAN_COMMAND_RX); | ||
391 | arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); | ||
392 | printk(KERN_NOTICE "%s: arlan driver version %s loaded\n", | ||
393 | dev->name, arlan_version); | ||
394 | |||
395 | // ARLAN_DEBUG_EXIT("arlan_setup_card"); | ||
396 | |||
397 | return 0; /* no errors */ | ||
398 | } | ||
399 | #endif | ||
400 | |||
401 | #ifdef ARLAN_PROC_INTERFACE | ||
402 | #ifdef ARLAN_PROC_SHM_DUMP | ||
403 | |||
404 | static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0"; | ||
405 | |||
406 | static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp, | ||
407 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
408 | { | ||
409 | int i; | ||
410 | int retv, pos, devnum; | ||
411 | struct arlan_private *priva = NULL; | ||
412 | struct net_device *dev; | ||
413 | pos = 0; | ||
414 | if (write) | ||
415 | { | ||
416 | printk("wrirte: "); | ||
417 | for (i = 0; i < 100; i++) | ||
418 | printk("adi %x \n", arlan_drive_info[i]); | ||
419 | } | ||
420 | if (ctl->procname == NULL || arlan_drive_info == NULL) | ||
421 | { | ||
422 | printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n "); | ||
423 | return -1; | ||
424 | } | ||
425 | devnum = ctl->procname[5] - '0'; | ||
426 | if (devnum < 0 || devnum > MAX_ARLANS - 1) | ||
427 | { | ||
428 | printk(KERN_WARNING "too strange devnum in procfs parse\n "); | ||
429 | return -1; | ||
430 | } | ||
431 | else if (arlan_device[devnum] == NULL) | ||
432 | { | ||
433 | if (ctl->procname) | ||
434 | pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname); | ||
435 | pos += sprintf(arlan_drive_info + pos, "No device found here \n"); | ||
436 | goto final; | ||
437 | } | ||
438 | else | ||
439 | priva = arlan_device[devnum]->priv; | ||
440 | |||
441 | if (priva == NULL) | ||
442 | { | ||
443 | printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); | ||
444 | return -1; | ||
445 | } | ||
446 | dev = arlan_device[devnum]; | ||
447 | |||
448 | memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); | ||
449 | |||
450 | pos = sprintf(arlan_drive_info, "Arlan info \n"); | ||
451 | /* Header Signature */ | ||
452 | SARLSTR(textRegion, 48); | ||
453 | SARLUC(resetFlag); | ||
454 | pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev)); | ||
455 | SARLUC(diagnosticInfo); | ||
456 | SARLUS(diagnosticOffset); | ||
457 | SARLUCN(_1, 12); | ||
458 | SARLUCN(lanCardNodeId, 6); | ||
459 | SARLUCN(broadcastAddress, 6); | ||
460 | pos += sprintf(arlan_drive_info + pos, "hardwareType =\t %s \n", arlan_hardware_type_string(dev)); | ||
461 | SARLUC(hardwareType); | ||
462 | SARLUC(majorHardwareVersion); | ||
463 | SARLUC(minorHardwareVersion); | ||
464 | SARLUC(radioModule); | ||
465 | SARLUC(defaultChannelSet); | ||
466 | SARLUCN(_2, 47); | ||
467 | |||
468 | /* Control/Status Block - 0x0080 */ | ||
469 | SARLUC(interruptInProgress); | ||
470 | SARLUC(cntrlRegImage); | ||
471 | |||
472 | SARLUCN(_3, 14); | ||
473 | SARLUC(commandByte); | ||
474 | SARLUCN(commandParameter, 15); | ||
475 | |||
476 | /* Receive Status - 0x00a0 */ | ||
477 | SARLUC(rxStatus); | ||
478 | SARLUC(rxFrmType); | ||
479 | SARLUS(rxOffset); | ||
480 | SARLUS(rxLength); | ||
481 | SARLUCN(rxSrc, 6); | ||
482 | SARLUC(rxBroadcastFlag); | ||
483 | SARLUC(rxQuality); | ||
484 | SARLUC(scrambled); | ||
485 | SARLUCN(_4, 1); | ||
486 | |||
487 | /* Transmit Status - 0x00b0 */ | ||
488 | SARLUC(txStatus); | ||
489 | SARLUC(txAckQuality); | ||
490 | SARLUC(numRetries); | ||
491 | SARLUCN(_5, 14); | ||
492 | SARLUCN(registeredRouter, 6); | ||
493 | SARLUCN(backboneRouter, 6); | ||
494 | SARLUC(registrationStatus); | ||
495 | SARLUC(configuredStatusFlag); | ||
496 | SARLUCN(_6, 1); | ||
497 | SARLUCN(ultimateDestAddress, 6); | ||
498 | SARLUCN(immedDestAddress, 6); | ||
499 | SARLUCN(immedSrcAddress, 6); | ||
500 | SARLUS(rxSequenceNumber); | ||
501 | SARLUC(assignedLocaltalkAddress); | ||
502 | SARLUCN(_7, 27); | ||
503 | |||
504 | /* System Parameter Block */ | ||
505 | |||
506 | /* - Driver Parameters (Novell Specific) */ | ||
507 | |||
508 | SARLUS(txTimeout); | ||
509 | SARLUS(transportTime); | ||
510 | SARLUCN(_8, 4); | ||
511 | |||
512 | /* - Configuration Parameters */ | ||
513 | SARLUC(irqLevel); | ||
514 | SARLUC(spreadingCode); | ||
515 | SARLUC(channelSet); | ||
516 | SARLUC(channelNumber); | ||
517 | SARLUS(radioNodeId); | ||
518 | SARLUCN(_9, 2); | ||
519 | SARLUC(scramblingDisable); | ||
520 | SARLUC(radioType); | ||
521 | SARLUS(routerId); | ||
522 | SARLUCN(_10, 9); | ||
523 | SARLUC(txAttenuation); | ||
524 | SARLUIA(systemId); | ||
525 | SARLUS(globalChecksum); | ||
526 | SARLUCN(_11, 4); | ||
527 | SARLUS(maxDatagramSize); | ||
528 | SARLUS(maxFrameSize); | ||
529 | SARLUC(maxRetries); | ||
530 | SARLUC(receiveMode); | ||
531 | SARLUC(priority); | ||
532 | SARLUC(rootOrRepeater); | ||
533 | SARLUCN(specifiedRouter, 6); | ||
534 | SARLUS(fastPollPeriod); | ||
535 | SARLUC(pollDecay); | ||
536 | SARLUSA(fastPollDelay); | ||
537 | SARLUC(arlThreshold); | ||
538 | SARLUC(arlDecay); | ||
539 | SARLUCN(_12, 1); | ||
540 | SARLUS(specRouterTimeout); | ||
541 | SARLUCN(_13, 5); | ||
542 | |||
543 | /* Scrambled Area */ | ||
544 | SARLUIA(SID); | ||
545 | SARLUCN(encryptionKey, 12); | ||
546 | SARLUIA(_14); | ||
547 | SARLUSA(waitTime); | ||
548 | SARLUSA(lParameter); | ||
549 | SARLUCN(_15, 3); | ||
550 | SARLUS(headerSize); | ||
551 | SARLUS(sectionChecksum); | ||
552 | |||
553 | SARLUC(registrationMode); | ||
554 | SARLUC(registrationFill); | ||
555 | SARLUS(pollPeriod); | ||
556 | SARLUS(refreshPeriod); | ||
557 | SARLSTR(name, 16); | ||
558 | SARLUCN(NID, 6); | ||
559 | SARLUC(localTalkAddress); | ||
560 | SARLUC(codeFormat); | ||
561 | SARLUC(numChannels); | ||
562 | SARLUC(channel1); | ||
563 | SARLUC(channel2); | ||
564 | SARLUC(channel3); | ||
565 | SARLUC(channel4); | ||
566 | SARLUCN(SSCode, 59); | ||
567 | |||
568 | /* SARLUCN( _16, 0x140); | ||
569 | */ | ||
570 | /* Statistics Block - 0x0300 */ | ||
571 | SARLUC(hostcpuLock); | ||
572 | SARLUC(lancpuLock); | ||
573 | SARLUCN(resetTime, 18); | ||
574 | SARLUIA(numDatagramsTransmitted); | ||
575 | SARLUIA(numReTransmissions); | ||
576 | SARLUIA(numFramesDiscarded); | ||
577 | SARLUIA(numDatagramsReceived); | ||
578 | SARLUIA(numDuplicateReceivedFrames); | ||
579 | SARLUIA(numDatagramsDiscarded); | ||
580 | SARLUS(maxNumReTransmitDatagram); | ||
581 | SARLUS(maxNumReTransmitFrames); | ||
582 | SARLUS(maxNumConsecutiveDuplicateFrames); | ||
583 | /* misaligned here so we have to go to characters */ | ||
584 | SARLUIA(numBytesTransmitted); | ||
585 | SARLUIA(numBytesReceived); | ||
586 | SARLUIA(numCRCErrors); | ||
587 | SARLUIA(numLengthErrors); | ||
588 | SARLUIA(numAbortErrors); | ||
589 | SARLUIA(numTXUnderruns); | ||
590 | SARLUIA(numRXOverruns); | ||
591 | SARLUIA(numHoldOffs); | ||
592 | SARLUIA(numFramesTransmitted); | ||
593 | SARLUIA(numFramesReceived); | ||
594 | SARLUIA(numReceiveFramesLost); | ||
595 | SARLUIA(numRXBufferOverflows); | ||
596 | SARLUIA(numFramesDiscardedAddrMismatch); | ||
597 | SARLUIA(numFramesDiscardedSIDMismatch); | ||
598 | SARLUIA(numPollsTransmistted); | ||
599 | SARLUIA(numPollAcknowledges); | ||
600 | SARLUIA(numStatusTimeouts); | ||
601 | SARLUIA(numNACKReceived); | ||
602 | SARLUS(auxCmd); | ||
603 | SARLUCN(dumpPtr, 4); | ||
604 | SARLUC(dumpVal); | ||
605 | SARLUC(wireTest); | ||
606 | |||
607 | /* next 4 seems too long for procfs, over single page ? | ||
608 | SARLUCN( _17, 0x86); | ||
609 | SARLUCN( txBuffer, 0x800); | ||
610 | SARLUCN( rxBuffer, 0x800); | ||
611 | SARLUCN( _18, 0x0bff); | ||
612 | */ | ||
613 | |||
614 | pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x"); | ||
615 | for (i = 0; i < 0x50; i++) | ||
616 | pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]); | ||
617 | pos += sprintf(arlan_drive_info + pos, "\n"); | ||
618 | |||
619 | SARLUC(configStatus); | ||
620 | SARLUC(_22); | ||
621 | SARLUC(progIOCtrl); | ||
622 | SARLUC(shareMBase); | ||
623 | SARLUC(controlRegister); | ||
624 | |||
625 | pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos); | ||
626 | if (ctl) | ||
627 | if (ctl->procname) | ||
628 | pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname); | ||
629 | final: | ||
630 | *lenp = pos; | ||
631 | |||
632 | if (!write) | ||
633 | retv = proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
634 | else | ||
635 | { | ||
636 | *lenp = 0; | ||
637 | return -1; | ||
638 | } | ||
639 | return retv; | ||
640 | } | ||
641 | |||
642 | |||
643 | static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp, | ||
644 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
645 | { | ||
646 | int i; | ||
647 | int retv, pos, devnum; | ||
648 | struct arlan_private *priva = NULL; | ||
649 | |||
650 | pos = 0; | ||
651 | devnum = ctl->procname[5] - '0'; | ||
652 | if (arlan_device[devnum] == NULL) | ||
653 | { | ||
654 | pos += sprintf(arlan_drive_info + pos, "No device found here \n"); | ||
655 | goto final; | ||
656 | } | ||
657 | else | ||
658 | priva = arlan_device[devnum]->priv; | ||
659 | if (priva == NULL) | ||
660 | { | ||
661 | printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); | ||
662 | return -1; | ||
663 | } | ||
664 | memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); | ||
665 | SARLUCN(_16, 0xC0); | ||
666 | SARLUCN(_17, 0x6A); | ||
667 | SARLUCN(_18, 14); | ||
668 | SARLUCN(_19, 0x86); | ||
669 | SARLUCN(_21, 0x3fd); | ||
670 | |||
671 | final: | ||
672 | *lenp = pos; | ||
673 | retv = proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
674 | return retv; | ||
675 | } | ||
676 | |||
677 | static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp, | ||
678 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
679 | { | ||
680 | int i; | ||
681 | int retv, pos, devnum; | ||
682 | struct arlan_private *priva = NULL; | ||
683 | |||
684 | pos = 0; | ||
685 | devnum = ctl->procname[5] - '0'; | ||
686 | if (arlan_device[devnum] == NULL) | ||
687 | { | ||
688 | pos += sprintf(arlan_drive_info + pos, "No device found here \n"); | ||
689 | goto final; | ||
690 | } | ||
691 | else | ||
692 | priva = arlan_device[devnum]->priv; | ||
693 | if (priva == NULL) | ||
694 | { | ||
695 | printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); | ||
696 | return -1; | ||
697 | } | ||
698 | memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); | ||
699 | SARLBNpln(u_char, txBuffer, 0x800); | ||
700 | final: | ||
701 | *lenp = pos; | ||
702 | retv = proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
703 | return retv; | ||
704 | } | ||
705 | |||
706 | static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp, | ||
707 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
708 | { | ||
709 | int i; | ||
710 | int retv, pos, devnum; | ||
711 | struct arlan_private *priva = NULL; | ||
712 | |||
713 | pos = 0; | ||
714 | devnum = ctl->procname[5] - '0'; | ||
715 | if (arlan_device[devnum] == NULL) | ||
716 | { | ||
717 | pos += sprintf(arlan_drive_info + pos, "No device found here \n"); | ||
718 | goto final; | ||
719 | } else | ||
720 | priva = arlan_device[devnum]->priv; | ||
721 | if (priva == NULL) | ||
722 | { | ||
723 | printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); | ||
724 | return -1; | ||
725 | } | ||
726 | memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); | ||
727 | SARLBNpln(u_char, rxBuffer, 0x800); | ||
728 | final: | ||
729 | *lenp = pos; | ||
730 | retv = proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
731 | return retv; | ||
732 | } | ||
733 | |||
734 | static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp, | ||
735 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
736 | { | ||
737 | int i; | ||
738 | int retv, pos, devnum; | ||
739 | struct arlan_private *priva = NULL; | ||
740 | |||
741 | pos = 0; | ||
742 | devnum = ctl->procname[5] - '0'; | ||
743 | if (arlan_device[devnum] == NULL) | ||
744 | { | ||
745 | pos += sprintf(arlan_drive_info + pos, "No device found here \n"); | ||
746 | goto final; | ||
747 | } | ||
748 | else | ||
749 | priva = arlan_device[devnum]->priv; | ||
750 | if (priva == NULL) | ||
751 | { | ||
752 | printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); | ||
753 | return -1; | ||
754 | } | ||
755 | memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); | ||
756 | SARLBNpln(u_char, _18, 0x800); | ||
757 | |||
758 | final: | ||
759 | *lenp = pos; | ||
760 | retv = proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
761 | return retv; | ||
762 | } | ||
763 | |||
764 | |||
765 | #endif /* #ifdef ARLAN_PROC_SHM_DUMP */ | ||
766 | |||
767 | |||
768 | static char conf_reset_result[200]; | ||
769 | |||
770 | static int arlan_configure(ctl_table * ctl, int write, struct file *filp, | ||
771 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
772 | { | ||
773 | int pos = 0; | ||
774 | int devnum = ctl->procname[6] - '0'; | ||
775 | struct arlan_private *priv; | ||
776 | |||
777 | if (devnum < 0 || devnum > MAX_ARLANS - 1) | ||
778 | { | ||
779 | printk(KERN_WARNING "too strange devnum in procfs parse\n "); | ||
780 | return -1; | ||
781 | } | ||
782 | else if (arlan_device[devnum] != NULL) | ||
783 | { | ||
784 | priv = arlan_device[devnum]->priv; | ||
785 | |||
786 | arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); | ||
787 | } | ||
788 | else | ||
789 | return -1; | ||
790 | |||
791 | *lenp = pos; | ||
792 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
793 | } | ||
794 | |||
795 | static int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, | ||
796 | void __user *buffer, size_t * lenp, loff_t *ppos) | ||
797 | { | ||
798 | int pos = 0; | ||
799 | int devnum = ctl->procname[5] - '0'; | ||
800 | struct arlan_private *priv; | ||
801 | |||
802 | if (devnum < 0 || devnum > MAX_ARLANS - 1) | ||
803 | { | ||
804 | printk(KERN_WARNING "too strange devnum in procfs parse\n "); | ||
805 | return -1; | ||
806 | } | ||
807 | else if (arlan_device[devnum] != NULL) | ||
808 | { | ||
809 | priv = arlan_device[devnum]->priv; | ||
810 | arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); | ||
811 | |||
812 | } else | ||
813 | return -1; | ||
814 | *lenp = pos + 3; | ||
815 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
816 | } | ||
817 | |||
818 | |||
819 | /* Place files in /proc/sys/dev/arlan */ | ||
820 | #define CTBLN(num,card,nam) \ | ||
821 | { .ctl_name = num,\ | ||
822 | .procname = #nam,\ | ||
823 | .data = &(arlan_conf[card].nam),\ | ||
824 | .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec} | ||
825 | #ifdef ARLAN_DEBUGGING | ||
826 | |||
827 | #define ARLAN_PROC_DEBUG_ENTRIES \ | ||
828 | { .ctl_name = 48, .procname = "entry_exit_debug",\ | ||
829 | .data = &arlan_entry_and_exit_debug,\ | ||
830 | .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec},\ | ||
831 | { .ctl_name = 49, .procname = "debug", .data = &arlan_debug,\ | ||
832 | .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec}, | ||
833 | #else | ||
834 | #define ARLAN_PROC_DEBUG_ENTRIES | ||
835 | #endif | ||
836 | |||
837 | #define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ | ||
838 | CTBLN(1,cardNo,spreadingCode),\ | ||
839 | CTBLN(2,cardNo, channelNumber),\ | ||
840 | CTBLN(3,cardNo, scramblingDisable),\ | ||
841 | CTBLN(4,cardNo, txAttenuation),\ | ||
842 | CTBLN(5,cardNo, systemId), \ | ||
843 | CTBLN(6,cardNo, maxDatagramSize),\ | ||
844 | CTBLN(7,cardNo, maxFrameSize),\ | ||
845 | CTBLN(8,cardNo, maxRetries),\ | ||
846 | CTBLN(9,cardNo, receiveMode),\ | ||
847 | CTBLN(10,cardNo, priority),\ | ||
848 | CTBLN(11,cardNo, rootOrRepeater),\ | ||
849 | CTBLN(12,cardNo, SID),\ | ||
850 | CTBLN(13,cardNo, registrationMode),\ | ||
851 | CTBLN(14,cardNo, registrationFill),\ | ||
852 | CTBLN(15,cardNo, localTalkAddress),\ | ||
853 | CTBLN(16,cardNo, codeFormat),\ | ||
854 | CTBLN(17,cardNo, numChannels),\ | ||
855 | CTBLN(18,cardNo, channel1),\ | ||
856 | CTBLN(19,cardNo, channel2),\ | ||
857 | CTBLN(20,cardNo, channel3),\ | ||
858 | CTBLN(21,cardNo, channel4),\ | ||
859 | CTBLN(22,cardNo, txClear),\ | ||
860 | CTBLN(23,cardNo, txRetries),\ | ||
861 | CTBLN(24,cardNo, txRouting),\ | ||
862 | CTBLN(25,cardNo, txScrambled),\ | ||
863 | CTBLN(26,cardNo, rxParameter),\ | ||
864 | CTBLN(27,cardNo, txTimeoutMs),\ | ||
865 | CTBLN(28,cardNo, waitCardTimeout),\ | ||
866 | CTBLN(29,cardNo, channelSet), \ | ||
867 | {.ctl_name = 30, .procname = "name",\ | ||
868 | .data = arlan_conf[cardNo].siteName,\ | ||
869 | .maxlen = 16, .mode = 0600, .proc_handler = &proc_dostring},\ | ||
870 | CTBLN(31,cardNo,waitTime),\ | ||
871 | CTBLN(32,cardNo,lParameter),\ | ||
872 | CTBLN(33,cardNo,_15),\ | ||
873 | CTBLN(34,cardNo,headerSize),\ | ||
874 | CTBLN(36,cardNo,tx_delay_ms),\ | ||
875 | CTBLN(37,cardNo,retries),\ | ||
876 | CTBLN(38,cardNo,ReTransmitPacketMaxSize),\ | ||
877 | CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\ | ||
878 | CTBLN(40,cardNo,fastReTransCount),\ | ||
879 | CTBLN(41,cardNo,driverRetransmissions),\ | ||
880 | CTBLN(42,cardNo,txAckTimeoutMs),\ | ||
881 | CTBLN(43,cardNo,registrationInterrupts),\ | ||
882 | CTBLN(44,cardNo,hardwareType),\ | ||
883 | CTBLN(45,cardNo,radioType),\ | ||
884 | CTBLN(46,cardNo,writeEEPROM),\ | ||
885 | CTBLN(47,cardNo,writeRadioType),\ | ||
886 | ARLAN_PROC_DEBUG_ENTRIES\ | ||
887 | CTBLN(50,cardNo,in_speed),\ | ||
888 | CTBLN(51,cardNo,out_speed),\ | ||
889 | CTBLN(52,cardNo,in_speed10),\ | ||
890 | CTBLN(53,cardNo,out_speed10),\ | ||
891 | CTBLN(54,cardNo,in_speed_max),\ | ||
892 | CTBLN(55,cardNo,out_speed_max),\ | ||
893 | CTBLN(56,cardNo,measure_rate),\ | ||
894 | CTBLN(57,cardNo,pre_Command_Wait),\ | ||
895 | CTBLN(58,cardNo,rx_tweak1),\ | ||
896 | CTBLN(59,cardNo,rx_tweak2),\ | ||
897 | CTBLN(60,cardNo,tx_queue_len),\ | ||
898 | |||
899 | |||
900 | |||
901 | static ctl_table arlan_conf_table0[] = | ||
902 | { | ||
903 | ARLAN_SYSCTL_TABLE_TOTAL(0) | ||
904 | |||
905 | #ifdef ARLAN_PROC_SHM_DUMP | ||
906 | { | ||
907 | .ctl_name = 150, | ||
908 | .procname = "arlan0-txRing", | ||
909 | .data = &arlan_drive_info, | ||
910 | .maxlen = ARLAN_STR_SIZE, | ||
911 | .mode = 0400, | ||
912 | .proc_handler = &arlan_sysctl_infotxRing, | ||
913 | }, | ||
914 | { | ||
915 | .ctl_name = 151, | ||
916 | .procname = "arlan0-rxRing", | ||
917 | .data = &arlan_drive_info, | ||
918 | .maxlen = ARLAN_STR_SIZE, | ||
919 | .mode = 0400, | ||
920 | .proc_handler = &arlan_sysctl_inforxRing, | ||
921 | }, | ||
922 | { | ||
923 | .ctl_name = 152, | ||
924 | .procname = "arlan0-18", | ||
925 | .data = &arlan_drive_info, | ||
926 | .maxlen = ARLAN_STR_SIZE, | ||
927 | .mode = 0400, | ||
928 | .proc_handler = &arlan_sysctl_info18, | ||
929 | }, | ||
930 | { | ||
931 | .ctl_name = 153, | ||
932 | .procname = "arlan0-ring", | ||
933 | .data = &arlan_drive_info, | ||
934 | .maxlen = ARLAN_STR_SIZE, | ||
935 | .mode = 0400, | ||
936 | .proc_handler = &arlan_sysctl_info161719, | ||
937 | }, | ||
938 | { | ||
939 | .ctl_name = 154, | ||
940 | .procname = "arlan0-shm-cpy", | ||
941 | .data = &arlan_drive_info, | ||
942 | .maxlen = ARLAN_STR_SIZE, | ||
943 | .mode = 0400, | ||
944 | .proc_handler = &arlan_sysctl_info, | ||
945 | }, | ||
946 | #endif | ||
947 | { | ||
948 | .ctl_name = 155, | ||
949 | .procname = "config0", | ||
950 | .data = &conf_reset_result, | ||
951 | .maxlen = 100, | ||
952 | .mode = 0400, | ||
953 | .proc_handler = &arlan_configure | ||
954 | }, | ||
955 | { | ||
956 | .ctl_name = 156, | ||
957 | .procname = "reset0", | ||
958 | .data = &conf_reset_result, | ||
959 | .maxlen = 100, | ||
960 | .mode = 0400, | ||
961 | .proc_handler = &arlan_sysctl_reset, | ||
962 | }, | ||
963 | { .ctl_name = 0 } | ||
964 | }; | ||
965 | |||
966 | static ctl_table arlan_conf_table1[] = | ||
967 | { | ||
968 | |||
969 | ARLAN_SYSCTL_TABLE_TOTAL(1) | ||
970 | |||
971 | #ifdef ARLAN_PROC_SHM_DUMP | ||
972 | { | ||
973 | .ctl_name = 150, | ||
974 | .procname = "arlan1-txRing", | ||
975 | .data = &arlan_drive_info, | ||
976 | .maxlen = ARLAN_STR_SIZE, | ||
977 | .mode = 0400, | ||
978 | .proc_handler = &arlan_sysctl_infotxRing, | ||
979 | }, | ||
980 | { | ||
981 | .ctl_name = 151, | ||
982 | .procname = "arlan1-rxRing", | ||
983 | .data = &arlan_drive_info, | ||
984 | .maxlen = ARLAN_STR_SIZE, | ||
985 | .mode = 0400, | ||
986 | .proc_handler = &arlan_sysctl_inforxRing, | ||
987 | }, | ||
988 | { | ||
989 | .ctl_name = 152, | ||
990 | .procname = "arlan1-18", | ||
991 | .data = &arlan_drive_info, | ||
992 | .maxlen = ARLAN_STR_SIZE, | ||
993 | .mode = 0400, | ||
994 | .proc_handler = &arlan_sysctl_info18, | ||
995 | }, | ||
996 | { | ||
997 | .ctl_name = 153, | ||
998 | .procname = "arlan1-ring", | ||
999 | .data = &arlan_drive_info, | ||
1000 | .maxlen = ARLAN_STR_SIZE, | ||
1001 | .mode = 0400, | ||
1002 | .proc_handler = &arlan_sysctl_info161719, | ||
1003 | }, | ||
1004 | { | ||
1005 | .ctl_name = 154, | ||
1006 | .procname = "arlan1-shm-cpy", | ||
1007 | .data = &arlan_drive_info, | ||
1008 | .maxlen = ARLAN_STR_SIZE, | ||
1009 | .mode = 0400, | ||
1010 | .proc_handler = &arlan_sysctl_info, | ||
1011 | }, | ||
1012 | #endif | ||
1013 | { | ||
1014 | .ctl_name = 155, | ||
1015 | .procname = "config1", | ||
1016 | .data = &conf_reset_result, | ||
1017 | .maxlen = 100, | ||
1018 | .mode = 0400, | ||
1019 | .proc_handler = &arlan_configure, | ||
1020 | }, | ||
1021 | { | ||
1022 | .ctl_name = 156, | ||
1023 | .procname = "reset1", | ||
1024 | .data = &conf_reset_result, | ||
1025 | .maxlen = 100, | ||
1026 | .mode = 0400, | ||
1027 | .proc_handler = &arlan_sysctl_reset, | ||
1028 | }, | ||
1029 | { .ctl_name = 0 } | ||
1030 | }; | ||
1031 | |||
1032 | static ctl_table arlan_conf_table2[] = | ||
1033 | { | ||
1034 | |||
1035 | ARLAN_SYSCTL_TABLE_TOTAL(2) | ||
1036 | |||
1037 | #ifdef ARLAN_PROC_SHM_DUMP | ||
1038 | { | ||
1039 | .ctl_name = 150, | ||
1040 | .procname = "arlan2-txRing", | ||
1041 | .data = &arlan_drive_info, | ||
1042 | .maxlen = ARLAN_STR_SIZE, | ||
1043 | .mode = 0400, | ||
1044 | .proc_handler = &arlan_sysctl_infotxRing, | ||
1045 | }, | ||
1046 | { | ||
1047 | .ctl_name = 151, | ||
1048 | .procname = "arlan2-rxRing", | ||
1049 | .data = &arlan_drive_info, | ||
1050 | .maxlen = ARLAN_STR_SIZE, | ||
1051 | .mode = 0400, | ||
1052 | .proc_handler = &arlan_sysctl_inforxRing, | ||
1053 | }, | ||
1054 | { | ||
1055 | .ctl_name = 152, | ||
1056 | .procname = "arlan2-18", | ||
1057 | .data = &arlan_drive_info, | ||
1058 | .maxlen = ARLAN_STR_SIZE, | ||
1059 | .mode = 0400, | ||
1060 | .proc_handler = &arlan_sysctl_info18, | ||
1061 | }, | ||
1062 | { | ||
1063 | .ctl_name = 153, | ||
1064 | .procname = "arlan2-ring", | ||
1065 | .data = &arlan_drive_info, | ||
1066 | .maxlen = ARLAN_STR_SIZE, | ||
1067 | .mode = 0400, | ||
1068 | .proc_handler = &arlan_sysctl_info161719, | ||
1069 | }, | ||
1070 | { | ||
1071 | .ctl_name = 154, | ||
1072 | .procname = "arlan2-shm-cpy", | ||
1073 | .data = &arlan_drive_info, | ||
1074 | .maxlen = ARLAN_STR_SIZE, | ||
1075 | .mode = 0400, | ||
1076 | .proc_handler = &arlan_sysctl_info, | ||
1077 | }, | ||
1078 | #endif | ||
1079 | { | ||
1080 | .ctl_name = 155, | ||
1081 | .procname = "config2", | ||
1082 | .data = &conf_reset_result, | ||
1083 | .maxlen = 100, | ||
1084 | .mode = 0400, | ||
1085 | .proc_handler = &arlan_configure, | ||
1086 | }, | ||
1087 | { | ||
1088 | .ctl_name = 156, | ||
1089 | .procname = "reset2", | ||
1090 | .data = &conf_reset_result, | ||
1091 | .maxlen = 100, | ||
1092 | .mode = 0400, | ||
1093 | .proc_handler = &arlan_sysctl_reset, | ||
1094 | }, | ||
1095 | { .ctl_name = 0 } | ||
1096 | }; | ||
1097 | |||
1098 | static ctl_table arlan_conf_table3[] = | ||
1099 | { | ||
1100 | |||
1101 | ARLAN_SYSCTL_TABLE_TOTAL(3) | ||
1102 | |||
1103 | #ifdef ARLAN_PROC_SHM_DUMP | ||
1104 | { | ||
1105 | .ctl_name = 150, | ||
1106 | .procname = "arlan3-txRing", | ||
1107 | .data = &arlan_drive_info, | ||
1108 | .maxlen = ARLAN_STR_SIZE, | ||
1109 | .mode = 0400, | ||
1110 | .proc_handler = &arlan_sysctl_infotxRing, | ||
1111 | }, | ||
1112 | { | ||
1113 | .ctl_name = 151, | ||
1114 | .procname = "arlan3-rxRing", | ||
1115 | .data = &arlan_drive_info, | ||
1116 | .maxlen = ARLAN_STR_SIZE, | ||
1117 | .mode = 0400, | ||
1118 | .proc_handler = &arlan_sysctl_inforxRing, | ||
1119 | }, | ||
1120 | { | ||
1121 | .ctl_name = 152, | ||
1122 | .procname = "arlan3-18", | ||
1123 | .data = &arlan_drive_info, | ||
1124 | .maxlen = ARLAN_STR_SIZE, | ||
1125 | .mode = 0400, | ||
1126 | .proc_handler = &arlan_sysctl_info18, | ||
1127 | }, | ||
1128 | { | ||
1129 | .ctl_name = 153, | ||
1130 | .procname = "arlan3-ring", | ||
1131 | .data = &arlan_drive_info, | ||
1132 | .maxlen = ARLAN_STR_SIZE, | ||
1133 | .mode = 0400, | ||
1134 | .proc_handler = &arlan_sysctl_info161719, | ||
1135 | }, | ||
1136 | { | ||
1137 | .ctl_name = 154, | ||
1138 | .procname = "arlan3-shm-cpy", | ||
1139 | .data = &arlan_drive_info, | ||
1140 | .maxlen = ARLAN_STR_SIZE, | ||
1141 | .mode = 0400, | ||
1142 | .proc_handler = &arlan_sysctl_info, | ||
1143 | }, | ||
1144 | #endif | ||
1145 | { | ||
1146 | .ctl_name = 155, | ||
1147 | .procname = "config3", | ||
1148 | .data = &conf_reset_result, | ||
1149 | .maxlen = 100, | ||
1150 | .mode = 0400, | ||
1151 | .proc_handler = &arlan_configure, | ||
1152 | }, | ||
1153 | { | ||
1154 | .ctl_name = 156, | ||
1155 | .procname = "reset3", | ||
1156 | .data = &conf_reset_result, | ||
1157 | .maxlen = 100, | ||
1158 | .mode = 0400, | ||
1159 | .proc_handler = &arlan_sysctl_reset, | ||
1160 | }, | ||
1161 | { .ctl_name = 0 } | ||
1162 | }; | ||
1163 | |||
1164 | |||
1165 | |||
1166 | static ctl_table arlan_table[] = | ||
1167 | { | ||
1168 | { | ||
1169 | .ctl_name = 0, | ||
1170 | .procname = "arlan0", | ||
1171 | .maxlen = 0, | ||
1172 | .mode = 0600, | ||
1173 | .child = arlan_conf_table0, | ||
1174 | }, | ||
1175 | { | ||
1176 | .ctl_name = 0, | ||
1177 | .procname = "arlan1", | ||
1178 | .maxlen = 0, | ||
1179 | .mode = 0600, | ||
1180 | .child = arlan_conf_table1, | ||
1181 | }, | ||
1182 | { | ||
1183 | .ctl_name = 0, | ||
1184 | .procname = "arlan2", | ||
1185 | .maxlen = 0, | ||
1186 | .mode = 0600, | ||
1187 | .child = arlan_conf_table2, | ||
1188 | }, | ||
1189 | { | ||
1190 | .ctl_name = 0, | ||
1191 | .procname = "arlan3", | ||
1192 | .maxlen = 0, | ||
1193 | .mode = 0600, | ||
1194 | .child = arlan_conf_table3, | ||
1195 | }, | ||
1196 | { .ctl_name = 0 } | ||
1197 | }; | ||
1198 | |||
1199 | #else | ||
1200 | |||
1201 | static ctl_table arlan_table[MAX_ARLANS + 1] = | ||
1202 | { | ||
1203 | { .ctl_name = 0 } | ||
1204 | }; | ||
1205 | #endif | ||
1206 | #else | ||
1207 | |||
1208 | static ctl_table arlan_table[MAX_ARLANS + 1] = | ||
1209 | { | ||
1210 | { .ctl_name = 0 } | ||
1211 | }; | ||
1212 | #endif | ||
1213 | |||
1214 | |||
1215 | // static int mmtu = 1234; | ||
1216 | |||
1217 | static ctl_table arlan_root_table[] = | ||
1218 | { | ||
1219 | { | ||
1220 | .ctl_name = 254, | ||
1221 | .procname = "arlan", | ||
1222 | .maxlen = 0, | ||
1223 | .mode = 0555, | ||
1224 | .child = arlan_table, | ||
1225 | }, | ||
1226 | { .ctl_name = 0 } | ||
1227 | }; | ||
1228 | |||
1229 | /* Make sure that /proc/sys/dev is there */ | ||
1230 | //static ctl_table arlan_device_root_table[] = | ||
1231 | //{ | ||
1232 | // {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, | ||
1233 | // {0} | ||
1234 | //}; | ||
1235 | |||
1236 | |||
1237 | #ifdef CONFIG_PROC_FS | ||
1238 | static struct ctl_table_header *arlan_device_sysctl_header; | ||
1239 | |||
1240 | int __init init_arlan_proc(void) | ||
1241 | { | ||
1242 | |||
1243 | int i = 0; | ||
1244 | if (arlan_device_sysctl_header) | ||
1245 | return 0; | ||
1246 | for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) | ||
1247 | arlan_table[i].ctl_name = i + 1; | ||
1248 | arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0); | ||
1249 | if (!arlan_device_sysctl_header) | ||
1250 | return -1; | ||
1251 | |||
1252 | return 0; | ||
1253 | |||
1254 | } | ||
1255 | |||
1256 | void __exit cleanup_arlan_proc(void) | ||
1257 | { | ||
1258 | unregister_sysctl_table(arlan_device_sysctl_header); | ||
1259 | arlan_device_sysctl_header = NULL; | ||
1260 | |||
1261 | } | ||
1262 | #endif | ||
diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h new file mode 100644 index 000000000000..70a6d7b83c4a --- /dev/null +++ b/drivers/net/wireless/arlan.h | |||
@@ -0,0 +1,541 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Cullen Jennings | ||
3 | * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 | ||
4 | * GNU General Public License applies | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/config.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/if_ether.h> /* For the statistics structure. */ | ||
13 | #include <linux/if_arp.h> /* For ARPHRD_ETHER */ | ||
14 | #include <linux/ptrace.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/in.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/timer.h> | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/bitops.h> | ||
23 | #include <asm/system.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | |||
30 | |||
31 | //#define ARLAN_DEBUGGING 1 | ||
32 | |||
33 | #define ARLAN_PROC_INTERFACE | ||
34 | #define MAX_ARLANS 4 /* not more than 4 ! */ | ||
35 | #define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ | ||
36 | |||
37 | #define ARLAN_MAX_MULTICAST_ADDRS 16 | ||
38 | #define ARLAN_RCV_CLEAN 0 | ||
39 | #define ARLAN_RCV_PROMISC 1 | ||
40 | #define ARLAN_RCV_CONTROL 2 | ||
41 | |||
42 | #ifdef CONFIG_PROC_FS | ||
43 | extern int init_arlan_proc(void); | ||
44 | extern void cleanup_arlan_proc(void); | ||
45 | #else | ||
46 | #define init_arlan_proc() ({ 0; }) | ||
47 | #define cleanup_arlan_proc() do { } while (0) | ||
48 | #endif | ||
49 | |||
50 | extern struct net_device *arlan_device[MAX_ARLANS]; | ||
51 | extern int arlan_debug; | ||
52 | extern int arlan_entry_debug; | ||
53 | extern int arlan_exit_debug; | ||
54 | extern int testMemory; | ||
55 | extern int arlan_command(struct net_device * dev, int command); | ||
56 | |||
57 | #define SIDUNKNOWN -1 | ||
58 | #define radioNodeIdUNKNOWN -1 | ||
59 | #define irqUNKNOWN 0 | ||
60 | #define debugUNKNOWN 0 | ||
61 | #define testMemoryUNKNOWN 1 | ||
62 | #define spreadingCodeUNKNOWN 0 | ||
63 | #define channelNumberUNKNOWN 0 | ||
64 | #define channelSetUNKNOWN 0 | ||
65 | #define systemIdUNKNOWN -1 | ||
66 | #define registrationModeUNKNOWN -1 | ||
67 | |||
68 | |||
69 | #define IFDEBUG( L ) if ( (L) & arlan_debug ) | ||
70 | #define ARLAN_FAKE_HDR_LEN 12 | ||
71 | |||
72 | #ifdef ARLAN_DEBUGGING | ||
73 | #define DEBUG 1 | ||
74 | #define ARLAN_ENTRY_EXIT_DEBUGGING 1 | ||
75 | #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) | ||
76 | #else | ||
77 | #define ARLAN_DEBUG(a,b) | ||
78 | #endif | ||
79 | |||
80 | #define ARLAN_SHMEM_SIZE 0x2000 | ||
81 | |||
82 | struct arlan_shmem | ||
83 | { | ||
84 | /* Header Signature */ | ||
85 | volatile char textRegion[48]; | ||
86 | volatile u_char resetFlag; | ||
87 | volatile u_char diagnosticInfo; | ||
88 | volatile u_short diagnosticOffset; | ||
89 | volatile u_char _1[12]; | ||
90 | volatile u_char lanCardNodeId[6]; | ||
91 | volatile u_char broadcastAddress[6]; | ||
92 | volatile u_char hardwareType; | ||
93 | volatile u_char majorHardwareVersion; | ||
94 | volatile u_char minorHardwareVersion; | ||
95 | volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 | ||
96 | volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A | ||
97 | volatile u_char _2[47]; | ||
98 | |||
99 | /* Control/Status Block - 0x0080 */ | ||
100 | volatile u_char interruptInProgress; /* not used by lancpu */ | ||
101 | volatile u_char cntrlRegImage; /* not used by lancpu */ | ||
102 | volatile u_char _3[13]; | ||
103 | volatile u_char dumpByte; | ||
104 | volatile u_char commandByte; /* non-zero = active */ | ||
105 | volatile u_char commandParameter[15]; | ||
106 | |||
107 | /* Receive Status - 0x00a0 */ | ||
108 | volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ | ||
109 | volatile u_char rxFrmType; | ||
110 | volatile u_short rxOffset; | ||
111 | volatile u_short rxLength; | ||
112 | volatile u_char rxSrc[6]; | ||
113 | volatile u_char rxBroadcastFlag; | ||
114 | volatile u_char rxQuality; | ||
115 | volatile u_char scrambled; | ||
116 | volatile u_char _4[1]; | ||
117 | |||
118 | /* Transmit Status - 0x00b0 */ | ||
119 | volatile u_char txStatus; | ||
120 | volatile u_char txAckQuality; | ||
121 | volatile u_char numRetries; | ||
122 | volatile u_char _5[14]; | ||
123 | volatile u_char registeredRouter[6]; | ||
124 | volatile u_char backboneRouter[6]; | ||
125 | volatile u_char registrationStatus; | ||
126 | volatile u_char configuredStatusFlag; | ||
127 | volatile u_char _6[1]; | ||
128 | volatile u_char ultimateDestAddress[6]; | ||
129 | volatile u_char immedDestAddress[6]; | ||
130 | volatile u_char immedSrcAddress[6]; | ||
131 | volatile u_short rxSequenceNumber; | ||
132 | volatile u_char assignedLocaltalkAddress; | ||
133 | volatile u_char _7[27]; | ||
134 | |||
135 | /* System Parameter Block */ | ||
136 | |||
137 | /* - Driver Parameters (Novell Specific) */ | ||
138 | |||
139 | volatile u_short txTimeout; | ||
140 | volatile u_short transportTime; | ||
141 | volatile u_char _8[4]; | ||
142 | |||
143 | /* - Configuration Parameters */ | ||
144 | volatile u_char irqLevel; | ||
145 | volatile u_char spreadingCode; | ||
146 | volatile u_char channelSet; | ||
147 | volatile u_char channelNumber; | ||
148 | volatile u_short radioNodeId; | ||
149 | volatile u_char _9[2]; | ||
150 | volatile u_char scramblingDisable; | ||
151 | volatile u_char radioType; | ||
152 | volatile u_short routerId; | ||
153 | volatile u_char _10[9]; | ||
154 | volatile u_char txAttenuation; | ||
155 | volatile u_char systemId[4]; | ||
156 | volatile u_short globalChecksum; | ||
157 | volatile u_char _11[4]; | ||
158 | volatile u_short maxDatagramSize; | ||
159 | volatile u_short maxFrameSize; | ||
160 | volatile u_char maxRetries; | ||
161 | volatile u_char receiveMode; | ||
162 | volatile u_char priority; | ||
163 | volatile u_char rootOrRepeater; | ||
164 | volatile u_char specifiedRouter[6]; | ||
165 | volatile u_short fastPollPeriod; | ||
166 | volatile u_char pollDecay; | ||
167 | volatile u_char fastPollDelay[2]; | ||
168 | volatile u_char arlThreshold; | ||
169 | volatile u_char arlDecay; | ||
170 | volatile u_char _12[1]; | ||
171 | volatile u_short specRouterTimeout; | ||
172 | volatile u_char _13[5]; | ||
173 | |||
174 | /* Scrambled Area */ | ||
175 | volatile u_char SID[4]; | ||
176 | volatile u_char encryptionKey[12]; | ||
177 | volatile u_char _14[2]; | ||
178 | volatile u_char waitTime[2]; | ||
179 | volatile u_char lParameter[2]; | ||
180 | volatile u_char _15[3]; | ||
181 | volatile u_short headerSize; | ||
182 | volatile u_short sectionChecksum; | ||
183 | |||
184 | volatile u_char registrationMode; | ||
185 | volatile u_char registrationFill; | ||
186 | volatile u_short pollPeriod; | ||
187 | volatile u_short refreshPeriod; | ||
188 | volatile u_char name[16]; | ||
189 | volatile u_char NID[6]; | ||
190 | volatile u_char localTalkAddress; | ||
191 | volatile u_char codeFormat; | ||
192 | volatile u_char numChannels; | ||
193 | volatile u_char channel1; | ||
194 | volatile u_char channel2; | ||
195 | volatile u_char channel3; | ||
196 | volatile u_char channel4; | ||
197 | volatile u_char SSCode[59]; | ||
198 | |||
199 | volatile u_char _16[0xC0]; | ||
200 | volatile u_short auxCmd; | ||
201 | volatile u_char dumpPtr[4]; | ||
202 | volatile u_char dumpVal; | ||
203 | volatile u_char _17[0x6A]; | ||
204 | volatile u_char wireTest; | ||
205 | volatile u_char _18[14]; | ||
206 | |||
207 | /* Statistics Block - 0x0300 */ | ||
208 | volatile u_char hostcpuLock; | ||
209 | volatile u_char lancpuLock; | ||
210 | volatile u_char resetTime[18]; | ||
211 | |||
212 | volatile u_char numDatagramsTransmitted[4]; | ||
213 | volatile u_char numReTransmissions[4]; | ||
214 | volatile u_char numFramesDiscarded[4]; | ||
215 | volatile u_char numDatagramsReceived[4]; | ||
216 | volatile u_char numDuplicateReceivedFrames[4]; | ||
217 | volatile u_char numDatagramsDiscarded[4]; | ||
218 | |||
219 | volatile u_short maxNumReTransmitDatagram; | ||
220 | volatile u_short maxNumReTransmitFrames; | ||
221 | volatile u_short maxNumConsecutiveDuplicateFrames; | ||
222 | /* misaligned here so we have to go to characters */ | ||
223 | |||
224 | volatile u_char numBytesTransmitted[4]; | ||
225 | volatile u_char numBytesReceived[4]; | ||
226 | volatile u_char numCRCErrors[4]; | ||
227 | volatile u_char numLengthErrors[4]; | ||
228 | volatile u_char numAbortErrors[4]; | ||
229 | volatile u_char numTXUnderruns[4]; | ||
230 | volatile u_char numRXOverruns[4]; | ||
231 | volatile u_char numHoldOffs[4]; | ||
232 | volatile u_char numFramesTransmitted[4]; | ||
233 | volatile u_char numFramesReceived[4]; | ||
234 | volatile u_char numReceiveFramesLost[4]; | ||
235 | volatile u_char numRXBufferOverflows[4]; | ||
236 | volatile u_char numFramesDiscardedAddrMismatch[4]; | ||
237 | volatile u_char numFramesDiscardedSIDMismatch[4]; | ||
238 | volatile u_char numPollsTransmistted[4]; | ||
239 | volatile u_char numPollAcknowledges[4]; | ||
240 | volatile u_char numStatusTimeouts[4]; | ||
241 | volatile u_char numNACKReceived[4]; | ||
242 | |||
243 | volatile u_char _19[0x86]; | ||
244 | |||
245 | volatile u_char txBuffer[0x800]; | ||
246 | volatile u_char rxBuffer[0x800]; | ||
247 | |||
248 | volatile u_char _20[0x800]; | ||
249 | volatile u_char _21[0x3fb]; | ||
250 | volatile u_char configStatus; | ||
251 | volatile u_char _22; | ||
252 | volatile u_char progIOCtrl; | ||
253 | volatile u_char shareMBase; | ||
254 | volatile u_char controlRegister; | ||
255 | }; | ||
256 | |||
257 | struct arlan_conf_stru { | ||
258 | int spreadingCode; | ||
259 | int channelSet; | ||
260 | int channelNumber; | ||
261 | int scramblingDisable; | ||
262 | int txAttenuation; | ||
263 | int systemId; | ||
264 | int maxDatagramSize; | ||
265 | int maxFrameSize; | ||
266 | int maxRetries; | ||
267 | int receiveMode; | ||
268 | int priority; | ||
269 | int rootOrRepeater; | ||
270 | int SID; | ||
271 | int radioNodeId; | ||
272 | int registrationMode; | ||
273 | int registrationFill; | ||
274 | int localTalkAddress; | ||
275 | int codeFormat; | ||
276 | int numChannels; | ||
277 | int channel1; | ||
278 | int channel2; | ||
279 | int channel3; | ||
280 | int channel4; | ||
281 | int txClear; | ||
282 | int txRetries; | ||
283 | int txRouting; | ||
284 | int txScrambled; | ||
285 | int rxParameter; | ||
286 | int txTimeoutMs; | ||
287 | int txAckTimeoutMs; | ||
288 | int waitCardTimeout; | ||
289 | int waitTime; | ||
290 | int lParameter; | ||
291 | int _15; | ||
292 | int headerSize; | ||
293 | int retries; | ||
294 | int tx_delay_ms; | ||
295 | int waitReTransmitPacketMaxSize; | ||
296 | int ReTransmitPacketMaxSize; | ||
297 | int fastReTransCount; | ||
298 | int driverRetransmissions; | ||
299 | int registrationInterrupts; | ||
300 | int hardwareType; | ||
301 | int radioType; | ||
302 | int writeRadioType; | ||
303 | int writeEEPROM; | ||
304 | char siteName[17]; | ||
305 | int measure_rate; | ||
306 | int in_speed; | ||
307 | int out_speed; | ||
308 | int in_speed10; | ||
309 | int out_speed10; | ||
310 | int in_speed_max; | ||
311 | int out_speed_max; | ||
312 | int pre_Command_Wait; | ||
313 | int rx_tweak1; | ||
314 | int rx_tweak2; | ||
315 | int tx_queue_len; | ||
316 | }; | ||
317 | |||
318 | extern struct arlan_conf_stru arlan_conf[MAX_ARLANS]; | ||
319 | |||
320 | struct TxParam | ||
321 | { | ||
322 | volatile short offset; | ||
323 | volatile short length; | ||
324 | volatile u_char dest[6]; | ||
325 | volatile unsigned char clear; | ||
326 | volatile unsigned char retries; | ||
327 | volatile unsigned char routing; | ||
328 | volatile unsigned char scrambled; | ||
329 | }; | ||
330 | |||
331 | #define TX_RING_SIZE 2 | ||
332 | /* Information that need to be kept for each board. */ | ||
333 | struct arlan_private { | ||
334 | struct net_device_stats stats; | ||
335 | struct arlan_shmem __iomem * card; | ||
336 | struct arlan_shmem * conf; | ||
337 | |||
338 | struct arlan_conf_stru * Conf; | ||
339 | int bad; | ||
340 | int reset; | ||
341 | unsigned long lastReset; | ||
342 | struct timer_list timer; | ||
343 | struct timer_list tx_delay_timer; | ||
344 | struct timer_list tx_retry_timer; | ||
345 | struct timer_list rx_check_timer; | ||
346 | |||
347 | int registrationLostCount; | ||
348 | int reRegisterExp; | ||
349 | int irq_test_done; | ||
350 | |||
351 | struct TxParam txRing[TX_RING_SIZE]; | ||
352 | char reTransmitBuff[0x800]; | ||
353 | int txLast; | ||
354 | unsigned ReTransmitRequested; | ||
355 | unsigned long tx_done_delayed; | ||
356 | unsigned long registrationLastSeen; | ||
357 | |||
358 | unsigned long tx_last_sent; | ||
359 | unsigned long tx_last_cleared; | ||
360 | unsigned long retransmissions; | ||
361 | unsigned long interrupt_ack_requested; | ||
362 | spinlock_t lock; | ||
363 | unsigned long waiting_command_mask; | ||
364 | unsigned long card_polling_interval; | ||
365 | unsigned long last_command_buff_free_time; | ||
366 | |||
367 | int under_reset; | ||
368 | int under_config; | ||
369 | int rx_command_given; | ||
370 | int tx_command_given; | ||
371 | unsigned long interrupt_processing_active; | ||
372 | unsigned long last_rx_int_ack_time; | ||
373 | unsigned long in_bytes; | ||
374 | unsigned long out_bytes; | ||
375 | unsigned long in_time; | ||
376 | unsigned long out_time; | ||
377 | unsigned long in_time10; | ||
378 | unsigned long out_time10; | ||
379 | unsigned long in_bytes10; | ||
380 | unsigned long out_bytes10; | ||
381 | int init_etherdev_alloc; | ||
382 | }; | ||
383 | |||
384 | |||
385 | |||
386 | #define ARLAN_CLEAR 0x00 | ||
387 | #define ARLAN_RESET 0x01 | ||
388 | #define ARLAN_CHANNEL_ATTENTION 0x02 | ||
389 | #define ARLAN_INTERRUPT_ENABLE 0x04 | ||
390 | #define ARLAN_CLEAR_INTERRUPT 0x08 | ||
391 | #define ARLAN_POWER 0x40 | ||
392 | #define ARLAN_ACCESS 0x80 | ||
393 | |||
394 | #define ARLAN_COM_CONF 0x01 | ||
395 | #define ARLAN_COM_RX_ENABLE 0x03 | ||
396 | #define ARLAN_COM_RX_ABORT 0x04 | ||
397 | #define ARLAN_COM_TX_ENABLE 0x05 | ||
398 | #define ARLAN_COM_TX_ABORT 0x06 | ||
399 | #define ARLAN_COM_NOP 0x07 | ||
400 | #define ARLAN_COM_STANDBY 0x08 | ||
401 | #define ARLAN_COM_ACTIVATE 0x09 | ||
402 | #define ARLAN_COM_GOTO_SLOW_POLL 0x0a | ||
403 | #define ARLAN_COM_INT 0x80 | ||
404 | |||
405 | |||
406 | #define TXLAST(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[((struct arlan_private *)netdev_priv(dev))->txLast]) | ||
407 | #define TXHEAD(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[0]) | ||
408 | #define TXTAIL(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[1]) | ||
409 | |||
410 | #define TXBuffStart(dev) offsetof(struct arlan_shmem, txBuffer) | ||
411 | #define TXBuffEnd(dev) offsetof(struct arlan_shmem, xxBuffer) | ||
412 | |||
413 | #define READSHM(to,from,atype) {\ | ||
414 | atype tmp;\ | ||
415 | memcpy_fromio(&(tmp),&(from),sizeof(atype));\ | ||
416 | to = tmp;\ | ||
417 | } | ||
418 | |||
419 | #define READSHMEM(from,atype)\ | ||
420 | atype from; \ | ||
421 | READSHM(from, arlan->from, atype); | ||
422 | |||
423 | #define WRITESHM(to,from,atype) \ | ||
424 | { atype tmpSHM = from;\ | ||
425 | memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ | ||
426 | } | ||
427 | |||
428 | #define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ | ||
429 | { atype tmpSHM; \ | ||
430 | memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ | ||
431 | IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ | ||
432 | } | ||
433 | |||
434 | #define WRITESHMB(to, val) \ | ||
435 | writeb(val,&(to)) | ||
436 | #define READSHMB(to) \ | ||
437 | readb(&(to)) | ||
438 | #define WRITESHMS(to, val) \ | ||
439 | writew(val,&(to)) | ||
440 | #define READSHMS(to) \ | ||
441 | readw(&(to)) | ||
442 | #define WRITESHMI(to, val) \ | ||
443 | writel(val,&(to)) | ||
444 | #define READSHMI(to) \ | ||
445 | readl(&(to)) | ||
446 | |||
447 | |||
448 | |||
449 | |||
450 | |||
451 | #define registrationBad(dev)\ | ||
452 | ( ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationMode) > 0) && \ | ||
453 | ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationStatus) == 0) ) | ||
454 | |||
455 | |||
456 | #define readControlRegister(dev)\ | ||
457 | READSHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage) | ||
458 | |||
459 | #define writeControlRegister(dev, v){\ | ||
460 | WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage ,((v) &0xF) );\ | ||
461 | WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->controlRegister ,(v) );} | ||
462 | |||
463 | |||
464 | #define arlan_interrupt_lancpu(dev) {\ | ||
465 | int cr; \ | ||
466 | \ | ||
467 | cr = readControlRegister(dev);\ | ||
468 | if (cr & ARLAN_CHANNEL_ATTENTION){ \ | ||
469 | writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ | ||
470 | }else \ | ||
471 | writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ | ||
472 | } | ||
473 | |||
474 | #define clearChannelAttention(dev){ \ | ||
475 | writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} | ||
476 | #define setHardwareReset(dev) {\ | ||
477 | writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} | ||
478 | #define clearHardwareReset(dev) {\ | ||
479 | writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} | ||
480 | #define setInterruptEnable(dev){\ | ||
481 | writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} | ||
482 | #define clearInterruptEnable(dev){\ | ||
483 | writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} | ||
484 | #define setClearInterrupt(dev){\ | ||
485 | writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} | ||
486 | #define clearClearInterrupt(dev){\ | ||
487 | writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} | ||
488 | #define setPowerOff(dev){\ | ||
489 | writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ | ||
490 | writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} | ||
491 | #define setPowerOn(dev){\ | ||
492 | writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } | ||
493 | #define arlan_lock_card_access(dev){\ | ||
494 | writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} | ||
495 | #define arlan_unlock_card_access(dev){\ | ||
496 | writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } | ||
497 | |||
498 | |||
499 | |||
500 | |||
501 | #define ARLAN_COMMAND_RX 0x000001 | ||
502 | #define ARLAN_COMMAND_NOOP 0x000002 | ||
503 | #define ARLAN_COMMAND_NOOPINT 0x000004 | ||
504 | #define ARLAN_COMMAND_TX 0x000008 | ||
505 | #define ARLAN_COMMAND_CONF 0x000010 | ||
506 | #define ARLAN_COMMAND_RESET 0x000020 | ||
507 | #define ARLAN_COMMAND_TX_ABORT 0x000040 | ||
508 | #define ARLAN_COMMAND_RX_ABORT 0x000080 | ||
509 | #define ARLAN_COMMAND_POWERDOWN 0x000100 | ||
510 | #define ARLAN_COMMAND_POWERUP 0x000200 | ||
511 | #define ARLAN_COMMAND_SLOW_POLL 0x000400 | ||
512 | #define ARLAN_COMMAND_ACTIVATE 0x000800 | ||
513 | #define ARLAN_COMMAND_INT_ACK 0x001000 | ||
514 | #define ARLAN_COMMAND_INT_ENABLE 0x002000 | ||
515 | #define ARLAN_COMMAND_WAIT_NOW 0x004000 | ||
516 | #define ARLAN_COMMAND_LONG_WAIT_NOW 0x008000 | ||
517 | #define ARLAN_COMMAND_STANDBY 0x010000 | ||
518 | #define ARLAN_COMMAND_INT_RACK 0x020000 | ||
519 | #define ARLAN_COMMAND_INT_RENABLE 0x040000 | ||
520 | #define ARLAN_COMMAND_CONF_WAIT 0x080000 | ||
521 | #define ARLAN_COMMAND_TBUSY_CLEAR 0x100000 | ||
522 | #define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ | ||
523 | | ARLAN_COMMAND_RX_ABORT\ | ||
524 | | ARLAN_COMMAND_CONF) | ||
525 | #define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ | ||
526 | | ARLAN_COMMAND_RX_ABORT\ | ||
527 | | ARLAN_COMMAND_RESET) | ||
528 | |||
529 | |||
530 | |||
531 | #define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 | ||
532 | #define ARLAN_DEBUG_RESET 0x00002 | ||
533 | #define ARLAN_DEBUG_TIMING 0x00004 | ||
534 | #define ARLAN_DEBUG_CARD_STATE 0x00008 | ||
535 | #define ARLAN_DEBUG_TX_CHAIN 0x00010 | ||
536 | #define ARLAN_DEBUG_MULTICAST 0x00020 | ||
537 | #define ARLAN_DEBUG_HEADER_DUMP 0x00040 | ||
538 | #define ARLAN_DEBUG_INTERRUPT 0x00080 | ||
539 | #define ARLAN_DEBUG_STARTUP 0x00100 | ||
540 | #define ARLAN_DEBUG_SHUTDOWN 0x00200 | ||
541 | |||
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c new file mode 100644 index 000000000000..18a7d38d2a13 --- /dev/null +++ b/drivers/net/wireless/atmel.c | |||
@@ -0,0 +1,4272 @@ | |||
1 | /*** -*- linux-c -*- ********************************************************** | ||
2 | |||
3 | Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | ||
4 | |||
5 | Copyright 2000-2001 ATMEL Corporation. | ||
6 | Copyright 2003-2004 Simon Kelley. | ||
7 | |||
8 | This code was developed from version 2.1.1 of the Atmel drivers, | ||
9 | released by Atmel corp. under the GPL in December 2002. It also | ||
10 | includes code from the Linux aironet drivers (C) Benjamin Reed, | ||
11 | and the Linux PCMCIA package, (C) David Hinds and the Linux wireless | ||
12 | extensions, (C) Jean Tourrilhes. | ||
13 | |||
14 | The firmware module for reading the MAC address of the card comes from | ||
15 | net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright | ||
16 | by him. net.russotto.AtmelMACFW is used under the GPL license version 2. | ||
17 | This file contains the module in binary form and, under the terms | ||
18 | of the GPL, in source form. The source is located at the end of the file. | ||
19 | |||
20 | This program is free software; you can redistribute it and/or modify | ||
21 | it under the terms of the GNU General Public License as published by | ||
22 | the Free Software Foundation; either version 2 of the License, or | ||
23 | (at your option) any later version. | ||
24 | |||
25 | This software is distributed in the hope that it will be useful, | ||
26 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | GNU General Public License for more details. | ||
29 | |||
30 | You should have received a copy of the GNU General Public License | ||
31 | along with Atmel wireless lan drivers; if not, write to the Free Software | ||
32 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
33 | |||
34 | For all queries about this code, please contact the current author, | ||
35 | Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. | ||
36 | |||
37 | Credit is due to HP UK and Cambridge Online Systems Ltd for supplying | ||
38 | hardware used during development of this driver. | ||
39 | |||
40 | ******************************************************************************/ | ||
41 | |||
42 | #include <linux/config.h> | ||
43 | #include <linux/init.h> | ||
44 | |||
45 | #include <linux/kernel.h> | ||
46 | #include <linux/sched.h> | ||
47 | #include <linux/ptrace.h> | ||
48 | #include <linux/slab.h> | ||
49 | #include <linux/string.h> | ||
50 | #include <linux/ctype.h> | ||
51 | #include <linux/timer.h> | ||
52 | #include <asm/io.h> | ||
53 | #include <asm/system.h> | ||
54 | #include <asm/uaccess.h> | ||
55 | #include <linux/module.h> | ||
56 | #include <linux/netdevice.h> | ||
57 | #include <linux/etherdevice.h> | ||
58 | #include <linux/skbuff.h> | ||
59 | #include <linux/if_arp.h> | ||
60 | #include <linux/ioport.h> | ||
61 | #include <linux/fcntl.h> | ||
62 | #include <linux/delay.h> | ||
63 | #include <linux/wireless.h> | ||
64 | #include <net/iw_handler.h> | ||
65 | #include <linux/byteorder/generic.h> | ||
66 | #include <linux/crc32.h> | ||
67 | #include <linux/proc_fs.h> | ||
68 | #include <linux/device.h> | ||
69 | #include <linux/moduleparam.h> | ||
70 | #include <linux/firmware.h> | ||
71 | #include "ieee802_11.h" | ||
72 | #include "atmel.h" | ||
73 | |||
74 | #define DRIVER_MAJOR 0 | ||
75 | #define DRIVER_MINOR 96 | ||
76 | |||
77 | MODULE_AUTHOR("Simon Kelley"); | ||
78 | MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | ||
79 | MODULE_LICENSE("GPL"); | ||
80 | MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards"); | ||
81 | |||
82 | /* The name of the firmware file to be loaded | ||
83 | over-rides any automatic selection */ | ||
84 | static char *firmware = NULL; | ||
85 | module_param(firmware, charp, 0); | ||
86 | |||
87 | /* table of firmware file names */ | ||
88 | static struct { | ||
89 | AtmelFWType fw_type; | ||
90 | const char *fw_file; | ||
91 | const char *fw_file_ext; | ||
92 | } fw_table[] = { | ||
93 | { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, | ||
94 | { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, | ||
95 | { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, | ||
96 | { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, | ||
97 | { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, | ||
98 | { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, | ||
99 | { ATMEL_FW_TYPE_504A_2958,"atmel_at76c504a_2958","bin" }, | ||
100 | { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, | ||
101 | { ATMEL_FW_TYPE_NONE, NULL, NULL } | ||
102 | }; | ||
103 | |||
104 | #define MAX_SSID_LENGTH 32 | ||
105 | #define MGMT_JIFFIES (256 * HZ / 100) | ||
106 | |||
107 | #define MAX_BSS_ENTRIES 64 | ||
108 | |||
109 | /* registers */ | ||
110 | #define GCR 0x00 // (SIR0) General Configuration Register | ||
111 | #define BSR 0x02 // (SIR1) Bank Switching Select Register | ||
112 | #define AR 0x04 | ||
113 | #define DR 0x08 | ||
114 | #define MR1 0x12 // Mirror Register 1 | ||
115 | #define MR2 0x14 // Mirror Register 2 | ||
116 | #define MR3 0x16 // Mirror Register 3 | ||
117 | #define MR4 0x18 // Mirror Register 4 | ||
118 | |||
119 | #define GPR1 0x0c | ||
120 | #define GPR2 0x0e | ||
121 | #define GPR3 0x10 | ||
122 | // | ||
123 | // Constants for the GCR register. | ||
124 | // | ||
125 | #define GCR_REMAP 0x0400 // Remap internal SRAM to 0 | ||
126 | #define GCR_SWRES 0x0080 // BIU reset (ARM and PAI are NOT reset) | ||
127 | #define GCR_CORES 0x0060 // Core Reset (ARM and PAI are reset) | ||
128 | #define GCR_ENINT 0x0002 // Enable Interrupts | ||
129 | #define GCR_ACKINT 0x0008 // Acknowledge Interrupts | ||
130 | |||
131 | #define BSS_SRAM 0x0200 // AMBA module selection --> SRAM | ||
132 | #define BSS_IRAM 0x0100 // AMBA module selection --> IRAM | ||
133 | // | ||
134 | // Constants for the MR registers. | ||
135 | // | ||
136 | #define MAC_INIT_COMPLETE 0x0001 // MAC init has been completed | ||
137 | #define MAC_BOOT_COMPLETE 0x0010 // MAC boot has been completed | ||
138 | #define MAC_INIT_OK 0x0002 // MAC boot has been completed | ||
139 | |||
140 | #define C80211_SUBTYPE_MGMT_ASS_REQUEST 0x00 | ||
141 | #define C80211_SUBTYPE_MGMT_ASS_RESPONSE 0x10 | ||
142 | #define C80211_SUBTYPE_MGMT_REASS_REQUEST 0x20 | ||
143 | #define C80211_SUBTYPE_MGMT_REASS_RESPONSE 0x30 | ||
144 | #define C80211_SUBTYPE_MGMT_ProbeRequest 0x40 | ||
145 | #define C80211_SUBTYPE_MGMT_ProbeResponse 0x50 | ||
146 | #define C80211_SUBTYPE_MGMT_BEACON 0x80 | ||
147 | #define C80211_SUBTYPE_MGMT_ATIM 0x90 | ||
148 | #define C80211_SUBTYPE_MGMT_DISASSOSIATION 0xA0 | ||
149 | #define C80211_SUBTYPE_MGMT_Authentication 0xB0 | ||
150 | #define C80211_SUBTYPE_MGMT_Deauthentication 0xC0 | ||
151 | |||
152 | #define C80211_MGMT_AAN_OPENSYSTEM 0x0000 | ||
153 | #define C80211_MGMT_AAN_SHAREDKEY 0x0001 | ||
154 | |||
155 | #define C80211_MGMT_CAPABILITY_ESS 0x0001 // see 802.11 p.58 | ||
156 | #define C80211_MGMT_CAPABILITY_IBSS 0x0002 // - " - | ||
157 | #define C80211_MGMT_CAPABILITY_CFPollable 0x0004 // - " - | ||
158 | #define C80211_MGMT_CAPABILITY_CFPollRequest 0x0008 // - " - | ||
159 | #define C80211_MGMT_CAPABILITY_Privacy 0x0010 // - " - | ||
160 | |||
161 | #define C80211_MGMT_SC_Success 0 | ||
162 | #define C80211_MGMT_SC_Unspecified 1 | ||
163 | #define C80211_MGMT_SC_SupportCapabilities 10 | ||
164 | #define C80211_MGMT_SC_ReassDenied 11 | ||
165 | #define C80211_MGMT_SC_AssDenied 12 | ||
166 | #define C80211_MGMT_SC_AuthAlgNotSupported 13 | ||
167 | #define C80211_MGMT_SC_AuthTransSeqNumError 14 | ||
168 | #define C80211_MGMT_SC_AuthRejectChallenge 15 | ||
169 | #define C80211_MGMT_SC_AuthRejectTimeout 16 | ||
170 | #define C80211_MGMT_SC_AssDeniedHandleAP 17 | ||
171 | #define C80211_MGMT_SC_AssDeniedBSSRate 18 | ||
172 | |||
173 | #define C80211_MGMT_ElementID_SSID 0 | ||
174 | #define C80211_MGMT_ElementID_SupportedRates 1 | ||
175 | #define C80211_MGMT_ElementID_ChallengeText 16 | ||
176 | #define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020 | ||
177 | |||
178 | #define MIB_MAX_DATA_BYTES 212 | ||
179 | #define MIB_HEADER_SIZE 4 /* first four fields */ | ||
180 | |||
181 | struct get_set_mib { | ||
182 | u8 type; | ||
183 | u8 size; | ||
184 | u8 index; | ||
185 | u8 reserved; | ||
186 | u8 data[MIB_MAX_DATA_BYTES]; | ||
187 | }; | ||
188 | |||
189 | struct rx_desc { | ||
190 | u32 Next; | ||
191 | u16 MsduPos; | ||
192 | u16 MsduSize; | ||
193 | |||
194 | u8 State; | ||
195 | u8 Status; | ||
196 | u8 Rate; | ||
197 | u8 Rssi; | ||
198 | u8 LinkQuality; | ||
199 | u8 PreambleType; | ||
200 | u16 Duration; | ||
201 | u32 RxTime; | ||
202 | |||
203 | }; | ||
204 | |||
205 | #define RX_DESC_FLAG_VALID 0x80 | ||
206 | #define RX_DESC_FLAG_CONSUMED 0x40 | ||
207 | #define RX_DESC_FLAG_IDLE 0x00 | ||
208 | |||
209 | #define RX_STATUS_SUCCESS 0x00 | ||
210 | |||
211 | #define RX_DESC_MSDU_POS_OFFSET 4 | ||
212 | #define RX_DESC_MSDU_SIZE_OFFSET 6 | ||
213 | #define RX_DESC_FLAGS_OFFSET 8 | ||
214 | #define RX_DESC_STATUS_OFFSET 9 | ||
215 | #define RX_DESC_RSSI_OFFSET 11 | ||
216 | #define RX_DESC_LINK_QUALITY_OFFSET 12 | ||
217 | #define RX_DESC_PREAMBLE_TYPE_OFFSET 13 | ||
218 | #define RX_DESC_DURATION_OFFSET 14 | ||
219 | #define RX_DESC_RX_TIME_OFFSET 16 | ||
220 | |||
221 | |||
222 | struct tx_desc { | ||
223 | u32 NextDescriptor; | ||
224 | u16 TxStartOfFrame; | ||
225 | u16 TxLength; | ||
226 | |||
227 | u8 TxState; | ||
228 | u8 TxStatus; | ||
229 | u8 RetryCount; | ||
230 | |||
231 | u8 TxRate; | ||
232 | |||
233 | u8 KeyIndex; | ||
234 | u8 ChiperType; | ||
235 | u8 ChipreLength; | ||
236 | u8 Reserved1; | ||
237 | |||
238 | u8 Reserved; | ||
239 | u8 PacketType; | ||
240 | u16 HostTxLength; | ||
241 | |||
242 | }; | ||
243 | |||
244 | |||
245 | #define TX_DESC_NEXT_OFFSET 0 | ||
246 | #define TX_DESC_POS_OFFSET 4 | ||
247 | #define TX_DESC_SIZE_OFFSET 6 | ||
248 | #define TX_DESC_FLAGS_OFFSET 8 | ||
249 | #define TX_DESC_STATUS_OFFSET 9 | ||
250 | #define TX_DESC_RETRY_OFFSET 10 | ||
251 | #define TX_DESC_RATE_OFFSET 11 | ||
252 | #define TX_DESC_KEY_INDEX_OFFSET 12 | ||
253 | #define TX_DESC_CIPHER_TYPE_OFFSET 13 | ||
254 | #define TX_DESC_CIPHER_LENGTH_OFFSET 14 | ||
255 | #define TX_DESC_PACKET_TYPE_OFFSET 17 | ||
256 | #define TX_DESC_HOST_LENGTH_OFFSET 18 | ||
257 | |||
258 | |||
259 | |||
260 | /////////////////////////////////////////////////////// | ||
261 | // Host-MAC interface | ||
262 | /////////////////////////////////////////////////////// | ||
263 | |||
264 | #define TX_STATUS_SUCCESS 0x00 | ||
265 | |||
266 | #define TX_FIRM_OWN 0x80 | ||
267 | #define TX_DONE 0x40 | ||
268 | |||
269 | |||
270 | #define TX_ERROR 0x01 | ||
271 | |||
272 | #define TX_PACKET_TYPE_DATA 0x01 | ||
273 | #define TX_PACKET_TYPE_MGMT 0x02 | ||
274 | |||
275 | #define ISR_EMPTY 0x00 // no bits set in ISR | ||
276 | #define ISR_TxCOMPLETE 0x01 // packet transmitted | ||
277 | #define ISR_RxCOMPLETE 0x02 // packet received | ||
278 | #define ISR_RxFRAMELOST 0x04 // Rx Frame lost | ||
279 | #define ISR_FATAL_ERROR 0x08 // Fatal error | ||
280 | #define ISR_COMMAND_COMPLETE 0x10 // command completed | ||
281 | #define ISR_OUT_OF_RANGE 0x20 // command completed | ||
282 | #define ISR_IBSS_MERGE 0x40 // (4.1.2.30): IBSS merge | ||
283 | #define ISR_GENERIC_IRQ 0x80 | ||
284 | |||
285 | |||
286 | #define Local_Mib_Type 0x01 | ||
287 | #define Mac_Address_Mib_Type 0x02 | ||
288 | #define Mac_Mib_Type 0x03 | ||
289 | #define Statistics_Mib_Type 0x04 | ||
290 | #define Mac_Mgmt_Mib_Type 0x05 | ||
291 | #define Mac_Wep_Mib_Type 0x06 | ||
292 | #define Phy_Mib_Type 0x07 | ||
293 | #define Multi_Domain_MIB 0x08 | ||
294 | |||
295 | #define MAC_MGMT_MIB_CUR_BSSID_POS 14 | ||
296 | #define MAC_MIB_FRAG_THRESHOLD_POS 8 | ||
297 | #define MAC_MIB_RTS_THRESHOLD_POS 10 | ||
298 | #define MAC_MIB_SHORT_RETRY_POS 16 | ||
299 | #define MAC_MIB_LONG_RETRY_POS 17 | ||
300 | #define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 | ||
301 | #define MAC_MGMT_MIB_BEACON_PER_POS 0 | ||
302 | #define MAC_MGMT_MIB_STATION_ID_POS 6 | ||
303 | #define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 | ||
304 | #define MAC_MGMT_MIB_CUR_BSSID_POS 14 | ||
305 | #define MAC_MGMT_MIB_PS_MODE_POS 53 | ||
306 | #define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 | ||
307 | #define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 | ||
308 | #define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 | ||
309 | #define PHY_MIB_CHANNEL_POS 14 | ||
310 | #define PHY_MIB_RATE_SET_POS 20 | ||
311 | #define PHY_MIB_REG_DOMAIN_POS 26 | ||
312 | #define LOCAL_MIB_AUTO_TX_RATE_POS 3 | ||
313 | #define LOCAL_MIB_SSID_SIZE 5 | ||
314 | #define LOCAL_MIB_TX_PROMISCUOUS_POS 6 | ||
315 | #define LOCAL_MIB_TX_MGMT_RATE_POS 7 | ||
316 | #define LOCAL_MIB_TX_CONTROL_RATE_POS 8 | ||
317 | #define LOCAL_MIB_PREAMBLE_TYPE 9 | ||
318 | #define MAC_ADDR_MIB_MAC_ADDR_POS 0 | ||
319 | |||
320 | |||
321 | #define CMD_Set_MIB_Vars 0x01 | ||
322 | #define CMD_Get_MIB_Vars 0x02 | ||
323 | #define CMD_Scan 0x03 | ||
324 | #define CMD_Join 0x04 | ||
325 | #define CMD_Start 0x05 | ||
326 | #define CMD_EnableRadio 0x06 | ||
327 | #define CMD_DisableRadio 0x07 | ||
328 | #define CMD_SiteSurvey 0x0B | ||
329 | |||
330 | #define CMD_STATUS_IDLE 0x00 | ||
331 | #define CMD_STATUS_COMPLETE 0x01 | ||
332 | #define CMD_STATUS_UNKNOWN 0x02 | ||
333 | #define CMD_STATUS_INVALID_PARAMETER 0x03 | ||
334 | #define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 | ||
335 | #define CMD_STATUS_TIME_OUT 0x07 | ||
336 | #define CMD_STATUS_IN_PROGRESS 0x08 | ||
337 | #define CMD_STATUS_REJECTED_RADIO_OFF 0x09 | ||
338 | #define CMD_STATUS_HOST_ERROR 0xFF | ||
339 | #define CMD_STATUS_BUSY 0xFE | ||
340 | |||
341 | |||
342 | #define CMD_BLOCK_COMMAND_OFFSET 0 | ||
343 | #define CMD_BLOCK_STATUS_OFFSET 1 | ||
344 | #define CMD_BLOCK_PARAMETERS_OFFSET 4 | ||
345 | |||
346 | #define SCAN_OPTIONS_SITE_SURVEY 0x80 | ||
347 | |||
348 | #define MGMT_FRAME_BODY_OFFSET 24 | ||
349 | #define MAX_AUTHENTICATION_RETRIES 3 | ||
350 | #define MAX_ASSOCIATION_RETRIES 3 | ||
351 | |||
352 | #define AUTHENTICATION_RESPONSE_TIME_OUT 1000 | ||
353 | |||
354 | #define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ | ||
355 | #define LOOP_RETRY_LIMIT 500000 | ||
356 | |||
357 | #define ACTIVE_MODE 1 | ||
358 | #define PS_MODE 2 | ||
359 | |||
360 | #define MAX_ENCRYPTION_KEYS 4 | ||
361 | #define MAX_ENCRYPTION_KEY_SIZE 40 | ||
362 | |||
363 | /////////////////////////////////////////////////////////////////////////// | ||
364 | // 802.11 related definitions | ||
365 | /////////////////////////////////////////////////////////////////////////// | ||
366 | |||
367 | // | ||
368 | // Regulatory Domains | ||
369 | // | ||
370 | |||
371 | #define REG_DOMAIN_FCC 0x10 //Channels 1-11 USA | ||
372 | #define REG_DOMAIN_DOC 0x20 //Channel 1-11 Canada | ||
373 | #define REG_DOMAIN_ETSI 0x30 //Channel 1-13 Europe (ex Spain/France) | ||
374 | #define REG_DOMAIN_SPAIN 0x31 //Channel 10-11 Spain | ||
375 | #define REG_DOMAIN_FRANCE 0x32 //Channel 10-13 France | ||
376 | #define REG_DOMAIN_MKK 0x40 //Channel 14 Japan | ||
377 | #define REG_DOMAIN_MKK1 0x41 //Channel 1-14 Japan(MKK1) | ||
378 | #define REG_DOMAIN_ISRAEL 0x50 //Channel 3-9 ISRAEL | ||
379 | |||
380 | #define BSS_TYPE_AD_HOC 1 | ||
381 | #define BSS_TYPE_INFRASTRUCTURE 2 | ||
382 | |||
383 | #define SCAN_TYPE_ACTIVE 0 | ||
384 | #define SCAN_TYPE_PASSIVE 1 | ||
385 | |||
386 | #define LONG_PREAMBLE 0 | ||
387 | #define SHORT_PREAMBLE 1 | ||
388 | #define AUTO_PREAMBLE 2 | ||
389 | |||
390 | #define DATA_FRAME_WS_HEADER_SIZE 30 | ||
391 | |||
392 | /* promiscuous mode control */ | ||
393 | #define PROM_MODE_OFF 0x0 | ||
394 | #define PROM_MODE_UNKNOWN 0x1 | ||
395 | #define PROM_MODE_CRC_FAILED 0x2 | ||
396 | #define PROM_MODE_DUPLICATED 0x4 | ||
397 | #define PROM_MODE_MGMT 0x8 | ||
398 | #define PROM_MODE_CTRL 0x10 | ||
399 | #define PROM_MODE_BAD_PROTOCOL 0x20 | ||
400 | |||
401 | |||
402 | #define IFACE_INT_STATUS_OFFSET 0 | ||
403 | #define IFACE_INT_MASK_OFFSET 1 | ||
404 | #define IFACE_LOCKOUT_HOST_OFFSET 2 | ||
405 | #define IFACE_LOCKOUT_MAC_OFFSET 3 | ||
406 | #define IFACE_FUNC_CTRL_OFFSET 28 | ||
407 | #define IFACE_MAC_STAT_OFFSET 30 | ||
408 | #define IFACE_GENERIC_INT_TYPE_OFFSET 32 | ||
409 | |||
410 | #define CIPHER_SUITE_NONE 0 | ||
411 | #define CIPHER_SUITE_WEP_64 1 | ||
412 | #define CIPHER_SUITE_TKIP 2 | ||
413 | #define CIPHER_SUITE_AES 3 | ||
414 | #define CIPHER_SUITE_CCX 4 | ||
415 | #define CIPHER_SUITE_WEP_128 5 | ||
416 | |||
417 | // | ||
418 | // IFACE MACROS & definitions | ||
419 | // | ||
420 | // | ||
421 | |||
422 | // FuncCtrl field: | ||
423 | // | ||
424 | #define FUNC_CTRL_TxENABLE 0x10 | ||
425 | #define FUNC_CTRL_RxENABLE 0x20 | ||
426 | #define FUNC_CTRL_INIT_COMPLETE 0x01 | ||
427 | |||
428 | /* A stub firmware image which reads the MAC address from NVRAM on the card. | ||
429 | For copyright information and source see the end of this file. */ | ||
430 | static u8 mac_reader[] = { | ||
431 | 0x06,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea, | ||
432 | 0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, | ||
433 | 0xd3,0x00,0xa0,0xe3,0x00,0xf0,0x21,0xe1,0x0e,0x04,0xa0,0xe3,0x00,0x10,0xa0,0xe3, | ||
434 | 0x81,0x11,0xa0,0xe1,0x00,0x10,0x81,0xe3,0x00,0x10,0x80,0xe5,0x1c,0x10,0x90,0xe5, | ||
435 | 0x10,0x10,0xc1,0xe3,0x1c,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5, | ||
436 | 0x02,0x03,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xb0,0x10,0xc0,0xe1,0xb4,0x10,0xc0,0xe1, | ||
437 | 0xb8,0x10,0xc0,0xe1,0xbc,0x10,0xc0,0xe1,0x56,0xdc,0xa0,0xe3,0x21,0x00,0x00,0xeb, | ||
438 | 0x0a,0x00,0xa0,0xe3,0x1a,0x00,0x00,0xeb,0x10,0x00,0x00,0xeb,0x07,0x00,0x00,0xeb, | ||
439 | 0x02,0x03,0xa0,0xe3,0x02,0x14,0xa0,0xe3,0xb4,0x10,0xc0,0xe1,0x4c,0x10,0x9f,0xe5, | ||
440 | 0xbc,0x10,0xc0,0xe1,0x10,0x10,0xa0,0xe3,0xb8,0x10,0xc0,0xe1,0xfe,0xff,0xff,0xea, | ||
441 | 0x00,0x40,0x2d,0xe9,0x00,0x20,0xa0,0xe3,0x02,0x3c,0xa0,0xe3,0x00,0x10,0xa0,0xe3, | ||
442 | 0x28,0x00,0x9f,0xe5,0x37,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, | ||
443 | 0x00,0x40,0x2d,0xe9,0x12,0x2e,0xa0,0xe3,0x06,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe3, | ||
444 | 0x02,0x04,0xa0,0xe3,0x2f,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, | ||
445 | 0x00,0x02,0x00,0x02,0x80,0x01,0x90,0xe0,0x01,0x00,0x00,0x0a,0x01,0x00,0x50,0xe2, | ||
446 | 0xfc,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x80,0x10,0xa0,0xe3,0xf3,0x06,0xa0,0xe3, | ||
447 | 0x00,0x10,0x80,0xe5,0x00,0x10,0xa0,0xe3,0x00,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3, | ||
448 | 0x04,0x10,0x80,0xe5,0x00,0x10,0x80,0xe5,0x0e,0x34,0xa0,0xe3,0x1c,0x10,0x93,0xe5, | ||
449 | 0x02,0x1a,0x81,0xe3,0x1c,0x10,0x83,0xe5,0x58,0x11,0x9f,0xe5,0x30,0x10,0x80,0xe5, | ||
450 | 0x54,0x11,0x9f,0xe5,0x34,0x10,0x80,0xe5,0x38,0x10,0x80,0xe5,0x3c,0x10,0x80,0xe5, | ||
451 | 0x10,0x10,0x90,0xe5,0x08,0x00,0x90,0xe5,0x1e,0xff,0x2f,0xe1,0xf3,0x16,0xa0,0xe3, | ||
452 | 0x08,0x00,0x91,0xe5,0x05,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,0x10,0x00,0x91,0xe5, | ||
453 | 0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0xff,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5, | ||
454 | 0x10,0x00,0x91,0xe5,0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, | ||
455 | 0x10,0x00,0x91,0xe5,0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, | ||
456 | 0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x30,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1, | ||
457 | 0x03,0x40,0xa0,0xe1,0xa2,0x02,0xa0,0xe1,0x08,0x00,0x00,0xe2,0x03,0x00,0x80,0xe2, | ||
458 | 0xd8,0x10,0x9f,0xe5,0x00,0x00,0xc1,0xe5,0x01,0x20,0xc1,0xe5,0xe2,0xff,0xff,0xeb, | ||
459 | 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x1a,0x14,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xeb, | ||
460 | 0x04,0x20,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x02,0x00,0xa0,0xe3,0x01,0x00,0x00,0xeb, | ||
461 | 0x30,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0xf3,0x46,0xa0,0xe3, | ||
462 | 0x00,0x30,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x9a,0x8c,0x50,0x9f,0xe5, | ||
463 | 0x03,0x60,0xd5,0xe7,0x0c,0x60,0x84,0xe5,0x10,0x60,0x94,0xe5,0x02,0x00,0x16,0xe3, | ||
464 | 0xfc,0xff,0xff,0x0a,0x01,0x30,0x83,0xe2,0x00,0x00,0x53,0xe1,0xf7,0xff,0xff,0x3a, | ||
465 | 0xff,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x08,0x00,0x94,0xe5,0x10,0x00,0x94,0xe5, | ||
466 | 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x94,0xe5,0x00,0x00,0xa0,0xe3, | ||
467 | 0x00,0x00,0x52,0xe3,0x0b,0x00,0x00,0x9a,0x10,0x50,0x94,0xe5,0x02,0x00,0x15,0xe3, | ||
468 | 0xfc,0xff,0xff,0x0a,0x0c,0x30,0x84,0xe5,0x10,0x50,0x94,0xe5,0x01,0x00,0x15,0xe3, | ||
469 | 0xfc,0xff,0xff,0x0a,0x08,0x50,0x94,0xe5,0x01,0x50,0xc1,0xe4,0x01,0x00,0x80,0xe2, | ||
470 | 0x02,0x00,0x50,0xe1,0xf3,0xff,0xff,0x3a,0xc8,0x00,0xa0,0xe3,0x98,0xff,0xff,0xeb, | ||
471 | 0x70,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x01,0x0c,0x00,0x02,0x01,0x02,0x00,0x02, | ||
472 | 0x00,0x01,0x00,0x02 | ||
473 | }; | ||
474 | |||
475 | struct atmel_private { | ||
476 | void *card; /* Bus dependent stucture varies for PCcard */ | ||
477 | int (*present_callback)(void *); /* And callback which uses it */ | ||
478 | char firmware_id[32]; | ||
479 | AtmelFWType firmware_type; | ||
480 | u8 *firmware; | ||
481 | int firmware_length; | ||
482 | struct timer_list management_timer; | ||
483 | struct net_device *dev; | ||
484 | struct device *sys_dev; | ||
485 | struct iw_statistics wstats; | ||
486 | struct net_device_stats stats; // device stats | ||
487 | spinlock_t irqlock, timerlock; // spinlocks | ||
488 | enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; | ||
489 | enum { | ||
490 | CARD_TYPE_PARALLEL_FLASH, | ||
491 | CARD_TYPE_SPI_FLASH, | ||
492 | CARD_TYPE_EEPROM | ||
493 | } card_type; | ||
494 | int do_rx_crc; /* If we need to CRC incoming packets */ | ||
495 | int probe_crc; /* set if we don't yet know */ | ||
496 | int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ | ||
497 | u16 rx_desc_head; | ||
498 | u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; | ||
499 | u16 tx_free_mem, tx_buff_head, tx_buff_tail; | ||
500 | |||
501 | u16 frag_seq, frag_len, frag_no; | ||
502 | u8 frag_source[6]; | ||
503 | |||
504 | u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; | ||
505 | u8 group_cipher_suite, pairwise_cipher_suite; | ||
506 | u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; | ||
507 | int wep_key_len[MAX_ENCRYPTION_KEYS]; | ||
508 | int use_wpa, radio_on_broken; /* firmware dependent stuff. */ | ||
509 | |||
510 | u16 host_info_base; | ||
511 | struct host_info_struct { | ||
512 | /* NB this is matched to the hardware, don't change. */ | ||
513 | u8 volatile int_status; | ||
514 | u8 volatile int_mask; | ||
515 | u8 volatile lockout_host; | ||
516 | u8 volatile lockout_mac; | ||
517 | |||
518 | u16 tx_buff_pos; | ||
519 | u16 tx_buff_size; | ||
520 | u16 tx_desc_pos; | ||
521 | u16 tx_desc_count; | ||
522 | |||
523 | u16 rx_buff_pos; | ||
524 | u16 rx_buff_size; | ||
525 | u16 rx_desc_pos; | ||
526 | u16 rx_desc_count; | ||
527 | |||
528 | u16 build_version; | ||
529 | u16 command_pos; | ||
530 | |||
531 | u16 major_version; | ||
532 | u16 minor_version; | ||
533 | |||
534 | u16 func_ctrl; | ||
535 | u16 mac_status; | ||
536 | u16 generic_IRQ_type; | ||
537 | u8 reserved[2]; | ||
538 | } host_info; | ||
539 | |||
540 | enum { | ||
541 | STATION_STATE_SCANNING, | ||
542 | STATION_STATE_JOINNING, | ||
543 | STATION_STATE_AUTHENTICATING, | ||
544 | STATION_STATE_ASSOCIATING, | ||
545 | STATION_STATE_READY, | ||
546 | STATION_STATE_REASSOCIATING, | ||
547 | STATION_STATE_DOWN, | ||
548 | STATION_STATE_MGMT_ERROR | ||
549 | } station_state; | ||
550 | |||
551 | int operating_mode, power_mode; | ||
552 | time_t last_qual; | ||
553 | int beacons_this_sec; | ||
554 | int channel; | ||
555 | int reg_domain, config_reg_domain; | ||
556 | int tx_rate; | ||
557 | int auto_tx_rate; | ||
558 | int rts_threshold; | ||
559 | int frag_threshold; | ||
560 | int long_retry, short_retry; | ||
561 | int preamble; | ||
562 | int default_beacon_period, beacon_period, listen_interval; | ||
563 | int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; | ||
564 | int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; | ||
565 | enum { | ||
566 | SITE_SURVEY_IDLE, | ||
567 | SITE_SURVEY_IN_PROGRESS, | ||
568 | SITE_SURVEY_COMPLETED | ||
569 | } site_survey_state; | ||
570 | time_t last_survey; | ||
571 | |||
572 | int station_was_associated, station_is_associated; | ||
573 | int fast_scan; | ||
574 | |||
575 | struct bss_info { | ||
576 | int channel; | ||
577 | int SSIDsize; | ||
578 | int RSSI; | ||
579 | int UsingWEP; | ||
580 | int preamble; | ||
581 | int beacon_period; | ||
582 | int BSStype; | ||
583 | u8 BSSID[6]; | ||
584 | u8 SSID[MAX_SSID_LENGTH]; | ||
585 | } BSSinfo[MAX_BSS_ENTRIES]; | ||
586 | int BSS_list_entries, current_BSS; | ||
587 | int connect_to_any_BSS; | ||
588 | int SSID_size, new_SSID_size; | ||
589 | u8 CurrentBSSID[6], BSSID[6]; | ||
590 | u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; | ||
591 | u64 last_beacon_timestamp; | ||
592 | u8 rx_buf[MAX_WIRELESS_BODY]; | ||
593 | |||
594 | }; | ||
595 | |||
596 | static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16}; | ||
597 | |||
598 | static const struct { | ||
599 | int reg_domain; | ||
600 | int min, max; | ||
601 | char *name; | ||
602 | } channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, | ||
603 | { REG_DOMAIN_DOC, 1, 11, "Canada" }, | ||
604 | { REG_DOMAIN_ETSI, 1, 13, "Europe" }, | ||
605 | { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, | ||
606 | { REG_DOMAIN_FRANCE, 10, 13, "France" }, | ||
607 | { REG_DOMAIN_MKK, 14, 14, "MKK" }, | ||
608 | { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, | ||
609 | { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; | ||
610 | |||
611 | static void build_wpa_mib(struct atmel_private *priv); | ||
612 | static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | ||
613 | static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len); | ||
614 | static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len); | ||
615 | static void atmel_set_gcr(struct net_device *dev, u16 mask); | ||
616 | static void atmel_clear_gcr(struct net_device *dev, u16 mask); | ||
617 | static int atmel_lock_mac(struct atmel_private *priv); | ||
618 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); | ||
619 | static void atmel_command_irq(struct atmel_private *priv); | ||
620 | static int atmel_validate_channel(struct atmel_private *priv, int channel); | ||
621 | static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, | ||
622 | u16 frame_len, u8 rssi); | ||
623 | static void atmel_management_timer(u_long a); | ||
624 | static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); | ||
625 | static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); | ||
626 | static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, | ||
627 | u8 *body, int body_len); | ||
628 | |||
629 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); | ||
630 | static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data); | ||
631 | static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data); | ||
632 | static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); | ||
633 | static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); | ||
634 | static void atmel_scan(struct atmel_private *priv, int specific_ssid); | ||
635 | static void atmel_join_bss(struct atmel_private *priv, int bss_index); | ||
636 | static void atmel_smooth_qual(struct atmel_private *priv); | ||
637 | static void atmel_writeAR(struct net_device *dev, u16 data); | ||
638 | static int probe_atmel_card(struct net_device *dev); | ||
639 | static int reset_atmel_card(struct net_device *dev ); | ||
640 | static void atmel_enter_state(struct atmel_private *priv, int new_state); | ||
641 | int atmel_open (struct net_device *dev); | ||
642 | |||
643 | static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) | ||
644 | { | ||
645 | return priv->host_info_base + offset; | ||
646 | } | ||
647 | |||
648 | static inline u16 atmel_co(struct atmel_private *priv, u16 offset) | ||
649 | { | ||
650 | return priv->host_info.command_pos + offset; | ||
651 | } | ||
652 | |||
653 | static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) | ||
654 | { | ||
655 | return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; | ||
656 | } | ||
657 | |||
658 | static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) | ||
659 | { | ||
660 | return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; | ||
661 | } | ||
662 | |||
663 | static inline u8 atmel_read8(struct net_device *dev, u16 offset) | ||
664 | { | ||
665 | return inb(dev->base_addr + offset); | ||
666 | } | ||
667 | |||
668 | static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) | ||
669 | { | ||
670 | outb(data, dev->base_addr + offset); | ||
671 | } | ||
672 | |||
673 | static inline u16 atmel_read16(struct net_device *dev, u16 offset) | ||
674 | { | ||
675 | return inw(dev->base_addr + offset); | ||
676 | } | ||
677 | |||
678 | static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) | ||
679 | { | ||
680 | outw(data, dev->base_addr + offset); | ||
681 | } | ||
682 | |||
683 | static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) | ||
684 | { | ||
685 | atmel_writeAR(priv->dev, pos); | ||
686 | return atmel_read8(priv->dev, DR); | ||
687 | } | ||
688 | |||
689 | static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) | ||
690 | { | ||
691 | atmel_writeAR(priv->dev, pos); | ||
692 | atmel_write8(priv->dev, DR, data); | ||
693 | } | ||
694 | |||
695 | static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) | ||
696 | { | ||
697 | atmel_writeAR(priv->dev, pos); | ||
698 | return atmel_read16(priv->dev, DR); | ||
699 | } | ||
700 | |||
701 | static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) | ||
702 | { | ||
703 | atmel_writeAR(priv->dev, pos); | ||
704 | atmel_write16(priv->dev, DR, data); | ||
705 | } | ||
706 | |||
707 | static const struct iw_handler_def atmel_handler_def; | ||
708 | |||
709 | static void tx_done_irq(struct atmel_private *priv) | ||
710 | { | ||
711 | int i; | ||
712 | |||
713 | for (i = 0; | ||
714 | atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && | ||
715 | i < priv->host_info.tx_desc_count; | ||
716 | i++) { | ||
717 | |||
718 | u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); | ||
719 | u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); | ||
720 | u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); | ||
721 | |||
722 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); | ||
723 | |||
724 | priv->tx_free_mem += msdu_size; | ||
725 | priv->tx_desc_free++; | ||
726 | |||
727 | if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) | ||
728 | priv->tx_buff_head = 0; | ||
729 | else | ||
730 | priv->tx_buff_head += msdu_size; | ||
731 | |||
732 | if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) | ||
733 | priv->tx_desc_head++ ; | ||
734 | else | ||
735 | priv->tx_desc_head = 0; | ||
736 | |||
737 | if (type == TX_PACKET_TYPE_DATA) { | ||
738 | if (status == TX_STATUS_SUCCESS) | ||
739 | priv->stats.tx_packets++; | ||
740 | else | ||
741 | priv->stats.tx_errors++; | ||
742 | netif_wake_queue(priv->dev); | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | |||
747 | static u16 find_tx_buff(struct atmel_private *priv, u16 len) | ||
748 | { | ||
749 | u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; | ||
750 | |||
751 | if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) | ||
752 | return 0; | ||
753 | |||
754 | if (bottom_free >= len) | ||
755 | return priv->host_info.tx_buff_pos + priv->tx_buff_tail; | ||
756 | |||
757 | if (priv->tx_free_mem - bottom_free >= len) { | ||
758 | priv->tx_buff_tail = 0; | ||
759 | return priv->host_info.tx_buff_pos; | ||
760 | } | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 len, u16 buff, u8 type) | ||
766 | { | ||
767 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); | ||
768 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); | ||
769 | if (!priv->use_wpa) | ||
770 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); | ||
771 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); | ||
772 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); | ||
773 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); | ||
774 | if (priv->use_wpa) { | ||
775 | int cipher_type, cipher_length; | ||
776 | if (is_bcast) { | ||
777 | cipher_type = priv->group_cipher_suite; | ||
778 | if (cipher_type == CIPHER_SUITE_WEP_64 || | ||
779 | cipher_type == CIPHER_SUITE_WEP_128 ) | ||
780 | cipher_length = 8; | ||
781 | else if (cipher_type == CIPHER_SUITE_TKIP) | ||
782 | cipher_length = 12; | ||
783 | else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || | ||
784 | priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { | ||
785 | cipher_type = priv->pairwise_cipher_suite; | ||
786 | cipher_length = 8; | ||
787 | } else { | ||
788 | cipher_type = CIPHER_SUITE_NONE; | ||
789 | cipher_length = 0; | ||
790 | } | ||
791 | } else { | ||
792 | cipher_type = priv->pairwise_cipher_suite; | ||
793 | if (cipher_type == CIPHER_SUITE_WEP_64 || | ||
794 | cipher_type == CIPHER_SUITE_WEP_128 ) | ||
795 | cipher_length = 8; | ||
796 | else if (cipher_type == CIPHER_SUITE_TKIP) | ||
797 | cipher_length = 12; | ||
798 | else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || | ||
799 | priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { | ||
800 | cipher_type = priv->group_cipher_suite; | ||
801 | cipher_length = 8; | ||
802 | } else { | ||
803 | cipher_type = CIPHER_SUITE_NONE; | ||
804 | cipher_length = 0; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), | ||
809 | cipher_type); | ||
810 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), | ||
811 | cipher_length); | ||
812 | } | ||
813 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); | ||
814 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); | ||
815 | if (priv->tx_desc_previous != priv->tx_desc_tail) | ||
816 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); | ||
817 | priv->tx_desc_previous = priv->tx_desc_tail; | ||
818 | if (priv->tx_desc_tail < (priv->host_info.tx_desc_count -1 )) | ||
819 | priv->tx_desc_tail++; | ||
820 | else | ||
821 | priv->tx_desc_tail = 0; | ||
822 | priv->tx_desc_free--; | ||
823 | priv->tx_free_mem -= len; | ||
824 | |||
825 | } | ||
826 | |||
827 | static int start_tx (struct sk_buff *skb, struct net_device *dev) | ||
828 | { | ||
829 | struct atmel_private *priv = netdev_priv(dev); | ||
830 | struct ieee802_11_hdr header; | ||
831 | unsigned long flags; | ||
832 | u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; | ||
833 | u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | ||
834 | |||
835 | if (priv->card && priv->present_callback && | ||
836 | !(*priv->present_callback)(priv->card)) { | ||
837 | priv->stats.tx_errors++; | ||
838 | dev_kfree_skb(skb); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | if (priv->station_state != STATION_STATE_READY) { | ||
843 | priv->stats.tx_errors++; | ||
844 | dev_kfree_skb(skb); | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | /* first ensure the timer func cannot run */ | ||
849 | spin_lock_bh(&priv->timerlock); | ||
850 | /* then stop the hardware ISR */ | ||
851 | spin_lock_irqsave(&priv->irqlock, flags); | ||
852 | /* nb doing the above in the opposite order will deadlock */ | ||
853 | |||
854 | /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the | ||
855 | 12 first bytes (containing DA/SA) and put them in the appropriate fields of | ||
856 | the Wireless Header. Thus the packet length is then the initial + 18 (+30-12) */ | ||
857 | |||
858 | if (!(buff = find_tx_buff(priv, len + 18))) { | ||
859 | priv->stats.tx_dropped++; | ||
860 | spin_unlock_irqrestore(&priv->irqlock, flags); | ||
861 | spin_unlock_bh(&priv->timerlock); | ||
862 | netif_stop_queue(dev); | ||
863 | return 1; | ||
864 | } | ||
865 | |||
866 | frame_ctl = IEEE802_11_FTYPE_DATA; | ||
867 | header.duration_id = 0; | ||
868 | header.seq_ctl = 0; | ||
869 | if (priv->wep_is_on) | ||
870 | frame_ctl |= IEEE802_11_FCTL_WEP; | ||
871 | if (priv->operating_mode == IW_MODE_ADHOC) { | ||
872 | memcpy(&header.addr1, skb->data, 6); | ||
873 | memcpy(&header.addr2, dev->dev_addr, 6); | ||
874 | memcpy(&header.addr3, priv->BSSID, 6); | ||
875 | } else { | ||
876 | frame_ctl |= IEEE802_11_FCTL_TODS; | ||
877 | memcpy(&header.addr1, priv->CurrentBSSID, 6); | ||
878 | memcpy(&header.addr2, dev->dev_addr, 6); | ||
879 | memcpy(&header.addr3, skb->data, 6); | ||
880 | } | ||
881 | |||
882 | if (priv->use_wpa) | ||
883 | memcpy(&header.addr4, SNAP_RFC1024, 6); | ||
884 | |||
885 | header.frame_ctl = cpu_to_le16(frame_ctl); | ||
886 | /* Copy the wireless header into the card */ | ||
887 | atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); | ||
888 | /* Copy the packet sans its 802.3 header addresses which have been replaced */ | ||
889 | atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); | ||
890 | priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; | ||
891 | |||
892 | /* low bit of first byte of destination tells us if broadcast */ | ||
893 | tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); | ||
894 | dev->trans_start = jiffies; | ||
895 | priv->stats.tx_bytes += len; | ||
896 | |||
897 | spin_unlock_irqrestore(&priv->irqlock, flags); | ||
898 | spin_unlock_bh(&priv->timerlock); | ||
899 | dev_kfree_skb(skb); | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static void atmel_transmit_management_frame(struct atmel_private *priv, | ||
905 | struct ieee802_11_hdr *header, | ||
906 | u8 *body, int body_len) | ||
907 | { | ||
908 | u16 buff; | ||
909 | int len = MGMT_FRAME_BODY_OFFSET + body_len; | ||
910 | |||
911 | if (!(buff = find_tx_buff(priv, len))) | ||
912 | return; | ||
913 | |||
914 | atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); | ||
915 | atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); | ||
916 | priv->tx_buff_tail += len; | ||
917 | tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); | ||
918 | } | ||
919 | |||
920 | static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, | ||
921 | u16 msdu_size, u16 rx_packet_loc, u32 crc) | ||
922 | { | ||
923 | /* fast path: unfragmented packet copy directly into skbuf */ | ||
924 | u8 mac4[6]; | ||
925 | struct sk_buff *skb; | ||
926 | unsigned char *skbp; | ||
927 | |||
928 | /* get the final, mac 4 header field, this tells us encapsulation */ | ||
929 | atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); | ||
930 | msdu_size -= 6; | ||
931 | |||
932 | if (priv->do_rx_crc) { | ||
933 | crc = crc32_le(crc, mac4, 6); | ||
934 | msdu_size -= 4; | ||
935 | } | ||
936 | |||
937 | if (!(skb = dev_alloc_skb(msdu_size + 14))) { | ||
938 | priv->stats.rx_dropped++; | ||
939 | return; | ||
940 | } | ||
941 | |||
942 | skb_reserve(skb, 2); | ||
943 | skbp = skb_put(skb, msdu_size + 12); | ||
944 | atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); | ||
945 | |||
946 | if (priv->do_rx_crc) { | ||
947 | u32 netcrc; | ||
948 | crc = crc32_le(crc, skbp + 12, msdu_size); | ||
949 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); | ||
950 | if ((crc ^ 0xffffffff) != netcrc) { | ||
951 | priv->stats.rx_crc_errors++; | ||
952 | dev_kfree_skb(skb); | ||
953 | return; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | memcpy(skbp, header->addr1, 6); /* destination address */ | ||
958 | if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) | ||
959 | memcpy(&skbp[6], header->addr3, 6); | ||
960 | else | ||
961 | memcpy(&skbp[6], header->addr2, 6); /* source address */ | ||
962 | |||
963 | priv->dev->last_rx=jiffies; | ||
964 | skb->dev = priv->dev; | ||
965 | skb->protocol = eth_type_trans(skb, priv->dev); | ||
966 | skb->ip_summed = CHECKSUM_NONE; | ||
967 | netif_rx(skb); | ||
968 | priv->stats.rx_bytes += 12 + msdu_size; | ||
969 | priv->stats.rx_packets++; | ||
970 | } | ||
971 | |||
972 | /* Test to see if the packet in card memory at packet_loc has a valid CRC | ||
973 | It doesn't matter that this is slow: it is only used to proble the first few packets. */ | ||
974 | static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) | ||
975 | { | ||
976 | int i = msdu_size - 4; | ||
977 | u32 netcrc, crc = 0xffffffff; | ||
978 | |||
979 | if (msdu_size < 4) | ||
980 | return 0; | ||
981 | |||
982 | atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); | ||
983 | |||
984 | atmel_writeAR(priv->dev, packet_loc); | ||
985 | while (i--) { | ||
986 | u8 octet = atmel_read8(priv->dev, DR); | ||
987 | crc = crc32_le(crc, &octet, 1); | ||
988 | } | ||
989 | |||
990 | return (crc ^ 0xffffffff) == netcrc; | ||
991 | } | ||
992 | |||
993 | static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, | ||
994 | u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) | ||
995 | { | ||
996 | u8 mac4[6]; | ||
997 | u8 source[6]; | ||
998 | struct sk_buff *skb; | ||
999 | |||
1000 | if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) | ||
1001 | memcpy(source, header->addr3, 6); | ||
1002 | else | ||
1003 | memcpy(source, header->addr2, 6); | ||
1004 | |||
1005 | rx_packet_loc += 24; /* skip header */ | ||
1006 | |||
1007 | if (priv->do_rx_crc) | ||
1008 | msdu_size -= 4; | ||
1009 | |||
1010 | if (frag_no == 0) { /* first fragment */ | ||
1011 | atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); | ||
1012 | msdu_size -= 6; | ||
1013 | rx_packet_loc += 6; | ||
1014 | |||
1015 | if (priv->do_rx_crc) | ||
1016 | crc = crc32_le(crc, mac4, 6); | ||
1017 | |||
1018 | priv->frag_seq = seq_no; | ||
1019 | priv->frag_no = 1; | ||
1020 | priv->frag_len = msdu_size; | ||
1021 | memcpy(priv->frag_source, source, 6); | ||
1022 | memcpy(&priv->rx_buf[6], source, 6); | ||
1023 | memcpy(priv->rx_buf, header->addr1, 6); | ||
1024 | |||
1025 | atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); | ||
1026 | |||
1027 | if (priv->do_rx_crc) { | ||
1028 | u32 netcrc; | ||
1029 | crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); | ||
1030 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); | ||
1031 | if ((crc ^ 0xffffffff) != netcrc) { | ||
1032 | priv->stats.rx_crc_errors++; | ||
1033 | memset(priv->frag_source, 0xff, 6); | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | } else if (priv->frag_no == frag_no && | ||
1038 | priv->frag_seq == seq_no && | ||
1039 | memcmp(priv->frag_source, source, 6) == 0) { | ||
1040 | |||
1041 | atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], | ||
1042 | rx_packet_loc, msdu_size); | ||
1043 | if (priv->do_rx_crc) { | ||
1044 | u32 netcrc; | ||
1045 | crc = crc32_le(crc, | ||
1046 | &priv->rx_buf[12 + priv->frag_len], | ||
1047 | msdu_size); | ||
1048 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); | ||
1049 | if ((crc ^ 0xffffffff) != netcrc) { | ||
1050 | priv->stats.rx_crc_errors++; | ||
1051 | memset(priv->frag_source, 0xff, 6); | ||
1052 | more_frags = 1; /* don't send broken assembly */ | ||
1053 | } | ||
1054 | } | ||
1055 | |||
1056 | priv->frag_len += msdu_size; | ||
1057 | priv->frag_no++; | ||
1058 | |||
1059 | if (!more_frags) { /* last one */ | ||
1060 | memset(priv->frag_source, 0xff, 6); | ||
1061 | if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { | ||
1062 | priv->stats.rx_dropped++; | ||
1063 | } else { | ||
1064 | skb_reserve(skb, 2); | ||
1065 | memcpy(skb_put(skb, priv->frag_len + 12), | ||
1066 | priv->rx_buf, | ||
1067 | priv->frag_len + 12); | ||
1068 | priv->dev->last_rx = jiffies; | ||
1069 | skb->dev = priv->dev; | ||
1070 | skb->protocol = eth_type_trans(skb, priv->dev); | ||
1071 | skb->ip_summed = CHECKSUM_NONE; | ||
1072 | netif_rx(skb); | ||
1073 | priv->stats.rx_bytes += priv->frag_len + 12; | ||
1074 | priv->stats.rx_packets++; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | } else | ||
1079 | priv->wstats.discard.fragment++; | ||
1080 | } | ||
1081 | |||
1082 | static void rx_done_irq(struct atmel_private *priv) | ||
1083 | { | ||
1084 | int i; | ||
1085 | struct ieee802_11_hdr header; | ||
1086 | |||
1087 | for (i = 0; | ||
1088 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && | ||
1089 | i < priv->host_info.rx_desc_count; | ||
1090 | i++) { | ||
1091 | |||
1092 | u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; | ||
1093 | u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); | ||
1094 | u32 crc = 0xffffffff; | ||
1095 | |||
1096 | if (status != RX_STATUS_SUCCESS) { | ||
1097 | if (status == 0xc1) /* determined by experiment */ | ||
1098 | priv->wstats.discard.nwid++; | ||
1099 | else | ||
1100 | priv->stats.rx_errors++; | ||
1101 | goto next; | ||
1102 | } | ||
1103 | |||
1104 | msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); | ||
1105 | rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); | ||
1106 | |||
1107 | if (msdu_size < 30) { | ||
1108 | priv->stats.rx_errors++; | ||
1109 | goto next; | ||
1110 | } | ||
1111 | |||
1112 | /* Get header as far as end of seq_ctl */ | ||
1113 | atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); | ||
1114 | frame_ctl = le16_to_cpu(header.frame_ctl); | ||
1115 | seq_control = le16_to_cpu(header.seq_ctl); | ||
1116 | |||
1117 | /* probe for CRC use here if needed once five packets have arrived with | ||
1118 | the same crc status, we assume we know what's happening and stop probing */ | ||
1119 | if (priv->probe_crc) { | ||
1120 | if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) { | ||
1121 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); | ||
1122 | } else { | ||
1123 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); | ||
1124 | } | ||
1125 | if (priv->do_rx_crc) { | ||
1126 | if (priv->crc_ok_cnt++ > 5) | ||
1127 | priv->probe_crc = 0; | ||
1128 | } else { | ||
1129 | if (priv->crc_ko_cnt++ > 5) | ||
1130 | priv->probe_crc = 0; | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | /* don't CRC header when WEP in use */ | ||
1135 | if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) { | ||
1136 | crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); | ||
1137 | } | ||
1138 | msdu_size -= 24; /* header */ | ||
1139 | |||
1140 | if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { | ||
1141 | |||
1142 | int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS; | ||
1143 | u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG; | ||
1144 | u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4; | ||
1145 | |||
1146 | if (!more_fragments && packet_fragment_no == 0 ) { | ||
1147 | fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); | ||
1148 | } else { | ||
1149 | frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, | ||
1150 | packet_sequence_no, packet_fragment_no, more_fragments); | ||
1151 | } | ||
1152 | } | ||
1153 | |||
1154 | if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) { | ||
1155 | /* copy rest of packet into buffer */ | ||
1156 | atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); | ||
1157 | |||
1158 | /* we use the same buffer for frag reassembly and control packets */ | ||
1159 | memset(priv->frag_source, 0xff, 6); | ||
1160 | |||
1161 | if (priv->do_rx_crc) { | ||
1162 | /* last 4 octets is crc */ | ||
1163 | msdu_size -= 4; | ||
1164 | crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); | ||
1165 | if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { | ||
1166 | priv->stats.rx_crc_errors++; | ||
1167 | goto next; | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | atmel_management_frame(priv, &header, msdu_size, | ||
1172 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); | ||
1173 | } | ||
1174 | |||
1175 | next: | ||
1176 | /* release descriptor */ | ||
1177 | atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); | ||
1178 | |||
1179 | if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) | ||
1180 | priv->rx_desc_head++; | ||
1181 | else | ||
1182 | priv->rx_desc_head = 0; | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1186 | static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1187 | { | ||
1188 | struct net_device *dev = (struct net_device *) dev_id; | ||
1189 | struct atmel_private *priv = netdev_priv(dev); | ||
1190 | u8 isr; | ||
1191 | int i = -1; | ||
1192 | static u8 irq_order[] = { | ||
1193 | ISR_OUT_OF_RANGE, | ||
1194 | ISR_RxCOMPLETE, | ||
1195 | ISR_TxCOMPLETE, | ||
1196 | ISR_RxFRAMELOST, | ||
1197 | ISR_FATAL_ERROR, | ||
1198 | ISR_COMMAND_COMPLETE, | ||
1199 | ISR_IBSS_MERGE, | ||
1200 | ISR_GENERIC_IRQ | ||
1201 | }; | ||
1202 | |||
1203 | |||
1204 | if (priv->card && priv->present_callback && | ||
1205 | !(*priv->present_callback)(priv->card)) | ||
1206 | return IRQ_HANDLED; | ||
1207 | |||
1208 | /* In this state upper-level code assumes it can mess with | ||
1209 | the card unhampered by interrupts which may change register state. | ||
1210 | Note that even though the card shouldn't generate interrupts | ||
1211 | the inturrupt line may be shared. This allows card setup | ||
1212 | to go on without disabling interrupts for a long time. */ | ||
1213 | if (priv->station_state == STATION_STATE_DOWN) | ||
1214 | return IRQ_NONE; | ||
1215 | |||
1216 | atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ | ||
1217 | |||
1218 | while (1) { | ||
1219 | if (!atmel_lock_mac(priv)) { | ||
1220 | /* failed to contact card */ | ||
1221 | printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); | ||
1222 | return IRQ_HANDLED; | ||
1223 | } | ||
1224 | |||
1225 | isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); | ||
1226 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | ||
1227 | |||
1228 | if (!isr) { | ||
1229 | atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ | ||
1230 | return i == -1 ? IRQ_NONE : IRQ_HANDLED; | ||
1231 | } | ||
1232 | |||
1233 | atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ | ||
1234 | |||
1235 | for (i = 0; i < sizeof(irq_order)/sizeof(u8); i++) | ||
1236 | if (isr & irq_order[i]) | ||
1237 | break; | ||
1238 | |||
1239 | if (!atmel_lock_mac(priv)) { | ||
1240 | /* failed to contact card */ | ||
1241 | printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); | ||
1242 | return IRQ_HANDLED; | ||
1243 | } | ||
1244 | |||
1245 | isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); | ||
1246 | isr ^= irq_order[i]; | ||
1247 | atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); | ||
1248 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | ||
1249 | |||
1250 | switch (irq_order[i]) { | ||
1251 | |||
1252 | case ISR_OUT_OF_RANGE: | ||
1253 | if (priv->operating_mode == IW_MODE_INFRA && | ||
1254 | priv->station_state == STATION_STATE_READY) { | ||
1255 | priv->station_is_associated = 0; | ||
1256 | atmel_scan(priv, 1); | ||
1257 | } | ||
1258 | break; | ||
1259 | |||
1260 | case ISR_RxFRAMELOST: | ||
1261 | priv->wstats.discard.misc++; | ||
1262 | /* fall through */ | ||
1263 | case ISR_RxCOMPLETE: | ||
1264 | rx_done_irq(priv); | ||
1265 | break; | ||
1266 | |||
1267 | case ISR_TxCOMPLETE: | ||
1268 | tx_done_irq(priv); | ||
1269 | break; | ||
1270 | |||
1271 | case ISR_FATAL_ERROR: | ||
1272 | printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); | ||
1273 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
1274 | break; | ||
1275 | |||
1276 | case ISR_COMMAND_COMPLETE: | ||
1277 | atmel_command_irq(priv); | ||
1278 | break; | ||
1279 | |||
1280 | case ISR_IBSS_MERGE: | ||
1281 | atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, | ||
1282 | priv->CurrentBSSID, 6); | ||
1283 | /* The WPA stuff cares about the current AP address */ | ||
1284 | if (priv->use_wpa) | ||
1285 | build_wpa_mib(priv); | ||
1286 | break; | ||
1287 | case ISR_GENERIC_IRQ: | ||
1288 | printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); | ||
1289 | break; | ||
1290 | } | ||
1291 | } | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | static struct net_device_stats *atmel_get_stats (struct net_device *dev) | ||
1296 | { | ||
1297 | struct atmel_private *priv = netdev_priv(dev); | ||
1298 | return &priv->stats; | ||
1299 | } | ||
1300 | |||
1301 | static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev) | ||
1302 | { | ||
1303 | struct atmel_private *priv = netdev_priv(dev); | ||
1304 | |||
1305 | /* update the link quality here in case we are seeing no beacons | ||
1306 | at all to drive the process */ | ||
1307 | atmel_smooth_qual(priv); | ||
1308 | |||
1309 | priv->wstats.status = priv->station_state; | ||
1310 | |||
1311 | if (priv->operating_mode == IW_MODE_INFRA) { | ||
1312 | if (priv->station_state != STATION_STATE_READY) { | ||
1313 | priv->wstats.qual.qual = 0; | ||
1314 | priv->wstats.qual.level = 0; | ||
1315 | priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID | ||
1316 | | IW_QUAL_LEVEL_INVALID); | ||
1317 | } | ||
1318 | priv->wstats.qual.noise = 0; | ||
1319 | priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | ||
1320 | } else { | ||
1321 | /* Quality levels cannot be determined in ad-hoc mode, | ||
1322 | because we can 'hear' more that one remote station. */ | ||
1323 | priv->wstats.qual.qual = 0; | ||
1324 | priv->wstats.qual.level = 0; | ||
1325 | priv->wstats.qual.noise = 0; | ||
1326 | priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID | ||
1327 | | IW_QUAL_LEVEL_INVALID | ||
1328 | | IW_QUAL_NOISE_INVALID; | ||
1329 | priv->wstats.miss.beacon = 0; | ||
1330 | } | ||
1331 | |||
1332 | return (&priv->wstats); | ||
1333 | } | ||
1334 | |||
1335 | static int atmel_change_mtu(struct net_device *dev, int new_mtu) | ||
1336 | { | ||
1337 | if ((new_mtu < 68) || (new_mtu > 2312)) | ||
1338 | return -EINVAL; | ||
1339 | dev->mtu = new_mtu; | ||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1343 | static int atmel_set_mac_address(struct net_device *dev, void *p) | ||
1344 | { | ||
1345 | struct sockaddr *addr = p; | ||
1346 | |||
1347 | memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); | ||
1348 | return atmel_open(dev); | ||
1349 | } | ||
1350 | |||
1351 | EXPORT_SYMBOL(atmel_open); | ||
1352 | |||
1353 | int atmel_open (struct net_device *dev) | ||
1354 | { | ||
1355 | struct atmel_private *priv = netdev_priv(dev); | ||
1356 | int i, channel; | ||
1357 | |||
1358 | /* any scheduled timer is no longer needed and might screw things up.. */ | ||
1359 | del_timer_sync(&priv->management_timer); | ||
1360 | |||
1361 | /* Interrupts will not touch the card once in this state... */ | ||
1362 | priv->station_state = STATION_STATE_DOWN; | ||
1363 | |||
1364 | if (priv->new_SSID_size) { | ||
1365 | memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); | ||
1366 | priv->SSID_size = priv->new_SSID_size; | ||
1367 | priv->new_SSID_size = 0; | ||
1368 | } | ||
1369 | priv->BSS_list_entries = 0; | ||
1370 | |||
1371 | priv->AuthenticationRequestRetryCnt = 0; | ||
1372 | priv->AssociationRequestRetryCnt = 0; | ||
1373 | priv->ReAssociationRequestRetryCnt = 0; | ||
1374 | priv->CurrentAuthentTransactionSeqNum = 0x0001; | ||
1375 | priv->ExpectedAuthentTransactionSeqNum = 0x0002; | ||
1376 | |||
1377 | priv->site_survey_state = SITE_SURVEY_IDLE; | ||
1378 | priv->station_is_associated = 0; | ||
1379 | |||
1380 | if (!reset_atmel_card(dev)) | ||
1381 | return -EAGAIN; | ||
1382 | |||
1383 | if (priv->config_reg_domain) { | ||
1384 | priv->reg_domain = priv->config_reg_domain; | ||
1385 | atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); | ||
1386 | } else { | ||
1387 | priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); | ||
1388 | for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) | ||
1389 | if (priv->reg_domain == channel_table[i].reg_domain) | ||
1390 | break; | ||
1391 | if (i == sizeof(channel_table)/sizeof(channel_table[0])) { | ||
1392 | priv->reg_domain = REG_DOMAIN_MKK1; | ||
1393 | printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); | ||
1394 | } | ||
1395 | } | ||
1396 | |||
1397 | if ((channel = atmel_validate_channel(priv, priv->channel))) | ||
1398 | priv->channel = channel; | ||
1399 | |||
1400 | /* this moves station_state on.... */ | ||
1401 | atmel_scan(priv, 1); | ||
1402 | |||
1403 | atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ | ||
1404 | return 0; | ||
1405 | } | ||
1406 | |||
1407 | static int atmel_close (struct net_device *dev) | ||
1408 | { | ||
1409 | struct atmel_private *priv = netdev_priv(dev); | ||
1410 | |||
1411 | atmel_enter_state(priv, STATION_STATE_DOWN); | ||
1412 | |||
1413 | if (priv->bus_type == BUS_TYPE_PCCARD) | ||
1414 | atmel_write16(dev, GCR, 0x0060); | ||
1415 | atmel_write16(dev, GCR, 0x0040); | ||
1416 | return 0; | ||
1417 | } | ||
1418 | |||
1419 | static int atmel_validate_channel(struct atmel_private *priv, int channel) | ||
1420 | { | ||
1421 | /* check that channel is OK, if so return zero, | ||
1422 | else return suitable default channel */ | ||
1423 | int i; | ||
1424 | |||
1425 | for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) | ||
1426 | if (priv->reg_domain == channel_table[i].reg_domain) { | ||
1427 | if (channel >= channel_table[i].min && | ||
1428 | channel <= channel_table[i].max) | ||
1429 | return 0; | ||
1430 | else | ||
1431 | return channel_table[i].min; | ||
1432 | } | ||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1436 | static int atmel_proc_output (char *buf, struct atmel_private *priv) | ||
1437 | { | ||
1438 | int i; | ||
1439 | char *p = buf; | ||
1440 | char *s, *r, *c; | ||
1441 | |||
1442 | p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); | ||
1443 | |||
1444 | if (priv->station_state != STATION_STATE_DOWN) { | ||
1445 | p += sprintf(p, "Firmware version:\t%d.%d build %d\nFirmware location:\t", | ||
1446 | priv->host_info.major_version, | ||
1447 | priv->host_info.minor_version, | ||
1448 | priv->host_info.build_version); | ||
1449 | |||
1450 | if (priv->card_type != CARD_TYPE_EEPROM) | ||
1451 | p += sprintf(p, "on card\n"); | ||
1452 | else if (priv->firmware) | ||
1453 | p += sprintf(p, "%s loaded by host\n", priv->firmware_id); | ||
1454 | else | ||
1455 | p += sprintf(p, "%s loaded by hotplug\n", priv->firmware_id); | ||
1456 | |||
1457 | switch(priv->card_type) { | ||
1458 | case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break; | ||
1459 | case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break; | ||
1460 | case CARD_TYPE_EEPROM: c = "EEPROM"; break; | ||
1461 | default: c = "<unknown>"; | ||
1462 | } | ||
1463 | |||
1464 | |||
1465 | r = "<unknown>"; | ||
1466 | for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) | ||
1467 | if (priv->reg_domain == channel_table[i].reg_domain) | ||
1468 | r = channel_table[i].name; | ||
1469 | |||
1470 | p += sprintf(p, "MAC memory type:\t%s\n", c); | ||
1471 | p += sprintf(p, "Regulatory domain:\t%s\n", r); | ||
1472 | p += sprintf(p, "Host CRC checking:\t%s\n", | ||
1473 | priv->do_rx_crc ? "On" : "Off"); | ||
1474 | p += sprintf(p, "WPA-capable firmware:\t%s\n", | ||
1475 | priv->use_wpa ? "Yes" : "No"); | ||
1476 | } | ||
1477 | |||
1478 | switch(priv->station_state) { | ||
1479 | case STATION_STATE_SCANNING: s = "Scanning"; break; | ||
1480 | case STATION_STATE_JOINNING: s = "Joining"; break; | ||
1481 | case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break; | ||
1482 | case STATION_STATE_ASSOCIATING: s = "Associating"; break; | ||
1483 | case STATION_STATE_READY: s = "Ready"; break; | ||
1484 | case STATION_STATE_REASSOCIATING: s = "Reassociating"; break; | ||
1485 | case STATION_STATE_MGMT_ERROR: s = "Management error"; break; | ||
1486 | case STATION_STATE_DOWN: s = "Down"; break; | ||
1487 | default: s = "<unknown>"; | ||
1488 | } | ||
1489 | |||
1490 | p += sprintf(p, "Current state:\t\t%s\n", s); | ||
1491 | return p - buf; | ||
1492 | } | ||
1493 | |||
1494 | static int atmel_read_proc(char *page, char **start, off_t off, | ||
1495 | int count, int *eof, void *data) | ||
1496 | { | ||
1497 | struct atmel_private *priv = data; | ||
1498 | int len = atmel_proc_output (page, priv); | ||
1499 | if (len <= off+count) *eof = 1; | ||
1500 | *start = page + off; | ||
1501 | len -= off; | ||
1502 | if (len>count) len = count; | ||
1503 | if (len<0) len = 0; | ||
1504 | return len; | ||
1505 | } | ||
1506 | |||
1507 | struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWType fw_type, | ||
1508 | struct device *sys_dev, int (*card_present)(void *), void *card) | ||
1509 | { | ||
1510 | struct net_device *dev; | ||
1511 | struct atmel_private *priv; | ||
1512 | int rc; | ||
1513 | |||
1514 | /* Create the network device object. */ | ||
1515 | dev = alloc_etherdev(sizeof(*priv)); | ||
1516 | if (!dev) { | ||
1517 | printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n"); | ||
1518 | return NULL; | ||
1519 | } | ||
1520 | if (dev_alloc_name(dev, dev->name) < 0) { | ||
1521 | printk(KERN_ERR "atmel: Couldn't get name!\n"); | ||
1522 | goto err_out_free; | ||
1523 | } | ||
1524 | |||
1525 | priv = netdev_priv(dev); | ||
1526 | priv->dev = dev; | ||
1527 | priv->sys_dev = sys_dev; | ||
1528 | priv->present_callback = card_present; | ||
1529 | priv->card = card; | ||
1530 | priv->firmware = NULL; | ||
1531 | priv->firmware_id[0] = '\0'; | ||
1532 | priv->firmware_type = fw_type; | ||
1533 | if (firmware) /* module parameter */ | ||
1534 | strcpy(priv->firmware_id, firmware); | ||
1535 | priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; | ||
1536 | priv->station_state = STATION_STATE_DOWN; | ||
1537 | priv->do_rx_crc = 0; | ||
1538 | /* For PCMCIA cards, some chips need CRC, some don't | ||
1539 | so we have to probe. */ | ||
1540 | if (priv->bus_type == BUS_TYPE_PCCARD) { | ||
1541 | priv->probe_crc = 1; | ||
1542 | priv->crc_ok_cnt = priv->crc_ko_cnt = 0; | ||
1543 | } else | ||
1544 | priv->probe_crc = 0; | ||
1545 | memset(&priv->stats, 0, sizeof(priv->stats)); | ||
1546 | memset(&priv->wstats, 0, sizeof(priv->wstats)); | ||
1547 | priv->last_qual = jiffies; | ||
1548 | priv->last_beacon_timestamp = 0; | ||
1549 | memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); | ||
1550 | memset(priv->BSSID, 0, 6); | ||
1551 | priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ | ||
1552 | priv->station_was_associated = 0; | ||
1553 | |||
1554 | priv->last_survey = jiffies; | ||
1555 | priv->preamble = LONG_PREAMBLE; | ||
1556 | priv->operating_mode = IW_MODE_INFRA; | ||
1557 | priv->connect_to_any_BSS = 0; | ||
1558 | priv->config_reg_domain = 0; | ||
1559 | priv->reg_domain = 0; | ||
1560 | priv->tx_rate = 3; | ||
1561 | priv->auto_tx_rate = 1; | ||
1562 | priv->channel = 4; | ||
1563 | priv->power_mode = 0; | ||
1564 | priv->SSID[0] = '\0'; | ||
1565 | priv->SSID_size = 0; | ||
1566 | priv->new_SSID_size = 0; | ||
1567 | priv->frag_threshold = 2346; | ||
1568 | priv->rts_threshold = 2347; | ||
1569 | priv->short_retry = 7; | ||
1570 | priv->long_retry = 4; | ||
1571 | |||
1572 | priv->wep_is_on = 0; | ||
1573 | priv->default_key = 0; | ||
1574 | priv->encryption_level = 0; | ||
1575 | priv->exclude_unencrypted = 0; | ||
1576 | priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | ||
1577 | priv->use_wpa = 0; | ||
1578 | memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); | ||
1579 | memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); | ||
1580 | |||
1581 | priv->default_beacon_period = priv->beacon_period = 100; | ||
1582 | priv->listen_interval = 1; | ||
1583 | |||
1584 | init_timer(&priv->management_timer); | ||
1585 | spin_lock_init(&priv->irqlock); | ||
1586 | spin_lock_init(&priv->timerlock); | ||
1587 | priv->management_timer.function = atmel_management_timer; | ||
1588 | priv->management_timer.data = (unsigned long) dev; | ||
1589 | |||
1590 | dev->open = atmel_open; | ||
1591 | dev->stop = atmel_close; | ||
1592 | dev->change_mtu = atmel_change_mtu; | ||
1593 | dev->set_mac_address = atmel_set_mac_address; | ||
1594 | dev->hard_start_xmit = start_tx; | ||
1595 | dev->get_stats = atmel_get_stats; | ||
1596 | dev->get_wireless_stats = atmel_get_wireless_stats; | ||
1597 | dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; | ||
1598 | dev->do_ioctl = atmel_ioctl; | ||
1599 | dev->irq = irq; | ||
1600 | dev->base_addr = port; | ||
1601 | |||
1602 | SET_NETDEV_DEV(dev, sys_dev); | ||
1603 | |||
1604 | if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) { | ||
1605 | printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc ); | ||
1606 | goto err_out_free; | ||
1607 | } | ||
1608 | |||
1609 | if (priv->bus_type == BUS_TYPE_PCI && | ||
1610 | !request_region( dev->base_addr, 64, dev->name )) { | ||
1611 | goto err_out_irq; | ||
1612 | } | ||
1613 | |||
1614 | if (register_netdev(dev)) | ||
1615 | goto err_out_res; | ||
1616 | |||
1617 | if (!probe_atmel_card(dev)){ | ||
1618 | unregister_netdev(dev); | ||
1619 | goto err_out_res; | ||
1620 | } | ||
1621 | |||
1622 | netif_carrier_off(dev); | ||
1623 | |||
1624 | create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv); | ||
1625 | |||
1626 | printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n", | ||
1627 | dev->name, DRIVER_MAJOR, DRIVER_MINOR); | ||
1628 | |||
1629 | SET_MODULE_OWNER(dev); | ||
1630 | return dev; | ||
1631 | |||
1632 | err_out_res: | ||
1633 | if (priv->bus_type == BUS_TYPE_PCI) | ||
1634 | release_region( dev->base_addr, 64 ); | ||
1635 | err_out_irq: | ||
1636 | free_irq(dev->irq, dev); | ||
1637 | err_out_free: | ||
1638 | free_netdev(dev); | ||
1639 | return NULL; | ||
1640 | } | ||
1641 | |||
1642 | EXPORT_SYMBOL(init_atmel_card); | ||
1643 | |||
1644 | void stop_atmel_card(struct net_device *dev, int freeres) | ||
1645 | { | ||
1646 | struct atmel_private *priv = netdev_priv(dev); | ||
1647 | |||
1648 | /* put a brick on it... */ | ||
1649 | if (priv->bus_type == BUS_TYPE_PCCARD) | ||
1650 | atmel_write16(dev, GCR, 0x0060); | ||
1651 | atmel_write16(dev, GCR, 0x0040); | ||
1652 | |||
1653 | del_timer_sync(&priv->management_timer); | ||
1654 | unregister_netdev(dev); | ||
1655 | remove_proc_entry("driver/atmel", NULL); | ||
1656 | free_irq(dev->irq, dev); | ||
1657 | if (priv->firmware) | ||
1658 | kfree(priv->firmware); | ||
1659 | if (freeres) { | ||
1660 | /* PCMCIA frees this stuff, so only for PCI */ | ||
1661 | release_region(dev->base_addr, 64); | ||
1662 | } | ||
1663 | free_netdev(dev); | ||
1664 | } | ||
1665 | |||
1666 | EXPORT_SYMBOL(stop_atmel_card); | ||
1667 | |||
1668 | static int atmel_set_essid(struct net_device *dev, | ||
1669 | struct iw_request_info *info, | ||
1670 | struct iw_point *dwrq, | ||
1671 | char *extra) | ||
1672 | { | ||
1673 | struct atmel_private *priv = netdev_priv(dev); | ||
1674 | |||
1675 | /* Check if we asked for `any' */ | ||
1676 | if(dwrq->flags == 0) { | ||
1677 | priv->connect_to_any_BSS = 1; | ||
1678 | } else { | ||
1679 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1680 | |||
1681 | priv->connect_to_any_BSS = 0; | ||
1682 | |||
1683 | /* Check the size of the string */ | ||
1684 | if (dwrq->length > MAX_SSID_LENGTH + 1) | ||
1685 | return -E2BIG ; | ||
1686 | if (index != 0) | ||
1687 | return -EINVAL; | ||
1688 | |||
1689 | memcpy(priv->new_SSID, extra, dwrq->length - 1); | ||
1690 | priv->new_SSID_size = dwrq->length - 1; | ||
1691 | } | ||
1692 | |||
1693 | return -EINPROGRESS; | ||
1694 | } | ||
1695 | |||
1696 | static int atmel_get_essid(struct net_device *dev, | ||
1697 | struct iw_request_info *info, | ||
1698 | struct iw_point *dwrq, | ||
1699 | char *extra) | ||
1700 | { | ||
1701 | struct atmel_private *priv = netdev_priv(dev); | ||
1702 | |||
1703 | /* Get the current SSID */ | ||
1704 | if (priv->new_SSID_size != 0) { | ||
1705 | memcpy(extra, priv->new_SSID, priv->new_SSID_size); | ||
1706 | extra[priv->new_SSID_size] = '\0'; | ||
1707 | dwrq->length = priv->new_SSID_size + 1; | ||
1708 | } else { | ||
1709 | memcpy(extra, priv->SSID, priv->SSID_size); | ||
1710 | extra[priv->SSID_size] = '\0'; | ||
1711 | dwrq->length = priv->SSID_size + 1; | ||
1712 | } | ||
1713 | |||
1714 | dwrq->flags = !priv->connect_to_any_BSS; /* active */ | ||
1715 | |||
1716 | return 0; | ||
1717 | } | ||
1718 | |||
1719 | static int atmel_get_wap(struct net_device *dev, | ||
1720 | struct iw_request_info *info, | ||
1721 | struct sockaddr *awrq, | ||
1722 | char *extra) | ||
1723 | { | ||
1724 | struct atmel_private *priv = netdev_priv(dev); | ||
1725 | memcpy(awrq->sa_data, priv->CurrentBSSID, 6); | ||
1726 | awrq->sa_family = ARPHRD_ETHER; | ||
1727 | |||
1728 | return 0; | ||
1729 | } | ||
1730 | |||
1731 | static int atmel_set_encode(struct net_device *dev, | ||
1732 | struct iw_request_info *info, | ||
1733 | struct iw_point *dwrq, | ||
1734 | char *extra) | ||
1735 | { | ||
1736 | struct atmel_private *priv = netdev_priv(dev); | ||
1737 | |||
1738 | /* Basic checking: do we have a key to set ? | ||
1739 | * Note : with the new API, it's impossible to get a NULL pointer. | ||
1740 | * Therefore, we need to check a key size == 0 instead. | ||
1741 | * New version of iwconfig properly set the IW_ENCODE_NOKEY flag | ||
1742 | * when no key is present (only change flags), but older versions | ||
1743 | * don't do it. - Jean II */ | ||
1744 | if (dwrq->length > 0) { | ||
1745 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1746 | int current_index = priv->default_key; | ||
1747 | /* Check the size of the key */ | ||
1748 | if (dwrq->length > 13) { | ||
1749 | return -EINVAL; | ||
1750 | } | ||
1751 | /* Check the index (none -> use current) */ | ||
1752 | if (index < 0 || index >= 4) | ||
1753 | index = current_index; | ||
1754 | else | ||
1755 | priv->default_key = index; | ||
1756 | /* Set the length */ | ||
1757 | if (dwrq->length > 5) | ||
1758 | priv->wep_key_len[index] = 13; | ||
1759 | else | ||
1760 | if (dwrq->length > 0) | ||
1761 | priv->wep_key_len[index] = 5; | ||
1762 | else | ||
1763 | /* Disable the key */ | ||
1764 | priv->wep_key_len[index] = 0; | ||
1765 | /* Check if the key is not marked as invalid */ | ||
1766 | if(!(dwrq->flags & IW_ENCODE_NOKEY)) { | ||
1767 | /* Cleanup */ | ||
1768 | memset(priv->wep_keys[index], 0, 13); | ||
1769 | /* Copy the key in the driver */ | ||
1770 | memcpy(priv->wep_keys[index], extra, dwrq->length); | ||
1771 | } | ||
1772 | /* WE specify that if a valid key is set, encryption | ||
1773 | * should be enabled (user may turn it off later) | ||
1774 | * This is also how "iwconfig ethX key on" works */ | ||
1775 | if (index == current_index && | ||
1776 | priv->wep_key_len[index] > 0) { | ||
1777 | priv->wep_is_on = 1; | ||
1778 | priv->exclude_unencrypted = 1; | ||
1779 | if (priv->wep_key_len[index] > 5) { | ||
1780 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | ||
1781 | priv->encryption_level = 2; | ||
1782 | } else { | ||
1783 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | ||
1784 | priv->encryption_level = 1; | ||
1785 | } | ||
1786 | } | ||
1787 | } else { | ||
1788 | /* Do we want to just set the transmit key index ? */ | ||
1789 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1790 | if ( index>=0 && index < 4 ) { | ||
1791 | priv->default_key = index; | ||
1792 | } else | ||
1793 | /* Don't complain if only change the mode */ | ||
1794 | if(!dwrq->flags & IW_ENCODE_MODE) { | ||
1795 | return -EINVAL; | ||
1796 | } | ||
1797 | } | ||
1798 | /* Read the flags */ | ||
1799 | if(dwrq->flags & IW_ENCODE_DISABLED) { | ||
1800 | priv->wep_is_on = 0; | ||
1801 | priv->encryption_level = 0; | ||
1802 | priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | ||
1803 | } else { | ||
1804 | priv->wep_is_on = 1; | ||
1805 | if (priv->wep_key_len[priv->default_key] > 5) { | ||
1806 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | ||
1807 | priv->encryption_level = 2; | ||
1808 | } else { | ||
1809 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | ||
1810 | priv->encryption_level = 1; | ||
1811 | } | ||
1812 | } | ||
1813 | if(dwrq->flags & IW_ENCODE_RESTRICTED) | ||
1814 | priv->exclude_unencrypted = 1; | ||
1815 | if(dwrq->flags & IW_ENCODE_OPEN) | ||
1816 | priv->exclude_unencrypted = 0; | ||
1817 | |||
1818 | return -EINPROGRESS; /* Call commit handler */ | ||
1819 | } | ||
1820 | |||
1821 | |||
1822 | static int atmel_get_encode(struct net_device *dev, | ||
1823 | struct iw_request_info *info, | ||
1824 | struct iw_point *dwrq, | ||
1825 | char *extra) | ||
1826 | { | ||
1827 | struct atmel_private *priv = netdev_priv(dev); | ||
1828 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1829 | |||
1830 | if (!priv->wep_is_on) | ||
1831 | dwrq->flags = IW_ENCODE_DISABLED; | ||
1832 | else if (priv->exclude_unencrypted) | ||
1833 | dwrq->flags = IW_ENCODE_RESTRICTED; | ||
1834 | else | ||
1835 | dwrq->flags = IW_ENCODE_OPEN; | ||
1836 | |||
1837 | /* Which key do we want ? -1 -> tx index */ | ||
1838 | if (index < 0 || index >= 4) | ||
1839 | index = priv->default_key; | ||
1840 | dwrq->flags |= index + 1; | ||
1841 | /* Copy the key to the user buffer */ | ||
1842 | dwrq->length = priv->wep_key_len[index]; | ||
1843 | if (dwrq->length > 16) { | ||
1844 | dwrq->length=0; | ||
1845 | } else { | ||
1846 | memset(extra, 0, 16); | ||
1847 | memcpy(extra, priv->wep_keys[index], dwrq->length); | ||
1848 | } | ||
1849 | |||
1850 | return 0; | ||
1851 | } | ||
1852 | |||
1853 | static int atmel_get_name(struct net_device *dev, | ||
1854 | struct iw_request_info *info, | ||
1855 | char *cwrq, | ||
1856 | char *extra) | ||
1857 | { | ||
1858 | strcpy(cwrq, "IEEE 802.11-DS"); | ||
1859 | return 0; | ||
1860 | } | ||
1861 | |||
1862 | static int atmel_set_rate(struct net_device *dev, | ||
1863 | struct iw_request_info *info, | ||
1864 | struct iw_param *vwrq, | ||
1865 | char *extra) | ||
1866 | { | ||
1867 | struct atmel_private *priv = netdev_priv(dev); | ||
1868 | |||
1869 | if (vwrq->fixed == 0) { | ||
1870 | priv->tx_rate = 3; | ||
1871 | priv->auto_tx_rate = 1; | ||
1872 | } else { | ||
1873 | priv->auto_tx_rate = 0; | ||
1874 | |||
1875 | /* Which type of value ? */ | ||
1876 | if((vwrq->value < 4) && (vwrq->value >= 0)) { | ||
1877 | /* Setting by rate index */ | ||
1878 | priv->tx_rate = vwrq->value; | ||
1879 | } else { | ||
1880 | /* Setting by frequency value */ | ||
1881 | switch (vwrq->value) { | ||
1882 | case 1000000: priv->tx_rate = 0; break; | ||
1883 | case 2000000: priv->tx_rate = 1; break; | ||
1884 | case 5500000: priv->tx_rate = 2; break; | ||
1885 | case 11000000: priv->tx_rate = 3; break; | ||
1886 | default: return -EINVAL; | ||
1887 | } | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | return -EINPROGRESS; | ||
1892 | } | ||
1893 | |||
1894 | static int atmel_set_mode(struct net_device *dev, | ||
1895 | struct iw_request_info *info, | ||
1896 | __u32 *uwrq, | ||
1897 | char *extra) | ||
1898 | { | ||
1899 | struct atmel_private *priv = netdev_priv(dev); | ||
1900 | |||
1901 | if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) | ||
1902 | return -EINVAL; | ||
1903 | |||
1904 | priv->operating_mode = *uwrq; | ||
1905 | return -EINPROGRESS; | ||
1906 | } | ||
1907 | |||
1908 | static int atmel_get_mode(struct net_device *dev, | ||
1909 | struct iw_request_info *info, | ||
1910 | __u32 *uwrq, | ||
1911 | char *extra) | ||
1912 | { | ||
1913 | struct atmel_private *priv = netdev_priv(dev); | ||
1914 | |||
1915 | *uwrq = priv->operating_mode; | ||
1916 | return 0; | ||
1917 | } | ||
1918 | |||
1919 | static int atmel_get_rate(struct net_device *dev, | ||
1920 | struct iw_request_info *info, | ||
1921 | struct iw_param *vwrq, | ||
1922 | char *extra) | ||
1923 | { | ||
1924 | struct atmel_private *priv = netdev_priv(dev); | ||
1925 | |||
1926 | if (priv->auto_tx_rate) { | ||
1927 | vwrq->fixed = 0; | ||
1928 | vwrq->value = 11000000; | ||
1929 | } else { | ||
1930 | vwrq->fixed = 1; | ||
1931 | switch(priv->tx_rate) { | ||
1932 | case 0: vwrq->value = 1000000; break; | ||
1933 | case 1: vwrq->value = 2000000; break; | ||
1934 | case 2: vwrq->value = 5500000; break; | ||
1935 | case 3: vwrq->value = 11000000; break; | ||
1936 | } | ||
1937 | } | ||
1938 | return 0; | ||
1939 | } | ||
1940 | |||
1941 | static int atmel_set_power(struct net_device *dev, | ||
1942 | struct iw_request_info *info, | ||
1943 | struct iw_param *vwrq, | ||
1944 | char *extra) | ||
1945 | { | ||
1946 | struct atmel_private *priv = netdev_priv(dev); | ||
1947 | priv->power_mode = vwrq->disabled ? 0 : 1; | ||
1948 | return -EINPROGRESS; | ||
1949 | } | ||
1950 | |||
1951 | static int atmel_get_power(struct net_device *dev, | ||
1952 | struct iw_request_info *info, | ||
1953 | struct iw_param *vwrq, | ||
1954 | char *extra) | ||
1955 | { | ||
1956 | struct atmel_private *priv = netdev_priv(dev); | ||
1957 | vwrq->disabled = priv->power_mode ? 0 : 1; | ||
1958 | vwrq->flags = IW_POWER_ON; | ||
1959 | return 0; | ||
1960 | } | ||
1961 | |||
1962 | static int atmel_set_retry(struct net_device *dev, | ||
1963 | struct iw_request_info *info, | ||
1964 | struct iw_param *vwrq, | ||
1965 | char *extra) | ||
1966 | { | ||
1967 | struct atmel_private *priv = netdev_priv(dev); | ||
1968 | |||
1969 | if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { | ||
1970 | if(vwrq->flags & IW_RETRY_MAX) | ||
1971 | priv->long_retry = vwrq->value; | ||
1972 | else if (vwrq->flags & IW_RETRY_MIN) | ||
1973 | priv->short_retry = vwrq->value; | ||
1974 | else { | ||
1975 | /* No modifier : set both */ | ||
1976 | priv->long_retry = vwrq->value; | ||
1977 | priv->short_retry = vwrq->value; | ||
1978 | } | ||
1979 | return -EINPROGRESS; | ||
1980 | } | ||
1981 | |||
1982 | return -EINVAL; | ||
1983 | } | ||
1984 | |||
1985 | static int atmel_get_retry(struct net_device *dev, | ||
1986 | struct iw_request_info *info, | ||
1987 | struct iw_param *vwrq, | ||
1988 | char *extra) | ||
1989 | { | ||
1990 | struct atmel_private *priv = netdev_priv(dev); | ||
1991 | |||
1992 | vwrq->disabled = 0; /* Can't be disabled */ | ||
1993 | |||
1994 | /* Note : by default, display the min retry number */ | ||
1995 | if((vwrq->flags & IW_RETRY_MAX)) { | ||
1996 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
1997 | vwrq->value = priv->long_retry; | ||
1998 | } else { | ||
1999 | vwrq->flags = IW_RETRY_LIMIT; | ||
2000 | vwrq->value = priv->short_retry; | ||
2001 | if(priv->long_retry != priv->short_retry) | ||
2002 | vwrq->flags |= IW_RETRY_MIN; | ||
2003 | } | ||
2004 | |||
2005 | return 0; | ||
2006 | } | ||
2007 | |||
2008 | static int atmel_set_rts(struct net_device *dev, | ||
2009 | struct iw_request_info *info, | ||
2010 | struct iw_param *vwrq, | ||
2011 | char *extra) | ||
2012 | { | ||
2013 | struct atmel_private *priv = netdev_priv(dev); | ||
2014 | int rthr = vwrq->value; | ||
2015 | |||
2016 | if(vwrq->disabled) | ||
2017 | rthr = 2347; | ||
2018 | if((rthr < 0) || (rthr > 2347)) { | ||
2019 | return -EINVAL; | ||
2020 | } | ||
2021 | priv->rts_threshold = rthr; | ||
2022 | |||
2023 | return -EINPROGRESS; /* Call commit handler */ | ||
2024 | } | ||
2025 | |||
2026 | static int atmel_get_rts(struct net_device *dev, | ||
2027 | struct iw_request_info *info, | ||
2028 | struct iw_param *vwrq, | ||
2029 | char *extra) | ||
2030 | { | ||
2031 | struct atmel_private *priv = netdev_priv(dev); | ||
2032 | |||
2033 | vwrq->value = priv->rts_threshold; | ||
2034 | vwrq->disabled = (vwrq->value >= 2347); | ||
2035 | vwrq->fixed = 1; | ||
2036 | |||
2037 | return 0; | ||
2038 | } | ||
2039 | |||
2040 | static int atmel_set_frag(struct net_device *dev, | ||
2041 | struct iw_request_info *info, | ||
2042 | struct iw_param *vwrq, | ||
2043 | char *extra) | ||
2044 | { | ||
2045 | struct atmel_private *priv = netdev_priv(dev); | ||
2046 | int fthr = vwrq->value; | ||
2047 | |||
2048 | if(vwrq->disabled) | ||
2049 | fthr = 2346; | ||
2050 | if((fthr < 256) || (fthr > 2346)) { | ||
2051 | return -EINVAL; | ||
2052 | } | ||
2053 | fthr &= ~0x1; /* Get an even value - is it really needed ??? */ | ||
2054 | priv->frag_threshold = fthr; | ||
2055 | |||
2056 | return -EINPROGRESS; /* Call commit handler */ | ||
2057 | } | ||
2058 | |||
2059 | static int atmel_get_frag(struct net_device *dev, | ||
2060 | struct iw_request_info *info, | ||
2061 | struct iw_param *vwrq, | ||
2062 | char *extra) | ||
2063 | { | ||
2064 | struct atmel_private *priv = netdev_priv(dev); | ||
2065 | |||
2066 | vwrq->value = priv->frag_threshold; | ||
2067 | vwrq->disabled = (vwrq->value >= 2346); | ||
2068 | vwrq->fixed = 1; | ||
2069 | |||
2070 | return 0; | ||
2071 | } | ||
2072 | |||
2073 | static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, | ||
2074 | 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; | ||
2075 | |||
2076 | static int atmel_set_freq(struct net_device *dev, | ||
2077 | struct iw_request_info *info, | ||
2078 | struct iw_freq *fwrq, | ||
2079 | char *extra) | ||
2080 | { | ||
2081 | struct atmel_private *priv = netdev_priv(dev); | ||
2082 | int rc = -EINPROGRESS; /* Call commit handler */ | ||
2083 | |||
2084 | /* If setting by frequency, convert to a channel */ | ||
2085 | if((fwrq->e == 1) && | ||
2086 | (fwrq->m >= (int) 241200000) && | ||
2087 | (fwrq->m <= (int) 248700000)) { | ||
2088 | int f = fwrq->m / 100000; | ||
2089 | int c = 0; | ||
2090 | while((c < 14) && (f != frequency_list[c])) | ||
2091 | c++; | ||
2092 | /* Hack to fall through... */ | ||
2093 | fwrq->e = 0; | ||
2094 | fwrq->m = c + 1; | ||
2095 | } | ||
2096 | /* Setting by channel number */ | ||
2097 | if((fwrq->m > 1000) || (fwrq->e > 0)) | ||
2098 | rc = -EOPNOTSUPP; | ||
2099 | else { | ||
2100 | int channel = fwrq->m; | ||
2101 | if (atmel_validate_channel(priv, channel) == 0) { | ||
2102 | priv->channel = channel; | ||
2103 | } else { | ||
2104 | rc = -EINVAL; | ||
2105 | } | ||
2106 | } | ||
2107 | return rc; | ||
2108 | } | ||
2109 | |||
2110 | static int atmel_get_freq(struct net_device *dev, | ||
2111 | struct iw_request_info *info, | ||
2112 | struct iw_freq *fwrq, | ||
2113 | char *extra) | ||
2114 | { | ||
2115 | struct atmel_private *priv = netdev_priv(dev); | ||
2116 | |||
2117 | fwrq->m = priv->channel; | ||
2118 | fwrq->e = 0; | ||
2119 | return 0; | ||
2120 | } | ||
2121 | |||
2122 | static int atmel_set_scan(struct net_device *dev, | ||
2123 | struct iw_request_info *info, | ||
2124 | struct iw_param *vwrq, | ||
2125 | char *extra) | ||
2126 | { | ||
2127 | struct atmel_private *priv = netdev_priv(dev); | ||
2128 | unsigned long flags; | ||
2129 | |||
2130 | /* Note : you may have realised that, as this is a SET operation, | ||
2131 | * this is privileged and therefore a normal user can't | ||
2132 | * perform scanning. | ||
2133 | * This is not an error, while the device perform scanning, | ||
2134 | * traffic doesn't flow, so it's a perfect DoS... | ||
2135 | * Jean II */ | ||
2136 | |||
2137 | if (priv->station_state == STATION_STATE_DOWN) | ||
2138 | return -EAGAIN; | ||
2139 | |||
2140 | /* Timeout old surveys. */ | ||
2141 | if ((jiffies - priv->last_survey) > (20 * HZ)) | ||
2142 | priv->site_survey_state = SITE_SURVEY_IDLE; | ||
2143 | priv->last_survey = jiffies; | ||
2144 | |||
2145 | /* Initiate a scan command */ | ||
2146 | if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) | ||
2147 | return -EBUSY; | ||
2148 | |||
2149 | del_timer_sync(&priv->management_timer); | ||
2150 | spin_lock_irqsave(&priv->irqlock, flags); | ||
2151 | |||
2152 | priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; | ||
2153 | priv->fast_scan = 0; | ||
2154 | atmel_scan(priv, 0); | ||
2155 | spin_unlock_irqrestore(&priv->irqlock, flags); | ||
2156 | |||
2157 | return 0; | ||
2158 | } | ||
2159 | |||
2160 | static int atmel_get_scan(struct net_device *dev, | ||
2161 | struct iw_request_info *info, | ||
2162 | struct iw_point *dwrq, | ||
2163 | char *extra) | ||
2164 | { | ||
2165 | struct atmel_private *priv = netdev_priv(dev); | ||
2166 | int i; | ||
2167 | char *current_ev = extra; | ||
2168 | struct iw_event iwe; | ||
2169 | |||
2170 | if (priv->site_survey_state != SITE_SURVEY_COMPLETED) | ||
2171 | return -EAGAIN; | ||
2172 | |||
2173 | for(i=0; i<priv->BSS_list_entries; i++) { | ||
2174 | iwe.cmd = SIOCGIWAP; | ||
2175 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
2176 | memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); | ||
2177 | current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); | ||
2178 | |||
2179 | iwe.u.data.length = priv->BSSinfo[i].SSIDsize; | ||
2180 | if (iwe.u.data.length > 32) | ||
2181 | iwe.u.data.length = 32; | ||
2182 | iwe.cmd = SIOCGIWESSID; | ||
2183 | iwe.u.data.flags = 1; | ||
2184 | current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID); | ||
2185 | |||
2186 | iwe.cmd = SIOCGIWMODE; | ||
2187 | iwe.u.mode = priv->BSSinfo[i].BSStype; | ||
2188 | current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); | ||
2189 | |||
2190 | iwe.cmd = SIOCGIWFREQ; | ||
2191 | iwe.u.freq.m = priv->BSSinfo[i].channel; | ||
2192 | iwe.u.freq.e = 0; | ||
2193 | current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); | ||
2194 | |||
2195 | iwe.cmd = SIOCGIWENCODE; | ||
2196 | if (priv->BSSinfo[i].UsingWEP) | ||
2197 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
2198 | else | ||
2199 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
2200 | iwe.u.data.length = 0; | ||
2201 | current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); | ||
2202 | |||
2203 | } | ||
2204 | |||
2205 | /* Length of data */ | ||
2206 | dwrq->length = (current_ev - extra); | ||
2207 | dwrq->flags = 0; | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
2212 | static int atmel_get_range(struct net_device *dev, | ||
2213 | struct iw_request_info *info, | ||
2214 | struct iw_point *dwrq, | ||
2215 | char *extra) | ||
2216 | { | ||
2217 | struct atmel_private *priv = netdev_priv(dev); | ||
2218 | struct iw_range *range = (struct iw_range *) extra; | ||
2219 | int k,i,j; | ||
2220 | |||
2221 | dwrq->length = sizeof(struct iw_range); | ||
2222 | memset(range, 0, sizeof(range)); | ||
2223 | range->min_nwid = 0x0000; | ||
2224 | range->max_nwid = 0x0000; | ||
2225 | range->num_channels = 0; | ||
2226 | for (j = 0; j < sizeof(channel_table)/sizeof(channel_table[0]); j++) | ||
2227 | if (priv->reg_domain == channel_table[j].reg_domain) { | ||
2228 | range->num_channels = channel_table[j].max - channel_table[j].min + 1; | ||
2229 | break; | ||
2230 | } | ||
2231 | if (range->num_channels != 0) { | ||
2232 | for(k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { | ||
2233 | range->freq[k].i = i; /* List index */ | ||
2234 | range->freq[k].m = frequency_list[i-1] * 100000; | ||
2235 | range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ | ||
2236 | } | ||
2237 | range->num_frequency = k; | ||
2238 | } | ||
2239 | |||
2240 | range->max_qual.qual = 100; | ||
2241 | range->max_qual.level = 100; | ||
2242 | range->max_qual.noise = 0; | ||
2243 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; | ||
2244 | |||
2245 | range->avg_qual.qual = 50; | ||
2246 | range->avg_qual.level = 50; | ||
2247 | range->avg_qual.noise = 0; | ||
2248 | range->avg_qual.updated = IW_QUAL_NOISE_INVALID; | ||
2249 | |||
2250 | range->sensitivity = 0; | ||
2251 | |||
2252 | range->bitrate[0] = 1000000; | ||
2253 | range->bitrate[1] = 2000000; | ||
2254 | range->bitrate[2] = 5500000; | ||
2255 | range->bitrate[3] = 11000000; | ||
2256 | range->num_bitrates = 4; | ||
2257 | |||
2258 | range->min_rts = 0; | ||
2259 | range->max_rts = 2347; | ||
2260 | range->min_frag = 256; | ||
2261 | range->max_frag = 2346; | ||
2262 | |||
2263 | range->encoding_size[0] = 5; | ||
2264 | range->encoding_size[1] = 13; | ||
2265 | range->num_encoding_sizes = 2; | ||
2266 | range->max_encoding_tokens = 4; | ||
2267 | |||
2268 | range->pmp_flags = IW_POWER_ON; | ||
2269 | range->pmt_flags = IW_POWER_ON; | ||
2270 | range->pm_capa = 0; | ||
2271 | |||
2272 | range->we_version_source = WIRELESS_EXT; | ||
2273 | range->we_version_compiled = WIRELESS_EXT; | ||
2274 | range->retry_capa = IW_RETRY_LIMIT ; | ||
2275 | range->retry_flags = IW_RETRY_LIMIT; | ||
2276 | range->r_time_flags = 0; | ||
2277 | range->min_retry = 1; | ||
2278 | range->max_retry = 65535; | ||
2279 | |||
2280 | return 0; | ||
2281 | } | ||
2282 | |||
2283 | static int atmel_set_wap(struct net_device *dev, | ||
2284 | struct iw_request_info *info, | ||
2285 | struct sockaddr *awrq, | ||
2286 | char *extra) | ||
2287 | { | ||
2288 | struct atmel_private *priv = netdev_priv(dev); | ||
2289 | int i; | ||
2290 | static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; | ||
2291 | unsigned long flags; | ||
2292 | |||
2293 | if (awrq->sa_family != ARPHRD_ETHER) | ||
2294 | return -EINVAL; | ||
2295 | |||
2296 | if (memcmp(bcast, awrq->sa_data, 6) == 0) { | ||
2297 | del_timer_sync(&priv->management_timer); | ||
2298 | spin_lock_irqsave(&priv->irqlock, flags); | ||
2299 | atmel_scan(priv, 1); | ||
2300 | spin_unlock_irqrestore(&priv->irqlock, flags); | ||
2301 | return 0; | ||
2302 | } | ||
2303 | |||
2304 | for(i=0; i<priv->BSS_list_entries; i++) { | ||
2305 | if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { | ||
2306 | if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { | ||
2307 | return -EINVAL; | ||
2308 | } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { | ||
2309 | return -EINVAL; | ||
2310 | } else { | ||
2311 | del_timer_sync(&priv->management_timer); | ||
2312 | spin_lock_irqsave(&priv->irqlock, flags); | ||
2313 | atmel_join_bss(priv, i); | ||
2314 | spin_unlock_irqrestore(&priv->irqlock, flags); | ||
2315 | return 0; | ||
2316 | } | ||
2317 | } | ||
2318 | } | ||
2319 | |||
2320 | return -EINVAL; | ||
2321 | } | ||
2322 | |||
2323 | static int atmel_config_commit(struct net_device *dev, | ||
2324 | struct iw_request_info *info, /* NULL */ | ||
2325 | void *zwrq, /* NULL */ | ||
2326 | char *extra) /* NULL */ | ||
2327 | { | ||
2328 | return atmel_open(dev); | ||
2329 | } | ||
2330 | |||
2331 | static const iw_handler atmel_handler[] = | ||
2332 | { | ||
2333 | (iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */ | ||
2334 | (iw_handler) atmel_get_name, /* SIOCGIWNAME */ | ||
2335 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
2336 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
2337 | (iw_handler) atmel_set_freq, /* SIOCSIWFREQ */ | ||
2338 | (iw_handler) atmel_get_freq, /* SIOCGIWFREQ */ | ||
2339 | (iw_handler) atmel_set_mode, /* SIOCSIWMODE */ | ||
2340 | (iw_handler) atmel_get_mode, /* SIOCGIWMODE */ | ||
2341 | (iw_handler) NULL, /* SIOCSIWSENS */ | ||
2342 | (iw_handler) NULL, /* SIOCGIWSENS */ | ||
2343 | (iw_handler) NULL, /* SIOCSIWRANGE */ | ||
2344 | (iw_handler) atmel_get_range, /* SIOCGIWRANGE */ | ||
2345 | (iw_handler) NULL, /* SIOCSIWPRIV */ | ||
2346 | (iw_handler) NULL, /* SIOCGIWPRIV */ | ||
2347 | (iw_handler) NULL, /* SIOCSIWSTATS */ | ||
2348 | (iw_handler) NULL, /* SIOCGIWSTATS */ | ||
2349 | (iw_handler) NULL, /* SIOCSIWSPY */ | ||
2350 | (iw_handler) NULL, /* SIOCGIWSPY */ | ||
2351 | (iw_handler) NULL, /* -- hole -- */ | ||
2352 | (iw_handler) NULL, /* -- hole -- */ | ||
2353 | (iw_handler) atmel_set_wap, /* SIOCSIWAP */ | ||
2354 | (iw_handler) atmel_get_wap, /* SIOCGIWAP */ | ||
2355 | (iw_handler) NULL, /* -- hole -- */ | ||
2356 | (iw_handler) NULL, /* SIOCGIWAPLIST */ | ||
2357 | (iw_handler) atmel_set_scan, /* SIOCSIWSCAN */ | ||
2358 | (iw_handler) atmel_get_scan, /* SIOCGIWSCAN */ | ||
2359 | (iw_handler) atmel_set_essid, /* SIOCSIWESSID */ | ||
2360 | (iw_handler) atmel_get_essid, /* SIOCGIWESSID */ | ||
2361 | (iw_handler) NULL, /* SIOCSIWNICKN */ | ||
2362 | (iw_handler) NULL, /* SIOCGIWNICKN */ | ||
2363 | (iw_handler) NULL, /* -- hole -- */ | ||
2364 | (iw_handler) NULL, /* -- hole -- */ | ||
2365 | (iw_handler) atmel_set_rate, /* SIOCSIWRATE */ | ||
2366 | (iw_handler) atmel_get_rate, /* SIOCGIWRATE */ | ||
2367 | (iw_handler) atmel_set_rts, /* SIOCSIWRTS */ | ||
2368 | (iw_handler) atmel_get_rts, /* SIOCGIWRTS */ | ||
2369 | (iw_handler) atmel_set_frag, /* SIOCSIWFRAG */ | ||
2370 | (iw_handler) atmel_get_frag, /* SIOCGIWFRAG */ | ||
2371 | (iw_handler) NULL, /* SIOCSIWTXPOW */ | ||
2372 | (iw_handler) NULL, /* SIOCGIWTXPOW */ | ||
2373 | (iw_handler) atmel_set_retry, /* SIOCSIWRETRY */ | ||
2374 | (iw_handler) atmel_get_retry, /* SIOCGIWRETRY */ | ||
2375 | (iw_handler) atmel_set_encode, /* SIOCSIWENCODE */ | ||
2376 | (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ | ||
2377 | (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ | ||
2378 | (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ | ||
2379 | }; | ||
2380 | |||
2381 | |||
2382 | static const iw_handler atmel_private_handler[] = | ||
2383 | { | ||
2384 | NULL, /* SIOCIWFIRSTPRIV */ | ||
2385 | }; | ||
2386 | |||
2387 | typedef struct atmel_priv_ioctl { | ||
2388 | char id[32]; | ||
2389 | unsigned char __user *data; | ||
2390 | unsigned short len; | ||
2391 | } atmel_priv_ioctl; | ||
2392 | |||
2393 | |||
2394 | #define ATMELFWL SIOCIWFIRSTPRIV | ||
2395 | #define ATMELIDIFC ATMELFWL + 1 | ||
2396 | #define ATMELRD ATMELFWL + 2 | ||
2397 | #define ATMELMAGIC 0x51807 | ||
2398 | #define REGDOMAINSZ 20 | ||
2399 | |||
2400 | static const struct iw_priv_args atmel_private_args[] = { | ||
2401 | /*{ cmd, set_args, get_args, name } */ | ||
2402 | { ATMELFWL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (atmel_priv_ioctl), IW_PRIV_TYPE_NONE, "atmelfwl" }, | ||
2403 | { ATMELIDIFC, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "atmelidifc" }, | ||
2404 | { ATMELRD, IW_PRIV_TYPE_CHAR | REGDOMAINSZ, IW_PRIV_TYPE_NONE, "regdomain" }, | ||
2405 | }; | ||
2406 | |||
2407 | static const struct iw_handler_def atmel_handler_def = | ||
2408 | { | ||
2409 | .num_standard = sizeof(atmel_handler)/sizeof(iw_handler), | ||
2410 | .num_private = sizeof(atmel_private_handler)/sizeof(iw_handler), | ||
2411 | .num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args), | ||
2412 | .standard = (iw_handler *) atmel_handler, | ||
2413 | .private = (iw_handler *) atmel_private_handler, | ||
2414 | .private_args = (struct iw_priv_args *) atmel_private_args | ||
2415 | }; | ||
2416 | |||
2417 | static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
2418 | { | ||
2419 | int i, rc = 0; | ||
2420 | struct atmel_private *priv = netdev_priv(dev); | ||
2421 | atmel_priv_ioctl com; | ||
2422 | struct iwreq *wrq = (struct iwreq *) rq; | ||
2423 | unsigned char *new_firmware; | ||
2424 | char domain[REGDOMAINSZ+1]; | ||
2425 | |||
2426 | switch (cmd) { | ||
2427 | case SIOCGIWPRIV: | ||
2428 | if(wrq->u.data.pointer) { | ||
2429 | /* Set the number of ioctl available */ | ||
2430 | wrq->u.data.length = sizeof(atmel_private_args) / sizeof(atmel_private_args[0]); | ||
2431 | |||
2432 | /* Copy structure to the user buffer */ | ||
2433 | if (copy_to_user(wrq->u.data.pointer, | ||
2434 | (u_char *) atmel_private_args, | ||
2435 | sizeof(atmel_private_args))) | ||
2436 | rc = -EFAULT; | ||
2437 | } | ||
2438 | break; | ||
2439 | |||
2440 | case ATMELIDIFC: | ||
2441 | wrq->u.param.value = ATMELMAGIC; | ||
2442 | break; | ||
2443 | |||
2444 | case ATMELFWL: | ||
2445 | if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { | ||
2446 | rc = -EFAULT; | ||
2447 | break; | ||
2448 | } | ||
2449 | |||
2450 | if (!capable(CAP_NET_ADMIN)) { | ||
2451 | rc = -EPERM; | ||
2452 | break; | ||
2453 | } | ||
2454 | |||
2455 | if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { | ||
2456 | rc = -ENOMEM; | ||
2457 | break; | ||
2458 | } | ||
2459 | |||
2460 | if (copy_from_user(new_firmware, com.data, com.len)) { | ||
2461 | kfree(new_firmware); | ||
2462 | rc = -EFAULT; | ||
2463 | break; | ||
2464 | } | ||
2465 | |||
2466 | if (priv->firmware) | ||
2467 | kfree(priv->firmware); | ||
2468 | |||
2469 | priv->firmware = new_firmware; | ||
2470 | priv->firmware_length = com.len; | ||
2471 | strncpy(priv->firmware_id, com.id, 31); | ||
2472 | priv->firmware_id[31] = '\0'; | ||
2473 | break; | ||
2474 | |||
2475 | case ATMELRD: | ||
2476 | if (copy_from_user(domain, rq->ifr_data, REGDOMAINSZ)) { | ||
2477 | rc = -EFAULT; | ||
2478 | break; | ||
2479 | } | ||
2480 | |||
2481 | if (!capable(CAP_NET_ADMIN)) { | ||
2482 | rc = -EPERM; | ||
2483 | break; | ||
2484 | } | ||
2485 | |||
2486 | domain[REGDOMAINSZ] = 0; | ||
2487 | rc = -EINVAL; | ||
2488 | for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) { | ||
2489 | /* strcasecmp doesn't exist in the library */ | ||
2490 | char *a = channel_table[i].name; | ||
2491 | char *b = domain; | ||
2492 | while (*a) { | ||
2493 | char c1 = *a++; | ||
2494 | char c2 = *b++; | ||
2495 | if (tolower(c1) != tolower(c2)) | ||
2496 | break; | ||
2497 | } | ||
2498 | if (!*a && !*b) { | ||
2499 | priv->config_reg_domain = channel_table[i].reg_domain; | ||
2500 | rc = 0; | ||
2501 | } | ||
2502 | } | ||
2503 | |||
2504 | if (rc == 0 && priv->station_state != STATION_STATE_DOWN) | ||
2505 | rc = atmel_open(dev); | ||
2506 | break; | ||
2507 | |||
2508 | default: | ||
2509 | rc = -EOPNOTSUPP; | ||
2510 | } | ||
2511 | |||
2512 | return rc; | ||
2513 | } | ||
2514 | |||
2515 | struct auth_body { | ||
2516 | u16 alg; | ||
2517 | u16 trans_seq; | ||
2518 | u16 status; | ||
2519 | u8 el_id; | ||
2520 | u8 chall_text_len; | ||
2521 | u8 chall_text[253]; | ||
2522 | }; | ||
2523 | |||
2524 | static void atmel_enter_state(struct atmel_private *priv, int new_state) | ||
2525 | { | ||
2526 | int old_state = priv->station_state; | ||
2527 | |||
2528 | if (new_state == old_state) | ||
2529 | return; | ||
2530 | |||
2531 | priv->station_state = new_state; | ||
2532 | |||
2533 | if (new_state == STATION_STATE_READY) { | ||
2534 | netif_start_queue(priv->dev); | ||
2535 | netif_carrier_on(priv->dev); | ||
2536 | } | ||
2537 | |||
2538 | if (old_state == STATION_STATE_READY) { | ||
2539 | netif_carrier_off(priv->dev); | ||
2540 | if (netif_running(priv->dev)) | ||
2541 | netif_stop_queue(priv->dev); | ||
2542 | priv->last_beacon_timestamp = 0; | ||
2543 | } | ||
2544 | } | ||
2545 | |||
2546 | static void atmel_scan(struct atmel_private *priv, int specific_ssid) | ||
2547 | { | ||
2548 | struct { | ||
2549 | u8 BSSID[6]; | ||
2550 | u8 SSID[MAX_SSID_LENGTH]; | ||
2551 | u8 scan_type; | ||
2552 | u8 channel; | ||
2553 | u16 BSS_type; | ||
2554 | u16 min_channel_time; | ||
2555 | u16 max_channel_time; | ||
2556 | u8 options; | ||
2557 | u8 SSID_size; | ||
2558 | } cmd; | ||
2559 | |||
2560 | memset(cmd.BSSID, 0xff, 6); | ||
2561 | |||
2562 | if (priv->fast_scan) { | ||
2563 | cmd.SSID_size = priv->SSID_size; | ||
2564 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | ||
2565 | cmd.min_channel_time = cpu_to_le16(10); | ||
2566 | cmd.max_channel_time = cpu_to_le16(50); | ||
2567 | } else { | ||
2568 | priv->BSS_list_entries = 0; | ||
2569 | cmd.SSID_size = 0; | ||
2570 | cmd.min_channel_time = cpu_to_le16(10); | ||
2571 | cmd.max_channel_time = cpu_to_le16(120); | ||
2572 | } | ||
2573 | |||
2574 | cmd.options = 0; | ||
2575 | |||
2576 | if (!specific_ssid) | ||
2577 | cmd.options |= SCAN_OPTIONS_SITE_SURVEY; | ||
2578 | |||
2579 | cmd.channel = (priv->channel & 0x7f); | ||
2580 | cmd.scan_type = SCAN_TYPE_ACTIVE; | ||
2581 | cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? | ||
2582 | BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); | ||
2583 | |||
2584 | atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); | ||
2585 | |||
2586 | /* This must come after all hardware access to avoid being messed up | ||
2587 | by stuff happening in interrupt context after we leave STATE_DOWN */ | ||
2588 | atmel_enter_state(priv, STATION_STATE_SCANNING); | ||
2589 | } | ||
2590 | |||
2591 | static void join(struct atmel_private *priv, int type) | ||
2592 | { | ||
2593 | struct { | ||
2594 | u8 BSSID[6]; | ||
2595 | u8 SSID[MAX_SSID_LENGTH]; | ||
2596 | u8 BSS_type; /* this is a short in a scan command - weird */ | ||
2597 | u8 channel; | ||
2598 | u16 timeout; | ||
2599 | u8 SSID_size; | ||
2600 | u8 reserved; | ||
2601 | } cmd; | ||
2602 | |||
2603 | cmd.SSID_size = priv->SSID_size; | ||
2604 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | ||
2605 | memcpy(cmd.BSSID, priv->CurrentBSSID, 6); | ||
2606 | cmd.channel = (priv->channel & 0x7f); | ||
2607 | cmd.BSS_type = type; | ||
2608 | cmd.timeout = cpu_to_le16(2000); | ||
2609 | |||
2610 | atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); | ||
2611 | } | ||
2612 | |||
2613 | |||
2614 | static void start(struct atmel_private *priv, int type) | ||
2615 | { | ||
2616 | struct { | ||
2617 | u8 BSSID[6]; | ||
2618 | u8 SSID[MAX_SSID_LENGTH]; | ||
2619 | u8 BSS_type; | ||
2620 | u8 channel; | ||
2621 | u8 SSID_size; | ||
2622 | u8 reserved[3]; | ||
2623 | } cmd; | ||
2624 | |||
2625 | cmd.SSID_size = priv->SSID_size; | ||
2626 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | ||
2627 | memcpy(cmd.BSSID, priv->BSSID, 6); | ||
2628 | cmd.BSS_type = type; | ||
2629 | cmd.channel = (priv->channel & 0x7f); | ||
2630 | |||
2631 | atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); | ||
2632 | } | ||
2633 | |||
2634 | static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) | ||
2635 | { | ||
2636 | int rejoin = 0; | ||
2637 | int new = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? | ||
2638 | SHORT_PREAMBLE : LONG_PREAMBLE; | ||
2639 | |||
2640 | if (priv->preamble != new) { | ||
2641 | priv->preamble = new; | ||
2642 | rejoin = 1; | ||
2643 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); | ||
2644 | } | ||
2645 | |||
2646 | if (priv->channel != channel) { | ||
2647 | priv->channel = channel; | ||
2648 | rejoin = 1; | ||
2649 | atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); | ||
2650 | } | ||
2651 | |||
2652 | if (rejoin) { | ||
2653 | priv->station_is_associated = 0; | ||
2654 | atmel_enter_state(priv, STATION_STATE_JOINNING); | ||
2655 | |||
2656 | if (priv->operating_mode == IW_MODE_INFRA) | ||
2657 | join(priv, BSS_TYPE_INFRASTRUCTURE); | ||
2658 | else | ||
2659 | join(priv, BSS_TYPE_AD_HOC); | ||
2660 | } | ||
2661 | } | ||
2662 | |||
2663 | |||
2664 | static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) | ||
2665 | { | ||
2666 | struct ieee802_11_hdr header; | ||
2667 | struct auth_body auth; | ||
2668 | |||
2669 | header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH); | ||
2670 | header.duration_id = cpu_to_le16(0x8000); | ||
2671 | header.seq_ctl = 0; | ||
2672 | memcpy(header.addr1, priv->CurrentBSSID, 6); | ||
2673 | memcpy(header.addr2, priv->dev->dev_addr, 6); | ||
2674 | memcpy(header.addr3, priv->CurrentBSSID, 6); | ||
2675 | |||
2676 | if (priv->wep_is_on) { | ||
2677 | auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY); | ||
2678 | /* no WEP for authentication frames with TrSeqNo 1 */ | ||
2679 | if (priv->CurrentAuthentTransactionSeqNum != 1) | ||
2680 | header.frame_ctl |= cpu_to_le16(IEEE802_11_FCTL_WEP); | ||
2681 | } else { | ||
2682 | auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM); | ||
2683 | } | ||
2684 | |||
2685 | auth.status = 0; | ||
2686 | auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); | ||
2687 | priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; | ||
2688 | priv->CurrentAuthentTransactionSeqNum += 2; | ||
2689 | |||
2690 | if (challenge_len != 0) { | ||
2691 | auth.el_id = 16; /* challenge_text */ | ||
2692 | auth.chall_text_len = challenge_len; | ||
2693 | memcpy(auth.chall_text, challenge, challenge_len); | ||
2694 | atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); | ||
2695 | } else { | ||
2696 | atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); | ||
2697 | } | ||
2698 | } | ||
2699 | |||
2700 | static void send_association_request(struct atmel_private *priv, int is_reassoc) | ||
2701 | { | ||
2702 | u8 *ssid_el_p; | ||
2703 | int bodysize; | ||
2704 | struct ieee802_11_hdr header; | ||
2705 | struct ass_req_format { | ||
2706 | u16 capability; | ||
2707 | u16 listen_interval; | ||
2708 | u8 ap[6]; /* nothing after here directly accessible */ | ||
2709 | u8 ssid_el_id; | ||
2710 | u8 ssid_len; | ||
2711 | u8 ssid[MAX_SSID_LENGTH]; | ||
2712 | u8 sup_rates_el_id; | ||
2713 | u8 sup_rates_len; | ||
2714 | u8 rates[4]; | ||
2715 | } body; | ||
2716 | |||
2717 | header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | | ||
2718 | (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ)); | ||
2719 | header.duration_id = cpu_to_le16(0x8000); | ||
2720 | header.seq_ctl = 0; | ||
2721 | |||
2722 | memcpy(header.addr1, priv->CurrentBSSID, 6); | ||
2723 | memcpy(header.addr2, priv->dev->dev_addr, 6); | ||
2724 | memcpy(header.addr3, priv->CurrentBSSID, 6); | ||
2725 | |||
2726 | body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS); | ||
2727 | if (priv->wep_is_on) | ||
2728 | body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy); | ||
2729 | if (priv->preamble == SHORT_PREAMBLE) | ||
2730 | body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble); | ||
2731 | |||
2732 | body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); | ||
2733 | |||
2734 | /* current AP address - only in reassoc frame */ | ||
2735 | if (is_reassoc) { | ||
2736 | memcpy(body.ap, priv->CurrentBSSID, 6); | ||
2737 | ssid_el_p = (u8 *)&body.ssid_el_id; | ||
2738 | bodysize = 18 + priv->SSID_size; | ||
2739 | } else { | ||
2740 | ssid_el_p = (u8 *)&body.ap[0]; | ||
2741 | bodysize = 12 + priv->SSID_size; | ||
2742 | } | ||
2743 | |||
2744 | ssid_el_p[0]= C80211_MGMT_ElementID_SSID; | ||
2745 | ssid_el_p[1] = priv->SSID_size; | ||
2746 | memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); | ||
2747 | ssid_el_p[2 + priv->SSID_size] = C80211_MGMT_ElementID_SupportedRates; | ||
2748 | ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ | ||
2749 | memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); | ||
2750 | |||
2751 | atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); | ||
2752 | } | ||
2753 | |||
2754 | static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header) | ||
2755 | { | ||
2756 | if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) | ||
2757 | return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; | ||
2758 | else | ||
2759 | return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; | ||
2760 | } | ||
2761 | |||
2762 | static int retrieve_bss(struct atmel_private *priv) | ||
2763 | { | ||
2764 | int i; | ||
2765 | int max_rssi = -128; | ||
2766 | int max_index = -1; | ||
2767 | |||
2768 | if (priv->BSS_list_entries == 0) | ||
2769 | return -1; | ||
2770 | |||
2771 | if (priv->connect_to_any_BSS) { | ||
2772 | /* Select a BSS with the max-RSSI but of the same type and of the same WEP mode | ||
2773 | and that it is not marked as 'bad' (i.e. we had previously failed to connect to | ||
2774 | this BSS with the settings that we currently use) */ | ||
2775 | priv->current_BSS = 0; | ||
2776 | for(i=0; i<priv->BSS_list_entries; i++) { | ||
2777 | if (priv->operating_mode == priv->BSSinfo[i].BSStype && | ||
2778 | ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || | ||
2779 | (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && | ||
2780 | !(priv->BSSinfo[i].channel & 0x80)) { | ||
2781 | max_rssi = priv->BSSinfo[i].RSSI; | ||
2782 | priv->current_BSS = max_index = i; | ||
2783 | } | ||
2784 | |||
2785 | } | ||
2786 | return max_index; | ||
2787 | } | ||
2788 | |||
2789 | for(i=0; i<priv->BSS_list_entries; i++) { | ||
2790 | if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && | ||
2791 | memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && | ||
2792 | priv->operating_mode == priv->BSSinfo[i].BSStype && | ||
2793 | atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { | ||
2794 | if (priv->BSSinfo[i].RSSI >= max_rssi) { | ||
2795 | max_rssi = priv->BSSinfo[i].RSSI; | ||
2796 | max_index = i; | ||
2797 | } | ||
2798 | } | ||
2799 | } | ||
2800 | return max_index; | ||
2801 | } | ||
2802 | |||
2803 | |||
2804 | static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header, | ||
2805 | u16 capability, u16 beacon_period, u8 channel, u8 rssi, | ||
2806 | u8 ssid_len, u8 *ssid, int is_beacon) | ||
2807 | { | ||
2808 | u8 *bss = capability & C80211_MGMT_CAPABILITY_ESS ? header->addr2 : header->addr3; | ||
2809 | int i, index; | ||
2810 | |||
2811 | for (index = -1, i = 0; i < priv->BSS_list_entries; i++) | ||
2812 | if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0) | ||
2813 | index = i; | ||
2814 | |||
2815 | /* If we process a probe and an entry from this BSS exists | ||
2816 | we will update the BSS entry with the info from this BSS. | ||
2817 | If we process a beacon we will only update RSSI */ | ||
2818 | |||
2819 | if (index == -1) { | ||
2820 | if (priv->BSS_list_entries == MAX_BSS_ENTRIES) | ||
2821 | return; | ||
2822 | index = priv->BSS_list_entries++; | ||
2823 | memcpy(priv->BSSinfo[index].BSSID, bss, 6); | ||
2824 | priv->BSSinfo[index].RSSI = rssi; | ||
2825 | } else { | ||
2826 | if (rssi > priv->BSSinfo[index].RSSI) | ||
2827 | priv->BSSinfo[index].RSSI = rssi; | ||
2828 | if (is_beacon) | ||
2829 | return; | ||
2830 | } | ||
2831 | |||
2832 | priv->BSSinfo[index].channel = channel; | ||
2833 | priv->BSSinfo[index].beacon_period = beacon_period; | ||
2834 | priv->BSSinfo[index].UsingWEP = capability & C80211_MGMT_CAPABILITY_Privacy; | ||
2835 | memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); | ||
2836 | priv->BSSinfo[index].SSIDsize = ssid_len; | ||
2837 | |||
2838 | if (capability & C80211_MGMT_CAPABILITY_IBSS) | ||
2839 | priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; | ||
2840 | else if (capability & C80211_MGMT_CAPABILITY_ESS) | ||
2841 | priv->BSSinfo[index].BSStype =IW_MODE_INFRA; | ||
2842 | |||
2843 | priv->BSSinfo[index].preamble = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? | ||
2844 | SHORT_PREAMBLE : LONG_PREAMBLE; | ||
2845 | } | ||
2846 | |||
2847 | static void authenticate(struct atmel_private *priv, u16 frame_len) | ||
2848 | { | ||
2849 | struct auth_body *auth = (struct auth_body *)priv->rx_buf; | ||
2850 | u16 status = le16_to_cpu(auth->status); | ||
2851 | u16 trans_seq_no = le16_to_cpu(auth->trans_seq); | ||
2852 | |||
2853 | if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) { | ||
2854 | /* no WEP */ | ||
2855 | if (priv->station_was_associated) { | ||
2856 | atmel_enter_state(priv, STATION_STATE_REASSOCIATING); | ||
2857 | send_association_request(priv, 1); | ||
2858 | return; | ||
2859 | } else { | ||
2860 | atmel_enter_state(priv, STATION_STATE_ASSOCIATING); | ||
2861 | send_association_request(priv, 0); | ||
2862 | return; | ||
2863 | } | ||
2864 | } | ||
2865 | |||
2866 | if (status == C80211_MGMT_SC_Success && priv->wep_is_on) { | ||
2867 | /* WEP */ | ||
2868 | if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) | ||
2869 | return; | ||
2870 | |||
2871 | if (trans_seq_no == 0x0002 && | ||
2872 | auth->el_id == C80211_MGMT_ElementID_ChallengeText) { | ||
2873 | send_authentication_request(priv, auth->chall_text, auth->chall_text_len); | ||
2874 | return; | ||
2875 | } | ||
2876 | |||
2877 | if (trans_seq_no == 0x0004) { | ||
2878 | if(priv->station_was_associated) { | ||
2879 | atmel_enter_state(priv, STATION_STATE_REASSOCIATING); | ||
2880 | send_association_request(priv, 1); | ||
2881 | return; | ||
2882 | } else { | ||
2883 | atmel_enter_state(priv, STATION_STATE_ASSOCIATING); | ||
2884 | send_association_request(priv, 0); | ||
2885 | return; | ||
2886 | } | ||
2887 | } | ||
2888 | } | ||
2889 | |||
2890 | if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) { | ||
2891 | int bss_index; | ||
2892 | |||
2893 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | ||
2894 | |||
2895 | if ((bss_index = retrieve_bss(priv)) != -1) { | ||
2896 | atmel_join_bss(priv, bss_index); | ||
2897 | return; | ||
2898 | } | ||
2899 | } | ||
2900 | |||
2901 | |||
2902 | priv->AuthenticationRequestRetryCnt = 0; | ||
2903 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
2904 | priv->station_is_associated = 0; | ||
2905 | } | ||
2906 | |||
2907 | static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) | ||
2908 | { | ||
2909 | struct ass_resp_format { | ||
2910 | u16 capability; | ||
2911 | u16 status; | ||
2912 | u16 ass_id; | ||
2913 | u8 el_id; | ||
2914 | u8 length; | ||
2915 | u8 rates[4]; | ||
2916 | } *ass_resp = (struct ass_resp_format *)priv->rx_buf; | ||
2917 | |||
2918 | u16 status = le16_to_cpu(ass_resp->status); | ||
2919 | u16 ass_id = le16_to_cpu(ass_resp->ass_id); | ||
2920 | u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; | ||
2921 | |||
2922 | if (frame_len < 8 + rates_len) | ||
2923 | return; | ||
2924 | |||
2925 | if (status == C80211_MGMT_SC_Success) { | ||
2926 | if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE) | ||
2927 | priv->AssociationRequestRetryCnt = 0; | ||
2928 | else | ||
2929 | priv->ReAssociationRequestRetryCnt = 0; | ||
2930 | |||
2931 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); | ||
2932 | atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); | ||
2933 | if (priv->power_mode == 0) { | ||
2934 | priv->listen_interval = 1; | ||
2935 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | ||
2936 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | ||
2937 | } else { | ||
2938 | priv->listen_interval = 2; | ||
2939 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); | ||
2940 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); | ||
2941 | } | ||
2942 | |||
2943 | priv->station_is_associated = 1; | ||
2944 | priv->station_was_associated = 1; | ||
2945 | atmel_enter_state(priv, STATION_STATE_READY); | ||
2946 | return; | ||
2947 | } | ||
2948 | |||
2949 | if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE && | ||
2950 | status != C80211_MGMT_SC_AssDeniedBSSRate && | ||
2951 | status != C80211_MGMT_SC_SupportCapabilities && | ||
2952 | priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { | ||
2953 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | ||
2954 | priv->AssociationRequestRetryCnt++; | ||
2955 | send_association_request(priv, 0); | ||
2956 | return; | ||
2957 | } | ||
2958 | |||
2959 | if (subtype == C80211_SUBTYPE_MGMT_REASS_RESPONSE && | ||
2960 | status != C80211_MGMT_SC_AssDeniedBSSRate && | ||
2961 | status != C80211_MGMT_SC_SupportCapabilities && | ||
2962 | priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { | ||
2963 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | ||
2964 | priv->ReAssociationRequestRetryCnt++; | ||
2965 | send_association_request(priv, 1); | ||
2966 | return; | ||
2967 | } | ||
2968 | |||
2969 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
2970 | priv->station_is_associated = 0; | ||
2971 | |||
2972 | if(priv->connect_to_any_BSS) { | ||
2973 | int bss_index; | ||
2974 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | ||
2975 | |||
2976 | if ((bss_index = retrieve_bss(priv)) != -1) | ||
2977 | atmel_join_bss(priv, bss_index); | ||
2978 | |||
2979 | } | ||
2980 | } | ||
2981 | |||
2982 | void atmel_join_bss(struct atmel_private *priv, int bss_index) | ||
2983 | { | ||
2984 | struct bss_info *bss = &priv->BSSinfo[bss_index]; | ||
2985 | |||
2986 | memcpy(priv->CurrentBSSID, bss->BSSID, 6); | ||
2987 | memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); | ||
2988 | |||
2989 | /* The WPA stuff cares about the current AP address */ | ||
2990 | if (priv->use_wpa) | ||
2991 | build_wpa_mib(priv); | ||
2992 | |||
2993 | /* When switching to AdHoc turn OFF Power Save if needed */ | ||
2994 | |||
2995 | if (bss->BSStype == IW_MODE_ADHOC && | ||
2996 | priv->operating_mode != IW_MODE_ADHOC && | ||
2997 | priv->power_mode) { | ||
2998 | priv->power_mode = 0; | ||
2999 | priv->listen_interval = 1; | ||
3000 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | ||
3001 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | ||
3002 | } | ||
3003 | |||
3004 | priv->operating_mode = bss->BSStype; | ||
3005 | priv->channel = bss->channel & 0x7f; | ||
3006 | priv->beacon_period = bss->beacon_period; | ||
3007 | |||
3008 | if (priv->preamble != bss->preamble) { | ||
3009 | priv->preamble = bss->preamble; | ||
3010 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); | ||
3011 | } | ||
3012 | |||
3013 | if (!priv->wep_is_on && bss->UsingWEP) { | ||
3014 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
3015 | priv->station_is_associated = 0; | ||
3016 | return; | ||
3017 | } | ||
3018 | |||
3019 | if (priv->wep_is_on && !bss->UsingWEP) { | ||
3020 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
3021 | priv->station_is_associated = 0; | ||
3022 | return; | ||
3023 | } | ||
3024 | |||
3025 | atmel_enter_state(priv, STATION_STATE_JOINNING); | ||
3026 | |||
3027 | if (priv->operating_mode == IW_MODE_INFRA) | ||
3028 | join(priv, BSS_TYPE_INFRASTRUCTURE); | ||
3029 | else | ||
3030 | join(priv, BSS_TYPE_AD_HOC); | ||
3031 | } | ||
3032 | |||
3033 | |||
3034 | static void restart_search(struct atmel_private *priv) | ||
3035 | { | ||
3036 | int bss_index; | ||
3037 | |||
3038 | if (!priv->connect_to_any_BSS) { | ||
3039 | atmel_scan(priv, 1); | ||
3040 | } else { | ||
3041 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | ||
3042 | |||
3043 | if ((bss_index = retrieve_bss(priv)) != -1) | ||
3044 | atmel_join_bss(priv, bss_index); | ||
3045 | else | ||
3046 | atmel_scan(priv, 0); | ||
3047 | |||
3048 | } | ||
3049 | } | ||
3050 | |||
3051 | static void smooth_rssi(struct atmel_private *priv, u8 rssi) | ||
3052 | { | ||
3053 | u8 old = priv->wstats.qual.level; | ||
3054 | u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ | ||
3055 | |||
3056 | switch (priv->firmware_type) { | ||
3057 | case ATMEL_FW_TYPE_502E: | ||
3058 | max_rssi = 63; /* 502-rmfd-reve max by experiment */ | ||
3059 | break; | ||
3060 | default: | ||
3061 | break; | ||
3062 | } | ||
3063 | |||
3064 | rssi = rssi * 100 / max_rssi; | ||
3065 | if((rssi + old) % 2) | ||
3066 | priv->wstats.qual.level = ((rssi + old)/2) + 1; | ||
3067 | else | ||
3068 | priv->wstats.qual.level = ((rssi + old)/2); | ||
3069 | priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | ||
3070 | priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; | ||
3071 | } | ||
3072 | |||
3073 | static void atmel_smooth_qual(struct atmel_private *priv) | ||
3074 | { | ||
3075 | unsigned long time_diff = (jiffies - priv->last_qual)/HZ; | ||
3076 | while (time_diff--) { | ||
3077 | priv->last_qual += HZ; | ||
3078 | priv->wstats.qual.qual = priv->wstats.qual.qual/2; | ||
3079 | priv->wstats.qual.qual += | ||
3080 | priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; | ||
3081 | priv->beacons_this_sec = 0; | ||
3082 | } | ||
3083 | priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | ||
3084 | priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; | ||
3085 | } | ||
3086 | |||
3087 | /* deals with incoming managment frames. */ | ||
3088 | static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, | ||
3089 | u16 frame_len, u8 rssi) | ||
3090 | { | ||
3091 | u16 subtype; | ||
3092 | |||
3093 | switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) { | ||
3094 | case C80211_SUBTYPE_MGMT_BEACON : | ||
3095 | case C80211_SUBTYPE_MGMT_ProbeResponse: | ||
3096 | |||
3097 | /* beacon frame has multiple variable-length fields - | ||
3098 | never let an engineer loose with a data structure design. */ | ||
3099 | { | ||
3100 | struct beacon_format { | ||
3101 | u64 timestamp; | ||
3102 | u16 interval; | ||
3103 | u16 capability; | ||
3104 | u8 ssid_el_id; | ||
3105 | u8 ssid_length; | ||
3106 | /* ssid here */ | ||
3107 | u8 rates_el_id; | ||
3108 | u8 rates_length; | ||
3109 | /* rates here */ | ||
3110 | u8 ds_el_id; | ||
3111 | u8 ds_length; | ||
3112 | /* ds here */ | ||
3113 | } *beacon = (struct beacon_format *)priv->rx_buf; | ||
3114 | |||
3115 | u8 channel, rates_length, ssid_length; | ||
3116 | u64 timestamp = le64_to_cpu(beacon->timestamp); | ||
3117 | u16 beacon_interval = le16_to_cpu(beacon->interval); | ||
3118 | u16 capability = le16_to_cpu(beacon->capability); | ||
3119 | u8 *beaconp = priv->rx_buf; | ||
3120 | ssid_length = beacon->ssid_length; | ||
3121 | /* this blows chunks. */ | ||
3122 | if (frame_len < 14 || frame_len < ssid_length + 15) | ||
3123 | return; | ||
3124 | rates_length = beaconp[beacon->ssid_length + 15]; | ||
3125 | if (frame_len < ssid_length + rates_length + 18) | ||
3126 | return; | ||
3127 | if (ssid_length > MAX_SSID_LENGTH) | ||
3128 | return; | ||
3129 | channel = beaconp[ssid_length + rates_length + 18]; | ||
3130 | |||
3131 | if (priv->station_state == STATION_STATE_READY) { | ||
3132 | smooth_rssi(priv, rssi); | ||
3133 | if (is_frame_from_current_bss(priv, header)) { | ||
3134 | priv->beacons_this_sec++; | ||
3135 | atmel_smooth_qual(priv); | ||
3136 | if (priv->last_beacon_timestamp) { | ||
3137 | /* Note truncate this to 32 bits - kernel can't divide a long long */ | ||
3138 | u32 beacon_delay = timestamp - priv->last_beacon_timestamp; | ||
3139 | int beacons = beacon_delay / (beacon_interval * 1000); | ||
3140 | if (beacons > 1) | ||
3141 | priv->wstats.miss.beacon += beacons - 1; | ||
3142 | } | ||
3143 | priv->last_beacon_timestamp = timestamp; | ||
3144 | handle_beacon_probe(priv, capability, channel); | ||
3145 | } | ||
3146 | } | ||
3147 | |||
3148 | if (priv->station_state == STATION_STATE_SCANNING ) | ||
3149 | store_bss_info(priv, header, capability, beacon_interval, channel, | ||
3150 | rssi, ssid_length, &beacon->rates_el_id, | ||
3151 | subtype == C80211_SUBTYPE_MGMT_BEACON) ; | ||
3152 | } | ||
3153 | break; | ||
3154 | |||
3155 | case C80211_SUBTYPE_MGMT_Authentication: | ||
3156 | |||
3157 | if (priv->station_state == STATION_STATE_AUTHENTICATING) | ||
3158 | authenticate(priv, frame_len); | ||
3159 | |||
3160 | break; | ||
3161 | |||
3162 | case C80211_SUBTYPE_MGMT_ASS_RESPONSE: | ||
3163 | case C80211_SUBTYPE_MGMT_REASS_RESPONSE: | ||
3164 | |||
3165 | if (priv->station_state == STATION_STATE_ASSOCIATING || | ||
3166 | priv->station_state == STATION_STATE_REASSOCIATING) | ||
3167 | associate(priv, frame_len, subtype); | ||
3168 | |||
3169 | break; | ||
3170 | |||
3171 | case C80211_SUBTYPE_MGMT_DISASSOSIATION: | ||
3172 | if (priv->station_is_associated && | ||
3173 | priv->operating_mode == IW_MODE_INFRA && | ||
3174 | is_frame_from_current_bss(priv, header)) { | ||
3175 | priv->station_was_associated = 0; | ||
3176 | priv->station_is_associated = 0; | ||
3177 | |||
3178 | atmel_enter_state(priv, STATION_STATE_JOINNING); | ||
3179 | join(priv, BSS_TYPE_INFRASTRUCTURE); | ||
3180 | } | ||
3181 | |||
3182 | break; | ||
3183 | |||
3184 | case C80211_SUBTYPE_MGMT_Deauthentication: | ||
3185 | if (priv->operating_mode == IW_MODE_INFRA && | ||
3186 | is_frame_from_current_bss(priv, header)) { | ||
3187 | priv->station_was_associated = 0; | ||
3188 | |||
3189 | atmel_enter_state(priv, STATION_STATE_JOINNING); | ||
3190 | join(priv, BSS_TYPE_INFRASTRUCTURE); | ||
3191 | } | ||
3192 | |||
3193 | break; | ||
3194 | } | ||
3195 | } | ||
3196 | |||
3197 | /* run when timer expires */ | ||
3198 | static void atmel_management_timer(u_long a) | ||
3199 | { | ||
3200 | struct net_device *dev = (struct net_device *) a; | ||
3201 | struct atmel_private *priv = netdev_priv(dev); | ||
3202 | unsigned long flags; | ||
3203 | |||
3204 | /* Check if the card has been yanked. */ | ||
3205 | if (priv->card && priv->present_callback && | ||
3206 | !(*priv->present_callback)(priv->card)) | ||
3207 | return; | ||
3208 | |||
3209 | spin_lock_irqsave(&priv->irqlock, flags); | ||
3210 | |||
3211 | switch (priv->station_state) { | ||
3212 | |||
3213 | case STATION_STATE_AUTHENTICATING: | ||
3214 | if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { | ||
3215 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
3216 | priv->station_is_associated = 0; | ||
3217 | priv->AuthenticationRequestRetryCnt = 0; | ||
3218 | restart_search(priv); | ||
3219 | } else { | ||
3220 | priv->AuthenticationRequestRetryCnt++; | ||
3221 | priv->CurrentAuthentTransactionSeqNum = 0x0001; | ||
3222 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | ||
3223 | send_authentication_request(priv, NULL, 0); | ||
3224 | } | ||
3225 | |||
3226 | break; | ||
3227 | |||
3228 | case STATION_STATE_ASSOCIATING: | ||
3229 | if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { | ||
3230 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
3231 | priv->station_is_associated = 0; | ||
3232 | priv->AssociationRequestRetryCnt = 0; | ||
3233 | restart_search(priv); | ||
3234 | } else { | ||
3235 | priv->AssociationRequestRetryCnt++; | ||
3236 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | ||
3237 | send_association_request(priv, 0); | ||
3238 | } | ||
3239 | |||
3240 | break; | ||
3241 | |||
3242 | case STATION_STATE_REASSOCIATING: | ||
3243 | if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { | ||
3244 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | ||
3245 | priv->station_is_associated = 0; | ||
3246 | priv->ReAssociationRequestRetryCnt = 0; | ||
3247 | restart_search(priv); | ||
3248 | } else { | ||
3249 | priv->ReAssociationRequestRetryCnt++; | ||
3250 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | ||
3251 | send_association_request(priv, 1); | ||
3252 | } | ||
3253 | |||
3254 | break; | ||
3255 | |||
3256 | default: | ||
3257 | break; | ||
3258 | } | ||
3259 | |||
3260 | spin_unlock_irqrestore(&priv->irqlock, flags); | ||
3261 | } | ||
3262 | |||
3263 | static void atmel_command_irq(struct atmel_private *priv) | ||
3264 | { | ||
3265 | u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | ||
3266 | u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); | ||
3267 | int fast_scan; | ||
3268 | |||
3269 | if (status == CMD_STATUS_IDLE || | ||
3270 | status == CMD_STATUS_IN_PROGRESS) | ||
3271 | return; | ||
3272 | |||
3273 | switch (command){ | ||
3274 | |||
3275 | case CMD_Start: | ||
3276 | if (status == CMD_STATUS_COMPLETE) { | ||
3277 | priv->station_was_associated = priv->station_is_associated; | ||
3278 | atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, | ||
3279 | (u8 *)priv->CurrentBSSID, 6); | ||
3280 | atmel_enter_state(priv, STATION_STATE_READY); | ||
3281 | } | ||
3282 | break; | ||
3283 | |||
3284 | case CMD_Scan: | ||
3285 | fast_scan = priv->fast_scan; | ||
3286 | priv->fast_scan = 0; | ||
3287 | |||
3288 | if (status != CMD_STATUS_COMPLETE) { | ||
3289 | atmel_scan(priv, 1); | ||
3290 | } else { | ||
3291 | int bss_index = retrieve_bss(priv); | ||
3292 | if (bss_index != -1) { | ||
3293 | atmel_join_bss(priv, bss_index); | ||
3294 | } else if (priv->operating_mode == IW_MODE_ADHOC && | ||
3295 | priv->SSID_size != 0) { | ||
3296 | start(priv, BSS_TYPE_AD_HOC); | ||
3297 | } else { | ||
3298 | priv->fast_scan = !fast_scan; | ||
3299 | atmel_scan(priv, 1); | ||
3300 | } | ||
3301 | priv->site_survey_state = SITE_SURVEY_COMPLETED; | ||
3302 | } | ||
3303 | break; | ||
3304 | |||
3305 | case CMD_SiteSurvey: | ||
3306 | priv->fast_scan = 0; | ||
3307 | |||
3308 | if (status != CMD_STATUS_COMPLETE) | ||
3309 | return; | ||
3310 | |||
3311 | priv->site_survey_state = SITE_SURVEY_COMPLETED; | ||
3312 | if (priv->station_is_associated) { | ||
3313 | atmel_enter_state(priv, STATION_STATE_READY); | ||
3314 | } else { | ||
3315 | atmel_scan(priv, 1); | ||
3316 | } | ||
3317 | break; | ||
3318 | |||
3319 | case CMD_Join: | ||
3320 | if (status == CMD_STATUS_COMPLETE) { | ||
3321 | if (priv->operating_mode == IW_MODE_ADHOC) { | ||
3322 | priv->station_was_associated = priv->station_is_associated; | ||
3323 | atmel_enter_state(priv, STATION_STATE_READY); | ||
3324 | } else { | ||
3325 | priv->AuthenticationRequestRetryCnt = 0; | ||
3326 | atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); | ||
3327 | |||
3328 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | ||
3329 | priv->CurrentAuthentTransactionSeqNum = 0x0001; | ||
3330 | send_authentication_request(priv, NULL, 0); | ||
3331 | } | ||
3332 | return; | ||
3333 | } | ||
3334 | |||
3335 | atmel_scan(priv, 1); | ||
3336 | |||
3337 | } | ||
3338 | } | ||
3339 | |||
3340 | static int atmel_wakeup_firmware(struct atmel_private *priv) | ||
3341 | { | ||
3342 | struct host_info_struct *iface = &priv->host_info; | ||
3343 | u16 mr1, mr3; | ||
3344 | int i; | ||
3345 | |||
3346 | if (priv->card_type == CARD_TYPE_SPI_FLASH) | ||
3347 | atmel_set_gcr(priv->dev, GCR_REMAP); | ||
3348 | |||
3349 | /* wake up on-board processor */ | ||
3350 | atmel_clear_gcr(priv->dev, 0x0040); | ||
3351 | atmel_write16(priv->dev, BSR, BSS_SRAM); | ||
3352 | |||
3353 | if (priv->card_type == CARD_TYPE_SPI_FLASH) | ||
3354 | mdelay(100); | ||
3355 | |||
3356 | /* and wait for it */ | ||
3357 | for (i = LOOP_RETRY_LIMIT; i; i--) { | ||
3358 | mr1 = atmel_read16(priv->dev, MR1); | ||
3359 | mr3 = atmel_read16(priv->dev, MR3); | ||
3360 | |||
3361 | if (mr3 & MAC_BOOT_COMPLETE) | ||
3362 | break; | ||
3363 | if (mr1 & MAC_BOOT_COMPLETE && | ||
3364 | priv->bus_type == BUS_TYPE_PCCARD) | ||
3365 | break; | ||
3366 | } | ||
3367 | |||
3368 | if (i == 0) { | ||
3369 | printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); | ||
3370 | return 0; | ||
3371 | } | ||
3372 | |||
3373 | if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { | ||
3374 | printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); | ||
3375 | return 0; | ||
3376 | } | ||
3377 | |||
3378 | /* now check for completion of MAC initialization through | ||
3379 | the FunCtrl field of the IFACE, poll MR1 to detect completion of | ||
3380 | MAC initialization, check completion status, set interrupt mask, | ||
3381 | enables interrupts and calls Tx and Rx initialization functions */ | ||
3382 | |||
3383 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); | ||
3384 | |||
3385 | for (i = LOOP_RETRY_LIMIT; i; i--) { | ||
3386 | mr1 = atmel_read16(priv->dev, MR1); | ||
3387 | mr3 = atmel_read16(priv->dev, MR3); | ||
3388 | |||
3389 | if (mr3 & MAC_INIT_COMPLETE) | ||
3390 | break; | ||
3391 | if (mr1 & MAC_INIT_COMPLETE && | ||
3392 | priv->bus_type == BUS_TYPE_PCCARD) | ||
3393 | break; | ||
3394 | } | ||
3395 | |||
3396 | if (i == 0) { | ||
3397 | printk(KERN_ALERT "%s: MAC failed to initialise.\n", priv->dev->name); | ||
3398 | return 0; | ||
3399 | } | ||
3400 | |||
3401 | /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ | ||
3402 | if ((mr3 & MAC_INIT_COMPLETE) && | ||
3403 | !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { | ||
3404 | printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); | ||
3405 | return 0; | ||
3406 | } | ||
3407 | if ((mr1 & MAC_INIT_COMPLETE) && | ||
3408 | !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { | ||
3409 | printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); | ||
3410 | return 0; | ||
3411 | } | ||
3412 | |||
3413 | atmel_copy_to_host(priv->dev, (unsigned char *)iface, | ||
3414 | priv->host_info_base, sizeof(*iface)); | ||
3415 | |||
3416 | iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); | ||
3417 | iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); | ||
3418 | iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); | ||
3419 | iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); | ||
3420 | iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); | ||
3421 | iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); | ||
3422 | iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); | ||
3423 | iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); | ||
3424 | iface->build_version = le16_to_cpu(iface->build_version); | ||
3425 | iface->command_pos = le16_to_cpu(iface->command_pos); | ||
3426 | iface->major_version = le16_to_cpu(iface->major_version); | ||
3427 | iface->minor_version = le16_to_cpu(iface->minor_version); | ||
3428 | iface->func_ctrl = le16_to_cpu(iface->func_ctrl); | ||
3429 | iface->mac_status = le16_to_cpu(iface->mac_status); | ||
3430 | |||
3431 | return 1; | ||
3432 | } | ||
3433 | |||
3434 | /* determine type of memory and MAC address */ | ||
3435 | static int probe_atmel_card(struct net_device *dev) | ||
3436 | { | ||
3437 | int rc = 0; | ||
3438 | struct atmel_private *priv = netdev_priv(dev); | ||
3439 | |||
3440 | /* reset pccard */ | ||
3441 | if (priv->bus_type == BUS_TYPE_PCCARD) | ||
3442 | atmel_write16(dev, GCR, 0x0060); | ||
3443 | |||
3444 | atmel_write16(dev, GCR, 0x0040); | ||
3445 | mdelay(500); | ||
3446 | |||
3447 | if (atmel_read16(dev, MR2) == 0) { | ||
3448 | /* No stored firmware so load a small stub which just | ||
3449 | tells us the MAC address */ | ||
3450 | int i; | ||
3451 | priv->card_type = CARD_TYPE_EEPROM; | ||
3452 | atmel_write16(dev, BSR, BSS_IRAM); | ||
3453 | atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); | ||
3454 | atmel_set_gcr(dev, GCR_REMAP); | ||
3455 | atmel_clear_gcr(priv->dev, 0x0040); | ||
3456 | atmel_write16(dev, BSR, BSS_SRAM); | ||
3457 | for (i = LOOP_RETRY_LIMIT; i; i--) | ||
3458 | if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) | ||
3459 | break; | ||
3460 | if (i == 0) { | ||
3461 | printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); | ||
3462 | } else { | ||
3463 | atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); | ||
3464 | /* got address, now squash it again until the network | ||
3465 | interface is opened */ | ||
3466 | if (priv->bus_type == BUS_TYPE_PCCARD) | ||
3467 | atmel_write16(dev, GCR, 0x0060); | ||
3468 | atmel_write16(dev, GCR, 0x0040); | ||
3469 | rc = 1; | ||
3470 | } | ||
3471 | } else if (atmel_read16(dev, MR4) == 0) { | ||
3472 | /* Mac address easy in this case. */ | ||
3473 | priv->card_type = CARD_TYPE_PARALLEL_FLASH; | ||
3474 | atmel_write16(dev, BSR, 1); | ||
3475 | atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6); | ||
3476 | atmel_write16(dev, BSR, 0x200); | ||
3477 | rc = 1; | ||
3478 | } else { | ||
3479 | /* Standard firmware in flash, boot it up and ask | ||
3480 | for the Mac Address */ | ||
3481 | priv->card_type = CARD_TYPE_SPI_FLASH; | ||
3482 | if (atmel_wakeup_firmware(priv)) { | ||
3483 | atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6); | ||
3484 | |||
3485 | /* got address, now squash it again until the network | ||
3486 | interface is opened */ | ||
3487 | if (priv->bus_type == BUS_TYPE_PCCARD) | ||
3488 | atmel_write16(dev, GCR, 0x0060); | ||
3489 | atmel_write16(dev, GCR, 0x0040); | ||
3490 | rc = 1; | ||
3491 | } | ||
3492 | } | ||
3493 | |||
3494 | if (rc) { | ||
3495 | if (dev->dev_addr[0] == 0xFF) { | ||
3496 | u8 default_mac[] = {0x00,0x04, 0x25, 0x00, 0x00, 0x00}; | ||
3497 | printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); | ||
3498 | memcpy(dev->dev_addr, default_mac, 6); | ||
3499 | } | ||
3500 | printk(KERN_INFO "%s: MAC address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", | ||
3501 | dev->name, | ||
3502 | dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], | ||
3503 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); | ||
3504 | |||
3505 | } | ||
3506 | |||
3507 | return rc; | ||
3508 | } | ||
3509 | |||
3510 | static void build_wep_mib(struct atmel_private *priv) | ||
3511 | /* Move the encyption information on the MIB structure. | ||
3512 | This routine is for the pre-WPA firmware: later firmware has | ||
3513 | a different format MIB and a different routine. */ | ||
3514 | { | ||
3515 | struct { /* NB this is matched to the hardware, don't change. */ | ||
3516 | u8 wep_is_on; | ||
3517 | u8 default_key; /* 0..3 */ | ||
3518 | u8 reserved; | ||
3519 | u8 exclude_unencrypted; | ||
3520 | |||
3521 | u32 WEPICV_error_count; | ||
3522 | u32 WEP_excluded_count; | ||
3523 | |||
3524 | u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; | ||
3525 | u8 encryption_level; /* 0, 1, 2 */ | ||
3526 | u8 reserved2[3]; | ||
3527 | } mib; | ||
3528 | int i; | ||
3529 | |||
3530 | mib.wep_is_on = priv->wep_is_on; | ||
3531 | if (priv->wep_is_on) { | ||
3532 | if (priv->wep_key_len[priv->default_key] > 5) | ||
3533 | mib.encryption_level = 2; | ||
3534 | else | ||
3535 | mib.encryption_level = 1; | ||
3536 | } else { | ||
3537 | mib.encryption_level = 0; | ||
3538 | } | ||
3539 | |||
3540 | mib.default_key = priv->default_key; | ||
3541 | mib.exclude_unencrypted = priv->exclude_unencrypted; | ||
3542 | |||
3543 | for(i = 0; i < MAX_ENCRYPTION_KEYS; i++) | ||
3544 | memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); | ||
3545 | |||
3546 | atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); | ||
3547 | } | ||
3548 | |||
3549 | static void build_wpa_mib(struct atmel_private *priv) | ||
3550 | { | ||
3551 | /* This is for the later (WPA enabled) firmware. */ | ||
3552 | |||
3553 | struct { /* NB this is matched to the hardware, don't change. */ | ||
3554 | u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; | ||
3555 | u8 receiver_address[6]; | ||
3556 | u8 wep_is_on; | ||
3557 | u8 default_key; /* 0..3 */ | ||
3558 | u8 group_key; | ||
3559 | u8 exclude_unencrypted; | ||
3560 | u8 encryption_type; | ||
3561 | u8 reserved; | ||
3562 | |||
3563 | u32 WEPICV_error_count; | ||
3564 | u32 WEP_excluded_count; | ||
3565 | |||
3566 | u8 key_RSC[4][8]; | ||
3567 | } mib; | ||
3568 | |||
3569 | int i; | ||
3570 | |||
3571 | mib.wep_is_on = priv->wep_is_on; | ||
3572 | mib.exclude_unencrypted = priv->exclude_unencrypted; | ||
3573 | memcpy(mib.receiver_address, priv->CurrentBSSID, 6); | ||
3574 | |||
3575 | /* zero all the keys before adding in valid ones. */ | ||
3576 | memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); | ||
3577 | |||
3578 | if (priv->wep_is_on) { | ||
3579 | /* There's a comment in the Atmel code to the effect that this is only valid | ||
3580 | when still using WEP, it may need to be set to something to use WPA */ | ||
3581 | memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); | ||
3582 | |||
3583 | mib.default_key = mib.group_key = 255; | ||
3584 | for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { | ||
3585 | if (priv->wep_key_len[i] > 0) { | ||
3586 | memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); | ||
3587 | if (i == priv->default_key) { | ||
3588 | mib.default_key = i; | ||
3589 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; | ||
3590 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; | ||
3591 | } else { | ||
3592 | mib.group_key = i; | ||
3593 | priv->group_cipher_suite = priv->pairwise_cipher_suite; | ||
3594 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; | ||
3595 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; | ||
3596 | } | ||
3597 | } | ||
3598 | } | ||
3599 | if (mib.default_key == 255) | ||
3600 | mib.default_key = mib.group_key != 255 ? mib.group_key : 0; | ||
3601 | if (mib.group_key == 255) | ||
3602 | mib.group_key = mib.default_key; | ||
3603 | |||
3604 | } | ||
3605 | |||
3606 | atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); | ||
3607 | } | ||
3608 | |||
3609 | static int reset_atmel_card(struct net_device *dev) | ||
3610 | { | ||
3611 | /* do everything necessary to wake up the hardware, including | ||
3612 | waiting for the lightning strike and throwing the knife switch.... | ||
3613 | |||
3614 | set all the Mib values which matter in the card to match | ||
3615 | their settings in the atmel_private structure. Some of these | ||
3616 | can be altered on the fly, but many (WEP, infrastucture or ad-hoc) | ||
3617 | can only be changed by tearing down the world and coming back through | ||
3618 | here. | ||
3619 | |||
3620 | This routine is also responsible for initialising some | ||
3621 | hardware-specific fields in the atmel_private structure, | ||
3622 | including a copy of the firmware's hostinfo stucture | ||
3623 | which is the route into the rest of the firmare datastructures. */ | ||
3624 | |||
3625 | struct atmel_private *priv = netdev_priv(dev); | ||
3626 | u8 configuration; | ||
3627 | |||
3628 | /* data to add to the firmware names, in priority order | ||
3629 | this implemenents firmware versioning */ | ||
3630 | |||
3631 | static char *firmware_modifier[] = { | ||
3632 | "-wpa", | ||
3633 | "", | ||
3634 | NULL | ||
3635 | }; | ||
3636 | |||
3637 | /* reset pccard */ | ||
3638 | if (priv->bus_type == BUS_TYPE_PCCARD) | ||
3639 | atmel_write16(priv->dev, GCR, 0x0060); | ||
3640 | |||
3641 | /* stop card , disable interrupts */ | ||
3642 | atmel_write16(priv->dev, GCR, 0x0040); | ||
3643 | |||
3644 | if (priv->card_type == CARD_TYPE_EEPROM) { | ||
3645 | /* copy in firmware if needed */ | ||
3646 | const struct firmware *fw_entry = NULL; | ||
3647 | unsigned char *fw; | ||
3648 | int len = priv->firmware_length; | ||
3649 | if (!(fw = priv->firmware)) { | ||
3650 | if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { | ||
3651 | if (strlen(priv->firmware_id) == 0) { | ||
3652 | printk(KERN_INFO | ||
3653 | "%s: card type is unknown: assuming at76c502 firmware is OK.\n", | ||
3654 | dev->name); | ||
3655 | printk(KERN_INFO | ||
3656 | "%s: if not, use the firmware= module parameter.\n", | ||
3657 | dev->name); | ||
3658 | strcpy(priv->firmware_id, "atmel_at76c502.bin"); | ||
3659 | } | ||
3660 | if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) { | ||
3661 | printk(KERN_ALERT | ||
3662 | "%s: firmware %s is missing, cannot continue.\n", | ||
3663 | dev->name, priv->firmware_id); | ||
3664 | return 0; | ||
3665 | } | ||
3666 | } else { | ||
3667 | int fw_index = 0; | ||
3668 | int success = 0; | ||
3669 | |||
3670 | /* get firmware filename entry based on firmware type ID */ | ||
3671 | while (fw_table[fw_index].fw_type != priv->firmware_type | ||
3672 | && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) | ||
3673 | fw_index++; | ||
3674 | |||
3675 | /* construct the actual firmware file name */ | ||
3676 | if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { | ||
3677 | int i; | ||
3678 | for (i = 0; firmware_modifier[i]; i++) { | ||
3679 | snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, | ||
3680 | firmware_modifier[i], fw_table[fw_index].fw_file_ext); | ||
3681 | priv->firmware_id[31] = '\0'; | ||
3682 | if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { | ||
3683 | success = 1; | ||
3684 | break; | ||
3685 | } | ||
3686 | } | ||
3687 | } | ||
3688 | if (!success) { | ||
3689 | printk(KERN_ALERT | ||
3690 | "%s: firmware %s is missing, cannot start.\n", | ||
3691 | dev->name, priv->firmware_id); | ||
3692 | priv->firmware_id[0] = '\0'; | ||
3693 | return 0; | ||
3694 | } | ||
3695 | } | ||
3696 | |||
3697 | fw = fw_entry->data; | ||
3698 | len = fw_entry->size; | ||
3699 | } | ||
3700 | |||
3701 | if (len <= 0x6000) { | ||
3702 | atmel_write16(priv->dev, BSR, BSS_IRAM); | ||
3703 | atmel_copy_to_card(priv->dev, 0, fw, len); | ||
3704 | atmel_set_gcr(priv->dev, GCR_REMAP); | ||
3705 | } else { | ||
3706 | /* Remap */ | ||
3707 | atmel_set_gcr(priv->dev, GCR_REMAP); | ||
3708 | atmel_write16(priv->dev, BSR, BSS_IRAM); | ||
3709 | atmel_copy_to_card(priv->dev, 0, fw, 0x6000); | ||
3710 | atmel_write16(priv->dev, BSR, 0x2ff); | ||
3711 | atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); | ||
3712 | } | ||
3713 | |||
3714 | if (fw_entry) | ||
3715 | release_firmware(fw_entry); | ||
3716 | } | ||
3717 | |||
3718 | if (!atmel_wakeup_firmware(priv)) | ||
3719 | return 0; | ||
3720 | |||
3721 | /* Check the version and set the correct flag for wpa stuff, | ||
3722 | old and new firmware is incompatible. | ||
3723 | The pre-wpa 3com firmware reports major version 5, | ||
3724 | the wpa 3com firmware is major version 4 and doesn't need | ||
3725 | the 3com broken-ness filter. */ | ||
3726 | priv->use_wpa = (priv->host_info.major_version == 4); | ||
3727 | priv->radio_on_broken = (priv->host_info.major_version == 5); | ||
3728 | |||
3729 | /* unmask all irq sources */ | ||
3730 | atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); | ||
3731 | |||
3732 | /* int Tx system and enable Tx */ | ||
3733 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); | ||
3734 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); | ||
3735 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); | ||
3736 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); | ||
3737 | |||
3738 | priv->tx_desc_free = priv->host_info.tx_desc_count; | ||
3739 | priv->tx_desc_head = 0; | ||
3740 | priv->tx_desc_tail = 0; | ||
3741 | priv->tx_desc_previous = 0; | ||
3742 | priv->tx_free_mem = priv->host_info.tx_buff_size; | ||
3743 | priv->tx_buff_head = 0; | ||
3744 | priv->tx_buff_tail = 0; | ||
3745 | |||
3746 | configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); | ||
3747 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), | ||
3748 | configuration | FUNC_CTRL_TxENABLE); | ||
3749 | |||
3750 | /* init Rx system and enable */ | ||
3751 | priv->rx_desc_head = 0; | ||
3752 | |||
3753 | configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); | ||
3754 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), | ||
3755 | configuration | FUNC_CTRL_RxENABLE); | ||
3756 | |||
3757 | if (!priv->radio_on_broken) { | ||
3758 | if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == | ||
3759 | CMD_STATUS_REJECTED_RADIO_OFF) { | ||
3760 | printk(KERN_INFO | ||
3761 | "%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n", | ||
3762 | dev->name); | ||
3763 | return 0; | ||
3764 | } | ||
3765 | } | ||
3766 | |||
3767 | /* set up enough MIB values to run. */ | ||
3768 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); | ||
3769 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); | ||
3770 | atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); | ||
3771 | atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); | ||
3772 | atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); | ||
3773 | atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); | ||
3774 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); | ||
3775 | atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, | ||
3776 | priv->dev->dev_addr, 6); | ||
3777 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | ||
3778 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | ||
3779 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); | ||
3780 | atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); | ||
3781 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); | ||
3782 | if (priv->use_wpa) | ||
3783 | build_wpa_mib(priv); | ||
3784 | else | ||
3785 | build_wep_mib(priv); | ||
3786 | |||
3787 | return 1; | ||
3788 | } | ||
3789 | |||
3790 | static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size) | ||
3791 | { | ||
3792 | if (cmd) | ||
3793 | atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), | ||
3794 | cmd, cmd_size); | ||
3795 | |||
3796 | atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); | ||
3797 | atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); | ||
3798 | } | ||
3799 | |||
3800 | static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size) | ||
3801 | { | ||
3802 | int i, status; | ||
3803 | |||
3804 | atmel_send_command(priv, command, cmd, cmd_size); | ||
3805 | |||
3806 | for (i = 5000; i; i--) { | ||
3807 | status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | ||
3808 | if (status != CMD_STATUS_IDLE && | ||
3809 | status != CMD_STATUS_IN_PROGRESS) | ||
3810 | break; | ||
3811 | udelay(20); | ||
3812 | } | ||
3813 | |||
3814 | if (i == 0) { | ||
3815 | printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); | ||
3816 | status = CMD_STATUS_HOST_ERROR; | ||
3817 | } else { | ||
3818 | if (command != CMD_EnableRadio) | ||
3819 | status = CMD_STATUS_COMPLETE; | ||
3820 | } | ||
3821 | |||
3822 | return status; | ||
3823 | } | ||
3824 | |||
3825 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) | ||
3826 | { | ||
3827 | struct get_set_mib m; | ||
3828 | m.type = type; | ||
3829 | m.size = 1; | ||
3830 | m.index = index; | ||
3831 | |||
3832 | atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); | ||
3833 | return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); | ||
3834 | } | ||
3835 | |||
3836 | static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) | ||
3837 | { | ||
3838 | struct get_set_mib m; | ||
3839 | m.type = type; | ||
3840 | m.size = 1; | ||
3841 | m.index = index; | ||
3842 | m.data[0] = data; | ||
3843 | |||
3844 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); | ||
3845 | } | ||
3846 | |||
3847 | static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data) | ||
3848 | { | ||
3849 | struct get_set_mib m; | ||
3850 | m.type = type; | ||
3851 | m.size = 2; | ||
3852 | m.index = index; | ||
3853 | m.data[0] = data; | ||
3854 | m.data[1] = data >> 8; | ||
3855 | |||
3856 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); | ||
3857 | } | ||
3858 | |||
3859 | static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) | ||
3860 | { | ||
3861 | struct get_set_mib m; | ||
3862 | m.type = type; | ||
3863 | m.size = data_len; | ||
3864 | m.index = index; | ||
3865 | |||
3866 | if (data_len > MIB_MAX_DATA_BYTES) | ||
3867 | printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); | ||
3868 | |||
3869 | memcpy(m.data, data, data_len); | ||
3870 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); | ||
3871 | } | ||
3872 | |||
3873 | static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) | ||
3874 | { | ||
3875 | struct get_set_mib m; | ||
3876 | m.type = type; | ||
3877 | m.size = data_len; | ||
3878 | m.index = index; | ||
3879 | |||
3880 | if (data_len > MIB_MAX_DATA_BYTES) | ||
3881 | printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); | ||
3882 | |||
3883 | atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); | ||
3884 | atmel_copy_to_host(priv->dev, data, | ||
3885 | atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); | ||
3886 | } | ||
3887 | |||
3888 | static void atmel_writeAR(struct net_device *dev, u16 data) | ||
3889 | { | ||
3890 | int i; | ||
3891 | outw(data, dev->base_addr + AR); | ||
3892 | /* Address register appears to need some convincing..... */ | ||
3893 | for (i = 0; data != inw(dev->base_addr + AR) && i<10; i++) | ||
3894 | outw(data, dev->base_addr + AR); | ||
3895 | } | ||
3896 | |||
3897 | static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len) | ||
3898 | { | ||
3899 | int i; | ||
3900 | atmel_writeAR(dev, dest); | ||
3901 | if (dest % 2) { | ||
3902 | atmel_write8(dev, DR, *src); | ||
3903 | src++; len--; | ||
3904 | } | ||
3905 | for (i = len; i > 1 ; i -= 2) { | ||
3906 | u8 lb = *src++; | ||
3907 | u8 hb = *src++; | ||
3908 | atmel_write16(dev, DR, lb | (hb << 8)); | ||
3909 | } | ||
3910 | if (i) | ||
3911 | atmel_write8(dev, DR, *src); | ||
3912 | } | ||
3913 | |||
3914 | static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len) | ||
3915 | { | ||
3916 | int i; | ||
3917 | atmel_writeAR(dev, src); | ||
3918 | if (src % 2) { | ||
3919 | *dest = atmel_read8(dev, DR); | ||
3920 | dest++; len--; | ||
3921 | } | ||
3922 | for (i = len; i > 1 ; i -= 2) { | ||
3923 | u16 hw = atmel_read16(dev, DR); | ||
3924 | *dest++ = hw; | ||
3925 | *dest++ = hw >> 8; | ||
3926 | } | ||
3927 | if (i) | ||
3928 | *dest = atmel_read8(dev, DR); | ||
3929 | } | ||
3930 | |||
3931 | static void atmel_set_gcr(struct net_device *dev, u16 mask) | ||
3932 | { | ||
3933 | outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); | ||
3934 | } | ||
3935 | |||
3936 | static void atmel_clear_gcr(struct net_device *dev, u16 mask) | ||
3937 | { | ||
3938 | outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); | ||
3939 | } | ||
3940 | |||
3941 | static int atmel_lock_mac(struct atmel_private *priv) | ||
3942 | { | ||
3943 | int i, j = 20; | ||
3944 | retry: | ||
3945 | for (i = 5000; i; i--) { | ||
3946 | if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) | ||
3947 | break; | ||
3948 | udelay(20); | ||
3949 | } | ||
3950 | |||
3951 | if (!i) return 0; /* timed out */ | ||
3952 | |||
3953 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); | ||
3954 | if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { | ||
3955 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | ||
3956 | if (!j--) return 0; /* timed out */ | ||
3957 | goto retry; | ||
3958 | } | ||
3959 | |||
3960 | return 1; | ||
3961 | } | ||
3962 | |||
3963 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) | ||
3964 | { | ||
3965 | atmel_writeAR(priv->dev, pos); | ||
3966 | atmel_write16(priv->dev, DR, data); /* card is little-endian */ | ||
3967 | atmel_write16(priv->dev, DR, data >> 16); | ||
3968 | } | ||
3969 | |||
3970 | /***************************************************************************/ | ||
3971 | /* There follows the source form of the MAC address reading firmware */ | ||
3972 | /***************************************************************************/ | ||
3973 | #if 0 | ||
3974 | |||
3975 | /* Copyright 2003 Matthew T. Russotto */ | ||
3976 | /* But derived from the Atmel 76C502 firmware written by Atmel and */ | ||
3977 | /* included in "atmel wireless lan drivers" package */ | ||
3978 | /** | ||
3979 | This file is part of net.russotto.AtmelMACFW, hereto referred to | ||
3980 | as AtmelMACFW | ||
3981 | |||
3982 | AtmelMACFW is free software; you can redistribute it and/or modify | ||
3983 | it under the terms of the GNU General Public License version 2 | ||
3984 | as published by the Free Software Foundation. | ||
3985 | |||
3986 | AtmelMACFW is distributed in the hope that it will be useful, | ||
3987 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3988 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3989 | GNU General Public License for more details. | ||
3990 | |||
3991 | You should have received a copy of the GNU General Public License | ||
3992 | along with AtmelMACFW; if not, write to the Free Software | ||
3993 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
3994 | |||
3995 | ****************************************************************************/ | ||
3996 | /* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ | ||
3997 | /* It will probably work on the 76C504 and 76C502 RFMD_3COM */ | ||
3998 | /* It only works on SPI EEPROM versions of the card. */ | ||
3999 | |||
4000 | /* This firmware initializes the SPI controller and clock, reads the MAC */ | ||
4001 | /* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ | ||
4002 | /* address in MR2, and sets MR3 to 0x10 to indicate it is done */ | ||
4003 | /* It also puts a complete copy of the EEPROM in SRAM with the offset in */ | ||
4004 | /* MR4, for investigational purposes (maybe we can determine chip type */ | ||
4005 | /* from that?) */ | ||
4006 | |||
4007 | .org 0 | ||
4008 | .set MRBASE, 0x8000000 | ||
4009 | .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ | ||
4010 | .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ | ||
4011 | .set SRAM_BASE, 0x02000000 | ||
4012 | .set SP_BASE, 0x0F300000 | ||
4013 | .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ | ||
4014 | .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ | ||
4015 | .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ | ||
4016 | .set STACK_BASE, 0x5600 | ||
4017 | .set SP_SR, 0x10 | ||
4018 | .set SP_TDRE, 2 /* status register bit -- TDR empty */ | ||
4019 | .set SP_RDRF, 1 /* status register bit -- RDR full */ | ||
4020 | .set SP_SWRST, 0x80 | ||
4021 | .set SP_SPIEN, 0x1 | ||
4022 | .set SP_CR, 0 /* control register */ | ||
4023 | .set SP_MR, 4 /* mode register */ | ||
4024 | .set SP_RDR, 0x08 /* Read Data Register */ | ||
4025 | .set SP_TDR, 0x0C /* Transmit Data Register */ | ||
4026 | .set SP_CSR0, 0x30 /* chip select registers */ | ||
4027 | .set SP_CSR1, 0x34 | ||
4028 | .set SP_CSR2, 0x38 | ||
4029 | .set SP_CSR3, 0x3C | ||
4030 | .set NVRAM_CMD_RDSR, 5 /* read status register */ | ||
4031 | .set NVRAM_CMD_READ, 3 /* read data */ | ||
4032 | .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ | ||
4033 | .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the | ||
4034 | serial output, since SO is normally high. But it | ||
4035 | does cause 8 clock cycles and thus 8 bits to be | ||
4036 | clocked in to the chip. See Atmel's SPI | ||
4037 | controller (e.g. AT91M55800) timing and 4K | ||
4038 | SPI EEPROM manuals */ | ||
4039 | |||
4040 | .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ | ||
4041 | .set NVRAM_IMAGE, 0x02000200 | ||
4042 | .set NVRAM_LENGTH, 0x0200 | ||
4043 | .set MAC_ADDRESS_MIB, SRAM_BASE | ||
4044 | .set MAC_ADDRESS_LENGTH, 6 | ||
4045 | .set MAC_BOOT_FLAG, 0x10 | ||
4046 | .set MR1, 0 | ||
4047 | .set MR2, 4 | ||
4048 | .set MR3, 8 | ||
4049 | .set MR4, 0xC | ||
4050 | RESET_VECTOR: | ||
4051 | b RESET_HANDLER | ||
4052 | UNDEF_VECTOR: | ||
4053 | b HALT1 | ||
4054 | SWI_VECTOR: | ||
4055 | b HALT1 | ||
4056 | IABORT_VECTOR: | ||
4057 | b HALT1 | ||
4058 | DABORT_VECTOR: | ||
4059 | RESERVED_VECTOR: | ||
4060 | b HALT1 | ||
4061 | IRQ_VECTOR: | ||
4062 | b HALT1 | ||
4063 | FIQ_VECTOR: | ||
4064 | b HALT1 | ||
4065 | HALT1: b HALT1 | ||
4066 | RESET_HANDLER: | ||
4067 | mov r0, #CPSR_INITIAL | ||
4068 | msr CPSR_c, r0 /* This is probably unnecessary */ | ||
4069 | |||
4070 | /* I'm guessing this is initializing clock generator electronics for SPI */ | ||
4071 | ldr r0, =SPI_CGEN_BASE | ||
4072 | mov r1, #0 | ||
4073 | mov r1, r1, lsl #3 | ||
4074 | orr r1,r1, #0 | ||
4075 | str r1, [r0] | ||
4076 | ldr r1, [r0, #28] | ||
4077 | bic r1, r1, #16 | ||
4078 | str r1, [r0, #28] | ||
4079 | mov r1, #1 | ||
4080 | str r1, [r0, #8] | ||
4081 | |||
4082 | ldr r0, =MRBASE | ||
4083 | mov r1, #0 | ||
4084 | strh r1, [r0, #MR1] | ||
4085 | strh r1, [r0, #MR2] | ||
4086 | strh r1, [r0, #MR3] | ||
4087 | strh r1, [r0, #MR4] | ||
4088 | |||
4089 | mov sp, #STACK_BASE | ||
4090 | bl SP_INIT | ||
4091 | mov r0, #10 | ||
4092 | bl DELAY9 | ||
4093 | bl GET_MAC_ADDR | ||
4094 | bl GET_WHOLE_NVRAM | ||
4095 | ldr r0, =MRBASE | ||
4096 | ldr r1, =MAC_ADDRESS_MIB | ||
4097 | strh r1, [r0, #MR2] | ||
4098 | ldr r1, =NVRAM_IMAGE | ||
4099 | strh r1, [r0, #MR4] | ||
4100 | mov r1, #MAC_BOOT_FLAG | ||
4101 | strh r1, [r0, #MR3] | ||
4102 | HALT2: b HALT2 | ||
4103 | .func Get_Whole_NVRAM, GET_WHOLE_NVRAM | ||
4104 | GET_WHOLE_NVRAM: | ||
4105 | stmdb sp!, {lr} | ||
4106 | mov r2, #0 /* 0th bytes of NVRAM */ | ||
4107 | mov r3, #NVRAM_LENGTH | ||
4108 | mov r1, #0 /* not used in routine */ | ||
4109 | ldr r0, =NVRAM_IMAGE | ||
4110 | bl NVRAM_XFER | ||
4111 | ldmia sp!, {lr} | ||
4112 | bx lr | ||
4113 | .endfunc | ||
4114 | |||
4115 | .func Get_MAC_Addr, GET_MAC_ADDR | ||
4116 | GET_MAC_ADDR: | ||
4117 | stmdb sp!, {lr} | ||
4118 | mov r2, #0x120 /* address of MAC Address within NVRAM */ | ||
4119 | mov r3, #MAC_ADDRESS_LENGTH | ||
4120 | mov r1, #0 /* not used in routine */ | ||
4121 | ldr r0, =MAC_ADDRESS_MIB | ||
4122 | bl NVRAM_XFER | ||
4123 | ldmia sp!, {lr} | ||
4124 | bx lr | ||
4125 | .endfunc | ||
4126 | .ltorg | ||
4127 | .func Delay9, DELAY9 | ||
4128 | DELAY9: | ||
4129 | adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ | ||
4130 | DELAYLOOP: | ||
4131 | beq DELAY9_done | ||
4132 | subs r0, r0, #1 | ||
4133 | b DELAYLOOP | ||
4134 | DELAY9_done: | ||
4135 | bx lr | ||
4136 | .endfunc | ||
4137 | |||
4138 | .func SP_Init, SP_INIT | ||
4139 | SP_INIT: | ||
4140 | mov r1, #SP_SWRST | ||
4141 | ldr r0, =SP_BASE | ||
4142 | str r1, [r0, #SP_CR] /* reset the SPI */ | ||
4143 | mov r1, #0 | ||
4144 | str r1, [r0, #SP_CR] /* release SPI from reset state */ | ||
4145 | mov r1, #SP_SPIEN | ||
4146 | str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ | ||
4147 | str r1, [r0, #SP_CR] /* enable the SPI */ | ||
4148 | |||
4149 | /* My guess would be this turns on the SPI clock */ | ||
4150 | ldr r3, =SPI_CGEN_BASE | ||
4151 | ldr r1, [r3, #28] | ||
4152 | orr r1, r1, #0x2000 | ||
4153 | str r1, [r3, #28] | ||
4154 | |||
4155 | ldr r1, =0x2000c01 | ||
4156 | str r1, [r0, #SP_CSR0] | ||
4157 | ldr r1, =0x2000201 | ||
4158 | str r1, [r0, #SP_CSR1] | ||
4159 | str r1, [r0, #SP_CSR2] | ||
4160 | str r1, [r0, #SP_CSR3] | ||
4161 | ldr r1, [r0, #SP_SR] | ||
4162 | ldr r0, [r0, #SP_RDR] | ||
4163 | bx lr | ||
4164 | .endfunc | ||
4165 | .func NVRAM_Init, NVRAM_INIT | ||
4166 | NVRAM_INIT: | ||
4167 | ldr r1, =SP_BASE | ||
4168 | ldr r0, [r1, #SP_RDR] | ||
4169 | mov r0, #NVRAM_CMD_RDSR | ||
4170 | str r0, [r1, #SP_TDR] | ||
4171 | SP_loop1: | ||
4172 | ldr r0, [r1, #SP_SR] | ||
4173 | tst r0, #SP_TDRE | ||
4174 | beq SP_loop1 | ||
4175 | |||
4176 | mov r0, #SPI_8CLOCKS | ||
4177 | str r0, [r1, #SP_TDR] | ||
4178 | SP_loop2: | ||
4179 | ldr r0, [r1, #SP_SR] | ||
4180 | tst r0, #SP_TDRE | ||
4181 | beq SP_loop2 | ||
4182 | |||
4183 | ldr r0, [r1, #SP_RDR] | ||
4184 | SP_loop3: | ||
4185 | ldr r0, [r1, #SP_SR] | ||
4186 | tst r0, #SP_RDRF | ||
4187 | beq SP_loop3 | ||
4188 | |||
4189 | ldr r0, [r1, #SP_RDR] | ||
4190 | and r0, r0, #255 | ||
4191 | bx lr | ||
4192 | .endfunc | ||
4193 | |||
4194 | .func NVRAM_Xfer, NVRAM_XFER | ||
4195 | /* r0 = dest address */ | ||
4196 | /* r1 = not used */ | ||
4197 | /* r2 = src address within NVRAM */ | ||
4198 | /* r3 = length */ | ||
4199 | NVRAM_XFER: | ||
4200 | stmdb sp!, {r4, r5, lr} | ||
4201 | mov r5, r0 /* save r0 (dest address) */ | ||
4202 | mov r4, r3 /* save r3 (length) */ | ||
4203 | mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ | ||
4204 | and r0, r0, #8 | ||
4205 | add r0, r0, #NVRAM_CMD_READ | ||
4206 | ldr r1, =NVRAM_SCRATCH | ||
4207 | strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ | ||
4208 | strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ | ||
4209 | _local1: | ||
4210 | bl NVRAM_INIT | ||
4211 | tst r0, #NVRAM_SR_RDY | ||
4212 | bne _local1 | ||
4213 | mov r0, #20 | ||
4214 | bl DELAY9 | ||
4215 | mov r2, r4 /* length */ | ||
4216 | mov r1, r5 /* dest address */ | ||
4217 | mov r0, #2 /* bytes to transfer in command */ | ||
4218 | bl NVRAM_XFER2 | ||
4219 | ldmia sp!, {r4, r5, lr} | ||
4220 | bx lr | ||
4221 | .endfunc | ||
4222 | |||
4223 | .func NVRAM_Xfer2, NVRAM_XFER2 | ||
4224 | NVRAM_XFER2: | ||
4225 | stmdb sp!, {r4, r5, r6, lr} | ||
4226 | ldr r4, =SP_BASE | ||
4227 | mov r3, #0 | ||
4228 | cmp r0, #0 | ||
4229 | bls _local2 | ||
4230 | ldr r5, =NVRAM_SCRATCH | ||
4231 | _local4: | ||
4232 | ldrb r6, [r5, r3] | ||
4233 | str r6, [r4, #SP_TDR] | ||
4234 | _local3: | ||
4235 | ldr r6, [r4, #SP_SR] | ||
4236 | tst r6, #SP_TDRE | ||
4237 | beq _local3 | ||
4238 | add r3, r3, #1 | ||
4239 | cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ | ||
4240 | blo _local4 | ||
4241 | _local2: | ||
4242 | mov r3, #SPI_8CLOCKS | ||
4243 | str r3, [r4, #SP_TDR] | ||
4244 | ldr r0, [r4, #SP_RDR] | ||
4245 | _local5: | ||
4246 | ldr r0, [r4, #SP_SR] | ||
4247 | tst r0, #SP_RDRF | ||
4248 | beq _local5 | ||
4249 | ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ | ||
4250 | mov r0, #0 | ||
4251 | cmp r2, #0 /* r2 is # of bytes to copy in */ | ||
4252 | bls _local6 | ||
4253 | _local7: | ||
4254 | ldr r5, [r4, #SP_SR] | ||
4255 | tst r5, #SP_TDRE | ||
4256 | beq _local7 | ||
4257 | str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ | ||
4258 | _local8: | ||
4259 | ldr r5, [r4, #SP_SR] | ||
4260 | tst r5, #SP_RDRF | ||
4261 | beq _local8 | ||
4262 | ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ | ||
4263 | strb r5, [r1], #1 /* postindexed */ | ||
4264 | add r0, r0, #1 | ||
4265 | cmp r0, r2 | ||
4266 | blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ | ||
4267 | _local6: | ||
4268 | mov r0, #200 | ||
4269 | bl DELAY9 | ||
4270 | ldmia sp!, {r4, r5, r6, lr} | ||
4271 | bx lr | ||
4272 | #endif | ||
diff --git a/drivers/net/wireless/atmel.h b/drivers/net/wireless/atmel.h new file mode 100644 index 000000000000..825000edfc2c --- /dev/null +++ b/drivers/net/wireless/atmel.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /*** -*- linux-c -*- ********************************************************** | ||
2 | |||
3 | Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | ||
4 | |||
5 | Copyright 2005 Dan Williams and Red Hat, Inc. | ||
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 software 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 Atmel wireless lan drivers; 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 _ATMEL_H | ||
24 | #define _ATMEL_H | ||
25 | |||
26 | typedef enum { | ||
27 | ATMEL_FW_TYPE_NONE = 0, | ||
28 | ATMEL_FW_TYPE_502, | ||
29 | ATMEL_FW_TYPE_502D, | ||
30 | ATMEL_FW_TYPE_502E, | ||
31 | ATMEL_FW_TYPE_502_3COM, | ||
32 | ATMEL_FW_TYPE_504, | ||
33 | ATMEL_FW_TYPE_504_2958, | ||
34 | ATMEL_FW_TYPE_504A_2958, | ||
35 | ATMEL_FW_TYPE_506 | ||
36 | } AtmelFWType; | ||
37 | |||
38 | struct net_device *init_atmel_card(unsigned short, int, const AtmelFWType, struct device *, | ||
39 | int (*present_func)(void *), void * ); | ||
40 | void stop_atmel_card( struct net_device *, int ); | ||
41 | int atmel_open( struct net_device * ); | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c new file mode 100644 index 000000000000..a91b507e0a7a --- /dev/null +++ b/drivers/net/wireless/atmel_cs.c | |||
@@ -0,0 +1,708 @@ | |||
1 | /*** -*- linux-c -*- ********************************************************** | ||
2 | |||
3 | Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | ||
4 | |||
5 | Copyright 2000-2001 ATMEL Corporation. | ||
6 | Copyright 2003 Simon Kelley. | ||
7 | |||
8 | This code was developed from version 2.1.1 of the Atmel drivers, | ||
9 | released by Atmel corp. under the GPL in December 2002. It also | ||
10 | includes code from the Linux aironet drivers (C) Benjamin Reed, | ||
11 | and the Linux PCMCIA package, (C) David Hinds. | ||
12 | |||
13 | For all queries about this code, please contact the current author, | ||
14 | Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. | ||
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 software 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 Atmel wireless lan drivers; if not, write to the Free Software | ||
28 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | |||
30 | ******************************************************************************/ | ||
31 | |||
32 | #include <linux/config.h> | ||
33 | #ifdef __IN_PCMCIA_PACKAGE__ | ||
34 | #include <pcmcia/k_compat.h> | ||
35 | #endif | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/ptrace.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/string.h> | ||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/moduleparam.h> | ||
44 | #include <linux/device.h> | ||
45 | |||
46 | #include <pcmcia/version.h> | ||
47 | #include <pcmcia/cs_types.h> | ||
48 | #include <pcmcia/cs.h> | ||
49 | #include <pcmcia/cistpl.h> | ||
50 | #include <pcmcia/cisreg.h> | ||
51 | #include <pcmcia/ds.h> | ||
52 | #include <pcmcia/ciscode.h> | ||
53 | |||
54 | #include <asm/io.h> | ||
55 | #include <asm/system.h> | ||
56 | #include <linux/wireless.h> | ||
57 | |||
58 | #include "atmel.h" | ||
59 | |||
60 | /* | ||
61 | All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If | ||
62 | you do not define PCMCIA_DEBUG at all, all the debug code will be | ||
63 | left out. If you compile with PCMCIA_DEBUG=0, the debug code will | ||
64 | be present but disabled -- but it can then be enabled for specific | ||
65 | modules at load time with a 'pc_debug=#' option to insmod. | ||
66 | */ | ||
67 | #ifdef PCMCIA_DEBUG | ||
68 | static int pc_debug = PCMCIA_DEBUG; | ||
69 | module_param(pc_debug, int, 0); | ||
70 | static char *version = "$Revision: 1.2 $"; | ||
71 | #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); | ||
72 | #else | ||
73 | #define DEBUG(n, args...) | ||
74 | #endif | ||
75 | |||
76 | /*====================================================================*/ | ||
77 | |||
78 | MODULE_AUTHOR("Simon Kelley"); | ||
79 | MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | ||
80 | MODULE_LICENSE("GPL"); | ||
81 | MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); | ||
82 | |||
83 | /*====================================================================*/ | ||
84 | |||
85 | /* | ||
86 | The event() function is this driver's Card Services event handler. | ||
87 | It will be called by Card Services when an appropriate card status | ||
88 | event is received. The config() and release() entry points are | ||
89 | used to configure or release a socket, in response to card | ||
90 | insertion and ejection events. They are invoked from the atmel_cs | ||
91 | event handler. | ||
92 | */ | ||
93 | |||
94 | static void atmel_config(dev_link_t *link); | ||
95 | static void atmel_release(dev_link_t *link); | ||
96 | static int atmel_event(event_t event, int priority, | ||
97 | event_callback_args_t *args); | ||
98 | |||
99 | /* | ||
100 | The attach() and detach() entry points are used to create and destroy | ||
101 | "instances" of the driver, where each instance represents everything | ||
102 | needed to manage one actual PCMCIA card. | ||
103 | */ | ||
104 | |||
105 | static dev_link_t *atmel_attach(void); | ||
106 | static void atmel_detach(dev_link_t *); | ||
107 | |||
108 | /* | ||
109 | You'll also need to prototype all the functions that will actually | ||
110 | be used to talk to your device. See 'pcmem_cs' for a good example | ||
111 | of a fully self-sufficient driver; the other drivers rely more or | ||
112 | less on other parts of the kernel. | ||
113 | */ | ||
114 | |||
115 | /* | ||
116 | The dev_info variable is the "key" that is used to match up this | ||
117 | device driver with appropriate cards, through the card configuration | ||
118 | database. | ||
119 | */ | ||
120 | |||
121 | static dev_info_t dev_info = "atmel_cs"; | ||
122 | |||
123 | /* | ||
124 | A linked list of "instances" of the atmelnet device. Each actual | ||
125 | PCMCIA card corresponds to one device instance, and is described | ||
126 | by one dev_link_t structure (defined in ds.h). | ||
127 | |||
128 | You may not want to use a linked list for this -- for example, the | ||
129 | memory card driver uses an array of dev_link_t pointers, where minor | ||
130 | device numbers are used to derive the corresponding array index. | ||
131 | */ | ||
132 | |||
133 | static dev_link_t *dev_list = NULL; | ||
134 | |||
135 | /* | ||
136 | A dev_link_t structure has fields for most things that are needed | ||
137 | to keep track of a socket, but there will usually be some device | ||
138 | specific information that also needs to be kept track of. The | ||
139 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
140 | a device-specific private data structure, like this. | ||
141 | |||
142 | A driver needs to provide a dev_node_t structure for each device | ||
143 | on a card. In some cases, there is only one device per card (for | ||
144 | example, ethernet cards, modems). In other cases, there may be | ||
145 | many actual or logical devices (SCSI adapters, memory cards with | ||
146 | multiple partitions). The dev_node_t structures need to be kept | ||
147 | in a linked list starting at the 'dev' field of a dev_link_t | ||
148 | structure. We allocate them in the card's private data structure, | ||
149 | because they generally shouldn't be allocated dynamically. | ||
150 | |||
151 | In this case, we also provide a flag to indicate if a device is | ||
152 | "stopped" due to a power management event, or card ejection. The | ||
153 | device IO routines can use a flag like this to throttle IO to a | ||
154 | card that is not ready to accept it. | ||
155 | */ | ||
156 | |||
157 | typedef struct local_info_t { | ||
158 | dev_node_t node; | ||
159 | struct net_device *eth_dev; | ||
160 | } local_info_t; | ||
161 | |||
162 | /*====================================================================== | ||
163 | |||
164 | atmel_attach() creates an "instance" of the driver, allocating | ||
165 | local data structures for one device. The device is registered | ||
166 | with Card Services. | ||
167 | |||
168 | The dev_link structure is initialized, but we don't actually | ||
169 | configure the card at this point -- we wait until we receive a | ||
170 | card insertion event. | ||
171 | |||
172 | ======================================================================*/ | ||
173 | |||
174 | static dev_link_t *atmel_attach(void) | ||
175 | { | ||
176 | client_reg_t client_reg; | ||
177 | dev_link_t *link; | ||
178 | local_info_t *local; | ||
179 | int ret; | ||
180 | |||
181 | DEBUG(0, "atmel_attach()\n"); | ||
182 | |||
183 | /* Initialize the dev_link_t structure */ | ||
184 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
185 | if (!link) { | ||
186 | printk(KERN_ERR "atmel_cs: no memory for new device\n"); | ||
187 | return NULL; | ||
188 | } | ||
189 | memset(link, 0, sizeof(struct dev_link_t)); | ||
190 | |||
191 | /* Interrupt setup */ | ||
192 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; | ||
193 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
194 | link->irq.Handler = NULL; | ||
195 | |||
196 | /* | ||
197 | General socket configuration defaults can go here. In this | ||
198 | client, we assume very little, and rely on the CIS for almost | ||
199 | everything. In most clients, many details (i.e., number, sizes, | ||
200 | and attributes of IO windows) are fixed by the nature of the | ||
201 | device, and can be hard-wired here. | ||
202 | */ | ||
203 | link->conf.Attributes = 0; | ||
204 | link->conf.Vcc = 50; | ||
205 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
206 | |||
207 | /* Allocate space for private device-specific data */ | ||
208 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | ||
209 | if (!local) { | ||
210 | printk(KERN_ERR "atmel_cs: no memory for new device\n"); | ||
211 | kfree (link); | ||
212 | return NULL; | ||
213 | } | ||
214 | memset(local, 0, sizeof(local_info_t)); | ||
215 | link->priv = local; | ||
216 | |||
217 | /* Register with Card Services */ | ||
218 | link->next = dev_list; | ||
219 | dev_list = link; | ||
220 | client_reg.dev_info = &dev_info; | ||
221 | client_reg.EventMask = | ||
222 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
223 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
224 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
225 | client_reg.event_handler = &atmel_event; | ||
226 | client_reg.Version = 0x0210; | ||
227 | client_reg.event_callback_args.client_data = link; | ||
228 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
229 | if (ret != 0) { | ||
230 | cs_error(link->handle, RegisterClient, ret); | ||
231 | atmel_detach(link); | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | return link; | ||
236 | } /* atmel_attach */ | ||
237 | |||
238 | /*====================================================================== | ||
239 | |||
240 | This deletes a driver "instance". The device is de-registered | ||
241 | with Card Services. If it has been released, all local data | ||
242 | structures are freed. Otherwise, the structures will be freed | ||
243 | when the device is released. | ||
244 | |||
245 | ======================================================================*/ | ||
246 | |||
247 | static void atmel_detach(dev_link_t *link) | ||
248 | { | ||
249 | dev_link_t **linkp; | ||
250 | |||
251 | DEBUG(0, "atmel_detach(0x%p)\n", link); | ||
252 | |||
253 | /* Locate device structure */ | ||
254 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
255 | if (*linkp == link) break; | ||
256 | if (*linkp == NULL) | ||
257 | return; | ||
258 | |||
259 | if (link->state & DEV_CONFIG) | ||
260 | atmel_release(link); | ||
261 | |||
262 | /* Break the link with Card Services */ | ||
263 | if (link->handle) | ||
264 | pcmcia_deregister_client(link->handle); | ||
265 | |||
266 | /* Unlink device structure, free pieces */ | ||
267 | *linkp = link->next; | ||
268 | if (link->priv) | ||
269 | kfree(link->priv); | ||
270 | kfree(link); | ||
271 | } | ||
272 | |||
273 | /*====================================================================== | ||
274 | |||
275 | atmel_config() is scheduled to run after a CARD_INSERTION event | ||
276 | is received, to configure the PCMCIA socket, and to make the | ||
277 | device available to the system. | ||
278 | |||
279 | ======================================================================*/ | ||
280 | |||
281 | #define CS_CHECK(fn, ret) \ | ||
282 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
283 | |||
284 | /* Call-back function to interrogate PCMCIA-specific information | ||
285 | about the current existance of the card */ | ||
286 | static int card_present(void *arg) | ||
287 | { | ||
288 | dev_link_t *link = (dev_link_t *)arg; | ||
289 | if (link->state & DEV_SUSPEND) | ||
290 | return 0; | ||
291 | else if (link->state & DEV_PRESENT) | ||
292 | return 1; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | /* list of cards we know about and their firmware requirements. | ||
298 | Go either by Manfid or version strings. | ||
299 | Cards not in this list will need a firmware parameter to the module | ||
300 | in all probability. Note that the SMC 2632 V2 and V3 have the same | ||
301 | manfids, so we ignore those and use the version1 strings. */ | ||
302 | |||
303 | static struct { | ||
304 | int manf, card; | ||
305 | char *ver1; | ||
306 | AtmelFWType firmware; | ||
307 | char *name; | ||
308 | } card_table[] = { | ||
309 | { 0, 0, "WLAN/802.11b PC CARD", ATMEL_FW_TYPE_502D, "Actiontec 802CAT1" }, | ||
310 | { 0, 0, "ATMEL/AT76C502AR", ATMEL_FW_TYPE_502, "NoName-RFMD" }, | ||
311 | { 0, 0, "ATMEL/AT76C502AR_D", ATMEL_FW_TYPE_502D, "NoName-revD" }, | ||
312 | { 0, 0, "ATMEL/AT76C502AR_E", ATMEL_FW_TYPE_502E, "NoName-revE" }, | ||
313 | { 0, 0, "ATMEL/AT76C504", ATMEL_FW_TYPE_504, "NoName-504" }, | ||
314 | { 0, 0, "ATMEL/AT76C504A", ATMEL_FW_TYPE_504A_2958, "NoName-504a-2958" }, | ||
315 | { 0, 0, "ATMEL/AT76C504_R", ATMEL_FW_TYPE_504_2958, "NoName-504-2958" }, | ||
316 | { MANFID_3COM, 0x0620, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRWE62092B" }, | ||
317 | { MANFID_3COM, 0x0696, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRSHPW196" }, | ||
318 | { 0, 0, "SMC/2632W-V2", ATMEL_FW_TYPE_502, "SMC 2632W-V2" }, | ||
319 | { 0, 0, "SMC/2632W", ATMEL_FW_TYPE_502D, "SMC 2632W-V3" }, | ||
320 | { 0xd601, 0x0007, NULL, ATMEL_FW_TYPE_502, "Sitecom WLAN-011" }, | ||
321 | { 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" }, | ||
322 | { 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" }, | ||
323 | { 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" }, | ||
324 | { 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" }, | ||
325 | { 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" }, | ||
326 | { 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" }, | ||
327 | { 0, 0, "11WAVE/11WP611AL-E", ATMEL_FW_TYPE_502E, "11WAVE WaveBuddy" }, | ||
328 | { 0, 0, "LG/LW2100N", ATMEL_FW_TYPE_502E, "LG LW2100N 11Mbps WLAN PCMCIA Card" }, | ||
329 | }; | ||
330 | |||
331 | static void atmel_config(dev_link_t *link) | ||
332 | { | ||
333 | client_handle_t handle; | ||
334 | tuple_t tuple; | ||
335 | cisparse_t parse; | ||
336 | local_info_t *dev; | ||
337 | int last_fn, last_ret; | ||
338 | u_char buf[64]; | ||
339 | int card_index = -1, done = 0; | ||
340 | |||
341 | handle = link->handle; | ||
342 | dev = link->priv; | ||
343 | |||
344 | DEBUG(0, "atmel_config(0x%p)\n", link); | ||
345 | |||
346 | tuple.Attributes = 0; | ||
347 | tuple.TupleData = buf; | ||
348 | tuple.TupleDataMax = sizeof(buf); | ||
349 | tuple.TupleOffset = 0; | ||
350 | |||
351 | tuple.DesiredTuple = CISTPL_MANFID; | ||
352 | if (pcmcia_get_first_tuple(handle, &tuple) == 0) { | ||
353 | int i; | ||
354 | cistpl_manfid_t *manfid; | ||
355 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
356 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
357 | manfid = &(parse.manfid); | ||
358 | for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { | ||
359 | if (!card_table[i].ver1 && | ||
360 | manfid->manf == card_table[i].manf && | ||
361 | manfid->card == card_table[i].card) { | ||
362 | card_index = i; | ||
363 | done = 1; | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | tuple.DesiredTuple = CISTPL_VERS_1; | ||
369 | if (!done && (pcmcia_get_first_tuple(handle, &tuple) == 0)) { | ||
370 | int i, j, k; | ||
371 | cistpl_vers_1_t *ver1; | ||
372 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
373 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
374 | ver1 = &(parse.version_1); | ||
375 | |||
376 | for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { | ||
377 | for (j = 0; j < ver1->ns; j++) { | ||
378 | char *p = card_table[i].ver1; | ||
379 | char *q = &ver1->str[ver1->ofs[j]]; | ||
380 | if (!p) | ||
381 | goto mismatch; | ||
382 | for (k = 0; k < j; k++) { | ||
383 | while ((*p != '\0') && (*p != '/')) p++; | ||
384 | if (*p == '\0') { | ||
385 | if (*q != '\0') | ||
386 | goto mismatch; | ||
387 | } else { | ||
388 | p++; | ||
389 | } | ||
390 | } | ||
391 | while((*q != '\0') && (*p != '\0') && | ||
392 | (*p != '/') && (*p == *q)) p++, q++; | ||
393 | if (((*p != '\0') && *p != '/') || *q != '\0') | ||
394 | goto mismatch; | ||
395 | } | ||
396 | card_index = i; | ||
397 | break; /* done */ | ||
398 | |||
399 | mismatch: | ||
400 | j = 0; /* dummy stmt to shut up compiler */ | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | This reads the card's CONFIG tuple to find its configuration | ||
406 | registers. | ||
407 | */ | ||
408 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
409 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
410 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
411 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
412 | link->conf.ConfigBase = parse.config.base; | ||
413 | link->conf.Present = parse.config.rmask[0]; | ||
414 | |||
415 | /* Configure card */ | ||
416 | link->state |= DEV_CONFIG; | ||
417 | |||
418 | /* | ||
419 | In this loop, we scan the CIS for configuration table entries, | ||
420 | each of which describes a valid card configuration, including | ||
421 | voltage, IO window, memory window, and interrupt settings. | ||
422 | |||
423 | We make no assumptions about the card to be configured: we use | ||
424 | just the information available in the CIS. In an ideal world, | ||
425 | this would work for any PCMCIA card, but it requires a complete | ||
426 | and accurate CIS. In practice, a driver usually "knows" most of | ||
427 | these things without consulting the CIS, and most client drivers | ||
428 | will only use the CIS to fill in implementation-defined details. | ||
429 | */ | ||
430 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
431 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
432 | while (1) { | ||
433 | cistpl_cftable_entry_t dflt = { 0 }; | ||
434 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
435 | if (pcmcia_get_tuple_data(handle, &tuple) != 0 || | ||
436 | pcmcia_parse_tuple(handle, &tuple, &parse) != 0) | ||
437 | goto next_entry; | ||
438 | |||
439 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; | ||
440 | if (cfg->index == 0) goto next_entry; | ||
441 | link->conf.ConfigIndex = cfg->index; | ||
442 | |||
443 | /* Does this card need audio output? */ | ||
444 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
445 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
446 | link->conf.Status = CCSR_AUDIO_ENA; | ||
447 | } | ||
448 | |||
449 | /* Use power settings for Vcc and Vpp if present */ | ||
450 | /* Note that the CIS values need to be rescaled */ | ||
451 | if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) | ||
452 | link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; | ||
453 | else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) | ||
454 | link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; | ||
455 | |||
456 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
457 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
458 | cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
459 | else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
460 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
461 | dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
462 | |||
463 | /* Do we need to allocate an interrupt? */ | ||
464 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
465 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
466 | |||
467 | /* IO window settings */ | ||
468 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
469 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
470 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
471 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
472 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
473 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
474 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
475 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
476 | link->io.BasePort1 = io->win[0].base; | ||
477 | link->io.NumPorts1 = io->win[0].len; | ||
478 | if (io->nwin > 1) { | ||
479 | link->io.Attributes2 = link->io.Attributes1; | ||
480 | link->io.BasePort2 = io->win[1].base; | ||
481 | link->io.NumPorts2 = io->win[1].len; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | /* This reserves IO space but doesn't actually enable it */ | ||
486 | if (pcmcia_request_io(link->handle, &link->io) != 0) | ||
487 | goto next_entry; | ||
488 | |||
489 | /* If we got this far, we're cool! */ | ||
490 | break; | ||
491 | |||
492 | next_entry: | ||
493 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | Allocate an interrupt line. Note that this does not assign a | ||
498 | handler to the interrupt, unless the 'Handler' member of the | ||
499 | irq structure is initialized. | ||
500 | */ | ||
501 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
502 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
503 | |||
504 | /* | ||
505 | This actually configures the PCMCIA socket -- setting up | ||
506 | the I/O windows and the interrupt mapping, and putting the | ||
507 | card and host interface into "Memory and IO" mode. | ||
508 | */ | ||
509 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
510 | |||
511 | if (link->irq.AssignedIRQ == 0) { | ||
512 | printk(KERN_ALERT | ||
513 | "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); | ||
514 | goto cs_failed; | ||
515 | } | ||
516 | |||
517 | ((local_info_t*)link->priv)->eth_dev = | ||
518 | init_atmel_card(link->irq.AssignedIRQ, | ||
519 | link->io.BasePort1, | ||
520 | card_index == -1 ? ATMEL_FW_TYPE_NONE : card_table[card_index].firmware, | ||
521 | &handle_to_dev(handle), | ||
522 | card_present, | ||
523 | link); | ||
524 | if (!((local_info_t*)link->priv)->eth_dev) | ||
525 | goto cs_failed; | ||
526 | |||
527 | /* | ||
528 | At this point, the dev_node_t structure(s) need to be | ||
529 | initialized and arranged in a linked list at link->dev. | ||
530 | */ | ||
531 | strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); | ||
532 | dev->node.major = dev->node.minor = 0; | ||
533 | link->dev = &dev->node; | ||
534 | |||
535 | /* Finally, report what we've done */ | ||
536 | printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d", | ||
537 | dev->node.dev_name, | ||
538 | card_index == -1 ? "" : card_table[card_index].name, | ||
539 | card_index == -1 ? "" : " ", | ||
540 | link->conf.ConfigIndex, | ||
541 | link->conf.Vcc/10, link->conf.Vcc%10); | ||
542 | if (link->conf.Vpp1) | ||
543 | printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); | ||
544 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
545 | printk(", irq %d", link->irq.AssignedIRQ); | ||
546 | if (link->io.NumPorts1) | ||
547 | printk(", io 0x%04x-0x%04x", link->io.BasePort1, | ||
548 | link->io.BasePort1+link->io.NumPorts1-1); | ||
549 | if (link->io.NumPorts2) | ||
550 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | ||
551 | link->io.BasePort2+link->io.NumPorts2-1); | ||
552 | printk("\n"); | ||
553 | |||
554 | link->state &= ~DEV_CONFIG_PENDING; | ||
555 | return; | ||
556 | |||
557 | cs_failed: | ||
558 | cs_error(link->handle, last_fn, last_ret); | ||
559 | atmel_release(link); | ||
560 | } | ||
561 | |||
562 | /*====================================================================== | ||
563 | |||
564 | After a card is removed, atmel_release() will unregister the | ||
565 | device, and release the PCMCIA configuration. If the device is | ||
566 | still open, this will be postponed until it is closed. | ||
567 | |||
568 | ======================================================================*/ | ||
569 | |||
570 | static void atmel_release(dev_link_t *link) | ||
571 | { | ||
572 | struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; | ||
573 | |||
574 | DEBUG(0, "atmel_release(0x%p)\n", link); | ||
575 | |||
576 | /* Unlink the device chain */ | ||
577 | link->dev = NULL; | ||
578 | |||
579 | if (dev) | ||
580 | stop_atmel_card(dev, 0); | ||
581 | ((local_info_t*)link->priv)->eth_dev = NULL; | ||
582 | |||
583 | /* Don't bother checking to see if these succeed or not */ | ||
584 | pcmcia_release_configuration(link->handle); | ||
585 | if (link->io.NumPorts1) | ||
586 | pcmcia_release_io(link->handle, &link->io); | ||
587 | if (link->irq.AssignedIRQ) | ||
588 | pcmcia_release_irq(link->handle, &link->irq); | ||
589 | link->state &= ~DEV_CONFIG; | ||
590 | } | ||
591 | |||
592 | /*====================================================================== | ||
593 | |||
594 | The card status event handler. Mostly, this schedules other | ||
595 | stuff to run after an event is received. | ||
596 | |||
597 | When a CARD_REMOVAL event is received, we immediately set a | ||
598 | private flag to block future accesses to this device. All the | ||
599 | functions that actually access the device should check this flag | ||
600 | to make sure the card is still present. | ||
601 | |||
602 | ======================================================================*/ | ||
603 | |||
604 | static int atmel_event(event_t event, int priority, | ||
605 | event_callback_args_t *args) | ||
606 | { | ||
607 | dev_link_t *link = args->client_data; | ||
608 | local_info_t *local = link->priv; | ||
609 | |||
610 | DEBUG(1, "atmel_event(0x%06x)\n", event); | ||
611 | |||
612 | switch (event) { | ||
613 | case CS_EVENT_CARD_REMOVAL: | ||
614 | link->state &= ~DEV_PRESENT; | ||
615 | if (link->state & DEV_CONFIG) { | ||
616 | netif_device_detach(local->eth_dev); | ||
617 | atmel_release(link); | ||
618 | } | ||
619 | break; | ||
620 | case CS_EVENT_CARD_INSERTION: | ||
621 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
622 | atmel_config(link); | ||
623 | break; | ||
624 | case CS_EVENT_PM_SUSPEND: | ||
625 | link->state |= DEV_SUSPEND; | ||
626 | /* Fall through... */ | ||
627 | case CS_EVENT_RESET_PHYSICAL: | ||
628 | if (link->state & DEV_CONFIG) { | ||
629 | netif_device_detach(local->eth_dev); | ||
630 | pcmcia_release_configuration(link->handle); | ||
631 | } | ||
632 | break; | ||
633 | case CS_EVENT_PM_RESUME: | ||
634 | link->state &= ~DEV_SUSPEND; | ||
635 | /* Fall through... */ | ||
636 | case CS_EVENT_CARD_RESET: | ||
637 | if (link->state & DEV_CONFIG) { | ||
638 | pcmcia_request_configuration(link->handle, &link->conf); | ||
639 | atmel_open(local->eth_dev); | ||
640 | netif_device_attach(local->eth_dev); | ||
641 | } | ||
642 | break; | ||
643 | } | ||
644 | return 0; | ||
645 | } /* atmel_event */ | ||
646 | |||
647 | /*====================================================================*/ | ||
648 | static struct pcmcia_driver atmel_driver = { | ||
649 | .owner = THIS_MODULE, | ||
650 | .drv = { | ||
651 | .name = "atmel_cs", | ||
652 | }, | ||
653 | .attach = atmel_attach, | ||
654 | .detach = atmel_detach, | ||
655 | }; | ||
656 | |||
657 | static int atmel_cs_init(void) | ||
658 | { | ||
659 | return pcmcia_register_driver(&atmel_driver); | ||
660 | } | ||
661 | |||
662 | static void atmel_cs_cleanup(void) | ||
663 | { | ||
664 | pcmcia_unregister_driver(&atmel_driver); | ||
665 | BUG_ON(dev_list != NULL); | ||
666 | } | ||
667 | |||
668 | /* | ||
669 | This program is free software; you can redistribute it and/or | ||
670 | modify it under the terms of the GNU General Public License | ||
671 | as published by the Free Software Foundation; either version 2 | ||
672 | of the License, or (at your option) any later version. | ||
673 | |||
674 | This program is distributed in the hope that it will be useful, | ||
675 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
676 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
677 | GNU General Public License for more details. | ||
678 | |||
679 | In addition: | ||
680 | |||
681 | Redistribution and use in source and binary forms, with or without | ||
682 | modification, are permitted provided that the following conditions | ||
683 | are met: | ||
684 | |||
685 | 1. Redistributions of source code must retain the above copyright | ||
686 | notice, this list of conditions and the following disclaimer. | ||
687 | 2. Redistributions in binary form must reproduce the above copyright | ||
688 | notice, this list of conditions and the following disclaimer in the | ||
689 | documentation and/or other materials provided with the distribution. | ||
690 | 3. The name of the author may not be used to endorse or promote | ||
691 | products derived from this software without specific prior written | ||
692 | permission. | ||
693 | |||
694 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
695 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
696 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
697 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | ||
698 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
699 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
700 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
701 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
702 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
703 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
704 | POSSIBILITY OF SUCH DAMAGE. | ||
705 | */ | ||
706 | |||
707 | module_init(atmel_cs_init); | ||
708 | module_exit(atmel_cs_cleanup); | ||
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c new file mode 100644 index 000000000000..2eb00a957bbe --- /dev/null +++ b/drivers/net/wireless/atmel_pci.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /*** -*- linux-c -*- ********************************************************** | ||
2 | |||
3 | Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | ||
4 | |||
5 | Copyright 2004 Simon Kelley. | ||
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 software 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 Atmel wireless lan drivers; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | |||
21 | ******************************************************************************/ | ||
22 | #include <linux/config.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include "atmel.h" | ||
29 | |||
30 | MODULE_AUTHOR("Simon Kelley"); | ||
31 | MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | MODULE_SUPPORTED_DEVICE("Atmel at76c506 PCI wireless cards"); | ||
34 | |||
35 | static struct pci_device_id card_ids[] = { | ||
36 | { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID }, | ||
37 | { 0, } | ||
38 | }; | ||
39 | |||
40 | MODULE_DEVICE_TABLE(pci, card_ids); | ||
41 | |||
42 | static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *); | ||
43 | static void atmel_pci_remove(struct pci_dev *); | ||
44 | |||
45 | static struct pci_driver atmel_driver = { | ||
46 | .name = "atmel", | ||
47 | .id_table = card_ids, | ||
48 | .probe = atmel_pci_probe, | ||
49 | .remove = __devexit_p(atmel_pci_remove), | ||
50 | }; | ||
51 | |||
52 | |||
53 | static int __devinit atmel_pci_probe(struct pci_dev *pdev, | ||
54 | const struct pci_device_id *pent) | ||
55 | { | ||
56 | struct net_device *dev; | ||
57 | |||
58 | if (pci_enable_device(pdev)) | ||
59 | return -ENODEV; | ||
60 | |||
61 | pci_set_master(pdev); | ||
62 | |||
63 | dev = init_atmel_card(pdev->irq, pdev->resource[1].start, | ||
64 | ATMEL_FW_TYPE_506, | ||
65 | &pdev->dev, NULL, NULL); | ||
66 | if (!dev) | ||
67 | return -ENODEV; | ||
68 | |||
69 | pci_set_drvdata(pdev, dev); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void __devexit atmel_pci_remove(struct pci_dev *pdev) | ||
74 | { | ||
75 | stop_atmel_card(pci_get_drvdata(pdev), 1); | ||
76 | } | ||
77 | |||
78 | static int __init atmel_init_module(void) | ||
79 | { | ||
80 | return pci_module_init(&atmel_driver); | ||
81 | } | ||
82 | |||
83 | static void __exit atmel_cleanup_module(void) | ||
84 | { | ||
85 | pci_unregister_driver(&atmel_driver); | ||
86 | } | ||
87 | |||
88 | module_init(atmel_init_module); | ||
89 | module_exit(atmel_cleanup_module); | ||
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c new file mode 100644 index 000000000000..21c3d0d227e6 --- /dev/null +++ b/drivers/net/wireless/hermes.c | |||
@@ -0,0 +1,554 @@ | |||
1 | /* hermes.c | ||
2 | * | ||
3 | * Driver core for the "Hermes" wireless MAC controller, as used in | ||
4 | * the Lucent Orinoco and Cabletron RoamAbout cards. It should also | ||
5 | * work on the hfa3841 and hfa3842 MAC controller chips used in the | ||
6 | * Prism II chipsets. | ||
7 | * | ||
8 | * This is not a complete driver, just low-level access routines for | ||
9 | * the MAC controller itself. | ||
10 | * | ||
11 | * Based on the prism2 driver from Absolute Value Systems' linux-wlan | ||
12 | * project, the Linux wvlan_cs driver, Lucent's HCF-Light | ||
13 | * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no | ||
14 | * particular order). | ||
15 | * | ||
16 | * Copyright (C) 2000, David Gibson, Linuxcare Australia. | ||
17 | * (C) Copyright David Gibson, IBM Corp. 2001-2003. | ||
18 | * | ||
19 | * The contents of this file are subject to the Mozilla Public License | ||
20 | * Version 1.1 (the "License"); you may not use this file except in | ||
21 | * compliance with the License. You may obtain a copy of the License | ||
22 | * at http://www.mozilla.org/MPL/ | ||
23 | * | ||
24 | * Software distributed under the License is distributed on an "AS IS" | ||
25 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
26 | * the License for the specific language governing rights and | ||
27 | * limitations under the License. | ||
28 | * | ||
29 | * Alternatively, the contents of this file may be used under the | ||
30 | * terms of the GNU General Public License version 2 (the "GPL"), in | ||
31 | * which case the provisions of the GPL are applicable instead of the | ||
32 | * above. If you wish to allow the use of your version of this file | ||
33 | * only under the terms of the GPL and not to allow others to use your | ||
34 | * version of this file under the MPL, indicate your decision by | ||
35 | * deleting the provisions above and replace them with the notice and | ||
36 | * other provisions required by the GPL. If you do not delete the | ||
37 | * provisions above, a recipient may use your version of this file | ||
38 | * under either the MPL or the GPL. | ||
39 | */ | ||
40 | |||
41 | #include <linux/config.h> | ||
42 | |||
43 | #include <linux/module.h> | ||
44 | #include <linux/types.h> | ||
45 | #include <linux/threads.h> | ||
46 | #include <linux/smp.h> | ||
47 | #include <asm/io.h> | ||
48 | #include <linux/delay.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/kernel.h> | ||
51 | #include <linux/net.h> | ||
52 | #include <asm/errno.h> | ||
53 | |||
54 | #include "hermes.h" | ||
55 | |||
56 | MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); | ||
57 | MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>" | ||
58 | " & David Gibson <hermes@gibson.dropbear.id.au>"); | ||
59 | MODULE_LICENSE("Dual MPL/GPL"); | ||
60 | |||
61 | /* These are maximum timeouts. Most often, card wil react much faster */ | ||
62 | #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ | ||
63 | #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ | ||
64 | #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ | ||
65 | #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ | ||
66 | |||
67 | /* | ||
68 | * Debugging helpers | ||
69 | */ | ||
70 | |||
71 | #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ | ||
72 | printk(stuff);} while (0) | ||
73 | |||
74 | #undef HERMES_DEBUG | ||
75 | #ifdef HERMES_DEBUG | ||
76 | #include <stdarg.h> | ||
77 | |||
78 | #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff) | ||
79 | |||
80 | #else /* ! HERMES_DEBUG */ | ||
81 | |||
82 | #define DEBUG(lvl, stuff...) do { } while (0) | ||
83 | |||
84 | #endif /* ! HERMES_DEBUG */ | ||
85 | |||
86 | |||
87 | /* | ||
88 | * Internal functions | ||
89 | */ | ||
90 | |||
91 | /* Issue a command to the chip. Waiting for it to complete is the caller's | ||
92 | problem. | ||
93 | |||
94 | Returns -EBUSY if the command register is busy, 0 on success. | ||
95 | |||
96 | Callable from any context. | ||
97 | */ | ||
98 | static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) | ||
99 | { | ||
100 | int k = CMD_BUSY_TIMEOUT; | ||
101 | u16 reg; | ||
102 | |||
103 | /* First wait for the command register to unbusy */ | ||
104 | reg = hermes_read_regn(hw, CMD); | ||
105 | while ( (reg & HERMES_CMD_BUSY) && k ) { | ||
106 | k--; | ||
107 | udelay(1); | ||
108 | reg = hermes_read_regn(hw, CMD); | ||
109 | } | ||
110 | if (reg & HERMES_CMD_BUSY) { | ||
111 | return -EBUSY; | ||
112 | } | ||
113 | |||
114 | hermes_write_regn(hw, PARAM2, 0); | ||
115 | hermes_write_regn(hw, PARAM1, 0); | ||
116 | hermes_write_regn(hw, PARAM0, param0); | ||
117 | hermes_write_regn(hw, CMD, cmd); | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Function definitions | ||
124 | */ | ||
125 | |||
126 | void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) | ||
127 | { | ||
128 | hw->iobase = address; | ||
129 | hw->reg_spacing = reg_spacing; | ||
130 | hw->inten = 0x0; | ||
131 | |||
132 | #ifdef HERMES_DEBUG_BUFFER | ||
133 | hw->dbufp = 0; | ||
134 | memset(&hw->dbuf, 0xff, sizeof(hw->dbuf)); | ||
135 | memset(&hw->profile, 0, sizeof(hw->profile)); | ||
136 | #endif | ||
137 | } | ||
138 | |||
139 | int hermes_init(hermes_t *hw) | ||
140 | { | ||
141 | u16 status, reg; | ||
142 | int err = 0; | ||
143 | int k; | ||
144 | |||
145 | /* We don't want to be interrupted while resetting the chipset */ | ||
146 | hw->inten = 0x0; | ||
147 | hermes_write_regn(hw, INTEN, 0); | ||
148 | hermes_write_regn(hw, EVACK, 0xffff); | ||
149 | |||
150 | /* Normally it's a "can't happen" for the command register to | ||
151 | be busy when we go to issue a command because we are | ||
152 | serializing all commands. However we want to have some | ||
153 | chance of resetting the card even if it gets into a stupid | ||
154 | state, so we actually wait to see if the command register | ||
155 | will unbusy itself here. */ | ||
156 | k = CMD_BUSY_TIMEOUT; | ||
157 | reg = hermes_read_regn(hw, CMD); | ||
158 | while (k && (reg & HERMES_CMD_BUSY)) { | ||
159 | if (reg == 0xffff) /* Special case - the card has probably been removed, | ||
160 | so don't wait for the timeout */ | ||
161 | return -ENODEV; | ||
162 | |||
163 | k--; | ||
164 | udelay(1); | ||
165 | reg = hermes_read_regn(hw, CMD); | ||
166 | } | ||
167 | |||
168 | /* No need to explicitly handle the timeout - if we've timed | ||
169 | out hermes_issue_cmd() will probably return -EBUSY below */ | ||
170 | |||
171 | /* According to the documentation, EVSTAT may contain | ||
172 | obsolete event occurrence information. We have to acknowledge | ||
173 | it by writing EVACK. */ | ||
174 | reg = hermes_read_regn(hw, EVSTAT); | ||
175 | hermes_write_regn(hw, EVACK, reg); | ||
176 | |||
177 | /* We don't use hermes_docmd_wait here, because the reset wipes | ||
178 | the magic constant in SWSUPPORT0 away, and it gets confused */ | ||
179 | err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); | ||
180 | if (err) | ||
181 | return err; | ||
182 | |||
183 | reg = hermes_read_regn(hw, EVSTAT); | ||
184 | k = CMD_INIT_TIMEOUT; | ||
185 | while ( (! (reg & HERMES_EV_CMD)) && k) { | ||
186 | k--; | ||
187 | udelay(10); | ||
188 | reg = hermes_read_regn(hw, EVSTAT); | ||
189 | } | ||
190 | |||
191 | hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); | ||
192 | |||
193 | if (! hermes_present(hw)) { | ||
194 | DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", | ||
195 | hw->iobase); | ||
196 | err = -ENODEV; | ||
197 | goto out; | ||
198 | } | ||
199 | |||
200 | if (! (reg & HERMES_EV_CMD)) { | ||
201 | printk(KERN_ERR "hermes @ %p: " | ||
202 | "Timeout waiting for card to reset (reg=0x%04x)!\n", | ||
203 | hw->iobase, reg); | ||
204 | err = -ETIMEDOUT; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | status = hermes_read_regn(hw, STATUS); | ||
209 | |||
210 | hermes_write_regn(hw, EVACK, HERMES_EV_CMD); | ||
211 | |||
212 | if (status & HERMES_STATUS_RESULT) | ||
213 | err = -EIO; | ||
214 | |||
215 | out: | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | /* Issue a command to the chip, and (busy!) wait for it to | ||
220 | * complete. | ||
221 | * | ||
222 | * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware | ||
223 | * | ||
224 | * Callable from any context, but locking is your problem. */ | ||
225 | int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, | ||
226 | struct hermes_response *resp) | ||
227 | { | ||
228 | int err; | ||
229 | int k; | ||
230 | u16 reg; | ||
231 | u16 status; | ||
232 | |||
233 | err = hermes_issue_cmd(hw, cmd, parm0); | ||
234 | if (err) { | ||
235 | if (! hermes_present(hw)) { | ||
236 | if (net_ratelimit()) | ||
237 | printk(KERN_WARNING "hermes @ %p: " | ||
238 | "Card removed while issuing command " | ||
239 | "0x%04x.\n", hw->iobase, cmd); | ||
240 | err = -ENODEV; | ||
241 | } else | ||
242 | if (net_ratelimit()) | ||
243 | printk(KERN_ERR "hermes @ %p: " | ||
244 | "Error %d issuing command 0x%04x.\n", | ||
245 | hw->iobase, err, cmd); | ||
246 | goto out; | ||
247 | } | ||
248 | |||
249 | reg = hermes_read_regn(hw, EVSTAT); | ||
250 | k = CMD_COMPL_TIMEOUT; | ||
251 | while ( (! (reg & HERMES_EV_CMD)) && k) { | ||
252 | k--; | ||
253 | udelay(10); | ||
254 | reg = hermes_read_regn(hw, EVSTAT); | ||
255 | } | ||
256 | |||
257 | if (! hermes_present(hw)) { | ||
258 | printk(KERN_WARNING "hermes @ %p: Card removed " | ||
259 | "while waiting for command 0x%04x completion.\n", | ||
260 | hw->iobase, cmd); | ||
261 | err = -ENODEV; | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | if (! (reg & HERMES_EV_CMD)) { | ||
266 | printk(KERN_ERR "hermes @ %p: Timeout waiting for " | ||
267 | "command 0x%04x completion.\n", hw->iobase, cmd); | ||
268 | err = -ETIMEDOUT; | ||
269 | goto out; | ||
270 | } | ||
271 | |||
272 | status = hermes_read_regn(hw, STATUS); | ||
273 | if (resp) { | ||
274 | resp->status = status; | ||
275 | resp->resp0 = hermes_read_regn(hw, RESP0); | ||
276 | resp->resp1 = hermes_read_regn(hw, RESP1); | ||
277 | resp->resp2 = hermes_read_regn(hw, RESP2); | ||
278 | } | ||
279 | |||
280 | hermes_write_regn(hw, EVACK, HERMES_EV_CMD); | ||
281 | |||
282 | if (status & HERMES_STATUS_RESULT) | ||
283 | err = -EIO; | ||
284 | |||
285 | out: | ||
286 | return err; | ||
287 | } | ||
288 | |||
289 | int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) | ||
290 | { | ||
291 | int err = 0; | ||
292 | int k; | ||
293 | u16 reg; | ||
294 | |||
295 | if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) | ||
296 | return -EINVAL; | ||
297 | |||
298 | err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); | ||
299 | if (err) { | ||
300 | return err; | ||
301 | } | ||
302 | |||
303 | reg = hermes_read_regn(hw, EVSTAT); | ||
304 | k = ALLOC_COMPL_TIMEOUT; | ||
305 | while ( (! (reg & HERMES_EV_ALLOC)) && k) { | ||
306 | k--; | ||
307 | udelay(10); | ||
308 | reg = hermes_read_regn(hw, EVSTAT); | ||
309 | } | ||
310 | |||
311 | if (! hermes_present(hw)) { | ||
312 | printk(KERN_WARNING "hermes @ %p: " | ||
313 | "Card removed waiting for frame allocation.\n", | ||
314 | hw->iobase); | ||
315 | return -ENODEV; | ||
316 | } | ||
317 | |||
318 | if (! (reg & HERMES_EV_ALLOC)) { | ||
319 | printk(KERN_ERR "hermes @ %p: " | ||
320 | "Timeout waiting for frame allocation\n", | ||
321 | hw->iobase); | ||
322 | return -ETIMEDOUT; | ||
323 | } | ||
324 | |||
325 | *fid = hermes_read_regn(hw, ALLOCFID); | ||
326 | hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | |||
332 | /* Set up a BAP to read a particular chunk of data from card's internal buffer. | ||
333 | * | ||
334 | * Returns: < 0 on internal failure (errno), 0 on success, >0 on error | ||
335 | * from firmware | ||
336 | * | ||
337 | * Callable from any context */ | ||
338 | static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset) | ||
339 | { | ||
340 | int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; | ||
341 | int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; | ||
342 | int k; | ||
343 | u16 reg; | ||
344 | |||
345 | /* Paranoia.. */ | ||
346 | if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) | ||
347 | return -EINVAL; | ||
348 | |||
349 | k = HERMES_BAP_BUSY_TIMEOUT; | ||
350 | reg = hermes_read_reg(hw, oreg); | ||
351 | while ((reg & HERMES_OFFSET_BUSY) && k) { | ||
352 | k--; | ||
353 | udelay(1); | ||
354 | reg = hermes_read_reg(hw, oreg); | ||
355 | } | ||
356 | |||
357 | #ifdef HERMES_DEBUG_BUFFER | ||
358 | hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++; | ||
359 | |||
360 | if (k < HERMES_BAP_BUSY_TIMEOUT) { | ||
361 | struct hermes_debug_entry *e = | ||
362 | &hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE]; | ||
363 | e->bap = bap; | ||
364 | e->id = id; | ||
365 | e->offset = offset; | ||
366 | e->cycles = HERMES_BAP_BUSY_TIMEOUT - k; | ||
367 | } | ||
368 | #endif | ||
369 | |||
370 | if (reg & HERMES_OFFSET_BUSY) | ||
371 | return -ETIMEDOUT; | ||
372 | |||
373 | /* Now we actually set up the transfer */ | ||
374 | hermes_write_reg(hw, sreg, id); | ||
375 | hermes_write_reg(hw, oreg, offset); | ||
376 | |||
377 | /* Wait for the BAP to be ready */ | ||
378 | k = HERMES_BAP_BUSY_TIMEOUT; | ||
379 | reg = hermes_read_reg(hw, oreg); | ||
380 | while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { | ||
381 | k--; | ||
382 | udelay(1); | ||
383 | reg = hermes_read_reg(hw, oreg); | ||
384 | } | ||
385 | |||
386 | if (reg != offset) { | ||
387 | printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " | ||
388 | "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, | ||
389 | (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", | ||
390 | reg, id, offset); | ||
391 | |||
392 | if (reg & HERMES_OFFSET_BUSY) { | ||
393 | return -ETIMEDOUT; | ||
394 | } | ||
395 | |||
396 | return -EIO; /* error or wrong offset */ | ||
397 | } | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | /* Read a block of data from the chip's buffer, via the | ||
403 | * BAP. Synchronization/serialization is the caller's problem. len | ||
404 | * must be even. | ||
405 | * | ||
406 | * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware | ||
407 | */ | ||
408 | int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, | ||
409 | u16 id, u16 offset) | ||
410 | { | ||
411 | int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; | ||
412 | int err = 0; | ||
413 | |||
414 | if ( (len < 0) || (len % 2) ) | ||
415 | return -EINVAL; | ||
416 | |||
417 | err = hermes_bap_seek(hw, bap, id, offset); | ||
418 | if (err) | ||
419 | goto out; | ||
420 | |||
421 | /* Actually do the transfer */ | ||
422 | hermes_read_words(hw, dreg, buf, len/2); | ||
423 | |||
424 | out: | ||
425 | return err; | ||
426 | } | ||
427 | |||
428 | /* Write a block of data to the chip's buffer, via the | ||
429 | * BAP. Synchronization/serialization is the caller's problem. len | ||
430 | * must be even. | ||
431 | * | ||
432 | * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware | ||
433 | */ | ||
434 | int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, | ||
435 | u16 id, u16 offset) | ||
436 | { | ||
437 | int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; | ||
438 | int err = 0; | ||
439 | |||
440 | if ( (len < 0) || (len % 2) ) | ||
441 | return -EINVAL; | ||
442 | |||
443 | err = hermes_bap_seek(hw, bap, id, offset); | ||
444 | if (err) | ||
445 | goto out; | ||
446 | |||
447 | /* Actually do the transfer */ | ||
448 | hermes_write_words(hw, dreg, buf, len/2); | ||
449 | |||
450 | out: | ||
451 | return err; | ||
452 | } | ||
453 | |||
454 | /* Read a Length-Type-Value record from the card. | ||
455 | * | ||
456 | * If length is NULL, we ignore the length read from the card, and | ||
457 | * read the entire buffer regardless. This is useful because some of | ||
458 | * the configuration records appear to have incorrect lengths in | ||
459 | * practice. | ||
460 | * | ||
461 | * Callable from user or bh context. */ | ||
462 | int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, | ||
463 | u16 *length, void *buf) | ||
464 | { | ||
465 | int err = 0; | ||
466 | int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; | ||
467 | u16 rlength, rtype; | ||
468 | unsigned nwords; | ||
469 | |||
470 | if ( (bufsize < 0) || (bufsize % 2) ) | ||
471 | return -EINVAL; | ||
472 | |||
473 | err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); | ||
474 | if (err) | ||
475 | return err; | ||
476 | |||
477 | err = hermes_bap_seek(hw, bap, rid, 0); | ||
478 | if (err) | ||
479 | return err; | ||
480 | |||
481 | rlength = hermes_read_reg(hw, dreg); | ||
482 | |||
483 | if (! rlength) | ||
484 | return -ENODATA; | ||
485 | |||
486 | rtype = hermes_read_reg(hw, dreg); | ||
487 | |||
488 | if (length) | ||
489 | *length = rlength; | ||
490 | |||
491 | if (rtype != rid) | ||
492 | printk(KERN_WARNING "hermes @ %p: %s(): " | ||
493 | "rid (0x%04x) does not match type (0x%04x)\n", | ||
494 | hw->iobase, __FUNCTION__, rid, rtype); | ||
495 | if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) | ||
496 | printk(KERN_WARNING "hermes @ %p: " | ||
497 | "Truncating LTV record from %d to %d bytes. " | ||
498 | "(rid=0x%04x, len=0x%04x)\n", hw->iobase, | ||
499 | HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); | ||
500 | |||
501 | nwords = min((unsigned)rlength - 1, bufsize / 2); | ||
502 | hermes_read_words(hw, dreg, buf, nwords); | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, | ||
508 | u16 length, const void *value) | ||
509 | { | ||
510 | int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; | ||
511 | int err = 0; | ||
512 | unsigned count; | ||
513 | |||
514 | if (length == 0) | ||
515 | return -EINVAL; | ||
516 | |||
517 | err = hermes_bap_seek(hw, bap, rid, 0); | ||
518 | if (err) | ||
519 | return err; | ||
520 | |||
521 | hermes_write_reg(hw, dreg, length); | ||
522 | hermes_write_reg(hw, dreg, rid); | ||
523 | |||
524 | count = length - 1; | ||
525 | |||
526 | hermes_write_words(hw, dreg, value, count); | ||
527 | |||
528 | err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, | ||
529 | rid, NULL); | ||
530 | |||
531 | return err; | ||
532 | } | ||
533 | |||
534 | EXPORT_SYMBOL(hermes_struct_init); | ||
535 | EXPORT_SYMBOL(hermes_init); | ||
536 | EXPORT_SYMBOL(hermes_docmd_wait); | ||
537 | EXPORT_SYMBOL(hermes_allocate); | ||
538 | |||
539 | EXPORT_SYMBOL(hermes_bap_pread); | ||
540 | EXPORT_SYMBOL(hermes_bap_pwrite); | ||
541 | EXPORT_SYMBOL(hermes_read_ltv); | ||
542 | EXPORT_SYMBOL(hermes_write_ltv); | ||
543 | |||
544 | static int __init init_hermes(void) | ||
545 | { | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static void __exit exit_hermes(void) | ||
550 | { | ||
551 | } | ||
552 | |||
553 | module_init(init_hermes); | ||
554 | module_exit(exit_hermes); | ||
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h new file mode 100644 index 000000000000..8c9e874c9118 --- /dev/null +++ b/drivers/net/wireless/hermes.h | |||
@@ -0,0 +1,481 @@ | |||
1 | /* hermes.h | ||
2 | * | ||
3 | * Driver core for the "Hermes" wireless MAC controller, as used in | ||
4 | * the Lucent Orinoco and Cabletron RoamAbout cards. It should also | ||
5 | * work on the hfa3841 and hfa3842 MAC controller chips used in the | ||
6 | * Prism I & II chipsets. | ||
7 | * | ||
8 | * This is not a complete driver, just low-level access routines for | ||
9 | * the MAC controller itself. | ||
10 | * | ||
11 | * Based on the prism2 driver from Absolute Value Systems' linux-wlan | ||
12 | * project, the Linux wvlan_cs driver, Lucent's HCF-Light | ||
13 | * (wvlan_hcf.c) library, and the NetBSD wireless driver. | ||
14 | * | ||
15 | * Copyright (C) 2000, David Gibson, Linuxcare Australia. | ||
16 | * (C) Copyright David Gibson, IBM Corp. 2001-2003. | ||
17 | * | ||
18 | * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. | ||
19 | * | ||
20 | * This file distributed under the GPL, version 2. | ||
21 | */ | ||
22 | |||
23 | #ifndef _HERMES_H | ||
24 | #define _HERMES_H | ||
25 | |||
26 | /* Notes on locking: | ||
27 | * | ||
28 | * As a module of low level hardware access routines, there is no | ||
29 | * locking. Users of this module should ensure that they serialize | ||
30 | * access to the hermes_t structure, and to the hardware | ||
31 | */ | ||
32 | |||
33 | #include <linux/delay.h> | ||
34 | #include <linux/if_ether.h> | ||
35 | #include <asm/byteorder.h> | ||
36 | |||
37 | /* | ||
38 | * Limits and constants | ||
39 | */ | ||
40 | #define HERMES_ALLOC_LEN_MIN (4) | ||
41 | #define HERMES_ALLOC_LEN_MAX (2400) | ||
42 | #define HERMES_LTV_LEN_MAX (34) | ||
43 | #define HERMES_BAP_DATALEN_MAX (4096) | ||
44 | #define HERMES_BAP_OFFSET_MAX (4096) | ||
45 | #define HERMES_PORTID_MAX (7) | ||
46 | #define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) | ||
47 | #define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ | ||
48 | #define HERMES_PDA_RECS_MAX (200) /* a guess */ | ||
49 | #define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ | ||
50 | #define HERMES_SCANRESULT_MAX (35) | ||
51 | #define HERMES_CHINFORESULT_MAX (8) | ||
52 | #define HERMES_MAX_MULTICAST (16) | ||
53 | #define HERMES_MAGIC (0x7d1f) | ||
54 | |||
55 | /* | ||
56 | * Hermes register offsets | ||
57 | */ | ||
58 | #define HERMES_CMD (0x00) | ||
59 | #define HERMES_PARAM0 (0x02) | ||
60 | #define HERMES_PARAM1 (0x04) | ||
61 | #define HERMES_PARAM2 (0x06) | ||
62 | #define HERMES_STATUS (0x08) | ||
63 | #define HERMES_RESP0 (0x0A) | ||
64 | #define HERMES_RESP1 (0x0C) | ||
65 | #define HERMES_RESP2 (0x0E) | ||
66 | #define HERMES_INFOFID (0x10) | ||
67 | #define HERMES_RXFID (0x20) | ||
68 | #define HERMES_ALLOCFID (0x22) | ||
69 | #define HERMES_TXCOMPLFID (0x24) | ||
70 | #define HERMES_SELECT0 (0x18) | ||
71 | #define HERMES_OFFSET0 (0x1C) | ||
72 | #define HERMES_DATA0 (0x36) | ||
73 | #define HERMES_SELECT1 (0x1A) | ||
74 | #define HERMES_OFFSET1 (0x1E) | ||
75 | #define HERMES_DATA1 (0x38) | ||
76 | #define HERMES_EVSTAT (0x30) | ||
77 | #define HERMES_INTEN (0x32) | ||
78 | #define HERMES_EVACK (0x34) | ||
79 | #define HERMES_CONTROL (0x14) | ||
80 | #define HERMES_SWSUPPORT0 (0x28) | ||
81 | #define HERMES_SWSUPPORT1 (0x2A) | ||
82 | #define HERMES_SWSUPPORT2 (0x2C) | ||
83 | #define HERMES_AUXPAGE (0x3A) | ||
84 | #define HERMES_AUXOFFSET (0x3C) | ||
85 | #define HERMES_AUXDATA (0x3E) | ||
86 | |||
87 | /* | ||
88 | * CMD register bitmasks | ||
89 | */ | ||
90 | #define HERMES_CMD_BUSY (0x8000) | ||
91 | #define HERMES_CMD_AINFO (0x7f00) | ||
92 | #define HERMES_CMD_MACPORT (0x0700) | ||
93 | #define HERMES_CMD_RECL (0x0100) | ||
94 | #define HERMES_CMD_WRITE (0x0100) | ||
95 | #define HERMES_CMD_PROGMODE (0x0300) | ||
96 | #define HERMES_CMD_CMDCODE (0x003f) | ||
97 | |||
98 | /* | ||
99 | * STATUS register bitmasks | ||
100 | */ | ||
101 | #define HERMES_STATUS_RESULT (0x7f00) | ||
102 | #define HERMES_STATUS_CMDCODE (0x003f) | ||
103 | |||
104 | /* | ||
105 | * OFFSET register bitmasks | ||
106 | */ | ||
107 | #define HERMES_OFFSET_BUSY (0x8000) | ||
108 | #define HERMES_OFFSET_ERR (0x4000) | ||
109 | #define HERMES_OFFSET_DATAOFF (0x0ffe) | ||
110 | |||
111 | /* | ||
112 | * Event register bitmasks (INTEN, EVSTAT, EVACK) | ||
113 | */ | ||
114 | #define HERMES_EV_TICK (0x8000) | ||
115 | #define HERMES_EV_WTERR (0x4000) | ||
116 | #define HERMES_EV_INFDROP (0x2000) | ||
117 | #define HERMES_EV_INFO (0x0080) | ||
118 | #define HERMES_EV_DTIM (0x0020) | ||
119 | #define HERMES_EV_CMD (0x0010) | ||
120 | #define HERMES_EV_ALLOC (0x0008) | ||
121 | #define HERMES_EV_TXEXC (0x0004) | ||
122 | #define HERMES_EV_TX (0x0002) | ||
123 | #define HERMES_EV_RX (0x0001) | ||
124 | |||
125 | /* | ||
126 | * Command codes | ||
127 | */ | ||
128 | /*--- Controller Commands ----------------------------*/ | ||
129 | #define HERMES_CMD_INIT (0x0000) | ||
130 | #define HERMES_CMD_ENABLE (0x0001) | ||
131 | #define HERMES_CMD_DISABLE (0x0002) | ||
132 | #define HERMES_CMD_DIAG (0x0003) | ||
133 | |||
134 | /*--- Buffer Mgmt Commands ---------------------------*/ | ||
135 | #define HERMES_CMD_ALLOC (0x000A) | ||
136 | #define HERMES_CMD_TX (0x000B) | ||
137 | |||
138 | /*--- Regulate Commands ------------------------------*/ | ||
139 | #define HERMES_CMD_NOTIFY (0x0010) | ||
140 | #define HERMES_CMD_INQUIRE (0x0011) | ||
141 | |||
142 | /*--- Configure Commands -----------------------------*/ | ||
143 | #define HERMES_CMD_ACCESS (0x0021) | ||
144 | #define HERMES_CMD_DOWNLD (0x0022) | ||
145 | |||
146 | /*--- Serial I/O Commands ----------------------------*/ | ||
147 | #define HERMES_CMD_READMIF (0x0030) | ||
148 | #define HERMES_CMD_WRITEMIF (0x0031) | ||
149 | |||
150 | /*--- Debugging Commands -----------------------------*/ | ||
151 | #define HERMES_CMD_TEST (0x0038) | ||
152 | |||
153 | |||
154 | /* Test command arguments */ | ||
155 | #define HERMES_TEST_SET_CHANNEL 0x0800 | ||
156 | #define HERMES_TEST_MONITOR 0x0b00 | ||
157 | #define HERMES_TEST_STOP 0x0f00 | ||
158 | |||
159 | /* Authentication algorithms */ | ||
160 | #define HERMES_AUTH_OPEN 1 | ||
161 | #define HERMES_AUTH_SHARED_KEY 2 | ||
162 | |||
163 | /* WEP settings */ | ||
164 | #define HERMES_WEP_PRIVACY_INVOKED 0x0001 | ||
165 | #define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 | ||
166 | #define HERMES_WEP_HOST_ENCRYPT 0x0010 | ||
167 | #define HERMES_WEP_HOST_DECRYPT 0x0080 | ||
168 | |||
169 | /* Symbol hostscan options */ | ||
170 | #define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 | ||
171 | #define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 | ||
172 | #define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 | ||
173 | #define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 | ||
174 | |||
175 | /* | ||
176 | * Frame structures and constants | ||
177 | */ | ||
178 | |||
179 | #define HERMES_DESCRIPTOR_OFFSET 0 | ||
180 | #define HERMES_802_11_OFFSET (14) | ||
181 | #define HERMES_802_3_OFFSET (14+32) | ||
182 | #define HERMES_802_2_OFFSET (14+32+14) | ||
183 | |||
184 | #define HERMES_RXSTAT_ERR (0x0003) | ||
185 | #define HERMES_RXSTAT_BADCRC (0x0001) | ||
186 | #define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) | ||
187 | #define HERMES_RXSTAT_MACPORT (0x0700) | ||
188 | #define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ | ||
189 | #define HERMES_RXSTAT_MSGTYPE (0xE000) | ||
190 | #define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ | ||
191 | #define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ | ||
192 | #define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ | ||
193 | |||
194 | struct hermes_tx_descriptor { | ||
195 | u16 status; | ||
196 | u16 reserved1; | ||
197 | u16 reserved2; | ||
198 | u32 sw_support; | ||
199 | u8 retry_count; | ||
200 | u8 tx_rate; | ||
201 | u16 tx_control; | ||
202 | } __attribute__ ((packed)); | ||
203 | |||
204 | #define HERMES_TXSTAT_RETRYERR (0x0001) | ||
205 | #define HERMES_TXSTAT_AGEDERR (0x0002) | ||
206 | #define HERMES_TXSTAT_DISCON (0x0004) | ||
207 | #define HERMES_TXSTAT_FORMERR (0x0008) | ||
208 | |||
209 | #define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ | ||
210 | #define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ | ||
211 | #define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ | ||
212 | #define HERMES_TXCTRL_ALT_RTRY (0x0020) | ||
213 | |||
214 | /* Inquiry constants and data types */ | ||
215 | |||
216 | #define HERMES_INQ_TALLIES (0xF100) | ||
217 | #define HERMES_INQ_SCAN (0xF101) | ||
218 | #define HERMES_INQ_CHANNELINFO (0xF102) | ||
219 | #define HERMES_INQ_HOSTSCAN (0xF103) | ||
220 | #define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) | ||
221 | #define HERMES_INQ_LINKSTATUS (0xF200) | ||
222 | #define HERMES_INQ_SEC_STAT_AGERE (0xF202) | ||
223 | |||
224 | struct hermes_tallies_frame { | ||
225 | u16 TxUnicastFrames; | ||
226 | u16 TxMulticastFrames; | ||
227 | u16 TxFragments; | ||
228 | u16 TxUnicastOctets; | ||
229 | u16 TxMulticastOctets; | ||
230 | u16 TxDeferredTransmissions; | ||
231 | u16 TxSingleRetryFrames; | ||
232 | u16 TxMultipleRetryFrames; | ||
233 | u16 TxRetryLimitExceeded; | ||
234 | u16 TxDiscards; | ||
235 | u16 RxUnicastFrames; | ||
236 | u16 RxMulticastFrames; | ||
237 | u16 RxFragments; | ||
238 | u16 RxUnicastOctets; | ||
239 | u16 RxMulticastOctets; | ||
240 | u16 RxFCSErrors; | ||
241 | u16 RxDiscards_NoBuffer; | ||
242 | u16 TxDiscardsWrongSA; | ||
243 | u16 RxWEPUndecryptable; | ||
244 | u16 RxMsgInMsgFragments; | ||
245 | u16 RxMsgInBadMsgFragments; | ||
246 | /* Those last are probably not available in very old firmwares */ | ||
247 | u16 RxDiscards_WEPICVError; | ||
248 | u16 RxDiscards_WEPExcluded; | ||
249 | } __attribute__ ((packed)); | ||
250 | |||
251 | /* Grabbed from wlan-ng - Thanks Mark... - Jean II | ||
252 | * This is the result of a scan inquiry command */ | ||
253 | /* Structure describing info about an Access Point */ | ||
254 | struct prism2_scan_apinfo { | ||
255 | u16 channel; /* Channel where the AP sits */ | ||
256 | u16 noise; /* Noise level */ | ||
257 | u16 level; /* Signal level */ | ||
258 | u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ | ||
259 | u16 beacon_interv; /* Beacon interval */ | ||
260 | u16 capabilities; /* Capabilities */ | ||
261 | u16 essid_len; /* ESSID length */ | ||
262 | u8 essid[32]; /* ESSID of the network */ | ||
263 | u8 rates[10]; /* Bit rate supported */ | ||
264 | u16 proberesp_rate; /* Data rate of the response frame */ | ||
265 | u16 atim; /* ATIM window time, Kus (hostscan only) */ | ||
266 | } __attribute__ ((packed)); | ||
267 | |||
268 | /* Same stuff for the Lucent/Agere card. | ||
269 | * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */ | ||
270 | struct agere_scan_apinfo { | ||
271 | u16 channel; /* Channel where the AP sits */ | ||
272 | u16 noise; /* Noise level */ | ||
273 | u16 level; /* Signal level */ | ||
274 | u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ | ||
275 | u16 beacon_interv; /* Beacon interval */ | ||
276 | u16 capabilities; /* Capabilities */ | ||
277 | /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ | ||
278 | u16 essid_len; /* ESSID length */ | ||
279 | u8 essid[32]; /* ESSID of the network */ | ||
280 | } __attribute__ ((packed)); | ||
281 | |||
282 | /* Moustafa: Scan structure for Symbol cards */ | ||
283 | struct symbol_scan_apinfo { | ||
284 | u8 channel; /* Channel where the AP sits */ | ||
285 | u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ | ||
286 | u16 noise; /* Noise level */ | ||
287 | u16 level; /* Signal level */ | ||
288 | u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ | ||
289 | u16 beacon_interv; /* Beacon interval */ | ||
290 | u16 capabilities; /* Capabilities */ | ||
291 | /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ | ||
292 | u16 essid_len; /* ESSID length */ | ||
293 | u8 essid[32]; /* ESSID of the network */ | ||
294 | u16 rates[5]; /* Bit rate supported */ | ||
295 | u16 basic_rates; /* Basic rates bitmask */ | ||
296 | u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ | ||
297 | u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ | ||
298 | } __attribute__ ((packed)); | ||
299 | |||
300 | union hermes_scan_info { | ||
301 | struct agere_scan_apinfo a; | ||
302 | struct prism2_scan_apinfo p; | ||
303 | struct symbol_scan_apinfo s; | ||
304 | }; | ||
305 | |||
306 | #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) | ||
307 | #define HERMES_LINKSTATUS_CONNECTED (0x0001) | ||
308 | #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) | ||
309 | #define HERMES_LINKSTATUS_AP_CHANGE (0x0003) | ||
310 | #define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004) | ||
311 | #define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005) | ||
312 | #define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) | ||
313 | |||
314 | struct hermes_linkstatus { | ||
315 | u16 linkstatus; /* Link status */ | ||
316 | } __attribute__ ((packed)); | ||
317 | |||
318 | struct hermes_response { | ||
319 | u16 status, resp0, resp1, resp2; | ||
320 | }; | ||
321 | |||
322 | /* "ID" structure - used for ESSID and station nickname */ | ||
323 | struct hermes_idstring { | ||
324 | u16 len; | ||
325 | u16 val[16]; | ||
326 | } __attribute__ ((packed)); | ||
327 | |||
328 | struct hermes_multicast { | ||
329 | u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; | ||
330 | } __attribute__ ((packed)); | ||
331 | |||
332 | // #define HERMES_DEBUG_BUFFER 1 | ||
333 | #define HERMES_DEBUG_BUFSIZE 4096 | ||
334 | struct hermes_debug_entry { | ||
335 | int bap; | ||
336 | u16 id, offset; | ||
337 | int cycles; | ||
338 | }; | ||
339 | |||
340 | #ifdef __KERNEL__ | ||
341 | |||
342 | /* Timeouts */ | ||
343 | #define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ | ||
344 | |||
345 | /* Basic control structure */ | ||
346 | typedef struct hermes { | ||
347 | void __iomem *iobase; | ||
348 | int reg_spacing; | ||
349 | #define HERMES_16BIT_REGSPACING 0 | ||
350 | #define HERMES_32BIT_REGSPACING 1 | ||
351 | |||
352 | u16 inten; /* Which interrupts should be enabled? */ | ||
353 | |||
354 | #ifdef HERMES_DEBUG_BUFFER | ||
355 | struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE]; | ||
356 | unsigned long dbufp; | ||
357 | unsigned long profile[HERMES_BAP_BUSY_TIMEOUT+1]; | ||
358 | #endif | ||
359 | } hermes_t; | ||
360 | |||
361 | /* Register access convenience macros */ | ||
362 | #define hermes_read_reg(hw, off) \ | ||
363 | (ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing ))) | ||
364 | #define hermes_write_reg(hw, off, val) \ | ||
365 | (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) | ||
366 | #define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) | ||
367 | #define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) | ||
368 | |||
369 | /* Function prototypes */ | ||
370 | void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing); | ||
371 | int hermes_init(hermes_t *hw); | ||
372 | int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, | ||
373 | struct hermes_response *resp); | ||
374 | int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); | ||
375 | |||
376 | int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, | ||
377 | u16 id, u16 offset); | ||
378 | int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, | ||
379 | u16 id, u16 offset); | ||
380 | int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, | ||
381 | u16 *length, void *buf); | ||
382 | int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, | ||
383 | u16 length, const void *value); | ||
384 | |||
385 | /* Inline functions */ | ||
386 | |||
387 | static inline int hermes_present(hermes_t *hw) | ||
388 | { | ||
389 | return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; | ||
390 | } | ||
391 | |||
392 | static inline void hermes_set_irqmask(hermes_t *hw, u16 events) | ||
393 | { | ||
394 | hw->inten = events; | ||
395 | hermes_write_regn(hw, INTEN, events); | ||
396 | } | ||
397 | |||
398 | static inline int hermes_enable_port(hermes_t *hw, int port) | ||
399 | { | ||
400 | return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), | ||
401 | 0, NULL); | ||
402 | } | ||
403 | |||
404 | static inline int hermes_disable_port(hermes_t *hw, int port) | ||
405 | { | ||
406 | return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), | ||
407 | 0, NULL); | ||
408 | } | ||
409 | |||
410 | /* Initiate an INQUIRE command (tallies or scan). The result will come as an | ||
411 | * information frame in __orinoco_ev_info() */ | ||
412 | static inline int hermes_inquire(hermes_t *hw, u16 rid) | ||
413 | { | ||
414 | return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL); | ||
415 | } | ||
416 | |||
417 | #define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 ) | ||
418 | #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) | ||
419 | |||
420 | /* Note that for the next two, the count is in 16-bit words, not bytes */ | ||
421 | static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count) | ||
422 | { | ||
423 | off = off << hw->reg_spacing; | ||
424 | ioread16_rep(hw->iobase + off, buf, count); | ||
425 | } | ||
426 | |||
427 | static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count) | ||
428 | { | ||
429 | off = off << hw->reg_spacing; | ||
430 | iowrite16_rep(hw->iobase + off, buf, count); | ||
431 | } | ||
432 | |||
433 | static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) | ||
434 | { | ||
435 | unsigned i; | ||
436 | |||
437 | off = off << hw->reg_spacing; | ||
438 | |||
439 | for (i = 0; i < count; i++) | ||
440 | iowrite16(0, hw->iobase + off); | ||
441 | } | ||
442 | |||
443 | #define HERMES_READ_RECORD(hw, bap, rid, buf) \ | ||
444 | (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) | ||
445 | #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ | ||
446 | (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) | ||
447 | |||
448 | static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) | ||
449 | { | ||
450 | u16 rec; | ||
451 | int err; | ||
452 | |||
453 | err = HERMES_READ_RECORD(hw, bap, rid, &rec); | ||
454 | *word = le16_to_cpu(rec); | ||
455 | return err; | ||
456 | } | ||
457 | |||
458 | static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word) | ||
459 | { | ||
460 | u16 rec = cpu_to_le16(word); | ||
461 | return HERMES_WRITE_RECORD(hw, bap, rid, &rec); | ||
462 | } | ||
463 | |||
464 | #else /* ! __KERNEL__ */ | ||
465 | |||
466 | /* These are provided for the benefit of userspace drivers and testing programs | ||
467 | which use ioperm() or iopl() */ | ||
468 | |||
469 | #define hermes_read_reg(base, off) (inw((base) + (off))) | ||
470 | #define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) | ||
471 | |||
472 | #define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) | ||
473 | #define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) | ||
474 | |||
475 | /* Note that for the next two, the count is in 16-bit words, not bytes */ | ||
476 | #define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) | ||
477 | #define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) | ||
478 | |||
479 | #endif /* ! __KERNEL__ */ | ||
480 | |||
481 | #endif /* _HERMES_H */ | ||
diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h new file mode 100644 index 000000000000..4f46b4809e55 --- /dev/null +++ b/drivers/net/wireless/hermes_rid.h | |||
@@ -0,0 +1,148 @@ | |||
1 | #ifndef _HERMES_RID_H | ||
2 | #define _HERMES_RID_H | ||
3 | |||
4 | /* | ||
5 | * Configuration RIDs | ||
6 | */ | ||
7 | #define HERMES_RID_CNFPORTTYPE 0xFC00 | ||
8 | #define HERMES_RID_CNFOWNMACADDR 0xFC01 | ||
9 | #define HERMES_RID_CNFDESIREDSSID 0xFC02 | ||
10 | #define HERMES_RID_CNFOWNCHANNEL 0xFC03 | ||
11 | #define HERMES_RID_CNFOWNSSID 0xFC04 | ||
12 | #define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 | ||
13 | #define HERMES_RID_CNFSYSTEMSCALE 0xFC06 | ||
14 | #define HERMES_RID_CNFMAXDATALEN 0xFC07 | ||
15 | #define HERMES_RID_CNFWDSADDRESS 0xFC08 | ||
16 | #define HERMES_RID_CNFPMENABLED 0xFC09 | ||
17 | #define HERMES_RID_CNFPMEPS 0xFC0A | ||
18 | #define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B | ||
19 | #define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C | ||
20 | #define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D | ||
21 | #define HERMES_RID_CNFOWNNAME 0xFC0E | ||
22 | #define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 | ||
23 | #define HERMES_RID_CNFWDSADDRESS1 0xFC11 | ||
24 | #define HERMES_RID_CNFWDSADDRESS2 0xFC12 | ||
25 | #define HERMES_RID_CNFWDSADDRESS3 0xFC13 | ||
26 | #define HERMES_RID_CNFWDSADDRESS4 0xFC14 | ||
27 | #define HERMES_RID_CNFWDSADDRESS5 0xFC15 | ||
28 | #define HERMES_RID_CNFWDSADDRESS6 0xFC16 | ||
29 | #define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 | ||
30 | #define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 | ||
31 | #define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 | ||
32 | #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 | ||
33 | #define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 | ||
34 | #define HERMES_RID_CNFDEFAULTKEY0 0xFC24 | ||
35 | #define HERMES_RID_CNFDEFAULTKEY1 0xFC25 | ||
36 | #define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 | ||
37 | #define HERMES_RID_CNFDEFAULTKEY2 0xFC26 | ||
38 | #define HERMES_RID_CNFDEFAULTKEY3 0xFC27 | ||
39 | #define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 | ||
40 | #define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 | ||
41 | #define HERMES_RID_CNFAUTHENTICATION 0xFC2A | ||
42 | #define HERMES_RID_CNFMAXASSOCSTA 0xFC2B | ||
43 | #define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B | ||
44 | #define HERMES_RID_CNFTXCONTROL 0xFC2C | ||
45 | #define HERMES_RID_CNFROAMINGMODE 0xFC2D | ||
46 | #define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E | ||
47 | #define HERMES_RID_CNFRCVCRCERROR 0xFC30 | ||
48 | #define HERMES_RID_CNFMMLIFE 0xFC31 | ||
49 | #define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 | ||
50 | #define HERMES_RID_CNFBEACONINT 0xFC33 | ||
51 | #define HERMES_RID_CNFAPPCFINFO 0xFC34 | ||
52 | #define HERMES_RID_CNFSTAPCFINFO 0xFC35 | ||
53 | #define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 | ||
54 | #define HERMES_RID_CNFTIMCTRL 0xFC40 | ||
55 | #define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 | ||
56 | #define HERMES_RID_CNFENHSECURITY 0xFC43 | ||
57 | #define HERMES_RID_CNFGROUPADDRESSES 0xFC80 | ||
58 | #define HERMES_RID_CNFCREATEIBSS 0xFC81 | ||
59 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 | ||
60 | #define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 | ||
61 | #define HERMES_RID_CNFTXRATECONTROL 0xFC84 | ||
62 | #define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 | ||
63 | #define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A | ||
64 | #define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C | ||
65 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 | ||
66 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 | ||
67 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 | ||
68 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 | ||
69 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 | ||
70 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 | ||
71 | #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 | ||
72 | #define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 | ||
73 | #define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 | ||
74 | #define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 | ||
75 | #define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A | ||
76 | #define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B | ||
77 | #define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C | ||
78 | #define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D | ||
79 | #define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB | ||
80 | #define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 | ||
81 | #define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 | ||
82 | #define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 | ||
83 | #define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 | ||
84 | #define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 | ||
85 | #define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 | ||
86 | #define HERMES_RID_CNFBASICRATES 0xFCB3 | ||
87 | #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 | ||
88 | #define HERMES_RID_CNFTICKTIME 0xFCE0 | ||
89 | #define HERMES_RID_CNFSCANREQUEST 0xFCE1 | ||
90 | #define HERMES_RID_CNFJOINREQUEST 0xFCE2 | ||
91 | #define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 | ||
92 | #define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 | ||
93 | #define HERMES_RID_CNFHOSTSCAN 0xFCE5 | ||
94 | |||
95 | /* | ||
96 | * Information RIDs | ||
97 | */ | ||
98 | #define HERMES_RID_MAXLOADTIME 0xFD00 | ||
99 | #define HERMES_RID_DOWNLOADBUFFER 0xFD01 | ||
100 | #define HERMES_RID_PRIID 0xFD02 | ||
101 | #define HERMES_RID_PRISUPRANGE 0xFD03 | ||
102 | #define HERMES_RID_CFIACTRANGES 0xFD04 | ||
103 | #define HERMES_RID_NICSERNUM 0xFD0A | ||
104 | #define HERMES_RID_NICID 0xFD0B | ||
105 | #define HERMES_RID_MFISUPRANGE 0xFD0C | ||
106 | #define HERMES_RID_CFISUPRANGE 0xFD0D | ||
107 | #define HERMES_RID_CHANNELLIST 0xFD10 | ||
108 | #define HERMES_RID_REGULATORYDOMAINS 0xFD11 | ||
109 | #define HERMES_RID_TEMPTYPE 0xFD12 | ||
110 | #define HERMES_RID_CIS 0xFD13 | ||
111 | #define HERMES_RID_STAID 0xFD20 | ||
112 | #define HERMES_RID_STASUPRANGE 0xFD21 | ||
113 | #define HERMES_RID_MFIACTRANGES 0xFD22 | ||
114 | #define HERMES_RID_CFIACTRANGES2 0xFD23 | ||
115 | #define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 | ||
116 | #define HERMES_RID_PORTSTATUS 0xFD40 | ||
117 | #define HERMES_RID_CURRENTSSID 0xFD41 | ||
118 | #define HERMES_RID_CURRENTBSSID 0xFD42 | ||
119 | #define HERMES_RID_COMMSQUALITY 0xFD43 | ||
120 | #define HERMES_RID_CURRENTTXRATE 0xFD44 | ||
121 | #define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 | ||
122 | #define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 | ||
123 | #define HERMES_RID_PROTOCOLRSPTIME 0xFD47 | ||
124 | #define HERMES_RID_SHORTRETRYLIMIT 0xFD48 | ||
125 | #define HERMES_RID_LONGRETRYLIMIT 0xFD49 | ||
126 | #define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A | ||
127 | #define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B | ||
128 | #define HERMES_RID_CFPOLLABLE 0xFD4C | ||
129 | #define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D | ||
130 | #define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F | ||
131 | #define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 | ||
132 | #define HERMES_RID_CURRENTTXRATE1 0xFD80 | ||
133 | #define HERMES_RID_CURRENTTXRATE2 0xFD81 | ||
134 | #define HERMES_RID_CURRENTTXRATE3 0xFD82 | ||
135 | #define HERMES_RID_CURRENTTXRATE4 0xFD83 | ||
136 | #define HERMES_RID_CURRENTTXRATE5 0xFD84 | ||
137 | #define HERMES_RID_CURRENTTXRATE6 0xFD85 | ||
138 | #define HERMES_RID_OWNMACADDR 0xFD86 | ||
139 | #define HERMES_RID_SCANRESULTSTABLE 0xFD88 | ||
140 | #define HERMES_RID_PHYTYPE 0xFDC0 | ||
141 | #define HERMES_RID_CURRENTCHANNEL 0xFDC1 | ||
142 | #define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 | ||
143 | #define HERMES_RID_CCAMODE 0xFDC3 | ||
144 | #define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 | ||
145 | #define HERMES_RID_BUILDSEQ 0xFFFE | ||
146 | #define HERMES_RID_FWID 0xFFFF | ||
147 | |||
148 | #endif | ||
diff --git a/drivers/net/wireless/i82586.h b/drivers/net/wireless/i82586.h new file mode 100644 index 000000000000..5f65b250646f --- /dev/null +++ b/drivers/net/wireless/i82586.h | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. | ||
3 | * | ||
4 | * See: | ||
5 | * Intel Microcommunications 1991 | ||
6 | * p1-1 to p1-37 | ||
7 | * Intel order No. 231658 | ||
8 | * ISBN 1-55512-119-5 | ||
9 | * | ||
10 | * Unfortunately, the above chapter mentions neither | ||
11 | * the System Configuration Pointer (SCP) nor the | ||
12 | * Intermediate System Configuration Pointer (ISCP), | ||
13 | * so we probably need to look elsewhere for the | ||
14 | * whole story -- some recommend the "Intel LAN | ||
15 | * Components manual" but I have neither a copy | ||
16 | * nor a full reference. But "elsewhere" may be | ||
17 | * in the same publication... | ||
18 | * The description of a later device, the | ||
19 | * "82596CA High-Performance 32-Bit Local Area Network | ||
20 | * Coprocessor", (ibid. p1-38 to p1-109) does mention | ||
21 | * the SCP and ISCP and also has an i82586 compatibility | ||
22 | * mode. Even more useful is "AP-235 An 82586 Data Link | ||
23 | * Driver" (ibid. p1-337 to p1-417). | ||
24 | */ | ||
25 | |||
26 | #define I82586_MEMZ (64 * 1024) | ||
27 | |||
28 | #define I82586_SCP_ADDR (I82586_MEMZ - sizeof(scp_t)) | ||
29 | |||
30 | #define ADDR_LEN 6 | ||
31 | #define I82586NULL 0xFFFF | ||
32 | |||
33 | #define toff(t,p,f) (unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0) | ||
34 | |||
35 | /* | ||
36 | * System Configuration Pointer (SCP). | ||
37 | */ | ||
38 | typedef struct scp_t scp_t; | ||
39 | struct scp_t | ||
40 | { | ||
41 | unsigned short scp_sysbus; /* 82586 bus width: */ | ||
42 | #define SCP_SY_16BBUS (0x0 << 0) /* 16 bits */ | ||
43 | #define SCP_SY_8BBUS (0x1 << 0) /* 8 bits. */ | ||
44 | unsigned short scp_junk[2]; /* Unused */ | ||
45 | unsigned short scp_iscpl; /* lower 16 bits of ISCP_ADDR */ | ||
46 | unsigned short scp_iscph; /* upper 16 bits of ISCP_ADDR */ | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * Intermediate System Configuration Pointer (ISCP). | ||
51 | */ | ||
52 | typedef struct iscp_t iscp_t; | ||
53 | struct iscp_t | ||
54 | { | ||
55 | unsigned short iscp_busy; /* set by CPU before first CA, */ | ||
56 | /* cleared by 82586 after read. */ | ||
57 | unsigned short iscp_offset; /* offset of SCB */ | ||
58 | unsigned short iscp_basel; /* base of SCB */ | ||
59 | unsigned short iscp_baseh; /* " */ | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * System Control Block (SCB). | ||
64 | * The 82586 writes its status to scb_status and then | ||
65 | * raises an interrupt to alert the CPU. | ||
66 | * The CPU writes a command to scb_command and | ||
67 | * then issues a Channel Attention (CA) to alert the 82586. | ||
68 | */ | ||
69 | typedef struct scb_t scb_t; | ||
70 | struct scb_t | ||
71 | { | ||
72 | unsigned short scb_status; /* Status of 82586 */ | ||
73 | #define SCB_ST_INT (0xF << 12) /* Some of: */ | ||
74 | #define SCB_ST_CX (0x1 << 15) /* Cmd completed */ | ||
75 | #define SCB_ST_FR (0x1 << 14) /* Frame received */ | ||
76 | #define SCB_ST_CNA (0x1 << 13) /* Cmd unit not active */ | ||
77 | #define SCB_ST_RNR (0x1 << 12) /* Rcv unit not ready */ | ||
78 | #define SCB_ST_JUNK0 (0x1 << 11) /* 0 */ | ||
79 | #define SCB_ST_CUS (0x7 << 8) /* Cmd unit status */ | ||
80 | #define SCB_ST_CUS_IDLE (0 << 8) /* Idle */ | ||
81 | #define SCB_ST_CUS_SUSP (1 << 8) /* Suspended */ | ||
82 | #define SCB_ST_CUS_ACTV (2 << 8) /* Active */ | ||
83 | #define SCB_ST_JUNK1 (0x1 << 7) /* 0 */ | ||
84 | #define SCB_ST_RUS (0x7 << 4) /* Rcv unit status */ | ||
85 | #define SCB_ST_RUS_IDLE (0 << 4) /* Idle */ | ||
86 | #define SCB_ST_RUS_SUSP (1 << 4) /* Suspended */ | ||
87 | #define SCB_ST_RUS_NRES (2 << 4) /* No resources */ | ||
88 | #define SCB_ST_RUS_RDY (4 << 4) /* Ready */ | ||
89 | unsigned short scb_command; /* Next command */ | ||
90 | #define SCB_CMD_ACK_CX (0x1 << 15) /* Ack cmd completion */ | ||
91 | #define SCB_CMD_ACK_FR (0x1 << 14) /* Ack frame received */ | ||
92 | #define SCB_CMD_ACK_CNA (0x1 << 13) /* Ack CU not active */ | ||
93 | #define SCB_CMD_ACK_RNR (0x1 << 12) /* Ack RU not ready */ | ||
94 | #define SCB_CMD_JUNKX (0x1 << 11) /* Unused */ | ||
95 | #define SCB_CMD_CUC (0x7 << 8) /* Command Unit command */ | ||
96 | #define SCB_CMD_CUC_NOP (0 << 8) /* Nop */ | ||
97 | #define SCB_CMD_CUC_GO (1 << 8) /* Start cbl_offset */ | ||
98 | #define SCB_CMD_CUC_RES (2 << 8) /* Resume execution */ | ||
99 | #define SCB_CMD_CUC_SUS (3 << 8) /* Suspend " */ | ||
100 | #define SCB_CMD_CUC_ABT (4 << 8) /* Abort " */ | ||
101 | #define SCB_CMD_RESET (0x1 << 7) /* Reset chip (hardware) */ | ||
102 | #define SCB_CMD_RUC (0x7 << 4) /* Receive Unit command */ | ||
103 | #define SCB_CMD_RUC_NOP (0 << 4) /* Nop */ | ||
104 | #define SCB_CMD_RUC_GO (1 << 4) /* Start rfa_offset */ | ||
105 | #define SCB_CMD_RUC_RES (2 << 4) /* Resume reception */ | ||
106 | #define SCB_CMD_RUC_SUS (3 << 4) /* Suspend " */ | ||
107 | #define SCB_CMD_RUC_ABT (4 << 4) /* Abort " */ | ||
108 | unsigned short scb_cbl_offset; /* Offset of first command unit */ | ||
109 | /* Action Command */ | ||
110 | unsigned short scb_rfa_offset; /* Offset of first Receive */ | ||
111 | /* Frame Descriptor in the */ | ||
112 | /* Receive Frame Area */ | ||
113 | unsigned short scb_crcerrs; /* Properly aligned frames */ | ||
114 | /* received with a CRC error */ | ||
115 | unsigned short scb_alnerrs; /* Misaligned frames received */ | ||
116 | /* with a CRC error */ | ||
117 | unsigned short scb_rscerrs; /* Frames lost due to no space */ | ||
118 | unsigned short scb_ovrnerrs; /* Frames lost due to slow bus */ | ||
119 | }; | ||
120 | |||
121 | #define scboff(p,f) toff(scb_t, p, f) | ||
122 | |||
123 | /* | ||
124 | * The eight Action Commands. | ||
125 | */ | ||
126 | typedef enum acmd_e acmd_e; | ||
127 | enum acmd_e | ||
128 | { | ||
129 | acmd_nop = 0, /* Do nothing */ | ||
130 | acmd_ia_setup = 1, /* Load an (ethernet) address into the */ | ||
131 | /* 82586 */ | ||
132 | acmd_configure = 2, /* Update the 82586 operating parameters */ | ||
133 | acmd_mc_setup = 3, /* Load a list of (ethernet) multicast */ | ||
134 | /* addresses into the 82586 */ | ||
135 | acmd_transmit = 4, /* Transmit a frame */ | ||
136 | acmd_tdr = 5, /* Perform a Time Domain Reflectometer */ | ||
137 | /* test on the serial link */ | ||
138 | acmd_dump = 6, /* Copy 82586 registers to memory */ | ||
139 | acmd_diagnose = 7, /* Run an internal self test */ | ||
140 | }; | ||
141 | |||
142 | /* | ||
143 | * Generic Action Command header. | ||
144 | */ | ||
145 | typedef struct ach_t ach_t; | ||
146 | struct ach_t | ||
147 | { | ||
148 | unsigned short ac_status; /* Command status: */ | ||
149 | #define AC_SFLD_C (0x1 << 15) /* Command completed */ | ||
150 | #define AC_SFLD_B (0x1 << 14) /* Busy executing */ | ||
151 | #define AC_SFLD_OK (0x1 << 13) /* Completed error free */ | ||
152 | #define AC_SFLD_A (0x1 << 12) /* Command aborted */ | ||
153 | #define AC_SFLD_FAIL (0x1 << 11) /* Selftest failed */ | ||
154 | #define AC_SFLD_S10 (0x1 << 10) /* No carrier sense */ | ||
155 | /* during transmission */ | ||
156 | #define AC_SFLD_S9 (0x1 << 9) /* Tx unsuccessful: */ | ||
157 | /* (stopped) lost CTS */ | ||
158 | #define AC_SFLD_S8 (0x1 << 8) /* Tx unsuccessful: */ | ||
159 | /* (stopped) slow DMA */ | ||
160 | #define AC_SFLD_S7 (0x1 << 7) /* Tx deferred: */ | ||
161 | /* other link traffic */ | ||
162 | #define AC_SFLD_S6 (0x1 << 6) /* Heart Beat: collision */ | ||
163 | /* detect after last tx */ | ||
164 | #define AC_SFLD_S5 (0x1 << 5) /* Tx stopped: */ | ||
165 | /* excessive collisions */ | ||
166 | #define AC_SFLD_MAXCOL (0xF << 0) /* Collision count */ | ||
167 | unsigned short ac_command; /* Command specifier: */ | ||
168 | #define AC_CFLD_EL (0x1 << 15) /* End of command list */ | ||
169 | #define AC_CFLD_S (0x1 << 14) /* Suspend on completion */ | ||
170 | #define AC_CFLD_I (0x1 << 13) /* Interrupt on completion */ | ||
171 | #define AC_CFLD_CMD (0x7 << 0) /* acmd_e */ | ||
172 | unsigned short ac_link; /* Next Action Command */ | ||
173 | }; | ||
174 | |||
175 | #define acoff(p,f) toff(ach_t, p, f) | ||
176 | |||
177 | /* | ||
178 | * The Nop Action Command. | ||
179 | */ | ||
180 | typedef struct ac_nop_t ac_nop_t; | ||
181 | struct ac_nop_t | ||
182 | { | ||
183 | ach_t nop_h; | ||
184 | }; | ||
185 | |||
186 | /* | ||
187 | * The IA-Setup Action Command. | ||
188 | */ | ||
189 | typedef struct ac_ias_t ac_ias_t; | ||
190 | struct ac_ias_t | ||
191 | { | ||
192 | ach_t ias_h; | ||
193 | unsigned char ias_addr[ADDR_LEN]; /* The (ethernet) address */ | ||
194 | }; | ||
195 | |||
196 | /* | ||
197 | * The Configure Action Command. | ||
198 | */ | ||
199 | typedef struct ac_cfg_t ac_cfg_t; | ||
200 | struct ac_cfg_t | ||
201 | { | ||
202 | ach_t cfg_h; | ||
203 | unsigned char cfg_byte_cnt; /* Size foll data: 4-12 */ | ||
204 | #define AC_CFG_BYTE_CNT(v) (((v) & 0xF) << 0) | ||
205 | unsigned char cfg_fifolim; /* FIFO threshold */ | ||
206 | #define AC_CFG_FIFOLIM(v) (((v) & 0xF) << 0) | ||
207 | unsigned char cfg_byte8; | ||
208 | #define AC_CFG_SAV_BF(v) (((v) & 0x1) << 7) /* Save rxd bad frames */ | ||
209 | #define AC_CFG_SRDY(v) (((v) & 0x1) << 6) /* SRDY/ARDY pin means */ | ||
210 | /* external sync. */ | ||
211 | unsigned char cfg_byte9; | ||
212 | #define AC_CFG_ELPBCK(v) (((v) & 0x1) << 7) /* External loopback */ | ||
213 | #define AC_CFG_ILPBCK(v) (((v) & 0x1) << 6) /* Internal loopback */ | ||
214 | #define AC_CFG_PRELEN(v) (((v) & 0x3) << 4) /* Preamble length */ | ||
215 | #define AC_CFG_PLEN_2 0 /* 2 bytes */ | ||
216 | #define AC_CFG_PLEN_4 1 /* 4 bytes */ | ||
217 | #define AC_CFG_PLEN_8 2 /* 8 bytes */ | ||
218 | #define AC_CFG_PLEN_16 3 /* 16 bytes */ | ||
219 | #define AC_CFG_ALOC(v) (((v) & 0x1) << 3) /* Addr/len data is */ | ||
220 | /* explicit in buffers */ | ||
221 | #define AC_CFG_ADDRLEN(v) (((v) & 0x7) << 0) /* Bytes per address */ | ||
222 | unsigned char cfg_byte10; | ||
223 | #define AC_CFG_BOFMET(v) (((v) & 0x1) << 7) /* Use alternate expo. */ | ||
224 | /* backoff method */ | ||
225 | #define AC_CFG_ACR(v) (((v) & 0x7) << 4) /* Accelerated cont. res. */ | ||
226 | #define AC_CFG_LINPRIO(v) (((v) & 0x7) << 0) /* Linear priority */ | ||
227 | unsigned char cfg_ifs; /* Interframe spacing */ | ||
228 | unsigned char cfg_slotl; /* Slot time (low byte) */ | ||
229 | unsigned char cfg_byte13; | ||
230 | #define AC_CFG_RETRYNUM(v) (((v) & 0xF) << 4) /* Max. collision retry */ | ||
231 | #define AC_CFG_SLTTMHI(v) (((v) & 0x7) << 0) /* Slot time (high bits) */ | ||
232 | unsigned char cfg_byte14; | ||
233 | #define AC_CFG_FLGPAD(v) (((v) & 0x1) << 7) /* Pad with HDLC flags */ | ||
234 | #define AC_CFG_BTSTF(v) (((v) & 0x1) << 6) /* Do HDLC bitstuffing */ | ||
235 | #define AC_CFG_CRC16(v) (((v) & 0x1) << 5) /* 16 bit CCITT CRC */ | ||
236 | #define AC_CFG_NCRC(v) (((v) & 0x1) << 4) /* Insert no CRC */ | ||
237 | #define AC_CFG_TNCRS(v) (((v) & 0x1) << 3) /* Tx even if no carrier */ | ||
238 | #define AC_CFG_MANCH(v) (((v) & 0x1) << 2) /* Manchester coding */ | ||
239 | #define AC_CFG_BCDIS(v) (((v) & 0x1) << 1) /* Disable broadcast */ | ||
240 | #define AC_CFG_PRM(v) (((v) & 0x1) << 0) /* Promiscuous mode */ | ||
241 | unsigned char cfg_byte15; | ||
242 | #define AC_CFG_ICDS(v) (((v) & 0x1) << 7) /* Internal collision */ | ||
243 | /* detect source */ | ||
244 | #define AC_CFG_CDTF(v) (((v) & 0x7) << 4) /* Collision detect */ | ||
245 | /* filter in bit times */ | ||
246 | #define AC_CFG_ICSS(v) (((v) & 0x1) << 3) /* Internal carrier */ | ||
247 | /* sense source */ | ||
248 | #define AC_CFG_CSTF(v) (((v) & 0x7) << 0) /* Carrier sense */ | ||
249 | /* filter in bit times */ | ||
250 | unsigned short cfg_min_frm_len; | ||
251 | #define AC_CFG_MNFRM(v) (((v) & 0xFF) << 0) /* Min. bytes/frame (<= 255) */ | ||
252 | }; | ||
253 | |||
254 | /* | ||
255 | * The MC-Setup Action Command. | ||
256 | */ | ||
257 | typedef struct ac_mcs_t ac_mcs_t; | ||
258 | struct ac_mcs_t | ||
259 | { | ||
260 | ach_t mcs_h; | ||
261 | unsigned short mcs_cnt; /* No. of bytes of MC addresses */ | ||
262 | #if 0 | ||
263 | unsigned char mcs_data[ADDR_LEN]; /* The first MC address .. */ | ||
264 | ... | ||
265 | #endif | ||
266 | }; | ||
267 | |||
268 | #define I82586_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ | ||
269 | |||
270 | /* | ||
271 | * The Transmit Action Command. | ||
272 | */ | ||
273 | typedef struct ac_tx_t ac_tx_t; | ||
274 | struct ac_tx_t | ||
275 | { | ||
276 | ach_t tx_h; | ||
277 | unsigned short tx_tbd_offset; /* Address of list of buffers. */ | ||
278 | #if 0 | ||
279 | Linux packets are passed down with the destination MAC address | ||
280 | and length/type field already prepended to the data, | ||
281 | so we do not need to insert it. Consistent with this | ||
282 | we must also set the AC_CFG_ALOC(..) flag during the | ||
283 | ac_cfg_t action command. | ||
284 | unsigned char tx_addr[ADDR_LEN]; /* The frame dest. address */ | ||
285 | unsigned short tx_length; /* The frame length */ | ||
286 | #endif /* 0 */ | ||
287 | }; | ||
288 | |||
289 | /* | ||
290 | * The Time Domain Reflectometer Action Command. | ||
291 | */ | ||
292 | typedef struct ac_tdr_t ac_tdr_t; | ||
293 | struct ac_tdr_t | ||
294 | { | ||
295 | ach_t tdr_h; | ||
296 | unsigned short tdr_result; /* Result. */ | ||
297 | #define AC_TDR_LNK_OK (0x1 << 15) /* No link problem */ | ||
298 | #define AC_TDR_XCVR_PRB (0x1 << 14) /* Txcvr cable problem */ | ||
299 | #define AC_TDR_ET_OPN (0x1 << 13) /* Open on the link */ | ||
300 | #define AC_TDR_ET_SRT (0x1 << 12) /* Short on the link */ | ||
301 | #define AC_TDR_TIME (0x7FF << 0) /* Distance to problem */ | ||
302 | /* site in transmit */ | ||
303 | /* clock cycles */ | ||
304 | }; | ||
305 | |||
306 | /* | ||
307 | * The Dump Action Command. | ||
308 | */ | ||
309 | typedef struct ac_dmp_t ac_dmp_t; | ||
310 | struct ac_dmp_t | ||
311 | { | ||
312 | ach_t dmp_h; | ||
313 | unsigned short dmp_offset; /* Result. */ | ||
314 | }; | ||
315 | |||
316 | /* | ||
317 | * Size of the result of the dump command. | ||
318 | */ | ||
319 | #define DUMPBYTES 170 | ||
320 | |||
321 | /* | ||
322 | * The Diagnose Action Command. | ||
323 | */ | ||
324 | typedef struct ac_dgn_t ac_dgn_t; | ||
325 | struct ac_dgn_t | ||
326 | { | ||
327 | ach_t dgn_h; | ||
328 | }; | ||
329 | |||
330 | /* | ||
331 | * Transmit Buffer Descriptor (TBD). | ||
332 | */ | ||
333 | typedef struct tbd_t tbd_t; | ||
334 | struct tbd_t | ||
335 | { | ||
336 | unsigned short tbd_status; /* Written by the CPU */ | ||
337 | #define TBD_STATUS_EOF (0x1 << 15) /* This TBD is the */ | ||
338 | /* last for this frame */ | ||
339 | #define TBD_STATUS_ACNT (0x3FFF << 0) /* Actual count of data */ | ||
340 | /* bytes in this buffer */ | ||
341 | unsigned short tbd_next_bd_offset; /* Next in list */ | ||
342 | unsigned short tbd_bufl; /* Buffer address (low) */ | ||
343 | unsigned short tbd_bufh; /* " " (high) */ | ||
344 | }; | ||
345 | |||
346 | /* | ||
347 | * Receive Buffer Descriptor (RBD). | ||
348 | */ | ||
349 | typedef struct rbd_t rbd_t; | ||
350 | struct rbd_t | ||
351 | { | ||
352 | unsigned short rbd_status; /* Written by the 82586 */ | ||
353 | #define RBD_STATUS_EOF (0x1 << 15) /* This RBD is the */ | ||
354 | /* last for this frame */ | ||
355 | #define RBD_STATUS_F (0x1 << 14) /* ACNT field is valid */ | ||
356 | #define RBD_STATUS_ACNT (0x3FFF << 0) /* Actual no. of data */ | ||
357 | /* bytes in this buffer */ | ||
358 | unsigned short rbd_next_rbd_offset; /* Next rbd in list */ | ||
359 | unsigned short rbd_bufl; /* Data pointer (low) */ | ||
360 | unsigned short rbd_bufh; /* " " (high) */ | ||
361 | unsigned short rbd_el_size; /* EL+Data buf. size */ | ||
362 | #define RBD_EL (0x1 << 15) /* This BD is the */ | ||
363 | /* last in the list */ | ||
364 | #define RBD_SIZE (0x3FFF << 0) /* No. of bytes the */ | ||
365 | /* buffer can hold */ | ||
366 | }; | ||
367 | |||
368 | #define rbdoff(p,f) toff(rbd_t, p, f) | ||
369 | |||
370 | /* | ||
371 | * Frame Descriptor (FD). | ||
372 | */ | ||
373 | typedef struct fd_t fd_t; | ||
374 | struct fd_t | ||
375 | { | ||
376 | unsigned short fd_status; /* Written by the 82586 */ | ||
377 | #define FD_STATUS_C (0x1 << 15) /* Completed storing frame */ | ||
378 | #define FD_STATUS_B (0x1 << 14) /* FD was consumed by RU */ | ||
379 | #define FD_STATUS_OK (0x1 << 13) /* Frame rxd successfully */ | ||
380 | #define FD_STATUS_S11 (0x1 << 11) /* CRC error */ | ||
381 | #define FD_STATUS_S10 (0x1 << 10) /* Alignment error */ | ||
382 | #define FD_STATUS_S9 (0x1 << 9) /* Ran out of resources */ | ||
383 | #define FD_STATUS_S8 (0x1 << 8) /* Rx DMA overrun */ | ||
384 | #define FD_STATUS_S7 (0x1 << 7) /* Frame too short */ | ||
385 | #define FD_STATUS_S6 (0x1 << 6) /* No EOF flag */ | ||
386 | unsigned short fd_command; /* Command */ | ||
387 | #define FD_COMMAND_EL (0x1 << 15) /* Last FD in list */ | ||
388 | #define FD_COMMAND_S (0x1 << 14) /* Suspend RU after rx */ | ||
389 | unsigned short fd_link_offset; /* Next FD */ | ||
390 | unsigned short fd_rbd_offset; /* First RBD (data) */ | ||
391 | /* Prepared by CPU, */ | ||
392 | /* updated by 82586 */ | ||
393 | #if 0 | ||
394 | I think the rest is unused since we | ||
395 | have set AC_CFG_ALOC(..). However, just | ||
396 | in case, we leave the space. | ||
397 | #endif /* 0 */ | ||
398 | unsigned char fd_dest[ADDR_LEN]; /* Destination address */ | ||
399 | /* Written by 82586 */ | ||
400 | unsigned char fd_src[ADDR_LEN]; /* Source address */ | ||
401 | /* Written by 82586 */ | ||
402 | unsigned short fd_length; /* Frame length or type */ | ||
403 | /* Written by 82586 */ | ||
404 | }; | ||
405 | |||
406 | #define fdoff(p,f) toff(fd_t, p, f) | ||
407 | |||
408 | /* | ||
409 | * This software may only be used and distributed | ||
410 | * according to the terms of the GNU General Public License. | ||
411 | * | ||
412 | * For more details, see wavelan.c. | ||
413 | */ | ||
diff --git a/drivers/net/wireless/i82593.h b/drivers/net/wireless/i82593.h new file mode 100644 index 000000000000..33acb8add4d6 --- /dev/null +++ b/drivers/net/wireless/i82593.h | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * Definitions for Intel 82593 CSMA/CD Core LAN Controller | ||
3 | * The definitions are taken from the 1992 users manual with Intel | ||
4 | * order number 297125-001. | ||
5 | * | ||
6 | * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp | ||
7 | * | ||
8 | * Copyright 1994, Anders Klemets <klemets@it.kth.se> | ||
9 | * | ||
10 | * This software may be freely distributed for noncommercial purposes | ||
11 | * as long as this notice is retained. | ||
12 | * | ||
13 | * HISTORY | ||
14 | * i82593.h,v | ||
15 | * Revision 1.1 1996/07/17 15:23:12 root | ||
16 | * Initial revision | ||
17 | * | ||
18 | * Revision 1.3 1995/04/05 15:13:58 adj | ||
19 | * Initial alpha release | ||
20 | * | ||
21 | * Revision 1.2 1994/06/16 23:57:31 klemets | ||
22 | * Mirrored all the fields in the configuration block. | ||
23 | * | ||
24 | * Revision 1.1 1994/06/02 20:25:34 klemets | ||
25 | * Initial revision | ||
26 | * | ||
27 | * | ||
28 | */ | ||
29 | #ifndef _I82593_H | ||
30 | #define _I82593_H | ||
31 | |||
32 | /* Intel 82593 CSMA/CD Core LAN Controller */ | ||
33 | |||
34 | /* Port 0 Command Register definitions */ | ||
35 | |||
36 | /* Execution operations */ | ||
37 | #define OP0_NOP 0 /* CHNL = 0 */ | ||
38 | #define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ | ||
39 | #define OP0_IA_SETUP 1 | ||
40 | #define OP0_CONFIGURE 2 | ||
41 | #define OP0_MC_SETUP 3 | ||
42 | #define OP0_TRANSMIT 4 | ||
43 | #define OP0_TDR 5 | ||
44 | #define OP0_DUMP 6 | ||
45 | #define OP0_DIAGNOSE 7 | ||
46 | #define OP0_TRANSMIT_NO_CRC 9 | ||
47 | #define OP0_RETRANSMIT 12 | ||
48 | #define OP0_ABORT 13 | ||
49 | /* Reception operations */ | ||
50 | #define OP0_RCV_ENABLE 8 | ||
51 | #define OP0_RCV_DISABLE 10 | ||
52 | #define OP0_STOP_RCV 11 | ||
53 | /* Status pointer control operations */ | ||
54 | #define OP0_FIX_PTR 15 /* CHNL = 1 */ | ||
55 | #define OP0_RLS_PTR 15 /* CHNL = 0 */ | ||
56 | #define OP0_RESET 14 | ||
57 | |||
58 | #define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ | ||
59 | #define CR0_STATUS_0 0x00 | ||
60 | #define CR0_STATUS_1 0x20 | ||
61 | #define CR0_STATUS_2 0x40 | ||
62 | #define CR0_STATUS_3 0x60 | ||
63 | #define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ | ||
64 | |||
65 | /* Port 0 Status Register definitions */ | ||
66 | |||
67 | #define SR0_NO_RESULT 0 /* dummy */ | ||
68 | #define SR0_EVENT_MASK 0x0f | ||
69 | #define SR0_IA_SETUP_DONE 1 | ||
70 | #define SR0_CONFIGURE_DONE 2 | ||
71 | #define SR0_MC_SETUP_DONE 3 | ||
72 | #define SR0_TRANSMIT_DONE 4 | ||
73 | #define SR0_TDR_DONE 5 | ||
74 | #define SR0_DUMP_DONE 6 | ||
75 | #define SR0_DIAGNOSE_PASSED 7 | ||
76 | #define SR0_TRANSMIT_NO_CRC_DONE 9 | ||
77 | #define SR0_RETRANSMIT_DONE 12 | ||
78 | #define SR0_EXECUTION_ABORTED 13 | ||
79 | #define SR0_END_OF_FRAME 8 | ||
80 | #define SR0_RECEPTION_ABORTED 10 | ||
81 | #define SR0_DIAGNOSE_FAILED 15 | ||
82 | #define SR0_STOP_REG_HIT 11 | ||
83 | |||
84 | #define SR0_CHNL (1 << 4) | ||
85 | #define SR0_EXECUTION (1 << 5) | ||
86 | #define SR0_RECEPTION (1 << 6) | ||
87 | #define SR0_INTERRUPT (1 << 7) | ||
88 | #define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) | ||
89 | |||
90 | #define SR3_EXEC_STATE_MASK 0x03 | ||
91 | #define SR3_EXEC_IDLE 0 | ||
92 | #define SR3_TX_ABORT_IN_PROGRESS 1 | ||
93 | #define SR3_EXEC_ACTIVE 2 | ||
94 | #define SR3_ABORT_IN_PROGRESS 3 | ||
95 | #define SR3_EXEC_CHNL (1 << 2) | ||
96 | #define SR3_STP_ON_NO_RSRC (1 << 3) | ||
97 | #define SR3_RCVING_NO_RSRC (1 << 4) | ||
98 | #define SR3_RCV_STATE_MASK 0x60 | ||
99 | #define SR3_RCV_IDLE 0x00 | ||
100 | #define SR3_RCV_READY 0x20 | ||
101 | #define SR3_RCV_ACTIVE 0x40 | ||
102 | #define SR3_RCV_STOP_IN_PROG 0x60 | ||
103 | #define SR3_RCV_CHNL (1 << 7) | ||
104 | |||
105 | /* Port 1 Command Register definitions */ | ||
106 | |||
107 | #define OP1_NOP 0 | ||
108 | #define OP1_SWIT_TO_PORT_0 1 | ||
109 | #define OP1_INT_DISABLE 2 | ||
110 | #define OP1_INT_ENABLE 3 | ||
111 | #define OP1_SET_TS 5 | ||
112 | #define OP1_RST_TS 7 | ||
113 | #define OP1_POWER_DOWN 8 | ||
114 | #define OP1_RESET_RING_MNGMT 11 | ||
115 | #define OP1_RESET 14 | ||
116 | #define OP1_SEL_RST 15 | ||
117 | |||
118 | #define CR1_STATUS_4 0x00 | ||
119 | #define CR1_STATUS_5 0x20 | ||
120 | #define CR1_STATUS_6 0x40 | ||
121 | #define CR1_STOP_REG_UPDATE (1 << 7) | ||
122 | |||
123 | /* Receive frame status bits */ | ||
124 | |||
125 | #define RX_RCLD (1 << 0) | ||
126 | #define RX_IA_MATCH (1 << 1) | ||
127 | #define RX_NO_AD_MATCH (1 << 2) | ||
128 | #define RX_NO_SFD (1 << 3) | ||
129 | #define RX_SRT_FRM (1 << 7) | ||
130 | #define RX_OVRRUN (1 << 8) | ||
131 | #define RX_ALG_ERR (1 << 10) | ||
132 | #define RX_CRC_ERR (1 << 11) | ||
133 | #define RX_LEN_ERR (1 << 12) | ||
134 | #define RX_RCV_OK (1 << 13) | ||
135 | #define RX_TYP_LEN (1 << 15) | ||
136 | |||
137 | /* Transmit status bits */ | ||
138 | |||
139 | #define TX_NCOL_MASK 0x0f | ||
140 | #define TX_FRTL (1 << 4) | ||
141 | #define TX_MAX_COL (1 << 5) | ||
142 | #define TX_HRT_BEAT (1 << 6) | ||
143 | #define TX_DEFER (1 << 7) | ||
144 | #define TX_UND_RUN (1 << 8) | ||
145 | #define TX_LOST_CTS (1 << 9) | ||
146 | #define TX_LOST_CRS (1 << 10) | ||
147 | #define TX_LTCOL (1 << 11) | ||
148 | #define TX_OK (1 << 13) | ||
149 | #define TX_COLL (1 << 15) | ||
150 | |||
151 | struct i82593_conf_block { | ||
152 | u_char fifo_limit : 4, | ||
153 | forgnesi : 1, | ||
154 | fifo_32 : 1, | ||
155 | d6mod : 1, | ||
156 | throttle_enb : 1; | ||
157 | u_char throttle : 6, | ||
158 | cntrxint : 1, | ||
159 | contin : 1; | ||
160 | u_char addr_len : 3, | ||
161 | acloc : 1, | ||
162 | preamb_len : 2, | ||
163 | loopback : 2; | ||
164 | u_char lin_prio : 3, | ||
165 | tbofstop : 1, | ||
166 | exp_prio : 3, | ||
167 | bof_met : 1; | ||
168 | u_char : 4, | ||
169 | ifrm_spc : 4; | ||
170 | u_char : 5, | ||
171 | slottim_low : 3; | ||
172 | u_char slottim_hi : 3, | ||
173 | : 1, | ||
174 | max_retr : 4; | ||
175 | u_char prmisc : 1, | ||
176 | bc_dis : 1, | ||
177 | : 1, | ||
178 | crs_1 : 1, | ||
179 | nocrc_ins : 1, | ||
180 | crc_1632 : 1, | ||
181 | : 1, | ||
182 | crs_cdt : 1; | ||
183 | u_char cs_filter : 3, | ||
184 | crs_src : 1, | ||
185 | cd_filter : 3, | ||
186 | : 1; | ||
187 | u_char : 2, | ||
188 | min_fr_len : 6; | ||
189 | u_char lng_typ : 1, | ||
190 | lng_fld : 1, | ||
191 | rxcrc_xf : 1, | ||
192 | artx : 1, | ||
193 | sarec : 1, | ||
194 | tx_jabber : 1, /* why is this called max_len in the manual? */ | ||
195 | hash_1 : 1, | ||
196 | lbpkpol : 1; | ||
197 | u_char : 6, | ||
198 | fdx : 1, | ||
199 | : 1; | ||
200 | u_char dummy_6 : 6, /* supposed to be ones */ | ||
201 | mult_ia : 1, | ||
202 | dis_bof : 1; | ||
203 | u_char dummy_1 : 1, /* supposed to be one */ | ||
204 | tx_ifs_retrig : 2, | ||
205 | mc_all : 1, | ||
206 | rcv_mon : 2, | ||
207 | frag_acpt : 1, | ||
208 | tstrttrs : 1; | ||
209 | u_char fretx : 1, | ||
210 | runt_eop : 1, | ||
211 | hw_sw_pin : 1, | ||
212 | big_endn : 1, | ||
213 | syncrqs : 1, | ||
214 | sttlen : 1, | ||
215 | tx_eop : 1, | ||
216 | rx_eop : 1; | ||
217 | u_char rbuf_size : 5, | ||
218 | rcvstop : 1, | ||
219 | : 2; | ||
220 | }; | ||
221 | |||
222 | #define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ | ||
223 | |||
224 | #endif /* _I82593_H */ | ||
diff --git a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h new file mode 100644 index 000000000000..53dd5248f9f1 --- /dev/null +++ b/drivers/net/wireless/ieee802_11.h | |||
@@ -0,0 +1,78 @@ | |||
1 | #ifndef _IEEE802_11_H | ||
2 | #define _IEEE802_11_H | ||
3 | |||
4 | #define IEEE802_11_DATA_LEN 2304 | ||
5 | /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section | ||
6 | 6.2.1.1.2. | ||
7 | |||
8 | The figure in section 7.1.2 suggests a body size of up to 2312 | ||
9 | bytes is allowed, which is a bit confusing, I suspect this | ||
10 | represents the 2304 bytes of real data, plus a possible 8 bytes of | ||
11 | WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ | ||
12 | |||
13 | |||
14 | #define IEEE802_11_HLEN 30 | ||
15 | #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN) | ||
16 | |||
17 | struct ieee802_11_hdr { | ||
18 | u16 frame_ctl; | ||
19 | u16 duration_id; | ||
20 | u8 addr1[ETH_ALEN]; | ||
21 | u8 addr2[ETH_ALEN]; | ||
22 | u8 addr3[ETH_ALEN]; | ||
23 | u16 seq_ctl; | ||
24 | u8 addr4[ETH_ALEN]; | ||
25 | } __attribute__ ((packed)); | ||
26 | |||
27 | /* Frame control field constants */ | ||
28 | #define IEEE802_11_FCTL_VERS 0x0002 | ||
29 | #define IEEE802_11_FCTL_FTYPE 0x000c | ||
30 | #define IEEE802_11_FCTL_STYPE 0x00f0 | ||
31 | #define IEEE802_11_FCTL_TODS 0x0100 | ||
32 | #define IEEE802_11_FCTL_FROMDS 0x0200 | ||
33 | #define IEEE802_11_FCTL_MOREFRAGS 0x0400 | ||
34 | #define IEEE802_11_FCTL_RETRY 0x0800 | ||
35 | #define IEEE802_11_FCTL_PM 0x1000 | ||
36 | #define IEEE802_11_FCTL_MOREDATA 0x2000 | ||
37 | #define IEEE802_11_FCTL_WEP 0x4000 | ||
38 | #define IEEE802_11_FCTL_ORDER 0x8000 | ||
39 | |||
40 | #define IEEE802_11_FTYPE_MGMT 0x0000 | ||
41 | #define IEEE802_11_FTYPE_CTL 0x0004 | ||
42 | #define IEEE802_11_FTYPE_DATA 0x0008 | ||
43 | |||
44 | /* management */ | ||
45 | #define IEEE802_11_STYPE_ASSOC_REQ 0x0000 | ||
46 | #define IEEE802_11_STYPE_ASSOC_RESP 0x0010 | ||
47 | #define IEEE802_11_STYPE_REASSOC_REQ 0x0020 | ||
48 | #define IEEE802_11_STYPE_REASSOC_RESP 0x0030 | ||
49 | #define IEEE802_11_STYPE_PROBE_REQ 0x0040 | ||
50 | #define IEEE802_11_STYPE_PROBE_RESP 0x0050 | ||
51 | #define IEEE802_11_STYPE_BEACON 0x0080 | ||
52 | #define IEEE802_11_STYPE_ATIM 0x0090 | ||
53 | #define IEEE802_11_STYPE_DISASSOC 0x00A0 | ||
54 | #define IEEE802_11_STYPE_AUTH 0x00B0 | ||
55 | #define IEEE802_11_STYPE_DEAUTH 0x00C0 | ||
56 | |||
57 | /* control */ | ||
58 | #define IEEE802_11_STYPE_PSPOLL 0x00A0 | ||
59 | #define IEEE802_11_STYPE_RTS 0x00B0 | ||
60 | #define IEEE802_11_STYPE_CTS 0x00C0 | ||
61 | #define IEEE802_11_STYPE_ACK 0x00D0 | ||
62 | #define IEEE802_11_STYPE_CFEND 0x00E0 | ||
63 | #define IEEE802_11_STYPE_CFENDACK 0x00F0 | ||
64 | |||
65 | /* data */ | ||
66 | #define IEEE802_11_STYPE_DATA 0x0000 | ||
67 | #define IEEE802_11_STYPE_DATA_CFACK 0x0010 | ||
68 | #define IEEE802_11_STYPE_DATA_CFPOLL 0x0020 | ||
69 | #define IEEE802_11_STYPE_DATA_CFACKPOLL 0x0030 | ||
70 | #define IEEE802_11_STYPE_NULLFUNC 0x0040 | ||
71 | #define IEEE802_11_STYPE_CFACK 0x0050 | ||
72 | #define IEEE802_11_STYPE_CFPOLL 0x0060 | ||
73 | #define IEEE802_11_STYPE_CFACKPOLL 0x0070 | ||
74 | |||
75 | #define IEEE802_11_SCTL_FRAG 0x000F | ||
76 | #define IEEE802_11_SCTL_SEQ 0xFFF0 | ||
77 | |||
78 | #endif /* _IEEE802_11_H */ | ||
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c new file mode 100644 index 000000000000..382241e7edbb --- /dev/null +++ b/drivers/net/wireless/netwave_cs.c | |||
@@ -0,0 +1,1736 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: netwave_cs.c | ||
4 | * Version: 0.4.1 | ||
5 | * Description: Netwave AirSurfer Wireless LAN PC Card driver | ||
6 | * Status: Experimental. | ||
7 | * Authors: John Markus Bjørndalen <johnm@cs.uit.no> | ||
8 | * Dag Brattli <dagb@cs.uit.no> | ||
9 | * David Hinds <dahinds@users.sourceforge.net> | ||
10 | * Created at: A long time ago! | ||
11 | * Modified at: Mon Nov 10 11:54:37 1997 | ||
12 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
13 | * | ||
14 | * Copyright (c) 1997 University of Tromsø, Norway | ||
15 | * | ||
16 | * Revision History: | ||
17 | * | ||
18 | * 08-Nov-97 15:14:47 John Markus Bjørndalen <johnm@cs.uit.no> | ||
19 | * - Fixed some bugs in netwave_rx and cleaned it up a bit. | ||
20 | * (One of the bugs would have destroyed packets when receiving | ||
21 | * multiple packets per interrupt). | ||
22 | * - Cleaned up parts of newave_hw_xmit. | ||
23 | * - A few general cleanups. | ||
24 | * 24-Oct-97 13:17:36 Dag Brattli <dagb@cs.uit.no> | ||
25 | * - Fixed netwave_rx receive function (got updated docs) | ||
26 | * Others: | ||
27 | * - Changed name from xircnw to netwave, take a look at | ||
28 | * http://www.netwave-wireless.com | ||
29 | * - Some reorganizing of the code | ||
30 | * - Removed possible race condition between interrupt handler and transmit | ||
31 | * function | ||
32 | * - Started to add wireless extensions, but still needs some coding | ||
33 | * - Added watchdog for better handling of transmission timeouts | ||
34 | * (hopefully this works better) | ||
35 | ********************************************************************/ | ||
36 | |||
37 | /* To have statistics (just packets sent) define this */ | ||
38 | #undef NETWAVE_STATS | ||
39 | |||
40 | #include <linux/config.h> | ||
41 | #include <linux/module.h> | ||
42 | #include <linux/kernel.h> | ||
43 | #include <linux/init.h> | ||
44 | #include <linux/types.h> | ||
45 | #include <linux/fcntl.h> | ||
46 | #include <linux/interrupt.h> | ||
47 | #include <linux/ptrace.h> | ||
48 | #include <linux/ioport.h> | ||
49 | #include <linux/in.h> | ||
50 | #include <linux/slab.h> | ||
51 | #include <linux/string.h> | ||
52 | #include <linux/timer.h> | ||
53 | #include <linux/errno.h> | ||
54 | #include <linux/netdevice.h> | ||
55 | #include <linux/etherdevice.h> | ||
56 | #include <linux/skbuff.h> | ||
57 | #include <linux/bitops.h> | ||
58 | #ifdef CONFIG_NET_RADIO | ||
59 | #include <linux/wireless.h> | ||
60 | #if WIRELESS_EXT > 12 | ||
61 | #include <net/iw_handler.h> | ||
62 | #endif /* WIRELESS_EXT > 12 */ | ||
63 | #endif | ||
64 | |||
65 | #include <pcmcia/version.h> | ||
66 | #include <pcmcia/cs_types.h> | ||
67 | #include <pcmcia/cs.h> | ||
68 | #include <pcmcia/cistpl.h> | ||
69 | #include <pcmcia/cisreg.h> | ||
70 | #include <pcmcia/ds.h> | ||
71 | #include <pcmcia/mem_op.h> | ||
72 | |||
73 | #include <asm/system.h> | ||
74 | #include <asm/io.h> | ||
75 | #include <asm/dma.h> | ||
76 | |||
77 | #define NETWAVE_REGOFF 0x8000 | ||
78 | /* The Netwave IO registers, offsets to iobase */ | ||
79 | #define NETWAVE_REG_COR 0x0 | ||
80 | #define NETWAVE_REG_CCSR 0x2 | ||
81 | #define NETWAVE_REG_ASR 0x4 | ||
82 | #define NETWAVE_REG_IMR 0xa | ||
83 | #define NETWAVE_REG_PMR 0xc | ||
84 | #define NETWAVE_REG_IOLOW 0x6 | ||
85 | #define NETWAVE_REG_IOHI 0x7 | ||
86 | #define NETWAVE_REG_IOCONTROL 0x8 | ||
87 | #define NETWAVE_REG_DATA 0xf | ||
88 | /* The Netwave Extended IO registers, offsets to RamBase */ | ||
89 | #define NETWAVE_EREG_ASCC 0x114 | ||
90 | #define NETWAVE_EREG_RSER 0x120 | ||
91 | #define NETWAVE_EREG_RSERW 0x124 | ||
92 | #define NETWAVE_EREG_TSER 0x130 | ||
93 | #define NETWAVE_EREG_TSERW 0x134 | ||
94 | #define NETWAVE_EREG_CB 0x100 | ||
95 | #define NETWAVE_EREG_SPCQ 0x154 | ||
96 | #define NETWAVE_EREG_SPU 0x155 | ||
97 | #define NETWAVE_EREG_LIF 0x14e | ||
98 | #define NETWAVE_EREG_ISPLQ 0x156 | ||
99 | #define NETWAVE_EREG_HHC 0x158 | ||
100 | #define NETWAVE_EREG_NI 0x16e | ||
101 | #define NETWAVE_EREG_MHS 0x16b | ||
102 | #define NETWAVE_EREG_TDP 0x140 | ||
103 | #define NETWAVE_EREG_RDP 0x150 | ||
104 | #define NETWAVE_EREG_PA 0x160 | ||
105 | #define NETWAVE_EREG_EC 0x180 | ||
106 | #define NETWAVE_EREG_CRBP 0x17a | ||
107 | #define NETWAVE_EREG_ARW 0x166 | ||
108 | |||
109 | /* | ||
110 | * Commands used in the extended command buffer | ||
111 | * NETWAVE_EREG_CB (0x100-0x10F) | ||
112 | */ | ||
113 | #define NETWAVE_CMD_NOP 0x00 | ||
114 | #define NETWAVE_CMD_SRC 0x01 | ||
115 | #define NETWAVE_CMD_STC 0x02 | ||
116 | #define NETWAVE_CMD_AMA 0x03 | ||
117 | #define NETWAVE_CMD_DMA 0x04 | ||
118 | #define NETWAVE_CMD_SAMA 0x05 | ||
119 | #define NETWAVE_CMD_ER 0x06 | ||
120 | #define NETWAVE_CMD_DR 0x07 | ||
121 | #define NETWAVE_CMD_TL 0x08 | ||
122 | #define NETWAVE_CMD_SRP 0x09 | ||
123 | #define NETWAVE_CMD_SSK 0x0a | ||
124 | #define NETWAVE_CMD_SMD 0x0b | ||
125 | #define NETWAVE_CMD_SAPD 0x0c | ||
126 | #define NETWAVE_CMD_SSS 0x11 | ||
127 | /* End of Command marker */ | ||
128 | #define NETWAVE_CMD_EOC 0x00 | ||
129 | |||
130 | /* ASR register bits */ | ||
131 | #define NETWAVE_ASR_RXRDY 0x80 | ||
132 | #define NETWAVE_ASR_TXBA 0x01 | ||
133 | |||
134 | #define TX_TIMEOUT ((32*HZ)/100) | ||
135 | |||
136 | static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */ | ||
137 | static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */ | ||
138 | |||
139 | static const unsigned int corConfIENA = 0x01; /* Interrupt enable */ | ||
140 | static const unsigned int corConfLVLREQ = 0x40; /* Keep high */ | ||
141 | |||
142 | static const unsigned int rxConfRxEna = 0x80; /* Receive Enable */ | ||
143 | static const unsigned int rxConfMAC = 0x20; /* MAC host receive mode*/ | ||
144 | static const unsigned int rxConfPro = 0x10; /* Promiscuous */ | ||
145 | static const unsigned int rxConfAMP = 0x08; /* Accept Multicast Packets */ | ||
146 | static const unsigned int rxConfBcast = 0x04; /* Accept Broadcast Packets */ | ||
147 | |||
148 | static const unsigned int txConfTxEna = 0x80; /* Transmit Enable */ | ||
149 | static const unsigned int txConfMAC = 0x20; /* Host sends MAC mode */ | ||
150 | static const unsigned int txConfEUD = 0x10; /* Enable Uni-Data packets */ | ||
151 | static const unsigned int txConfKey = 0x02; /* Scramble data packets */ | ||
152 | static const unsigned int txConfLoop = 0x01; /* Loopback mode */ | ||
153 | |||
154 | /* | ||
155 | All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If | ||
156 | you do not define PCMCIA_DEBUG at all, all the debug code will be | ||
157 | left out. If you compile with PCMCIA_DEBUG=0, the debug code will | ||
158 | be present but disabled -- but it can then be enabled for specific | ||
159 | modules at load time with a 'pc_debug=#' option to insmod. | ||
160 | */ | ||
161 | |||
162 | #ifdef PCMCIA_DEBUG | ||
163 | static int pc_debug = PCMCIA_DEBUG; | ||
164 | module_param(pc_debug, int, 0); | ||
165 | #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) | ||
166 | static char *version = | ||
167 | "netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; | ||
168 | #else | ||
169 | #define DEBUG(n, args...) | ||
170 | #endif | ||
171 | |||
172 | static dev_info_t dev_info = "netwave_cs"; | ||
173 | |||
174 | /*====================================================================*/ | ||
175 | |||
176 | /* Parameters that can be set with 'insmod' */ | ||
177 | |||
178 | /* Choose the domain, default is 0x100 */ | ||
179 | static u_int domain = 0x100; | ||
180 | |||
181 | /* Scramble key, range from 0x0 to 0xffff. | ||
182 | * 0x0 is no scrambling. | ||
183 | */ | ||
184 | static u_int scramble_key = 0x0; | ||
185 | |||
186 | /* Shared memory speed, in ns. The documentation states that | ||
187 | * the card should not be read faster than every 400ns. | ||
188 | * This timing should be provided by the HBA. If it becomes a | ||
189 | * problem, try setting mem_speed to 400. | ||
190 | */ | ||
191 | static int mem_speed; | ||
192 | |||
193 | module_param(domain, int, 0); | ||
194 | module_param(scramble_key, int, 0); | ||
195 | module_param(mem_speed, int, 0); | ||
196 | |||
197 | /*====================================================================*/ | ||
198 | |||
199 | /* PCMCIA (Card Services) related functions */ | ||
200 | static void netwave_release(dev_link_t *link); /* Card removal */ | ||
201 | static int netwave_event(event_t event, int priority, | ||
202 | event_callback_args_t *args); | ||
203 | static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card | ||
204 | insertion */ | ||
205 | static dev_link_t *netwave_attach(void); /* Create instance */ | ||
206 | static void netwave_detach(dev_link_t *); /* Destroy instance */ | ||
207 | |||
208 | /* Hardware configuration */ | ||
209 | static void netwave_doreset(kio_addr_t iobase, u_char __iomem *ramBase); | ||
210 | static void netwave_reset(struct net_device *dev); | ||
211 | |||
212 | /* Misc device stuff */ | ||
213 | static int netwave_open(struct net_device *dev); /* Open the device */ | ||
214 | static int netwave_close(struct net_device *dev); /* Close the device */ | ||
215 | |||
216 | /* Packet transmission and Packet reception */ | ||
217 | static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); | ||
218 | static int netwave_rx( struct net_device *dev); | ||
219 | |||
220 | /* Interrupt routines */ | ||
221 | static irqreturn_t netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
222 | static void netwave_watchdog(struct net_device *); | ||
223 | |||
224 | /* Statistics */ | ||
225 | static void update_stats(struct net_device *dev); | ||
226 | static struct net_device_stats *netwave_get_stats(struct net_device *dev); | ||
227 | |||
228 | /* Wireless extensions */ | ||
229 | #ifdef WIRELESS_EXT | ||
230 | static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); | ||
231 | #endif | ||
232 | static int netwave_ioctl(struct net_device *, struct ifreq *, int); | ||
233 | |||
234 | static void set_multicast_list(struct net_device *dev); | ||
235 | |||
236 | /* | ||
237 | A linked list of "instances" of the skeleton device. Each actual | ||
238 | PCMCIA card corresponds to one device instance, and is described | ||
239 | by one dev_link_t structure (defined in ds.h). | ||
240 | |||
241 | You may not want to use a linked list for this -- for example, the | ||
242 | memory card driver uses an array of dev_link_t pointers, where minor | ||
243 | device numbers are used to derive the corresponding array index. | ||
244 | */ | ||
245 | static dev_link_t *dev_list; | ||
246 | |||
247 | /* | ||
248 | A dev_link_t structure has fields for most things that are needed | ||
249 | to keep track of a socket, but there will usually be some device | ||
250 | specific information that also needs to be kept track of. The | ||
251 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
252 | a device-specific private data structure, like this. | ||
253 | |||
254 | A driver needs to provide a dev_node_t structure for each device | ||
255 | on a card. In some cases, there is only one device per card (for | ||
256 | example, ethernet cards, modems). In other cases, there may be | ||
257 | many actual or logical devices (SCSI adapters, memory cards with | ||
258 | multiple partitions). The dev_node_t structures need to be kept | ||
259 | in a linked list starting at the 'dev' field of a dev_link_t | ||
260 | structure. We allocate them in the card's private data structure, | ||
261 | because they generally can't be allocated dynamically. | ||
262 | */ | ||
263 | |||
264 | #if WIRELESS_EXT <= 12 | ||
265 | /* Wireless extensions backward compatibility */ | ||
266 | |||
267 | /* Part of iw_handler prototype we need */ | ||
268 | struct iw_request_info | ||
269 | { | ||
270 | __u16 cmd; /* Wireless Extension command */ | ||
271 | __u16 flags; /* More to come ;-) */ | ||
272 | }; | ||
273 | |||
274 | /* Wireless Extension Backward compatibility - Jean II | ||
275 | * If the new wireless device private ioctl range is not defined, | ||
276 | * default to standard device private ioctl range */ | ||
277 | #ifndef SIOCIWFIRSTPRIV | ||
278 | #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE | ||
279 | #endif /* SIOCIWFIRSTPRIV */ | ||
280 | |||
281 | #else /* WIRELESS_EXT <= 12 */ | ||
282 | static const struct iw_handler_def netwave_handler_def; | ||
283 | #endif /* WIRELESS_EXT <= 12 */ | ||
284 | |||
285 | #define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ | ||
286 | |||
287 | #define MAX_ESA 10 | ||
288 | |||
289 | typedef struct net_addr { | ||
290 | u_char addr48[6]; | ||
291 | } net_addr; | ||
292 | |||
293 | struct site_survey { | ||
294 | u_short length; | ||
295 | u_char struct_revision; | ||
296 | u_char roaming_state; | ||
297 | |||
298 | u_char sp_existsFlag; | ||
299 | u_char sp_link_quality; | ||
300 | u_char sp_max_link_quality; | ||
301 | u_char linkQualityGoodFairBoundary; | ||
302 | u_char linkQualityFairPoorBoundary; | ||
303 | u_char sp_utilization; | ||
304 | u_char sp_goodness; | ||
305 | u_char sp_hotheadcount; | ||
306 | u_char roaming_condition; | ||
307 | |||
308 | net_addr sp; | ||
309 | u_char numAPs; | ||
310 | net_addr nearByAccessPoints[MAX_ESA]; | ||
311 | }; | ||
312 | |||
313 | typedef struct netwave_private { | ||
314 | dev_link_t link; | ||
315 | spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ | ||
316 | dev_node_t node; | ||
317 | u_char __iomem *ramBase; | ||
318 | int timeoutCounter; | ||
319 | int lastExec; | ||
320 | struct timer_list watchdog; /* To avoid blocking state */ | ||
321 | struct site_survey nss; | ||
322 | struct net_device_stats stats; | ||
323 | #ifdef WIRELESS_EXT | ||
324 | struct iw_statistics iw_stats; /* Wireless stats */ | ||
325 | #endif | ||
326 | } netwave_private; | ||
327 | |||
328 | #ifdef NETWAVE_STATS | ||
329 | static struct net_device_stats *netwave_get_stats(struct net_device *dev); | ||
330 | #endif | ||
331 | |||
332 | /* | ||
333 | * The Netwave card is little-endian, so won't work for big endian | ||
334 | * systems. | ||
335 | */ | ||
336 | static inline unsigned short get_uint16(u_char __iomem *staddr) | ||
337 | { | ||
338 | return readw(staddr); /* Return only 16 bits */ | ||
339 | } | ||
340 | |||
341 | static inline short get_int16(u_char __iomem * staddr) | ||
342 | { | ||
343 | return readw(staddr); | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Wait until the WOC (Write Operation Complete) bit in the | ||
348 | * ASR (Adapter Status Register) is asserted. | ||
349 | * This should have aborted if it takes too long time. | ||
350 | */ | ||
351 | static inline void wait_WOC(unsigned int iobase) | ||
352 | { | ||
353 | /* Spin lock */ | ||
354 | while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; | ||
355 | } | ||
356 | |||
357 | #ifdef WIRELESS_EXT | ||
358 | static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, | ||
359 | kio_addr_t iobase) { | ||
360 | u_short resultBuffer; | ||
361 | |||
362 | /* if time since last snapshot is > 1 sec. (100 jiffies?) then take | ||
363 | * new snapshot, else return cached data. This is the recommended rate. | ||
364 | */ | ||
365 | if ( jiffies - priv->lastExec > 100) { | ||
366 | /* Take site survey snapshot */ | ||
367 | /*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies - | ||
368 | priv->lastExec); */ | ||
369 | wait_WOC(iobase); | ||
370 | writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); | ||
371 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); | ||
372 | wait_WOC(iobase); | ||
373 | |||
374 | /* Get result and copy to cach */ | ||
375 | resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); | ||
376 | copy_from_pc( &priv->nss, ramBase+resultBuffer, | ||
377 | sizeof(struct site_survey)); | ||
378 | } | ||
379 | } | ||
380 | #endif | ||
381 | |||
382 | #ifdef WIRELESS_EXT | ||
383 | /* | ||
384 | * Function netwave_get_wireless_stats (dev) | ||
385 | * | ||
386 | * Wireless extensions statistics | ||
387 | * | ||
388 | */ | ||
389 | static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) | ||
390 | { | ||
391 | unsigned long flags; | ||
392 | kio_addr_t iobase = dev->base_addr; | ||
393 | netwave_private *priv = netdev_priv(dev); | ||
394 | u_char __iomem *ramBase = priv->ramBase; | ||
395 | struct iw_statistics* wstats; | ||
396 | |||
397 | wstats = &priv->iw_stats; | ||
398 | |||
399 | spin_lock_irqsave(&priv->spinlock, flags); | ||
400 | |||
401 | netwave_snapshot( priv, ramBase, iobase); | ||
402 | |||
403 | wstats->status = priv->nss.roaming_state; | ||
404 | wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); | ||
405 | wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ); | ||
406 | wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f; | ||
407 | wstats->discard.nwid = 0L; | ||
408 | wstats->discard.code = 0L; | ||
409 | wstats->discard.misc = 0L; | ||
410 | |||
411 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
412 | |||
413 | return &priv->iw_stats; | ||
414 | } | ||
415 | #endif | ||
416 | |||
417 | /* | ||
418 | * Function netwave_attach (void) | ||
419 | * | ||
420 | * Creates an "instance" of the driver, allocating local data | ||
421 | * structures for one device. The device is registered with Card | ||
422 | * Services. | ||
423 | * | ||
424 | * The dev_link structure is initialized, but we don't actually | ||
425 | * configure the card at this point -- we wait until we receive a | ||
426 | * card insertion event. | ||
427 | */ | ||
428 | static dev_link_t *netwave_attach(void) | ||
429 | { | ||
430 | client_reg_t client_reg; | ||
431 | dev_link_t *link; | ||
432 | struct net_device *dev; | ||
433 | netwave_private *priv; | ||
434 | int ret; | ||
435 | |||
436 | DEBUG(0, "netwave_attach()\n"); | ||
437 | |||
438 | /* Initialize the dev_link_t structure */ | ||
439 | dev = alloc_etherdev(sizeof(netwave_private)); | ||
440 | if (!dev) | ||
441 | return NULL; | ||
442 | priv = netdev_priv(dev); | ||
443 | link = &priv->link; | ||
444 | link->priv = dev; | ||
445 | |||
446 | /* The io structure describes IO port mapping */ | ||
447 | link->io.NumPorts1 = 16; | ||
448 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
449 | /* link->io.NumPorts2 = 16; | ||
450 | link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */ | ||
451 | link->io.IOAddrLines = 5; | ||
452 | |||
453 | /* Interrupt setup */ | ||
454 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
455 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
456 | link->irq.Handler = &netwave_interrupt; | ||
457 | |||
458 | /* General socket configuration */ | ||
459 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
460 | link->conf.Vcc = 50; | ||
461 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
462 | link->conf.ConfigIndex = 1; | ||
463 | link->conf.Present = PRESENT_OPTION; | ||
464 | |||
465 | /* Netwave private struct init. link/dev/node already taken care of, | ||
466 | * other stuff zero'd - Jean II */ | ||
467 | spin_lock_init(&priv->spinlock); | ||
468 | |||
469 | /* Netwave specific entries in the device structure */ | ||
470 | SET_MODULE_OWNER(dev); | ||
471 | dev->hard_start_xmit = &netwave_start_xmit; | ||
472 | dev->get_stats = &netwave_get_stats; | ||
473 | dev->set_multicast_list = &set_multicast_list; | ||
474 | /* wireless extensions */ | ||
475 | #ifdef WIRELESS_EXT | ||
476 | dev->get_wireless_stats = &netwave_get_wireless_stats; | ||
477 | #if WIRELESS_EXT > 12 | ||
478 | dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def; | ||
479 | #endif /* WIRELESS_EXT > 12 */ | ||
480 | #endif /* WIRELESS_EXT */ | ||
481 | dev->do_ioctl = &netwave_ioctl; | ||
482 | |||
483 | dev->tx_timeout = &netwave_watchdog; | ||
484 | dev->watchdog_timeo = TX_TIMEOUT; | ||
485 | |||
486 | dev->open = &netwave_open; | ||
487 | dev->stop = &netwave_close; | ||
488 | link->irq.Instance = dev; | ||
489 | |||
490 | /* Register with Card Services */ | ||
491 | link->next = dev_list; | ||
492 | dev_list = link; | ||
493 | client_reg.dev_info = &dev_info; | ||
494 | client_reg.EventMask = | ||
495 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
496 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
497 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
498 | client_reg.event_handler = &netwave_event; | ||
499 | client_reg.Version = 0x0210; | ||
500 | client_reg.event_callback_args.client_data = link; | ||
501 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
502 | if (ret != 0) { | ||
503 | cs_error(link->handle, RegisterClient, ret); | ||
504 | netwave_detach(link); | ||
505 | return NULL; | ||
506 | } | ||
507 | |||
508 | return link; | ||
509 | } /* netwave_attach */ | ||
510 | |||
511 | /* | ||
512 | * Function netwave_detach (link) | ||
513 | * | ||
514 | * This deletes a driver "instance". The device is de-registered | ||
515 | * with Card Services. If it has been released, all local data | ||
516 | * structures are freed. Otherwise, the structures will be freed | ||
517 | * when the device is released. | ||
518 | */ | ||
519 | static void netwave_detach(dev_link_t *link) | ||
520 | { | ||
521 | struct net_device *dev = link->priv; | ||
522 | dev_link_t **linkp; | ||
523 | |||
524 | DEBUG(0, "netwave_detach(0x%p)\n", link); | ||
525 | |||
526 | /* | ||
527 | If the device is currently configured and active, we won't | ||
528 | actually delete it yet. Instead, it is marked so that when | ||
529 | the release() function is called, that will trigger a proper | ||
530 | detach(). | ||
531 | */ | ||
532 | if (link->state & DEV_CONFIG) | ||
533 | netwave_release(link); | ||
534 | |||
535 | /* Break the link with Card Services */ | ||
536 | if (link->handle) | ||
537 | pcmcia_deregister_client(link->handle); | ||
538 | |||
539 | /* Locate device structure */ | ||
540 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
541 | if (*linkp == link) break; | ||
542 | if (*linkp == NULL) | ||
543 | { | ||
544 | DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n", | ||
545 | link->dev->dev_name); | ||
546 | return; | ||
547 | } | ||
548 | |||
549 | /* Unlink device structure, free pieces */ | ||
550 | *linkp = link->next; | ||
551 | if (link->dev) | ||
552 | unregister_netdev(dev); | ||
553 | free_netdev(dev); | ||
554 | |||
555 | } /* netwave_detach */ | ||
556 | |||
557 | /* | ||
558 | * Wireless Handler : get protocol name | ||
559 | */ | ||
560 | static int netwave_get_name(struct net_device *dev, | ||
561 | struct iw_request_info *info, | ||
562 | union iwreq_data *wrqu, | ||
563 | char *extra) | ||
564 | { | ||
565 | strcpy(wrqu->name, "Netwave"); | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | /* | ||
570 | * Wireless Handler : set Network ID | ||
571 | */ | ||
572 | static int netwave_set_nwid(struct net_device *dev, | ||
573 | struct iw_request_info *info, | ||
574 | union iwreq_data *wrqu, | ||
575 | char *extra) | ||
576 | { | ||
577 | unsigned long flags; | ||
578 | kio_addr_t iobase = dev->base_addr; | ||
579 | netwave_private *priv = netdev_priv(dev); | ||
580 | u_char __iomem *ramBase = priv->ramBase; | ||
581 | |||
582 | /* Disable interrupts & save flags */ | ||
583 | spin_lock_irqsave(&priv->spinlock, flags); | ||
584 | |||
585 | #if WIRELESS_EXT > 8 | ||
586 | if(!wrqu->nwid.disabled) { | ||
587 | domain = wrqu->nwid.value; | ||
588 | #else /* WIRELESS_EXT > 8 */ | ||
589 | if(wrqu->nwid.on) { | ||
590 | domain = wrqu->nwid.nwid; | ||
591 | #endif /* WIRELESS_EXT > 8 */ | ||
592 | printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", | ||
593 | (domain >> 8) & 0x01, domain & 0xff); | ||
594 | wait_WOC(iobase); | ||
595 | writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); | ||
596 | writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); | ||
597 | writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); | ||
598 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); | ||
599 | } | ||
600 | |||
601 | /* ReEnable interrupts & restore flags */ | ||
602 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Wireless Handler : get Network ID | ||
609 | */ | ||
610 | static int netwave_get_nwid(struct net_device *dev, | ||
611 | struct iw_request_info *info, | ||
612 | union iwreq_data *wrqu, | ||
613 | char *extra) | ||
614 | { | ||
615 | #if WIRELESS_EXT > 8 | ||
616 | wrqu->nwid.value = domain; | ||
617 | wrqu->nwid.disabled = 0; | ||
618 | wrqu->nwid.fixed = 1; | ||
619 | #else /* WIRELESS_EXT > 8 */ | ||
620 | wrqu->nwid.nwid = domain; | ||
621 | wrqu->nwid.on = 1; | ||
622 | #endif /* WIRELESS_EXT > 8 */ | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | /* | ||
628 | * Wireless Handler : set scramble key | ||
629 | */ | ||
630 | static int netwave_set_scramble(struct net_device *dev, | ||
631 | struct iw_request_info *info, | ||
632 | union iwreq_data *wrqu, | ||
633 | char *key) | ||
634 | { | ||
635 | unsigned long flags; | ||
636 | kio_addr_t iobase = dev->base_addr; | ||
637 | netwave_private *priv = netdev_priv(dev); | ||
638 | u_char __iomem *ramBase = priv->ramBase; | ||
639 | |||
640 | /* Disable interrupts & save flags */ | ||
641 | spin_lock_irqsave(&priv->spinlock, flags); | ||
642 | |||
643 | scramble_key = (key[0] << 8) | key[1]; | ||
644 | wait_WOC(iobase); | ||
645 | writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); | ||
646 | writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); | ||
647 | writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); | ||
648 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); | ||
649 | |||
650 | /* ReEnable interrupts & restore flags */ | ||
651 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * Wireless Handler : get scramble key | ||
658 | */ | ||
659 | static int netwave_get_scramble(struct net_device *dev, | ||
660 | struct iw_request_info *info, | ||
661 | union iwreq_data *wrqu, | ||
662 | char *key) | ||
663 | { | ||
664 | key[1] = scramble_key & 0xff; | ||
665 | key[0] = (scramble_key>>8) & 0xff; | ||
666 | #if WIRELESS_EXT > 8 | ||
667 | wrqu->encoding.flags = IW_ENCODE_ENABLED; | ||
668 | wrqu->encoding.length = 2; | ||
669 | #else /* WIRELESS_EXT > 8 */ | ||
670 | wrqu->encoding.method = 1; | ||
671 | #endif /* WIRELESS_EXT > 8 */ | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | #if WIRELESS_EXT > 8 | ||
677 | /* | ||
678 | * Wireless Handler : get mode | ||
679 | */ | ||
680 | static int netwave_get_mode(struct net_device *dev, | ||
681 | struct iw_request_info *info, | ||
682 | union iwreq_data *wrqu, | ||
683 | char *extra) | ||
684 | { | ||
685 | if(domain & 0x100) | ||
686 | wrqu->mode = IW_MODE_INFRA; | ||
687 | else | ||
688 | wrqu->mode = IW_MODE_ADHOC; | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | #endif /* WIRELESS_EXT > 8 */ | ||
693 | |||
694 | /* | ||
695 | * Wireless Handler : get range info | ||
696 | */ | ||
697 | static int netwave_get_range(struct net_device *dev, | ||
698 | struct iw_request_info *info, | ||
699 | union iwreq_data *wrqu, | ||
700 | char *extra) | ||
701 | { | ||
702 | struct iw_range *range = (struct iw_range *) extra; | ||
703 | int ret = 0; | ||
704 | |||
705 | /* Set the length (very important for backward compatibility) */ | ||
706 | wrqu->data.length = sizeof(struct iw_range); | ||
707 | |||
708 | /* Set all the info we don't care or don't know about to zero */ | ||
709 | memset(range, 0, sizeof(struct iw_range)); | ||
710 | |||
711 | #if WIRELESS_EXT > 10 | ||
712 | /* Set the Wireless Extension versions */ | ||
713 | range->we_version_compiled = WIRELESS_EXT; | ||
714 | range->we_version_source = 9; /* Nothing for us in v10 and v11 */ | ||
715 | #endif /* WIRELESS_EXT > 10 */ | ||
716 | |||
717 | /* Set information in the range struct */ | ||
718 | range->throughput = 450 * 1000; /* don't argue on this ! */ | ||
719 | range->min_nwid = 0x0000; | ||
720 | range->max_nwid = 0x01FF; | ||
721 | |||
722 | range->num_channels = range->num_frequency = 0; | ||
723 | |||
724 | range->sensitivity = 0x3F; | ||
725 | range->max_qual.qual = 255; | ||
726 | range->max_qual.level = 255; | ||
727 | range->max_qual.noise = 0; | ||
728 | |||
729 | #if WIRELESS_EXT > 7 | ||
730 | range->num_bitrates = 1; | ||
731 | range->bitrate[0] = 1000000; /* 1 Mb/s */ | ||
732 | #endif /* WIRELESS_EXT > 7 */ | ||
733 | |||
734 | #if WIRELESS_EXT > 8 | ||
735 | range->encoding_size[0] = 2; /* 16 bits scrambling */ | ||
736 | range->num_encoding_sizes = 1; | ||
737 | range->max_encoding_tokens = 1; /* Only one key possible */ | ||
738 | #endif /* WIRELESS_EXT > 8 */ | ||
739 | |||
740 | return ret; | ||
741 | } | ||
742 | |||
743 | /* | ||
744 | * Wireless Private Handler : get snapshot | ||
745 | */ | ||
746 | static int netwave_get_snap(struct net_device *dev, | ||
747 | struct iw_request_info *info, | ||
748 | union iwreq_data *wrqu, | ||
749 | char *extra) | ||
750 | { | ||
751 | unsigned long flags; | ||
752 | kio_addr_t iobase = dev->base_addr; | ||
753 | netwave_private *priv = netdev_priv(dev); | ||
754 | u_char __iomem *ramBase = priv->ramBase; | ||
755 | |||
756 | /* Disable interrupts & save flags */ | ||
757 | spin_lock_irqsave(&priv->spinlock, flags); | ||
758 | |||
759 | /* Take snapshot of environment */ | ||
760 | netwave_snapshot( priv, ramBase, iobase); | ||
761 | wrqu->data.length = priv->nss.length; | ||
762 | memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey)); | ||
763 | |||
764 | priv->lastExec = jiffies; | ||
765 | |||
766 | /* ReEnable interrupts & restore flags */ | ||
767 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
768 | |||
769 | return(0); | ||
770 | } | ||
771 | |||
772 | /* | ||
773 | * Structures to export the Wireless Handlers | ||
774 | * This is the stuff that are treated the wireless extensions (iwconfig) | ||
775 | */ | ||
776 | |||
777 | static const struct iw_priv_args netwave_private_args[] = { | ||
778 | /*{ cmd, set_args, get_args, name } */ | ||
779 | { SIOCGIPSNAP, 0, | ||
780 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey), | ||
781 | "getsitesurvey" }, | ||
782 | }; | ||
783 | |||
784 | #if WIRELESS_EXT > 12 | ||
785 | |||
786 | static const iw_handler netwave_handler[] = | ||
787 | { | ||
788 | NULL, /* SIOCSIWNAME */ | ||
789 | netwave_get_name, /* SIOCGIWNAME */ | ||
790 | netwave_set_nwid, /* SIOCSIWNWID */ | ||
791 | netwave_get_nwid, /* SIOCGIWNWID */ | ||
792 | NULL, /* SIOCSIWFREQ */ | ||
793 | NULL, /* SIOCGIWFREQ */ | ||
794 | NULL, /* SIOCSIWMODE */ | ||
795 | netwave_get_mode, /* SIOCGIWMODE */ | ||
796 | NULL, /* SIOCSIWSENS */ | ||
797 | NULL, /* SIOCGIWSENS */ | ||
798 | NULL, /* SIOCSIWRANGE */ | ||
799 | netwave_get_range, /* SIOCGIWRANGE */ | ||
800 | NULL, /* SIOCSIWPRIV */ | ||
801 | NULL, /* SIOCGIWPRIV */ | ||
802 | NULL, /* SIOCSIWSTATS */ | ||
803 | NULL, /* SIOCGIWSTATS */ | ||
804 | NULL, /* SIOCSIWSPY */ | ||
805 | NULL, /* SIOCGIWSPY */ | ||
806 | NULL, /* -- hole -- */ | ||
807 | NULL, /* -- hole -- */ | ||
808 | NULL, /* SIOCSIWAP */ | ||
809 | NULL, /* SIOCGIWAP */ | ||
810 | NULL, /* -- hole -- */ | ||
811 | NULL, /* SIOCGIWAPLIST */ | ||
812 | NULL, /* -- hole -- */ | ||
813 | NULL, /* -- hole -- */ | ||
814 | NULL, /* SIOCSIWESSID */ | ||
815 | NULL, /* SIOCGIWESSID */ | ||
816 | NULL, /* SIOCSIWNICKN */ | ||
817 | NULL, /* SIOCGIWNICKN */ | ||
818 | NULL, /* -- hole -- */ | ||
819 | NULL, /* -- hole -- */ | ||
820 | NULL, /* SIOCSIWRATE */ | ||
821 | NULL, /* SIOCGIWRATE */ | ||
822 | NULL, /* SIOCSIWRTS */ | ||
823 | NULL, /* SIOCGIWRTS */ | ||
824 | NULL, /* SIOCSIWFRAG */ | ||
825 | NULL, /* SIOCGIWFRAG */ | ||
826 | NULL, /* SIOCSIWTXPOW */ | ||
827 | NULL, /* SIOCGIWTXPOW */ | ||
828 | NULL, /* SIOCSIWRETRY */ | ||
829 | NULL, /* SIOCGIWRETRY */ | ||
830 | netwave_set_scramble, /* SIOCSIWENCODE */ | ||
831 | netwave_get_scramble, /* SIOCGIWENCODE */ | ||
832 | }; | ||
833 | |||
834 | static const iw_handler netwave_private_handler[] = | ||
835 | { | ||
836 | NULL, /* SIOCIWFIRSTPRIV */ | ||
837 | netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */ | ||
838 | }; | ||
839 | |||
840 | static const struct iw_handler_def netwave_handler_def = | ||
841 | { | ||
842 | .num_standard = sizeof(netwave_handler)/sizeof(iw_handler), | ||
843 | .num_private = sizeof(netwave_private_handler)/sizeof(iw_handler), | ||
844 | .num_private_args = sizeof(netwave_private_args)/sizeof(struct iw_priv_args), | ||
845 | .standard = (iw_handler *) netwave_handler, | ||
846 | .private = (iw_handler *) netwave_private_handler, | ||
847 | .private_args = (struct iw_priv_args *) netwave_private_args, | ||
848 | }; | ||
849 | #endif /* WIRELESS_EXT > 12 */ | ||
850 | |||
851 | /* | ||
852 | * Function netwave_ioctl (dev, rq, cmd) | ||
853 | * | ||
854 | * Perform ioctl : config & info stuff | ||
855 | * This is the stuff that are treated the wireless extensions (iwconfig) | ||
856 | * | ||
857 | */ | ||
858 | static int netwave_ioctl(struct net_device *dev, /* ioctl device */ | ||
859 | struct ifreq *rq, /* Data passed */ | ||
860 | int cmd) /* Ioctl number */ | ||
861 | { | ||
862 | int ret = 0; | ||
863 | #ifdef WIRELESS_EXT | ||
864 | #if WIRELESS_EXT <= 12 | ||
865 | struct iwreq *wrq = (struct iwreq *) rq; | ||
866 | #endif | ||
867 | #endif | ||
868 | |||
869 | DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); | ||
870 | |||
871 | /* Look what is the request */ | ||
872 | switch(cmd) { | ||
873 | /* --------------- WIRELESS EXTENSIONS --------------- */ | ||
874 | #ifdef WIRELESS_EXT | ||
875 | #if WIRELESS_EXT <= 12 | ||
876 | case SIOCGIWNAME: | ||
877 | netwave_get_name(dev, NULL, &(wrq->u), NULL); | ||
878 | break; | ||
879 | case SIOCSIWNWID: | ||
880 | ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL); | ||
881 | break; | ||
882 | case SIOCGIWNWID: | ||
883 | ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL); | ||
884 | break; | ||
885 | #if WIRELESS_EXT > 8 /* Note : The API did change... */ | ||
886 | case SIOCGIWENCODE: | ||
887 | /* Get scramble key */ | ||
888 | if(wrq->u.encoding.pointer != (caddr_t) 0) | ||
889 | { | ||
890 | char key[2]; | ||
891 | ret = netwave_get_scramble(dev, NULL, &(wrq->u), key); | ||
892 | if(copy_to_user(wrq->u.encoding.pointer, key, 2)) | ||
893 | ret = -EFAULT; | ||
894 | } | ||
895 | break; | ||
896 | case SIOCSIWENCODE: | ||
897 | /* Set scramble key */ | ||
898 | if(wrq->u.encoding.pointer != (caddr_t) 0) | ||
899 | { | ||
900 | char key[2]; | ||
901 | if(copy_from_user(key, wrq->u.encoding.pointer, 2)) | ||
902 | { | ||
903 | ret = -EFAULT; | ||
904 | break; | ||
905 | } | ||
906 | ret = netwave_set_scramble(dev, NULL, &(wrq->u), key); | ||
907 | } | ||
908 | break; | ||
909 | case SIOCGIWMODE: | ||
910 | /* Mode of operation */ | ||
911 | ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL); | ||
912 | break; | ||
913 | #else /* WIRELESS_EXT > 8 */ | ||
914 | case SIOCGIWENCODE: | ||
915 | /* Get scramble key */ | ||
916 | ret = netwave_get_scramble(dev, NULL, &(wrq->u), | ||
917 | (char *) &wrq->u.encoding.code); | ||
918 | break; | ||
919 | case SIOCSIWENCODE: | ||
920 | /* Set scramble key */ | ||
921 | ret = netwave_set_scramble(dev, NULL, &(wrq->u), | ||
922 | (char *) &wrq->u.encoding.code); | ||
923 | break; | ||
924 | #endif /* WIRELESS_EXT > 8 */ | ||
925 | case SIOCGIWRANGE: | ||
926 | /* Basic checking... */ | ||
927 | if(wrq->u.data.pointer != (caddr_t) 0) { | ||
928 | struct iw_range range; | ||
929 | ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range); | ||
930 | if (copy_to_user(wrq->u.data.pointer, &range, | ||
931 | sizeof(struct iw_range))) | ||
932 | ret = -EFAULT; | ||
933 | } | ||
934 | break; | ||
935 | case SIOCGIWPRIV: | ||
936 | /* Basic checking... */ | ||
937 | if(wrq->u.data.pointer != (caddr_t) 0) { | ||
938 | /* Set the number of ioctl available */ | ||
939 | wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]); | ||
940 | |||
941 | /* Copy structure to the user buffer */ | ||
942 | if(copy_to_user(wrq->u.data.pointer, | ||
943 | (u_char *) netwave_private_args, | ||
944 | sizeof(netwave_private_args))) | ||
945 | ret = -EFAULT; | ||
946 | } | ||
947 | break; | ||
948 | case SIOCGIPSNAP: | ||
949 | if(wrq->u.data.pointer != (caddr_t) 0) { | ||
950 | char buffer[sizeof( struct site_survey)]; | ||
951 | ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer); | ||
952 | /* Copy structure to the user buffer */ | ||
953 | if(copy_to_user(wrq->u.data.pointer, | ||
954 | buffer, | ||
955 | sizeof( struct site_survey))) | ||
956 | { | ||
957 | printk(KERN_DEBUG "Bad buffer!\n"); | ||
958 | break; | ||
959 | } | ||
960 | } | ||
961 | break; | ||
962 | #endif /* WIRELESS_EXT <= 12 */ | ||
963 | #endif /* WIRELESS_EXT */ | ||
964 | default: | ||
965 | ret = -EOPNOTSUPP; | ||
966 | } | ||
967 | |||
968 | return ret; | ||
969 | } | ||
970 | |||
971 | /* | ||
972 | * Function netwave_pcmcia_config (link) | ||
973 | * | ||
974 | * netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION | ||
975 | * event is received, to configure the PCMCIA socket, and to make the | ||
976 | * device available to the system. | ||
977 | * | ||
978 | */ | ||
979 | |||
980 | #define CS_CHECK(fn, ret) \ | ||
981 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
982 | |||
983 | static void netwave_pcmcia_config(dev_link_t *link) { | ||
984 | client_handle_t handle = link->handle; | ||
985 | struct net_device *dev = link->priv; | ||
986 | netwave_private *priv = netdev_priv(dev); | ||
987 | tuple_t tuple; | ||
988 | cisparse_t parse; | ||
989 | int i, j, last_ret, last_fn; | ||
990 | u_char buf[64]; | ||
991 | win_req_t req; | ||
992 | memreq_t mem; | ||
993 | u_char __iomem *ramBase = NULL; | ||
994 | |||
995 | DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); | ||
996 | |||
997 | /* | ||
998 | This reads the card's CONFIG tuple to find its configuration | ||
999 | registers. | ||
1000 | */ | ||
1001 | tuple.Attributes = 0; | ||
1002 | tuple.TupleData = (cisdata_t *) buf; | ||
1003 | tuple.TupleDataMax = 64; | ||
1004 | tuple.TupleOffset = 0; | ||
1005 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
1006 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
1007 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
1008 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
1009 | link->conf.ConfigBase = parse.config.base; | ||
1010 | link->conf.Present = parse.config.rmask[0]; | ||
1011 | |||
1012 | /* Configure card */ | ||
1013 | link->state |= DEV_CONFIG; | ||
1014 | |||
1015 | /* | ||
1016 | * Try allocating IO ports. This tries a few fixed addresses. | ||
1017 | * If you want, you can also read the card's config table to | ||
1018 | * pick addresses -- see the serial driver for an example. | ||
1019 | */ | ||
1020 | for (i = j = 0x0; j < 0x400; j += 0x20) { | ||
1021 | link->io.BasePort1 = j ^ 0x300; | ||
1022 | i = pcmcia_request_io(link->handle, &link->io); | ||
1023 | if (i == CS_SUCCESS) break; | ||
1024 | } | ||
1025 | if (i != CS_SUCCESS) { | ||
1026 | cs_error(link->handle, RequestIO, i); | ||
1027 | goto failed; | ||
1028 | } | ||
1029 | |||
1030 | /* | ||
1031 | * Now allocate an interrupt line. Note that this does not | ||
1032 | * actually assign a handler to the interrupt. | ||
1033 | */ | ||
1034 | CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); | ||
1035 | |||
1036 | /* | ||
1037 | * This actually configures the PCMCIA socket -- setting up | ||
1038 | * the I/O windows and the interrupt mapping. | ||
1039 | */ | ||
1040 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); | ||
1041 | |||
1042 | /* | ||
1043 | * Allocate a 32K memory window. Note that the dev_link_t | ||
1044 | * structure provides space for one window handle -- if your | ||
1045 | * device needs several windows, you'll need to keep track of | ||
1046 | * the handles in your private data structure, dev->priv. | ||
1047 | */ | ||
1048 | DEBUG(1, "Setting mem speed of %d\n", mem_speed); | ||
1049 | |||
1050 | req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; | ||
1051 | req.Base = 0; req.Size = 0x8000; | ||
1052 | req.AccessSpeed = mem_speed; | ||
1053 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); | ||
1054 | mem.CardOffset = 0x20000; mem.Page = 0; | ||
1055 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); | ||
1056 | |||
1057 | /* Store base address of the common window frame */ | ||
1058 | ramBase = ioremap(req.Base, 0x8000); | ||
1059 | priv->ramBase = ramBase; | ||
1060 | |||
1061 | dev->irq = link->irq.AssignedIRQ; | ||
1062 | dev->base_addr = link->io.BasePort1; | ||
1063 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
1064 | |||
1065 | if (register_netdev(dev) != 0) { | ||
1066 | printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); | ||
1067 | goto failed; | ||
1068 | } | ||
1069 | |||
1070 | strcpy(priv->node.dev_name, dev->name); | ||
1071 | link->dev = &priv->node; | ||
1072 | link->state &= ~DEV_CONFIG_PENDING; | ||
1073 | |||
1074 | /* Reset card before reading physical address */ | ||
1075 | netwave_doreset(dev->base_addr, ramBase); | ||
1076 | |||
1077 | /* Read the ethernet address and fill in the Netwave registers. */ | ||
1078 | for (i = 0; i < 6; i++) | ||
1079 | dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); | ||
1080 | |||
1081 | printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id " | ||
1082 | "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq, | ||
1083 | (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), | ||
1084 | (int) readb(ramBase+NETWAVE_EREG_NI+1)); | ||
1085 | for (i = 0; i < 6; i++) | ||
1086 | printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); | ||
1087 | |||
1088 | /* get revision words */ | ||
1089 | printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", | ||
1090 | get_uint16(ramBase + NETWAVE_EREG_ARW), | ||
1091 | get_uint16(ramBase + NETWAVE_EREG_ARW+2)); | ||
1092 | return; | ||
1093 | |||
1094 | cs_failed: | ||
1095 | cs_error(link->handle, last_fn, last_ret); | ||
1096 | failed: | ||
1097 | netwave_release(link); | ||
1098 | } /* netwave_pcmcia_config */ | ||
1099 | |||
1100 | /* | ||
1101 | * Function netwave_release (arg) | ||
1102 | * | ||
1103 | * After a card is removed, netwave_release() will unregister the net | ||
1104 | * device, and release the PCMCIA configuration. If the device is | ||
1105 | * still open, this will be postponed until it is closed. | ||
1106 | */ | ||
1107 | static void netwave_release(dev_link_t *link) | ||
1108 | { | ||
1109 | struct net_device *dev = link->priv; | ||
1110 | netwave_private *priv = netdev_priv(dev); | ||
1111 | |||
1112 | DEBUG(0, "netwave_release(0x%p)\n", link); | ||
1113 | |||
1114 | /* Don't bother checking to see if these succeed or not */ | ||
1115 | if (link->win) { | ||
1116 | iounmap(priv->ramBase); | ||
1117 | pcmcia_release_window(link->win); | ||
1118 | } | ||
1119 | pcmcia_release_configuration(link->handle); | ||
1120 | pcmcia_release_io(link->handle, &link->io); | ||
1121 | pcmcia_release_irq(link->handle, &link->irq); | ||
1122 | |||
1123 | link->state &= ~DEV_CONFIG; | ||
1124 | } | ||
1125 | |||
1126 | /* | ||
1127 | * Function netwave_event (event, priority, args) | ||
1128 | * | ||
1129 | * The card status event handler. Mostly, this schedules other | ||
1130 | * stuff to run after an event is received. A CARD_REMOVAL event | ||
1131 | * also sets some flags to discourage the net drivers from trying | ||
1132 | * to talk to the card any more. | ||
1133 | * | ||
1134 | * When a CARD_REMOVAL event is received, we immediately set a flag | ||
1135 | * to block future accesses to this device. All the functions that | ||
1136 | * actually access the device should check this flag to make sure | ||
1137 | * the card is still present. | ||
1138 | * | ||
1139 | */ | ||
1140 | static int netwave_event(event_t event, int priority, | ||
1141 | event_callback_args_t *args) | ||
1142 | { | ||
1143 | dev_link_t *link = args->client_data; | ||
1144 | struct net_device *dev = link->priv; | ||
1145 | |||
1146 | DEBUG(1, "netwave_event(0x%06x)\n", event); | ||
1147 | |||
1148 | switch (event) { | ||
1149 | case CS_EVENT_REGISTRATION_COMPLETE: | ||
1150 | DEBUG(0, "netwave_cs: registration complete\n"); | ||
1151 | break; | ||
1152 | |||
1153 | case CS_EVENT_CARD_REMOVAL: | ||
1154 | link->state &= ~DEV_PRESENT; | ||
1155 | if (link->state & DEV_CONFIG) { | ||
1156 | netif_device_detach(dev); | ||
1157 | netwave_release(link); | ||
1158 | } | ||
1159 | break; | ||
1160 | case CS_EVENT_CARD_INSERTION: | ||
1161 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
1162 | netwave_pcmcia_config( link); | ||
1163 | break; | ||
1164 | case CS_EVENT_PM_SUSPEND: | ||
1165 | link->state |= DEV_SUSPEND; | ||
1166 | /* Fall through... */ | ||
1167 | case CS_EVENT_RESET_PHYSICAL: | ||
1168 | if (link->state & DEV_CONFIG) { | ||
1169 | if (link->open) | ||
1170 | netif_device_detach(dev); | ||
1171 | pcmcia_release_configuration(link->handle); | ||
1172 | } | ||
1173 | break; | ||
1174 | case CS_EVENT_PM_RESUME: | ||
1175 | link->state &= ~DEV_SUSPEND; | ||
1176 | /* Fall through... */ | ||
1177 | case CS_EVENT_CARD_RESET: | ||
1178 | if (link->state & DEV_CONFIG) { | ||
1179 | pcmcia_request_configuration(link->handle, &link->conf); | ||
1180 | if (link->open) { | ||
1181 | netwave_reset(dev); | ||
1182 | netif_device_attach(dev); | ||
1183 | } | ||
1184 | } | ||
1185 | break; | ||
1186 | } | ||
1187 | return 0; | ||
1188 | } /* netwave_event */ | ||
1189 | |||
1190 | /* | ||
1191 | * Function netwave_doreset (ioBase, ramBase) | ||
1192 | * | ||
1193 | * Proper hardware reset of the card. | ||
1194 | */ | ||
1195 | static void netwave_doreset(kio_addr_t ioBase, u_char __iomem *ramBase) | ||
1196 | { | ||
1197 | /* Reset card */ | ||
1198 | wait_WOC(ioBase); | ||
1199 | outb(0x80, ioBase + NETWAVE_REG_PMR); | ||
1200 | writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */ | ||
1201 | outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */ | ||
1202 | } | ||
1203 | |||
1204 | /* | ||
1205 | * Function netwave_reset (dev) | ||
1206 | * | ||
1207 | * Reset and restore all of the netwave registers | ||
1208 | */ | ||
1209 | static void netwave_reset(struct net_device *dev) { | ||
1210 | /* u_char state; */ | ||
1211 | netwave_private *priv = netdev_priv(dev); | ||
1212 | u_char __iomem *ramBase = priv->ramBase; | ||
1213 | kio_addr_t iobase = dev->base_addr; | ||
1214 | |||
1215 | DEBUG(0, "netwave_reset: Done with hardware reset\n"); | ||
1216 | |||
1217 | priv->timeoutCounter = 0; | ||
1218 | |||
1219 | /* Reset card */ | ||
1220 | netwave_doreset(iobase, ramBase); | ||
1221 | printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n"); | ||
1222 | |||
1223 | /* Write a NOP to check the card */ | ||
1224 | wait_WOC(iobase); | ||
1225 | writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0); | ||
1226 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); | ||
1227 | |||
1228 | /* Set receive conf */ | ||
1229 | wait_WOC(iobase); | ||
1230 | writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); | ||
1231 | writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1); | ||
1232 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); | ||
1233 | |||
1234 | /* Set transmit conf */ | ||
1235 | wait_WOC(iobase); | ||
1236 | writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0); | ||
1237 | writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1); | ||
1238 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); | ||
1239 | |||
1240 | /* Now set the MU Domain */ | ||
1241 | printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); | ||
1242 | wait_WOC(iobase); | ||
1243 | writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); | ||
1244 | writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); | ||
1245 | writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2); | ||
1246 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); | ||
1247 | |||
1248 | /* Set scramble key */ | ||
1249 | printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key); | ||
1250 | wait_WOC(iobase); | ||
1251 | writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); | ||
1252 | writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); | ||
1253 | writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); | ||
1254 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); | ||
1255 | |||
1256 | /* Enable interrupts, bit 4 high to keep unused | ||
1257 | * source from interrupting us, bit 2 high to | ||
1258 | * set interrupt enable, 567 to enable TxDN, | ||
1259 | * RxErr and RxRdy | ||
1260 | */ | ||
1261 | wait_WOC(iobase); | ||
1262 | outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR); | ||
1263 | |||
1264 | /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36 | ||
1265 | * waitWOC | ||
1266 | * skriv 80 til d000:3688 | ||
1267 | * sjekk om det ble 80 | ||
1268 | */ | ||
1269 | |||
1270 | /* Enable Receiver */ | ||
1271 | wait_WOC(iobase); | ||
1272 | writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0); | ||
1273 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); | ||
1274 | |||
1275 | /* Set the IENA bit in COR */ | ||
1276 | wait_WOC(iobase); | ||
1277 | outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR); | ||
1278 | } | ||
1279 | |||
1280 | /* | ||
1281 | * Function netwave_hw_xmit (data, len, dev) | ||
1282 | */ | ||
1283 | static int netwave_hw_xmit(unsigned char* data, int len, | ||
1284 | struct net_device* dev) { | ||
1285 | unsigned long flags; | ||
1286 | unsigned int TxFreeList, | ||
1287 | curBuff, | ||
1288 | MaxData, | ||
1289 | DataOffset; | ||
1290 | int tmpcount; | ||
1291 | |||
1292 | netwave_private *priv = netdev_priv(dev); | ||
1293 | u_char __iomem * ramBase = priv->ramBase; | ||
1294 | kio_addr_t iobase = dev->base_addr; | ||
1295 | |||
1296 | /* Disable interrupts & save flags */ | ||
1297 | spin_lock_irqsave(&priv->spinlock, flags); | ||
1298 | |||
1299 | /* Check if there are transmit buffers available */ | ||
1300 | wait_WOC(iobase); | ||
1301 | if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) { | ||
1302 | /* No buffers available */ | ||
1303 | printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n", | ||
1304 | dev->name); | ||
1305 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
1306 | return 1; | ||
1307 | } | ||
1308 | |||
1309 | priv->stats.tx_bytes += len; | ||
1310 | |||
1311 | DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", | ||
1312 | readb(ramBase + NETWAVE_EREG_SPCQ), | ||
1313 | readb(ramBase + NETWAVE_EREG_SPU), | ||
1314 | readb(ramBase + NETWAVE_EREG_LIF), | ||
1315 | readb(ramBase + NETWAVE_EREG_ISPLQ)); | ||
1316 | |||
1317 | /* Now try to insert it into the adapters free memory */ | ||
1318 | wait_WOC(iobase); | ||
1319 | TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP); | ||
1320 | MaxData = get_uint16(ramBase + NETWAVE_EREG_TDP+2); | ||
1321 | DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4); | ||
1322 | |||
1323 | DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n", | ||
1324 | TxFreeList, MaxData, DataOffset); | ||
1325 | |||
1326 | /* Copy packet to the adapter fragment buffers */ | ||
1327 | curBuff = TxFreeList; | ||
1328 | tmpcount = 0; | ||
1329 | while (tmpcount < len) { | ||
1330 | int tmplen = len - tmpcount; | ||
1331 | copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, | ||
1332 | (tmplen < MaxData) ? tmplen : MaxData); | ||
1333 | tmpcount += MaxData; | ||
1334 | |||
1335 | /* Advance to next buffer */ | ||
1336 | curBuff = get_uint16(ramBase + curBuff); | ||
1337 | } | ||
1338 | |||
1339 | /* Now issue transmit list */ | ||
1340 | wait_WOC(iobase); | ||
1341 | writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0); | ||
1342 | writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1); | ||
1343 | writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); | ||
1344 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); | ||
1345 | |||
1346 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
1347 | return 0; | ||
1348 | } | ||
1349 | |||
1350 | static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { | ||
1351 | /* This flag indicate that the hardware can't perform a transmission. | ||
1352 | * Theoritically, NET3 check it before sending a packet to the driver, | ||
1353 | * but in fact it never do that and pool continuously. | ||
1354 | * As the watchdog will abort too long transmissions, we are quite safe... | ||
1355 | */ | ||
1356 | |||
1357 | netif_stop_queue(dev); | ||
1358 | |||
1359 | { | ||
1360 | short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
1361 | unsigned char* buf = skb->data; | ||
1362 | |||
1363 | if (netwave_hw_xmit( buf, length, dev) == 1) { | ||
1364 | /* Some error, let's make them call us another time? */ | ||
1365 | netif_start_queue(dev); | ||
1366 | } | ||
1367 | dev->trans_start = jiffies; | ||
1368 | } | ||
1369 | dev_kfree_skb(skb); | ||
1370 | |||
1371 | return 0; | ||
1372 | } /* netwave_start_xmit */ | ||
1373 | |||
1374 | /* | ||
1375 | * Function netwave_interrupt (irq, dev_id, regs) | ||
1376 | * | ||
1377 | * This function is the interrupt handler for the Netwave card. This | ||
1378 | * routine will be called whenever: | ||
1379 | * 1. A packet is received. | ||
1380 | * 2. A packet has successfully been transferred and the unit is | ||
1381 | * ready to transmit another packet. | ||
1382 | * 3. A command has completed execution. | ||
1383 | */ | ||
1384 | static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) | ||
1385 | { | ||
1386 | kio_addr_t iobase; | ||
1387 | u_char __iomem *ramBase; | ||
1388 | struct net_device *dev = (struct net_device *)dev_id; | ||
1389 | struct netwave_private *priv = netdev_priv(dev); | ||
1390 | dev_link_t *link = &priv->link; | ||
1391 | int i; | ||
1392 | |||
1393 | if (!netif_device_present(dev)) | ||
1394 | return IRQ_NONE; | ||
1395 | |||
1396 | iobase = dev->base_addr; | ||
1397 | ramBase = priv->ramBase; | ||
1398 | |||
1399 | /* Now find what caused the interrupt, check while interrupts ready */ | ||
1400 | for (i = 0; i < 10; i++) { | ||
1401 | u_char status; | ||
1402 | |||
1403 | wait_WOC(iobase); | ||
1404 | if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02)) | ||
1405 | break; /* None of the interrupt sources asserted (normal exit) */ | ||
1406 | |||
1407 | status = inb(iobase + NETWAVE_REG_ASR); | ||
1408 | |||
1409 | if (!DEV_OK(link)) { | ||
1410 | DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x " | ||
1411 | "from removed or suspended card!\n", status); | ||
1412 | break; | ||
1413 | } | ||
1414 | |||
1415 | /* RxRdy */ | ||
1416 | if (status & 0x80) { | ||
1417 | netwave_rx(dev); | ||
1418 | /* wait_WOC(iobase); */ | ||
1419 | /* RxRdy cannot be reset directly by the host */ | ||
1420 | } | ||
1421 | /* RxErr */ | ||
1422 | if (status & 0x40) { | ||
1423 | u_char rser; | ||
1424 | |||
1425 | rser = readb(ramBase + NETWAVE_EREG_RSER); | ||
1426 | |||
1427 | if (rser & 0x04) { | ||
1428 | ++priv->stats.rx_dropped; | ||
1429 | ++priv->stats.rx_crc_errors; | ||
1430 | } | ||
1431 | if (rser & 0x02) | ||
1432 | ++priv->stats.rx_frame_errors; | ||
1433 | |||
1434 | /* Clear the RxErr bit in RSER. RSER+4 is the | ||
1435 | * write part. Also clear the RxCRC (0x04) and | ||
1436 | * RxBig (0x02) bits if present */ | ||
1437 | wait_WOC(iobase); | ||
1438 | writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4); | ||
1439 | |||
1440 | /* Write bit 6 high to ASCC to clear RxErr in ASR, | ||
1441 | * WOC must be set first! | ||
1442 | */ | ||
1443 | wait_WOC(iobase); | ||
1444 | writeb(0x40, ramBase + NETWAVE_EREG_ASCC); | ||
1445 | |||
1446 | /* Remember to count up priv->stats on error packets */ | ||
1447 | ++priv->stats.rx_errors; | ||
1448 | } | ||
1449 | /* TxDN */ | ||
1450 | if (status & 0x20) { | ||
1451 | int txStatus; | ||
1452 | |||
1453 | txStatus = readb(ramBase + NETWAVE_EREG_TSER); | ||
1454 | DEBUG(3, "Transmit done. TSER = %x id %x\n", | ||
1455 | txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1)); | ||
1456 | |||
1457 | if (txStatus & 0x20) { | ||
1458 | /* Transmitting was okay, clear bits */ | ||
1459 | wait_WOC(iobase); | ||
1460 | writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4); | ||
1461 | ++priv->stats.tx_packets; | ||
1462 | } | ||
1463 | |||
1464 | if (txStatus & 0xd0) { | ||
1465 | if (txStatus & 0x80) { | ||
1466 | ++priv->stats.collisions; /* Because of /proc/net/dev*/ | ||
1467 | /* ++priv->stats.tx_aborted_errors; */ | ||
1468 | /* printk("Collision. %ld\n", jiffies - dev->trans_start); */ | ||
1469 | } | ||
1470 | if (txStatus & 0x40) | ||
1471 | ++priv->stats.tx_carrier_errors; | ||
1472 | /* 0x80 TxGU Transmit giveup - nine times and no luck | ||
1473 | * 0x40 TxNOAP No access point. Discarded packet. | ||
1474 | * 0x10 TxErr Transmit error. Always set when | ||
1475 | * TxGU and TxNOAP is set. (Those are the only ones | ||
1476 | * to set TxErr). | ||
1477 | */ | ||
1478 | DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", | ||
1479 | txStatus); | ||
1480 | |||
1481 | /* Clear out TxGU, TxNOAP, TxErr and TxTrys */ | ||
1482 | wait_WOC(iobase); | ||
1483 | writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4); | ||
1484 | ++priv->stats.tx_errors; | ||
1485 | } | ||
1486 | DEBUG(3, "New status is TSER %x ASR %x\n", | ||
1487 | readb(ramBase + NETWAVE_EREG_TSER), | ||
1488 | inb(iobase + NETWAVE_REG_ASR)); | ||
1489 | |||
1490 | netif_wake_queue(dev); | ||
1491 | } | ||
1492 | /* TxBA, this would trigger on all error packets received */ | ||
1493 | /* if (status & 0x01) { | ||
1494 | DEBUG(4, "Transmit buffers available, %x\n", status); | ||
1495 | } | ||
1496 | */ | ||
1497 | } | ||
1498 | /* Handled if we looped at least one time - Jean II */ | ||
1499 | return IRQ_RETVAL(i); | ||
1500 | } /* netwave_interrupt */ | ||
1501 | |||
1502 | /* | ||
1503 | * Function netwave_watchdog (a) | ||
1504 | * | ||
1505 | * Watchdog : when we start a transmission, we set a timer in the | ||
1506 | * kernel. If the transmission complete, this timer is disabled. If | ||
1507 | * it expire, we reset the card. | ||
1508 | * | ||
1509 | */ | ||
1510 | static void netwave_watchdog(struct net_device *dev) { | ||
1511 | |||
1512 | DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); | ||
1513 | netwave_reset(dev); | ||
1514 | dev->trans_start = jiffies; | ||
1515 | netif_wake_queue(dev); | ||
1516 | } /* netwave_watchdog */ | ||
1517 | |||
1518 | static struct net_device_stats *netwave_get_stats(struct net_device *dev) { | ||
1519 | netwave_private *priv = netdev_priv(dev); | ||
1520 | |||
1521 | update_stats(dev); | ||
1522 | |||
1523 | DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x" | ||
1524 | " %x tx %x %x %x %x\n", | ||
1525 | readb(priv->ramBase + NETWAVE_EREG_SPCQ), | ||
1526 | readb(priv->ramBase + NETWAVE_EREG_SPU), | ||
1527 | readb(priv->ramBase + NETWAVE_EREG_LIF), | ||
1528 | readb(priv->ramBase + NETWAVE_EREG_ISPLQ), | ||
1529 | readb(priv->ramBase + NETWAVE_EREG_MHS), | ||
1530 | readb(priv->ramBase + NETWAVE_EREG_EC + 0xe), | ||
1531 | readb(priv->ramBase + NETWAVE_EREG_EC + 0xf), | ||
1532 | readb(priv->ramBase + NETWAVE_EREG_EC + 0x18), | ||
1533 | readb(priv->ramBase + NETWAVE_EREG_EC + 0x19), | ||
1534 | readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a), | ||
1535 | readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b)); | ||
1536 | |||
1537 | return &priv->stats; | ||
1538 | } | ||
1539 | |||
1540 | static void update_stats(struct net_device *dev) { | ||
1541 | //unsigned long flags; | ||
1542 | /* netwave_private *priv = netdev_priv(dev); */ | ||
1543 | |||
1544 | //spin_lock_irqsave(&priv->spinlock, flags); | ||
1545 | |||
1546 | /* priv->stats.rx_packets = readb(priv->ramBase + 0x18e); | ||
1547 | priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */ | ||
1548 | |||
1549 | //spin_unlock_irqrestore(&priv->spinlock, flags); | ||
1550 | } | ||
1551 | |||
1552 | static int netwave_rx(struct net_device *dev) | ||
1553 | { | ||
1554 | netwave_private *priv = netdev_priv(dev); | ||
1555 | u_char __iomem *ramBase = priv->ramBase; | ||
1556 | kio_addr_t iobase = dev->base_addr; | ||
1557 | u_char rxStatus; | ||
1558 | struct sk_buff *skb = NULL; | ||
1559 | unsigned int curBuffer, | ||
1560 | rcvList; | ||
1561 | int rcvLen; | ||
1562 | int tmpcount = 0; | ||
1563 | int dataCount, dataOffset; | ||
1564 | int i; | ||
1565 | u_char *ptr; | ||
1566 | |||
1567 | DEBUG(3, "xinw_rx: Receiving ... \n"); | ||
1568 | |||
1569 | /* Receive max 10 packets for now. */ | ||
1570 | for (i = 0; i < 10; i++) { | ||
1571 | /* Any packets? */ | ||
1572 | wait_WOC(iobase); | ||
1573 | rxStatus = readb(ramBase + NETWAVE_EREG_RSER); | ||
1574 | if ( !( rxStatus & 0x80)) /* No more packets */ | ||
1575 | break; | ||
1576 | |||
1577 | /* Check if multicast/broadcast or other */ | ||
1578 | /* multicast = (rxStatus & 0x20); */ | ||
1579 | |||
1580 | /* The receive list pointer and length of the packet */ | ||
1581 | wait_WOC(iobase); | ||
1582 | rcvLen = get_int16( ramBase + NETWAVE_EREG_RDP); | ||
1583 | rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2); | ||
1584 | |||
1585 | if (rcvLen < 0) { | ||
1586 | printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", | ||
1587 | rcvLen); | ||
1588 | return 0; | ||
1589 | } | ||
1590 | |||
1591 | skb = dev_alloc_skb(rcvLen+5); | ||
1592 | if (skb == NULL) { | ||
1593 | DEBUG(1, "netwave_rx: Could not allocate an sk_buff of " | ||
1594 | "length %d\n", rcvLen); | ||
1595 | ++priv->stats.rx_dropped; | ||
1596 | /* Tell the adapter to skip the packet */ | ||
1597 | wait_WOC(iobase); | ||
1598 | writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); | ||
1599 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); | ||
1600 | return 0; | ||
1601 | } | ||
1602 | |||
1603 | skb_reserve( skb, 2); /* Align IP on 16 byte */ | ||
1604 | skb_put( skb, rcvLen); | ||
1605 | skb->dev = dev; | ||
1606 | |||
1607 | /* Copy packet fragments to the skb data area */ | ||
1608 | ptr = (u_char*) skb->data; | ||
1609 | curBuffer = rcvList; | ||
1610 | tmpcount = 0; | ||
1611 | while ( tmpcount < rcvLen) { | ||
1612 | /* Get length and offset of current buffer */ | ||
1613 | dataCount = get_uint16( ramBase+curBuffer+2); | ||
1614 | dataOffset = get_uint16( ramBase+curBuffer+4); | ||
1615 | |||
1616 | copy_from_pc( ptr + tmpcount, | ||
1617 | ramBase+curBuffer+dataOffset, dataCount); | ||
1618 | |||
1619 | tmpcount += dataCount; | ||
1620 | |||
1621 | /* Point to next buffer */ | ||
1622 | curBuffer = get_uint16(ramBase + curBuffer); | ||
1623 | } | ||
1624 | |||
1625 | skb->protocol = eth_type_trans(skb,dev); | ||
1626 | /* Queue packet for network layer */ | ||
1627 | netif_rx(skb); | ||
1628 | |||
1629 | dev->last_rx = jiffies; | ||
1630 | priv->stats.rx_packets++; | ||
1631 | priv->stats.rx_bytes += rcvLen; | ||
1632 | |||
1633 | /* Got the packet, tell the adapter to skip it */ | ||
1634 | wait_WOC(iobase); | ||
1635 | writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); | ||
1636 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); | ||
1637 | DEBUG(3, "Packet reception ok\n"); | ||
1638 | } | ||
1639 | return 0; | ||
1640 | } | ||
1641 | |||
1642 | static int netwave_open(struct net_device *dev) { | ||
1643 | netwave_private *priv = netdev_priv(dev); | ||
1644 | dev_link_t *link = &priv->link; | ||
1645 | |||
1646 | DEBUG(1, "netwave_open: starting.\n"); | ||
1647 | |||
1648 | if (!DEV_OK(link)) | ||
1649 | return -ENODEV; | ||
1650 | |||
1651 | link->open++; | ||
1652 | |||
1653 | netif_start_queue(dev); | ||
1654 | netwave_reset(dev); | ||
1655 | |||
1656 | return 0; | ||
1657 | } | ||
1658 | |||
1659 | static int netwave_close(struct net_device *dev) { | ||
1660 | netwave_private *priv = netdev_priv(dev); | ||
1661 | dev_link_t *link = &priv->link; | ||
1662 | |||
1663 | DEBUG(1, "netwave_close: finishing.\n"); | ||
1664 | |||
1665 | link->open--; | ||
1666 | netif_stop_queue(dev); | ||
1667 | |||
1668 | return 0; | ||
1669 | } | ||
1670 | |||
1671 | static struct pcmcia_driver netwave_driver = { | ||
1672 | .owner = THIS_MODULE, | ||
1673 | .drv = { | ||
1674 | .name = "netwave_cs", | ||
1675 | }, | ||
1676 | .attach = netwave_attach, | ||
1677 | .detach = netwave_detach, | ||
1678 | }; | ||
1679 | |||
1680 | static int __init init_netwave_cs(void) | ||
1681 | { | ||
1682 | return pcmcia_register_driver(&netwave_driver); | ||
1683 | } | ||
1684 | |||
1685 | static void __exit exit_netwave_cs(void) | ||
1686 | { | ||
1687 | pcmcia_unregister_driver(&netwave_driver); | ||
1688 | BUG_ON(dev_list != NULL); | ||
1689 | } | ||
1690 | |||
1691 | module_init(init_netwave_cs); | ||
1692 | module_exit(exit_netwave_cs); | ||
1693 | |||
1694 | /* Set or clear the multicast filter for this adaptor. | ||
1695 | num_addrs == -1 Promiscuous mode, receive all packets | ||
1696 | num_addrs == 0 Normal mode, clear multicast list | ||
1697 | num_addrs > 0 Multicast mode, receive normal and MC packets, and do | ||
1698 | best-effort filtering. | ||
1699 | */ | ||
1700 | static void set_multicast_list(struct net_device *dev) | ||
1701 | { | ||
1702 | kio_addr_t iobase = dev->base_addr; | ||
1703 | netwave_private *priv = netdev_priv(dev); | ||
1704 | u_char __iomem * ramBase = priv->ramBase; | ||
1705 | u_char rcvMode = 0; | ||
1706 | |||
1707 | #ifdef PCMCIA_DEBUG | ||
1708 | if (pc_debug > 2) { | ||
1709 | static int old; | ||
1710 | if (old != dev->mc_count) { | ||
1711 | old = dev->mc_count; | ||
1712 | DEBUG(0, "%s: setting Rx mode to %d addresses.\n", | ||
1713 | dev->name, dev->mc_count); | ||
1714 | } | ||
1715 | } | ||
1716 | #endif | ||
1717 | |||
1718 | if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { | ||
1719 | /* Multicast Mode */ | ||
1720 | rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast; | ||
1721 | } else if (dev->flags & IFF_PROMISC) { | ||
1722 | /* Promiscous mode */ | ||
1723 | rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast; | ||
1724 | } else { | ||
1725 | /* Normal mode */ | ||
1726 | rcvMode = rxConfRxEna + rxConfBcast; | ||
1727 | } | ||
1728 | |||
1729 | /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/ | ||
1730 | /* Now set receive mode */ | ||
1731 | wait_WOC(iobase); | ||
1732 | writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); | ||
1733 | writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1); | ||
1734 | writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); | ||
1735 | } | ||
1736 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c new file mode 100644 index 000000000000..a3a32430ae9d --- /dev/null +++ b/drivers/net/wireless/orinoco.c | |||
@@ -0,0 +1,4243 @@ | |||
1 | /* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c) | ||
2 | * | ||
3 | * A driver for Hermes or Prism 2 chipset based PCMCIA wireless | ||
4 | * adaptors, with Lucent/Agere, Intersil or Symbol firmware. | ||
5 | * | ||
6 | * Current maintainers (as of 29 September 2003) are: | ||
7 | * Pavel Roskin <proski AT gnu.org> | ||
8 | * and David Gibson <hermes AT gibson.dropbear.id.au> | ||
9 | * | ||
10 | * (C) Copyright David Gibson, IBM Corporation 2001-2003. | ||
11 | * Copyright (C) 2000 David Gibson, Linuxcare Australia. | ||
12 | * With some help from : | ||
13 | * Copyright (C) 2001 Jean Tourrilhes, HP Labs | ||
14 | * Copyright (C) 2001 Benjamin Herrenschmidt | ||
15 | * | ||
16 | * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 | ||
17 | * | ||
18 | * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy | ||
19 | * AT fasta.fh-dortmund.de> | ||
20 | * http://www.stud.fh-dortmund.de/~andy/wvlan/ | ||
21 | * | ||
22 | * The contents of this file are subject to the Mozilla Public License | ||
23 | * Version 1.1 (the "License"); you may not use this file except in | ||
24 | * compliance with the License. You may obtain a copy of the License | ||
25 | * at http://www.mozilla.org/MPL/ | ||
26 | * | ||
27 | * Software distributed under the License is distributed on an "AS IS" | ||
28 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
29 | * the License for the specific language governing rights and | ||
30 | * limitations under the License. | ||
31 | * | ||
32 | * The initial developer of the original code is David A. Hinds | ||
33 | * <dahinds AT users.sourceforge.net>. Portions created by David | ||
34 | * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights | ||
35 | * Reserved. | ||
36 | * | ||
37 | * Alternatively, the contents of this file may be used under the | ||
38 | * terms of the GNU General Public License version 2 (the "GPL"), in | ||
39 | * which case the provisions of the GPL are applicable instead of the | ||
40 | * above. If you wish to allow the use of your version of this file | ||
41 | * only under the terms of the GPL and not to allow others to use your | ||
42 | * version of this file under the MPL, indicate your decision by | ||
43 | * deleting the provisions above and replace them with the notice and | ||
44 | * other provisions required by the GPL. If you do not delete the | ||
45 | * provisions above, a recipient may use your version of this file | ||
46 | * under either the MPL or the GPL. */ | ||
47 | |||
48 | /* | ||
49 | * v0.01 -> v0.02 - 21/3/2001 - Jean II | ||
50 | * o Allow to use regular ethX device name instead of dldwdX | ||
51 | * o Warning on IBSS with ESSID=any for firmware 6.06 | ||
52 | * o Put proper range.throughput values (optimistic) | ||
53 | * o IWSPY support (IOCTL and stat gather in Rx path) | ||
54 | * o Allow setting frequency in Ad-Hoc mode | ||
55 | * o Disable WEP setting if !has_wep to work on old firmware | ||
56 | * o Fix txpower range | ||
57 | * o Start adding support for Samsung/Compaq firmware | ||
58 | * | ||
59 | * v0.02 -> v0.03 - 23/3/2001 - Jean II | ||
60 | * o Start adding Symbol support - need to check all that | ||
61 | * o Fix Prism2/Symbol WEP to accept 128 bits keys | ||
62 | * o Add Symbol WEP (add authentication type) | ||
63 | * o Add Prism2/Symbol rate | ||
64 | * o Add PM timeout (holdover duration) | ||
65 | * o Enable "iwconfig eth0 key off" and friends (toggle flags) | ||
66 | * o Enable "iwconfig eth0 power unicast/all" (toggle flags) | ||
67 | * o Try with an Intel card. It report firmware 1.01, behave like | ||
68 | * an antiquated firmware, however on windows it says 2.00. Yuck ! | ||
69 | * o Workaround firmware bug in allocate buffer (Intel 1.01) | ||
70 | * o Finish external renaming to orinoco... | ||
71 | * o Testing with various Wavelan firmwares | ||
72 | * | ||
73 | * v0.03 -> v0.04 - 30/3/2001 - Jean II | ||
74 | * o Update to Wireless 11 -> add retry limit/lifetime support | ||
75 | * o Tested with a D-Link DWL 650 card, fill in firmware support | ||
76 | * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) | ||
77 | * o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-( | ||
78 | * It works on D-Link *only* after a tcpdump. Weird... | ||
79 | * And still doesn't work on Intel card. Grrrr... | ||
80 | * o Update the mode after a setport3 | ||
81 | * o Add preamble setting for Symbol cards (not yet enabled) | ||
82 | * o Don't complain as much about Symbol cards... | ||
83 | * | ||
84 | * v0.04 -> v0.04b - 22/4/2001 - David Gibson | ||
85 | * o Removed the 'eth' parameter - always use ethXX as the | ||
86 | * interface name instead of dldwdXX. The other was racy | ||
87 | * anyway. | ||
88 | * o Clean up RID definitions in hermes.h, other cleanups | ||
89 | * | ||
90 | * v0.04b -> v0.04c - 24/4/2001 - Jean II | ||
91 | * o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card | ||
92 | * with vendor 02 and firmware 0.08. Added in the capabilities... | ||
93 | * o Tested Lucent firmware 7.28, everything works... | ||
94 | * | ||
95 | * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt | ||
96 | * o Spin-off Pcmcia code. This file is renamed orinoco.c, | ||
97 | * and orinoco_cs.c now contains only the Pcmcia specific stuff | ||
98 | * o Add Airport driver support on top of orinoco.c (see airport.c) | ||
99 | * | ||
100 | * v0.05 -> v0.05a - 4/5/2001 - Jean II | ||
101 | * o Revert to old Pcmcia code to fix breakage of Ben's changes... | ||
102 | * | ||
103 | * v0.05a -> v0.05b - 4/5/2001 - Jean II | ||
104 | * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V | ||
105 | * o D-Link firmware doesn't support multicast. We just print a few | ||
106 | * error messages, but otherwise everything works... | ||
107 | * o For David : set/getport3 works fine, just upgrade iwpriv... | ||
108 | * | ||
109 | * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt | ||
110 | * o Adapt airport.c to latest changes in orinoco.c | ||
111 | * o Remove deferred power enabling code | ||
112 | * | ||
113 | * v0.05c -> v0.05d - 5/5/2001 - Jean II | ||
114 | * o Workaround to SNAP decapsulate frame from Linksys AP | ||
115 | * original patch from : Dong Liu <dliu AT research.bell-labs.com> | ||
116 | * (note : the memcmp bug was mine - fixed) | ||
117 | * o Remove set_retry stuff, no firmware support it (bloat--). | ||
118 | * | ||
119 | * v0.05d -> v0.06 - 25/5/2001 - Jean II | ||
120 | * Original patch from "Hong Lin" <alin AT redhat.com>, | ||
121 | * "Ian Kinner" <ikinner AT redhat.com> | ||
122 | * and "David Smith" <dsmith AT redhat.com> | ||
123 | * o Init of priv->tx_rate_ctrl in firmware specific section. | ||
124 | * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh ! | ||
125 | * o Spectrum card always need cor_reset (for every reset) | ||
126 | * o Fix cor_reset to not lose bit 7 in the register | ||
127 | * o flush_stale_links to remove zombie Pcmcia instances | ||
128 | * o Ack previous hermes event before reset | ||
129 | * Me (with my little hands) | ||
130 | * o Allow orinoco.c to call cor_reset via priv->card_reset_handler | ||
131 | * o Add priv->need_card_reset to toggle this feature | ||
132 | * o Fix various buglets when setting WEP in Symbol firmware | ||
133 | * Now, encryption is fully functional on Symbol cards. Youpi ! | ||
134 | * | ||
135 | * v0.06 -> v0.06b - 25/5/2001 - Jean II | ||
136 | * o IBSS on Symbol use port_mode = 4. Please don't ask... | ||
137 | * | ||
138 | * v0.06b -> v0.06c - 29/5/2001 - Jean II | ||
139 | * o Show first spy address in /proc/net/wireless for IBSS mode as well | ||
140 | * | ||
141 | * v0.06c -> v0.06d - 6/7/2001 - David Gibson | ||
142 | * o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus' | ||
143 | * wishes to reduce the number of unnecessary messages. | ||
144 | * o Removed bogus message on CRC error. | ||
145 | * o Merged fixes for v0.08 Prism 2 firmware from William Waghorn | ||
146 | * <willwaghorn AT yahoo.co.uk> | ||
147 | * o Slight cleanup/re-arrangement of firmware detection code. | ||
148 | * | ||
149 | * v0.06d -> v0.06e - 1/8/2001 - David Gibson | ||
150 | * o Removed some redundant global initializers (orinoco_cs.c). | ||
151 | * o Added some module metadata | ||
152 | * | ||
153 | * v0.06e -> v0.06f - 14/8/2001 - David Gibson | ||
154 | * o Wording fix to license | ||
155 | * o Added a 'use_alternate_encaps' module parameter for APs which need an | ||
156 | * oui of 00:00:00. We really need a better way of handling this, but | ||
157 | * the module flag is better than nothing for now. | ||
158 | * | ||
159 | * v0.06f -> v0.07 - 20/8/2001 - David Gibson | ||
160 | * o Removed BAP error retries from hermes_bap_seek(). For Tx we now | ||
161 | * let the upper layers handle the retry, we retry explicitly in the | ||
162 | * Rx path, but don't make as much noise about it. | ||
163 | * o Firmware detection cleanups. | ||
164 | * | ||
165 | * v0.07 -> v0.07a - 1/10/3001 - Jean II | ||
166 | * o Add code to read Symbol firmware revision, inspired by latest code | ||
167 | * in Spectrum24 by Lee John Keyser-Allen - Thanks Lee ! | ||
168 | * o Thanks to Jared Valentine <hidden AT xmission.com> for "providing" me | ||
169 | * a 3Com card with a recent firmware, fill out Symbol firmware | ||
170 | * capabilities of latest rev (2.20), as well as older Symbol cards. | ||
171 | * o Disable Power Management in newer Symbol firmware, the API | ||
172 | * has changed (documentation needed). | ||
173 | * | ||
174 | * v0.07a -> v0.08 - 3/10/2001 - David Gibson | ||
175 | * o Fixed a possible buffer overrun found by the Stanford checker (in | ||
176 | * dldwd_ioctl_setiwencode()). Can only be called by root anyway, so not | ||
177 | * a big problem. | ||
178 | * o Turned has_big_wep on for Intersil cards. That's not true for all of | ||
179 | * them but we should at least let the capable ones try. | ||
180 | * o Wait for BUSY to clear at the beginning of hermes_bap_seek(). I | ||
181 | * realized that my assumption that the driver's serialization | ||
182 | * would prevent the BAP being busy on entry was possibly false, because | ||
183 | * things other than seeks may make the BAP busy. | ||
184 | * o Use "alternate" (oui 00:00:00) encapsulation by default. | ||
185 | * Setting use_old_encaps will mimic the old behaviour, but I think we | ||
186 | * will be able to eliminate this. | ||
187 | * o Don't try to make __initdata const (the version string). This can't | ||
188 | * work because of the way the __initdata sectioning works. | ||
189 | * o Added MODULE_LICENSE tags. | ||
190 | * o Support for PLX (transparent PCMCIA->PCI bridge) cards. | ||
191 | * o Changed to using the new type-fascist min/max. | ||
192 | * | ||
193 | * v0.08 -> v0.08a - 9/10/2001 - David Gibson | ||
194 | * o Inserted some missing acknowledgements/info into the Changelog. | ||
195 | * o Fixed some bugs in the normalization of signal level reporting. | ||
196 | * o Fixed bad bug in WEP key handling on Intersil and Symbol firmware, | ||
197 | * which led to an instant crash on big-endian machines. | ||
198 | * | ||
199 | * v0.08a -> v0.08b - 20/11/2001 - David Gibson | ||
200 | * o Lots of cleanup and bugfixes in orinoco_plx.c | ||
201 | * o Cleanup to handling of Tx rate setting. | ||
202 | * o Removed support for old encapsulation method. | ||
203 | * o Removed old "dldwd" names. | ||
204 | * o Split RID constants into a new file hermes_rid.h | ||
205 | * o Renamed RID constants to match linux-wlan-ng and prism2.o | ||
206 | * o Bugfixes in hermes.c | ||
207 | * o Poke the PLX's INTCSR register, so it actually starts | ||
208 | * generating interrupts. These cards might actually work now. | ||
209 | * o Update to wireless extensions v12 (Jean II) | ||
210 | * o Support for tallies and inquire command (Jean II) | ||
211 | * o Airport updates for newer PPC kernels (BenH) | ||
212 | * | ||
213 | * v0.08b -> v0.09 - 21/12/2001 - David Gibson | ||
214 | * o Some new PCI IDs for PLX cards. | ||
215 | * o Removed broken attempt to do ALLMULTI reception. Just use | ||
216 | * promiscuous mode instead | ||
217 | * o Preliminary work for list-AP (Jean II) | ||
218 | * o Airport updates from (BenH) | ||
219 | * o Eliminated racy hw_ready stuff | ||
220 | * o Fixed generation of fake events in irq handler. This should | ||
221 | * finally kill the EIO problems (Jean II & dgibson) | ||
222 | * o Fixed breakage of bitrate set/get on Agere firmware (Jean II) | ||
223 | * | ||
224 | * v0.09 -> v0.09a - 2/1/2002 - David Gibson | ||
225 | * o Fixed stupid mistake in multicast list handling, triggering | ||
226 | * a BUG() | ||
227 | * | ||
228 | * v0.09a -> v0.09b - 16/1/2002 - David Gibson | ||
229 | * o Fixed even stupider mistake in new interrupt handling, which | ||
230 | * seriously broke things on big-endian machines. | ||
231 | * o Removed a bunch of redundant includes and exports. | ||
232 | * o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c | ||
233 | * o Don't attempt to do hardware level multicast reception on | ||
234 | * Intersil firmware, just go promisc instead. | ||
235 | * o Typo fixed in hermes_issue_cmd() | ||
236 | * o Eliminated WIRELESS_SPY #ifdefs | ||
237 | * o Status code reported on Tx exceptions | ||
238 | * o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC | ||
239 | * interrupts, which should fix the timeouts we're seeing. | ||
240 | * | ||
241 | * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson | ||
242 | * o Removed nested structures used for header parsing, so the | ||
243 | * driver should now work without hackery on ARM | ||
244 | * o Fix for WEP handling on Intersil (Hawk Newton) | ||
245 | * o Eliminated the /proc/hermes/ethXX/regs debugging file. It | ||
246 | * was never very useful. | ||
247 | * o Make Rx errors less noisy. | ||
248 | * | ||
249 | * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson | ||
250 | * o Laid the groundwork in hermes.[ch] for devices which map | ||
251 | * into PCI memory space rather than IO space. | ||
252 | * o Fixed bug in multicast handling (cleared multicast list when | ||
253 | * leaving promiscuous mode). | ||
254 | * o Relegated Tx error messages to debug. | ||
255 | * o Cleaned up / corrected handling of allocation lengths. | ||
256 | * o Set OWNSSID in IBSS mode for WinXP interoperability (jimc). | ||
257 | * o Change to using alloc_etherdev() for structure allocations. | ||
258 | * o Check for and drop undersized packets. | ||
259 | * o Fixed a race in stopping/waking the queue. This should fix | ||
260 | * the timeout problems (Pavel Roskin) | ||
261 | * o Reverted to netif_wake_queue() on the ALLOC event. | ||
262 | * o Fixes for recent Symbol firmwares which lack AP density | ||
263 | * (Pavel Roskin). | ||
264 | * | ||
265 | * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson | ||
266 | * o Handle different register spacing, necessary for Prism 2.5 | ||
267 | * PCI adaptors (Steve Hill). | ||
268 | * o Cleaned up initialization of card structures in orinoco_cs | ||
269 | * and airport. Removed card->priv field. | ||
270 | * o Make response structure optional for hermes_docmd_wait() | ||
271 | * Pavel Roskin) | ||
272 | * o Added PCI id for Nortel emobility to orinoco_plx.c. | ||
273 | * o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin) | ||
274 | * o Cleanups to firmware capability detection. | ||
275 | * o Arrange for orinoco_pci.c to override firmware detection. | ||
276 | * We should be able to support the PCI Intersil cards now. | ||
277 | * o Cleanup handling of reset_cor and hard_reset (Pavel Roskin). | ||
278 | * o Remove erroneous use of USER_BAP in the TxExc handler (Jouni | ||
279 | * Malinen). | ||
280 | * o Makefile changes for better integration into David Hinds | ||
281 | * pcmcia-cs package. | ||
282 | * | ||
283 | * v0.11a -> v0.11b - 1 May 2002 - David Gibson | ||
284 | * o Better error reporting in orinoco_plx_init_one() | ||
285 | * o Fixed multiple bad kfree() bugs introduced by the | ||
286 | * alloc_orinocodev() changes. | ||
287 | * | ||
288 | * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson | ||
289 | * o Support changing the MAC address. | ||
290 | * o Correct display of Intersil firmware revision numbers. | ||
291 | * o Entirely revised locking scheme. Should be both simpler and | ||
292 | * better. | ||
293 | * o Merged some common code in orinoco_plx, orinoco_pci and | ||
294 | * airport by creating orinoco_default_{open,stop,reset}() | ||
295 | * which are used as the dev->open, dev->stop, priv->reset | ||
296 | * callbacks if none are specified when alloc_orinocodev() is | ||
297 | * called. | ||
298 | * o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt(). | ||
299 | * They didn't do anything. | ||
300 | * | ||
301 | * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson | ||
302 | * o Some rearrangement of code. | ||
303 | * o Numerous fixups to locking and rest handling, particularly | ||
304 | * for PCMCIA. | ||
305 | * o This allows open and stop net_device methods to be in | ||
306 | * orinoco.c now, rather than in the init modules. | ||
307 | * o In orinoco_cs.c link->priv now points to the struct | ||
308 | * net_device not to the struct orinoco_private. | ||
309 | * o Added a check for undersized SNAP frames, which could cause | ||
310 | * crashes. | ||
311 | * | ||
312 | * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson | ||
313 | * o Fix hw->num_init testing code, so num_init is actually | ||
314 | * incremented. | ||
315 | * o Fix very stupid bug in orinoco_cs which broke compile with | ||
316 | * CONFIG_SMP. | ||
317 | * o Squashed a warning. | ||
318 | * | ||
319 | * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson | ||
320 | * o Change to C9X style designated initializers. | ||
321 | * o Add support for 3Com AirConnect PCI. | ||
322 | * o No longer ignore the hard_reset argument to | ||
323 | * alloc_orinocodev(). Oops. | ||
324 | * | ||
325 | * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson | ||
326 | * o Revert the broken 0.12* locking scheme and go to a new yet | ||
327 | * simpler scheme. | ||
328 | * o Do firmware resets only in orinoco_init() and when waking | ||
329 | * the card from hard sleep. | ||
330 | * | ||
331 | * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson | ||
332 | * o Re-introduced full resets (via schedule_task()) on Tx | ||
333 | * timeout. | ||
334 | * | ||
335 | * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson | ||
336 | * o Minor cleanups to info frame handling. Add basic support | ||
337 | * for linkstatus info frames. | ||
338 | * o Include required kernel headers in orinoco.h, to avoid | ||
339 | * compile problems. | ||
340 | * | ||
341 | * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson | ||
342 | * o Implemented hard reset for Airport cards | ||
343 | * o Experimental suspend/resume implementation for orinoco_pci | ||
344 | * o Abolished /proc debugging support, replaced with a debugging | ||
345 | * iwpriv. Now it's ugly and simple instead of ugly and complex. | ||
346 | * o Bugfix in hermes.c if the firmware returned a record length | ||
347 | * of 0, we could go clobbering memory. | ||
348 | * o Bugfix in orinoco_stop() - it used to fail if hw_unavailable | ||
349 | * was set, which was usually true on PCMCIA hot removes. | ||
350 | * o Track LINKSTATUS messages, silently drop Tx packets before | ||
351 | * we are connected (avoids confusing the firmware), and only | ||
352 | * give LINKSTATUS printk()s if the status has changed. | ||
353 | * | ||
354 | * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson | ||
355 | * o Cleanup: use dev instead of priv in various places. | ||
356 | * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event | ||
357 | * if we're in the middle of a (driver initiated) hard reset. | ||
358 | * o Bug fix: ETH_ZLEN is supposed to include the header | ||
359 | * (Dionysus Blazakis & Manish Karir) | ||
360 | * o Convert to using workqueues instead of taskqueues (and | ||
361 | * backwards compatibility macros for pre 2.5.41 kernels). | ||
362 | * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in | ||
363 | * airport.c | ||
364 | * o New orinoco_tmd.c init module from Joerg Dorchain for | ||
365 | * TMD7160 based PCI to PCMCIA bridges (similar to | ||
366 | * orinoco_plx.c). | ||
367 | * | ||
368 | * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson | ||
369 | * o Make hw_unavailable a counter, rather than just a flag, this | ||
370 | * is necessary to avoid some races (such as a card being | ||
371 | * removed in the middle of orinoco_reset(). | ||
372 | * o Restore Release/RequestConfiguration in the PCMCIA event handler | ||
373 | * when dealing with a driver initiated hard reset. This is | ||
374 | * necessary to prevent hangs due to a spurious interrupt while | ||
375 | * the reset is in progress. | ||
376 | * o Clear the 802.11 header when transmitting, even though we | ||
377 | * don't use it. This fixes a long standing bug on some | ||
378 | * firmwares, which seem to get confused if that isn't done. | ||
379 | * o Be less eager to de-encapsulate SNAP frames, only do so if | ||
380 | * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old | ||
381 | * behaviour broke CDP (Cisco Discovery Protocol). | ||
382 | * o Use dev instead of priv for free_irq() as well as | ||
383 | * request_irq() (oops). | ||
384 | * o Attempt to reset rather than giving up if we get too many | ||
385 | * IRQs. | ||
386 | * o Changed semantics of __orinoco_down() so it can be called | ||
387 | * safely with hw_unavailable set. It also now clears the | ||
388 | * linkstatus (since we're going to have to reassociate). | ||
389 | * | ||
390 | * v0.13d -> v0.13e - 12 May 2003 - David Gibson | ||
391 | * o Support for post-2.5.68 return values from irq handler. | ||
392 | * o Fixed bug where underlength packets would be double counted | ||
393 | * in the rx_dropped statistics. | ||
394 | * o Provided a module parameter to suppress linkstatus messages. | ||
395 | * | ||
396 | * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson | ||
397 | * o Replaced priv->connected logic with netif_carrier_on/off() | ||
398 | * calls. | ||
399 | * o Remove has_ibss_any and never set the CREATEIBSS RID when | ||
400 | * the ESSID is empty. Too many firmwares break if we do. | ||
401 | * o 2.6 merges: Replace pdev->slot_name with pci_name(), remove | ||
402 | * __devinitdata from PCI ID tables, use free_netdev(). | ||
403 | * o Enabled shared-key authentication for Agere firmware (from | ||
404 | * Robert J. Moore <Robert.J.Moore AT allanbank.com> | ||
405 | * o Move netif_wake_queue() (back) to the Tx completion from the | ||
406 | * ALLOC event. This seems to prevent/mitigate the rolling | ||
407 | * error -110 problems at least on some Intersil firmwares. | ||
408 | * Theoretically reduces performance, but I can't measure it. | ||
409 | * Patch from Andrew Tridgell <tridge AT samba.org> | ||
410 | * | ||
411 | * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson | ||
412 | * o Correctly turn off shared-key authentication when requested | ||
413 | * (bugfix from Robert J. Moore). | ||
414 | * o Correct airport sleep interfaces for current 2.6 kernels. | ||
415 | * o Add code for key change without disabling/enabling the MAC | ||
416 | * port. This is supposed to allow 802.1x to work sanely, but | ||
417 | * doesn't seem to yet. | ||
418 | * | ||
419 | * TODO | ||
420 | * o New wireless extensions API (patch from Moustafa | ||
421 | * Youssef, updated by Jim Carter and Pavel Roskin). | ||
422 | * o Handle de-encapsulation within network layer, provide 802.11 | ||
423 | * headers (patch from Thomas 'Dent' Mirlacher) | ||
424 | * o RF monitor mode support | ||
425 | * o Fix possible races in SPY handling. | ||
426 | * o Disconnect wireless extensions from fundamental configuration. | ||
427 | * o (maybe) Software WEP support (patch from Stano Meduna). | ||
428 | * o (maybe) Use multiple Tx buffers - driver handling queue | ||
429 | * rather than firmware. | ||
430 | */ | ||
431 | |||
432 | /* Locking and synchronization: | ||
433 | * | ||
434 | * The basic principle is that everything is serialized through a | ||
435 | * single spinlock, priv->lock. The lock is used in user, bh and irq | ||
436 | * context, so when taken outside hardirq context it should always be | ||
437 | * taken with interrupts disabled. The lock protects both the | ||
438 | * hardware and the struct orinoco_private. | ||
439 | * | ||
440 | * Another flag, priv->hw_unavailable indicates that the hardware is | ||
441 | * unavailable for an extended period of time (e.g. suspended, or in | ||
442 | * the middle of a hard reset). This flag is protected by the | ||
443 | * spinlock. All code which touches the hardware should check the | ||
444 | * flag after taking the lock, and if it is set, give up on whatever | ||
445 | * they are doing and drop the lock again. The orinoco_lock() | ||
446 | * function handles this (it unlocks and returns -EBUSY if | ||
447 | * hw_unavailable is non-zero). | ||
448 | */ | ||
449 | |||
450 | #define DRIVER_NAME "orinoco" | ||
451 | |||
452 | #include <linux/config.h> | ||
453 | |||
454 | #include <linux/module.h> | ||
455 | #include <linux/kernel.h> | ||
456 | #include <linux/init.h> | ||
457 | #include <linux/ptrace.h> | ||
458 | #include <linux/slab.h> | ||
459 | #include <linux/string.h> | ||
460 | #include <linux/timer.h> | ||
461 | #include <linux/ioport.h> | ||
462 | #include <linux/netdevice.h> | ||
463 | #include <linux/if_arp.h> | ||
464 | #include <linux/etherdevice.h> | ||
465 | #include <linux/wireless.h> | ||
466 | |||
467 | #include <asm/uaccess.h> | ||
468 | #include <asm/io.h> | ||
469 | #include <asm/system.h> | ||
470 | |||
471 | #include "hermes.h" | ||
472 | #include "hermes_rid.h" | ||
473 | #include "orinoco.h" | ||
474 | #include "ieee802_11.h" | ||
475 | |||
476 | /********************************************************************/ | ||
477 | /* Module information */ | ||
478 | /********************************************************************/ | ||
479 | |||
480 | MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>"); | ||
481 | MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); | ||
482 | MODULE_LICENSE("Dual MPL/GPL"); | ||
483 | |||
484 | /* Level of debugging. Used in the macros in orinoco.h */ | ||
485 | #ifdef ORINOCO_DEBUG | ||
486 | int orinoco_debug = ORINOCO_DEBUG; | ||
487 | module_param(orinoco_debug, int, 0644); | ||
488 | MODULE_PARM_DESC(orinoco_debug, "Debug level"); | ||
489 | EXPORT_SYMBOL(orinoco_debug); | ||
490 | #endif | ||
491 | |||
492 | static int suppress_linkstatus; /* = 0 */ | ||
493 | module_param(suppress_linkstatus, bool, 0644); | ||
494 | MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); | ||
495 | |||
496 | /********************************************************************/ | ||
497 | /* Compile time configuration and compatibility stuff */ | ||
498 | /********************************************************************/ | ||
499 | |||
500 | /* We do this this way to avoid ifdefs in the actual code */ | ||
501 | #ifdef WIRELESS_SPY | ||
502 | #define SPY_NUMBER(priv) (priv->spy_number) | ||
503 | #else | ||
504 | #define SPY_NUMBER(priv) 0 | ||
505 | #endif /* WIRELESS_SPY */ | ||
506 | |||
507 | /********************************************************************/ | ||
508 | /* Internal constants */ | ||
509 | /********************************************************************/ | ||
510 | |||
511 | #define ORINOCO_MIN_MTU 256 | ||
512 | #define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD) | ||
513 | |||
514 | #define SYMBOL_MAX_VER_LEN (14) | ||
515 | #define USER_BAP 0 | ||
516 | #define IRQ_BAP 1 | ||
517 | #define MAX_IRQLOOPS_PER_IRQ 10 | ||
518 | #define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of | ||
519 | * how many events the | ||
520 | * device could | ||
521 | * legitimately generate */ | ||
522 | #define SMALL_KEY_SIZE 5 | ||
523 | #define LARGE_KEY_SIZE 13 | ||
524 | #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ | ||
525 | |||
526 | #define DUMMY_FID 0xFFFF | ||
527 | |||
528 | /*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ | ||
529 | HERMES_MAX_MULTICAST : 0)*/ | ||
530 | #define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) | ||
531 | |||
532 | #define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ | ||
533 | | HERMES_EV_TX | HERMES_EV_TXEXC \ | ||
534 | | HERMES_EV_WTERR | HERMES_EV_INFO \ | ||
535 | | HERMES_EV_INFDROP ) | ||
536 | |||
537 | /********************************************************************/ | ||
538 | /* Data tables */ | ||
539 | /********************************************************************/ | ||
540 | |||
541 | /* The frequency of each channel in MHz */ | ||
542 | static const long channel_frequency[] = { | ||
543 | 2412, 2417, 2422, 2427, 2432, 2437, 2442, | ||
544 | 2447, 2452, 2457, 2462, 2467, 2472, 2484 | ||
545 | }; | ||
546 | #define NUM_CHANNELS ARRAY_SIZE(channel_frequency) | ||
547 | |||
548 | /* This tables gives the actual meanings of the bitrate IDs returned | ||
549 | * by the firmware. */ | ||
550 | static struct { | ||
551 | int bitrate; /* in 100s of kilobits */ | ||
552 | int automatic; | ||
553 | u16 agere_txratectrl; | ||
554 | u16 intersil_txratectrl; | ||
555 | } bitrate_table[] = { | ||
556 | {110, 1, 3, 15}, /* Entry 0 is the default */ | ||
557 | {10, 0, 1, 1}, | ||
558 | {10, 1, 1, 1}, | ||
559 | {20, 0, 2, 2}, | ||
560 | {20, 1, 6, 3}, | ||
561 | {55, 0, 4, 4}, | ||
562 | {55, 1, 7, 7}, | ||
563 | {110, 0, 5, 8}, | ||
564 | }; | ||
565 | #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) | ||
566 | |||
567 | /********************************************************************/ | ||
568 | /* Data types */ | ||
569 | /********************************************************************/ | ||
570 | |||
571 | struct header_struct { | ||
572 | /* 802.3 */ | ||
573 | u8 dest[ETH_ALEN]; | ||
574 | u8 src[ETH_ALEN]; | ||
575 | u16 len; | ||
576 | /* 802.2 */ | ||
577 | u8 dsap; | ||
578 | u8 ssap; | ||
579 | u8 ctrl; | ||
580 | /* SNAP */ | ||
581 | u8 oui[3]; | ||
582 | u16 ethertype; | ||
583 | } __attribute__ ((packed)); | ||
584 | |||
585 | /* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ | ||
586 | u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | ||
587 | |||
588 | #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) | ||
589 | |||
590 | struct hermes_rx_descriptor { | ||
591 | u16 status; | ||
592 | u32 time; | ||
593 | u8 silence; | ||
594 | u8 signal; | ||
595 | u8 rate; | ||
596 | u8 rxflow; | ||
597 | u32 reserved; | ||
598 | } __attribute__ ((packed)); | ||
599 | |||
600 | /********************************************************************/ | ||
601 | /* Function prototypes */ | ||
602 | /********************************************************************/ | ||
603 | |||
604 | static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | ||
605 | static int __orinoco_program_rids(struct net_device *dev); | ||
606 | static void __orinoco_set_multicast_list(struct net_device *dev); | ||
607 | static int orinoco_debug_dump_recs(struct net_device *dev); | ||
608 | |||
609 | /********************************************************************/ | ||
610 | /* Internal helper functions */ | ||
611 | /********************************************************************/ | ||
612 | |||
613 | static inline void set_port_type(struct orinoco_private *priv) | ||
614 | { | ||
615 | switch (priv->iw_mode) { | ||
616 | case IW_MODE_INFRA: | ||
617 | priv->port_type = 1; | ||
618 | priv->createibss = 0; | ||
619 | break; | ||
620 | case IW_MODE_ADHOC: | ||
621 | if (priv->prefer_port3) { | ||
622 | priv->port_type = 3; | ||
623 | priv->createibss = 0; | ||
624 | } else { | ||
625 | priv->port_type = priv->ibss_port; | ||
626 | priv->createibss = 1; | ||
627 | } | ||
628 | break; | ||
629 | default: | ||
630 | printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", | ||
631 | priv->ndev->name); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | /********************************************************************/ | ||
636 | /* Device methods */ | ||
637 | /********************************************************************/ | ||
638 | |||
639 | static int orinoco_open(struct net_device *dev) | ||
640 | { | ||
641 | struct orinoco_private *priv = netdev_priv(dev); | ||
642 | unsigned long flags; | ||
643 | int err; | ||
644 | |||
645 | if (orinoco_lock(priv, &flags) != 0) | ||
646 | return -EBUSY; | ||
647 | |||
648 | err = __orinoco_up(dev); | ||
649 | |||
650 | if (! err) | ||
651 | priv->open = 1; | ||
652 | |||
653 | orinoco_unlock(priv, &flags); | ||
654 | |||
655 | return err; | ||
656 | } | ||
657 | |||
658 | int orinoco_stop(struct net_device *dev) | ||
659 | { | ||
660 | struct orinoco_private *priv = netdev_priv(dev); | ||
661 | int err = 0; | ||
662 | |||
663 | /* We mustn't use orinoco_lock() here, because we need to be | ||
664 | able to close the interface even if hw_unavailable is set | ||
665 | (e.g. as we're released after a PC Card removal) */ | ||
666 | spin_lock_irq(&priv->lock); | ||
667 | |||
668 | priv->open = 0; | ||
669 | |||
670 | err = __orinoco_down(dev); | ||
671 | |||
672 | spin_unlock_irq(&priv->lock); | ||
673 | |||
674 | return err; | ||
675 | } | ||
676 | |||
677 | static struct net_device_stats *orinoco_get_stats(struct net_device *dev) | ||
678 | { | ||
679 | struct orinoco_private *priv = netdev_priv(dev); | ||
680 | |||
681 | return &priv->stats; | ||
682 | } | ||
683 | |||
684 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) | ||
685 | { | ||
686 | struct orinoco_private *priv = netdev_priv(dev); | ||
687 | hermes_t *hw = &priv->hw; | ||
688 | struct iw_statistics *wstats = &priv->wstats; | ||
689 | int err = 0; | ||
690 | unsigned long flags; | ||
691 | |||
692 | if (! netif_device_present(dev)) { | ||
693 | printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", | ||
694 | dev->name); | ||
695 | return NULL; /* FIXME: Can we do better than this? */ | ||
696 | } | ||
697 | |||
698 | if (orinoco_lock(priv, &flags) != 0) | ||
699 | return NULL; /* FIXME: Erg, we've been signalled, how | ||
700 | * do we propagate this back up? */ | ||
701 | |||
702 | if (priv->iw_mode == IW_MODE_ADHOC) { | ||
703 | memset(&wstats->qual, 0, sizeof(wstats->qual)); | ||
704 | /* If a spy address is defined, we report stats of the | ||
705 | * first spy address - Jean II */ | ||
706 | if (SPY_NUMBER(priv)) { | ||
707 | wstats->qual.qual = priv->spy_stat[0].qual; | ||
708 | wstats->qual.level = priv->spy_stat[0].level; | ||
709 | wstats->qual.noise = priv->spy_stat[0].noise; | ||
710 | wstats->qual.updated = priv->spy_stat[0].updated; | ||
711 | } | ||
712 | } else { | ||
713 | struct { | ||
714 | u16 qual, signal, noise; | ||
715 | } __attribute__ ((packed)) cq; | ||
716 | |||
717 | err = HERMES_READ_RECORD(hw, USER_BAP, | ||
718 | HERMES_RID_COMMSQUALITY, &cq); | ||
719 | |||
720 | wstats->qual.qual = (int)le16_to_cpu(cq.qual); | ||
721 | wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; | ||
722 | wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; | ||
723 | wstats->qual.updated = 7; | ||
724 | } | ||
725 | |||
726 | /* We can't really wait for the tallies inquiry command to | ||
727 | * complete, so we just use the previous results and trigger | ||
728 | * a new tallies inquiry command for next time - Jean II */ | ||
729 | /* FIXME: We're in user context (I think?), so we should just | ||
730 | wait for the tallies to come through */ | ||
731 | err = hermes_inquire(hw, HERMES_INQ_TALLIES); | ||
732 | |||
733 | orinoco_unlock(priv, &flags); | ||
734 | |||
735 | if (err) | ||
736 | return NULL; | ||
737 | |||
738 | return wstats; | ||
739 | } | ||
740 | |||
741 | static void orinoco_set_multicast_list(struct net_device *dev) | ||
742 | { | ||
743 | struct orinoco_private *priv = netdev_priv(dev); | ||
744 | unsigned long flags; | ||
745 | |||
746 | if (orinoco_lock(priv, &flags) != 0) { | ||
747 | printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " | ||
748 | "called when hw_unavailable\n", dev->name); | ||
749 | return; | ||
750 | } | ||
751 | |||
752 | __orinoco_set_multicast_list(dev); | ||
753 | orinoco_unlock(priv, &flags); | ||
754 | } | ||
755 | |||
756 | static int orinoco_change_mtu(struct net_device *dev, int new_mtu) | ||
757 | { | ||
758 | struct orinoco_private *priv = netdev_priv(dev); | ||
759 | |||
760 | if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) | ||
761 | return -EINVAL; | ||
762 | |||
763 | if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > | ||
764 | (priv->nicbuf_size - ETH_HLEN) ) | ||
765 | return -EINVAL; | ||
766 | |||
767 | dev->mtu = new_mtu; | ||
768 | |||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | /********************************************************************/ | ||
773 | /* Tx path */ | ||
774 | /********************************************************************/ | ||
775 | |||
776 | static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | ||
777 | { | ||
778 | struct orinoco_private *priv = netdev_priv(dev); | ||
779 | struct net_device_stats *stats = &priv->stats; | ||
780 | hermes_t *hw = &priv->hw; | ||
781 | int err = 0; | ||
782 | u16 txfid = priv->txfid; | ||
783 | char *p; | ||
784 | struct ethhdr *eh; | ||
785 | int len, data_len, data_off; | ||
786 | struct hermes_tx_descriptor desc; | ||
787 | unsigned long flags; | ||
788 | |||
789 | TRACE_ENTER(dev->name); | ||
790 | |||
791 | if (! netif_running(dev)) { | ||
792 | printk(KERN_ERR "%s: Tx on stopped device!\n", | ||
793 | dev->name); | ||
794 | TRACE_EXIT(dev->name); | ||
795 | return 1; | ||
796 | } | ||
797 | |||
798 | if (netif_queue_stopped(dev)) { | ||
799 | printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", | ||
800 | dev->name); | ||
801 | TRACE_EXIT(dev->name); | ||
802 | return 1; | ||
803 | } | ||
804 | |||
805 | if (orinoco_lock(priv, &flags) != 0) { | ||
806 | printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", | ||
807 | dev->name); | ||
808 | TRACE_EXIT(dev->name); | ||
809 | return 1; | ||
810 | } | ||
811 | |||
812 | if (! netif_carrier_ok(dev)) { | ||
813 | /* Oops, the firmware hasn't established a connection, | ||
814 | silently drop the packet (this seems to be the | ||
815 | safest approach). */ | ||
816 | stats->tx_errors++; | ||
817 | orinoco_unlock(priv, &flags); | ||
818 | dev_kfree_skb(skb); | ||
819 | TRACE_EXIT(dev->name); | ||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | /* Length of the packet body */ | ||
824 | /* FIXME: what if the skb is smaller than this? */ | ||
825 | len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); | ||
826 | |||
827 | eh = (struct ethhdr *)skb->data; | ||
828 | |||
829 | memset(&desc, 0, sizeof(desc)); | ||
830 | desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); | ||
831 | err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); | ||
832 | if (err) { | ||
833 | if (net_ratelimit()) | ||
834 | printk(KERN_ERR "%s: Error %d writing Tx descriptor " | ||
835 | "to BAP\n", dev->name, err); | ||
836 | stats->tx_errors++; | ||
837 | goto fail; | ||
838 | } | ||
839 | |||
840 | /* Clear the 802.11 header and data length fields - some | ||
841 | * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused | ||
842 | * if this isn't done. */ | ||
843 | hermes_clear_words(hw, HERMES_DATA0, | ||
844 | HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); | ||
845 | |||
846 | /* Encapsulate Ethernet-II frames */ | ||
847 | if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ | ||
848 | struct header_struct hdr; | ||
849 | data_len = len; | ||
850 | data_off = HERMES_802_3_OFFSET + sizeof(hdr); | ||
851 | p = skb->data + ETH_HLEN; | ||
852 | |||
853 | /* 802.3 header */ | ||
854 | memcpy(hdr.dest, eh->h_dest, ETH_ALEN); | ||
855 | memcpy(hdr.src, eh->h_source, ETH_ALEN); | ||
856 | hdr.len = htons(data_len + ENCAPS_OVERHEAD); | ||
857 | |||
858 | /* 802.2 header */ | ||
859 | memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); | ||
860 | |||
861 | hdr.ethertype = eh->h_proto; | ||
862 | err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), | ||
863 | txfid, HERMES_802_3_OFFSET); | ||
864 | if (err) { | ||
865 | if (net_ratelimit()) | ||
866 | printk(KERN_ERR "%s: Error %d writing packet " | ||
867 | "header to BAP\n", dev->name, err); | ||
868 | stats->tx_errors++; | ||
869 | goto fail; | ||
870 | } | ||
871 | } else { /* IEEE 802.3 frame */ | ||
872 | data_len = len + ETH_HLEN; | ||
873 | data_off = HERMES_802_3_OFFSET; | ||
874 | p = skb->data; | ||
875 | } | ||
876 | |||
877 | /* Round up for odd length packets */ | ||
878 | err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), | ||
879 | txfid, data_off); | ||
880 | if (err) { | ||
881 | printk(KERN_ERR "%s: Error %d writing packet to BAP\n", | ||
882 | dev->name, err); | ||
883 | stats->tx_errors++; | ||
884 | goto fail; | ||
885 | } | ||
886 | |||
887 | /* Finally, we actually initiate the send */ | ||
888 | netif_stop_queue(dev); | ||
889 | |||
890 | err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, | ||
891 | txfid, NULL); | ||
892 | if (err) { | ||
893 | netif_start_queue(dev); | ||
894 | printk(KERN_ERR "%s: Error %d transmitting packet\n", | ||
895 | dev->name, err); | ||
896 | stats->tx_errors++; | ||
897 | goto fail; | ||
898 | } | ||
899 | |||
900 | dev->trans_start = jiffies; | ||
901 | stats->tx_bytes += data_off + data_len; | ||
902 | |||
903 | orinoco_unlock(priv, &flags); | ||
904 | |||
905 | dev_kfree_skb(skb); | ||
906 | |||
907 | TRACE_EXIT(dev->name); | ||
908 | |||
909 | return 0; | ||
910 | fail: | ||
911 | TRACE_EXIT(dev->name); | ||
912 | |||
913 | orinoco_unlock(priv, &flags); | ||
914 | return err; | ||
915 | } | ||
916 | |||
917 | static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) | ||
918 | { | ||
919 | struct orinoco_private *priv = netdev_priv(dev); | ||
920 | u16 fid = hermes_read_regn(hw, ALLOCFID); | ||
921 | |||
922 | if (fid != priv->txfid) { | ||
923 | if (fid != DUMMY_FID) | ||
924 | printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", | ||
925 | dev->name, fid); | ||
926 | return; | ||
927 | } | ||
928 | |||
929 | hermes_write_regn(hw, ALLOCFID, DUMMY_FID); | ||
930 | } | ||
931 | |||
932 | static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) | ||
933 | { | ||
934 | struct orinoco_private *priv = netdev_priv(dev); | ||
935 | struct net_device_stats *stats = &priv->stats; | ||
936 | |||
937 | stats->tx_packets++; | ||
938 | |||
939 | netif_wake_queue(dev); | ||
940 | |||
941 | hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); | ||
942 | } | ||
943 | |||
944 | static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) | ||
945 | { | ||
946 | struct orinoco_private *priv = netdev_priv(dev); | ||
947 | struct net_device_stats *stats = &priv->stats; | ||
948 | u16 fid = hermes_read_regn(hw, TXCOMPLFID); | ||
949 | struct hermes_tx_descriptor desc; | ||
950 | int err = 0; | ||
951 | |||
952 | if (fid == DUMMY_FID) | ||
953 | return; /* Nothing's really happened */ | ||
954 | |||
955 | err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); | ||
956 | if (err) { | ||
957 | printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " | ||
958 | "(FID=%04X error %d)\n", | ||
959 | dev->name, fid, err); | ||
960 | } else { | ||
961 | DEBUG(1, "%s: Tx error, status %d\n", | ||
962 | dev->name, le16_to_cpu(desc.status)); | ||
963 | } | ||
964 | |||
965 | stats->tx_errors++; | ||
966 | |||
967 | netif_wake_queue(dev); | ||
968 | hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); | ||
969 | } | ||
970 | |||
971 | static void orinoco_tx_timeout(struct net_device *dev) | ||
972 | { | ||
973 | struct orinoco_private *priv = netdev_priv(dev); | ||
974 | struct net_device_stats *stats = &priv->stats; | ||
975 | struct hermes *hw = &priv->hw; | ||
976 | |||
977 | printk(KERN_WARNING "%s: Tx timeout! " | ||
978 | "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", | ||
979 | dev->name, hermes_read_regn(hw, ALLOCFID), | ||
980 | hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); | ||
981 | |||
982 | stats->tx_errors++; | ||
983 | |||
984 | schedule_work(&priv->reset_work); | ||
985 | } | ||
986 | |||
987 | /********************************************************************/ | ||
988 | /* Rx path (data frames) */ | ||
989 | /********************************************************************/ | ||
990 | |||
991 | /* Does the frame have a SNAP header indicating it should be | ||
992 | * de-encapsulated to Ethernet-II? */ | ||
993 | static inline int is_ethersnap(void *_hdr) | ||
994 | { | ||
995 | u8 *hdr = _hdr; | ||
996 | |||
997 | /* We de-encapsulate all packets which, a) have SNAP headers | ||
998 | * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header | ||
999 | * and where b) the OUI of the SNAP header is 00:00:00 or | ||
1000 | * 00:00:f8 - we need both because different APs appear to use | ||
1001 | * different OUIs for some reason */ | ||
1002 | return (memcmp(hdr, &encaps_hdr, 5) == 0) | ||
1003 | && ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) ); | ||
1004 | } | ||
1005 | |||
1006 | static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, | ||
1007 | int level, int noise) | ||
1008 | { | ||
1009 | struct orinoco_private *priv = netdev_priv(dev); | ||
1010 | int i; | ||
1011 | |||
1012 | /* Gather wireless spy statistics: for each packet, compare the | ||
1013 | * source address with out list, and if match, get the stats... */ | ||
1014 | for (i = 0; i < priv->spy_number; i++) | ||
1015 | if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { | ||
1016 | priv->spy_stat[i].level = level - 0x95; | ||
1017 | priv->spy_stat[i].noise = noise - 0x95; | ||
1018 | priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; | ||
1019 | priv->spy_stat[i].updated = 7; | ||
1020 | } | ||
1021 | } | ||
1022 | |||
1023 | static void orinoco_stat_gather(struct net_device *dev, | ||
1024 | struct sk_buff *skb, | ||
1025 | struct hermes_rx_descriptor *desc) | ||
1026 | { | ||
1027 | struct orinoco_private *priv = netdev_priv(dev); | ||
1028 | |||
1029 | /* Using spy support with lots of Rx packets, like in an | ||
1030 | * infrastructure (AP), will really slow down everything, because | ||
1031 | * the MAC address must be compared to each entry of the spy list. | ||
1032 | * If the user really asks for it (set some address in the | ||
1033 | * spy list), we do it, but he will pay the price. | ||
1034 | * Note that to get here, you need both WIRELESS_SPY | ||
1035 | * compiled in AND some addresses in the list !!! | ||
1036 | */ | ||
1037 | /* Note : gcc will optimise the whole section away if | ||
1038 | * WIRELESS_SPY is not defined... - Jean II */ | ||
1039 | if (SPY_NUMBER(priv)) { | ||
1040 | orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, | ||
1041 | desc->signal, desc->silence); | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | ||
1046 | { | ||
1047 | struct orinoco_private *priv = netdev_priv(dev); | ||
1048 | struct net_device_stats *stats = &priv->stats; | ||
1049 | struct iw_statistics *wstats = &priv->wstats; | ||
1050 | struct sk_buff *skb = NULL; | ||
1051 | u16 rxfid, status; | ||
1052 | int length, data_len, data_off; | ||
1053 | char *p; | ||
1054 | struct hermes_rx_descriptor desc; | ||
1055 | struct header_struct hdr; | ||
1056 | struct ethhdr *eh; | ||
1057 | int err; | ||
1058 | |||
1059 | rxfid = hermes_read_regn(hw, RXFID); | ||
1060 | |||
1061 | err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), | ||
1062 | rxfid, 0); | ||
1063 | if (err) { | ||
1064 | printk(KERN_ERR "%s: error %d reading Rx descriptor. " | ||
1065 | "Frame dropped.\n", dev->name, err); | ||
1066 | stats->rx_errors++; | ||
1067 | goto drop; | ||
1068 | } | ||
1069 | |||
1070 | status = le16_to_cpu(desc.status); | ||
1071 | |||
1072 | if (status & HERMES_RXSTAT_ERR) { | ||
1073 | if (status & HERMES_RXSTAT_UNDECRYPTABLE) { | ||
1074 | wstats->discard.code++; | ||
1075 | DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", | ||
1076 | dev->name); | ||
1077 | } else { | ||
1078 | stats->rx_crc_errors++; | ||
1079 | DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); | ||
1080 | } | ||
1081 | stats->rx_errors++; | ||
1082 | goto drop; | ||
1083 | } | ||
1084 | |||
1085 | /* For now we ignore the 802.11 header completely, assuming | ||
1086 | that the card's firmware has handled anything vital */ | ||
1087 | |||
1088 | err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), | ||
1089 | rxfid, HERMES_802_3_OFFSET); | ||
1090 | if (err) { | ||
1091 | printk(KERN_ERR "%s: error %d reading frame header. " | ||
1092 | "Frame dropped.\n", dev->name, err); | ||
1093 | stats->rx_errors++; | ||
1094 | goto drop; | ||
1095 | } | ||
1096 | |||
1097 | length = ntohs(hdr.len); | ||
1098 | |||
1099 | /* Sanity checks */ | ||
1100 | if (length < 3) { /* No for even an 802.2 LLC header */ | ||
1101 | /* At least on Symbol firmware with PCF we get quite a | ||
1102 | lot of these legitimately - Poll frames with no | ||
1103 | data. */ | ||
1104 | stats->rx_dropped++; | ||
1105 | goto drop; | ||
1106 | } | ||
1107 | if (length > IEEE802_11_DATA_LEN) { | ||
1108 | printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", | ||
1109 | dev->name, length); | ||
1110 | stats->rx_length_errors++; | ||
1111 | stats->rx_errors++; | ||
1112 | goto drop; | ||
1113 | } | ||
1114 | |||
1115 | /* We need space for the packet data itself, plus an ethernet | ||
1116 | header, plus 2 bytes so we can align the IP header on a | ||
1117 | 32bit boundary, plus 1 byte so we can read in odd length | ||
1118 | packets from the card, which has an IO granularity of 16 | ||
1119 | bits */ | ||
1120 | skb = dev_alloc_skb(length+ETH_HLEN+2+1); | ||
1121 | if (!skb) { | ||
1122 | printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", | ||
1123 | dev->name); | ||
1124 | goto drop; | ||
1125 | } | ||
1126 | |||
1127 | skb_reserve(skb, 2); /* This way the IP header is aligned */ | ||
1128 | |||
1129 | /* Handle decapsulation | ||
1130 | * In most cases, the firmware tell us about SNAP frames. | ||
1131 | * For some reason, the SNAP frames sent by LinkSys APs | ||
1132 | * are not properly recognised by most firmwares. | ||
1133 | * So, check ourselves */ | ||
1134 | if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || | ||
1135 | ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || | ||
1136 | is_ethersnap(&hdr)) { | ||
1137 | /* These indicate a SNAP within 802.2 LLC within | ||
1138 | 802.11 frame which we'll need to de-encapsulate to | ||
1139 | the original EthernetII frame. */ | ||
1140 | |||
1141 | if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ | ||
1142 | stats->rx_length_errors++; | ||
1143 | goto drop; | ||
1144 | } | ||
1145 | |||
1146 | /* Remove SNAP header, reconstruct EthernetII frame */ | ||
1147 | data_len = length - ENCAPS_OVERHEAD; | ||
1148 | data_off = HERMES_802_3_OFFSET + sizeof(hdr); | ||
1149 | |||
1150 | eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); | ||
1151 | |||
1152 | memcpy(eh, &hdr, 2 * ETH_ALEN); | ||
1153 | eh->h_proto = hdr.ethertype; | ||
1154 | } else { | ||
1155 | /* All other cases indicate a genuine 802.3 frame. No | ||
1156 | decapsulation needed. We just throw the whole | ||
1157 | thing in, and hope the protocol layer can deal with | ||
1158 | it as 802.3 */ | ||
1159 | data_len = length; | ||
1160 | data_off = HERMES_802_3_OFFSET; | ||
1161 | /* FIXME: we re-read from the card data we already read here */ | ||
1162 | } | ||
1163 | |||
1164 | p = skb_put(skb, data_len); | ||
1165 | err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2), | ||
1166 | rxfid, data_off); | ||
1167 | if (err) { | ||
1168 | printk(KERN_ERR "%s: error %d reading frame. " | ||
1169 | "Frame dropped.\n", dev->name, err); | ||
1170 | stats->rx_errors++; | ||
1171 | goto drop; | ||
1172 | } | ||
1173 | |||
1174 | dev->last_rx = jiffies; | ||
1175 | skb->dev = dev; | ||
1176 | skb->protocol = eth_type_trans(skb, dev); | ||
1177 | skb->ip_summed = CHECKSUM_NONE; | ||
1178 | |||
1179 | /* Process the wireless stats if needed */ | ||
1180 | orinoco_stat_gather(dev, skb, &desc); | ||
1181 | |||
1182 | /* Pass the packet to the networking stack */ | ||
1183 | netif_rx(skb); | ||
1184 | stats->rx_packets++; | ||
1185 | stats->rx_bytes += length; | ||
1186 | |||
1187 | return; | ||
1188 | |||
1189 | drop: | ||
1190 | stats->rx_dropped++; | ||
1191 | |||
1192 | if (skb) | ||
1193 | dev_kfree_skb_irq(skb); | ||
1194 | return; | ||
1195 | } | ||
1196 | |||
1197 | /********************************************************************/ | ||
1198 | /* Rx path (info frames) */ | ||
1199 | /********************************************************************/ | ||
1200 | |||
1201 | static void print_linkstatus(struct net_device *dev, u16 status) | ||
1202 | { | ||
1203 | char * s; | ||
1204 | |||
1205 | if (suppress_linkstatus) | ||
1206 | return; | ||
1207 | |||
1208 | switch (status) { | ||
1209 | case HERMES_LINKSTATUS_NOT_CONNECTED: | ||
1210 | s = "Not Connected"; | ||
1211 | break; | ||
1212 | case HERMES_LINKSTATUS_CONNECTED: | ||
1213 | s = "Connected"; | ||
1214 | break; | ||
1215 | case HERMES_LINKSTATUS_DISCONNECTED: | ||
1216 | s = "Disconnected"; | ||
1217 | break; | ||
1218 | case HERMES_LINKSTATUS_AP_CHANGE: | ||
1219 | s = "AP Changed"; | ||
1220 | break; | ||
1221 | case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: | ||
1222 | s = "AP Out of Range"; | ||
1223 | break; | ||
1224 | case HERMES_LINKSTATUS_AP_IN_RANGE: | ||
1225 | s = "AP In Range"; | ||
1226 | break; | ||
1227 | case HERMES_LINKSTATUS_ASSOC_FAILED: | ||
1228 | s = "Association Failed"; | ||
1229 | break; | ||
1230 | default: | ||
1231 | s = "UNKNOWN"; | ||
1232 | } | ||
1233 | |||
1234 | printk(KERN_INFO "%s: New link status: %s (%04x)\n", | ||
1235 | dev->name, s, status); | ||
1236 | } | ||
1237 | |||
1238 | static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | ||
1239 | { | ||
1240 | struct orinoco_private *priv = netdev_priv(dev); | ||
1241 | u16 infofid; | ||
1242 | struct { | ||
1243 | u16 len; | ||
1244 | u16 type; | ||
1245 | } __attribute__ ((packed)) info; | ||
1246 | int len, type; | ||
1247 | int err; | ||
1248 | |||
1249 | /* This is an answer to an INQUIRE command that we did earlier, | ||
1250 | * or an information "event" generated by the card | ||
1251 | * The controller return to us a pseudo frame containing | ||
1252 | * the information in question - Jean II */ | ||
1253 | infofid = hermes_read_regn(hw, INFOFID); | ||
1254 | |||
1255 | /* Read the info frame header - don't try too hard */ | ||
1256 | err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), | ||
1257 | infofid, 0); | ||
1258 | if (err) { | ||
1259 | printk(KERN_ERR "%s: error %d reading info frame. " | ||
1260 | "Frame dropped.\n", dev->name, err); | ||
1261 | return; | ||
1262 | } | ||
1263 | |||
1264 | len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); | ||
1265 | type = le16_to_cpu(info.type); | ||
1266 | |||
1267 | switch (type) { | ||
1268 | case HERMES_INQ_TALLIES: { | ||
1269 | struct hermes_tallies_frame tallies; | ||
1270 | struct iw_statistics *wstats = &priv->wstats; | ||
1271 | |||
1272 | if (len > sizeof(tallies)) { | ||
1273 | printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", | ||
1274 | dev->name, len); | ||
1275 | len = sizeof(tallies); | ||
1276 | } | ||
1277 | |||
1278 | /* Read directly the data (no seek) */ | ||
1279 | hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, | ||
1280 | len / 2); /* FIXME: blech! */ | ||
1281 | |||
1282 | /* Increment our various counters */ | ||
1283 | /* wstats->discard.nwid - no wrong BSSID stuff */ | ||
1284 | wstats->discard.code += | ||
1285 | le16_to_cpu(tallies.RxWEPUndecryptable); | ||
1286 | if (len == sizeof(tallies)) | ||
1287 | wstats->discard.code += | ||
1288 | le16_to_cpu(tallies.RxDiscards_WEPICVError) + | ||
1289 | le16_to_cpu(tallies.RxDiscards_WEPExcluded); | ||
1290 | wstats->discard.misc += | ||
1291 | le16_to_cpu(tallies.TxDiscardsWrongSA); | ||
1292 | wstats->discard.fragment += | ||
1293 | le16_to_cpu(tallies.RxMsgInBadMsgFragments); | ||
1294 | wstats->discard.retries += | ||
1295 | le16_to_cpu(tallies.TxRetryLimitExceeded); | ||
1296 | /* wstats->miss.beacon - no match */ | ||
1297 | } | ||
1298 | break; | ||
1299 | case HERMES_INQ_LINKSTATUS: { | ||
1300 | struct hermes_linkstatus linkstatus; | ||
1301 | u16 newstatus; | ||
1302 | int connected; | ||
1303 | |||
1304 | if (len != sizeof(linkstatus)) { | ||
1305 | printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", | ||
1306 | dev->name, len); | ||
1307 | break; | ||
1308 | } | ||
1309 | |||
1310 | hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus, | ||
1311 | len / 2); | ||
1312 | newstatus = le16_to_cpu(linkstatus.linkstatus); | ||
1313 | |||
1314 | connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) | ||
1315 | || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) | ||
1316 | || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); | ||
1317 | |||
1318 | if (connected) | ||
1319 | netif_carrier_on(dev); | ||
1320 | else | ||
1321 | netif_carrier_off(dev); | ||
1322 | |||
1323 | if (newstatus != priv->last_linkstatus) | ||
1324 | print_linkstatus(dev, newstatus); | ||
1325 | |||
1326 | priv->last_linkstatus = newstatus; | ||
1327 | } | ||
1328 | break; | ||
1329 | default: | ||
1330 | printk(KERN_DEBUG "%s: Unknown information frame received: " | ||
1331 | "type 0x%04x, length %d\n", dev->name, type, len); | ||
1332 | /* We don't actually do anything about it */ | ||
1333 | break; | ||
1334 | } | ||
1335 | } | ||
1336 | |||
1337 | static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) | ||
1338 | { | ||
1339 | if (net_ratelimit()) | ||
1340 | printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); | ||
1341 | } | ||
1342 | |||
1343 | /********************************************************************/ | ||
1344 | /* Internal hardware control routines */ | ||
1345 | /********************************************************************/ | ||
1346 | |||
1347 | int __orinoco_up(struct net_device *dev) | ||
1348 | { | ||
1349 | struct orinoco_private *priv = netdev_priv(dev); | ||
1350 | struct hermes *hw = &priv->hw; | ||
1351 | int err; | ||
1352 | |||
1353 | err = __orinoco_program_rids(dev); | ||
1354 | if (err) { | ||
1355 | printk(KERN_ERR "%s: Error %d configuring card\n", | ||
1356 | dev->name, err); | ||
1357 | return err; | ||
1358 | } | ||
1359 | |||
1360 | /* Fire things up again */ | ||
1361 | hermes_set_irqmask(hw, ORINOCO_INTEN); | ||
1362 | err = hermes_enable_port(hw, 0); | ||
1363 | if (err) { | ||
1364 | printk(KERN_ERR "%s: Error %d enabling MAC port\n", | ||
1365 | dev->name, err); | ||
1366 | return err; | ||
1367 | } | ||
1368 | |||
1369 | netif_start_queue(dev); | ||
1370 | |||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | int __orinoco_down(struct net_device *dev) | ||
1375 | { | ||
1376 | struct orinoco_private *priv = netdev_priv(dev); | ||
1377 | struct hermes *hw = &priv->hw; | ||
1378 | int err; | ||
1379 | |||
1380 | netif_stop_queue(dev); | ||
1381 | |||
1382 | if (! priv->hw_unavailable) { | ||
1383 | if (! priv->broken_disableport) { | ||
1384 | err = hermes_disable_port(hw, 0); | ||
1385 | if (err) { | ||
1386 | /* Some firmwares (e.g. Intersil 1.3.x) seem | ||
1387 | * to have problems disabling the port, oh | ||
1388 | * well, too bad. */ | ||
1389 | printk(KERN_WARNING "%s: Error %d disabling MAC port\n", | ||
1390 | dev->name, err); | ||
1391 | priv->broken_disableport = 1; | ||
1392 | } | ||
1393 | } | ||
1394 | hermes_set_irqmask(hw, 0); | ||
1395 | hermes_write_regn(hw, EVACK, 0xffff); | ||
1396 | } | ||
1397 | |||
1398 | /* firmware will have to reassociate */ | ||
1399 | netif_carrier_off(dev); | ||
1400 | priv->last_linkstatus = 0xffff; | ||
1401 | |||
1402 | return 0; | ||
1403 | } | ||
1404 | |||
1405 | int orinoco_reinit_firmware(struct net_device *dev) | ||
1406 | { | ||
1407 | struct orinoco_private *priv = netdev_priv(dev); | ||
1408 | struct hermes *hw = &priv->hw; | ||
1409 | int err; | ||
1410 | |||
1411 | err = hermes_init(hw); | ||
1412 | if (err) | ||
1413 | return err; | ||
1414 | |||
1415 | err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); | ||
1416 | if (err == -EIO) { | ||
1417 | /* Try workaround for old Symbol firmware bug */ | ||
1418 | printk(KERN_WARNING "%s: firmware ALLOC bug detected " | ||
1419 | "(old Symbol firmware?). Trying to work around... ", | ||
1420 | dev->name); | ||
1421 | |||
1422 | priv->nicbuf_size = TX_NICBUF_SIZE_BUG; | ||
1423 | err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); | ||
1424 | if (err) | ||
1425 | printk("failed!\n"); | ||
1426 | else | ||
1427 | printk("ok.\n"); | ||
1428 | } | ||
1429 | |||
1430 | return err; | ||
1431 | } | ||
1432 | |||
1433 | static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) | ||
1434 | { | ||
1435 | hermes_t *hw = &priv->hw; | ||
1436 | int err = 0; | ||
1437 | |||
1438 | if (priv->bitratemode >= BITRATE_TABLE_SIZE) { | ||
1439 | printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", | ||
1440 | priv->ndev->name, priv->bitratemode); | ||
1441 | return -EINVAL; | ||
1442 | } | ||
1443 | |||
1444 | switch (priv->firmware_type) { | ||
1445 | case FIRMWARE_TYPE_AGERE: | ||
1446 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1447 | HERMES_RID_CNFTXRATECONTROL, | ||
1448 | bitrate_table[priv->bitratemode].agere_txratectrl); | ||
1449 | break; | ||
1450 | case FIRMWARE_TYPE_INTERSIL: | ||
1451 | case FIRMWARE_TYPE_SYMBOL: | ||
1452 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1453 | HERMES_RID_CNFTXRATECONTROL, | ||
1454 | bitrate_table[priv->bitratemode].intersil_txratectrl); | ||
1455 | break; | ||
1456 | default: | ||
1457 | BUG(); | ||
1458 | } | ||
1459 | |||
1460 | return err; | ||
1461 | } | ||
1462 | |||
1463 | /* Change the WEP keys and/or the current keys. Can be called | ||
1464 | * either from __orinoco_hw_setup_wep() or directly from | ||
1465 | * orinoco_ioctl_setiwencode(). In the later case the association | ||
1466 | * with the AP is not broken (if the firmware can handle it), | ||
1467 | * which is needed for 802.1x implementations. */ | ||
1468 | static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | ||
1469 | { | ||
1470 | hermes_t *hw = &priv->hw; | ||
1471 | int err = 0; | ||
1472 | |||
1473 | switch (priv->firmware_type) { | ||
1474 | case FIRMWARE_TYPE_AGERE: | ||
1475 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1476 | HERMES_RID_CNFWEPKEYS_AGERE, | ||
1477 | &priv->keys); | ||
1478 | if (err) | ||
1479 | return err; | ||
1480 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1481 | HERMES_RID_CNFTXKEY_AGERE, | ||
1482 | priv->tx_key); | ||
1483 | if (err) | ||
1484 | return err; | ||
1485 | break; | ||
1486 | case FIRMWARE_TYPE_INTERSIL: | ||
1487 | case FIRMWARE_TYPE_SYMBOL: | ||
1488 | { | ||
1489 | int keylen; | ||
1490 | int i; | ||
1491 | |||
1492 | /* Force uniform key length to work around firmware bugs */ | ||
1493 | keylen = le16_to_cpu(priv->keys[priv->tx_key].len); | ||
1494 | |||
1495 | if (keylen > LARGE_KEY_SIZE) { | ||
1496 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", | ||
1497 | priv->ndev->name, priv->tx_key, keylen); | ||
1498 | return -E2BIG; | ||
1499 | } | ||
1500 | |||
1501 | /* Write all 4 keys */ | ||
1502 | for(i = 0; i < ORINOCO_MAX_KEYS; i++) { | ||
1503 | err = hermes_write_ltv(hw, USER_BAP, | ||
1504 | HERMES_RID_CNFDEFAULTKEY0 + i, | ||
1505 | HERMES_BYTES_TO_RECLEN(keylen), | ||
1506 | priv->keys[i].data); | ||
1507 | if (err) | ||
1508 | return err; | ||
1509 | } | ||
1510 | |||
1511 | /* Write the index of the key used in transmission */ | ||
1512 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1513 | HERMES_RID_CNFWEPDEFAULTKEYID, | ||
1514 | priv->tx_key); | ||
1515 | if (err) | ||
1516 | return err; | ||
1517 | } | ||
1518 | break; | ||
1519 | } | ||
1520 | |||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | static int __orinoco_hw_setup_wep(struct orinoco_private *priv) | ||
1525 | { | ||
1526 | hermes_t *hw = &priv->hw; | ||
1527 | int err = 0; | ||
1528 | int master_wep_flag; | ||
1529 | int auth_flag; | ||
1530 | |||
1531 | if (priv->wep_on) | ||
1532 | __orinoco_hw_setup_wepkeys(priv); | ||
1533 | |||
1534 | if (priv->wep_restrict) | ||
1535 | auth_flag = HERMES_AUTH_SHARED_KEY; | ||
1536 | else | ||
1537 | auth_flag = HERMES_AUTH_OPEN; | ||
1538 | |||
1539 | switch (priv->firmware_type) { | ||
1540 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ | ||
1541 | if (priv->wep_on) { | ||
1542 | /* Enable the shared-key authentication. */ | ||
1543 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1544 | HERMES_RID_CNFAUTHENTICATION_AGERE, | ||
1545 | auth_flag); | ||
1546 | } | ||
1547 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1548 | HERMES_RID_CNFWEPENABLED_AGERE, | ||
1549 | priv->wep_on); | ||
1550 | if (err) | ||
1551 | return err; | ||
1552 | break; | ||
1553 | |||
1554 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ | ||
1555 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ | ||
1556 | if (priv->wep_on) { | ||
1557 | if (priv->wep_restrict || | ||
1558 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) | ||
1559 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | | ||
1560 | HERMES_WEP_EXCL_UNENCRYPTED; | ||
1561 | else | ||
1562 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; | ||
1563 | |||
1564 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1565 | HERMES_RID_CNFAUTHENTICATION, | ||
1566 | auth_flag); | ||
1567 | if (err) | ||
1568 | return err; | ||
1569 | } else | ||
1570 | master_wep_flag = 0; | ||
1571 | |||
1572 | if (priv->iw_mode == IW_MODE_MONITOR) | ||
1573 | master_wep_flag |= HERMES_WEP_HOST_DECRYPT; | ||
1574 | |||
1575 | /* Master WEP setting : on/off */ | ||
1576 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1577 | HERMES_RID_CNFWEPFLAGS_INTERSIL, | ||
1578 | master_wep_flag); | ||
1579 | if (err) | ||
1580 | return err; | ||
1581 | |||
1582 | break; | ||
1583 | } | ||
1584 | |||
1585 | return 0; | ||
1586 | } | ||
1587 | |||
1588 | static int __orinoco_program_rids(struct net_device *dev) | ||
1589 | { | ||
1590 | struct orinoco_private *priv = netdev_priv(dev); | ||
1591 | hermes_t *hw = &priv->hw; | ||
1592 | int err; | ||
1593 | struct hermes_idstring idbuf; | ||
1594 | |||
1595 | /* Set the MAC address */ | ||
1596 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, | ||
1597 | HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); | ||
1598 | if (err) { | ||
1599 | printk(KERN_ERR "%s: Error %d setting MAC address\n", | ||
1600 | dev->name, err); | ||
1601 | return err; | ||
1602 | } | ||
1603 | |||
1604 | /* Set up the link mode */ | ||
1605 | err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, | ||
1606 | priv->port_type); | ||
1607 | if (err) { | ||
1608 | printk(KERN_ERR "%s: Error %d setting port type\n", | ||
1609 | dev->name, err); | ||
1610 | return err; | ||
1611 | } | ||
1612 | /* Set the channel/frequency */ | ||
1613 | if (priv->channel == 0) { | ||
1614 | printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name); | ||
1615 | if (priv->createibss) | ||
1616 | priv->channel = 10; | ||
1617 | } | ||
1618 | err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, | ||
1619 | priv->channel); | ||
1620 | if (err) { | ||
1621 | printk(KERN_ERR "%s: Error %d setting channel\n", | ||
1622 | dev->name, err); | ||
1623 | return err; | ||
1624 | } | ||
1625 | |||
1626 | if (priv->has_ibss) { | ||
1627 | u16 createibss; | ||
1628 | |||
1629 | if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { | ||
1630 | printk(KERN_WARNING "%s: This firmware requires an " | ||
1631 | "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); | ||
1632 | /* With wvlan_cs, in this case, we would crash. | ||
1633 | * hopefully, this driver will behave better... | ||
1634 | * Jean II */ | ||
1635 | createibss = 0; | ||
1636 | } else { | ||
1637 | createibss = priv->createibss; | ||
1638 | } | ||
1639 | |||
1640 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1641 | HERMES_RID_CNFCREATEIBSS, | ||
1642 | createibss); | ||
1643 | if (err) { | ||
1644 | printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", | ||
1645 | dev->name, err); | ||
1646 | return err; | ||
1647 | } | ||
1648 | } | ||
1649 | |||
1650 | /* Set the desired ESSID */ | ||
1651 | idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); | ||
1652 | memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); | ||
1653 | /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ | ||
1654 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, | ||
1655 | HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), | ||
1656 | &idbuf); | ||
1657 | if (err) { | ||
1658 | printk(KERN_ERR "%s: Error %d setting OWNSSID\n", | ||
1659 | dev->name, err); | ||
1660 | return err; | ||
1661 | } | ||
1662 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, | ||
1663 | HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), | ||
1664 | &idbuf); | ||
1665 | if (err) { | ||
1666 | printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", | ||
1667 | dev->name, err); | ||
1668 | return err; | ||
1669 | } | ||
1670 | |||
1671 | /* Set the station name */ | ||
1672 | idbuf.len = cpu_to_le16(strlen(priv->nick)); | ||
1673 | memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); | ||
1674 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, | ||
1675 | HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), | ||
1676 | &idbuf); | ||
1677 | if (err) { | ||
1678 | printk(KERN_ERR "%s: Error %d setting nickname\n", | ||
1679 | dev->name, err); | ||
1680 | return err; | ||
1681 | } | ||
1682 | |||
1683 | /* Set AP density */ | ||
1684 | if (priv->has_sensitivity) { | ||
1685 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1686 | HERMES_RID_CNFSYSTEMSCALE, | ||
1687 | priv->ap_density); | ||
1688 | if (err) { | ||
1689 | printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " | ||
1690 | "Disabling sensitivity control\n", | ||
1691 | dev->name, err); | ||
1692 | |||
1693 | priv->has_sensitivity = 0; | ||
1694 | } | ||
1695 | } | ||
1696 | |||
1697 | /* Set RTS threshold */ | ||
1698 | err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, | ||
1699 | priv->rts_thresh); | ||
1700 | if (err) { | ||
1701 | printk(KERN_ERR "%s: Error %d setting RTS threshold\n", | ||
1702 | dev->name, err); | ||
1703 | return err; | ||
1704 | } | ||
1705 | |||
1706 | /* Set fragmentation threshold or MWO robustness */ | ||
1707 | if (priv->has_mwo) | ||
1708 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1709 | HERMES_RID_CNFMWOROBUST_AGERE, | ||
1710 | priv->mwo_robust); | ||
1711 | else | ||
1712 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1713 | HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, | ||
1714 | priv->frag_thresh); | ||
1715 | if (err) { | ||
1716 | printk(KERN_ERR "%s: Error %d setting fragmentation\n", | ||
1717 | dev->name, err); | ||
1718 | return err; | ||
1719 | } | ||
1720 | |||
1721 | /* Set bitrate */ | ||
1722 | err = __orinoco_hw_set_bitrate(priv); | ||
1723 | if (err) { | ||
1724 | printk(KERN_ERR "%s: Error %d setting bitrate\n", | ||
1725 | dev->name, err); | ||
1726 | return err; | ||
1727 | } | ||
1728 | |||
1729 | /* Set power management */ | ||
1730 | if (priv->has_pm) { | ||
1731 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1732 | HERMES_RID_CNFPMENABLED, | ||
1733 | priv->pm_on); | ||
1734 | if (err) { | ||
1735 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1736 | dev->name, err); | ||
1737 | return err; | ||
1738 | } | ||
1739 | |||
1740 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1741 | HERMES_RID_CNFMULTICASTRECEIVE, | ||
1742 | priv->pm_mcast); | ||
1743 | if (err) { | ||
1744 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1745 | dev->name, err); | ||
1746 | return err; | ||
1747 | } | ||
1748 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1749 | HERMES_RID_CNFMAXSLEEPDURATION, | ||
1750 | priv->pm_period); | ||
1751 | if (err) { | ||
1752 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1753 | dev->name, err); | ||
1754 | return err; | ||
1755 | } | ||
1756 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1757 | HERMES_RID_CNFPMHOLDOVERDURATION, | ||
1758 | priv->pm_timeout); | ||
1759 | if (err) { | ||
1760 | printk(KERN_ERR "%s: Error %d setting up PM\n", | ||
1761 | dev->name, err); | ||
1762 | return err; | ||
1763 | } | ||
1764 | } | ||
1765 | |||
1766 | /* Set preamble - only for Symbol so far... */ | ||
1767 | if (priv->has_preamble) { | ||
1768 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1769 | HERMES_RID_CNFPREAMBLE_SYMBOL, | ||
1770 | priv->preamble); | ||
1771 | if (err) { | ||
1772 | printk(KERN_ERR "%s: Error %d setting preamble\n", | ||
1773 | dev->name, err); | ||
1774 | return err; | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | /* Set up encryption */ | ||
1779 | if (priv->has_wep) { | ||
1780 | err = __orinoco_hw_setup_wep(priv); | ||
1781 | if (err) { | ||
1782 | printk(KERN_ERR "%s: Error %d activating WEP\n", | ||
1783 | dev->name, err); | ||
1784 | return err; | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | /* Set promiscuity / multicast*/ | ||
1789 | priv->promiscuous = 0; | ||
1790 | priv->mc_count = 0; | ||
1791 | __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */ | ||
1792 | |||
1793 | return 0; | ||
1794 | } | ||
1795 | |||
1796 | /* FIXME: return int? */ | ||
1797 | static void | ||
1798 | __orinoco_set_multicast_list(struct net_device *dev) | ||
1799 | { | ||
1800 | struct orinoco_private *priv = netdev_priv(dev); | ||
1801 | hermes_t *hw = &priv->hw; | ||
1802 | int err = 0; | ||
1803 | int promisc, mc_count; | ||
1804 | |||
1805 | /* The Hermes doesn't seem to have an allmulti mode, so we go | ||
1806 | * into promiscuous mode and let the upper levels deal. */ | ||
1807 | if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || | ||
1808 | (dev->mc_count > MAX_MULTICAST(priv)) ) { | ||
1809 | promisc = 1; | ||
1810 | mc_count = 0; | ||
1811 | } else { | ||
1812 | promisc = 0; | ||
1813 | mc_count = dev->mc_count; | ||
1814 | } | ||
1815 | |||
1816 | if (promisc != priv->promiscuous) { | ||
1817 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1818 | HERMES_RID_CNFPROMISCUOUSMODE, | ||
1819 | promisc); | ||
1820 | if (err) { | ||
1821 | printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", | ||
1822 | dev->name, err); | ||
1823 | } else | ||
1824 | priv->promiscuous = promisc; | ||
1825 | } | ||
1826 | |||
1827 | if (! promisc && (mc_count || priv->mc_count) ) { | ||
1828 | struct dev_mc_list *p = dev->mc_list; | ||
1829 | struct hermes_multicast mclist; | ||
1830 | int i; | ||
1831 | |||
1832 | for (i = 0; i < mc_count; i++) { | ||
1833 | /* paranoia: is list shorter than mc_count? */ | ||
1834 | BUG_ON(! p); | ||
1835 | /* paranoia: bad address size in list? */ | ||
1836 | BUG_ON(p->dmi_addrlen != ETH_ALEN); | ||
1837 | |||
1838 | memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); | ||
1839 | p = p->next; | ||
1840 | } | ||
1841 | |||
1842 | if (p) | ||
1843 | printk(KERN_WARNING "%s: Multicast list is " | ||
1844 | "longer than mc_count\n", dev->name); | ||
1845 | |||
1846 | err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, | ||
1847 | HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), | ||
1848 | &mclist); | ||
1849 | if (err) | ||
1850 | printk(KERN_ERR "%s: Error %d setting multicast list.\n", | ||
1851 | dev->name, err); | ||
1852 | else | ||
1853 | priv->mc_count = mc_count; | ||
1854 | } | ||
1855 | |||
1856 | /* Since we can set the promiscuous flag when it wasn't asked | ||
1857 | for, make sure the net_device knows about it. */ | ||
1858 | if (priv->promiscuous) | ||
1859 | dev->flags |= IFF_PROMISC; | ||
1860 | else | ||
1861 | dev->flags &= ~IFF_PROMISC; | ||
1862 | } | ||
1863 | |||
1864 | static int orinoco_reconfigure(struct net_device *dev) | ||
1865 | { | ||
1866 | struct orinoco_private *priv = netdev_priv(dev); | ||
1867 | struct hermes *hw = &priv->hw; | ||
1868 | unsigned long flags; | ||
1869 | int err = 0; | ||
1870 | |||
1871 | if (priv->broken_disableport) { | ||
1872 | schedule_work(&priv->reset_work); | ||
1873 | return 0; | ||
1874 | } | ||
1875 | |||
1876 | if (orinoco_lock(priv, &flags) != 0) | ||
1877 | return -EBUSY; | ||
1878 | |||
1879 | err = hermes_disable_port(hw, 0); | ||
1880 | if (err) { | ||
1881 | printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", | ||
1882 | dev->name); | ||
1883 | priv->broken_disableport = 1; | ||
1884 | goto out; | ||
1885 | } | ||
1886 | |||
1887 | err = __orinoco_program_rids(dev); | ||
1888 | if (err) { | ||
1889 | printk(KERN_WARNING "%s: Unable to reconfigure card\n", | ||
1890 | dev->name); | ||
1891 | goto out; | ||
1892 | } | ||
1893 | |||
1894 | err = hermes_enable_port(hw, 0); | ||
1895 | if (err) { | ||
1896 | printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", | ||
1897 | dev->name); | ||
1898 | goto out; | ||
1899 | } | ||
1900 | |||
1901 | out: | ||
1902 | if (err) { | ||
1903 | printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); | ||
1904 | schedule_work(&priv->reset_work); | ||
1905 | err = 0; | ||
1906 | } | ||
1907 | |||
1908 | orinoco_unlock(priv, &flags); | ||
1909 | return err; | ||
1910 | |||
1911 | } | ||
1912 | |||
1913 | /* This must be called from user context, without locks held - use | ||
1914 | * schedule_work() */ | ||
1915 | static void orinoco_reset(struct net_device *dev) | ||
1916 | { | ||
1917 | struct orinoco_private *priv = netdev_priv(dev); | ||
1918 | struct hermes *hw = &priv->hw; | ||
1919 | int err = 0; | ||
1920 | unsigned long flags; | ||
1921 | |||
1922 | if (orinoco_lock(priv, &flags) != 0) | ||
1923 | /* When the hardware becomes available again, whatever | ||
1924 | * detects that is responsible for re-initializing | ||
1925 | * it. So no need for anything further */ | ||
1926 | return; | ||
1927 | |||
1928 | netif_stop_queue(dev); | ||
1929 | |||
1930 | /* Shut off interrupts. Depending on what state the hardware | ||
1931 | * is in, this might not work, but we'll try anyway */ | ||
1932 | hermes_set_irqmask(hw, 0); | ||
1933 | hermes_write_regn(hw, EVACK, 0xffff); | ||
1934 | |||
1935 | priv->hw_unavailable++; | ||
1936 | priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ | ||
1937 | netif_carrier_off(dev); | ||
1938 | |||
1939 | orinoco_unlock(priv, &flags); | ||
1940 | |||
1941 | if (priv->hard_reset) | ||
1942 | err = (*priv->hard_reset)(priv); | ||
1943 | if (err) { | ||
1944 | printk(KERN_ERR "%s: orinoco_reset: Error %d " | ||
1945 | "performing hard reset\n", dev->name, err); | ||
1946 | /* FIXME: shutdown of some sort */ | ||
1947 | return; | ||
1948 | } | ||
1949 | |||
1950 | err = orinoco_reinit_firmware(dev); | ||
1951 | if (err) { | ||
1952 | printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", | ||
1953 | dev->name, err); | ||
1954 | return; | ||
1955 | } | ||
1956 | |||
1957 | spin_lock_irq(&priv->lock); /* This has to be called from user context */ | ||
1958 | |||
1959 | priv->hw_unavailable--; | ||
1960 | |||
1961 | /* priv->open or priv->hw_unavailable might have changed while | ||
1962 | * we dropped the lock */ | ||
1963 | if (priv->open && (! priv->hw_unavailable)) { | ||
1964 | err = __orinoco_up(dev); | ||
1965 | if (err) { | ||
1966 | printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", | ||
1967 | dev->name, err); | ||
1968 | } else | ||
1969 | dev->trans_start = jiffies; | ||
1970 | } | ||
1971 | |||
1972 | spin_unlock_irq(&priv->lock); | ||
1973 | |||
1974 | return; | ||
1975 | } | ||
1976 | |||
1977 | /********************************************************************/ | ||
1978 | /* Interrupt handler */ | ||
1979 | /********************************************************************/ | ||
1980 | |||
1981 | static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) | ||
1982 | { | ||
1983 | printk(KERN_DEBUG "%s: TICK\n", dev->name); | ||
1984 | } | ||
1985 | |||
1986 | static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) | ||
1987 | { | ||
1988 | /* This seems to happen a fair bit under load, but ignoring it | ||
1989 | seems to work fine...*/ | ||
1990 | printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", | ||
1991 | dev->name); | ||
1992 | } | ||
1993 | |||
1994 | irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1995 | { | ||
1996 | struct net_device *dev = (struct net_device *)dev_id; | ||
1997 | struct orinoco_private *priv = netdev_priv(dev); | ||
1998 | hermes_t *hw = &priv->hw; | ||
1999 | int count = MAX_IRQLOOPS_PER_IRQ; | ||
2000 | u16 evstat, events; | ||
2001 | /* These are used to detect a runaway interrupt situation */ | ||
2002 | /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, | ||
2003 | * we panic and shut down the hardware */ | ||
2004 | static int last_irq_jiffy = 0; /* jiffies value the last time | ||
2005 | * we were called */ | ||
2006 | static int loops_this_jiffy = 0; | ||
2007 | unsigned long flags; | ||
2008 | |||
2009 | if (orinoco_lock(priv, &flags) != 0) { | ||
2010 | /* If hw is unavailable - we don't know if the irq was | ||
2011 | * for us or not */ | ||
2012 | return IRQ_HANDLED; | ||
2013 | } | ||
2014 | |||
2015 | evstat = hermes_read_regn(hw, EVSTAT); | ||
2016 | events = evstat & hw->inten; | ||
2017 | if (! events) { | ||
2018 | orinoco_unlock(priv, &flags); | ||
2019 | return IRQ_NONE; | ||
2020 | } | ||
2021 | |||
2022 | if (jiffies != last_irq_jiffy) | ||
2023 | loops_this_jiffy = 0; | ||
2024 | last_irq_jiffy = jiffies; | ||
2025 | |||
2026 | while (events && count--) { | ||
2027 | if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { | ||
2028 | printk(KERN_WARNING "%s: IRQ handler is looping too " | ||
2029 | "much! Resetting.\n", dev->name); | ||
2030 | /* Disable interrupts for now */ | ||
2031 | hermes_set_irqmask(hw, 0); | ||
2032 | schedule_work(&priv->reset_work); | ||
2033 | break; | ||
2034 | } | ||
2035 | |||
2036 | /* Check the card hasn't been removed */ | ||
2037 | if (! hermes_present(hw)) { | ||
2038 | DEBUG(0, "orinoco_interrupt(): card removed\n"); | ||
2039 | break; | ||
2040 | } | ||
2041 | |||
2042 | if (events & HERMES_EV_TICK) | ||
2043 | __orinoco_ev_tick(dev, hw); | ||
2044 | if (events & HERMES_EV_WTERR) | ||
2045 | __orinoco_ev_wterr(dev, hw); | ||
2046 | if (events & HERMES_EV_INFDROP) | ||
2047 | __orinoco_ev_infdrop(dev, hw); | ||
2048 | if (events & HERMES_EV_INFO) | ||
2049 | __orinoco_ev_info(dev, hw); | ||
2050 | if (events & HERMES_EV_RX) | ||
2051 | __orinoco_ev_rx(dev, hw); | ||
2052 | if (events & HERMES_EV_TXEXC) | ||
2053 | __orinoco_ev_txexc(dev, hw); | ||
2054 | if (events & HERMES_EV_TX) | ||
2055 | __orinoco_ev_tx(dev, hw); | ||
2056 | if (events & HERMES_EV_ALLOC) | ||
2057 | __orinoco_ev_alloc(dev, hw); | ||
2058 | |||
2059 | hermes_write_regn(hw, EVACK, events); | ||
2060 | |||
2061 | evstat = hermes_read_regn(hw, EVSTAT); | ||
2062 | events = evstat & hw->inten; | ||
2063 | }; | ||
2064 | |||
2065 | orinoco_unlock(priv, &flags); | ||
2066 | return IRQ_HANDLED; | ||
2067 | } | ||
2068 | |||
2069 | /********************************************************************/ | ||
2070 | /* Initialization */ | ||
2071 | /********************************************************************/ | ||
2072 | |||
2073 | struct comp_id { | ||
2074 | u16 id, variant, major, minor; | ||
2075 | } __attribute__ ((packed)); | ||
2076 | |||
2077 | static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) | ||
2078 | { | ||
2079 | if (nic_id->id < 0x8000) | ||
2080 | return FIRMWARE_TYPE_AGERE; | ||
2081 | else if (nic_id->id == 0x8000 && nic_id->major == 0) | ||
2082 | return FIRMWARE_TYPE_SYMBOL; | ||
2083 | else | ||
2084 | return FIRMWARE_TYPE_INTERSIL; | ||
2085 | } | ||
2086 | |||
2087 | /* Set priv->firmware type, determine firmware properties */ | ||
2088 | static int determine_firmware(struct net_device *dev) | ||
2089 | { | ||
2090 | struct orinoco_private *priv = netdev_priv(dev); | ||
2091 | hermes_t *hw = &priv->hw; | ||
2092 | int err; | ||
2093 | struct comp_id nic_id, sta_id; | ||
2094 | unsigned int firmver; | ||
2095 | char tmp[SYMBOL_MAX_VER_LEN+1]; | ||
2096 | |||
2097 | /* Get the hardware version */ | ||
2098 | err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); | ||
2099 | if (err) { | ||
2100 | printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", | ||
2101 | dev->name, err); | ||
2102 | return err; | ||
2103 | } | ||
2104 | |||
2105 | le16_to_cpus(&nic_id.id); | ||
2106 | le16_to_cpus(&nic_id.variant); | ||
2107 | le16_to_cpus(&nic_id.major); | ||
2108 | le16_to_cpus(&nic_id.minor); | ||
2109 | printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", | ||
2110 | dev->name, nic_id.id, nic_id.variant, | ||
2111 | nic_id.major, nic_id.minor); | ||
2112 | |||
2113 | priv->firmware_type = determine_firmware_type(&nic_id); | ||
2114 | |||
2115 | /* Get the firmware version */ | ||
2116 | err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); | ||
2117 | if (err) { | ||
2118 | printk(KERN_ERR "%s: Cannot read station identity: error %d\n", | ||
2119 | dev->name, err); | ||
2120 | return err; | ||
2121 | } | ||
2122 | |||
2123 | le16_to_cpus(&sta_id.id); | ||
2124 | le16_to_cpus(&sta_id.variant); | ||
2125 | le16_to_cpus(&sta_id.major); | ||
2126 | le16_to_cpus(&sta_id.minor); | ||
2127 | printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", | ||
2128 | dev->name, sta_id.id, sta_id.variant, | ||
2129 | sta_id.major, sta_id.minor); | ||
2130 | |||
2131 | switch (sta_id.id) { | ||
2132 | case 0x15: | ||
2133 | printk(KERN_ERR "%s: Primary firmware is active\n", | ||
2134 | dev->name); | ||
2135 | return -ENODEV; | ||
2136 | case 0x14b: | ||
2137 | printk(KERN_ERR "%s: Tertiary firmware is active\n", | ||
2138 | dev->name); | ||
2139 | return -ENODEV; | ||
2140 | case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ | ||
2141 | case 0x21: /* Symbol Spectrum24 Trilogy */ | ||
2142 | break; | ||
2143 | default: | ||
2144 | printk(KERN_NOTICE "%s: Unknown station ID, please report\n", | ||
2145 | dev->name); | ||
2146 | break; | ||
2147 | } | ||
2148 | |||
2149 | /* Default capabilities */ | ||
2150 | priv->has_sensitivity = 1; | ||
2151 | priv->has_mwo = 0; | ||
2152 | priv->has_preamble = 0; | ||
2153 | priv->has_port3 = 1; | ||
2154 | priv->has_ibss = 1; | ||
2155 | priv->has_wep = 0; | ||
2156 | priv->has_big_wep = 0; | ||
2157 | |||
2158 | /* Determine capabilities from the firmware version */ | ||
2159 | switch (priv->firmware_type) { | ||
2160 | case FIRMWARE_TYPE_AGERE: | ||
2161 | /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, | ||
2162 | ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ | ||
2163 | snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, | ||
2164 | "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); | ||
2165 | |||
2166 | firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; | ||
2167 | |||
2168 | priv->has_ibss = (firmver >= 0x60006); | ||
2169 | priv->has_wep = (firmver >= 0x40020); | ||
2170 | priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell | ||
2171 | Gold cards from the others? */ | ||
2172 | priv->has_mwo = (firmver >= 0x60000); | ||
2173 | priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ | ||
2174 | priv->ibss_port = 1; | ||
2175 | |||
2176 | /* Tested with Agere firmware : | ||
2177 | * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II | ||
2178 | * Tested CableTron firmware : 4.32 => Anton */ | ||
2179 | break; | ||
2180 | case FIRMWARE_TYPE_SYMBOL: | ||
2181 | /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ | ||
2182 | /* Intel MAC : 00:02:B3:* */ | ||
2183 | /* 3Com MAC : 00:50:DA:* */ | ||
2184 | memset(tmp, 0, sizeof(tmp)); | ||
2185 | /* Get the Symbol firmware version */ | ||
2186 | err = hermes_read_ltv(hw, USER_BAP, | ||
2187 | HERMES_RID_SECONDARYVERSION_SYMBOL, | ||
2188 | SYMBOL_MAX_VER_LEN, NULL, &tmp); | ||
2189 | if (err) { | ||
2190 | printk(KERN_WARNING | ||
2191 | "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n", | ||
2192 | dev->name, err); | ||
2193 | firmver = 0; | ||
2194 | tmp[0] = '\0'; | ||
2195 | } else { | ||
2196 | /* The firmware revision is a string, the format is | ||
2197 | * something like : "V2.20-01". | ||
2198 | * Quick and dirty parsing... - Jean II | ||
2199 | */ | ||
2200 | firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12) | ||
2201 | | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4) | ||
2202 | | (tmp[7] - '0'); | ||
2203 | |||
2204 | tmp[SYMBOL_MAX_VER_LEN] = '\0'; | ||
2205 | } | ||
2206 | |||
2207 | snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, | ||
2208 | "Symbol %s", tmp); | ||
2209 | |||
2210 | priv->has_ibss = (firmver >= 0x20000); | ||
2211 | priv->has_wep = (firmver >= 0x15012); | ||
2212 | priv->has_big_wep = (firmver >= 0x20000); | ||
2213 | priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || | ||
2214 | (firmver >= 0x29000 && firmver < 0x30000) || | ||
2215 | firmver >= 0x31000; | ||
2216 | priv->has_preamble = (firmver >= 0x20000); | ||
2217 | priv->ibss_port = 4; | ||
2218 | /* Tested with Intel firmware : 0x20015 => Jean II */ | ||
2219 | /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ | ||
2220 | break; | ||
2221 | case FIRMWARE_TYPE_INTERSIL: | ||
2222 | /* D-Link, Linksys, Adtron, ZoomAir, and many others... | ||
2223 | * Samsung, Compaq 100/200 and Proxim are slightly | ||
2224 | * different and less well tested */ | ||
2225 | /* D-Link MAC : 00:40:05:* */ | ||
2226 | /* Addtron MAC : 00:90:D1:* */ | ||
2227 | snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, | ||
2228 | "Intersil %d.%d.%d", sta_id.major, sta_id.minor, | ||
2229 | sta_id.variant); | ||
2230 | |||
2231 | firmver = ((unsigned long)sta_id.major << 16) | | ||
2232 | ((unsigned long)sta_id.minor << 8) | sta_id.variant; | ||
2233 | |||
2234 | priv->has_ibss = (firmver >= 0x000700); /* FIXME */ | ||
2235 | priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); | ||
2236 | priv->has_pm = (firmver >= 0x000700); | ||
2237 | |||
2238 | if (firmver >= 0x000800) | ||
2239 | priv->ibss_port = 0; | ||
2240 | else { | ||
2241 | printk(KERN_NOTICE "%s: Intersil firmware earlier " | ||
2242 | "than v0.8.x - several features not supported\n", | ||
2243 | dev->name); | ||
2244 | priv->ibss_port = 1; | ||
2245 | } | ||
2246 | break; | ||
2247 | } | ||
2248 | printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, | ||
2249 | priv->fw_name); | ||
2250 | |||
2251 | return 0; | ||
2252 | } | ||
2253 | |||
2254 | static int orinoco_init(struct net_device *dev) | ||
2255 | { | ||
2256 | struct orinoco_private *priv = netdev_priv(dev); | ||
2257 | hermes_t *hw = &priv->hw; | ||
2258 | int err = 0; | ||
2259 | struct hermes_idstring nickbuf; | ||
2260 | u16 reclen; | ||
2261 | int len; | ||
2262 | |||
2263 | TRACE_ENTER(dev->name); | ||
2264 | |||
2265 | /* No need to lock, the hw_unavailable flag is already set in | ||
2266 | * alloc_orinocodev() */ | ||
2267 | priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN; | ||
2268 | |||
2269 | /* Initialize the firmware */ | ||
2270 | err = hermes_init(hw); | ||
2271 | if (err != 0) { | ||
2272 | printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", | ||
2273 | dev->name, err); | ||
2274 | goto out; | ||
2275 | } | ||
2276 | |||
2277 | err = determine_firmware(dev); | ||
2278 | if (err != 0) { | ||
2279 | printk(KERN_ERR "%s: Incompatible firmware, aborting\n", | ||
2280 | dev->name); | ||
2281 | goto out; | ||
2282 | } | ||
2283 | |||
2284 | if (priv->has_port3) | ||
2285 | printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); | ||
2286 | if (priv->has_ibss) | ||
2287 | printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", | ||
2288 | dev->name); | ||
2289 | if (priv->has_wep) { | ||
2290 | printk(KERN_DEBUG "%s: WEP supported, ", dev->name); | ||
2291 | if (priv->has_big_wep) | ||
2292 | printk("104-bit key\n"); | ||
2293 | else | ||
2294 | printk("40-bit key\n"); | ||
2295 | } | ||
2296 | |||
2297 | /* Get the MAC address */ | ||
2298 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, | ||
2299 | ETH_ALEN, NULL, dev->dev_addr); | ||
2300 | if (err) { | ||
2301 | printk(KERN_WARNING "%s: failed to read MAC address!\n", | ||
2302 | dev->name); | ||
2303 | goto out; | ||
2304 | } | ||
2305 | |||
2306 | printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", | ||
2307 | dev->name, dev->dev_addr[0], dev->dev_addr[1], | ||
2308 | dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], | ||
2309 | dev->dev_addr[5]); | ||
2310 | |||
2311 | /* Get the station name */ | ||
2312 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, | ||
2313 | sizeof(nickbuf), &reclen, &nickbuf); | ||
2314 | if (err) { | ||
2315 | printk(KERN_ERR "%s: failed to read station name\n", | ||
2316 | dev->name); | ||
2317 | goto out; | ||
2318 | } | ||
2319 | if (nickbuf.len) | ||
2320 | len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); | ||
2321 | else | ||
2322 | len = min(IW_ESSID_MAX_SIZE, 2 * reclen); | ||
2323 | memcpy(priv->nick, &nickbuf.val, len); | ||
2324 | priv->nick[len] = '\0'; | ||
2325 | |||
2326 | printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); | ||
2327 | |||
2328 | /* Get allowed channels */ | ||
2329 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, | ||
2330 | &priv->channel_mask); | ||
2331 | if (err) { | ||
2332 | printk(KERN_ERR "%s: failed to read channel list!\n", | ||
2333 | dev->name); | ||
2334 | goto out; | ||
2335 | } | ||
2336 | |||
2337 | /* Get initial AP density */ | ||
2338 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, | ||
2339 | &priv->ap_density); | ||
2340 | if (err || priv->ap_density < 1 || priv->ap_density > 3) { | ||
2341 | priv->has_sensitivity = 0; | ||
2342 | } | ||
2343 | |||
2344 | /* Get initial RTS threshold */ | ||
2345 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, | ||
2346 | &priv->rts_thresh); | ||
2347 | if (err) { | ||
2348 | printk(KERN_ERR "%s: failed to read RTS threshold!\n", | ||
2349 | dev->name); | ||
2350 | goto out; | ||
2351 | } | ||
2352 | |||
2353 | /* Get initial fragmentation settings */ | ||
2354 | if (priv->has_mwo) | ||
2355 | err = hermes_read_wordrec(hw, USER_BAP, | ||
2356 | HERMES_RID_CNFMWOROBUST_AGERE, | ||
2357 | &priv->mwo_robust); | ||
2358 | else | ||
2359 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, | ||
2360 | &priv->frag_thresh); | ||
2361 | if (err) { | ||
2362 | printk(KERN_ERR "%s: failed to read fragmentation settings!\n", | ||
2363 | dev->name); | ||
2364 | goto out; | ||
2365 | } | ||
2366 | |||
2367 | /* Power management setup */ | ||
2368 | if (priv->has_pm) { | ||
2369 | priv->pm_on = 0; | ||
2370 | priv->pm_mcast = 1; | ||
2371 | err = hermes_read_wordrec(hw, USER_BAP, | ||
2372 | HERMES_RID_CNFMAXSLEEPDURATION, | ||
2373 | &priv->pm_period); | ||
2374 | if (err) { | ||
2375 | printk(KERN_ERR "%s: failed to read power management period!\n", | ||
2376 | dev->name); | ||
2377 | goto out; | ||
2378 | } | ||
2379 | err = hermes_read_wordrec(hw, USER_BAP, | ||
2380 | HERMES_RID_CNFPMHOLDOVERDURATION, | ||
2381 | &priv->pm_timeout); | ||
2382 | if (err) { | ||
2383 | printk(KERN_ERR "%s: failed to read power management timeout!\n", | ||
2384 | dev->name); | ||
2385 | goto out; | ||
2386 | } | ||
2387 | } | ||
2388 | |||
2389 | /* Preamble setup */ | ||
2390 | if (priv->has_preamble) { | ||
2391 | err = hermes_read_wordrec(hw, USER_BAP, | ||
2392 | HERMES_RID_CNFPREAMBLE_SYMBOL, | ||
2393 | &priv->preamble); | ||
2394 | if (err) | ||
2395 | goto out; | ||
2396 | } | ||
2397 | |||
2398 | /* Set up the default configuration */ | ||
2399 | priv->iw_mode = IW_MODE_INFRA; | ||
2400 | /* By default use IEEE/IBSS ad-hoc mode if we have it */ | ||
2401 | priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); | ||
2402 | set_port_type(priv); | ||
2403 | priv->channel = 10; /* default channel, more-or-less arbitrary */ | ||
2404 | |||
2405 | priv->promiscuous = 0; | ||
2406 | priv->wep_on = 0; | ||
2407 | priv->tx_key = 0; | ||
2408 | |||
2409 | err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); | ||
2410 | if (err == -EIO) { | ||
2411 | /* Try workaround for old Symbol firmware bug */ | ||
2412 | printk(KERN_WARNING "%s: firmware ALLOC bug detected " | ||
2413 | "(old Symbol firmware?). Trying to work around... ", | ||
2414 | dev->name); | ||
2415 | |||
2416 | priv->nicbuf_size = TX_NICBUF_SIZE_BUG; | ||
2417 | err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); | ||
2418 | if (err) | ||
2419 | printk("failed!\n"); | ||
2420 | else | ||
2421 | printk("ok.\n"); | ||
2422 | } | ||
2423 | if (err) { | ||
2424 | printk("%s: Error %d allocating Tx buffer\n", dev->name, err); | ||
2425 | goto out; | ||
2426 | } | ||
2427 | |||
2428 | /* Make the hardware available, as long as it hasn't been | ||
2429 | * removed elsewhere (e.g. by PCMCIA hot unplug) */ | ||
2430 | spin_lock_irq(&priv->lock); | ||
2431 | priv->hw_unavailable--; | ||
2432 | spin_unlock_irq(&priv->lock); | ||
2433 | |||
2434 | printk(KERN_DEBUG "%s: ready\n", dev->name); | ||
2435 | |||
2436 | out: | ||
2437 | TRACE_EXIT(dev->name); | ||
2438 | return err; | ||
2439 | } | ||
2440 | |||
2441 | struct net_device *alloc_orinocodev(int sizeof_card, | ||
2442 | int (*hard_reset)(struct orinoco_private *)) | ||
2443 | { | ||
2444 | struct net_device *dev; | ||
2445 | struct orinoco_private *priv; | ||
2446 | |||
2447 | dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); | ||
2448 | if (! dev) | ||
2449 | return NULL; | ||
2450 | priv = netdev_priv(dev); | ||
2451 | priv->ndev = dev; | ||
2452 | if (sizeof_card) | ||
2453 | priv->card = (void *)((unsigned long)netdev_priv(dev) | ||
2454 | + sizeof(struct orinoco_private)); | ||
2455 | else | ||
2456 | priv->card = NULL; | ||
2457 | |||
2458 | /* Setup / override net_device fields */ | ||
2459 | dev->init = orinoco_init; | ||
2460 | dev->hard_start_xmit = orinoco_xmit; | ||
2461 | dev->tx_timeout = orinoco_tx_timeout; | ||
2462 | dev->watchdog_timeo = HZ; /* 1 second timeout */ | ||
2463 | dev->get_stats = orinoco_get_stats; | ||
2464 | dev->get_wireless_stats = orinoco_get_wireless_stats; | ||
2465 | dev->do_ioctl = orinoco_ioctl; | ||
2466 | dev->change_mtu = orinoco_change_mtu; | ||
2467 | dev->set_multicast_list = orinoco_set_multicast_list; | ||
2468 | /* we use the default eth_mac_addr for setting the MAC addr */ | ||
2469 | |||
2470 | /* Set up default callbacks */ | ||
2471 | dev->open = orinoco_open; | ||
2472 | dev->stop = orinoco_stop; | ||
2473 | priv->hard_reset = hard_reset; | ||
2474 | |||
2475 | spin_lock_init(&priv->lock); | ||
2476 | priv->open = 0; | ||
2477 | priv->hw_unavailable = 1; /* orinoco_init() must clear this | ||
2478 | * before anything else touches the | ||
2479 | * hardware */ | ||
2480 | INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); | ||
2481 | |||
2482 | netif_carrier_off(dev); | ||
2483 | priv->last_linkstatus = 0xffff; | ||
2484 | |||
2485 | return dev; | ||
2486 | |||
2487 | } | ||
2488 | |||
2489 | void free_orinocodev(struct net_device *dev) | ||
2490 | { | ||
2491 | free_netdev(dev); | ||
2492 | } | ||
2493 | |||
2494 | /********************************************************************/ | ||
2495 | /* Wireless extensions */ | ||
2496 | /********************************************************************/ | ||
2497 | |||
2498 | static int orinoco_hw_get_bssid(struct orinoco_private *priv, | ||
2499 | char buf[ETH_ALEN]) | ||
2500 | { | ||
2501 | hermes_t *hw = &priv->hw; | ||
2502 | int err = 0; | ||
2503 | unsigned long flags; | ||
2504 | |||
2505 | if (orinoco_lock(priv, &flags) != 0) | ||
2506 | return -EBUSY; | ||
2507 | |||
2508 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | ||
2509 | ETH_ALEN, NULL, buf); | ||
2510 | |||
2511 | orinoco_unlock(priv, &flags); | ||
2512 | |||
2513 | return err; | ||
2514 | } | ||
2515 | |||
2516 | static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, | ||
2517 | char buf[IW_ESSID_MAX_SIZE+1]) | ||
2518 | { | ||
2519 | hermes_t *hw = &priv->hw; | ||
2520 | int err = 0; | ||
2521 | struct hermes_idstring essidbuf; | ||
2522 | char *p = (char *)(&essidbuf.val); | ||
2523 | int len; | ||
2524 | unsigned long flags; | ||
2525 | |||
2526 | if (orinoco_lock(priv, &flags) != 0) | ||
2527 | return -EBUSY; | ||
2528 | |||
2529 | if (strlen(priv->desired_essid) > 0) { | ||
2530 | /* We read the desired SSID from the hardware rather | ||
2531 | than from priv->desired_essid, just in case the | ||
2532 | firmware is allowed to change it on us. I'm not | ||
2533 | sure about this */ | ||
2534 | /* My guess is that the OWNSSID should always be whatever | ||
2535 | * we set to the card, whereas CURRENT_SSID is the one that | ||
2536 | * may change... - Jean II */ | ||
2537 | u16 rid; | ||
2538 | |||
2539 | *active = 1; | ||
2540 | |||
2541 | rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : | ||
2542 | HERMES_RID_CNFDESIREDSSID; | ||
2543 | |||
2544 | err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), | ||
2545 | NULL, &essidbuf); | ||
2546 | if (err) | ||
2547 | goto fail_unlock; | ||
2548 | } else { | ||
2549 | *active = 0; | ||
2550 | |||
2551 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, | ||
2552 | sizeof(essidbuf), NULL, &essidbuf); | ||
2553 | if (err) | ||
2554 | goto fail_unlock; | ||
2555 | } | ||
2556 | |||
2557 | len = le16_to_cpu(essidbuf.len); | ||
2558 | |||
2559 | memset(buf, 0, IW_ESSID_MAX_SIZE+1); | ||
2560 | memcpy(buf, p, len); | ||
2561 | buf[len] = '\0'; | ||
2562 | |||
2563 | fail_unlock: | ||
2564 | orinoco_unlock(priv, &flags); | ||
2565 | |||
2566 | return err; | ||
2567 | } | ||
2568 | |||
2569 | static long orinoco_hw_get_freq(struct orinoco_private *priv) | ||
2570 | { | ||
2571 | |||
2572 | hermes_t *hw = &priv->hw; | ||
2573 | int err = 0; | ||
2574 | u16 channel; | ||
2575 | long freq = 0; | ||
2576 | unsigned long flags; | ||
2577 | |||
2578 | if (orinoco_lock(priv, &flags) != 0) | ||
2579 | return -EBUSY; | ||
2580 | |||
2581 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); | ||
2582 | if (err) | ||
2583 | goto out; | ||
2584 | |||
2585 | /* Intersil firmware 1.3.5 returns 0 when the interface is down */ | ||
2586 | if (channel == 0) { | ||
2587 | err = -EBUSY; | ||
2588 | goto out; | ||
2589 | } | ||
2590 | |||
2591 | if ( (channel < 1) || (channel > NUM_CHANNELS) ) { | ||
2592 | printk(KERN_WARNING "%s: Channel out of range (%d)!\n", | ||
2593 | priv->ndev->name, channel); | ||
2594 | err = -EBUSY; | ||
2595 | goto out; | ||
2596 | |||
2597 | } | ||
2598 | freq = channel_frequency[channel-1] * 100000; | ||
2599 | |||
2600 | out: | ||
2601 | orinoco_unlock(priv, &flags); | ||
2602 | |||
2603 | if (err > 0) | ||
2604 | err = -EBUSY; | ||
2605 | return err ? err : freq; | ||
2606 | } | ||
2607 | |||
2608 | static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | ||
2609 | int *numrates, s32 *rates, int max) | ||
2610 | { | ||
2611 | hermes_t *hw = &priv->hw; | ||
2612 | struct hermes_idstring list; | ||
2613 | unsigned char *p = (unsigned char *)&list.val; | ||
2614 | int err = 0; | ||
2615 | int num; | ||
2616 | int i; | ||
2617 | unsigned long flags; | ||
2618 | |||
2619 | if (orinoco_lock(priv, &flags) != 0) | ||
2620 | return -EBUSY; | ||
2621 | |||
2622 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, | ||
2623 | sizeof(list), NULL, &list); | ||
2624 | orinoco_unlock(priv, &flags); | ||
2625 | |||
2626 | if (err) | ||
2627 | return err; | ||
2628 | |||
2629 | num = le16_to_cpu(list.len); | ||
2630 | *numrates = num; | ||
2631 | num = min(num, max); | ||
2632 | |||
2633 | for (i = 0; i < num; i++) { | ||
2634 | rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ | ||
2635 | } | ||
2636 | |||
2637 | return 0; | ||
2638 | } | ||
2639 | |||
2640 | static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) | ||
2641 | { | ||
2642 | struct orinoco_private *priv = netdev_priv(dev); | ||
2643 | int err = 0; | ||
2644 | int mode; | ||
2645 | struct iw_range range; | ||
2646 | int numrates; | ||
2647 | int i, k; | ||
2648 | unsigned long flags; | ||
2649 | |||
2650 | TRACE_ENTER(dev->name); | ||
2651 | |||
2652 | if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range))) | ||
2653 | return -EFAULT; | ||
2654 | |||
2655 | rrq->length = sizeof(range); | ||
2656 | |||
2657 | if (orinoco_lock(priv, &flags) != 0) | ||
2658 | return -EBUSY; | ||
2659 | |||
2660 | mode = priv->iw_mode; | ||
2661 | orinoco_unlock(priv, &flags); | ||
2662 | |||
2663 | memset(&range, 0, sizeof(range)); | ||
2664 | |||
2665 | /* Much of this shamelessly taken from wvlan_cs.c. No idea | ||
2666 | * what it all means -dgibson */ | ||
2667 | range.we_version_compiled = WIRELESS_EXT; | ||
2668 | range.we_version_source = 11; | ||
2669 | |||
2670 | range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ | ||
2671 | |||
2672 | /* Set available channels/frequencies */ | ||
2673 | range.num_channels = NUM_CHANNELS; | ||
2674 | k = 0; | ||
2675 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
2676 | if (priv->channel_mask & (1 << i)) { | ||
2677 | range.freq[k].i = i + 1; | ||
2678 | range.freq[k].m = channel_frequency[i] * 100000; | ||
2679 | range.freq[k].e = 1; | ||
2680 | k++; | ||
2681 | } | ||
2682 | |||
2683 | if (k >= IW_MAX_FREQUENCIES) | ||
2684 | break; | ||
2685 | } | ||
2686 | range.num_frequency = k; | ||
2687 | |||
2688 | range.sensitivity = 3; | ||
2689 | |||
2690 | if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ | ||
2691 | /* Quality stats meaningless in ad-hoc mode */ | ||
2692 | range.max_qual.qual = 0; | ||
2693 | range.max_qual.level = 0; | ||
2694 | range.max_qual.noise = 0; | ||
2695 | range.avg_qual.qual = 0; | ||
2696 | range.avg_qual.level = 0; | ||
2697 | range.avg_qual.noise = 0; | ||
2698 | } else { | ||
2699 | range.max_qual.qual = 0x8b - 0x2f; | ||
2700 | range.max_qual.level = 0x2f - 0x95 - 1; | ||
2701 | range.max_qual.noise = 0x2f - 0x95 - 1; | ||
2702 | /* Need to get better values */ | ||
2703 | range.avg_qual.qual = 0x24; | ||
2704 | range.avg_qual.level = 0xC2; | ||
2705 | range.avg_qual.noise = 0x9E; | ||
2706 | } | ||
2707 | |||
2708 | err = orinoco_hw_get_bitratelist(priv, &numrates, | ||
2709 | range.bitrate, IW_MAX_BITRATES); | ||
2710 | if (err) | ||
2711 | return err; | ||
2712 | range.num_bitrates = numrates; | ||
2713 | |||
2714 | /* Set an indication of the max TCP throughput in bit/s that we can | ||
2715 | * expect using this interface. May be use for QoS stuff... | ||
2716 | * Jean II */ | ||
2717 | if(numrates > 2) | ||
2718 | range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ | ||
2719 | else | ||
2720 | range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ | ||
2721 | |||
2722 | range.min_rts = 0; | ||
2723 | range.max_rts = 2347; | ||
2724 | range.min_frag = 256; | ||
2725 | range.max_frag = 2346; | ||
2726 | |||
2727 | if (orinoco_lock(priv, &flags) != 0) | ||
2728 | return -EBUSY; | ||
2729 | if (priv->has_wep) { | ||
2730 | range.max_encoding_tokens = ORINOCO_MAX_KEYS; | ||
2731 | |||
2732 | range.encoding_size[0] = SMALL_KEY_SIZE; | ||
2733 | range.num_encoding_sizes = 1; | ||
2734 | |||
2735 | if (priv->has_big_wep) { | ||
2736 | range.encoding_size[1] = LARGE_KEY_SIZE; | ||
2737 | range.num_encoding_sizes = 2; | ||
2738 | } | ||
2739 | } else { | ||
2740 | range.num_encoding_sizes = 0; | ||
2741 | range.max_encoding_tokens = 0; | ||
2742 | } | ||
2743 | orinoco_unlock(priv, &flags); | ||
2744 | |||
2745 | range.min_pmp = 0; | ||
2746 | range.max_pmp = 65535000; | ||
2747 | range.min_pmt = 0; | ||
2748 | range.max_pmt = 65535 * 1000; /* ??? */ | ||
2749 | range.pmp_flags = IW_POWER_PERIOD; | ||
2750 | range.pmt_flags = IW_POWER_TIMEOUT; | ||
2751 | range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; | ||
2752 | |||
2753 | range.num_txpower = 1; | ||
2754 | range.txpower[0] = 15; /* 15dBm */ | ||
2755 | range.txpower_capa = IW_TXPOW_DBM; | ||
2756 | |||
2757 | range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; | ||
2758 | range.retry_flags = IW_RETRY_LIMIT; | ||
2759 | range.r_time_flags = IW_RETRY_LIFETIME; | ||
2760 | range.min_retry = 0; | ||
2761 | range.max_retry = 65535; /* ??? */ | ||
2762 | range.min_r_time = 0; | ||
2763 | range.max_r_time = 65535 * 1000; /* ??? */ | ||
2764 | |||
2765 | if (copy_to_user(rrq->pointer, &range, sizeof(range))) | ||
2766 | return -EFAULT; | ||
2767 | |||
2768 | TRACE_EXIT(dev->name); | ||
2769 | |||
2770 | return 0; | ||
2771 | } | ||
2772 | |||
2773 | static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) | ||
2774 | { | ||
2775 | struct orinoco_private *priv = netdev_priv(dev); | ||
2776 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | ||
2777 | int setindex = priv->tx_key; | ||
2778 | int enable = priv->wep_on; | ||
2779 | int restricted = priv->wep_restrict; | ||
2780 | u16 xlen = 0; | ||
2781 | int err = 0; | ||
2782 | char keybuf[ORINOCO_MAX_KEY_SIZE]; | ||
2783 | unsigned long flags; | ||
2784 | |||
2785 | if (! priv->has_wep) | ||
2786 | return -EOPNOTSUPP; | ||
2787 | |||
2788 | if (erq->pointer) { | ||
2789 | /* We actually have a key to set - check its length */ | ||
2790 | if (erq->length > LARGE_KEY_SIZE) | ||
2791 | return -E2BIG; | ||
2792 | |||
2793 | if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) | ||
2794 | return -E2BIG; | ||
2795 | |||
2796 | if (copy_from_user(keybuf, erq->pointer, erq->length)) | ||
2797 | return -EFAULT; | ||
2798 | } | ||
2799 | |||
2800 | if (orinoco_lock(priv, &flags) != 0) | ||
2801 | return -EBUSY; | ||
2802 | |||
2803 | if (erq->pointer) { | ||
2804 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | ||
2805 | index = priv->tx_key; | ||
2806 | |||
2807 | /* Adjust key length to a supported value */ | ||
2808 | if (erq->length > SMALL_KEY_SIZE) { | ||
2809 | xlen = LARGE_KEY_SIZE; | ||
2810 | } else if (erq->length > 0) { | ||
2811 | xlen = SMALL_KEY_SIZE; | ||
2812 | } else | ||
2813 | xlen = 0; | ||
2814 | |||
2815 | /* Switch on WEP if off */ | ||
2816 | if ((!enable) && (xlen > 0)) { | ||
2817 | setindex = index; | ||
2818 | enable = 1; | ||
2819 | } | ||
2820 | } else { | ||
2821 | /* Important note : if the user do "iwconfig eth0 enc off", | ||
2822 | * we will arrive there with an index of -1. This is valid | ||
2823 | * but need to be taken care off... Jean II */ | ||
2824 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { | ||
2825 | if((index != -1) || (erq->flags == 0)) { | ||
2826 | err = -EINVAL; | ||
2827 | goto out; | ||
2828 | } | ||
2829 | } else { | ||
2830 | /* Set the index : Check that the key is valid */ | ||
2831 | if(priv->keys[index].len == 0) { | ||
2832 | err = -EINVAL; | ||
2833 | goto out; | ||
2834 | } | ||
2835 | setindex = index; | ||
2836 | } | ||
2837 | } | ||
2838 | |||
2839 | if (erq->flags & IW_ENCODE_DISABLED) | ||
2840 | enable = 0; | ||
2841 | if (erq->flags & IW_ENCODE_OPEN) | ||
2842 | restricted = 0; | ||
2843 | if (erq->flags & IW_ENCODE_RESTRICTED) | ||
2844 | restricted = 1; | ||
2845 | |||
2846 | if (erq->pointer) { | ||
2847 | priv->keys[index].len = cpu_to_le16(xlen); | ||
2848 | memset(priv->keys[index].data, 0, | ||
2849 | sizeof(priv->keys[index].data)); | ||
2850 | memcpy(priv->keys[index].data, keybuf, erq->length); | ||
2851 | } | ||
2852 | priv->tx_key = setindex; | ||
2853 | |||
2854 | /* Try fast key change if connected and only keys are changed */ | ||
2855 | if (priv->wep_on && enable && (priv->wep_restrict == restricted) && | ||
2856 | netif_carrier_ok(dev)) { | ||
2857 | err = __orinoco_hw_setup_wepkeys(priv); | ||
2858 | /* No need to commit if successful */ | ||
2859 | goto out; | ||
2860 | } | ||
2861 | |||
2862 | priv->wep_on = enable; | ||
2863 | priv->wep_restrict = restricted; | ||
2864 | |||
2865 | out: | ||
2866 | orinoco_unlock(priv, &flags); | ||
2867 | |||
2868 | return err; | ||
2869 | } | ||
2870 | |||
2871 | static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) | ||
2872 | { | ||
2873 | struct orinoco_private *priv = netdev_priv(dev); | ||
2874 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | ||
2875 | u16 xlen = 0; | ||
2876 | char keybuf[ORINOCO_MAX_KEY_SIZE]; | ||
2877 | unsigned long flags; | ||
2878 | |||
2879 | if (! priv->has_wep) | ||
2880 | return -EOPNOTSUPP; | ||
2881 | |||
2882 | if (orinoco_lock(priv, &flags) != 0) | ||
2883 | return -EBUSY; | ||
2884 | |||
2885 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | ||
2886 | index = priv->tx_key; | ||
2887 | |||
2888 | erq->flags = 0; | ||
2889 | if (! priv->wep_on) | ||
2890 | erq->flags |= IW_ENCODE_DISABLED; | ||
2891 | erq->flags |= index + 1; | ||
2892 | |||
2893 | if (priv->wep_restrict) | ||
2894 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
2895 | else | ||
2896 | erq->flags |= IW_ENCODE_OPEN; | ||
2897 | |||
2898 | xlen = le16_to_cpu(priv->keys[index].len); | ||
2899 | |||
2900 | erq->length = xlen; | ||
2901 | |||
2902 | memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); | ||
2903 | |||
2904 | orinoco_unlock(priv, &flags); | ||
2905 | |||
2906 | if (erq->pointer) { | ||
2907 | if (copy_to_user(erq->pointer, keybuf, xlen)) | ||
2908 | return -EFAULT; | ||
2909 | } | ||
2910 | |||
2911 | return 0; | ||
2912 | } | ||
2913 | |||
2914 | static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) | ||
2915 | { | ||
2916 | struct orinoco_private *priv = netdev_priv(dev); | ||
2917 | char essidbuf[IW_ESSID_MAX_SIZE+1]; | ||
2918 | unsigned long flags; | ||
2919 | |||
2920 | /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it | ||
2921 | * anyway... - Jean II */ | ||
2922 | |||
2923 | memset(&essidbuf, 0, sizeof(essidbuf)); | ||
2924 | |||
2925 | if (erq->flags) { | ||
2926 | if (erq->length > IW_ESSID_MAX_SIZE) | ||
2927 | return -E2BIG; | ||
2928 | |||
2929 | if (copy_from_user(&essidbuf, erq->pointer, erq->length)) | ||
2930 | return -EFAULT; | ||
2931 | |||
2932 | essidbuf[erq->length] = '\0'; | ||
2933 | } | ||
2934 | |||
2935 | if (orinoco_lock(priv, &flags) != 0) | ||
2936 | return -EBUSY; | ||
2937 | |||
2938 | memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid)); | ||
2939 | |||
2940 | orinoco_unlock(priv, &flags); | ||
2941 | |||
2942 | return 0; | ||
2943 | } | ||
2944 | |||
2945 | static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) | ||
2946 | { | ||
2947 | struct orinoco_private *priv = netdev_priv(dev); | ||
2948 | char essidbuf[IW_ESSID_MAX_SIZE+1]; | ||
2949 | int active; | ||
2950 | int err = 0; | ||
2951 | unsigned long flags; | ||
2952 | |||
2953 | TRACE_ENTER(dev->name); | ||
2954 | |||
2955 | if (netif_running(dev)) { | ||
2956 | err = orinoco_hw_get_essid(priv, &active, essidbuf); | ||
2957 | if (err) | ||
2958 | return err; | ||
2959 | } else { | ||
2960 | if (orinoco_lock(priv, &flags) != 0) | ||
2961 | return -EBUSY; | ||
2962 | memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf)); | ||
2963 | orinoco_unlock(priv, &flags); | ||
2964 | } | ||
2965 | |||
2966 | erq->flags = 1; | ||
2967 | erq->length = strlen(essidbuf) + 1; | ||
2968 | if (erq->pointer) | ||
2969 | if (copy_to_user(erq->pointer, essidbuf, erq->length)) | ||
2970 | return -EFAULT; | ||
2971 | |||
2972 | TRACE_EXIT(dev->name); | ||
2973 | |||
2974 | return 0; | ||
2975 | } | ||
2976 | |||
2977 | static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) | ||
2978 | { | ||
2979 | struct orinoco_private *priv = netdev_priv(dev); | ||
2980 | char nickbuf[IW_ESSID_MAX_SIZE+1]; | ||
2981 | unsigned long flags; | ||
2982 | |||
2983 | if (nrq->length > IW_ESSID_MAX_SIZE) | ||
2984 | return -E2BIG; | ||
2985 | |||
2986 | memset(nickbuf, 0, sizeof(nickbuf)); | ||
2987 | |||
2988 | if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) | ||
2989 | return -EFAULT; | ||
2990 | |||
2991 | nickbuf[nrq->length] = '\0'; | ||
2992 | |||
2993 | if (orinoco_lock(priv, &flags) != 0) | ||
2994 | return -EBUSY; | ||
2995 | |||
2996 | memcpy(priv->nick, nickbuf, sizeof(priv->nick)); | ||
2997 | |||
2998 | orinoco_unlock(priv, &flags); | ||
2999 | |||
3000 | return 0; | ||
3001 | } | ||
3002 | |||
3003 | static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) | ||
3004 | { | ||
3005 | struct orinoco_private *priv = netdev_priv(dev); | ||
3006 | char nickbuf[IW_ESSID_MAX_SIZE+1]; | ||
3007 | unsigned long flags; | ||
3008 | |||
3009 | if (orinoco_lock(priv, &flags) != 0) | ||
3010 | return -EBUSY; | ||
3011 | |||
3012 | memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); | ||
3013 | orinoco_unlock(priv, &flags); | ||
3014 | |||
3015 | nrq->length = strlen(nickbuf)+1; | ||
3016 | |||
3017 | if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) | ||
3018 | return -EFAULT; | ||
3019 | |||
3020 | return 0; | ||
3021 | } | ||
3022 | |||
3023 | static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) | ||
3024 | { | ||
3025 | struct orinoco_private *priv = netdev_priv(dev); | ||
3026 | int chan = -1; | ||
3027 | unsigned long flags; | ||
3028 | |||
3029 | /* We can only use this in Ad-Hoc demo mode to set the operating | ||
3030 | * frequency, or in IBSS mode to set the frequency where the IBSS | ||
3031 | * will be created - Jean II */ | ||
3032 | if (priv->iw_mode != IW_MODE_ADHOC) | ||
3033 | return -EOPNOTSUPP; | ||
3034 | |||
3035 | if ( (frq->e == 0) && (frq->m <= 1000) ) { | ||
3036 | /* Setting by channel number */ | ||
3037 | chan = frq->m; | ||
3038 | } else { | ||
3039 | /* Setting by frequency - search the table */ | ||
3040 | int mult = 1; | ||
3041 | int i; | ||
3042 | |||
3043 | for (i = 0; i < (6 - frq->e); i++) | ||
3044 | mult *= 10; | ||
3045 | |||
3046 | for (i = 0; i < NUM_CHANNELS; i++) | ||
3047 | if (frq->m == (channel_frequency[i] * mult)) | ||
3048 | chan = i+1; | ||
3049 | } | ||
3050 | |||
3051 | if ( (chan < 1) || (chan > NUM_CHANNELS) || | ||
3052 | ! (priv->channel_mask & (1 << (chan-1)) ) ) | ||
3053 | return -EINVAL; | ||
3054 | |||
3055 | if (orinoco_lock(priv, &flags) != 0) | ||
3056 | return -EBUSY; | ||
3057 | priv->channel = chan; | ||
3058 | orinoco_unlock(priv, &flags); | ||
3059 | |||
3060 | return 0; | ||
3061 | } | ||
3062 | |||
3063 | static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) | ||
3064 | { | ||
3065 | struct orinoco_private *priv = netdev_priv(dev); | ||
3066 | hermes_t *hw = &priv->hw; | ||
3067 | u16 val; | ||
3068 | int err; | ||
3069 | unsigned long flags; | ||
3070 | |||
3071 | if (!priv->has_sensitivity) | ||
3072 | return -EOPNOTSUPP; | ||
3073 | |||
3074 | if (orinoco_lock(priv, &flags) != 0) | ||
3075 | return -EBUSY; | ||
3076 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3077 | HERMES_RID_CNFSYSTEMSCALE, &val); | ||
3078 | orinoco_unlock(priv, &flags); | ||
3079 | |||
3080 | if (err) | ||
3081 | return err; | ||
3082 | |||
3083 | srq->value = val; | ||
3084 | srq->fixed = 0; /* auto */ | ||
3085 | |||
3086 | return 0; | ||
3087 | } | ||
3088 | |||
3089 | static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) | ||
3090 | { | ||
3091 | struct orinoco_private *priv = netdev_priv(dev); | ||
3092 | int val = srq->value; | ||
3093 | unsigned long flags; | ||
3094 | |||
3095 | if (!priv->has_sensitivity) | ||
3096 | return -EOPNOTSUPP; | ||
3097 | |||
3098 | if ((val < 1) || (val > 3)) | ||
3099 | return -EINVAL; | ||
3100 | |||
3101 | if (orinoco_lock(priv, &flags) != 0) | ||
3102 | return -EBUSY; | ||
3103 | priv->ap_density = val; | ||
3104 | orinoco_unlock(priv, &flags); | ||
3105 | |||
3106 | return 0; | ||
3107 | } | ||
3108 | |||
3109 | static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) | ||
3110 | { | ||
3111 | struct orinoco_private *priv = netdev_priv(dev); | ||
3112 | int val = rrq->value; | ||
3113 | unsigned long flags; | ||
3114 | |||
3115 | if (rrq->disabled) | ||
3116 | val = 2347; | ||
3117 | |||
3118 | if ( (val < 0) || (val > 2347) ) | ||
3119 | return -EINVAL; | ||
3120 | |||
3121 | if (orinoco_lock(priv, &flags) != 0) | ||
3122 | return -EBUSY; | ||
3123 | |||
3124 | priv->rts_thresh = val; | ||
3125 | orinoco_unlock(priv, &flags); | ||
3126 | |||
3127 | return 0; | ||
3128 | } | ||
3129 | |||
3130 | static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) | ||
3131 | { | ||
3132 | struct orinoco_private *priv = netdev_priv(dev); | ||
3133 | int err = 0; | ||
3134 | unsigned long flags; | ||
3135 | |||
3136 | if (orinoco_lock(priv, &flags) != 0) | ||
3137 | return -EBUSY; | ||
3138 | |||
3139 | if (priv->has_mwo) { | ||
3140 | if (frq->disabled) | ||
3141 | priv->mwo_robust = 0; | ||
3142 | else { | ||
3143 | if (frq->fixed) | ||
3144 | printk(KERN_WARNING "%s: Fixed fragmentation is " | ||
3145 | "not supported on this firmware. " | ||
3146 | "Using MWO robust instead.\n", dev->name); | ||
3147 | priv->mwo_robust = 1; | ||
3148 | } | ||
3149 | } else { | ||
3150 | if (frq->disabled) | ||
3151 | priv->frag_thresh = 2346; | ||
3152 | else { | ||
3153 | if ( (frq->value < 256) || (frq->value > 2346) ) | ||
3154 | err = -EINVAL; | ||
3155 | else | ||
3156 | priv->frag_thresh = frq->value & ~0x1; /* must be even */ | ||
3157 | } | ||
3158 | } | ||
3159 | |||
3160 | orinoco_unlock(priv, &flags); | ||
3161 | |||
3162 | return err; | ||
3163 | } | ||
3164 | |||
3165 | static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) | ||
3166 | { | ||
3167 | struct orinoco_private *priv = netdev_priv(dev); | ||
3168 | hermes_t *hw = &priv->hw; | ||
3169 | int err = 0; | ||
3170 | u16 val; | ||
3171 | unsigned long flags; | ||
3172 | |||
3173 | if (orinoco_lock(priv, &flags) != 0) | ||
3174 | return -EBUSY; | ||
3175 | |||
3176 | if (priv->has_mwo) { | ||
3177 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3178 | HERMES_RID_CNFMWOROBUST_AGERE, | ||
3179 | &val); | ||
3180 | if (err) | ||
3181 | val = 0; | ||
3182 | |||
3183 | frq->value = val ? 2347 : 0; | ||
3184 | frq->disabled = ! val; | ||
3185 | frq->fixed = 0; | ||
3186 | } else { | ||
3187 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, | ||
3188 | &val); | ||
3189 | if (err) | ||
3190 | val = 0; | ||
3191 | |||
3192 | frq->value = val; | ||
3193 | frq->disabled = (val >= 2346); | ||
3194 | frq->fixed = 1; | ||
3195 | } | ||
3196 | |||
3197 | orinoco_unlock(priv, &flags); | ||
3198 | |||
3199 | return err; | ||
3200 | } | ||
3201 | |||
3202 | static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) | ||
3203 | { | ||
3204 | struct orinoco_private *priv = netdev_priv(dev); | ||
3205 | int err = 0; | ||
3206 | int ratemode = -1; | ||
3207 | int bitrate; /* 100s of kilobits */ | ||
3208 | int i; | ||
3209 | unsigned long flags; | ||
3210 | |||
3211 | /* As the user space doesn't know our highest rate, it uses -1 | ||
3212 | * to ask us to set the highest rate. Test it using "iwconfig | ||
3213 | * ethX rate auto" - Jean II */ | ||
3214 | if (rrq->value == -1) | ||
3215 | bitrate = 110; | ||
3216 | else { | ||
3217 | if (rrq->value % 100000) | ||
3218 | return -EINVAL; | ||
3219 | bitrate = rrq->value / 100000; | ||
3220 | } | ||
3221 | |||
3222 | if ( (bitrate != 10) && (bitrate != 20) && | ||
3223 | (bitrate != 55) && (bitrate != 110) ) | ||
3224 | return -EINVAL; | ||
3225 | |||
3226 | for (i = 0; i < BITRATE_TABLE_SIZE; i++) | ||
3227 | if ( (bitrate_table[i].bitrate == bitrate) && | ||
3228 | (bitrate_table[i].automatic == ! rrq->fixed) ) { | ||
3229 | ratemode = i; | ||
3230 | break; | ||
3231 | } | ||
3232 | |||
3233 | if (ratemode == -1) | ||
3234 | return -EINVAL; | ||
3235 | |||
3236 | if (orinoco_lock(priv, &flags) != 0) | ||
3237 | return -EBUSY; | ||
3238 | priv->bitratemode = ratemode; | ||
3239 | orinoco_unlock(priv, &flags); | ||
3240 | |||
3241 | return err; | ||
3242 | } | ||
3243 | |||
3244 | static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) | ||
3245 | { | ||
3246 | struct orinoco_private *priv = netdev_priv(dev); | ||
3247 | hermes_t *hw = &priv->hw; | ||
3248 | int err = 0; | ||
3249 | int ratemode; | ||
3250 | int i; | ||
3251 | u16 val; | ||
3252 | unsigned long flags; | ||
3253 | |||
3254 | if (orinoco_lock(priv, &flags) != 0) | ||
3255 | return -EBUSY; | ||
3256 | |||
3257 | ratemode = priv->bitratemode; | ||
3258 | |||
3259 | BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); | ||
3260 | |||
3261 | rrq->value = bitrate_table[ratemode].bitrate * 100000; | ||
3262 | rrq->fixed = ! bitrate_table[ratemode].automatic; | ||
3263 | rrq->disabled = 0; | ||
3264 | |||
3265 | /* If the interface is running we try to find more about the | ||
3266 | current mode */ | ||
3267 | if (netif_running(dev)) { | ||
3268 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3269 | HERMES_RID_CURRENTTXRATE, &val); | ||
3270 | if (err) | ||
3271 | goto out; | ||
3272 | |||
3273 | switch (priv->firmware_type) { | ||
3274 | case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ | ||
3275 | /* Note : in Lucent firmware, the return value of | ||
3276 | * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, | ||
3277 | * and therefore is totally different from the | ||
3278 | * encoding of HERMES_RID_CNFTXRATECONTROL. | ||
3279 | * Don't forget that 6Mb/s is really 5.5Mb/s */ | ||
3280 | if (val == 6) | ||
3281 | rrq->value = 5500000; | ||
3282 | else | ||
3283 | rrq->value = val * 1000000; | ||
3284 | break; | ||
3285 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ | ||
3286 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ | ||
3287 | for (i = 0; i < BITRATE_TABLE_SIZE; i++) | ||
3288 | if (bitrate_table[i].intersil_txratectrl == val) { | ||
3289 | ratemode = i; | ||
3290 | break; | ||
3291 | } | ||
3292 | if (i >= BITRATE_TABLE_SIZE) | ||
3293 | printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", | ||
3294 | dev->name, val); | ||
3295 | |||
3296 | rrq->value = bitrate_table[ratemode].bitrate * 100000; | ||
3297 | break; | ||
3298 | default: | ||
3299 | BUG(); | ||
3300 | } | ||
3301 | } | ||
3302 | |||
3303 | out: | ||
3304 | orinoco_unlock(priv, &flags); | ||
3305 | |||
3306 | return err; | ||
3307 | } | ||
3308 | |||
3309 | static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) | ||
3310 | { | ||
3311 | struct orinoco_private *priv = netdev_priv(dev); | ||
3312 | int err = 0; | ||
3313 | unsigned long flags; | ||
3314 | |||
3315 | if (orinoco_lock(priv, &flags) != 0) | ||
3316 | return -EBUSY; | ||
3317 | |||
3318 | if (prq->disabled) { | ||
3319 | priv->pm_on = 0; | ||
3320 | } else { | ||
3321 | switch (prq->flags & IW_POWER_MODE) { | ||
3322 | case IW_POWER_UNICAST_R: | ||
3323 | priv->pm_mcast = 0; | ||
3324 | priv->pm_on = 1; | ||
3325 | break; | ||
3326 | case IW_POWER_ALL_R: | ||
3327 | priv->pm_mcast = 1; | ||
3328 | priv->pm_on = 1; | ||
3329 | break; | ||
3330 | case IW_POWER_ON: | ||
3331 | /* No flags : but we may have a value - Jean II */ | ||
3332 | break; | ||
3333 | default: | ||
3334 | err = -EINVAL; | ||
3335 | } | ||
3336 | if (err) | ||
3337 | goto out; | ||
3338 | |||
3339 | if (prq->flags & IW_POWER_TIMEOUT) { | ||
3340 | priv->pm_on = 1; | ||
3341 | priv->pm_timeout = prq->value / 1000; | ||
3342 | } | ||
3343 | if (prq->flags & IW_POWER_PERIOD) { | ||
3344 | priv->pm_on = 1; | ||
3345 | priv->pm_period = prq->value / 1000; | ||
3346 | } | ||
3347 | /* It's valid to not have a value if we are just toggling | ||
3348 | * the flags... Jean II */ | ||
3349 | if(!priv->pm_on) { | ||
3350 | err = -EINVAL; | ||
3351 | goto out; | ||
3352 | } | ||
3353 | } | ||
3354 | |||
3355 | out: | ||
3356 | orinoco_unlock(priv, &flags); | ||
3357 | |||
3358 | return err; | ||
3359 | } | ||
3360 | |||
3361 | static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) | ||
3362 | { | ||
3363 | struct orinoco_private *priv = netdev_priv(dev); | ||
3364 | hermes_t *hw = &priv->hw; | ||
3365 | int err = 0; | ||
3366 | u16 enable, period, timeout, mcast; | ||
3367 | unsigned long flags; | ||
3368 | |||
3369 | if (orinoco_lock(priv, &flags) != 0) | ||
3370 | return -EBUSY; | ||
3371 | |||
3372 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable); | ||
3373 | if (err) | ||
3374 | goto out; | ||
3375 | |||
3376 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3377 | HERMES_RID_CNFMAXSLEEPDURATION, &period); | ||
3378 | if (err) | ||
3379 | goto out; | ||
3380 | |||
3381 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); | ||
3382 | if (err) | ||
3383 | goto out; | ||
3384 | |||
3385 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast); | ||
3386 | if (err) | ||
3387 | goto out; | ||
3388 | |||
3389 | prq->disabled = !enable; | ||
3390 | /* Note : by default, display the period */ | ||
3391 | if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
3392 | prq->flags = IW_POWER_TIMEOUT; | ||
3393 | prq->value = timeout * 1000; | ||
3394 | } else { | ||
3395 | prq->flags = IW_POWER_PERIOD; | ||
3396 | prq->value = period * 1000; | ||
3397 | } | ||
3398 | if (mcast) | ||
3399 | prq->flags |= IW_POWER_ALL_R; | ||
3400 | else | ||
3401 | prq->flags |= IW_POWER_UNICAST_R; | ||
3402 | |||
3403 | out: | ||
3404 | orinoco_unlock(priv, &flags); | ||
3405 | |||
3406 | return err; | ||
3407 | } | ||
3408 | |||
3409 | static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) | ||
3410 | { | ||
3411 | struct orinoco_private *priv = netdev_priv(dev); | ||
3412 | hermes_t *hw = &priv->hw; | ||
3413 | int err = 0; | ||
3414 | u16 short_limit, long_limit, lifetime; | ||
3415 | unsigned long flags; | ||
3416 | |||
3417 | if (orinoco_lock(priv, &flags) != 0) | ||
3418 | return -EBUSY; | ||
3419 | |||
3420 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, | ||
3421 | &short_limit); | ||
3422 | if (err) | ||
3423 | goto out; | ||
3424 | |||
3425 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, | ||
3426 | &long_limit); | ||
3427 | if (err) | ||
3428 | goto out; | ||
3429 | |||
3430 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, | ||
3431 | &lifetime); | ||
3432 | if (err) | ||
3433 | goto out; | ||
3434 | |||
3435 | rrq->disabled = 0; /* Can't be disabled */ | ||
3436 | |||
3437 | /* Note : by default, display the retry number */ | ||
3438 | if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
3439 | rrq->flags = IW_RETRY_LIFETIME; | ||
3440 | rrq->value = lifetime * 1000; /* ??? */ | ||
3441 | } else { | ||
3442 | /* By default, display the min number */ | ||
3443 | if ((rrq->flags & IW_RETRY_MAX)) { | ||
3444 | rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
3445 | rrq->value = long_limit; | ||
3446 | } else { | ||
3447 | rrq->flags = IW_RETRY_LIMIT; | ||
3448 | rrq->value = short_limit; | ||
3449 | if(short_limit != long_limit) | ||
3450 | rrq->flags |= IW_RETRY_MIN; | ||
3451 | } | ||
3452 | } | ||
3453 | |||
3454 | out: | ||
3455 | orinoco_unlock(priv, &flags); | ||
3456 | |||
3457 | return err; | ||
3458 | } | ||
3459 | |||
3460 | static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) | ||
3461 | { | ||
3462 | struct orinoco_private *priv = netdev_priv(dev); | ||
3463 | int val = *( (int *) wrq->u.name ); | ||
3464 | unsigned long flags; | ||
3465 | |||
3466 | if (orinoco_lock(priv, &flags) != 0) | ||
3467 | return -EBUSY; | ||
3468 | |||
3469 | priv->ibss_port = val ; | ||
3470 | |||
3471 | /* Actually update the mode we are using */ | ||
3472 | set_port_type(priv); | ||
3473 | |||
3474 | orinoco_unlock(priv, &flags); | ||
3475 | return 0; | ||
3476 | } | ||
3477 | |||
3478 | static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) | ||
3479 | { | ||
3480 | struct orinoco_private *priv = netdev_priv(dev); | ||
3481 | int *val = (int *)wrq->u.name; | ||
3482 | unsigned long flags; | ||
3483 | |||
3484 | if (orinoco_lock(priv, &flags) != 0) | ||
3485 | return -EBUSY; | ||
3486 | |||
3487 | *val = priv->ibss_port; | ||
3488 | orinoco_unlock(priv, &flags); | ||
3489 | |||
3490 | return 0; | ||
3491 | } | ||
3492 | |||
3493 | static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) | ||
3494 | { | ||
3495 | struct orinoco_private *priv = netdev_priv(dev); | ||
3496 | int val = *( (int *) wrq->u.name ); | ||
3497 | int err = 0; | ||
3498 | unsigned long flags; | ||
3499 | |||
3500 | if (orinoco_lock(priv, &flags) != 0) | ||
3501 | return -EBUSY; | ||
3502 | |||
3503 | switch (val) { | ||
3504 | case 0: /* Try to do IEEE ad-hoc mode */ | ||
3505 | if (! priv->has_ibss) { | ||
3506 | err = -EINVAL; | ||
3507 | break; | ||
3508 | } | ||
3509 | priv->prefer_port3 = 0; | ||
3510 | |||
3511 | break; | ||
3512 | |||
3513 | case 1: /* Try to do Lucent proprietary ad-hoc mode */ | ||
3514 | if (! priv->has_port3) { | ||
3515 | err = -EINVAL; | ||
3516 | break; | ||
3517 | } | ||
3518 | priv->prefer_port3 = 1; | ||
3519 | break; | ||
3520 | |||
3521 | default: | ||
3522 | err = -EINVAL; | ||
3523 | } | ||
3524 | |||
3525 | if (! err) | ||
3526 | /* Actually update the mode we are using */ | ||
3527 | set_port_type(priv); | ||
3528 | |||
3529 | orinoco_unlock(priv, &flags); | ||
3530 | |||
3531 | return err; | ||
3532 | } | ||
3533 | |||
3534 | static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) | ||
3535 | { | ||
3536 | struct orinoco_private *priv = netdev_priv(dev); | ||
3537 | int *val = (int *)wrq->u.name; | ||
3538 | unsigned long flags; | ||
3539 | |||
3540 | if (orinoco_lock(priv, &flags) != 0) | ||
3541 | return -EBUSY; | ||
3542 | |||
3543 | *val = priv->prefer_port3; | ||
3544 | orinoco_unlock(priv, &flags); | ||
3545 | return 0; | ||
3546 | } | ||
3547 | |||
3548 | /* Spy is used for link quality/strength measurements in Ad-Hoc mode | ||
3549 | * Jean II */ | ||
3550 | static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) | ||
3551 | { | ||
3552 | struct orinoco_private *priv = netdev_priv(dev); | ||
3553 | struct sockaddr address[IW_MAX_SPY]; | ||
3554 | int number = srq->length; | ||
3555 | int i; | ||
3556 | int err = 0; | ||
3557 | unsigned long flags; | ||
3558 | |||
3559 | /* Check the number of addresses */ | ||
3560 | if (number > IW_MAX_SPY) | ||
3561 | return -E2BIG; | ||
3562 | |||
3563 | /* Get the data in the driver */ | ||
3564 | if (srq->pointer) { | ||
3565 | if (copy_from_user(address, srq->pointer, | ||
3566 | sizeof(struct sockaddr) * number)) | ||
3567 | return -EFAULT; | ||
3568 | } | ||
3569 | |||
3570 | /* Make sure nobody mess with the structure while we do */ | ||
3571 | if (orinoco_lock(priv, &flags) != 0) | ||
3572 | return -EBUSY; | ||
3573 | |||
3574 | /* orinoco_lock() doesn't disable interrupts, so make sure the | ||
3575 | * interrupt rx path don't get confused while we copy */ | ||
3576 | priv->spy_number = 0; | ||
3577 | |||
3578 | if (number > 0) { | ||
3579 | /* Extract the addresses */ | ||
3580 | for (i = 0; i < number; i++) | ||
3581 | memcpy(priv->spy_address[i], address[i].sa_data, | ||
3582 | ETH_ALEN); | ||
3583 | /* Reset stats */ | ||
3584 | memset(priv->spy_stat, 0, | ||
3585 | sizeof(struct iw_quality) * IW_MAX_SPY); | ||
3586 | /* Set number of addresses */ | ||
3587 | priv->spy_number = number; | ||
3588 | } | ||
3589 | |||
3590 | /* Now, let the others play */ | ||
3591 | orinoco_unlock(priv, &flags); | ||
3592 | |||
3593 | return err; | ||
3594 | } | ||
3595 | |||
3596 | static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) | ||
3597 | { | ||
3598 | struct orinoco_private *priv = netdev_priv(dev); | ||
3599 | struct sockaddr address[IW_MAX_SPY]; | ||
3600 | struct iw_quality spy_stat[IW_MAX_SPY]; | ||
3601 | int number; | ||
3602 | int i; | ||
3603 | unsigned long flags; | ||
3604 | |||
3605 | if (orinoco_lock(priv, &flags) != 0) | ||
3606 | return -EBUSY; | ||
3607 | |||
3608 | number = priv->spy_number; | ||
3609 | if ((number > 0) && (srq->pointer)) { | ||
3610 | /* Create address struct */ | ||
3611 | for (i = 0; i < number; i++) { | ||
3612 | memcpy(address[i].sa_data, priv->spy_address[i], | ||
3613 | ETH_ALEN); | ||
3614 | address[i].sa_family = AF_UNIX; | ||
3615 | } | ||
3616 | /* Copy stats */ | ||
3617 | /* In theory, we should disable irqs while copying the stats | ||
3618 | * because the rx path might update it in the middle... | ||
3619 | * Bah, who care ? - Jean II */ | ||
3620 | memcpy(&spy_stat, priv->spy_stat, | ||
3621 | sizeof(struct iw_quality) * IW_MAX_SPY); | ||
3622 | for (i=0; i < number; i++) | ||
3623 | priv->spy_stat[i].updated = 0; | ||
3624 | } | ||
3625 | |||
3626 | orinoco_unlock(priv, &flags); | ||
3627 | |||
3628 | /* Push stuff to user space */ | ||
3629 | srq->length = number; | ||
3630 | if(copy_to_user(srq->pointer, address, | ||
3631 | sizeof(struct sockaddr) * number)) | ||
3632 | return -EFAULT; | ||
3633 | if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), | ||
3634 | &spy_stat, sizeof(struct iw_quality) * number)) | ||
3635 | return -EFAULT; | ||
3636 | |||
3637 | return 0; | ||
3638 | } | ||
3639 | |||
3640 | static int | ||
3641 | orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
3642 | { | ||
3643 | struct orinoco_private *priv = netdev_priv(dev); | ||
3644 | struct iwreq *wrq = (struct iwreq *)rq; | ||
3645 | int err = 0; | ||
3646 | int tmp; | ||
3647 | int changed = 0; | ||
3648 | unsigned long flags; | ||
3649 | |||
3650 | TRACE_ENTER(dev->name); | ||
3651 | |||
3652 | /* In theory, we could allow most of the the SET stuff to be | ||
3653 | * done. In practice, the lapse of time at startup when the | ||
3654 | * card is not ready is very short, so why bother... Note | ||
3655 | * that netif_device_present is different from up/down | ||
3656 | * (ifconfig), when the device is not yet up, it is usually | ||
3657 | * already ready... Jean II */ | ||
3658 | if (! netif_device_present(dev)) | ||
3659 | return -ENODEV; | ||
3660 | |||
3661 | switch (cmd) { | ||
3662 | case SIOCGIWNAME: | ||
3663 | strcpy(wrq->u.name, "IEEE 802.11-DS"); | ||
3664 | break; | ||
3665 | |||
3666 | case SIOCGIWAP: | ||
3667 | wrq->u.ap_addr.sa_family = ARPHRD_ETHER; | ||
3668 | err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); | ||
3669 | break; | ||
3670 | |||
3671 | case SIOCGIWRANGE: | ||
3672 | err = orinoco_ioctl_getiwrange(dev, &wrq->u.data); | ||
3673 | break; | ||
3674 | |||
3675 | case SIOCSIWMODE: | ||
3676 | if (orinoco_lock(priv, &flags) != 0) | ||
3677 | return -EBUSY; | ||
3678 | switch (wrq->u.mode) { | ||
3679 | case IW_MODE_ADHOC: | ||
3680 | if (! (priv->has_ibss || priv->has_port3) ) | ||
3681 | err = -EINVAL; | ||
3682 | else { | ||
3683 | priv->iw_mode = IW_MODE_ADHOC; | ||
3684 | changed = 1; | ||
3685 | } | ||
3686 | break; | ||
3687 | |||
3688 | case IW_MODE_INFRA: | ||
3689 | priv->iw_mode = IW_MODE_INFRA; | ||
3690 | changed = 1; | ||
3691 | break; | ||
3692 | |||
3693 | default: | ||
3694 | err = -EINVAL; | ||
3695 | break; | ||
3696 | } | ||
3697 | set_port_type(priv); | ||
3698 | orinoco_unlock(priv, &flags); | ||
3699 | break; | ||
3700 | |||
3701 | case SIOCGIWMODE: | ||
3702 | if (orinoco_lock(priv, &flags) != 0) | ||
3703 | return -EBUSY; | ||
3704 | wrq->u.mode = priv->iw_mode; | ||
3705 | orinoco_unlock(priv, &flags); | ||
3706 | break; | ||
3707 | |||
3708 | case SIOCSIWENCODE: | ||
3709 | err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding); | ||
3710 | if (! err) | ||
3711 | changed = 1; | ||
3712 | break; | ||
3713 | |||
3714 | case SIOCGIWENCODE: | ||
3715 | if (! capable(CAP_NET_ADMIN)) { | ||
3716 | err = -EPERM; | ||
3717 | break; | ||
3718 | } | ||
3719 | |||
3720 | err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding); | ||
3721 | break; | ||
3722 | |||
3723 | case SIOCSIWESSID: | ||
3724 | err = orinoco_ioctl_setessid(dev, &wrq->u.essid); | ||
3725 | if (! err) | ||
3726 | changed = 1; | ||
3727 | break; | ||
3728 | |||
3729 | case SIOCGIWESSID: | ||
3730 | err = orinoco_ioctl_getessid(dev, &wrq->u.essid); | ||
3731 | break; | ||
3732 | |||
3733 | case SIOCSIWNICKN: | ||
3734 | err = orinoco_ioctl_setnick(dev, &wrq->u.data); | ||
3735 | if (! err) | ||
3736 | changed = 1; | ||
3737 | break; | ||
3738 | |||
3739 | case SIOCGIWNICKN: | ||
3740 | err = orinoco_ioctl_getnick(dev, &wrq->u.data); | ||
3741 | break; | ||
3742 | |||
3743 | case SIOCGIWFREQ: | ||
3744 | tmp = orinoco_hw_get_freq(priv); | ||
3745 | if (tmp < 0) { | ||
3746 | err = tmp; | ||
3747 | } else { | ||
3748 | wrq->u.freq.m = tmp; | ||
3749 | wrq->u.freq.e = 1; | ||
3750 | } | ||
3751 | break; | ||
3752 | |||
3753 | case SIOCSIWFREQ: | ||
3754 | err = orinoco_ioctl_setfreq(dev, &wrq->u.freq); | ||
3755 | if (! err) | ||
3756 | changed = 1; | ||
3757 | break; | ||
3758 | |||
3759 | case SIOCGIWSENS: | ||
3760 | err = orinoco_ioctl_getsens(dev, &wrq->u.sens); | ||
3761 | break; | ||
3762 | |||
3763 | case SIOCSIWSENS: | ||
3764 | err = orinoco_ioctl_setsens(dev, &wrq->u.sens); | ||
3765 | if (! err) | ||
3766 | changed = 1; | ||
3767 | break; | ||
3768 | |||
3769 | case SIOCGIWRTS: | ||
3770 | wrq->u.rts.value = priv->rts_thresh; | ||
3771 | wrq->u.rts.disabled = (wrq->u.rts.value == 2347); | ||
3772 | wrq->u.rts.fixed = 1; | ||
3773 | break; | ||
3774 | |||
3775 | case SIOCSIWRTS: | ||
3776 | err = orinoco_ioctl_setrts(dev, &wrq->u.rts); | ||
3777 | if (! err) | ||
3778 | changed = 1; | ||
3779 | break; | ||
3780 | |||
3781 | case SIOCSIWFRAG: | ||
3782 | err = orinoco_ioctl_setfrag(dev, &wrq->u.frag); | ||
3783 | if (! err) | ||
3784 | changed = 1; | ||
3785 | break; | ||
3786 | |||
3787 | case SIOCGIWFRAG: | ||
3788 | err = orinoco_ioctl_getfrag(dev, &wrq->u.frag); | ||
3789 | break; | ||
3790 | |||
3791 | case SIOCSIWRATE: | ||
3792 | err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate); | ||
3793 | if (! err) | ||
3794 | changed = 1; | ||
3795 | break; | ||
3796 | |||
3797 | case SIOCGIWRATE: | ||
3798 | err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate); | ||
3799 | break; | ||
3800 | |||
3801 | case SIOCSIWPOWER: | ||
3802 | err = orinoco_ioctl_setpower(dev, &wrq->u.power); | ||
3803 | if (! err) | ||
3804 | changed = 1; | ||
3805 | break; | ||
3806 | |||
3807 | case SIOCGIWPOWER: | ||
3808 | err = orinoco_ioctl_getpower(dev, &wrq->u.power); | ||
3809 | break; | ||
3810 | |||
3811 | case SIOCGIWTXPOW: | ||
3812 | /* The card only supports one tx power, so this is easy */ | ||
3813 | wrq->u.txpower.value = 15; /* dBm */ | ||
3814 | wrq->u.txpower.fixed = 1; | ||
3815 | wrq->u.txpower.disabled = 0; | ||
3816 | wrq->u.txpower.flags = IW_TXPOW_DBM; | ||
3817 | break; | ||
3818 | |||
3819 | case SIOCSIWRETRY: | ||
3820 | err = -EOPNOTSUPP; | ||
3821 | break; | ||
3822 | |||
3823 | case SIOCGIWRETRY: | ||
3824 | err = orinoco_ioctl_getretry(dev, &wrq->u.retry); | ||
3825 | break; | ||
3826 | |||
3827 | case SIOCSIWSPY: | ||
3828 | err = orinoco_ioctl_setspy(dev, &wrq->u.data); | ||
3829 | break; | ||
3830 | |||
3831 | case SIOCGIWSPY: | ||
3832 | err = orinoco_ioctl_getspy(dev, &wrq->u.data); | ||
3833 | break; | ||
3834 | |||
3835 | case SIOCGIWPRIV: | ||
3836 | if (wrq->u.data.pointer) { | ||
3837 | struct iw_priv_args privtab[] = { | ||
3838 | { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, | ||
3839 | { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, | ||
3840 | { SIOCIWFIRSTPRIV + 0x2, | ||
3841 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3842 | 0, "set_port3" }, | ||
3843 | { SIOCIWFIRSTPRIV + 0x3, 0, | ||
3844 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3845 | "get_port3" }, | ||
3846 | { SIOCIWFIRSTPRIV + 0x4, | ||
3847 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3848 | 0, "set_preamble" }, | ||
3849 | { SIOCIWFIRSTPRIV + 0x5, 0, | ||
3850 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3851 | "get_preamble" }, | ||
3852 | { SIOCIWFIRSTPRIV + 0x6, | ||
3853 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3854 | 0, "set_ibssport" }, | ||
3855 | { SIOCIWFIRSTPRIV + 0x7, 0, | ||
3856 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3857 | "get_ibssport" }, | ||
3858 | { SIOCIWLASTPRIV, 0, 0, "dump_recs" }, | ||
3859 | }; | ||
3860 | |||
3861 | wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); | ||
3862 | if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) | ||
3863 | err = -EFAULT; | ||
3864 | } | ||
3865 | break; | ||
3866 | |||
3867 | case SIOCIWFIRSTPRIV + 0x0: /* force_reset */ | ||
3868 | case SIOCIWFIRSTPRIV + 0x1: /* card_reset */ | ||
3869 | if (! capable(CAP_NET_ADMIN)) { | ||
3870 | err = -EPERM; | ||
3871 | break; | ||
3872 | } | ||
3873 | |||
3874 | printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); | ||
3875 | |||
3876 | schedule_work(&priv->reset_work); | ||
3877 | break; | ||
3878 | |||
3879 | case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ | ||
3880 | if (! capable(CAP_NET_ADMIN)) { | ||
3881 | err = -EPERM; | ||
3882 | break; | ||
3883 | } | ||
3884 | |||
3885 | err = orinoco_ioctl_setport3(dev, wrq); | ||
3886 | if (! err) | ||
3887 | changed = 1; | ||
3888 | break; | ||
3889 | |||
3890 | case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */ | ||
3891 | err = orinoco_ioctl_getport3(dev, wrq); | ||
3892 | break; | ||
3893 | |||
3894 | case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */ | ||
3895 | if (! capable(CAP_NET_ADMIN)) { | ||
3896 | err = -EPERM; | ||
3897 | break; | ||
3898 | } | ||
3899 | |||
3900 | /* 802.11b has recently defined some short preamble. | ||
3901 | * Basically, the Phy header has been reduced in size. | ||
3902 | * This increase performance, especially at high rates | ||
3903 | * (the preamble is transmitted at 1Mb/s), unfortunately | ||
3904 | * this give compatibility troubles... - Jean II */ | ||
3905 | if(priv->has_preamble) { | ||
3906 | int val = *( (int *) wrq->u.name ); | ||
3907 | |||
3908 | if (orinoco_lock(priv, &flags) != 0) | ||
3909 | return -EBUSY; | ||
3910 | if (val) | ||
3911 | priv->preamble = 1; | ||
3912 | else | ||
3913 | priv->preamble = 0; | ||
3914 | orinoco_unlock(priv, &flags); | ||
3915 | changed = 1; | ||
3916 | } else | ||
3917 | err = -EOPNOTSUPP; | ||
3918 | break; | ||
3919 | |||
3920 | case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */ | ||
3921 | if(priv->has_preamble) { | ||
3922 | int *val = (int *)wrq->u.name; | ||
3923 | |||
3924 | if (orinoco_lock(priv, &flags) != 0) | ||
3925 | return -EBUSY; | ||
3926 | *val = priv->preamble; | ||
3927 | orinoco_unlock(priv, &flags); | ||
3928 | } else | ||
3929 | err = -EOPNOTSUPP; | ||
3930 | break; | ||
3931 | case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */ | ||
3932 | if (! capable(CAP_NET_ADMIN)) { | ||
3933 | err = -EPERM; | ||
3934 | break; | ||
3935 | } | ||
3936 | |||
3937 | err = orinoco_ioctl_setibssport(dev, wrq); | ||
3938 | if (! err) | ||
3939 | changed = 1; | ||
3940 | break; | ||
3941 | |||
3942 | case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */ | ||
3943 | err = orinoco_ioctl_getibssport(dev, wrq); | ||
3944 | break; | ||
3945 | |||
3946 | case SIOCIWLASTPRIV: | ||
3947 | err = orinoco_debug_dump_recs(dev); | ||
3948 | if (err) | ||
3949 | printk(KERN_ERR "%s: Unable to dump records (%d)\n", | ||
3950 | dev->name, err); | ||
3951 | break; | ||
3952 | |||
3953 | |||
3954 | default: | ||
3955 | err = -EOPNOTSUPP; | ||
3956 | } | ||
3957 | |||
3958 | if (! err && changed && netif_running(dev)) { | ||
3959 | err = orinoco_reconfigure(dev); | ||
3960 | } | ||
3961 | |||
3962 | TRACE_EXIT(dev->name); | ||
3963 | |||
3964 | return err; | ||
3965 | } | ||
3966 | |||
3967 | struct { | ||
3968 | u16 rid; | ||
3969 | char *name; | ||
3970 | int displaytype; | ||
3971 | #define DISPLAY_WORDS 0 | ||
3972 | #define DISPLAY_BYTES 1 | ||
3973 | #define DISPLAY_STRING 2 | ||
3974 | #define DISPLAY_XSTRING 3 | ||
3975 | } record_table[] = { | ||
3976 | #define DEBUG_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type } | ||
3977 | DEBUG_REC(CNFPORTTYPE,WORDS), | ||
3978 | DEBUG_REC(CNFOWNMACADDR,BYTES), | ||
3979 | DEBUG_REC(CNFDESIREDSSID,STRING), | ||
3980 | DEBUG_REC(CNFOWNCHANNEL,WORDS), | ||
3981 | DEBUG_REC(CNFOWNSSID,STRING), | ||
3982 | DEBUG_REC(CNFOWNATIMWINDOW,WORDS), | ||
3983 | DEBUG_REC(CNFSYSTEMSCALE,WORDS), | ||
3984 | DEBUG_REC(CNFMAXDATALEN,WORDS), | ||
3985 | DEBUG_REC(CNFPMENABLED,WORDS), | ||
3986 | DEBUG_REC(CNFPMEPS,WORDS), | ||
3987 | DEBUG_REC(CNFMULTICASTRECEIVE,WORDS), | ||
3988 | DEBUG_REC(CNFMAXSLEEPDURATION,WORDS), | ||
3989 | DEBUG_REC(CNFPMHOLDOVERDURATION,WORDS), | ||
3990 | DEBUG_REC(CNFOWNNAME,STRING), | ||
3991 | DEBUG_REC(CNFOWNDTIMPERIOD,WORDS), | ||
3992 | DEBUG_REC(CNFMULTICASTPMBUFFERING,WORDS), | ||
3993 | DEBUG_REC(CNFWEPENABLED_AGERE,WORDS), | ||
3994 | DEBUG_REC(CNFMANDATORYBSSID_SYMBOL,WORDS), | ||
3995 | DEBUG_REC(CNFWEPDEFAULTKEYID,WORDS), | ||
3996 | DEBUG_REC(CNFDEFAULTKEY0,BYTES), | ||
3997 | DEBUG_REC(CNFDEFAULTKEY1,BYTES), | ||
3998 | DEBUG_REC(CNFMWOROBUST_AGERE,WORDS), | ||
3999 | DEBUG_REC(CNFDEFAULTKEY2,BYTES), | ||
4000 | DEBUG_REC(CNFDEFAULTKEY3,BYTES), | ||
4001 | DEBUG_REC(CNFWEPFLAGS_INTERSIL,WORDS), | ||
4002 | DEBUG_REC(CNFWEPKEYMAPPINGTABLE,WORDS), | ||
4003 | DEBUG_REC(CNFAUTHENTICATION,WORDS), | ||
4004 | DEBUG_REC(CNFMAXASSOCSTA,WORDS), | ||
4005 | DEBUG_REC(CNFKEYLENGTH_SYMBOL,WORDS), | ||
4006 | DEBUG_REC(CNFTXCONTROL,WORDS), | ||
4007 | DEBUG_REC(CNFROAMINGMODE,WORDS), | ||
4008 | DEBUG_REC(CNFHOSTAUTHENTICATION,WORDS), | ||
4009 | DEBUG_REC(CNFRCVCRCERROR,WORDS), | ||
4010 | DEBUG_REC(CNFMMLIFE,WORDS), | ||
4011 | DEBUG_REC(CNFALTRETRYCOUNT,WORDS), | ||
4012 | DEBUG_REC(CNFBEACONINT,WORDS), | ||
4013 | DEBUG_REC(CNFAPPCFINFO,WORDS), | ||
4014 | DEBUG_REC(CNFSTAPCFINFO,WORDS), | ||
4015 | DEBUG_REC(CNFPRIORITYQUSAGE,WORDS), | ||
4016 | DEBUG_REC(CNFTIMCTRL,WORDS), | ||
4017 | DEBUG_REC(CNFTHIRTY2TALLY,WORDS), | ||
4018 | DEBUG_REC(CNFENHSECURITY,WORDS), | ||
4019 | DEBUG_REC(CNFGROUPADDRESSES,BYTES), | ||
4020 | DEBUG_REC(CNFCREATEIBSS,WORDS), | ||
4021 | DEBUG_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS), | ||
4022 | DEBUG_REC(CNFRTSTHRESHOLD,WORDS), | ||
4023 | DEBUG_REC(CNFTXRATECONTROL,WORDS), | ||
4024 | DEBUG_REC(CNFPROMISCUOUSMODE,WORDS), | ||
4025 | DEBUG_REC(CNFBASICRATES_SYMBOL,WORDS), | ||
4026 | DEBUG_REC(CNFPREAMBLE_SYMBOL,WORDS), | ||
4027 | DEBUG_REC(CNFSHORTPREAMBLE,WORDS), | ||
4028 | DEBUG_REC(CNFWEPKEYS_AGERE,BYTES), | ||
4029 | DEBUG_REC(CNFEXCLUDELONGPREAMBLE,WORDS), | ||
4030 | DEBUG_REC(CNFTXKEY_AGERE,WORDS), | ||
4031 | DEBUG_REC(CNFAUTHENTICATIONRSPTO,WORDS), | ||
4032 | DEBUG_REC(CNFBASICRATES,WORDS), | ||
4033 | DEBUG_REC(CNFSUPPORTEDRATES,WORDS), | ||
4034 | DEBUG_REC(CNFTICKTIME,WORDS), | ||
4035 | DEBUG_REC(CNFSCANREQUEST,WORDS), | ||
4036 | DEBUG_REC(CNFJOINREQUEST,WORDS), | ||
4037 | DEBUG_REC(CNFAUTHENTICATESTATION,WORDS), | ||
4038 | DEBUG_REC(CNFCHANNELINFOREQUEST,WORDS), | ||
4039 | DEBUG_REC(MAXLOADTIME,WORDS), | ||
4040 | DEBUG_REC(DOWNLOADBUFFER,WORDS), | ||
4041 | DEBUG_REC(PRIID,WORDS), | ||
4042 | DEBUG_REC(PRISUPRANGE,WORDS), | ||
4043 | DEBUG_REC(CFIACTRANGES,WORDS), | ||
4044 | DEBUG_REC(NICSERNUM,XSTRING), | ||
4045 | DEBUG_REC(NICID,WORDS), | ||
4046 | DEBUG_REC(MFISUPRANGE,WORDS), | ||
4047 | DEBUG_REC(CFISUPRANGE,WORDS), | ||
4048 | DEBUG_REC(CHANNELLIST,WORDS), | ||
4049 | DEBUG_REC(REGULATORYDOMAINS,WORDS), | ||
4050 | DEBUG_REC(TEMPTYPE,WORDS), | ||
4051 | /* DEBUG_REC(CIS,BYTES), */ | ||
4052 | DEBUG_REC(STAID,WORDS), | ||
4053 | DEBUG_REC(CURRENTSSID,STRING), | ||
4054 | DEBUG_REC(CURRENTBSSID,BYTES), | ||
4055 | DEBUG_REC(COMMSQUALITY,WORDS), | ||
4056 | DEBUG_REC(CURRENTTXRATE,WORDS), | ||
4057 | DEBUG_REC(CURRENTBEACONINTERVAL,WORDS), | ||
4058 | DEBUG_REC(CURRENTSCALETHRESHOLDS,WORDS), | ||
4059 | DEBUG_REC(PROTOCOLRSPTIME,WORDS), | ||
4060 | DEBUG_REC(SHORTRETRYLIMIT,WORDS), | ||
4061 | DEBUG_REC(LONGRETRYLIMIT,WORDS), | ||
4062 | DEBUG_REC(MAXTRANSMITLIFETIME,WORDS), | ||
4063 | DEBUG_REC(MAXRECEIVELIFETIME,WORDS), | ||
4064 | DEBUG_REC(CFPOLLABLE,WORDS), | ||
4065 | DEBUG_REC(AUTHENTICATIONALGORITHMS,WORDS), | ||
4066 | DEBUG_REC(PRIVACYOPTIONIMPLEMENTED,WORDS), | ||
4067 | DEBUG_REC(OWNMACADDR,BYTES), | ||
4068 | DEBUG_REC(SCANRESULTSTABLE,WORDS), | ||
4069 | DEBUG_REC(PHYTYPE,WORDS), | ||
4070 | DEBUG_REC(CURRENTCHANNEL,WORDS), | ||
4071 | DEBUG_REC(CURRENTPOWERSTATE,WORDS), | ||
4072 | DEBUG_REC(CCAMODE,WORDS), | ||
4073 | DEBUG_REC(SUPPORTEDDATARATES,WORDS), | ||
4074 | DEBUG_REC(BUILDSEQ,BYTES), | ||
4075 | DEBUG_REC(FWID,XSTRING) | ||
4076 | #undef DEBUG_REC | ||
4077 | }; | ||
4078 | |||
4079 | #define DEBUG_LTV_SIZE 128 | ||
4080 | |||
4081 | static int orinoco_debug_dump_recs(struct net_device *dev) | ||
4082 | { | ||
4083 | struct orinoco_private *priv = netdev_priv(dev); | ||
4084 | hermes_t *hw = &priv->hw; | ||
4085 | u8 *val8; | ||
4086 | u16 *val16; | ||
4087 | int i,j; | ||
4088 | u16 length; | ||
4089 | int err; | ||
4090 | |||
4091 | /* I'm not sure: we might have a lock here, so we'd better go | ||
4092 | atomic, just in case. */ | ||
4093 | val8 = kmalloc(DEBUG_LTV_SIZE + 2, GFP_ATOMIC); | ||
4094 | if (! val8) | ||
4095 | return -ENOMEM; | ||
4096 | val16 = (u16 *)val8; | ||
4097 | |||
4098 | for (i = 0; i < ARRAY_SIZE(record_table); i++) { | ||
4099 | u16 rid = record_table[i].rid; | ||
4100 | int len; | ||
4101 | |||
4102 | memset(val8, 0, DEBUG_LTV_SIZE + 2); | ||
4103 | |||
4104 | err = hermes_read_ltv(hw, USER_BAP, rid, DEBUG_LTV_SIZE, | ||
4105 | &length, val8); | ||
4106 | if (err) { | ||
4107 | DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); | ||
4108 | continue; | ||
4109 | } | ||
4110 | val16 = (u16 *)val8; | ||
4111 | if (length == 0) | ||
4112 | continue; | ||
4113 | |||
4114 | printk(KERN_DEBUG "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", | ||
4115 | record_table[i].name, | ||
4116 | rid, length, (length-1)*2); | ||
4117 | len = min(((int)length-1)*2, DEBUG_LTV_SIZE); | ||
4118 | |||
4119 | switch (record_table[i].displaytype) { | ||
4120 | case DISPLAY_WORDS: | ||
4121 | for (j = 0; j < len / 2; j++) | ||
4122 | printk("%04X-", le16_to_cpu(val16[j])); | ||
4123 | break; | ||
4124 | |||
4125 | case DISPLAY_BYTES: | ||
4126 | default: | ||
4127 | for (j = 0; j < len; j++) | ||
4128 | printk("%02X:", val8[j]); | ||
4129 | break; | ||
4130 | |||
4131 | case DISPLAY_STRING: | ||
4132 | len = min(len, le16_to_cpu(val16[0])+2); | ||
4133 | val8[len] = '\0'; | ||
4134 | printk("\"%s\"", (char *)&val16[1]); | ||
4135 | break; | ||
4136 | |||
4137 | case DISPLAY_XSTRING: | ||
4138 | printk("'%s'", (char *)val8); | ||
4139 | } | ||
4140 | |||
4141 | printk("\n"); | ||
4142 | } | ||
4143 | |||
4144 | kfree(val8); | ||
4145 | |||
4146 | return 0; | ||
4147 | } | ||
4148 | |||
4149 | /********************************************************************/ | ||
4150 | /* Debugging */ | ||
4151 | /********************************************************************/ | ||
4152 | |||
4153 | #if 0 | ||
4154 | static void show_rx_frame(struct orinoco_rxframe_hdr *frame) | ||
4155 | { | ||
4156 | printk(KERN_DEBUG "RX descriptor:\n"); | ||
4157 | printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); | ||
4158 | printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); | ||
4159 | printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); | ||
4160 | printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); | ||
4161 | printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); | ||
4162 | printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); | ||
4163 | printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); | ||
4164 | |||
4165 | printk(KERN_DEBUG "IEEE 802.11 header:\n"); | ||
4166 | printk(KERN_DEBUG " frame_ctl = 0x%04x\n", | ||
4167 | frame->p80211.frame_ctl); | ||
4168 | printk(KERN_DEBUG " duration_id = 0x%04x\n", | ||
4169 | frame->p80211.duration_id); | ||
4170 | printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
4171 | frame->p80211.addr1[0], frame->p80211.addr1[1], | ||
4172 | frame->p80211.addr1[2], frame->p80211.addr1[3], | ||
4173 | frame->p80211.addr1[4], frame->p80211.addr1[5]); | ||
4174 | printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
4175 | frame->p80211.addr2[0], frame->p80211.addr2[1], | ||
4176 | frame->p80211.addr2[2], frame->p80211.addr2[3], | ||
4177 | frame->p80211.addr2[4], frame->p80211.addr2[5]); | ||
4178 | printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
4179 | frame->p80211.addr3[0], frame->p80211.addr3[1], | ||
4180 | frame->p80211.addr3[2], frame->p80211.addr3[3], | ||
4181 | frame->p80211.addr3[4], frame->p80211.addr3[5]); | ||
4182 | printk(KERN_DEBUG " seq_ctl = 0x%04x\n", | ||
4183 | frame->p80211.seq_ctl); | ||
4184 | printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
4185 | frame->p80211.addr4[0], frame->p80211.addr4[1], | ||
4186 | frame->p80211.addr4[2], frame->p80211.addr4[3], | ||
4187 | frame->p80211.addr4[4], frame->p80211.addr4[5]); | ||
4188 | printk(KERN_DEBUG " data_len = 0x%04x\n", | ||
4189 | frame->p80211.data_len); | ||
4190 | |||
4191 | printk(KERN_DEBUG "IEEE 802.3 header:\n"); | ||
4192 | printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
4193 | frame->p8023.h_dest[0], frame->p8023.h_dest[1], | ||
4194 | frame->p8023.h_dest[2], frame->p8023.h_dest[3], | ||
4195 | frame->p8023.h_dest[4], frame->p8023.h_dest[5]); | ||
4196 | printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
4197 | frame->p8023.h_source[0], frame->p8023.h_source[1], | ||
4198 | frame->p8023.h_source[2], frame->p8023.h_source[3], | ||
4199 | frame->p8023.h_source[4], frame->p8023.h_source[5]); | ||
4200 | printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); | ||
4201 | |||
4202 | printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); | ||
4203 | printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); | ||
4204 | printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); | ||
4205 | printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); | ||
4206 | printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", | ||
4207 | frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); | ||
4208 | printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); | ||
4209 | } | ||
4210 | #endif /* 0 */ | ||
4211 | |||
4212 | /********************************************************************/ | ||
4213 | /* Module initialization */ | ||
4214 | /********************************************************************/ | ||
4215 | |||
4216 | EXPORT_SYMBOL(alloc_orinocodev); | ||
4217 | EXPORT_SYMBOL(free_orinocodev); | ||
4218 | |||
4219 | EXPORT_SYMBOL(__orinoco_up); | ||
4220 | EXPORT_SYMBOL(__orinoco_down); | ||
4221 | EXPORT_SYMBOL(orinoco_stop); | ||
4222 | EXPORT_SYMBOL(orinoco_reinit_firmware); | ||
4223 | |||
4224 | EXPORT_SYMBOL(orinoco_interrupt); | ||
4225 | |||
4226 | /* Can't be declared "const" or the whole __initdata section will | ||
4227 | * become const */ | ||
4228 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
4229 | " (David Gibson <hermes@gibson.dropbear.id.au>, " | ||
4230 | "Pavel Roskin <proski@gnu.org>, et al)"; | ||
4231 | |||
4232 | static int __init init_orinoco(void) | ||
4233 | { | ||
4234 | printk(KERN_DEBUG "%s\n", version); | ||
4235 | return 0; | ||
4236 | } | ||
4237 | |||
4238 | static void __exit exit_orinoco(void) | ||
4239 | { | ||
4240 | } | ||
4241 | |||
4242 | module_init(init_orinoco); | ||
4243 | module_exit(exit_orinoco); | ||
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h new file mode 100644 index 000000000000..13e42c2afb27 --- /dev/null +++ b/drivers/net/wireless/orinoco.h | |||
@@ -0,0 +1,153 @@ | |||
1 | /* orinoco.h | ||
2 | * | ||
3 | * Common definitions to all pieces of the various orinoco | ||
4 | * drivers | ||
5 | */ | ||
6 | |||
7 | #ifndef _ORINOCO_H | ||
8 | #define _ORINOCO_H | ||
9 | |||
10 | #define DRIVER_VERSION "0.14alpha2" | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/netdevice.h> | ||
15 | #include <linux/wireless.h> | ||
16 | #include <linux/version.h> | ||
17 | |||
18 | #include "hermes.h" | ||
19 | |||
20 | /* To enable debug messages */ | ||
21 | //#define ORINOCO_DEBUG 3 | ||
22 | |||
23 | #define WIRELESS_SPY // enable iwspy support | ||
24 | |||
25 | #define ORINOCO_MAX_KEY_SIZE 14 | ||
26 | #define ORINOCO_MAX_KEYS 4 | ||
27 | |||
28 | struct orinoco_key { | ||
29 | u16 len; /* always stored as little-endian */ | ||
30 | char data[ORINOCO_MAX_KEY_SIZE]; | ||
31 | } __attribute__ ((packed)); | ||
32 | |||
33 | typedef enum { | ||
34 | FIRMWARE_TYPE_AGERE, | ||
35 | FIRMWARE_TYPE_INTERSIL, | ||
36 | FIRMWARE_TYPE_SYMBOL | ||
37 | } fwtype_t; | ||
38 | |||
39 | struct orinoco_private { | ||
40 | void *card; /* Pointer to card dependent structure */ | ||
41 | int (*hard_reset)(struct orinoco_private *); | ||
42 | |||
43 | /* Synchronisation stuff */ | ||
44 | spinlock_t lock; | ||
45 | int hw_unavailable; | ||
46 | struct work_struct reset_work; | ||
47 | |||
48 | /* driver state */ | ||
49 | int open; | ||
50 | u16 last_linkstatus; | ||
51 | |||
52 | /* Net device stuff */ | ||
53 | struct net_device *ndev; | ||
54 | struct net_device_stats stats; | ||
55 | struct iw_statistics wstats; | ||
56 | |||
57 | /* Hardware control variables */ | ||
58 | hermes_t hw; | ||
59 | u16 txfid; | ||
60 | |||
61 | /* Capabilities of the hardware/firmware */ | ||
62 | fwtype_t firmware_type; | ||
63 | char fw_name[32]; | ||
64 | int ibss_port; | ||
65 | int nicbuf_size; | ||
66 | u16 channel_mask; | ||
67 | |||
68 | /* Boolean capabilities */ | ||
69 | unsigned int has_ibss:1; | ||
70 | unsigned int has_port3:1; | ||
71 | unsigned int has_wep:1; | ||
72 | unsigned int has_big_wep:1; | ||
73 | unsigned int has_mwo:1; | ||
74 | unsigned int has_pm:1; | ||
75 | unsigned int has_preamble:1; | ||
76 | unsigned int has_sensitivity:1; | ||
77 | unsigned int broken_disableport:1; | ||
78 | |||
79 | /* Configuration paramaters */ | ||
80 | u32 iw_mode; | ||
81 | int prefer_port3; | ||
82 | u16 wep_on, wep_restrict, tx_key; | ||
83 | struct orinoco_key keys[ORINOCO_MAX_KEYS]; | ||
84 | int bitratemode; | ||
85 | char nick[IW_ESSID_MAX_SIZE+1]; | ||
86 | char desired_essid[IW_ESSID_MAX_SIZE+1]; | ||
87 | u16 frag_thresh, mwo_robust; | ||
88 | u16 channel; | ||
89 | u16 ap_density, rts_thresh; | ||
90 | u16 pm_on, pm_mcast, pm_period, pm_timeout; | ||
91 | u16 preamble; | ||
92 | #ifdef WIRELESS_SPY | ||
93 | int spy_number; | ||
94 | u_char spy_address[IW_MAX_SPY][ETH_ALEN]; | ||
95 | struct iw_quality spy_stat[IW_MAX_SPY]; | ||
96 | #endif | ||
97 | |||
98 | /* Configuration dependent variables */ | ||
99 | int port_type, createibss; | ||
100 | int promiscuous, mc_count; | ||
101 | }; | ||
102 | |||
103 | #ifdef ORINOCO_DEBUG | ||
104 | extern int orinoco_debug; | ||
105 | #define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0) | ||
106 | #else | ||
107 | #define DEBUG(n, args...) do { } while (0) | ||
108 | #endif /* ORINOCO_DEBUG */ | ||
109 | |||
110 | #define TRACE_ENTER(devname) DEBUG(2, "%s: -> %s()\n", devname, __FUNCTION__); | ||
111 | #define TRACE_EXIT(devname) DEBUG(2, "%s: <- %s()\n", devname, __FUNCTION__); | ||
112 | |||
113 | /********************************************************************/ | ||
114 | /* Exported prototypes */ | ||
115 | /********************************************************************/ | ||
116 | |||
117 | extern struct net_device *alloc_orinocodev(int sizeof_card, | ||
118 | int (*hard_reset)(struct orinoco_private *)); | ||
119 | extern void free_orinocodev(struct net_device *dev); | ||
120 | extern int __orinoco_up(struct net_device *dev); | ||
121 | extern int __orinoco_down(struct net_device *dev); | ||
122 | extern int orinoco_stop(struct net_device *dev); | ||
123 | extern int orinoco_reinit_firmware(struct net_device *dev); | ||
124 | extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); | ||
125 | |||
126 | /********************************************************************/ | ||
127 | /* Locking and synchronization functions */ | ||
128 | /********************************************************************/ | ||
129 | |||
130 | /* These functions *must* be inline or they will break horribly on | ||
131 | * SPARC, due to its weird semantics for save/restore flags. extern | ||
132 | * inline should prevent the kernel from linking or module from | ||
133 | * loading if they are not inlined. */ | ||
134 | extern inline int orinoco_lock(struct orinoco_private *priv, | ||
135 | unsigned long *flags) | ||
136 | { | ||
137 | spin_lock_irqsave(&priv->lock, *flags); | ||
138 | if (priv->hw_unavailable) { | ||
139 | DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", | ||
140 | priv->ndev); | ||
141 | spin_unlock_irqrestore(&priv->lock, *flags); | ||
142 | return -EBUSY; | ||
143 | } | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | extern inline void orinoco_unlock(struct orinoco_private *priv, | ||
148 | unsigned long *flags) | ||
149 | { | ||
150 | spin_unlock_irqrestore(&priv->lock, *flags); | ||
151 | } | ||
152 | |||
153 | #endif /* _ORINOCO_H */ | ||
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c new file mode 100644 index 000000000000..74a8227256aa --- /dev/null +++ b/drivers/net/wireless/orinoco_cs.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* orinoco_cs.c (formerly known as dldwd_cs.c) | ||
2 | * | ||
3 | * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such | ||
4 | * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ | ||
5 | * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). | ||
6 | * It should also be usable on various Prism II based cards such as the | ||
7 | * Linksys, D-Link and Farallon Skyline. It should also work on Symbol | ||
8 | * cards such as the 3Com AirConnect and Ericsson WLAN. | ||
9 | * | ||
10 | * Copyright notice & release notes in file orinoco.c | ||
11 | */ | ||
12 | |||
13 | #define DRIVER_NAME "orinoco_cs" | ||
14 | #define PFX DRIVER_NAME ": " | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #ifdef __IN_PCMCIA_PACKAGE__ | ||
18 | #include <pcmcia/k_compat.h> | ||
19 | #endif /* __IN_PCMCIA_PACKAGE__ */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/ptrace.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/if_arp.h> | ||
31 | #include <linux/etherdevice.h> | ||
32 | #include <linux/wireless.h> | ||
33 | |||
34 | #include <pcmcia/version.h> | ||
35 | #include <pcmcia/cs_types.h> | ||
36 | #include <pcmcia/cs.h> | ||
37 | #include <pcmcia/cistpl.h> | ||
38 | #include <pcmcia/cisreg.h> | ||
39 | #include <pcmcia/ds.h> | ||
40 | |||
41 | #include <asm/uaccess.h> | ||
42 | #include <asm/io.h> | ||
43 | #include <asm/system.h> | ||
44 | |||
45 | #include "orinoco.h" | ||
46 | |||
47 | /********************************************************************/ | ||
48 | /* Module stuff */ | ||
49 | /********************************************************************/ | ||
50 | |||
51 | MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); | ||
52 | MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); | ||
53 | MODULE_LICENSE("Dual MPL/GPL"); | ||
54 | |||
55 | /* Module parameters */ | ||
56 | |||
57 | /* Some D-Link cards have buggy CIS. They do work at 5v properly, but | ||
58 | * don't have any CIS entry for it. This workaround it... */ | ||
59 | static int ignore_cis_vcc; /* = 0 */ | ||
60 | module_param(ignore_cis_vcc, int, 0); | ||
61 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); | ||
62 | |||
63 | /********************************************************************/ | ||
64 | /* Magic constants */ | ||
65 | /********************************************************************/ | ||
66 | |||
67 | /* | ||
68 | * The dev_info variable is the "key" that is used to match up this | ||
69 | * device driver with appropriate cards, through the card | ||
70 | * configuration database. | ||
71 | */ | ||
72 | static dev_info_t dev_info = DRIVER_NAME; | ||
73 | |||
74 | /********************************************************************/ | ||
75 | /* Data structures */ | ||
76 | /********************************************************************/ | ||
77 | |||
78 | /* PCMCIA specific device information (goes in the card field of | ||
79 | * struct orinoco_private */ | ||
80 | struct orinoco_pccard { | ||
81 | dev_link_t link; | ||
82 | dev_node_t node; | ||
83 | |||
84 | /* Used to handle hard reset */ | ||
85 | /* yuck, we need this hack to work around the insanity of the | ||
86 | * PCMCIA layer */ | ||
87 | unsigned long hard_reset_in_progress; | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * A linked list of "instances" of the device. Each actual PCMCIA | ||
92 | * card corresponds to one device instance, and is described by one | ||
93 | * dev_link_t structure (defined in ds.h). | ||
94 | */ | ||
95 | static dev_link_t *dev_list; /* = NULL */ | ||
96 | |||
97 | /********************************************************************/ | ||
98 | /* Function prototypes */ | ||
99 | /********************************************************************/ | ||
100 | |||
101 | /* device methods */ | ||
102 | static int orinoco_cs_hard_reset(struct orinoco_private *priv); | ||
103 | |||
104 | /* PCMCIA gumpf */ | ||
105 | static void orinoco_cs_config(dev_link_t * link); | ||
106 | static void orinoco_cs_release(dev_link_t * link); | ||
107 | static int orinoco_cs_event(event_t event, int priority, | ||
108 | event_callback_args_t * args); | ||
109 | |||
110 | static dev_link_t *orinoco_cs_attach(void); | ||
111 | static void orinoco_cs_detach(dev_link_t *); | ||
112 | |||
113 | /********************************************************************/ | ||
114 | /* Device methods */ | ||
115 | /********************************************************************/ | ||
116 | |||
117 | static int | ||
118 | orinoco_cs_hard_reset(struct orinoco_private *priv) | ||
119 | { | ||
120 | struct orinoco_pccard *card = priv->card; | ||
121 | dev_link_t *link = &card->link; | ||
122 | int err; | ||
123 | |||
124 | /* We need atomic ops here, because we're not holding the lock */ | ||
125 | set_bit(0, &card->hard_reset_in_progress); | ||
126 | |||
127 | err = pcmcia_reset_card(link->handle, NULL); | ||
128 | if (err) | ||
129 | return err; | ||
130 | |||
131 | msleep(100); | ||
132 | clear_bit(0, &card->hard_reset_in_progress); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /********************************************************************/ | ||
138 | /* PCMCIA stuff */ | ||
139 | /********************************************************************/ | ||
140 | |||
141 | /* | ||
142 | * This creates an "instance" of the driver, allocating local data | ||
143 | * structures for one device. The device is registered with Card | ||
144 | * Services. | ||
145 | * | ||
146 | * The dev_link structure is initialized, but we don't actually | ||
147 | * configure the card at this point -- we wait until we receive a card | ||
148 | * insertion event. */ | ||
149 | static dev_link_t * | ||
150 | orinoco_cs_attach(void) | ||
151 | { | ||
152 | struct net_device *dev; | ||
153 | struct orinoco_private *priv; | ||
154 | struct orinoco_pccard *card; | ||
155 | dev_link_t *link; | ||
156 | client_reg_t client_reg; | ||
157 | int ret; | ||
158 | |||
159 | dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); | ||
160 | if (! dev) | ||
161 | return NULL; | ||
162 | priv = netdev_priv(dev); | ||
163 | card = priv->card; | ||
164 | |||
165 | /* Link both structures together */ | ||
166 | link = &card->link; | ||
167 | link->priv = dev; | ||
168 | |||
169 | /* Interrupt setup */ | ||
170 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
171 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
172 | link->irq.Handler = orinoco_interrupt; | ||
173 | link->irq.Instance = dev; | ||
174 | |||
175 | /* General socket configuration defaults can go here. In this | ||
176 | * client, we assume very little, and rely on the CIS for | ||
177 | * almost everything. In most clients, many details (i.e., | ||
178 | * number, sizes, and attributes of IO windows) are fixed by | ||
179 | * the nature of the device, and can be hard-wired here. */ | ||
180 | link->conf.Attributes = 0; | ||
181 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
182 | |||
183 | /* Register with Card Services */ | ||
184 | /* FIXME: need a lock? */ | ||
185 | link->next = dev_list; | ||
186 | dev_list = link; | ||
187 | |||
188 | client_reg.dev_info = &dev_info; | ||
189 | client_reg.EventMask = | ||
190 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
191 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
192 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
193 | client_reg.event_handler = &orinoco_cs_event; | ||
194 | client_reg.Version = 0x0210; /* FIXME: what does this mean? */ | ||
195 | client_reg.event_callback_args.client_data = link; | ||
196 | |||
197 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
198 | if (ret != CS_SUCCESS) { | ||
199 | cs_error(link->handle, RegisterClient, ret); | ||
200 | orinoco_cs_detach(link); | ||
201 | return NULL; | ||
202 | } | ||
203 | |||
204 | return link; | ||
205 | } /* orinoco_cs_attach */ | ||
206 | |||
207 | /* | ||
208 | * This deletes a driver "instance". The device is de-registered with | ||
209 | * Card Services. If it has been released, all local data structures | ||
210 | * are freed. Otherwise, the structures will be freed when the device | ||
211 | * is released. | ||
212 | */ | ||
213 | static void orinoco_cs_detach(dev_link_t *link) | ||
214 | { | ||
215 | dev_link_t **linkp; | ||
216 | struct net_device *dev = link->priv; | ||
217 | |||
218 | /* Locate device structure */ | ||
219 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
220 | if (*linkp == link) | ||
221 | break; | ||
222 | |||
223 | BUG_ON(*linkp == NULL); | ||
224 | |||
225 | if (link->state & DEV_CONFIG) | ||
226 | orinoco_cs_release(link); | ||
227 | |||
228 | /* Break the link with Card Services */ | ||
229 | if (link->handle) | ||
230 | pcmcia_deregister_client(link->handle); | ||
231 | |||
232 | /* Unlink device structure, and free it */ | ||
233 | *linkp = link->next; | ||
234 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); | ||
235 | if (link->dev) { | ||
236 | DEBUG(0, PFX "About to unregister net device %p\n", | ||
237 | dev); | ||
238 | unregister_netdev(dev); | ||
239 | } | ||
240 | free_orinocodev(dev); | ||
241 | } /* orinoco_cs_detach */ | ||
242 | |||
243 | /* | ||
244 | * orinoco_cs_config() is scheduled to run after a CARD_INSERTION | ||
245 | * event is received, to configure the PCMCIA socket, and to make the | ||
246 | * device available to the system. | ||
247 | */ | ||
248 | |||
249 | #define CS_CHECK(fn, ret) do { \ | ||
250 | last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ | ||
251 | } while (0) | ||
252 | |||
253 | static void | ||
254 | orinoco_cs_config(dev_link_t *link) | ||
255 | { | ||
256 | struct net_device *dev = link->priv; | ||
257 | client_handle_t handle = link->handle; | ||
258 | struct orinoco_private *priv = netdev_priv(dev); | ||
259 | struct orinoco_pccard *card = priv->card; | ||
260 | hermes_t *hw = &priv->hw; | ||
261 | int last_fn, last_ret; | ||
262 | u_char buf[64]; | ||
263 | config_info_t conf; | ||
264 | cisinfo_t info; | ||
265 | tuple_t tuple; | ||
266 | cisparse_t parse; | ||
267 | void __iomem *mem; | ||
268 | |||
269 | CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info)); | ||
270 | |||
271 | /* | ||
272 | * This reads the card's CONFIG tuple to find its | ||
273 | * configuration registers. | ||
274 | */ | ||
275 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
276 | tuple.Attributes = 0; | ||
277 | tuple.TupleData = buf; | ||
278 | tuple.TupleDataMax = sizeof(buf); | ||
279 | tuple.TupleOffset = 0; | ||
280 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
281 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
282 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
283 | link->conf.ConfigBase = parse.config.base; | ||
284 | link->conf.Present = parse.config.rmask[0]; | ||
285 | |||
286 | /* Configure card */ | ||
287 | link->state |= DEV_CONFIG; | ||
288 | |||
289 | /* Look up the current Vcc */ | ||
290 | CS_CHECK(GetConfigurationInfo, | ||
291 | pcmcia_get_configuration_info(handle, &conf)); | ||
292 | link->conf.Vcc = conf.Vcc; | ||
293 | |||
294 | /* | ||
295 | * In this loop, we scan the CIS for configuration table | ||
296 | * entries, each of which describes a valid card | ||
297 | * configuration, including voltage, IO window, memory window, | ||
298 | * and interrupt settings. | ||
299 | * | ||
300 | * We make no assumptions about the card to be configured: we | ||
301 | * use just the information available in the CIS. In an ideal | ||
302 | * world, this would work for any PCMCIA card, but it requires | ||
303 | * a complete and accurate CIS. In practice, a driver usually | ||
304 | * "knows" most of these things without consulting the CIS, | ||
305 | * and most client drivers will only use the CIS to fill in | ||
306 | * implementation-defined details. | ||
307 | */ | ||
308 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
309 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
310 | while (1) { | ||
311 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
312 | cistpl_cftable_entry_t dflt = { .index = 0 }; | ||
313 | |||
314 | if ( (pcmcia_get_tuple_data(handle, &tuple) != 0) | ||
315 | || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0)) | ||
316 | goto next_entry; | ||
317 | |||
318 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
319 | dflt = *cfg; | ||
320 | if (cfg->index == 0) | ||
321 | goto next_entry; | ||
322 | link->conf.ConfigIndex = cfg->index; | ||
323 | |||
324 | /* Does this card need audio output? */ | ||
325 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
326 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
327 | link->conf.Status = CCSR_AUDIO_ENA; | ||
328 | } | ||
329 | |||
330 | /* Use power settings for Vcc and Vpp if present */ | ||
331 | /* Note that the CIS values need to be rescaled */ | ||
332 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
333 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
334 | DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); | ||
335 | if (!ignore_cis_vcc) | ||
336 | goto next_entry; | ||
337 | } | ||
338 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
339 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
340 | DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); | ||
341 | if(!ignore_cis_vcc) | ||
342 | goto next_entry; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
347 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
348 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
349 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
350 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
351 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
352 | |||
353 | /* Do we need to allocate an interrupt? */ | ||
354 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
355 | |||
356 | /* IO window settings */ | ||
357 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
358 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
359 | cistpl_io_t *io = | ||
360 | (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
361 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
362 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
363 | link->io.Attributes1 = | ||
364 | IO_DATA_PATH_WIDTH_16; | ||
365 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
366 | link->io.Attributes1 = | ||
367 | IO_DATA_PATH_WIDTH_8; | ||
368 | link->io.IOAddrLines = | ||
369 | io->flags & CISTPL_IO_LINES_MASK; | ||
370 | link->io.BasePort1 = io->win[0].base; | ||
371 | link->io.NumPorts1 = io->win[0].len; | ||
372 | if (io->nwin > 1) { | ||
373 | link->io.Attributes2 = | ||
374 | link->io.Attributes1; | ||
375 | link->io.BasePort2 = io->win[1].base; | ||
376 | link->io.NumPorts2 = io->win[1].len; | ||
377 | } | ||
378 | |||
379 | /* This reserves IO space but doesn't actually enable it */ | ||
380 | if (pcmcia_request_io(link->handle, &link->io) != 0) | ||
381 | goto next_entry; | ||
382 | } | ||
383 | |||
384 | |||
385 | /* If we got this far, we're cool! */ | ||
386 | |||
387 | break; | ||
388 | |||
389 | next_entry: | ||
390 | if (link->io.NumPorts1) | ||
391 | pcmcia_release_io(link->handle, &link->io); | ||
392 | last_ret = pcmcia_get_next_tuple(handle, &tuple); | ||
393 | if (last_ret == CS_NO_MORE_ITEMS) { | ||
394 | printk(KERN_ERR PFX "GetNextTuple(): No matching " | ||
395 | "CIS configuration. Maybe you need the " | ||
396 | "ignore_cis_vcc=1 parameter.\n"); | ||
397 | goto cs_failed; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Allocate an interrupt line. Note that this does not assign | ||
403 | * a handler to the interrupt, unless the 'Handler' member of | ||
404 | * the irq structure is initialized. | ||
405 | */ | ||
406 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
407 | |||
408 | /* We initialize the hermes structure before completing PCMCIA | ||
409 | * configuration just in case the interrupt handler gets | ||
410 | * called. */ | ||
411 | mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); | ||
412 | if (!mem) | ||
413 | goto cs_failed; | ||
414 | |||
415 | hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); | ||
416 | |||
417 | /* | ||
418 | * This actually configures the PCMCIA socket -- setting up | ||
419 | * the I/O windows and the interrupt mapping, and putting the | ||
420 | * card and host interface into "Memory and IO" mode. | ||
421 | */ | ||
422 | CS_CHECK(RequestConfiguration, | ||
423 | pcmcia_request_configuration(link->handle, &link->conf)); | ||
424 | |||
425 | /* Ok, we have the configuration, prepare to register the netdev */ | ||
426 | dev->base_addr = link->io.BasePort1; | ||
427 | dev->irq = link->irq.AssignedIRQ; | ||
428 | SET_MODULE_OWNER(dev); | ||
429 | card->node.major = card->node.minor = 0; | ||
430 | |||
431 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
432 | /* Tell the stack we exist */ | ||
433 | if (register_netdev(dev) != 0) { | ||
434 | printk(KERN_ERR PFX "register_netdev() failed\n"); | ||
435 | goto failed; | ||
436 | } | ||
437 | |||
438 | /* At this point, the dev_node_t structure(s) needs to be | ||
439 | * initialized and arranged in a linked list at link->dev. */ | ||
440 | strcpy(card->node.dev_name, dev->name); | ||
441 | link->dev = &card->node; /* link->dev being non-NULL is also | ||
442 | used to indicate that the | ||
443 | net_device has been registered */ | ||
444 | link->state &= ~DEV_CONFIG_PENDING; | ||
445 | |||
446 | /* Finally, report what we've done */ | ||
447 | printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d", | ||
448 | dev->name, link->conf.ConfigIndex, | ||
449 | link->conf.Vcc / 10, link->conf.Vcc % 10); | ||
450 | if (link->conf.Vpp1) | ||
451 | printk(", Vpp %d.%d", link->conf.Vpp1 / 10, | ||
452 | link->conf.Vpp1 % 10); | ||
453 | printk(", irq %d", link->irq.AssignedIRQ); | ||
454 | if (link->io.NumPorts1) | ||
455 | printk(", io 0x%04x-0x%04x", link->io.BasePort1, | ||
456 | link->io.BasePort1 + link->io.NumPorts1 - 1); | ||
457 | if (link->io.NumPorts2) | ||
458 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | ||
459 | link->io.BasePort2 + link->io.NumPorts2 - 1); | ||
460 | printk("\n"); | ||
461 | |||
462 | return; | ||
463 | |||
464 | cs_failed: | ||
465 | cs_error(link->handle, last_fn, last_ret); | ||
466 | |||
467 | failed: | ||
468 | orinoco_cs_release(link); | ||
469 | } /* orinoco_cs_config */ | ||
470 | |||
471 | /* | ||
472 | * After a card is removed, orinoco_cs_release() will unregister the | ||
473 | * device, and release the PCMCIA configuration. If the device is | ||
474 | * still open, this will be postponed until it is closed. | ||
475 | */ | ||
476 | static void | ||
477 | orinoco_cs_release(dev_link_t *link) | ||
478 | { | ||
479 | struct net_device *dev = link->priv; | ||
480 | struct orinoco_private *priv = netdev_priv(dev); | ||
481 | unsigned long flags; | ||
482 | |||
483 | /* We're committed to taking the device away now, so mark the | ||
484 | * hardware as unavailable */ | ||
485 | spin_lock_irqsave(&priv->lock, flags); | ||
486 | priv->hw_unavailable++; | ||
487 | spin_unlock_irqrestore(&priv->lock, flags); | ||
488 | |||
489 | /* Don't bother checking to see if these succeed or not */ | ||
490 | pcmcia_release_configuration(link->handle); | ||
491 | if (link->io.NumPorts1) | ||
492 | pcmcia_release_io(link->handle, &link->io); | ||
493 | if (link->irq.AssignedIRQ) | ||
494 | pcmcia_release_irq(link->handle, &link->irq); | ||
495 | link->state &= ~DEV_CONFIG; | ||
496 | if (priv->hw.iobase) | ||
497 | ioport_unmap(priv->hw.iobase); | ||
498 | } /* orinoco_cs_release */ | ||
499 | |||
500 | /* | ||
501 | * The card status event handler. Mostly, this schedules other stuff | ||
502 | * to run after an event is received. | ||
503 | */ | ||
504 | static int | ||
505 | orinoco_cs_event(event_t event, int priority, | ||
506 | event_callback_args_t * args) | ||
507 | { | ||
508 | dev_link_t *link = args->client_data; | ||
509 | struct net_device *dev = link->priv; | ||
510 | struct orinoco_private *priv = netdev_priv(dev); | ||
511 | struct orinoco_pccard *card = priv->card; | ||
512 | int err = 0; | ||
513 | unsigned long flags; | ||
514 | |||
515 | switch (event) { | ||
516 | case CS_EVENT_CARD_REMOVAL: | ||
517 | link->state &= ~DEV_PRESENT; | ||
518 | if (link->state & DEV_CONFIG) { | ||
519 | unsigned long flags; | ||
520 | |||
521 | spin_lock_irqsave(&priv->lock, flags); | ||
522 | netif_device_detach(dev); | ||
523 | priv->hw_unavailable++; | ||
524 | spin_unlock_irqrestore(&priv->lock, flags); | ||
525 | } | ||
526 | break; | ||
527 | |||
528 | case CS_EVENT_CARD_INSERTION: | ||
529 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
530 | orinoco_cs_config(link); | ||
531 | break; | ||
532 | |||
533 | case CS_EVENT_PM_SUSPEND: | ||
534 | link->state |= DEV_SUSPEND; | ||
535 | /* Fall through... */ | ||
536 | case CS_EVENT_RESET_PHYSICAL: | ||
537 | /* Mark the device as stopped, to block IO until later */ | ||
538 | if (link->state & DEV_CONFIG) { | ||
539 | /* This is probably racy, but I can't think of | ||
540 | a better way, short of rewriting the PCMCIA | ||
541 | layer to not suck :-( */ | ||
542 | if (! test_bit(0, &card->hard_reset_in_progress)) { | ||
543 | spin_lock_irqsave(&priv->lock, flags); | ||
544 | |||
545 | err = __orinoco_down(dev); | ||
546 | if (err) | ||
547 | printk(KERN_WARNING "%s: %s: Error %d downing interface\n", | ||
548 | dev->name, | ||
549 | event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", | ||
550 | err); | ||
551 | |||
552 | netif_device_detach(dev); | ||
553 | priv->hw_unavailable++; | ||
554 | |||
555 | spin_unlock_irqrestore(&priv->lock, flags); | ||
556 | } | ||
557 | |||
558 | pcmcia_release_configuration(link->handle); | ||
559 | } | ||
560 | break; | ||
561 | |||
562 | case CS_EVENT_PM_RESUME: | ||
563 | link->state &= ~DEV_SUSPEND; | ||
564 | /* Fall through... */ | ||
565 | case CS_EVENT_CARD_RESET: | ||
566 | if (link->state & DEV_CONFIG) { | ||
567 | /* FIXME: should we double check that this is | ||
568 | * the same card as we had before */ | ||
569 | pcmcia_request_configuration(link->handle, &link->conf); | ||
570 | |||
571 | if (! test_bit(0, &card->hard_reset_in_progress)) { | ||
572 | err = orinoco_reinit_firmware(dev); | ||
573 | if (err) { | ||
574 | printk(KERN_ERR "%s: Error %d re-initializing firmware\n", | ||
575 | dev->name, err); | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | spin_lock_irqsave(&priv->lock, flags); | ||
580 | |||
581 | netif_device_attach(dev); | ||
582 | priv->hw_unavailable--; | ||
583 | |||
584 | if (priv->open && ! priv->hw_unavailable) { | ||
585 | err = __orinoco_up(dev); | ||
586 | if (err) | ||
587 | printk(KERN_ERR "%s: Error %d restarting card\n", | ||
588 | dev->name, err); | ||
589 | |||
590 | } | ||
591 | |||
592 | spin_unlock_irqrestore(&priv->lock, flags); | ||
593 | } | ||
594 | } | ||
595 | break; | ||
596 | } | ||
597 | |||
598 | return err; | ||
599 | } /* orinoco_cs_event */ | ||
600 | |||
601 | /********************************************************************/ | ||
602 | /* Module initialization */ | ||
603 | /********************************************************************/ | ||
604 | |||
605 | /* Can't be declared "const" or the whole __initdata section will | ||
606 | * become const */ | ||
607 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
608 | " (David Gibson <hermes@gibson.dropbear.id.au>, " | ||
609 | "Pavel Roskin <proski@gnu.org>, et al)"; | ||
610 | |||
611 | static struct pcmcia_driver orinoco_driver = { | ||
612 | .owner = THIS_MODULE, | ||
613 | .drv = { | ||
614 | .name = DRIVER_NAME, | ||
615 | }, | ||
616 | .attach = orinoco_cs_attach, | ||
617 | .detach = orinoco_cs_detach, | ||
618 | }; | ||
619 | |||
620 | static int __init | ||
621 | init_orinoco_cs(void) | ||
622 | { | ||
623 | printk(KERN_DEBUG "%s\n", version); | ||
624 | |||
625 | return pcmcia_register_driver(&orinoco_driver); | ||
626 | } | ||
627 | |||
628 | static void __exit | ||
629 | exit_orinoco_cs(void) | ||
630 | { | ||
631 | pcmcia_unregister_driver(&orinoco_driver); | ||
632 | BUG_ON(dev_list != NULL); | ||
633 | } | ||
634 | |||
635 | module_init(init_orinoco_cs); | ||
636 | module_exit(exit_orinoco_cs); | ||
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c new file mode 100644 index 000000000000..ff30d37e12e2 --- /dev/null +++ b/drivers/net/wireless/orinoco_pci.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* orinoco_pci.c | ||
2 | * | ||
3 | * Driver for Prism II devices that have a direct PCI interface | ||
4 | * (i.e., not in a Pcmcia or PLX bridge) | ||
5 | * | ||
6 | * Specifically here we're talking about the Linksys WMP11 | ||
7 | * | ||
8 | * Current maintainers (as of 29 September 2003) are: | ||
9 | * Pavel Roskin <proski AT gnu.org> | ||
10 | * and David Gibson <hermes AT gibson.dropbear.id.au> | ||
11 | * | ||
12 | * Some of this code is borrowed from orinoco_plx.c | ||
13 | * Copyright (C) 2001 Daniel Barlow <dan AT telent.net> | ||
14 | * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing | ||
15 | * has been copied from it. linux-wlan-ng-0.1.10 is originally : | ||
16 | * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. | ||
17 | * This file originally written by: | ||
18 | * Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com> | ||
19 | * And is now maintained by: | ||
20 | * (C) Copyright David Gibson, IBM Corp. 2002-2003. | ||
21 | * | ||
22 | * The contents of this file are subject to the Mozilla Public License | ||
23 | * Version 1.1 (the "License"); you may not use this file except in | ||
24 | * compliance with the License. You may obtain a copy of the License | ||
25 | * at http://www.mozilla.org/MPL/ | ||
26 | * | ||
27 | * Software distributed under the License is distributed on an "AS IS" | ||
28 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
29 | * the License for the specific language governing rights and | ||
30 | * limitations under the License. | ||
31 | * | ||
32 | * Alternatively, the contents of this file may be used under the | ||
33 | * terms of the GNU General Public License version 2 (the "GPL"), in | ||
34 | * which case the provisions of the GPL are applicable instead of the | ||
35 | * above. If you wish to allow the use of your version of this file | ||
36 | * only under the terms of the GPL and not to allow others to use your | ||
37 | * version of this file under the MPL, indicate your decision by | ||
38 | * deleting the provisions above and replace them with the notice and | ||
39 | * other provisions required by the GPL. If you do not delete the | ||
40 | * provisions above, a recipient may use your version of this file | ||
41 | * under either the MPL or the GPL. | ||
42 | */ | ||
43 | |||
44 | /* | ||
45 | * Theory of operation... | ||
46 | * ------------------- | ||
47 | * Maybe you had a look in orinoco_plx. Well, this is totally different... | ||
48 | * | ||
49 | * The card contains only one PCI region, which contains all the usual | ||
50 | * hermes registers. | ||
51 | * | ||
52 | * The driver will memory map this region in normal memory. Because | ||
53 | * the hermes registers are mapped in normal memory and not in ISA I/O | ||
54 | * post space, we can't use the usual inw/outw macros and we need to | ||
55 | * use readw/writew. | ||
56 | * This slight difference force us to compile our own version of | ||
57 | * hermes.c with the register access macro changed. That's a bit | ||
58 | * hackish but works fine. | ||
59 | * | ||
60 | * Note that the PCI region is pretty big (4K). That's much more than | ||
61 | * the usual set of hermes register (0x0 -> 0x3E). I've got a strong | ||
62 | * suspicion that the whole memory space of the adapter is in fact in | ||
63 | * this region. Accessing directly the adapter memory instead of going | ||
64 | * through the usual register would speed up significantely the | ||
65 | * operations... | ||
66 | * | ||
67 | * Finally, the card looks like this : | ||
68 | ----------------------- | ||
69 | Bus 0, device 14, function 0: | ||
70 | Network controller: PCI device 1260:3873 (Harris Semiconductor) (rev 1). | ||
71 | IRQ 11. | ||
72 | Master Capable. Latency=248. | ||
73 | Prefetchable 32 bit memory at 0xffbcc000 [0xffbccfff]. | ||
74 | ----------------------- | ||
75 | 00:0e.0 Network controller: Harris Semiconductor: Unknown device 3873 (rev 01) | ||
76 | Subsystem: Unknown device 1737:3874 | ||
77 | Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- | ||
78 | Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- | ||
79 | Latency: 248 set, cache line size 08 | ||
80 | Interrupt: pin A routed to IRQ 11 | ||
81 | Region 0: Memory at ffbcc000 (32-bit, prefetchable) [size=4K] | ||
82 | Capabilities: [dc] Power Management version 2 | ||
83 | Flags: PMEClk- AuxPwr- DSI- D1+ D2+ PME+ | ||
84 | Status: D0 PME-Enable- DSel=0 DScale=0 PME- | ||
85 | ----------------------- | ||
86 | * | ||
87 | * That's all.. | ||
88 | * | ||
89 | * Jean II | ||
90 | */ | ||
91 | |||
92 | #define DRIVER_NAME "orinoco_pci" | ||
93 | #define PFX DRIVER_NAME ": " | ||
94 | |||
95 | #include <linux/config.h> | ||
96 | |||
97 | #include <linux/module.h> | ||
98 | #include <linux/kernel.h> | ||
99 | #include <linux/init.h> | ||
100 | #include <linux/sched.h> | ||
101 | #include <linux/ptrace.h> | ||
102 | #include <linux/slab.h> | ||
103 | #include <linux/string.h> | ||
104 | #include <linux/timer.h> | ||
105 | #include <linux/ioport.h> | ||
106 | #include <linux/netdevice.h> | ||
107 | #include <linux/if_arp.h> | ||
108 | #include <linux/etherdevice.h> | ||
109 | #include <linux/list.h> | ||
110 | #include <linux/pci.h> | ||
111 | #include <linux/fcntl.h> | ||
112 | |||
113 | #include <asm/uaccess.h> | ||
114 | #include <asm/io.h> | ||
115 | #include <asm/system.h> | ||
116 | |||
117 | #include "hermes.h" | ||
118 | #include "orinoco.h" | ||
119 | |||
120 | /* All the magic there is from wlan-ng */ | ||
121 | /* Magic offset of the reset register of the PCI card */ | ||
122 | #define HERMES_PCI_COR (0x26) | ||
123 | /* Magic bitmask to reset the card */ | ||
124 | #define HERMES_PCI_COR_MASK (0x0080) | ||
125 | /* Magic timeouts for doing the reset. | ||
126 | * Those times are straight from wlan-ng, and it is claimed that they | ||
127 | * are necessary. Alan will kill me. Take your time and grab a coffee. */ | ||
128 | #define HERMES_PCI_COR_ONT (250) /* ms */ | ||
129 | #define HERMES_PCI_COR_OFFT (500) /* ms */ | ||
130 | #define HERMES_PCI_COR_BUSYT (500) /* ms */ | ||
131 | |||
132 | /* Orinoco PCI specific data */ | ||
133 | struct orinoco_pci_card { | ||
134 | void __iomem *pci_ioaddr; | ||
135 | }; | ||
136 | |||
137 | /* | ||
138 | * Do a soft reset of the PCI card using the Configuration Option Register | ||
139 | * We need this to get going... | ||
140 | * This is the part of the code that is strongly inspired from wlan-ng | ||
141 | * | ||
142 | * Note : This code is done with irq enabled. This mean that many | ||
143 | * interrupts will occur while we are there. This is why we use the | ||
144 | * jiffies to regulate time instead of a straight mdelay(). Usually we | ||
145 | * need only around 245 iteration of the loop to do 250 ms delay. | ||
146 | * | ||
147 | * Note bis : Don't try to access HERMES_CMD during the reset phase. | ||
148 | * It just won't work ! | ||
149 | */ | ||
150 | static int | ||
151 | orinoco_pci_cor_reset(struct orinoco_private *priv) | ||
152 | { | ||
153 | hermes_t *hw = &priv->hw; | ||
154 | unsigned long timeout; | ||
155 | u16 reg; | ||
156 | |||
157 | /* Assert the reset until the card notice */ | ||
158 | hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); | ||
159 | mdelay(HERMES_PCI_COR_ONT); | ||
160 | |||
161 | /* Give time for the card to recover from this hard effort */ | ||
162 | hermes_write_regn(hw, PCI_COR, 0x0000); | ||
163 | mdelay(HERMES_PCI_COR_OFFT); | ||
164 | |||
165 | /* The card is ready when it's no longer busy */ | ||
166 | timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); | ||
167 | reg = hermes_read_regn(hw, CMD); | ||
168 | while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { | ||
169 | mdelay(1); | ||
170 | reg = hermes_read_regn(hw, CMD); | ||
171 | } | ||
172 | |||
173 | /* Still busy? */ | ||
174 | if (reg & HERMES_CMD_BUSY) { | ||
175 | printk(KERN_ERR PFX "Busy timeout\n"); | ||
176 | return -ETIMEDOUT; | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Initialise a card. Mostly similar to PLX code. | ||
184 | */ | ||
185 | static int orinoco_pci_init_one(struct pci_dev *pdev, | ||
186 | const struct pci_device_id *ent) | ||
187 | { | ||
188 | int err = 0; | ||
189 | unsigned long pci_iorange; | ||
190 | u16 __iomem *pci_ioaddr = NULL; | ||
191 | unsigned long pci_iolen; | ||
192 | struct orinoco_private *priv = NULL; | ||
193 | struct orinoco_pci_card *card; | ||
194 | struct net_device *dev = NULL; | ||
195 | |||
196 | err = pci_enable_device(pdev); | ||
197 | if (err) { | ||
198 | printk(KERN_ERR PFX "Cannot enable PCI device\n"); | ||
199 | return err; | ||
200 | } | ||
201 | |||
202 | err = pci_request_regions(pdev, DRIVER_NAME); | ||
203 | if (err != 0) { | ||
204 | printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); | ||
205 | goto fail_resources; | ||
206 | } | ||
207 | |||
208 | /* Resource 0 is mapped to the hermes registers */ | ||
209 | pci_iorange = pci_resource_start(pdev, 0); | ||
210 | pci_iolen = pci_resource_len(pdev, 0); | ||
211 | pci_ioaddr = ioremap(pci_iorange, pci_iolen); | ||
212 | if (!pci_iorange) { | ||
213 | printk(KERN_ERR PFX "Cannot remap hardware registers\n"); | ||
214 | goto fail_map; | ||
215 | } | ||
216 | |||
217 | /* Allocate network device */ | ||
218 | dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); | ||
219 | if (! dev) { | ||
220 | err = -ENOMEM; | ||
221 | goto fail_alloc; | ||
222 | } | ||
223 | |||
224 | priv = netdev_priv(dev); | ||
225 | card = priv->card; | ||
226 | card->pci_ioaddr = pci_ioaddr; | ||
227 | dev->mem_start = pci_iorange; | ||
228 | dev->mem_end = pci_iorange + pci_iolen - 1; | ||
229 | SET_MODULE_OWNER(dev); | ||
230 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
231 | |||
232 | hermes_struct_init(&priv->hw, pci_ioaddr, HERMES_32BIT_REGSPACING); | ||
233 | |||
234 | printk(KERN_DEBUG PFX "Detected device %s, mem:0x%lx-0x%lx, irq %d\n", | ||
235 | pci_name(pdev), dev->mem_start, dev->mem_end, pdev->irq); | ||
236 | |||
237 | err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, | ||
238 | dev->name, dev); | ||
239 | if (err) { | ||
240 | printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); | ||
241 | err = -EBUSY; | ||
242 | goto fail_irq; | ||
243 | } | ||
244 | dev->irq = pdev->irq; | ||
245 | |||
246 | /* Perform a COR reset to start the card */ | ||
247 | err = orinoco_pci_cor_reset(priv); | ||
248 | if (err) { | ||
249 | printk(KERN_ERR PFX "Initial reset failed\n"); | ||
250 | goto fail; | ||
251 | } | ||
252 | |||
253 | err = register_netdev(dev); | ||
254 | if (err) { | ||
255 | printk(KERN_ERR PFX "Failed to register net device\n"); | ||
256 | goto fail; | ||
257 | } | ||
258 | |||
259 | pci_set_drvdata(pdev, dev); | ||
260 | |||
261 | return 0; | ||
262 | |||
263 | fail: | ||
264 | free_irq(pdev->irq, dev); | ||
265 | |||
266 | fail_irq: | ||
267 | pci_set_drvdata(pdev, NULL); | ||
268 | free_orinocodev(dev); | ||
269 | |||
270 | fail_alloc: | ||
271 | iounmap(pci_ioaddr); | ||
272 | |||
273 | fail_map: | ||
274 | pci_release_regions(pdev); | ||
275 | |||
276 | fail_resources: | ||
277 | pci_disable_device(pdev); | ||
278 | |||
279 | return err; | ||
280 | } | ||
281 | |||
282 | static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) | ||
283 | { | ||
284 | struct net_device *dev = pci_get_drvdata(pdev); | ||
285 | struct orinoco_private *priv = netdev_priv(dev); | ||
286 | struct orinoco_pci_card *card = priv->card; | ||
287 | |||
288 | unregister_netdev(dev); | ||
289 | free_irq(dev->irq, dev); | ||
290 | pci_set_drvdata(pdev, NULL); | ||
291 | free_orinocodev(dev); | ||
292 | iounmap(card->pci_ioaddr); | ||
293 | pci_release_regions(pdev); | ||
294 | pci_disable_device(pdev); | ||
295 | } | ||
296 | |||
297 | static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state) | ||
298 | { | ||
299 | struct net_device *dev = pci_get_drvdata(pdev); | ||
300 | struct orinoco_private *priv = netdev_priv(dev); | ||
301 | unsigned long flags; | ||
302 | int err; | ||
303 | |||
304 | printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n", | ||
305 | dev->name, state); | ||
306 | |||
307 | err = orinoco_lock(priv, &flags); | ||
308 | if (err) { | ||
309 | printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n", | ||
310 | dev->name); | ||
311 | return err; | ||
312 | } | ||
313 | |||
314 | err = __orinoco_down(dev); | ||
315 | if (err) | ||
316 | printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n", | ||
317 | dev->name, err); | ||
318 | |||
319 | netif_device_detach(dev); | ||
320 | |||
321 | priv->hw_unavailable++; | ||
322 | |||
323 | orinoco_unlock(priv, &flags); | ||
324 | |||
325 | pci_save_state(pdev); | ||
326 | pci_set_power_state(pdev, 3); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int orinoco_pci_resume(struct pci_dev *pdev) | ||
332 | { | ||
333 | struct net_device *dev = pci_get_drvdata(pdev); | ||
334 | struct orinoco_private *priv = netdev_priv(dev); | ||
335 | unsigned long flags; | ||
336 | int err; | ||
337 | |||
338 | printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name); | ||
339 | |||
340 | pci_set_power_state(pdev, 0); | ||
341 | pci_restore_state(pdev); | ||
342 | |||
343 | err = orinoco_reinit_firmware(dev); | ||
344 | if (err) { | ||
345 | printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n", | ||
346 | dev->name, err); | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | spin_lock_irqsave(&priv->lock, flags); | ||
351 | |||
352 | netif_device_attach(dev); | ||
353 | |||
354 | priv->hw_unavailable--; | ||
355 | |||
356 | if (priv->open && (! priv->hw_unavailable)) { | ||
357 | err = __orinoco_up(dev); | ||
358 | if (err) | ||
359 | printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n", | ||
360 | dev->name, err); | ||
361 | } | ||
362 | |||
363 | spin_unlock_irqrestore(&priv->lock, flags); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static struct pci_device_id orinoco_pci_pci_id_table[] = { | ||
369 | /* Intersil Prism 3 */ | ||
370 | {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, | ||
371 | /* Intersil Prism 2.5 */ | ||
372 | {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, | ||
373 | /* Samsung MagicLAN SWL-2210P */ | ||
374 | {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, | ||
375 | {0,}, | ||
376 | }; | ||
377 | |||
378 | MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table); | ||
379 | |||
380 | static struct pci_driver orinoco_pci_driver = { | ||
381 | .name = DRIVER_NAME, | ||
382 | .id_table = orinoco_pci_pci_id_table, | ||
383 | .probe = orinoco_pci_init_one, | ||
384 | .remove = __devexit_p(orinoco_pci_remove_one), | ||
385 | .suspend = orinoco_pci_suspend, | ||
386 | .resume = orinoco_pci_resume, | ||
387 | }; | ||
388 | |||
389 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
390 | " (Pavel Roskin <proski@gnu.org>," | ||
391 | " David Gibson <hermes@gibson.dropbear.id.au> &" | ||
392 | " Jean Tourrilhes <jt@hpl.hp.com>)"; | ||
393 | MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>"); | ||
394 | MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); | ||
395 | MODULE_LICENSE("Dual MPL/GPL"); | ||
396 | |||
397 | static int __init orinoco_pci_init(void) | ||
398 | { | ||
399 | printk(KERN_DEBUG "%s\n", version); | ||
400 | return pci_module_init(&orinoco_pci_driver); | ||
401 | } | ||
402 | |||
403 | static void __exit orinoco_pci_exit(void) | ||
404 | { | ||
405 | pci_unregister_driver(&orinoco_pci_driver); | ||
406 | } | ||
407 | |||
408 | module_init(orinoco_pci_init); | ||
409 | module_exit(orinoco_pci_exit); | ||
410 | |||
411 | /* | ||
412 | * Local variables: | ||
413 | * c-indent-level: 8 | ||
414 | * c-basic-offset: 8 | ||
415 | * tab-width: 8 | ||
416 | * End: | ||
417 | */ | ||
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c new file mode 100644 index 000000000000..7ab05b89fb3f --- /dev/null +++ b/drivers/net/wireless/orinoco_plx.c | |||
@@ -0,0 +1,419 @@ | |||
1 | /* orinoco_plx.c | ||
2 | * | ||
3 | * Driver for Prism II devices which would usually be driven by orinoco_cs, | ||
4 | * but are connected to the PCI bus by a PLX9052. | ||
5 | * | ||
6 | * Current maintainers (as of 29 September 2003) are: | ||
7 | * Pavel Roskin <proski AT gnu.org> | ||
8 | * and David Gibson <hermes AT gibson.dropbear.id.au> | ||
9 | * | ||
10 | * (C) Copyright David Gibson, IBM Corp. 2001-2003. | ||
11 | * Copyright (C) 2001 Daniel Barlow | ||
12 | * | ||
13 | * The contents of this file are subject to the Mozilla Public License | ||
14 | * Version 1.1 (the "License"); you may not use this file except in | ||
15 | * compliance with the License. You may obtain a copy of the License | ||
16 | * at http://www.mozilla.org/MPL/ | ||
17 | * | ||
18 | * Software distributed under the License is distributed on an "AS IS" | ||
19 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
20 | * the License for the specific language governing rights and | ||
21 | * limitations under the License. | ||
22 | * | ||
23 | * Alternatively, the contents of this file may be used under the | ||
24 | * terms of the GNU General Public License version 2 (the "GPL"), in | ||
25 | * which case the provisions of the GPL are applicable instead of the | ||
26 | * above. If you wish to allow the use of your version of this file | ||
27 | * only under the terms of the GPL and not to allow others to use your | ||
28 | * version of this file under the MPL, indicate your decision by | ||
29 | * deleting the provisions above and replace them with the notice and | ||
30 | * other provisions required by the GPL. If you do not delete the | ||
31 | * provisions above, a recipient may use your version of this file | ||
32 | * under either the MPL or the GPL. | ||
33 | |||
34 | * Caution: this is experimental and probably buggy. For success and | ||
35 | * failure reports for different cards and adaptors, see | ||
36 | * orinoco_plx_pci_id_table near the end of the file. If you have a | ||
37 | * card we don't have the PCI id for, and looks like it should work, | ||
38 | * drop me mail with the id and "it works"/"it doesn't work". | ||
39 | * | ||
40 | * Note: if everything gets detected fine but it doesn't actually send | ||
41 | * or receive packets, your first port of call should probably be to | ||
42 | * try newer firmware in the card. Especially if you're doing Ad-Hoc | ||
43 | * modes. | ||
44 | * | ||
45 | * The actual driving is done by orinoco.c, this is just resource | ||
46 | * allocation stuff. The explanation below is courtesy of Ryan Niemi | ||
47 | * on the linux-wlan-ng list at | ||
48 | * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html | ||
49 | * | ||
50 | * The PLX9052-based cards (WL11000 and several others) are a | ||
51 | * different beast than the usual PCMCIA-based PRISM2 configuration | ||
52 | * expected by wlan-ng. Here's the general details on how the WL11000 | ||
53 | * PCI adapter works: | ||
54 | * | ||
55 | * - Two PCI I/O address spaces, one 0x80 long which contains the | ||
56 | * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA | ||
57 | * slot I/O address space. | ||
58 | * | ||
59 | * - One PCI memory address space, mapped to the PCMCIA memory space | ||
60 | * (containing the CIS). | ||
61 | * | ||
62 | * After identifying the I/O and memory space, you can read through | ||
63 | * the memory space to confirm the CIS's device ID or manufacturer ID | ||
64 | * to make sure it's the expected card. qKeep in mind that the PCMCIA | ||
65 | * spec specifies the CIS as the lower 8 bits of each word read from | ||
66 | * the CIS, so to read the bytes of the CIS, read every other byte | ||
67 | * (0,2,4,...). Passing that test, you need to enable the I/O address | ||
68 | * space on the PCMCIA card via the PCMCIA COR register. This is the | ||
69 | * first byte following the CIS. In my case (which may not have any | ||
70 | * relation to what's on the PRISM2 cards), COR was at offset 0x800 | ||
71 | * within the PCI memory space. Write 0x41 to the COR register to | ||
72 | * enable I/O mode and to select level triggered interrupts. To | ||
73 | * confirm you actually succeeded, read the COR register back and make | ||
74 | * sure it actually got set to 0x41, incase you have an unexpected | ||
75 | * card inserted. | ||
76 | * | ||
77 | * Following that, you can treat the second PCI I/O address space (the | ||
78 | * one that's not 0x80 in length) as the PCMCIA I/O space. | ||
79 | * | ||
80 | * Note that in the Eumitcom's source for their drivers, they register | ||
81 | * the interrupt as edge triggered when registering it with the | ||
82 | * Windows kernel. I don't recall how to register edge triggered on | ||
83 | * Linux (if it can be done at all). But in some experimentation, I | ||
84 | * don't see much operational difference between using either | ||
85 | * interrupt mode. Don't mess with the interrupt mode in the COR | ||
86 | * register though, as the PLX9052 wants level triggers with the way | ||
87 | * the serial EEPROM configures it on the WL11000. | ||
88 | * | ||
89 | * There's some other little quirks related to timing that I bumped | ||
90 | * into, but I don't recall right now. Also, there's two variants of | ||
91 | * the WL11000 I've seen, revision A1 and T2. These seem to differ | ||
92 | * slightly in the timings configured in the wait-state generator in | ||
93 | * the PLX9052. There have also been some comments from Eumitcom that | ||
94 | * cards shouldn't be hot swapped, apparently due to risk of cooking | ||
95 | * the PLX9052. I'm unsure why they believe this, as I can't see | ||
96 | * anything in the design that would really cause a problem, except | ||
97 | * for crashing drivers not written to expect it. And having developed | ||
98 | * drivers for the WL11000, I'd say it's quite tricky to write code | ||
99 | * that will successfully deal with a hot unplug. Very odd things | ||
100 | * happen on the I/O side of things. But anyway, be warned. Despite | ||
101 | * that, I've hot-swapped a number of times during debugging and | ||
102 | * driver development for various reasons (stuck WAIT# line after the | ||
103 | * radio card's firmware locks up). | ||
104 | * | ||
105 | * Hope this is enough info for someone to add PLX9052 support to the | ||
106 | * wlan-ng card. In the case of the WL11000, the PCI ID's are | ||
107 | * 0x1639/0x0200, with matching subsystem ID's. Other PLX9052-based | ||
108 | * manufacturers other than Eumitcom (or on cards other than the | ||
109 | * WL11000) may have different PCI ID's. | ||
110 | * | ||
111 | * If anyone needs any more specific info, let me know. I haven't had | ||
112 | * time to implement support myself yet, and with the way things are | ||
113 | * going, might not have time for a while.. | ||
114 | */ | ||
115 | |||
116 | #define DRIVER_NAME "orinoco_plx" | ||
117 | #define PFX DRIVER_NAME ": " | ||
118 | |||
119 | #include <linux/config.h> | ||
120 | |||
121 | #include <linux/module.h> | ||
122 | #include <linux/kernel.h> | ||
123 | #include <linux/init.h> | ||
124 | #include <linux/sched.h> | ||
125 | #include <linux/ptrace.h> | ||
126 | #include <linux/slab.h> | ||
127 | #include <linux/string.h> | ||
128 | #include <linux/timer.h> | ||
129 | #include <linux/ioport.h> | ||
130 | #include <asm/uaccess.h> | ||
131 | #include <asm/io.h> | ||
132 | #include <asm/system.h> | ||
133 | #include <linux/netdevice.h> | ||
134 | #include <linux/if_arp.h> | ||
135 | #include <linux/etherdevice.h> | ||
136 | #include <linux/list.h> | ||
137 | #include <linux/pci.h> | ||
138 | #include <linux/fcntl.h> | ||
139 | |||
140 | #include <pcmcia/cisreg.h> | ||
141 | |||
142 | #include "hermes.h" | ||
143 | #include "orinoco.h" | ||
144 | |||
145 | #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ | ||
146 | #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ | ||
147 | #define COR_RESET (0x80) /* reset bit in the COR register */ | ||
148 | #define PLX_RESET_TIME (500) /* milliseconds */ | ||
149 | |||
150 | #define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ | ||
151 | #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ | ||
152 | |||
153 | static const u8 cis_magic[] = { | ||
154 | 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 | ||
155 | }; | ||
156 | |||
157 | /* Orinoco PLX specific data */ | ||
158 | struct orinoco_plx_card { | ||
159 | void __iomem *attr_mem; | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * Do a soft reset of the card using the Configuration Option Register | ||
164 | */ | ||
165 | static int orinoco_plx_cor_reset(struct orinoco_private *priv) | ||
166 | { | ||
167 | hermes_t *hw = &priv->hw; | ||
168 | struct orinoco_plx_card *card = priv->card; | ||
169 | u8 __iomem *attr_mem = card->attr_mem; | ||
170 | unsigned long timeout; | ||
171 | u16 reg; | ||
172 | |||
173 | writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET); | ||
174 | mdelay(1); | ||
175 | |||
176 | writeb(COR_VALUE, attr_mem + COR_OFFSET); | ||
177 | mdelay(1); | ||
178 | |||
179 | /* Just in case, wait more until the card is no longer busy */ | ||
180 | timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); | ||
181 | reg = hermes_read_regn(hw, CMD); | ||
182 | while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { | ||
183 | mdelay(1); | ||
184 | reg = hermes_read_regn(hw, CMD); | ||
185 | } | ||
186 | |||
187 | /* Did we timeout ? */ | ||
188 | if (reg & HERMES_CMD_BUSY) { | ||
189 | printk(KERN_ERR PFX "Busy timeout\n"); | ||
190 | return -ETIMEDOUT; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | static int orinoco_plx_init_one(struct pci_dev *pdev, | ||
198 | const struct pci_device_id *ent) | ||
199 | { | ||
200 | int err = 0; | ||
201 | u8 __iomem *attr_mem = NULL; | ||
202 | u32 csr_reg, plx_addr; | ||
203 | struct orinoco_private *priv = NULL; | ||
204 | struct orinoco_plx_card *card; | ||
205 | unsigned long pccard_ioaddr = 0; | ||
206 | unsigned long pccard_iolen = 0; | ||
207 | struct net_device *dev = NULL; | ||
208 | void __iomem *mem; | ||
209 | int i; | ||
210 | |||
211 | err = pci_enable_device(pdev); | ||
212 | if (err) { | ||
213 | printk(KERN_ERR PFX "Cannot enable PCI device\n"); | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | err = pci_request_regions(pdev, DRIVER_NAME); | ||
218 | if (err != 0) { | ||
219 | printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); | ||
220 | goto fail_resources; | ||
221 | } | ||
222 | |||
223 | /* Resource 1 is mapped to PLX-specific registers */ | ||
224 | plx_addr = pci_resource_start(pdev, 1); | ||
225 | |||
226 | /* Resource 2 is mapped to the PCMCIA attribute memory */ | ||
227 | attr_mem = ioremap(pci_resource_start(pdev, 2), | ||
228 | pci_resource_len(pdev, 2)); | ||
229 | if (!attr_mem) { | ||
230 | printk(KERN_ERR PFX "Cannot remap PCMCIA space\n"); | ||
231 | goto fail_map_attr; | ||
232 | } | ||
233 | |||
234 | /* Resource 3 is mapped to the PCMCIA I/O address space */ | ||
235 | pccard_ioaddr = pci_resource_start(pdev, 3); | ||
236 | pccard_iolen = pci_resource_len(pdev, 3); | ||
237 | |||
238 | mem = pci_iomap(pdev, 3, 0); | ||
239 | if (!mem) { | ||
240 | err = -ENOMEM; | ||
241 | goto fail_map_io; | ||
242 | } | ||
243 | |||
244 | /* Allocate network device */ | ||
245 | dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset); | ||
246 | if (!dev) { | ||
247 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | ||
248 | err = -ENOMEM; | ||
249 | goto fail_alloc; | ||
250 | } | ||
251 | |||
252 | priv = netdev_priv(dev); | ||
253 | card = priv->card; | ||
254 | card->attr_mem = attr_mem; | ||
255 | dev->base_addr = pccard_ioaddr; | ||
256 | SET_MODULE_OWNER(dev); | ||
257 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
258 | |||
259 | hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); | ||
260 | |||
261 | printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device " | ||
262 | "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, | ||
263 | pccard_ioaddr); | ||
264 | |||
265 | err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, | ||
266 | dev->name, dev); | ||
267 | if (err) { | ||
268 | printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); | ||
269 | err = -EBUSY; | ||
270 | goto fail_irq; | ||
271 | } | ||
272 | dev->irq = pdev->irq; | ||
273 | |||
274 | /* bjoern: We need to tell the card to enable interrupts, in | ||
275 | case the serial eprom didn't do this already. See the | ||
276 | PLX9052 data book, p8-1 and 8-24 for reference. */ | ||
277 | csr_reg = inl(plx_addr + PLX_INTCSR); | ||
278 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
279 | csr_reg |= PLX_INTCSR_INTEN; | ||
280 | outl(csr_reg, plx_addr + PLX_INTCSR); | ||
281 | csr_reg = inl(plx_addr + PLX_INTCSR); | ||
282 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
283 | printk(KERN_ERR PFX "Cannot enable interrupts\n"); | ||
284 | goto fail; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | err = orinoco_plx_cor_reset(priv); | ||
289 | if (err) { | ||
290 | printk(KERN_ERR PFX "Initial reset failed\n"); | ||
291 | goto fail; | ||
292 | } | ||
293 | |||
294 | printk(KERN_DEBUG PFX "CIS: "); | ||
295 | for (i = 0; i < 16; i++) { | ||
296 | printk("%02X:", readb(attr_mem + 2*i)); | ||
297 | } | ||
298 | printk("\n"); | ||
299 | |||
300 | /* Verify whether a supported PC card is present */ | ||
301 | /* FIXME: we probably need to be smarted about this */ | ||
302 | for (i = 0; i < sizeof(cis_magic); i++) { | ||
303 | if (cis_magic[i] != readb(attr_mem +2*i)) { | ||
304 | printk(KERN_ERR PFX "The CIS value of Prism2 PC " | ||
305 | "card is unexpected\n"); | ||
306 | err = -EIO; | ||
307 | goto fail; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | err = register_netdev(dev); | ||
312 | if (err) { | ||
313 | printk(KERN_ERR PFX "Cannot register network device\n"); | ||
314 | goto fail; | ||
315 | } | ||
316 | |||
317 | pci_set_drvdata(pdev, dev); | ||
318 | |||
319 | return 0; | ||
320 | |||
321 | fail: | ||
322 | free_irq(pdev->irq, dev); | ||
323 | |||
324 | fail_irq: | ||
325 | pci_set_drvdata(pdev, NULL); | ||
326 | free_orinocodev(dev); | ||
327 | |||
328 | fail_alloc: | ||
329 | pci_iounmap(pdev, mem); | ||
330 | |||
331 | fail_map_io: | ||
332 | iounmap(attr_mem); | ||
333 | |||
334 | fail_map_attr: | ||
335 | pci_release_regions(pdev); | ||
336 | |||
337 | fail_resources: | ||
338 | pci_disable_device(pdev); | ||
339 | |||
340 | return err; | ||
341 | } | ||
342 | |||
343 | static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) | ||
344 | { | ||
345 | struct net_device *dev = pci_get_drvdata(pdev); | ||
346 | struct orinoco_private *priv = netdev_priv(dev); | ||
347 | struct orinoco_plx_card *card = priv->card; | ||
348 | u8 __iomem *attr_mem = card->attr_mem; | ||
349 | |||
350 | BUG_ON(! dev); | ||
351 | |||
352 | unregister_netdev(dev); | ||
353 | free_irq(dev->irq, dev); | ||
354 | pci_set_drvdata(pdev, NULL); | ||
355 | free_orinocodev(dev); | ||
356 | pci_iounmap(pdev, priv->hw.iobase); | ||
357 | iounmap(attr_mem); | ||
358 | pci_release_regions(pdev); | ||
359 | pci_disable_device(pdev); | ||
360 | } | ||
361 | |||
362 | |||
363 | static struct pci_device_id orinoco_plx_pci_id_table[] = { | ||
364 | {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ | ||
365 | {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ | ||
366 | {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ | ||
367 | {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, | ||
368 | Eumitcom PCI WL11000, | ||
369 | Addtron AWA-100 */ | ||
370 | {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ | ||
371 | {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ | ||
372 | {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ | ||
373 | {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ | ||
374 | {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by | ||
375 | Brendan W. McAdams <rit AT jacked-in.org> */ | ||
376 | {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by | ||
377 | Damien Persohn <damien AT persohn.net> */ | ||
378 | {0,}, | ||
379 | }; | ||
380 | |||
381 | MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table); | ||
382 | |||
383 | static struct pci_driver orinoco_plx_driver = { | ||
384 | .name = DRIVER_NAME, | ||
385 | .id_table = orinoco_plx_pci_id_table, | ||
386 | .probe = orinoco_plx_init_one, | ||
387 | .remove = __devexit_p(orinoco_plx_remove_one), | ||
388 | }; | ||
389 | |||
390 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
391 | " (Pavel Roskin <proski@gnu.org>," | ||
392 | " David Gibson <hermes@gibson.dropbear.id.au>," | ||
393 | " Daniel Barlow <dan@telent.net>)"; | ||
394 | MODULE_AUTHOR("Daniel Barlow <dan@telent.net>"); | ||
395 | MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); | ||
396 | MODULE_LICENSE("Dual MPL/GPL"); | ||
397 | |||
398 | static int __init orinoco_plx_init(void) | ||
399 | { | ||
400 | printk(KERN_DEBUG "%s\n", version); | ||
401 | return pci_module_init(&orinoco_plx_driver); | ||
402 | } | ||
403 | |||
404 | static void __exit orinoco_plx_exit(void) | ||
405 | { | ||
406 | pci_unregister_driver(&orinoco_plx_driver); | ||
407 | ssleep(1); | ||
408 | } | ||
409 | |||
410 | module_init(orinoco_plx_init); | ||
411 | module_exit(orinoco_plx_exit); | ||
412 | |||
413 | /* | ||
414 | * Local variables: | ||
415 | * c-indent-level: 8 | ||
416 | * c-basic-offset: 8 | ||
417 | * tab-width: 8 | ||
418 | * End: | ||
419 | */ | ||
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c new file mode 100644 index 000000000000..85893f42445b --- /dev/null +++ b/drivers/net/wireless/orinoco_tmd.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* orinoco_tmd.c | ||
2 | * | ||
3 | * Driver for Prism II devices which would usually be driven by orinoco_cs, | ||
4 | * but are connected to the PCI bus by a TMD7160. | ||
5 | * | ||
6 | * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net> | ||
7 | * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow | ||
8 | * | ||
9 | * The contents of this file are subject to the Mozilla Public License | ||
10 | * Version 1.1 (the "License"); you may not use this file except in | ||
11 | * compliance with the License. You may obtain a copy of the License | ||
12 | * at http://www.mozilla.org/MPL/ | ||
13 | * | ||
14 | * Software distributed under the License is distributed on an "AS IS" | ||
15 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
16 | * the License for the specific language governing rights and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | * Alternatively, the contents of this file may be used under the | ||
20 | * terms of the GNU General Public License version 2 (the "GPL"), in | ||
21 | * which case the provisions of the GPL are applicable instead of the | ||
22 | * above. If you wish to allow the use of your version of this file | ||
23 | * only under the terms of the GPL and not to allow others to use your | ||
24 | * version of this file under the MPL, indicate your decision by | ||
25 | * deleting the provisions above and replace them with the notice and | ||
26 | * other provisions required by the GPL. If you do not delete the | ||
27 | * provisions above, a recipient may use your version of this file | ||
28 | * under either the MPL or the GPL. | ||
29 | |||
30 | * Caution: this is experimental and probably buggy. For success and | ||
31 | * failure reports for different cards and adaptors, see | ||
32 | * orinoco_tmd_pci_id_table near the end of the file. If you have a | ||
33 | * card we don't have the PCI id for, and looks like it should work, | ||
34 | * drop me mail with the id and "it works"/"it doesn't work". | ||
35 | * | ||
36 | * Note: if everything gets detected fine but it doesn't actually send | ||
37 | * or receive packets, your first port of call should probably be to | ||
38 | * try newer firmware in the card. Especially if you're doing Ad-Hoc | ||
39 | * modes | ||
40 | * | ||
41 | * The actual driving is done by orinoco.c, this is just resource | ||
42 | * allocation stuff. | ||
43 | * | ||
44 | * This driver is modeled after the orinoco_plx driver. The main | ||
45 | * difference is that the TMD chip has only IO port ranges and no | ||
46 | * memory space, i.e. no access to the CIS. Compared to the PLX chip, | ||
47 | * the io range functionalities are exchanged. | ||
48 | * | ||
49 | * Pheecom sells cards with the TMD chip as "ASIC version" | ||
50 | */ | ||
51 | |||
52 | #define DRIVER_NAME "orinoco_tmd" | ||
53 | #define PFX DRIVER_NAME ": " | ||
54 | |||
55 | #include <linux/config.h> | ||
56 | |||
57 | #include <linux/module.h> | ||
58 | #include <linux/kernel.h> | ||
59 | #include <linux/init.h> | ||
60 | #include <linux/sched.h> | ||
61 | #include <linux/ptrace.h> | ||
62 | #include <linux/slab.h> | ||
63 | #include <linux/string.h> | ||
64 | #include <linux/timer.h> | ||
65 | #include <linux/ioport.h> | ||
66 | #include <asm/uaccess.h> | ||
67 | #include <asm/io.h> | ||
68 | #include <asm/system.h> | ||
69 | #include <linux/netdevice.h> | ||
70 | #include <linux/if_arp.h> | ||
71 | #include <linux/etherdevice.h> | ||
72 | #include <linux/list.h> | ||
73 | #include <linux/pci.h> | ||
74 | #include <linux/fcntl.h> | ||
75 | |||
76 | #include <pcmcia/cisreg.h> | ||
77 | |||
78 | #include "hermes.h" | ||
79 | #include "orinoco.h" | ||
80 | |||
81 | #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ | ||
82 | #define COR_RESET (0x80) /* reset bit in the COR register */ | ||
83 | #define TMD_RESET_TIME (500) /* milliseconds */ | ||
84 | |||
85 | /* Orinoco TMD specific data */ | ||
86 | struct orinoco_tmd_card { | ||
87 | u32 tmd_io; | ||
88 | }; | ||
89 | |||
90 | |||
91 | /* | ||
92 | * Do a soft reset of the card using the Configuration Option Register | ||
93 | */ | ||
94 | static int orinoco_tmd_cor_reset(struct orinoco_private *priv) | ||
95 | { | ||
96 | hermes_t *hw = &priv->hw; | ||
97 | struct orinoco_tmd_card *card = priv->card; | ||
98 | u32 addr = card->tmd_io; | ||
99 | unsigned long timeout; | ||
100 | u16 reg; | ||
101 | |||
102 | outb(COR_VALUE | COR_RESET, addr); | ||
103 | mdelay(1); | ||
104 | |||
105 | outb(COR_VALUE, addr); | ||
106 | mdelay(1); | ||
107 | |||
108 | /* Just in case, wait more until the card is no longer busy */ | ||
109 | timeout = jiffies + (TMD_RESET_TIME * HZ / 1000); | ||
110 | reg = hermes_read_regn(hw, CMD); | ||
111 | while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { | ||
112 | mdelay(1); | ||
113 | reg = hermes_read_regn(hw, CMD); | ||
114 | } | ||
115 | |||
116 | /* Did we timeout ? */ | ||
117 | if (reg & HERMES_CMD_BUSY) { | ||
118 | printk(KERN_ERR PFX "Busy timeout\n"); | ||
119 | return -ETIMEDOUT; | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | |||
126 | static int orinoco_tmd_init_one(struct pci_dev *pdev, | ||
127 | const struct pci_device_id *ent) | ||
128 | { | ||
129 | int err = 0; | ||
130 | struct orinoco_private *priv = NULL; | ||
131 | struct orinoco_tmd_card *card; | ||
132 | struct net_device *dev = NULL; | ||
133 | void __iomem *mem; | ||
134 | |||
135 | err = pci_enable_device(pdev); | ||
136 | if (err) { | ||
137 | printk(KERN_ERR PFX "Cannot enable PCI device\n"); | ||
138 | return err; | ||
139 | } | ||
140 | |||
141 | err = pci_request_regions(pdev, DRIVER_NAME); | ||
142 | if (err != 0) { | ||
143 | printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); | ||
144 | goto fail_resources; | ||
145 | } | ||
146 | |||
147 | mem = pci_iomap(pdev, 2, 0); | ||
148 | if (! mem) { | ||
149 | err = -ENOMEM; | ||
150 | goto fail_iomap; | ||
151 | } | ||
152 | |||
153 | /* Allocate network device */ | ||
154 | dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset); | ||
155 | if (! dev) { | ||
156 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | ||
157 | err = -ENOMEM; | ||
158 | goto fail_alloc; | ||
159 | } | ||
160 | |||
161 | priv = netdev_priv(dev); | ||
162 | card = priv->card; | ||
163 | card->tmd_io = pci_resource_start(pdev, 1); | ||
164 | dev->base_addr = pci_resource_start(pdev, 2); | ||
165 | SET_MODULE_OWNER(dev); | ||
166 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
167 | |||
168 | hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); | ||
169 | |||
170 | printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device " | ||
171 | "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, | ||
172 | dev->base_addr); | ||
173 | |||
174 | err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, | ||
175 | dev->name, dev); | ||
176 | if (err) { | ||
177 | printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); | ||
178 | err = -EBUSY; | ||
179 | goto fail_irq; | ||
180 | } | ||
181 | dev->irq = pdev->irq; | ||
182 | |||
183 | err = orinoco_tmd_cor_reset(priv); | ||
184 | if (err) { | ||
185 | printk(KERN_ERR PFX "Initial reset failed\n"); | ||
186 | goto fail; | ||
187 | } | ||
188 | |||
189 | err = register_netdev(dev); | ||
190 | if (err) { | ||
191 | printk(KERN_ERR PFX "Cannot register network device\n"); | ||
192 | goto fail; | ||
193 | } | ||
194 | |||
195 | pci_set_drvdata(pdev, dev); | ||
196 | |||
197 | return 0; | ||
198 | |||
199 | fail: | ||
200 | free_irq(pdev->irq, dev); | ||
201 | |||
202 | fail_irq: | ||
203 | pci_set_drvdata(pdev, NULL); | ||
204 | free_orinocodev(dev); | ||
205 | |||
206 | fail_alloc: | ||
207 | pci_iounmap(pdev, mem); | ||
208 | |||
209 | fail_iomap: | ||
210 | pci_release_regions(pdev); | ||
211 | |||
212 | fail_resources: | ||
213 | pci_disable_device(pdev); | ||
214 | |||
215 | return err; | ||
216 | } | ||
217 | |||
218 | static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) | ||
219 | { | ||
220 | struct net_device *dev = pci_get_drvdata(pdev); | ||
221 | struct orinoco_private *priv = dev->priv; | ||
222 | |||
223 | BUG_ON(! dev); | ||
224 | |||
225 | unregister_netdev(dev); | ||
226 | free_irq(dev->irq, dev); | ||
227 | pci_set_drvdata(pdev, NULL); | ||
228 | free_orinocodev(dev); | ||
229 | pci_iounmap(pdev, priv->hw.iobase); | ||
230 | pci_release_regions(pdev); | ||
231 | pci_disable_device(pdev); | ||
232 | } | ||
233 | |||
234 | |||
235 | static struct pci_device_id orinoco_tmd_pci_id_table[] = { | ||
236 | {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ | ||
237 | {0,}, | ||
238 | }; | ||
239 | |||
240 | MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table); | ||
241 | |||
242 | static struct pci_driver orinoco_tmd_driver = { | ||
243 | .name = DRIVER_NAME, | ||
244 | .id_table = orinoco_tmd_pci_id_table, | ||
245 | .probe = orinoco_tmd_init_one, | ||
246 | .remove = __devexit_p(orinoco_tmd_remove_one), | ||
247 | }; | ||
248 | |||
249 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
250 | " (Joerg Dorchain <joerg@dorchain.net>)"; | ||
251 | MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>"); | ||
252 | MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); | ||
253 | MODULE_LICENSE("Dual MPL/GPL"); | ||
254 | |||
255 | static int __init orinoco_tmd_init(void) | ||
256 | { | ||
257 | printk(KERN_DEBUG "%s\n", version); | ||
258 | return pci_module_init(&orinoco_tmd_driver); | ||
259 | } | ||
260 | |||
261 | static void __exit orinoco_tmd_exit(void) | ||
262 | { | ||
263 | pci_unregister_driver(&orinoco_tmd_driver); | ||
264 | ssleep(1); | ||
265 | } | ||
266 | |||
267 | module_init(orinoco_tmd_init); | ||
268 | module_exit(orinoco_tmd_exit); | ||
269 | |||
270 | /* | ||
271 | * Local variables: | ||
272 | * c-indent-level: 8 | ||
273 | * c-basic-offset: 8 | ||
274 | * tab-width: 8 | ||
275 | * End: | ||
276 | */ | ||
diff --git a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile new file mode 100644 index 000000000000..fad305c76737 --- /dev/null +++ b/drivers/net/wireless/prism54/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # $Id: Makefile.k26,v 1.7 2004/01/30 16:24:00 ajfa Exp $ | ||
2 | |||
3 | prism54-objs := islpci_eth.o islpci_mgt.o \ | ||
4 | isl_38xx.o isl_ioctl.o islpci_dev.o \ | ||
5 | islpci_hotplug.o oid_mgt.o | ||
6 | |||
7 | obj-$(CONFIG_PRISM54) += prism54.o | ||
8 | |||
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c new file mode 100644 index 000000000000..4481ec18c5a0 --- /dev/null +++ b/drivers/net/wireless/prism54/isl_38xx.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_ | ||
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 | ||
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 | |||
21 | #include <linux/version.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/delay.h> | ||
25 | |||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/io.h> | ||
28 | |||
29 | #include "prismcompat.h" | ||
30 | #include "isl_38xx.h" | ||
31 | #include "islpci_dev.h" | ||
32 | #include "islpci_mgt.h" | ||
33 | |||
34 | /****************************************************************************** | ||
35 | Device Interface & Control functions | ||
36 | ******************************************************************************/ | ||
37 | |||
38 | /** | ||
39 | * isl38xx_disable_interrupts - disable all interrupts | ||
40 | * @device: pci memory base address | ||
41 | * | ||
42 | * Instructs the device to disable all interrupt reporting by asserting | ||
43 | * the IRQ line. New events may still show up in the interrupt identification | ||
44 | * register located at offset %ISL38XX_INT_IDENT_REG. | ||
45 | */ | ||
46 | void | ||
47 | isl38xx_disable_interrupts(void __iomem *device) | ||
48 | { | ||
49 | isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); | ||
50 | udelay(ISL38XX_WRITEIO_DELAY); | ||
51 | } | ||
52 | |||
53 | void | ||
54 | isl38xx_handle_sleep_request(isl38xx_control_block *control_block, | ||
55 | int *powerstate, void __iomem *device_base) | ||
56 | { | ||
57 | /* device requests to go into sleep mode | ||
58 | * check whether the transmit queues for data and management are empty */ | ||
59 | if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) | ||
60 | /* data tx queue not empty */ | ||
61 | return; | ||
62 | |||
63 | if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) | ||
64 | /* management tx queue not empty */ | ||
65 | return; | ||
66 | |||
67 | /* check also whether received frames are pending */ | ||
68 | if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) | ||
69 | /* data rx queue not empty */ | ||
70 | return; | ||
71 | |||
72 | if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) | ||
73 | /* management rx queue not empty */ | ||
74 | return; | ||
75 | |||
76 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
77 | DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); | ||
78 | #endif | ||
79 | |||
80 | /* all queues are empty, allow the device to go into sleep mode */ | ||
81 | *powerstate = ISL38XX_PSM_POWERSAVE_STATE; | ||
82 | |||
83 | /* assert the Sleep interrupt in the Device Interrupt Register */ | ||
84 | isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, | ||
85 | ISL38XX_DEV_INT_REG); | ||
86 | udelay(ISL38XX_WRITEIO_DELAY); | ||
87 | } | ||
88 | |||
89 | void | ||
90 | isl38xx_handle_wakeup(isl38xx_control_block *control_block, | ||
91 | int *powerstate, void __iomem *device_base) | ||
92 | { | ||
93 | /* device is in active state, update the powerstate flag */ | ||
94 | *powerstate = ISL38XX_PSM_ACTIVE_STATE; | ||
95 | |||
96 | /* now check whether there are frames pending for the card */ | ||
97 | if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) | ||
98 | && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) | ||
99 | return; | ||
100 | |||
101 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
102 | DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); | ||
103 | #endif | ||
104 | |||
105 | /* either data or management transmit queue has a frame pending | ||
106 | * trigger the device by setting the Update bit in the Device Int reg */ | ||
107 | isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, | ||
108 | ISL38XX_DEV_INT_REG); | ||
109 | udelay(ISL38XX_WRITEIO_DELAY); | ||
110 | } | ||
111 | |||
112 | void | ||
113 | isl38xx_trigger_device(int asleep, void __iomem *device_base) | ||
114 | { | ||
115 | struct timeval current_time; | ||
116 | u32 reg, counter = 0; | ||
117 | |||
118 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
119 | DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); | ||
120 | #endif | ||
121 | |||
122 | /* check whether the device is in power save mode */ | ||
123 | if (asleep) { | ||
124 | /* device is in powersave, trigger the device for wakeup */ | ||
125 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
126 | do_gettimeofday(¤t_time); | ||
127 | DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", | ||
128 | current_time.tv_sec, (long)current_time.tv_usec); | ||
129 | #endif | ||
130 | |||
131 | DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", | ||
132 | current_time.tv_sec, (long)current_time.tv_usec, | ||
133 | readl(device_base + ISL38XX_CTRL_STAT_REG)); | ||
134 | udelay(ISL38XX_WRITEIO_DELAY); | ||
135 | |||
136 | reg = readl(device_base + ISL38XX_INT_IDENT_REG); | ||
137 | if (reg == 0xabadface) { | ||
138 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
139 | do_gettimeofday(¤t_time); | ||
140 | DEBUG(SHOW_TRACING, | ||
141 | "%08li.%08li Device register abadface\n", | ||
142 | current_time.tv_sec, (long)current_time.tv_usec); | ||
143 | #endif | ||
144 | /* read the Device Status Register until Sleepmode bit is set */ | ||
145 | while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), | ||
146 | (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { | ||
147 | udelay(ISL38XX_WRITEIO_DELAY); | ||
148 | counter++; | ||
149 | } | ||
150 | |||
151 | DEBUG(SHOW_TRACING, | ||
152 | "%08li.%08li Device register read %08x\n", | ||
153 | current_time.tv_sec, (long)current_time.tv_usec, | ||
154 | readl(device_base + ISL38XX_CTRL_STAT_REG)); | ||
155 | udelay(ISL38XX_WRITEIO_DELAY); | ||
156 | |||
157 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
158 | do_gettimeofday(¤t_time); | ||
159 | DEBUG(SHOW_TRACING, | ||
160 | "%08li.%08li Device asleep counter %i\n", | ||
161 | current_time.tv_sec, (long)current_time.tv_usec, | ||
162 | counter); | ||
163 | #endif | ||
164 | } | ||
165 | /* assert the Wakeup interrupt in the Device Interrupt Register */ | ||
166 | isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, | ||
167 | ISL38XX_DEV_INT_REG); | ||
168 | udelay(ISL38XX_WRITEIO_DELAY); | ||
169 | |||
170 | /* perform another read on the Device Status Register */ | ||
171 | reg = readl(device_base + ISL38XX_CTRL_STAT_REG); | ||
172 | udelay(ISL38XX_WRITEIO_DELAY); | ||
173 | |||
174 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
175 | do_gettimeofday(¤t_time); | ||
176 | DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", | ||
177 | current_time.tv_sec, (long)current_time.tv_usec, reg); | ||
178 | #endif | ||
179 | } else { | ||
180 | /* device is (still) awake */ | ||
181 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
182 | DEBUG(SHOW_TRACING, "Device is in active state\n"); | ||
183 | #endif | ||
184 | /* trigger the device by setting the Update bit in the Device Int reg */ | ||
185 | |||
186 | isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, | ||
187 | ISL38XX_DEV_INT_REG); | ||
188 | udelay(ISL38XX_WRITEIO_DELAY); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | void | ||
193 | isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) | ||
194 | { | ||
195 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
196 | DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n"); | ||
197 | #endif | ||
198 | |||
199 | /* load the address of the control block in the device */ | ||
200 | isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); | ||
201 | udelay(ISL38XX_WRITEIO_DELAY); | ||
202 | |||
203 | /* set the reset bit in the Device Interrupt Register */ | ||
204 | isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG); | ||
205 | udelay(ISL38XX_WRITEIO_DELAY); | ||
206 | |||
207 | /* enable the interrupt for detecting initialization */ | ||
208 | |||
209 | /* Note: Do not enable other interrupts here. We want the | ||
210 | * device to have come up first 100% before allowing any other | ||
211 | * interrupts. */ | ||
212 | isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG); | ||
213 | udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ | ||
214 | } | ||
215 | |||
216 | void | ||
217 | isl38xx_enable_common_interrupts(void __iomem *device_base) { | ||
218 | u32 reg; | ||
219 | reg = ( ISL38XX_INT_IDENT_UPDATE | | ||
220 | ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); | ||
221 | isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); | ||
222 | udelay(ISL38XX_WRITEIO_DELAY); | ||
223 | } | ||
224 | |||
225 | int | ||
226 | isl38xx_in_queue(isl38xx_control_block *cb, int queue) | ||
227 | { | ||
228 | const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) - | ||
229 | le32_to_cpu(cb->device_curr_frag[queue])); | ||
230 | |||
231 | /* determine the amount of fragments in the queue depending on the type | ||
232 | * of the queue, either transmit or receive */ | ||
233 | |||
234 | BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */ | ||
235 | |||
236 | switch (queue) { | ||
237 | /* send queues */ | ||
238 | case ISL38XX_CB_TX_MGMTQ: | ||
239 | BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); | ||
240 | case ISL38XX_CB_TX_DATA_LQ: | ||
241 | case ISL38XX_CB_TX_DATA_HQ: | ||
242 | BUG_ON(delta > ISL38XX_CB_TX_QSIZE); | ||
243 | return delta; | ||
244 | break; | ||
245 | |||
246 | /* receive queues */ | ||
247 | case ISL38XX_CB_RX_MGMTQ: | ||
248 | BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); | ||
249 | return ISL38XX_CB_MGMT_QSIZE - delta; | ||
250 | break; | ||
251 | |||
252 | case ISL38XX_CB_RX_DATA_LQ: | ||
253 | case ISL38XX_CB_RX_DATA_HQ: | ||
254 | BUG_ON(delta > ISL38XX_CB_RX_QSIZE); | ||
255 | return ISL38XX_CB_RX_QSIZE - delta; | ||
256 | break; | ||
257 | } | ||
258 | BUG(); | ||
259 | return 0; | ||
260 | } | ||
diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h new file mode 100644 index 000000000000..e83e4912ab66 --- /dev/null +++ b/drivers/net/wireless/prism54/isl_38xx.h | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
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 | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #ifndef _ISL_38XX_H | ||
21 | #define _ISL_38XX_H | ||
22 | |||
23 | #include <linux/version.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/byteorder.h> | ||
26 | |||
27 | #define ISL38XX_CB_RX_QSIZE 8 | ||
28 | #define ISL38XX_CB_TX_QSIZE 32 | ||
29 | |||
30 | /* ISL38XX Access Point Specific definitions */ | ||
31 | #define ISL38XX_MAX_WDS_LINKS 8 | ||
32 | |||
33 | /* ISL38xx Client Specific definitions */ | ||
34 | #define ISL38XX_PSM_ACTIVE_STATE 0 | ||
35 | #define ISL38XX_PSM_POWERSAVE_STATE 1 | ||
36 | |||
37 | /* ISL38XX Host Interface Definitions */ | ||
38 | #define ISL38XX_PCI_MEM_SIZE 0x02000 | ||
39 | #define ISL38XX_MEMORY_WINDOW_SIZE 0x01000 | ||
40 | #define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000 | ||
41 | #define ISL38XX_WRITEIO_DELAY 10 /* in us */ | ||
42 | #define ISL38XX_RESET_DELAY 50 /* in ms */ | ||
43 | #define ISL38XX_WAIT_CYCLE 10 /* in 10ms */ | ||
44 | #define ISL38XX_MAX_WAIT_CYCLES 10 | ||
45 | |||
46 | /* PCI Memory Area */ | ||
47 | #define ISL38XX_HARDWARE_REG 0x0000 | ||
48 | #define ISL38XX_CARDBUS_CIS 0x0800 | ||
49 | #define ISL38XX_DIRECT_MEM_WIN 0x1000 | ||
50 | |||
51 | /* Hardware registers */ | ||
52 | #define ISL38XX_DEV_INT_REG 0x0000 | ||
53 | #define ISL38XX_INT_IDENT_REG 0x0010 | ||
54 | #define ISL38XX_INT_ACK_REG 0x0014 | ||
55 | #define ISL38XX_INT_EN_REG 0x0018 | ||
56 | #define ISL38XX_GEN_PURP_COM_REG_1 0x0020 | ||
57 | #define ISL38XX_GEN_PURP_COM_REG_2 0x0024 | ||
58 | #define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1 | ||
59 | #define ISL38XX_DIR_MEM_BASE_REG 0x0030 | ||
60 | #define ISL38XX_CTRL_STAT_REG 0x0078 | ||
61 | |||
62 | /* High end mobos queue up pci writes, the following | ||
63 | * is used to "read" from after a write to force flush */ | ||
64 | #define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG | ||
65 | |||
66 | /** | ||
67 | * isl38xx_w32_flush - PCI iomem write helper | ||
68 | * @base: (host) memory base address of the device | ||
69 | * @val: 32bit value (host order) to write | ||
70 | * @offset: byte offset into @base to write value to | ||
71 | * | ||
72 | * This helper takes care of writing a 32bit datum to the | ||
73 | * specified offset into the device's pci memory space, and making sure | ||
74 | * the pci memory buffers get flushed by performing one harmless read | ||
75 | * from the %ISL38XX_PCI_POSTING_FLUSH offset. | ||
76 | */ | ||
77 | static inline void | ||
78 | isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset) | ||
79 | { | ||
80 | writel(val, base + offset); | ||
81 | (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); | ||
82 | } | ||
83 | |||
84 | /* Device Interrupt register bits */ | ||
85 | #define ISL38XX_DEV_INT_RESET 0x0001 | ||
86 | #define ISL38XX_DEV_INT_UPDATE 0x0002 | ||
87 | #define ISL38XX_DEV_INT_WAKEUP 0x0008 | ||
88 | #define ISL38XX_DEV_INT_SLEEP 0x0010 | ||
89 | |||
90 | /* Interrupt Identification/Acknowledge/Enable register bits */ | ||
91 | #define ISL38XX_INT_IDENT_UPDATE 0x0002 | ||
92 | #define ISL38XX_INT_IDENT_INIT 0x0004 | ||
93 | #define ISL38XX_INT_IDENT_WAKEUP 0x0008 | ||
94 | #define ISL38XX_INT_IDENT_SLEEP 0x0010 | ||
95 | #define ISL38XX_INT_SOURCES 0x001E | ||
96 | |||
97 | /* Control/Status register bits */ | ||
98 | /* Looks like there are other meaningful bits | ||
99 | 0x20004400 seen in normal operation, | ||
100 | 0x200044db at 'timeout waiting for mgmt response' | ||
101 | */ | ||
102 | #define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 | ||
103 | #define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 | ||
104 | #define ISL38XX_CTRL_STAT_RESET 0x10000000 | ||
105 | #define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 | ||
106 | #define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 | ||
107 | #define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 | ||
108 | |||
109 | /* Control Block definitions */ | ||
110 | #define ISL38XX_CB_RX_DATA_LQ 0 | ||
111 | #define ISL38XX_CB_TX_DATA_LQ 1 | ||
112 | #define ISL38XX_CB_RX_DATA_HQ 2 | ||
113 | #define ISL38XX_CB_TX_DATA_HQ 3 | ||
114 | #define ISL38XX_CB_RX_MGMTQ 4 | ||
115 | #define ISL38XX_CB_TX_MGMTQ 5 | ||
116 | #define ISL38XX_CB_QCOUNT 6 | ||
117 | #define ISL38XX_CB_MGMT_QSIZE 4 | ||
118 | #define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */ | ||
119 | |||
120 | /* Memory Manager definitions */ | ||
121 | #define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */ | ||
122 | #define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */ | ||
123 | #define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */ | ||
124 | #define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT) | ||
125 | #define CONTROL_BLOCK_SIZE 1024 /* should be enough */ | ||
126 | #define PSM_FRAME_SIZE 1536 | ||
127 | #define PSM_MINIMAL_STATION_COUNT 64 | ||
128 | #define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT | ||
129 | #define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT | ||
130 | #define MAX_TRAP_RX_QUEUE 4 | ||
131 | #define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE | ||
132 | |||
133 | /* Fragment package definitions */ | ||
134 | #define FRAGMENT_FLAG_MF 0x0001 | ||
135 | #define MAX_FRAGMENT_SIZE 1536 | ||
136 | |||
137 | /* In monitor mode frames have a header. I don't know exactly how big those | ||
138 | * frame can be but I've never seen any frame bigger than 1584... : | ||
139 | */ | ||
140 | #define MAX_FRAGMENT_SIZE_RX 1600 | ||
141 | |||
142 | typedef struct { | ||
143 | u32 address; /* physical address on host */ | ||
144 | u16 size; /* packet size */ | ||
145 | u16 flags; /* set of bit-wise flags */ | ||
146 | } isl38xx_fragment; | ||
147 | |||
148 | struct isl38xx_cb { | ||
149 | u32 driver_curr_frag[ISL38XX_CB_QCOUNT]; | ||
150 | u32 device_curr_frag[ISL38XX_CB_QCOUNT]; | ||
151 | isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; | ||
152 | isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; | ||
153 | isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; | ||
154 | isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE]; | ||
155 | isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; | ||
156 | isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; | ||
157 | }; | ||
158 | |||
159 | typedef struct isl38xx_cb isl38xx_control_block; | ||
160 | |||
161 | /* determine number of entries currently in queue */ | ||
162 | int isl38xx_in_queue(isl38xx_control_block *cb, int queue); | ||
163 | |||
164 | void isl38xx_disable_interrupts(void __iomem *); | ||
165 | void isl38xx_enable_common_interrupts(void __iomem *); | ||
166 | |||
167 | void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, | ||
168 | void __iomem *); | ||
169 | void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *); | ||
170 | void isl38xx_trigger_device(int, void __iomem *); | ||
171 | void isl38xx_interface_reset(void __iomem *, dma_addr_t); | ||
172 | |||
173 | #endif /* _ISL_38XX_H */ | ||
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c new file mode 100644 index 000000000000..0f29a9c7bc2c --- /dev/null +++ b/drivers/net/wireless/prism54/isl_ioctl.c | |||
@@ -0,0 +1,2750 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * (C) 2003,2004 Aurelien Alleaume <slts@free.fr> | ||
5 | * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> | ||
6 | * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> | ||
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 | ||
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 | #include <linux/version.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/if_arp.h> | ||
27 | #include <linux/pci.h> | ||
28 | |||
29 | #include <asm/uaccess.h> | ||
30 | |||
31 | #include "prismcompat.h" | ||
32 | #include "isl_ioctl.h" | ||
33 | #include "islpci_mgt.h" | ||
34 | #include "isl_oid.h" /* additional types and defs for isl38xx fw */ | ||
35 | #include "oid_mgt.h" | ||
36 | |||
37 | #include <net/iw_handler.h> /* New driver API */ | ||
38 | |||
39 | |||
40 | static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, | ||
41 | u8 *wpa_ie, size_t wpa_ie_len); | ||
42 | static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); | ||
43 | static int prism54_set_wpa(struct net_device *, struct iw_request_info *, | ||
44 | __u32 *, char *); | ||
45 | |||
46 | |||
47 | /** | ||
48 | * prism54_mib_mode_helper - MIB change mode helper function | ||
49 | * @mib: the &struct islpci_mib object to modify | ||
50 | * @iw_mode: new mode (%IW_MODE_*) | ||
51 | * | ||
52 | * This is a helper function, hence it does not lock. Make sure | ||
53 | * caller deals with locking *if* necessary. This function sets the | ||
54 | * mode-dependent mib values and does the mapping of the Linux | ||
55 | * Wireless API modes to Device firmware modes. It also checks for | ||
56 | * correct valid Linux wireless modes. | ||
57 | */ | ||
58 | static int | ||
59 | prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) | ||
60 | { | ||
61 | u32 config = INL_CONFIG_MANUALRUN; | ||
62 | u32 mode, bsstype; | ||
63 | |||
64 | /* For now, just catch early the Repeater and Secondary modes here */ | ||
65 | if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { | ||
66 | printk(KERN_DEBUG | ||
67 | "%s(): Sorry, Repeater mode and Secondary mode " | ||
68 | "are not yet supported by this driver.\n", __FUNCTION__); | ||
69 | return -EINVAL; | ||
70 | } | ||
71 | |||
72 | priv->iw_mode = iw_mode; | ||
73 | |||
74 | switch (iw_mode) { | ||
75 | case IW_MODE_AUTO: | ||
76 | mode = INL_MODE_CLIENT; | ||
77 | bsstype = DOT11_BSSTYPE_ANY; | ||
78 | break; | ||
79 | case IW_MODE_ADHOC: | ||
80 | mode = INL_MODE_CLIENT; | ||
81 | bsstype = DOT11_BSSTYPE_IBSS; | ||
82 | break; | ||
83 | case IW_MODE_INFRA: | ||
84 | mode = INL_MODE_CLIENT; | ||
85 | bsstype = DOT11_BSSTYPE_INFRA; | ||
86 | break; | ||
87 | case IW_MODE_MASTER: | ||
88 | mode = INL_MODE_AP; | ||
89 | bsstype = DOT11_BSSTYPE_INFRA; | ||
90 | break; | ||
91 | case IW_MODE_MONITOR: | ||
92 | mode = INL_MODE_PROMISCUOUS; | ||
93 | bsstype = DOT11_BSSTYPE_ANY; | ||
94 | config |= INL_CONFIG_RXANNEX; | ||
95 | break; | ||
96 | default: | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | if (init_wds) | ||
101 | config |= INL_CONFIG_WDS; | ||
102 | mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); | ||
103 | mgt_set(priv, OID_INL_CONFIG, &config); | ||
104 | mgt_set(priv, OID_INL_MODE, &mode); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * prism54_mib_init - fill MIB cache with defaults | ||
111 | * | ||
112 | * this function initializes the struct given as @mib with defaults, | ||
113 | * of which many are retrieved from the global module parameter | ||
114 | * variables. | ||
115 | */ | ||
116 | |||
117 | void | ||
118 | prism54_mib_init(islpci_private *priv) | ||
119 | { | ||
120 | u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode; | ||
121 | struct obj_buffer psm_buffer = { | ||
122 | .size = PSM_BUFFER_SIZE, | ||
123 | .addr = priv->device_psm_buffer | ||
124 | }; | ||
125 | |||
126 | channel = CARD_DEFAULT_CHANNEL; | ||
127 | authen = CARD_DEFAULT_AUTHEN; | ||
128 | wep = CARD_DEFAULT_WEP; | ||
129 | filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */ | ||
130 | dot1x = CARD_DEFAULT_DOT1X; | ||
131 | mlme = CARD_DEFAULT_MLME_MODE; | ||
132 | conformance = CARD_DEFAULT_CONFORMANCE; | ||
133 | power = 127; | ||
134 | mode = CARD_DEFAULT_IW_MODE; | ||
135 | |||
136 | mgt_set(priv, DOT11_OID_CHANNEL, &channel); | ||
137 | mgt_set(priv, DOT11_OID_AUTHENABLE, &authen); | ||
138 | mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep); | ||
139 | mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); | ||
140 | mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter); | ||
141 | mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x); | ||
142 | mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme); | ||
143 | mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance); | ||
144 | mgt_set(priv, OID_INL_OUTPUTPOWER, &power); | ||
145 | |||
146 | /* This sets all of the mode-dependent values */ | ||
147 | prism54_mib_mode_helper(priv, mode); | ||
148 | } | ||
149 | |||
150 | /* this will be executed outside of atomic context thanks to | ||
151 | * schedule_work(), thus we can as well use sleeping semaphore | ||
152 | * locking */ | ||
153 | void | ||
154 | prism54_update_stats(islpci_private *priv) | ||
155 | { | ||
156 | char *data; | ||
157 | int j; | ||
158 | struct obj_bss bss, *bss2; | ||
159 | union oid_res_t r; | ||
160 | |||
161 | if (down_interruptible(&priv->stats_sem)) | ||
162 | return; | ||
163 | |||
164 | /* Noise floor. | ||
165 | * I'm not sure if the unit is dBm. | ||
166 | * Note : If we are not connected, this value seems to be irrelevant. */ | ||
167 | |||
168 | mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); | ||
169 | priv->local_iwstatistics.qual.noise = r.u; | ||
170 | |||
171 | /* Get the rssi of the link. To do this we need to retrieve a bss. */ | ||
172 | |||
173 | /* First get the MAC address of the AP we are associated with. */ | ||
174 | mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); | ||
175 | data = r.ptr; | ||
176 | |||
177 | /* copy this MAC to the bss */ | ||
178 | memcpy(bss.address, data, 6); | ||
179 | kfree(data); | ||
180 | |||
181 | /* now ask for the corresponding bss */ | ||
182 | j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); | ||
183 | bss2 = r.ptr; | ||
184 | /* report the rssi and use it to calculate | ||
185 | * link quality through a signal-noise | ||
186 | * ratio */ | ||
187 | priv->local_iwstatistics.qual.level = bss2->rssi; | ||
188 | priv->local_iwstatistics.qual.qual = | ||
189 | bss2->rssi - priv->iwstatistics.qual.noise; | ||
190 | |||
191 | kfree(bss2); | ||
192 | |||
193 | /* report that the stats are new */ | ||
194 | priv->local_iwstatistics.qual.updated = 0x7; | ||
195 | |||
196 | /* Rx : unable to decrypt the MPDU */ | ||
197 | mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); | ||
198 | priv->local_iwstatistics.discard.code = r.u; | ||
199 | |||
200 | /* Tx : Max MAC retries num reached */ | ||
201 | mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); | ||
202 | priv->local_iwstatistics.discard.retries = r.u; | ||
203 | |||
204 | up(&priv->stats_sem); | ||
205 | |||
206 | return; | ||
207 | } | ||
208 | |||
209 | struct iw_statistics * | ||
210 | prism54_get_wireless_stats(struct net_device *ndev) | ||
211 | { | ||
212 | islpci_private *priv = netdev_priv(ndev); | ||
213 | |||
214 | /* If the stats are being updated return old data */ | ||
215 | if (down_trylock(&priv->stats_sem) == 0) { | ||
216 | memcpy(&priv->iwstatistics, &priv->local_iwstatistics, | ||
217 | sizeof (struct iw_statistics)); | ||
218 | /* They won't be marked updated for the next time */ | ||
219 | priv->local_iwstatistics.qual.updated = 0; | ||
220 | up(&priv->stats_sem); | ||
221 | } else | ||
222 | priv->iwstatistics.qual.updated = 0; | ||
223 | |||
224 | /* Update our wireless stats, but do not schedule to often | ||
225 | * (max 1 HZ) */ | ||
226 | if ((priv->stats_timestamp == 0) || | ||
227 | time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { | ||
228 | schedule_work(&priv->stats_work); | ||
229 | priv->stats_timestamp = jiffies; | ||
230 | } | ||
231 | |||
232 | return &priv->iwstatistics; | ||
233 | } | ||
234 | |||
235 | static int | ||
236 | prism54_commit(struct net_device *ndev, struct iw_request_info *info, | ||
237 | char *cwrq, char *extra) | ||
238 | { | ||
239 | islpci_private *priv = netdev_priv(ndev); | ||
240 | |||
241 | /* simply re-set the last set SSID, this should commit most stuff */ | ||
242 | |||
243 | /* Commit in Monitor mode is not necessary, also setting essid | ||
244 | * in Monitor mode does not make sense and isn't allowed for this | ||
245 | * device's firmware */ | ||
246 | if (priv->iw_mode != IW_MODE_MONITOR) | ||
247 | return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int | ||
252 | prism54_get_name(struct net_device *ndev, struct iw_request_info *info, | ||
253 | char *cwrq, char *extra) | ||
254 | { | ||
255 | islpci_private *priv = netdev_priv(ndev); | ||
256 | char *capabilities; | ||
257 | union oid_res_t r; | ||
258 | int rvalue; | ||
259 | |||
260 | if (islpci_get_state(priv) < PRV_STATE_INIT) { | ||
261 | strncpy(cwrq, "NOT READY!", IFNAMSIZ); | ||
262 | return 0; | ||
263 | } | ||
264 | rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); | ||
265 | |||
266 | switch (r.u) { | ||
267 | case INL_PHYCAP_5000MHZ: | ||
268 | capabilities = "IEEE 802.11a/b/g"; | ||
269 | break; | ||
270 | case INL_PHYCAP_FAA: | ||
271 | capabilities = "IEEE 802.11b/g - FAA Support"; | ||
272 | break; | ||
273 | case INL_PHYCAP_2400MHZ: | ||
274 | default: | ||
275 | capabilities = "IEEE 802.11b/g"; /* Default */ | ||
276 | break; | ||
277 | } | ||
278 | strncpy(cwrq, capabilities, IFNAMSIZ); | ||
279 | return rvalue; | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, | ||
284 | struct iw_freq *fwrq, char *extra) | ||
285 | { | ||
286 | islpci_private *priv = netdev_priv(ndev); | ||
287 | int rvalue; | ||
288 | u32 c; | ||
289 | |||
290 | if (fwrq->m < 1000) | ||
291 | /* we have a channel number */ | ||
292 | c = fwrq->m; | ||
293 | else | ||
294 | c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0; | ||
295 | |||
296 | rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL; | ||
297 | |||
298 | /* Call commit handler */ | ||
299 | return (rvalue ? rvalue : -EINPROGRESS); | ||
300 | } | ||
301 | |||
302 | static int | ||
303 | prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, | ||
304 | struct iw_freq *fwrq, char *extra) | ||
305 | { | ||
306 | islpci_private *priv = netdev_priv(ndev); | ||
307 | union oid_res_t r; | ||
308 | int rvalue; | ||
309 | |||
310 | rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); | ||
311 | fwrq->i = r.u; | ||
312 | rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); | ||
313 | fwrq->m = r.u; | ||
314 | fwrq->e = 3; | ||
315 | |||
316 | return rvalue; | ||
317 | } | ||
318 | |||
319 | static int | ||
320 | prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, | ||
321 | __u32 * uwrq, char *extra) | ||
322 | { | ||
323 | islpci_private *priv = netdev_priv(ndev); | ||
324 | u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; | ||
325 | |||
326 | /* Let's see if the user passed a valid Linux Wireless mode */ | ||
327 | if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { | ||
328 | printk(KERN_DEBUG | ||
329 | "%s: %s() You passed a non-valid init_mode.\n", | ||
330 | priv->ndev->name, __FUNCTION__); | ||
331 | return -EINVAL; | ||
332 | } | ||
333 | |||
334 | down_write(&priv->mib_sem); | ||
335 | |||
336 | if (prism54_mib_mode_helper(priv, *uwrq)) { | ||
337 | up_write(&priv->mib_sem); | ||
338 | return -EOPNOTSUPP; | ||
339 | } | ||
340 | |||
341 | /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an | ||
342 | * extended one. | ||
343 | */ | ||
344 | if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) | ||
345 | mlmeautolevel = DOT11_MLME_INTERMEDIATE; | ||
346 | if (priv->wpa) | ||
347 | mlmeautolevel = DOT11_MLME_EXTENDED; | ||
348 | |||
349 | mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); | ||
350 | |||
351 | if (mgt_commit(priv)) { | ||
352 | up_write(&priv->mib_sem); | ||
353 | return -EIO; | ||
354 | } | ||
355 | priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) | ||
356 | ? priv->monitor_type : ARPHRD_ETHER; | ||
357 | up_write(&priv->mib_sem); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | /* Use mib cache */ | ||
363 | static int | ||
364 | prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, | ||
365 | __u32 * uwrq, char *extra) | ||
366 | { | ||
367 | islpci_private *priv = netdev_priv(ndev); | ||
368 | |||
369 | BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > | ||
370 | IW_MODE_MONITOR)); | ||
371 | *uwrq = priv->iw_mode; | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to | ||
377 | * emit data if (sensitivity > rssi - noise) (in dBm). | ||
378 | * prism54_set_sens does not seem to work. | ||
379 | */ | ||
380 | |||
381 | static int | ||
382 | prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, | ||
383 | struct iw_param *vwrq, char *extra) | ||
384 | { | ||
385 | islpci_private *priv = netdev_priv(ndev); | ||
386 | u32 sens; | ||
387 | |||
388 | /* by default the card sets this to 20. */ | ||
389 | sens = vwrq->disabled ? 20 : vwrq->value; | ||
390 | |||
391 | return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); | ||
392 | } | ||
393 | |||
394 | static int | ||
395 | prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, | ||
396 | struct iw_param *vwrq, char *extra) | ||
397 | { | ||
398 | islpci_private *priv = netdev_priv(ndev); | ||
399 | union oid_res_t r; | ||
400 | int rvalue; | ||
401 | |||
402 | rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); | ||
403 | |||
404 | vwrq->value = r.u; | ||
405 | vwrq->disabled = (vwrq->value == 0); | ||
406 | vwrq->fixed = 1; | ||
407 | |||
408 | return rvalue; | ||
409 | } | ||
410 | |||
411 | static int | ||
412 | prism54_get_range(struct net_device *ndev, struct iw_request_info *info, | ||
413 | struct iw_point *dwrq, char *extra) | ||
414 | { | ||
415 | struct iw_range *range = (struct iw_range *) extra; | ||
416 | islpci_private *priv = netdev_priv(ndev); | ||
417 | u8 *data; | ||
418 | int i, m, rvalue; | ||
419 | struct obj_frequencies *freq; | ||
420 | union oid_res_t r; | ||
421 | |||
422 | memset(range, 0, sizeof (struct iw_range)); | ||
423 | dwrq->length = sizeof (struct iw_range); | ||
424 | |||
425 | /* set the wireless extension version number */ | ||
426 | range->we_version_source = SUPPORTED_WIRELESS_EXT; | ||
427 | range->we_version_compiled = WIRELESS_EXT; | ||
428 | |||
429 | /* Now the encoding capabilities */ | ||
430 | range->num_encoding_sizes = 3; | ||
431 | /* 64(40) bits WEP */ | ||
432 | range->encoding_size[0] = 5; | ||
433 | /* 128(104) bits WEP */ | ||
434 | range->encoding_size[1] = 13; | ||
435 | /* 256 bits for WPA-PSK */ | ||
436 | range->encoding_size[2] = 32; | ||
437 | /* 4 keys are allowed */ | ||
438 | range->max_encoding_tokens = 4; | ||
439 | |||
440 | /* we don't know the quality range... */ | ||
441 | range->max_qual.level = 0; | ||
442 | range->max_qual.noise = 0; | ||
443 | range->max_qual.qual = 0; | ||
444 | /* these value describe an average quality. Needs more tweaking... */ | ||
445 | range->avg_qual.level = -80; /* -80 dBm */ | ||
446 | range->avg_qual.noise = 0; /* don't know what to put here */ | ||
447 | range->avg_qual.qual = 0; | ||
448 | |||
449 | range->sensitivity = 200; | ||
450 | |||
451 | /* retry limit capabilities */ | ||
452 | range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; | ||
453 | range->retry_flags = IW_RETRY_LIMIT; | ||
454 | range->r_time_flags = IW_RETRY_LIFETIME; | ||
455 | |||
456 | /* I don't know the range. Put stupid things here */ | ||
457 | range->min_retry = 1; | ||
458 | range->max_retry = 65535; | ||
459 | range->min_r_time = 1024; | ||
460 | range->max_r_time = 65535 * 1024; | ||
461 | |||
462 | /* txpower is supported in dBm's */ | ||
463 | range->txpower_capa = IW_TXPOW_DBM; | ||
464 | |||
465 | #if WIRELESS_EXT > 16 | ||
466 | /* Event capability (kernel + driver) */ | ||
467 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
468 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | | ||
469 | IW_EVENT_CAPA_MASK(SIOCGIWAP)); | ||
470 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
471 | range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); | ||
472 | #endif /* WIRELESS_EXT > 16 */ | ||
473 | |||
474 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
475 | return 0; | ||
476 | |||
477 | /* Request the device for the supported frequencies | ||
478 | * not really relevant since some devices will report the 5 GHz band | ||
479 | * frequencies even if they don't support them. | ||
480 | */ | ||
481 | rvalue = | ||
482 | mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); | ||
483 | freq = r.ptr; | ||
484 | |||
485 | range->num_channels = freq->nr; | ||
486 | range->num_frequency = freq->nr; | ||
487 | |||
488 | m = min(IW_MAX_FREQUENCIES, (int) freq->nr); | ||
489 | for (i = 0; i < m; i++) { | ||
490 | range->freq[i].m = freq->mhz[i]; | ||
491 | range->freq[i].e = 6; | ||
492 | range->freq[i].i = channel_of_freq(freq->mhz[i]); | ||
493 | } | ||
494 | kfree(freq); | ||
495 | |||
496 | rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); | ||
497 | data = r.ptr; | ||
498 | |||
499 | /* We got an array of char. It is NULL terminated. */ | ||
500 | i = 0; | ||
501 | while ((i < IW_MAX_BITRATES) && (*data != 0)) { | ||
502 | /* the result must be in bps. The card gives us 500Kbps */ | ||
503 | range->bitrate[i] = *data * 500000; | ||
504 | i++; | ||
505 | data++; | ||
506 | } | ||
507 | range->num_bitrates = i; | ||
508 | kfree(r.ptr); | ||
509 | |||
510 | return rvalue; | ||
511 | } | ||
512 | |||
513 | /* Set AP address*/ | ||
514 | |||
515 | static int | ||
516 | prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, | ||
517 | struct sockaddr *awrq, char *extra) | ||
518 | { | ||
519 | islpci_private *priv = netdev_priv(ndev); | ||
520 | char bssid[6]; | ||
521 | int rvalue; | ||
522 | |||
523 | if (awrq->sa_family != ARPHRD_ETHER) | ||
524 | return -EINVAL; | ||
525 | |||
526 | /* prepare the structure for the set object */ | ||
527 | memcpy(&bssid[0], awrq->sa_data, 6); | ||
528 | |||
529 | /* set the bssid -- does this make sense when in AP mode? */ | ||
530 | rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); | ||
531 | |||
532 | return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ | ||
533 | } | ||
534 | |||
535 | /* get AP address*/ | ||
536 | |||
537 | static int | ||
538 | prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, | ||
539 | struct sockaddr *awrq, char *extra) | ||
540 | { | ||
541 | islpci_private *priv = netdev_priv(ndev); | ||
542 | union oid_res_t r; | ||
543 | int rvalue; | ||
544 | |||
545 | rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); | ||
546 | memcpy(awrq->sa_data, r.ptr, 6); | ||
547 | awrq->sa_family = ARPHRD_ETHER; | ||
548 | kfree(r.ptr); | ||
549 | |||
550 | return rvalue; | ||
551 | } | ||
552 | |||
553 | static int | ||
554 | prism54_set_scan(struct net_device *dev, struct iw_request_info *info, | ||
555 | struct iw_param *vwrq, char *extra) | ||
556 | { | ||
557 | /* hehe the device does this automagicaly */ | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | /* a little helper that will translate our data into a card independent | ||
562 | * format that the Wireless Tools will understand. This was inspired by | ||
563 | * the "Aironet driver for 4500 and 4800 series cards" (GPL) | ||
564 | */ | ||
565 | |||
566 | static char * | ||
567 | prism54_translate_bss(struct net_device *ndev, char *current_ev, | ||
568 | char *end_buf, struct obj_bss *bss, char noise) | ||
569 | { | ||
570 | struct iw_event iwe; /* Temporary buffer */ | ||
571 | short cap; | ||
572 | islpci_private *priv = netdev_priv(ndev); | ||
573 | |||
574 | /* The first entry must be the MAC address */ | ||
575 | memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); | ||
576 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
577 | iwe.cmd = SIOCGIWAP; | ||
578 | current_ev = | ||
579 | iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); | ||
580 | |||
581 | /* The following entries will be displayed in the same order we give them */ | ||
582 | |||
583 | /* The ESSID. */ | ||
584 | iwe.u.data.length = bss->ssid.length; | ||
585 | iwe.u.data.flags = 1; | ||
586 | iwe.cmd = SIOCGIWESSID; | ||
587 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
588 | &iwe, bss->ssid.octets); | ||
589 | |||
590 | /* Capabilities */ | ||
591 | #define CAP_ESS 0x01 | ||
592 | #define CAP_IBSS 0x02 | ||
593 | #define CAP_CRYPT 0x10 | ||
594 | |||
595 | /* Mode */ | ||
596 | cap = bss->capinfo; | ||
597 | iwe.u.mode = 0; | ||
598 | if (cap & CAP_ESS) | ||
599 | iwe.u.mode = IW_MODE_MASTER; | ||
600 | else if (cap & CAP_IBSS) | ||
601 | iwe.u.mode = IW_MODE_ADHOC; | ||
602 | iwe.cmd = SIOCGIWMODE; | ||
603 | if (iwe.u.mode) | ||
604 | current_ev = | ||
605 | iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
606 | IW_EV_UINT_LEN); | ||
607 | |||
608 | /* Encryption capability */ | ||
609 | if (cap & CAP_CRYPT) | ||
610 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
611 | else | ||
612 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
613 | iwe.u.data.length = 0; | ||
614 | iwe.cmd = SIOCGIWENCODE; | ||
615 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); | ||
616 | |||
617 | /* Add frequency. (short) bss->channel is the frequency in MHz */ | ||
618 | iwe.u.freq.m = bss->channel; | ||
619 | iwe.u.freq.e = 6; | ||
620 | iwe.cmd = SIOCGIWFREQ; | ||
621 | current_ev = | ||
622 | iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); | ||
623 | |||
624 | /* Add quality statistics */ | ||
625 | iwe.u.qual.level = bss->rssi; | ||
626 | iwe.u.qual.noise = noise; | ||
627 | /* do a simple SNR for quality */ | ||
628 | iwe.u.qual.qual = bss->rssi - noise; | ||
629 | iwe.cmd = IWEVQUAL; | ||
630 | current_ev = | ||
631 | iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); | ||
632 | |||
633 | if (priv->wpa) { | ||
634 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
635 | char *buf, *p; | ||
636 | size_t wpa_ie_len; | ||
637 | int i; | ||
638 | |||
639 | wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); | ||
640 | if (wpa_ie_len > 0 && | ||
641 | (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { | ||
642 | p = buf; | ||
643 | p += sprintf(p, "wpa_ie="); | ||
644 | for (i = 0; i < wpa_ie_len; i++) { | ||
645 | p += sprintf(p, "%02x", wpa_ie[i]); | ||
646 | } | ||
647 | memset(&iwe, 0, sizeof (iwe)); | ||
648 | iwe.cmd = IWEVCUSTOM; | ||
649 | iwe.u.data.length = strlen(buf); | ||
650 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
651 | &iwe, buf); | ||
652 | kfree(buf); | ||
653 | } | ||
654 | } | ||
655 | return current_ev; | ||
656 | } | ||
657 | |||
658 | static int | ||
659 | prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, | ||
660 | struct iw_point *dwrq, char *extra) | ||
661 | { | ||
662 | islpci_private *priv = netdev_priv(ndev); | ||
663 | int i, rvalue; | ||
664 | struct obj_bsslist *bsslist; | ||
665 | u32 noise = 0; | ||
666 | char *current_ev = extra; | ||
667 | union oid_res_t r; | ||
668 | |||
669 | if (islpci_get_state(priv) < PRV_STATE_INIT) { | ||
670 | /* device is not ready, fail gently */ | ||
671 | dwrq->length = 0; | ||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | /* first get the noise value. We will use it to report the link quality */ | ||
676 | rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); | ||
677 | noise = r.u; | ||
678 | |||
679 | /* Ask the device for a list of known bss. | ||
680 | * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64. | ||
681 | * The new API, using SIOCGIWSCAN, is only limited by the buffer size. | ||
682 | * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes. | ||
683 | * Starting with WE-17, the buffer can be as big as needed. | ||
684 | * But the device won't repport anything if you change the value | ||
685 | * of IWMAX_BSS=24. */ | ||
686 | |||
687 | rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); | ||
688 | bsslist = r.ptr; | ||
689 | |||
690 | /* ok now, scan the list and translate its info */ | ||
691 | for (i = 0; i < (int) bsslist->nr; i++) { | ||
692 | current_ev = prism54_translate_bss(ndev, current_ev, | ||
693 | extra + dwrq->length, | ||
694 | &(bsslist->bsslist[i]), | ||
695 | noise); | ||
696 | #if WIRELESS_EXT > 16 | ||
697 | /* Check if there is space for one more entry */ | ||
698 | if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { | ||
699 | /* Ask user space to try again with a bigger buffer */ | ||
700 | rvalue = -E2BIG; | ||
701 | break; | ||
702 | } | ||
703 | #endif /* WIRELESS_EXT > 16 */ | ||
704 | } | ||
705 | |||
706 | kfree(bsslist); | ||
707 | dwrq->length = (current_ev - extra); | ||
708 | dwrq->flags = 0; /* todo */ | ||
709 | |||
710 | return rvalue; | ||
711 | } | ||
712 | |||
713 | static int | ||
714 | prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, | ||
715 | struct iw_point *dwrq, char *extra) | ||
716 | { | ||
717 | islpci_private *priv = netdev_priv(ndev); | ||
718 | struct obj_ssid essid; | ||
719 | |||
720 | memset(essid.octets, 0, 33); | ||
721 | |||
722 | /* Check if we were asked for `any' */ | ||
723 | if (dwrq->flags && dwrq->length) { | ||
724 | if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1)) | ||
725 | return -E2BIG; | ||
726 | essid.length = dwrq->length - 1; | ||
727 | memcpy(essid.octets, extra, dwrq->length); | ||
728 | } else | ||
729 | essid.length = 0; | ||
730 | |||
731 | if (priv->iw_mode != IW_MODE_MONITOR) | ||
732 | return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); | ||
733 | |||
734 | /* If in monitor mode, just save to mib */ | ||
735 | mgt_set(priv, DOT11_OID_SSID, &essid); | ||
736 | return 0; | ||
737 | |||
738 | } | ||
739 | |||
740 | static int | ||
741 | prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, | ||
742 | struct iw_point *dwrq, char *extra) | ||
743 | { | ||
744 | islpci_private *priv = netdev_priv(ndev); | ||
745 | struct obj_ssid *essid; | ||
746 | union oid_res_t r; | ||
747 | int rvalue; | ||
748 | |||
749 | rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); | ||
750 | essid = r.ptr; | ||
751 | |||
752 | if (essid->length) { | ||
753 | dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ | ||
754 | /* if it is to big, trunk it */ | ||
755 | dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1); | ||
756 | } else { | ||
757 | dwrq->flags = 0; | ||
758 | dwrq->length = 0; | ||
759 | } | ||
760 | essid->octets[essid->length] = '\0'; | ||
761 | memcpy(extra, essid->octets, dwrq->length); | ||
762 | kfree(essid); | ||
763 | |||
764 | return rvalue; | ||
765 | } | ||
766 | |||
767 | /* Provides no functionality, just completes the ioctl. In essence this is a | ||
768 | * just a cosmetic ioctl. | ||
769 | */ | ||
770 | static int | ||
771 | prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, | ||
772 | struct iw_point *dwrq, char *extra) | ||
773 | { | ||
774 | islpci_private *priv = netdev_priv(ndev); | ||
775 | |||
776 | if (dwrq->length > IW_ESSID_MAX_SIZE) | ||
777 | return -E2BIG; | ||
778 | |||
779 | down_write(&priv->mib_sem); | ||
780 | memset(priv->nickname, 0, sizeof (priv->nickname)); | ||
781 | memcpy(priv->nickname, extra, dwrq->length); | ||
782 | up_write(&priv->mib_sem); | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static int | ||
788 | prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, | ||
789 | struct iw_point *dwrq, char *extra) | ||
790 | { | ||
791 | islpci_private *priv = netdev_priv(ndev); | ||
792 | |||
793 | dwrq->length = 0; | ||
794 | |||
795 | down_read(&priv->mib_sem); | ||
796 | dwrq->length = strlen(priv->nickname) + 1; | ||
797 | memcpy(extra, priv->nickname, dwrq->length); | ||
798 | up_read(&priv->mib_sem); | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | /* Set the allowed Bitrates */ | ||
804 | |||
805 | static int | ||
806 | prism54_set_rate(struct net_device *ndev, | ||
807 | struct iw_request_info *info, | ||
808 | struct iw_param *vwrq, char *extra) | ||
809 | { | ||
810 | |||
811 | islpci_private *priv = netdev_priv(ndev); | ||
812 | u32 rate, profile; | ||
813 | char *data; | ||
814 | int ret, i; | ||
815 | union oid_res_t r; | ||
816 | |||
817 | if (vwrq->value == -1) { | ||
818 | /* auto mode. No limit. */ | ||
819 | profile = 1; | ||
820 | return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); | ||
821 | } | ||
822 | |||
823 | ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); | ||
824 | if (ret) { | ||
825 | kfree(r.ptr); | ||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | rate = (u32) (vwrq->value / 500000); | ||
830 | data = r.ptr; | ||
831 | i = 0; | ||
832 | |||
833 | while (data[i]) { | ||
834 | if (rate && (data[i] == rate)) { | ||
835 | break; | ||
836 | } | ||
837 | if (vwrq->value == i) { | ||
838 | break; | ||
839 | } | ||
840 | data[i] |= 0x80; | ||
841 | i++; | ||
842 | } | ||
843 | |||
844 | if (!data[i]) { | ||
845 | kfree(r.ptr); | ||
846 | return -EINVAL; | ||
847 | } | ||
848 | |||
849 | data[i] |= 0x80; | ||
850 | data[i + 1] = 0; | ||
851 | |||
852 | /* Now, check if we want a fixed or auto value */ | ||
853 | if (vwrq->fixed) { | ||
854 | data[0] = data[i]; | ||
855 | data[1] = 0; | ||
856 | } | ||
857 | |||
858 | /* | ||
859 | i = 0; | ||
860 | printk("prism54 rate: "); | ||
861 | while(data[i]) { | ||
862 | printk("%u ", data[i]); | ||
863 | i++; | ||
864 | } | ||
865 | printk("0\n"); | ||
866 | */ | ||
867 | profile = -1; | ||
868 | ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); | ||
869 | ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); | ||
870 | ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); | ||
871 | |||
872 | kfree(r.ptr); | ||
873 | |||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | /* Get the current bit rate */ | ||
878 | static int | ||
879 | prism54_get_rate(struct net_device *ndev, | ||
880 | struct iw_request_info *info, | ||
881 | struct iw_param *vwrq, char *extra) | ||
882 | { | ||
883 | islpci_private *priv = netdev_priv(ndev); | ||
884 | int rvalue; | ||
885 | char *data; | ||
886 | union oid_res_t r; | ||
887 | |||
888 | /* Get the current bit rate */ | ||
889 | if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) | ||
890 | return rvalue; | ||
891 | vwrq->value = r.u * 500000; | ||
892 | |||
893 | /* request the device for the enabled rates */ | ||
894 | rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r); | ||
895 | if (rvalue) { | ||
896 | kfree(r.ptr); | ||
897 | return rvalue; | ||
898 | } | ||
899 | data = r.ptr; | ||
900 | vwrq->fixed = (data[0] != 0) && (data[1] == 0); | ||
901 | kfree(r.ptr); | ||
902 | |||
903 | return 0; | ||
904 | } | ||
905 | |||
906 | static int | ||
907 | prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, | ||
908 | struct iw_param *vwrq, char *extra) | ||
909 | { | ||
910 | islpci_private *priv = netdev_priv(ndev); | ||
911 | |||
912 | return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); | ||
913 | } | ||
914 | |||
915 | static int | ||
916 | prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, | ||
917 | struct iw_param *vwrq, char *extra) | ||
918 | { | ||
919 | islpci_private *priv = netdev_priv(ndev); | ||
920 | union oid_res_t r; | ||
921 | int rvalue; | ||
922 | |||
923 | /* get the rts threshold */ | ||
924 | rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); | ||
925 | vwrq->value = r.u; | ||
926 | |||
927 | return rvalue; | ||
928 | } | ||
929 | |||
930 | static int | ||
931 | prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, | ||
932 | struct iw_param *vwrq, char *extra) | ||
933 | { | ||
934 | islpci_private *priv = netdev_priv(ndev); | ||
935 | |||
936 | return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); | ||
937 | } | ||
938 | |||
939 | static int | ||
940 | prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, | ||
941 | struct iw_param *vwrq, char *extra) | ||
942 | { | ||
943 | islpci_private *priv = netdev_priv(ndev); | ||
944 | union oid_res_t r; | ||
945 | int rvalue; | ||
946 | |||
947 | rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); | ||
948 | vwrq->value = r.u; | ||
949 | |||
950 | return rvalue; | ||
951 | } | ||
952 | |||
953 | /* Here we have (min,max) = max retries for (small frames, big frames). Where | ||
954 | * big frame <=> bigger than the rts threshold | ||
955 | * small frame <=> smaller than the rts threshold | ||
956 | * This is not really the behavior expected by the wireless tool but it seems | ||
957 | * to be a common behavior in other drivers. | ||
958 | */ | ||
959 | |||
960 | static int | ||
961 | prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, | ||
962 | struct iw_param *vwrq, char *extra) | ||
963 | { | ||
964 | islpci_private *priv = netdev_priv(ndev); | ||
965 | u32 slimit = 0, llimit = 0; /* short and long limit */ | ||
966 | u32 lifetime = 0; | ||
967 | int rvalue = 0; | ||
968 | |||
969 | if (vwrq->disabled) | ||
970 | /* we cannot disable this feature */ | ||
971 | return -EINVAL; | ||
972 | |||
973 | if (vwrq->flags & IW_RETRY_LIMIT) { | ||
974 | if (vwrq->flags & IW_RETRY_MIN) | ||
975 | slimit = vwrq->value; | ||
976 | else if (vwrq->flags & IW_RETRY_MAX) | ||
977 | llimit = vwrq->value; | ||
978 | else { | ||
979 | /* we are asked to set both */ | ||
980 | slimit = vwrq->value; | ||
981 | llimit = vwrq->value; | ||
982 | } | ||
983 | } | ||
984 | if (vwrq->flags & IW_RETRY_LIFETIME) | ||
985 | /* Wireless tools use us unit while the device uses 1024 us unit */ | ||
986 | lifetime = vwrq->value / 1024; | ||
987 | |||
988 | /* now set what is requested */ | ||
989 | if (slimit) | ||
990 | rvalue = | ||
991 | mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); | ||
992 | if (llimit) | ||
993 | rvalue |= | ||
994 | mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); | ||
995 | if (lifetime) | ||
996 | rvalue |= | ||
997 | mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, | ||
998 | &lifetime); | ||
999 | return rvalue; | ||
1000 | } | ||
1001 | |||
1002 | static int | ||
1003 | prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, | ||
1004 | struct iw_param *vwrq, char *extra) | ||
1005 | { | ||
1006 | islpci_private *priv = netdev_priv(ndev); | ||
1007 | union oid_res_t r; | ||
1008 | int rvalue = 0; | ||
1009 | vwrq->disabled = 0; /* It cannot be disabled */ | ||
1010 | |||
1011 | if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
1012 | /* we are asked for the life time */ | ||
1013 | rvalue = | ||
1014 | mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); | ||
1015 | vwrq->value = r.u * 1024; | ||
1016 | vwrq->flags = IW_RETRY_LIFETIME; | ||
1017 | } else if ((vwrq->flags & IW_RETRY_MAX)) { | ||
1018 | /* we are asked for the long retry limit */ | ||
1019 | rvalue |= | ||
1020 | mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); | ||
1021 | vwrq->value = r.u; | ||
1022 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
1023 | } else { | ||
1024 | /* default. get the short retry limit */ | ||
1025 | rvalue |= | ||
1026 | mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); | ||
1027 | vwrq->value = r.u; | ||
1028 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN; | ||
1029 | } | ||
1030 | |||
1031 | return rvalue; | ||
1032 | } | ||
1033 | |||
1034 | static int | ||
1035 | prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, | ||
1036 | struct iw_point *dwrq, char *extra) | ||
1037 | { | ||
1038 | islpci_private *priv = netdev_priv(ndev); | ||
1039 | int rvalue = 0, force = 0; | ||
1040 | int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; | ||
1041 | union oid_res_t r; | ||
1042 | |||
1043 | /* with the new API, it's impossible to get a NULL pointer. | ||
1044 | * New version of iwconfig set the IW_ENCODE_NOKEY flag | ||
1045 | * when no key is given, but older versions don't. */ | ||
1046 | |||
1047 | if (dwrq->length > 0) { | ||
1048 | /* we have a key to set */ | ||
1049 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1050 | int current_index; | ||
1051 | struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; | ||
1052 | |||
1053 | /* get the current key index */ | ||
1054 | rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); | ||
1055 | current_index = r.u; | ||
1056 | /* Verify that the key is not marked as invalid */ | ||
1057 | if (!(dwrq->flags & IW_ENCODE_NOKEY)) { | ||
1058 | key.length = dwrq->length > sizeof (key.key) ? | ||
1059 | sizeof (key.key) : dwrq->length; | ||
1060 | memcpy(key.key, extra, key.length); | ||
1061 | if (key.length == 32) | ||
1062 | /* we want WPA-PSK */ | ||
1063 | key.type = DOT11_PRIV_TKIP; | ||
1064 | if ((index < 0) || (index > 3)) | ||
1065 | /* no index provided use the current one */ | ||
1066 | index = current_index; | ||
1067 | |||
1068 | /* now send the key to the card */ | ||
1069 | rvalue |= | ||
1070 | mgt_set_request(priv, DOT11_OID_DEFKEYX, index, | ||
1071 | &key); | ||
1072 | } | ||
1073 | /* | ||
1074 | * If a valid key is set, encryption should be enabled | ||
1075 | * (user may turn it off later). | ||
1076 | * This is also how "iwconfig ethX key on" works | ||
1077 | */ | ||
1078 | if ((index == current_index) && (key.length > 0)) | ||
1079 | force = 1; | ||
1080 | } else { | ||
1081 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1082 | if ((index >= 0) && (index <= 3)) { | ||
1083 | /* we want to set the key index */ | ||
1084 | rvalue |= | ||
1085 | mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, | ||
1086 | &index); | ||
1087 | } else { | ||
1088 | if (!dwrq->flags & IW_ENCODE_MODE) { | ||
1089 | /* we cannot do anything. Complain. */ | ||
1090 | return -EINVAL; | ||
1091 | } | ||
1092 | } | ||
1093 | } | ||
1094 | /* now read the flags */ | ||
1095 | if (dwrq->flags & IW_ENCODE_DISABLED) { | ||
1096 | /* Encoding disabled, | ||
1097 | * authen = DOT11_AUTH_OS; | ||
1098 | * invoke = 0; | ||
1099 | * exunencrypt = 0; */ | ||
1100 | } | ||
1101 | if (dwrq->flags & IW_ENCODE_OPEN) | ||
1102 | /* Encode but accept non-encoded packets. No auth */ | ||
1103 | invoke = 1; | ||
1104 | if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { | ||
1105 | /* Refuse non-encoded packets. Auth */ | ||
1106 | authen = DOT11_AUTH_BOTH; | ||
1107 | invoke = 1; | ||
1108 | exunencrypt = 1; | ||
1109 | } | ||
1110 | /* do the change if requested */ | ||
1111 | if ((dwrq->flags & IW_ENCODE_MODE) || force) { | ||
1112 | rvalue |= | ||
1113 | mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); | ||
1114 | rvalue |= | ||
1115 | mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); | ||
1116 | rvalue |= | ||
1117 | mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, | ||
1118 | &exunencrypt); | ||
1119 | } | ||
1120 | return rvalue; | ||
1121 | } | ||
1122 | |||
1123 | static int | ||
1124 | prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, | ||
1125 | struct iw_point *dwrq, char *extra) | ||
1126 | { | ||
1127 | islpci_private *priv = netdev_priv(ndev); | ||
1128 | struct obj_key *key; | ||
1129 | u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1130 | u32 authen = 0, invoke = 0, exunencrypt = 0; | ||
1131 | int rvalue; | ||
1132 | union oid_res_t r; | ||
1133 | |||
1134 | /* first get the flags */ | ||
1135 | rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); | ||
1136 | authen = r.u; | ||
1137 | rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); | ||
1138 | invoke = r.u; | ||
1139 | rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); | ||
1140 | exunencrypt = r.u; | ||
1141 | |||
1142 | if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) | ||
1143 | dwrq->flags = IW_ENCODE_RESTRICTED; | ||
1144 | else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { | ||
1145 | if (invoke) | ||
1146 | dwrq->flags = IW_ENCODE_OPEN; | ||
1147 | else | ||
1148 | dwrq->flags = IW_ENCODE_DISABLED; | ||
1149 | } else | ||
1150 | /* The card should not work in this state */ | ||
1151 | dwrq->flags = 0; | ||
1152 | |||
1153 | /* get the current device key index */ | ||
1154 | rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); | ||
1155 | devindex = r.u; | ||
1156 | /* Now get the key, return it */ | ||
1157 | if ((index < 0) || (index > 3)) | ||
1158 | /* no index provided, use the current one */ | ||
1159 | index = devindex; | ||
1160 | rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); | ||
1161 | key = r.ptr; | ||
1162 | dwrq->length = key->length; | ||
1163 | memcpy(extra, key->key, dwrq->length); | ||
1164 | kfree(key); | ||
1165 | /* return the used key index */ | ||
1166 | dwrq->flags |= devindex + 1; | ||
1167 | |||
1168 | return rvalue; | ||
1169 | } | ||
1170 | |||
1171 | static int | ||
1172 | prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, | ||
1173 | struct iw_param *vwrq, char *extra) | ||
1174 | { | ||
1175 | islpci_private *priv = netdev_priv(ndev); | ||
1176 | union oid_res_t r; | ||
1177 | int rvalue; | ||
1178 | |||
1179 | rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); | ||
1180 | /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ | ||
1181 | vwrq->value = (s32) r.u / 4; | ||
1182 | vwrq->fixed = 1; | ||
1183 | /* radio is not turned of | ||
1184 | * btw: how is possible to turn off only the radio | ||
1185 | */ | ||
1186 | vwrq->disabled = 0; | ||
1187 | |||
1188 | return rvalue; | ||
1189 | } | ||
1190 | |||
1191 | static int | ||
1192 | prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, | ||
1193 | struct iw_param *vwrq, char *extra) | ||
1194 | { | ||
1195 | islpci_private *priv = netdev_priv(ndev); | ||
1196 | s32 u = vwrq->value; | ||
1197 | |||
1198 | /* intersil firmware operates in 0.25 dBm (1/4) */ | ||
1199 | u *= 4; | ||
1200 | if (vwrq->disabled) { | ||
1201 | /* don't know how to disable radio */ | ||
1202 | printk(KERN_DEBUG | ||
1203 | "%s: %s() disabling radio is not yet supported.\n", | ||
1204 | priv->ndev->name, __FUNCTION__); | ||
1205 | return -ENOTSUPP; | ||
1206 | } else if (vwrq->fixed) | ||
1207 | /* currently only fixed value is supported */ | ||
1208 | return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); | ||
1209 | else { | ||
1210 | printk(KERN_DEBUG | ||
1211 | "%s: %s() auto power will be implemented later.\n", | ||
1212 | priv->ndev->name, __FUNCTION__); | ||
1213 | return -ENOTSUPP; | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | static int | ||
1218 | prism54_reset(struct net_device *ndev, struct iw_request_info *info, | ||
1219 | __u32 * uwrq, char *extra) | ||
1220 | { | ||
1221 | islpci_reset(netdev_priv(ndev), 0); | ||
1222 | |||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
1226 | static int | ||
1227 | prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, | ||
1228 | struct iw_point *dwrq, char *extra) | ||
1229 | { | ||
1230 | union oid_res_t r; | ||
1231 | int rvalue; | ||
1232 | enum oid_num_t n = dwrq->flags; | ||
1233 | |||
1234 | rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r); | ||
1235 | dwrq->length = mgt_response_to_str(n, &r, extra); | ||
1236 | if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) | ||
1237 | kfree(r.ptr); | ||
1238 | return rvalue; | ||
1239 | } | ||
1240 | |||
1241 | static int | ||
1242 | prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, | ||
1243 | __u32 * uwrq, char *extra) | ||
1244 | { | ||
1245 | u32 oid = uwrq[0], u = uwrq[1]; | ||
1246 | |||
1247 | return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u); | ||
1248 | } | ||
1249 | |||
1250 | static int | ||
1251 | prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, | ||
1252 | struct iw_point *dwrq, char *extra) | ||
1253 | { | ||
1254 | u32 oid = dwrq->flags; | ||
1255 | |||
1256 | return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra); | ||
1257 | } | ||
1258 | |||
1259 | void | ||
1260 | prism54_acl_init(struct islpci_acl *acl) | ||
1261 | { | ||
1262 | sema_init(&acl->sem, 1); | ||
1263 | INIT_LIST_HEAD(&acl->mac_list); | ||
1264 | acl->size = 0; | ||
1265 | acl->policy = MAC_POLICY_OPEN; | ||
1266 | } | ||
1267 | |||
1268 | static void | ||
1269 | prism54_clear_mac(struct islpci_acl *acl) | ||
1270 | { | ||
1271 | struct list_head *ptr, *next; | ||
1272 | struct mac_entry *entry; | ||
1273 | |||
1274 | if (down_interruptible(&acl->sem)) | ||
1275 | return; | ||
1276 | |||
1277 | if (acl->size == 0) { | ||
1278 | up(&acl->sem); | ||
1279 | return; | ||
1280 | } | ||
1281 | |||
1282 | for (ptr = acl->mac_list.next, next = ptr->next; | ||
1283 | ptr != &acl->mac_list; ptr = next, next = ptr->next) { | ||
1284 | entry = list_entry(ptr, struct mac_entry, _list); | ||
1285 | list_del(ptr); | ||
1286 | kfree(entry); | ||
1287 | } | ||
1288 | acl->size = 0; | ||
1289 | up(&acl->sem); | ||
1290 | } | ||
1291 | |||
1292 | void | ||
1293 | prism54_acl_clean(struct islpci_acl *acl) | ||
1294 | { | ||
1295 | prism54_clear_mac(acl); | ||
1296 | } | ||
1297 | |||
1298 | static int | ||
1299 | prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, | ||
1300 | struct sockaddr *awrq, char *extra) | ||
1301 | { | ||
1302 | islpci_private *priv = netdev_priv(ndev); | ||
1303 | struct islpci_acl *acl = &priv->acl; | ||
1304 | struct mac_entry *entry; | ||
1305 | struct sockaddr *addr = (struct sockaddr *) extra; | ||
1306 | |||
1307 | if (addr->sa_family != ARPHRD_ETHER) | ||
1308 | return -EOPNOTSUPP; | ||
1309 | |||
1310 | entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); | ||
1311 | if (entry == NULL) | ||
1312 | return -ENOMEM; | ||
1313 | |||
1314 | memcpy(entry->addr, addr->sa_data, ETH_ALEN); | ||
1315 | |||
1316 | if (down_interruptible(&acl->sem)) { | ||
1317 | kfree(entry); | ||
1318 | return -ERESTARTSYS; | ||
1319 | } | ||
1320 | list_add_tail(&entry->_list, &acl->mac_list); | ||
1321 | acl->size++; | ||
1322 | up(&acl->sem); | ||
1323 | |||
1324 | return 0; | ||
1325 | } | ||
1326 | |||
1327 | static int | ||
1328 | prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, | ||
1329 | struct sockaddr *awrq, char *extra) | ||
1330 | { | ||
1331 | islpci_private *priv = netdev_priv(ndev); | ||
1332 | struct islpci_acl *acl = &priv->acl; | ||
1333 | struct mac_entry *entry; | ||
1334 | struct list_head *ptr; | ||
1335 | struct sockaddr *addr = (struct sockaddr *) extra; | ||
1336 | |||
1337 | if (addr->sa_family != ARPHRD_ETHER) | ||
1338 | return -EOPNOTSUPP; | ||
1339 | |||
1340 | if (down_interruptible(&acl->sem)) | ||
1341 | return -ERESTARTSYS; | ||
1342 | for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { | ||
1343 | entry = list_entry(ptr, struct mac_entry, _list); | ||
1344 | |||
1345 | if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { | ||
1346 | list_del(ptr); | ||
1347 | acl->size--; | ||
1348 | kfree(entry); | ||
1349 | up(&acl->sem); | ||
1350 | return 0; | ||
1351 | } | ||
1352 | } | ||
1353 | up(&acl->sem); | ||
1354 | return -EINVAL; | ||
1355 | } | ||
1356 | |||
1357 | static int | ||
1358 | prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, | ||
1359 | struct iw_point *dwrq, char *extra) | ||
1360 | { | ||
1361 | islpci_private *priv = netdev_priv(ndev); | ||
1362 | struct islpci_acl *acl = &priv->acl; | ||
1363 | struct mac_entry *entry; | ||
1364 | struct list_head *ptr; | ||
1365 | struct sockaddr *dst = (struct sockaddr *) extra; | ||
1366 | |||
1367 | dwrq->length = 0; | ||
1368 | |||
1369 | if (down_interruptible(&acl->sem)) | ||
1370 | return -ERESTARTSYS; | ||
1371 | |||
1372 | for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { | ||
1373 | entry = list_entry(ptr, struct mac_entry, _list); | ||
1374 | |||
1375 | memcpy(dst->sa_data, entry->addr, ETH_ALEN); | ||
1376 | dst->sa_family = ARPHRD_ETHER; | ||
1377 | dwrq->length++; | ||
1378 | dst++; | ||
1379 | } | ||
1380 | up(&acl->sem); | ||
1381 | return 0; | ||
1382 | } | ||
1383 | |||
1384 | /* Setting policy also clears the MAC acl, even if we don't change the defaut | ||
1385 | * policy | ||
1386 | */ | ||
1387 | |||
1388 | static int | ||
1389 | prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, | ||
1390 | __u32 * uwrq, char *extra) | ||
1391 | { | ||
1392 | islpci_private *priv = netdev_priv(ndev); | ||
1393 | struct islpci_acl *acl = &priv->acl; | ||
1394 | u32 mlmeautolevel; | ||
1395 | |||
1396 | prism54_clear_mac(acl); | ||
1397 | |||
1398 | if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) | ||
1399 | return -EINVAL; | ||
1400 | |||
1401 | down_write(&priv->mib_sem); | ||
1402 | |||
1403 | acl->policy = *uwrq; | ||
1404 | |||
1405 | /* the ACL code needs an intermediate mlmeautolevel */ | ||
1406 | if ((priv->iw_mode == IW_MODE_MASTER) && | ||
1407 | (acl->policy != MAC_POLICY_OPEN)) | ||
1408 | mlmeautolevel = DOT11_MLME_INTERMEDIATE; | ||
1409 | else | ||
1410 | mlmeautolevel = CARD_DEFAULT_MLME_MODE; | ||
1411 | if (priv->wpa) | ||
1412 | mlmeautolevel = DOT11_MLME_EXTENDED; | ||
1413 | mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); | ||
1414 | /* restart the card with our new policy */ | ||
1415 | if (mgt_commit(priv)) { | ||
1416 | up_write(&priv->mib_sem); | ||
1417 | return -EIO; | ||
1418 | } | ||
1419 | up_write(&priv->mib_sem); | ||
1420 | |||
1421 | return 0; | ||
1422 | } | ||
1423 | |||
1424 | static int | ||
1425 | prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, | ||
1426 | __u32 * uwrq, char *extra) | ||
1427 | { | ||
1428 | islpci_private *priv = netdev_priv(ndev); | ||
1429 | struct islpci_acl *acl = &priv->acl; | ||
1430 | |||
1431 | *uwrq = acl->policy; | ||
1432 | |||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1436 | /* Return 1 only if client should be accepted. */ | ||
1437 | |||
1438 | static int | ||
1439 | prism54_mac_accept(struct islpci_acl *acl, char *mac) | ||
1440 | { | ||
1441 | struct list_head *ptr; | ||
1442 | struct mac_entry *entry; | ||
1443 | int res = 0; | ||
1444 | |||
1445 | if (down_interruptible(&acl->sem)) | ||
1446 | return -ERESTARTSYS; | ||
1447 | |||
1448 | if (acl->policy == MAC_POLICY_OPEN) { | ||
1449 | up(&acl->sem); | ||
1450 | return 1; | ||
1451 | } | ||
1452 | |||
1453 | for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { | ||
1454 | entry = list_entry(ptr, struct mac_entry, _list); | ||
1455 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
1456 | res = 1; | ||
1457 | break; | ||
1458 | } | ||
1459 | } | ||
1460 | res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; | ||
1461 | up(&acl->sem); | ||
1462 | |||
1463 | return res; | ||
1464 | } | ||
1465 | |||
1466 | static int | ||
1467 | prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, | ||
1468 | struct iw_point *dwrq, char *extra) | ||
1469 | { | ||
1470 | struct obj_mlme *mlme; | ||
1471 | int rvalue; | ||
1472 | |||
1473 | mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); | ||
1474 | if (mlme == NULL) | ||
1475 | return -ENOMEM; | ||
1476 | |||
1477 | /* Tell the card to kick every client */ | ||
1478 | mlme->id = 0; | ||
1479 | rvalue = | ||
1480 | mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); | ||
1481 | kfree(mlme); | ||
1482 | |||
1483 | return rvalue; | ||
1484 | } | ||
1485 | |||
1486 | static int | ||
1487 | prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, | ||
1488 | struct sockaddr *awrq, char *extra) | ||
1489 | { | ||
1490 | struct obj_mlme *mlme; | ||
1491 | struct sockaddr *addr = (struct sockaddr *) extra; | ||
1492 | int rvalue; | ||
1493 | |||
1494 | if (addr->sa_family != ARPHRD_ETHER) | ||
1495 | return -EOPNOTSUPP; | ||
1496 | |||
1497 | mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); | ||
1498 | if (mlme == NULL) | ||
1499 | return -ENOMEM; | ||
1500 | |||
1501 | /* Tell the card to only kick the corresponding bastard */ | ||
1502 | memcpy(mlme->address, addr->sa_data, ETH_ALEN); | ||
1503 | mlme->id = -1; | ||
1504 | rvalue = | ||
1505 | mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); | ||
1506 | |||
1507 | kfree(mlme); | ||
1508 | |||
1509 | return rvalue; | ||
1510 | } | ||
1511 | |||
1512 | /* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ | ||
1513 | |||
1514 | static void | ||
1515 | format_event(islpci_private *priv, char *dest, const char *str, | ||
1516 | const struct obj_mlme *mlme, u16 *length, int error) | ||
1517 | { | ||
1518 | const u8 *a = mlme->address; | ||
1519 | int n = snprintf(dest, IW_CUSTOM_MAX, | ||
1520 | "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)", | ||
1521 | str, | ||
1522 | ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), | ||
1523 | a[0], a[1], a[2], a[3], a[4], a[5], | ||
1524 | (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") | ||
1525 | : ""), mlme->code); | ||
1526 | BUG_ON(n > IW_CUSTOM_MAX); | ||
1527 | *length = n; | ||
1528 | } | ||
1529 | |||
1530 | static void | ||
1531 | send_formatted_event(islpci_private *priv, const char *str, | ||
1532 | const struct obj_mlme *mlme, int error) | ||
1533 | { | ||
1534 | union iwreq_data wrqu; | ||
1535 | char *memptr; | ||
1536 | |||
1537 | memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); | ||
1538 | if (!memptr) | ||
1539 | return; | ||
1540 | wrqu.data.pointer = memptr; | ||
1541 | wrqu.data.length = 0; | ||
1542 | format_event(priv, memptr, str, mlme, &wrqu.data.length, | ||
1543 | error); | ||
1544 | wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); | ||
1545 | kfree(memptr); | ||
1546 | } | ||
1547 | |||
1548 | static void | ||
1549 | send_simple_event(islpci_private *priv, const char *str) | ||
1550 | { | ||
1551 | union iwreq_data wrqu; | ||
1552 | char *memptr; | ||
1553 | int n = strlen(str); | ||
1554 | |||
1555 | memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); | ||
1556 | if (!memptr) | ||
1557 | return; | ||
1558 | BUG_ON(n > IW_CUSTOM_MAX); | ||
1559 | wrqu.data.pointer = memptr; | ||
1560 | wrqu.data.length = n; | ||
1561 | strcpy(memptr, str); | ||
1562 | wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); | ||
1563 | kfree(memptr); | ||
1564 | } | ||
1565 | |||
1566 | static void | ||
1567 | link_changed(struct net_device *ndev, u32 bitrate) | ||
1568 | { | ||
1569 | islpci_private *priv = netdev_priv(ndev); | ||
1570 | |||
1571 | if (bitrate) { | ||
1572 | if (priv->iw_mode == IW_MODE_INFRA) { | ||
1573 | union iwreq_data uwrq; | ||
1574 | prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, | ||
1575 | NULL); | ||
1576 | wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); | ||
1577 | } else | ||
1578 | send_simple_event(netdev_priv(ndev), | ||
1579 | "Link established"); | ||
1580 | } else | ||
1581 | send_simple_event(netdev_priv(ndev), "Link lost"); | ||
1582 | } | ||
1583 | |||
1584 | /* Beacon/ProbeResp payload header */ | ||
1585 | struct ieee80211_beacon_phdr { | ||
1586 | u8 timestamp[8]; | ||
1587 | u16 beacon_int; | ||
1588 | u16 capab_info; | ||
1589 | } __attribute__ ((packed)); | ||
1590 | |||
1591 | #define WLAN_EID_GENERIC 0xdd | ||
1592 | static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; | ||
1593 | |||
1594 | #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] | ||
1595 | #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" | ||
1596 | |||
1597 | static void | ||
1598 | prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, | ||
1599 | u8 *wpa_ie, size_t wpa_ie_len) | ||
1600 | { | ||
1601 | struct list_head *ptr; | ||
1602 | struct islpci_bss_wpa_ie *bss = NULL; | ||
1603 | |||
1604 | if (wpa_ie_len > MAX_WPA_IE_LEN) | ||
1605 | wpa_ie_len = MAX_WPA_IE_LEN; | ||
1606 | |||
1607 | if (down_interruptible(&priv->wpa_sem)) | ||
1608 | return; | ||
1609 | |||
1610 | /* try to use existing entry */ | ||
1611 | list_for_each(ptr, &priv->bss_wpa_list) { | ||
1612 | bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); | ||
1613 | if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { | ||
1614 | list_move(&bss->list, &priv->bss_wpa_list); | ||
1615 | break; | ||
1616 | } | ||
1617 | bss = NULL; | ||
1618 | } | ||
1619 | |||
1620 | if (bss == NULL) { | ||
1621 | /* add a new BSS entry; if max number of entries is already | ||
1622 | * reached, replace the least recently updated */ | ||
1623 | if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { | ||
1624 | bss = list_entry(priv->bss_wpa_list.prev, | ||
1625 | struct islpci_bss_wpa_ie, list); | ||
1626 | list_del(&bss->list); | ||
1627 | } else { | ||
1628 | bss = kmalloc(sizeof (*bss), GFP_ATOMIC); | ||
1629 | if (bss != NULL) { | ||
1630 | priv->num_bss_wpa++; | ||
1631 | memset(bss, 0, sizeof (*bss)); | ||
1632 | } | ||
1633 | } | ||
1634 | if (bss != NULL) { | ||
1635 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
1636 | list_add(&bss->list, &priv->bss_wpa_list); | ||
1637 | } | ||
1638 | } | ||
1639 | |||
1640 | if (bss != NULL) { | ||
1641 | memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); | ||
1642 | bss->wpa_ie_len = wpa_ie_len; | ||
1643 | bss->last_update = jiffies; | ||
1644 | } else { | ||
1645 | printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR | ||
1646 | "\n", MAC2STR(bssid)); | ||
1647 | } | ||
1648 | |||
1649 | /* expire old entries from WPA list */ | ||
1650 | while (priv->num_bss_wpa > 0) { | ||
1651 | bss = list_entry(priv->bss_wpa_list.prev, | ||
1652 | struct islpci_bss_wpa_ie, list); | ||
1653 | if (!time_after(jiffies, bss->last_update + 60 * HZ)) | ||
1654 | break; | ||
1655 | |||
1656 | list_del(&bss->list); | ||
1657 | priv->num_bss_wpa--; | ||
1658 | kfree(bss); | ||
1659 | } | ||
1660 | |||
1661 | up(&priv->wpa_sem); | ||
1662 | } | ||
1663 | |||
1664 | static size_t | ||
1665 | prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) | ||
1666 | { | ||
1667 | struct list_head *ptr; | ||
1668 | struct islpci_bss_wpa_ie *bss = NULL; | ||
1669 | size_t len = 0; | ||
1670 | |||
1671 | if (down_interruptible(&priv->wpa_sem)) | ||
1672 | return 0; | ||
1673 | |||
1674 | list_for_each(ptr, &priv->bss_wpa_list) { | ||
1675 | bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); | ||
1676 | if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) | ||
1677 | break; | ||
1678 | bss = NULL; | ||
1679 | } | ||
1680 | if (bss) { | ||
1681 | len = bss->wpa_ie_len; | ||
1682 | memcpy(wpa_ie, bss->wpa_ie, len); | ||
1683 | } | ||
1684 | up(&priv->wpa_sem); | ||
1685 | |||
1686 | return len; | ||
1687 | } | ||
1688 | |||
1689 | void | ||
1690 | prism54_wpa_ie_init(islpci_private *priv) | ||
1691 | { | ||
1692 | INIT_LIST_HEAD(&priv->bss_wpa_list); | ||
1693 | sema_init(&priv->wpa_sem, 1); | ||
1694 | } | ||
1695 | |||
1696 | void | ||
1697 | prism54_wpa_ie_clean(islpci_private *priv) | ||
1698 | { | ||
1699 | struct list_head *ptr, *n; | ||
1700 | |||
1701 | list_for_each_safe(ptr, n, &priv->bss_wpa_list) { | ||
1702 | struct islpci_bss_wpa_ie *bss; | ||
1703 | bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); | ||
1704 | kfree(bss); | ||
1705 | } | ||
1706 | } | ||
1707 | |||
1708 | static void | ||
1709 | prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, | ||
1710 | u8 *payload, size_t len) | ||
1711 | { | ||
1712 | struct ieee80211_beacon_phdr *hdr; | ||
1713 | u8 *pos, *end; | ||
1714 | |||
1715 | if (!priv->wpa) | ||
1716 | return; | ||
1717 | |||
1718 | hdr = (struct ieee80211_beacon_phdr *) payload; | ||
1719 | pos = (u8 *) (hdr + 1); | ||
1720 | end = payload + len; | ||
1721 | while (pos < end) { | ||
1722 | if (pos + 2 + pos[1] > end) { | ||
1723 | printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " | ||
1724 | "for " MACSTR "\n", MAC2STR(addr)); | ||
1725 | return; | ||
1726 | } | ||
1727 | if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && | ||
1728 | memcmp(pos + 2, wpa_oid, 4) == 0) { | ||
1729 | prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); | ||
1730 | return; | ||
1731 | } | ||
1732 | pos += 2 + pos[1]; | ||
1733 | } | ||
1734 | } | ||
1735 | |||
1736 | static void | ||
1737 | handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) | ||
1738 | { | ||
1739 | if (((mlme->state == DOT11_STATE_AUTHING) || | ||
1740 | (mlme->state == DOT11_STATE_ASSOCING)) | ||
1741 | && mgt_mlme_answer(priv)) { | ||
1742 | /* Someone is requesting auth and we must respond. Just send back | ||
1743 | * the trap with error code set accordingly. | ||
1744 | */ | ||
1745 | mlme->code = prism54_mac_accept(&priv->acl, | ||
1746 | mlme->address) ? 0 : 1; | ||
1747 | mgt_set_request(priv, oid, 0, mlme); | ||
1748 | } | ||
1749 | } | ||
1750 | |||
1751 | static int | ||
1752 | prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, | ||
1753 | char *data) | ||
1754 | { | ||
1755 | struct obj_mlme *mlme = (struct obj_mlme *) data; | ||
1756 | struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data; | ||
1757 | struct obj_mlmeex *confirm; | ||
1758 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
1759 | int wpa_ie_len; | ||
1760 | size_t len = 0; /* u16, better? */ | ||
1761 | u8 *payload = NULL, *pos = NULL; | ||
1762 | int ret; | ||
1763 | |||
1764 | /* I think all trapable objects are listed here. | ||
1765 | * Some oids have a EX version. The difference is that they are emitted | ||
1766 | * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) | ||
1767 | * with more info. | ||
1768 | * The few events already defined by the wireless tools are not really | ||
1769 | * suited. We use the more flexible custom event facility. | ||
1770 | */ | ||
1771 | |||
1772 | if (oid >= DOT11_OID_BEACON) { | ||
1773 | len = mlmeex->size; | ||
1774 | payload = pos = mlmeex->data; | ||
1775 | } | ||
1776 | |||
1777 | /* I fear prism54_process_bss_data won't work with big endian data */ | ||
1778 | if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) | ||
1779 | prism54_process_bss_data(priv, oid, mlmeex->address, | ||
1780 | payload, len); | ||
1781 | |||
1782 | mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); | ||
1783 | |||
1784 | switch (oid) { | ||
1785 | |||
1786 | case GEN_OID_LINKSTATE: | ||
1787 | link_changed(priv->ndev, (u32) *data); | ||
1788 | break; | ||
1789 | |||
1790 | case DOT11_OID_MICFAILURE: | ||
1791 | send_simple_event(priv, "Mic failure"); | ||
1792 | break; | ||
1793 | |||
1794 | case DOT11_OID_DEAUTHENTICATE: | ||
1795 | send_formatted_event(priv, "DeAuthenticate request", mlme, 0); | ||
1796 | break; | ||
1797 | |||
1798 | case DOT11_OID_AUTHENTICATE: | ||
1799 | handle_request(priv, mlme, oid); | ||
1800 | send_formatted_event(priv, "Authenticate request", mlme, 1); | ||
1801 | break; | ||
1802 | |||
1803 | case DOT11_OID_DISASSOCIATE: | ||
1804 | send_formatted_event(priv, "Disassociate request", mlme, 0); | ||
1805 | break; | ||
1806 | |||
1807 | case DOT11_OID_ASSOCIATE: | ||
1808 | handle_request(priv, mlme, oid); | ||
1809 | send_formatted_event(priv, "Associate request", mlme, 1); | ||
1810 | break; | ||
1811 | |||
1812 | case DOT11_OID_REASSOCIATE: | ||
1813 | handle_request(priv, mlme, oid); | ||
1814 | send_formatted_event(priv, "ReAssociate request", mlme, 1); | ||
1815 | break; | ||
1816 | |||
1817 | case DOT11_OID_BEACON: | ||
1818 | send_formatted_event(priv, | ||
1819 | "Received a beacon from an unkown AP", | ||
1820 | mlme, 0); | ||
1821 | break; | ||
1822 | |||
1823 | case DOT11_OID_PROBE: | ||
1824 | /* we received a probe from a client. */ | ||
1825 | send_formatted_event(priv, "Received a probe from client", mlme, | ||
1826 | 0); | ||
1827 | break; | ||
1828 | |||
1829 | /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this | ||
1830 | * is backward compatible layout-wise with "struct obj_mlme". | ||
1831 | */ | ||
1832 | |||
1833 | case DOT11_OID_DEAUTHENTICATEEX: | ||
1834 | send_formatted_event(priv, "DeAuthenticate request", mlme, 0); | ||
1835 | break; | ||
1836 | |||
1837 | case DOT11_OID_AUTHENTICATEEX: | ||
1838 | handle_request(priv, mlme, oid); | ||
1839 | send_formatted_event(priv, "Authenticate request (ex)", mlme, 1); | ||
1840 | |||
1841 | if (priv->iw_mode != IW_MODE_MASTER | ||
1842 | && mlmeex->state != DOT11_STATE_AUTHING) | ||
1843 | break; | ||
1844 | |||
1845 | confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC); | ||
1846 | |||
1847 | if (!confirm) | ||
1848 | break; | ||
1849 | |||
1850 | memcpy(&confirm->address, mlmeex->address, ETH_ALEN); | ||
1851 | printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1852 | mlmeex->address[0], | ||
1853 | mlmeex->address[1], | ||
1854 | mlmeex->address[2], | ||
1855 | mlmeex->address[3], | ||
1856 | mlmeex->address[4], | ||
1857 | mlmeex->address[5] | ||
1858 | ); | ||
1859 | confirm->id = -1; /* or mlmeex->id ? */ | ||
1860 | confirm->state = 0; /* not used */ | ||
1861 | confirm->code = 0; | ||
1862 | confirm->size = 6; | ||
1863 | confirm->data[0] = 0x00; | ||
1864 | confirm->data[1] = 0x00; | ||
1865 | confirm->data[2] = 0x02; | ||
1866 | confirm->data[3] = 0x00; | ||
1867 | confirm->data[4] = 0x00; | ||
1868 | confirm->data[5] = 0x00; | ||
1869 | |||
1870 | ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6); | ||
1871 | |||
1872 | kfree(confirm); | ||
1873 | if (ret) | ||
1874 | return ret; | ||
1875 | break; | ||
1876 | |||
1877 | case DOT11_OID_DISASSOCIATEEX: | ||
1878 | send_formatted_event(priv, "Disassociate request (ex)", mlme, 0); | ||
1879 | break; | ||
1880 | |||
1881 | case DOT11_OID_ASSOCIATEEX: | ||
1882 | handle_request(priv, mlme, oid); | ||
1883 | send_formatted_event(priv, "Associate request (ex)", mlme, 1); | ||
1884 | |||
1885 | if (priv->iw_mode != IW_MODE_MASTER | ||
1886 | && mlmeex->state != DOT11_STATE_AUTHING) | ||
1887 | break; | ||
1888 | |||
1889 | confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); | ||
1890 | |||
1891 | if (!confirm) | ||
1892 | break; | ||
1893 | |||
1894 | memcpy(&confirm->address, mlmeex->address, ETH_ALEN); | ||
1895 | |||
1896 | confirm->id = ((struct obj_mlmeex *)mlme)->id; | ||
1897 | confirm->state = 0; /* not used */ | ||
1898 | confirm->code = 0; | ||
1899 | |||
1900 | wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); | ||
1901 | |||
1902 | if (!wpa_ie_len) { | ||
1903 | printk(KERN_DEBUG "No WPA IE found from " | ||
1904 | "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1905 | mlmeex->address[0], | ||
1906 | mlmeex->address[1], | ||
1907 | mlmeex->address[2], | ||
1908 | mlmeex->address[3], | ||
1909 | mlmeex->address[4], | ||
1910 | mlmeex->address[5] | ||
1911 | ); | ||
1912 | kfree(confirm); | ||
1913 | break; | ||
1914 | } | ||
1915 | |||
1916 | confirm->size = wpa_ie_len; | ||
1917 | memcpy(&confirm->data, wpa_ie, wpa_ie_len); | ||
1918 | |||
1919 | mgt_set_varlen(priv, oid, confirm, wpa_ie_len); | ||
1920 | |||
1921 | kfree(confirm); | ||
1922 | |||
1923 | break; | ||
1924 | |||
1925 | case DOT11_OID_REASSOCIATEEX: | ||
1926 | handle_request(priv, mlme, oid); | ||
1927 | send_formatted_event(priv, "Reassociate request (ex)", mlme, 1); | ||
1928 | |||
1929 | if (priv->iw_mode != IW_MODE_MASTER | ||
1930 | && mlmeex->state != DOT11_STATE_ASSOCING) | ||
1931 | break; | ||
1932 | |||
1933 | confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); | ||
1934 | |||
1935 | if (!confirm) | ||
1936 | break; | ||
1937 | |||
1938 | memcpy(&confirm->address, mlmeex->address, ETH_ALEN); | ||
1939 | |||
1940 | confirm->id = mlmeex->id; | ||
1941 | confirm->state = 0; /* not used */ | ||
1942 | confirm->code = 0; | ||
1943 | |||
1944 | wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); | ||
1945 | |||
1946 | if (!wpa_ie_len) { | ||
1947 | printk(KERN_DEBUG "No WPA IE found from " | ||
1948 | "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1949 | mlmeex->address[0], | ||
1950 | mlmeex->address[1], | ||
1951 | mlmeex->address[2], | ||
1952 | mlmeex->address[3], | ||
1953 | mlmeex->address[4], | ||
1954 | mlmeex->address[5] | ||
1955 | ); | ||
1956 | kfree(confirm); | ||
1957 | break; | ||
1958 | } | ||
1959 | |||
1960 | confirm->size = wpa_ie_len; | ||
1961 | memcpy(&confirm->data, wpa_ie, wpa_ie_len); | ||
1962 | |||
1963 | mgt_set_varlen(priv, oid, confirm, wpa_ie_len); | ||
1964 | |||
1965 | kfree(confirm); | ||
1966 | |||
1967 | break; | ||
1968 | |||
1969 | default: | ||
1970 | return -EINVAL; | ||
1971 | } | ||
1972 | |||
1973 | return 0; | ||
1974 | } | ||
1975 | |||
1976 | /* | ||
1977 | * Process a device trap. This is called via schedule_work(), outside of | ||
1978 | * interrupt context, no locks held. | ||
1979 | */ | ||
1980 | void | ||
1981 | prism54_process_trap(void *data) | ||
1982 | { | ||
1983 | struct islpci_mgmtframe *frame = data; | ||
1984 | struct net_device *ndev = frame->ndev; | ||
1985 | enum oid_num_t n = mgt_oidtonum(frame->header->oid); | ||
1986 | |||
1987 | if (n != OID_NUM_LAST) | ||
1988 | prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); | ||
1989 | islpci_mgt_release(frame); | ||
1990 | } | ||
1991 | |||
1992 | int | ||
1993 | prism54_set_mac_address(struct net_device *ndev, void *addr) | ||
1994 | { | ||
1995 | islpci_private *priv = netdev_priv(ndev); | ||
1996 | int ret; | ||
1997 | |||
1998 | if (ndev->addr_len != 6) | ||
1999 | return -EINVAL; | ||
2000 | ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, | ||
2001 | &((struct sockaddr *) addr)->sa_data); | ||
2002 | if (!ret) | ||
2003 | memcpy(priv->ndev->dev_addr, | ||
2004 | &((struct sockaddr *) addr)->sa_data, 6); | ||
2005 | |||
2006 | return ret; | ||
2007 | } | ||
2008 | |||
2009 | /* Note: currently, use hostapd ioctl from the Host AP driver for WPA | ||
2010 | * support. This is to be replaced with Linux wireless extensions once they | ||
2011 | * get WPA support. */ | ||
2012 | |||
2013 | /* Note II: please leave all this together as it will be easier to remove later, | ||
2014 | * once wireless extensions add WPA support -mcgrof */ | ||
2015 | |||
2016 | /* PRISM54_HOSTAPD ioctl() cmd: */ | ||
2017 | enum { | ||
2018 | PRISM2_SET_ENCRYPTION = 6, | ||
2019 | PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, | ||
2020 | PRISM2_HOSTAPD_MLME = 13, | ||
2021 | PRISM2_HOSTAPD_SCAN_REQ = 14, | ||
2022 | }; | ||
2023 | |||
2024 | #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 | ||
2025 | #define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25 | ||
2026 | #define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26 | ||
2027 | |||
2028 | #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 | ||
2029 | #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ | ||
2030 | ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) | ||
2031 | |||
2032 | /* Maximum length for algorithm names (-1 for nul termination) | ||
2033 | * used in ioctl() */ | ||
2034 | #define HOSTAP_CRYPT_ALG_NAME_LEN 16 | ||
2035 | |||
2036 | struct prism2_hostapd_param { | ||
2037 | u32 cmd; | ||
2038 | u8 sta_addr[ETH_ALEN]; | ||
2039 | union { | ||
2040 | struct { | ||
2041 | u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; | ||
2042 | u32 flags; | ||
2043 | u32 err; | ||
2044 | u8 idx; | ||
2045 | u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | ||
2046 | u16 key_len; | ||
2047 | u8 key[0]; | ||
2048 | } crypt; | ||
2049 | struct { | ||
2050 | u8 len; | ||
2051 | u8 data[0]; | ||
2052 | } generic_elem; | ||
2053 | struct { | ||
2054 | #define MLME_STA_DEAUTH 0 | ||
2055 | #define MLME_STA_DISASSOC 1 | ||
2056 | u16 cmd; | ||
2057 | u16 reason_code; | ||
2058 | } mlme; | ||
2059 | struct { | ||
2060 | u8 ssid_len; | ||
2061 | u8 ssid[32]; | ||
2062 | } scan_req; | ||
2063 | } u; | ||
2064 | }; | ||
2065 | |||
2066 | |||
2067 | static int | ||
2068 | prism2_ioctl_set_encryption(struct net_device *dev, | ||
2069 | struct prism2_hostapd_param *param, | ||
2070 | int param_len) | ||
2071 | { | ||
2072 | islpci_private *priv = netdev_priv(dev); | ||
2073 | int rvalue = 0, force = 0; | ||
2074 | int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; | ||
2075 | union oid_res_t r; | ||
2076 | |||
2077 | /* with the new API, it's impossible to get a NULL pointer. | ||
2078 | * New version of iwconfig set the IW_ENCODE_NOKEY flag | ||
2079 | * when no key is given, but older versions don't. */ | ||
2080 | |||
2081 | if (param->u.crypt.key_len > 0) { | ||
2082 | /* we have a key to set */ | ||
2083 | int index = param->u.crypt.idx; | ||
2084 | int current_index; | ||
2085 | struct obj_key key = { DOT11_PRIV_TKIP, 0, "" }; | ||
2086 | |||
2087 | /* get the current key index */ | ||
2088 | rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); | ||
2089 | current_index = r.u; | ||
2090 | /* Verify that the key is not marked as invalid */ | ||
2091 | if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) { | ||
2092 | key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ? | ||
2093 | sizeof (param->u.crypt.key) : param->u.crypt.key_len; | ||
2094 | memcpy(key.key, param->u.crypt.key, key.length); | ||
2095 | if (key.length == 32) | ||
2096 | /* we want WPA-PSK */ | ||
2097 | key.type = DOT11_PRIV_TKIP; | ||
2098 | if ((index < 0) || (index > 3)) | ||
2099 | /* no index provided use the current one */ | ||
2100 | index = current_index; | ||
2101 | |||
2102 | /* now send the key to the card */ | ||
2103 | rvalue |= | ||
2104 | mgt_set_request(priv, DOT11_OID_DEFKEYX, index, | ||
2105 | &key); | ||
2106 | } | ||
2107 | /* | ||
2108 | * If a valid key is set, encryption should be enabled | ||
2109 | * (user may turn it off later). | ||
2110 | * This is also how "iwconfig ethX key on" works | ||
2111 | */ | ||
2112 | if ((index == current_index) && (key.length > 0)) | ||
2113 | force = 1; | ||
2114 | } else { | ||
2115 | int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1; | ||
2116 | if ((index >= 0) && (index <= 3)) { | ||
2117 | /* we want to set the key index */ | ||
2118 | rvalue |= | ||
2119 | mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, | ||
2120 | &index); | ||
2121 | } else { | ||
2122 | if (!param->u.crypt.flags & IW_ENCODE_MODE) { | ||
2123 | /* we cannot do anything. Complain. */ | ||
2124 | return -EINVAL; | ||
2125 | } | ||
2126 | } | ||
2127 | } | ||
2128 | /* now read the flags */ | ||
2129 | if (param->u.crypt.flags & IW_ENCODE_DISABLED) { | ||
2130 | /* Encoding disabled, | ||
2131 | * authen = DOT11_AUTH_OS; | ||
2132 | * invoke = 0; | ||
2133 | * exunencrypt = 0; */ | ||
2134 | } | ||
2135 | if (param->u.crypt.flags & IW_ENCODE_OPEN) | ||
2136 | /* Encode but accept non-encoded packets. No auth */ | ||
2137 | invoke = 1; | ||
2138 | if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) { | ||
2139 | /* Refuse non-encoded packets. Auth */ | ||
2140 | authen = DOT11_AUTH_BOTH; | ||
2141 | invoke = 1; | ||
2142 | exunencrypt = 1; | ||
2143 | } | ||
2144 | /* do the change if requested */ | ||
2145 | if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) { | ||
2146 | rvalue |= | ||
2147 | mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); | ||
2148 | rvalue |= | ||
2149 | mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); | ||
2150 | rvalue |= | ||
2151 | mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, | ||
2152 | &exunencrypt); | ||
2153 | } | ||
2154 | return rvalue; | ||
2155 | } | ||
2156 | |||
2157 | static int | ||
2158 | prism2_ioctl_set_generic_element(struct net_device *ndev, | ||
2159 | struct prism2_hostapd_param *param, | ||
2160 | int param_len) | ||
2161 | { | ||
2162 | islpci_private *priv = netdev_priv(ndev); | ||
2163 | int max_len, len, alen, ret=0; | ||
2164 | struct obj_attachment *attach; | ||
2165 | |||
2166 | len = param->u.generic_elem.len; | ||
2167 | max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; | ||
2168 | if (max_len < 0 || max_len < len) | ||
2169 | return -EINVAL; | ||
2170 | |||
2171 | alen = sizeof(*attach) + len; | ||
2172 | attach = kmalloc(alen, GFP_KERNEL); | ||
2173 | if (attach == NULL) | ||
2174 | return -ENOMEM; | ||
2175 | |||
2176 | memset(attach, 0, alen); | ||
2177 | #define WLAN_FC_TYPE_MGMT 0 | ||
2178 | #define WLAN_FC_STYPE_ASSOC_REQ 0 | ||
2179 | #define WLAN_FC_STYPE_REASSOC_REQ 2 | ||
2180 | |||
2181 | /* Note: endianness is covered by mgt_set_varlen */ | ||
2182 | |||
2183 | attach->type = (WLAN_FC_TYPE_MGMT << 2) | | ||
2184 | (WLAN_FC_STYPE_ASSOC_REQ << 4); | ||
2185 | attach->id = -1; | ||
2186 | attach->size = len; | ||
2187 | memcpy(attach->data, param->u.generic_elem.data, len); | ||
2188 | |||
2189 | ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); | ||
2190 | |||
2191 | if (ret == 0) { | ||
2192 | attach->type = (WLAN_FC_TYPE_MGMT << 2) | | ||
2193 | (WLAN_FC_STYPE_REASSOC_REQ << 4); | ||
2194 | |||
2195 | ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); | ||
2196 | |||
2197 | if (ret == 0) | ||
2198 | printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", | ||
2199 | ndev->name); | ||
2200 | } | ||
2201 | |||
2202 | kfree(attach); | ||
2203 | return ret; | ||
2204 | |||
2205 | } | ||
2206 | |||
2207 | static int | ||
2208 | prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param) | ||
2209 | { | ||
2210 | return -EOPNOTSUPP; | ||
2211 | } | ||
2212 | |||
2213 | static int | ||
2214 | prism2_ioctl_scan_req(struct net_device *ndev, | ||
2215 | struct prism2_hostapd_param *param) | ||
2216 | { | ||
2217 | islpci_private *priv = netdev_priv(ndev); | ||
2218 | int i, rvalue; | ||
2219 | struct obj_bsslist *bsslist; | ||
2220 | u32 noise = 0; | ||
2221 | char *extra = ""; | ||
2222 | char *current_ev = "foo"; | ||
2223 | union oid_res_t r; | ||
2224 | |||
2225 | if (islpci_get_state(priv) < PRV_STATE_INIT) { | ||
2226 | /* device is not ready, fail gently */ | ||
2227 | return 0; | ||
2228 | } | ||
2229 | |||
2230 | /* first get the noise value. We will use it to report the link quality */ | ||
2231 | rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); | ||
2232 | noise = r.u; | ||
2233 | |||
2234 | /* Ask the device for a list of known bss. We can report at most | ||
2235 | * IW_MAX_AP=64 to the range struct. But the device won't repport anything | ||
2236 | * if you change the value of IWMAX_BSS=24. | ||
2237 | */ | ||
2238 | rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); | ||
2239 | bsslist = r.ptr; | ||
2240 | |||
2241 | /* ok now, scan the list and translate its info */ | ||
2242 | for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) | ||
2243 | current_ev = prism54_translate_bss(ndev, current_ev, | ||
2244 | extra + IW_SCAN_MAX_DATA, | ||
2245 | &(bsslist->bsslist[i]), | ||
2246 | noise); | ||
2247 | kfree(bsslist); | ||
2248 | |||
2249 | return rvalue; | ||
2250 | } | ||
2251 | |||
2252 | static int | ||
2253 | prism54_hostapd(struct net_device *ndev, struct iw_point *p) | ||
2254 | { | ||
2255 | struct prism2_hostapd_param *param; | ||
2256 | int ret = 0; | ||
2257 | u32 uwrq; | ||
2258 | |||
2259 | printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length); | ||
2260 | if (p->length < sizeof(struct prism2_hostapd_param) || | ||
2261 | p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) | ||
2262 | return -EINVAL; | ||
2263 | |||
2264 | param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); | ||
2265 | if (param == NULL) | ||
2266 | return -ENOMEM; | ||
2267 | |||
2268 | if (copy_from_user(param, p->pointer, p->length)) { | ||
2269 | kfree(param); | ||
2270 | return -EFAULT; | ||
2271 | } | ||
2272 | |||
2273 | switch (param->cmd) { | ||
2274 | case PRISM2_SET_ENCRYPTION: | ||
2275 | printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n", | ||
2276 | ndev->name); | ||
2277 | ret = prism2_ioctl_set_encryption(ndev, param, p->length); | ||
2278 | break; | ||
2279 | case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: | ||
2280 | printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n", | ||
2281 | ndev->name); | ||
2282 | ret = prism2_ioctl_set_generic_element(ndev, param, | ||
2283 | p->length); | ||
2284 | break; | ||
2285 | case PRISM2_HOSTAPD_MLME: | ||
2286 | printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n", | ||
2287 | ndev->name); | ||
2288 | ret = prism2_ioctl_mlme(ndev, param); | ||
2289 | break; | ||
2290 | case PRISM2_HOSTAPD_SCAN_REQ: | ||
2291 | printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n", | ||
2292 | ndev->name); | ||
2293 | ret = prism2_ioctl_scan_req(ndev, param); | ||
2294 | break; | ||
2295 | case PRISM54_SET_WPA: | ||
2296 | printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n", | ||
2297 | ndev->name); | ||
2298 | uwrq = 1; | ||
2299 | ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL); | ||
2300 | break; | ||
2301 | case PRISM54_DROP_UNENCRYPTED: | ||
2302 | printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n", | ||
2303 | ndev->name); | ||
2304 | #if 0 | ||
2305 | uwrq = 0x01; | ||
2306 | mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq); | ||
2307 | down_write(&priv->mib_sem); | ||
2308 | mgt_commit(priv); | ||
2309 | up_write(&priv->mib_sem); | ||
2310 | #endif | ||
2311 | /* Not necessary, as set_wpa does it, should we just do it here though? */ | ||
2312 | ret = 0; | ||
2313 | break; | ||
2314 | default: | ||
2315 | printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n", | ||
2316 | ndev->name); | ||
2317 | ret = -EOPNOTSUPP; | ||
2318 | break; | ||
2319 | } | ||
2320 | |||
2321 | if (ret == 0 && copy_to_user(p->pointer, param, p->length)) | ||
2322 | ret = -EFAULT; | ||
2323 | |||
2324 | kfree(param); | ||
2325 | |||
2326 | return ret; | ||
2327 | } | ||
2328 | |||
2329 | static int | ||
2330 | prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, | ||
2331 | __u32 * uwrq, char *extra) | ||
2332 | { | ||
2333 | islpci_private *priv = netdev_priv(ndev); | ||
2334 | u32 mlme, authen, dot1x, filter, wep; | ||
2335 | |||
2336 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
2337 | return 0; | ||
2338 | |||
2339 | wep = 1; /* For privacy invoked */ | ||
2340 | filter = 1; /* Filter out all unencrypted frames */ | ||
2341 | dot1x = 0x01; /* To enable eap filter */ | ||
2342 | mlme = DOT11_MLME_EXTENDED; | ||
2343 | authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ | ||
2344 | |||
2345 | down_write(&priv->mib_sem); | ||
2346 | priv->wpa = *uwrq; | ||
2347 | |||
2348 | switch (priv->wpa) { | ||
2349 | default: | ||
2350 | case 0: /* Clears/disables WPA and friends */ | ||
2351 | wep = 0; | ||
2352 | filter = 0; /* Do not filter un-encrypted data */ | ||
2353 | dot1x = 0; | ||
2354 | mlme = DOT11_MLME_AUTO; | ||
2355 | printk("%s: Disabling WPA\n", ndev->name); | ||
2356 | break; | ||
2357 | case 2: | ||
2358 | case 1: /* WPA */ | ||
2359 | printk("%s: Enabling WPA\n", ndev->name); | ||
2360 | break; | ||
2361 | } | ||
2362 | up_write(&priv->mib_sem); | ||
2363 | |||
2364 | mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); | ||
2365 | mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); | ||
2366 | mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); | ||
2367 | mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); | ||
2368 | mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); | ||
2369 | |||
2370 | return 0; | ||
2371 | } | ||
2372 | |||
2373 | static int | ||
2374 | prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, | ||
2375 | __u32 * uwrq, char *extra) | ||
2376 | { | ||
2377 | islpci_private *priv = netdev_priv(ndev); | ||
2378 | *uwrq = priv->wpa; | ||
2379 | return 0; | ||
2380 | } | ||
2381 | |||
2382 | static int | ||
2383 | prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, | ||
2384 | __u32 * uwrq, char *extra) | ||
2385 | { | ||
2386 | islpci_private *priv = netdev_priv(ndev); | ||
2387 | priv->monitor_type = | ||
2388 | (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); | ||
2389 | if (priv->iw_mode == IW_MODE_MONITOR) | ||
2390 | priv->ndev->type = priv->monitor_type; | ||
2391 | |||
2392 | return 0; | ||
2393 | } | ||
2394 | |||
2395 | static int | ||
2396 | prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, | ||
2397 | __u32 * uwrq, char *extra) | ||
2398 | { | ||
2399 | islpci_private *priv = netdev_priv(ndev); | ||
2400 | *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); | ||
2401 | return 0; | ||
2402 | } | ||
2403 | |||
2404 | static int | ||
2405 | prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, | ||
2406 | __u32 * uwrq, char *extra) | ||
2407 | { | ||
2408 | islpci_private *priv = netdev_priv(ndev); | ||
2409 | |||
2410 | priv->priv_oid = *uwrq; | ||
2411 | printk("%s: oid 0x%08X\n", ndev->name, *uwrq); | ||
2412 | |||
2413 | return 0; | ||
2414 | } | ||
2415 | |||
2416 | static int | ||
2417 | prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, | ||
2418 | struct iw_point *data, char *extra) | ||
2419 | { | ||
2420 | islpci_private *priv = netdev_priv(ndev); | ||
2421 | struct islpci_mgmtframe *response; | ||
2422 | int ret = -EIO; | ||
2423 | |||
2424 | printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); | ||
2425 | data->length = 0; | ||
2426 | |||
2427 | if (islpci_get_state(priv) >= PRV_STATE_INIT) { | ||
2428 | ret = | ||
2429 | islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, | ||
2430 | priv->priv_oid, extra, 256, | ||
2431 | &response); | ||
2432 | printk("%s: ret: %i\n", ndev->name, ret); | ||
2433 | if (ret || !response | ||
2434 | || response->header->operation == PIMFOR_OP_ERROR) { | ||
2435 | if (response) { | ||
2436 | islpci_mgt_release(response); | ||
2437 | } | ||
2438 | printk("%s: EIO\n", ndev->name); | ||
2439 | ret = -EIO; | ||
2440 | } | ||
2441 | if (!ret) { | ||
2442 | data->length = response->header->length; | ||
2443 | memcpy(extra, response->data, data->length); | ||
2444 | islpci_mgt_release(response); | ||
2445 | printk("%s: len: %i\n", ndev->name, data->length); | ||
2446 | } | ||
2447 | } | ||
2448 | |||
2449 | return ret; | ||
2450 | } | ||
2451 | |||
2452 | static int | ||
2453 | prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, | ||
2454 | struct iw_point *data, char *extra) | ||
2455 | { | ||
2456 | islpci_private *priv = netdev_priv(ndev); | ||
2457 | struct islpci_mgmtframe *response; | ||
2458 | int ret = 0, response_op = PIMFOR_OP_ERROR; | ||
2459 | |||
2460 | printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, | ||
2461 | data->length); | ||
2462 | |||
2463 | if (islpci_get_state(priv) >= PRV_STATE_INIT) { | ||
2464 | ret = | ||
2465 | islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, | ||
2466 | priv->priv_oid, extra, data->length, | ||
2467 | &response); | ||
2468 | printk("%s: ret: %i\n", ndev->name, ret); | ||
2469 | if (ret || !response | ||
2470 | || response->header->operation == PIMFOR_OP_ERROR) { | ||
2471 | if (response) { | ||
2472 | islpci_mgt_release(response); | ||
2473 | } | ||
2474 | printk("%s: EIO\n", ndev->name); | ||
2475 | ret = -EIO; | ||
2476 | } | ||
2477 | if (!ret) { | ||
2478 | response_op = response->header->operation; | ||
2479 | printk("%s: response_op: %i\n", ndev->name, | ||
2480 | response_op); | ||
2481 | islpci_mgt_release(response); | ||
2482 | } | ||
2483 | } | ||
2484 | |||
2485 | return (ret ? ret : -EINPROGRESS); | ||
2486 | } | ||
2487 | |||
2488 | static int | ||
2489 | prism54_set_spy(struct net_device *ndev, | ||
2490 | struct iw_request_info *info, | ||
2491 | union iwreq_data *uwrq, char *extra) | ||
2492 | { | ||
2493 | islpci_private *priv = netdev_priv(ndev); | ||
2494 | u32 u, oid = OID_INL_CONFIG; | ||
2495 | |||
2496 | down_write(&priv->mib_sem); | ||
2497 | mgt_get(priv, OID_INL_CONFIG, &u); | ||
2498 | |||
2499 | if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) | ||
2500 | /* disable spy */ | ||
2501 | u &= ~INL_CONFIG_RXANNEX; | ||
2502 | else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) | ||
2503 | /* enable spy */ | ||
2504 | u |= INL_CONFIG_RXANNEX; | ||
2505 | |||
2506 | mgt_set(priv, OID_INL_CONFIG, &u); | ||
2507 | mgt_commit_list(priv, &oid, 1); | ||
2508 | up_write(&priv->mib_sem); | ||
2509 | |||
2510 | return iw_handler_set_spy(ndev, info, uwrq, extra); | ||
2511 | } | ||
2512 | |||
2513 | static const iw_handler prism54_handler[] = { | ||
2514 | (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ | ||
2515 | (iw_handler) prism54_get_name, /* SIOCGIWNAME */ | ||
2516 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
2517 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
2518 | (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ | ||
2519 | (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ | ||
2520 | (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ | ||
2521 | (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ | ||
2522 | (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ | ||
2523 | (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ | ||
2524 | (iw_handler) NULL, /* SIOCSIWRANGE */ | ||
2525 | (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ | ||
2526 | (iw_handler) NULL, /* SIOCSIWPRIV */ | ||
2527 | (iw_handler) NULL, /* SIOCGIWPRIV */ | ||
2528 | (iw_handler) NULL, /* SIOCSIWSTATS */ | ||
2529 | (iw_handler) NULL, /* SIOCGIWSTATS */ | ||
2530 | prism54_set_spy, /* SIOCSIWSPY */ | ||
2531 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2532 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2533 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2534 | (iw_handler) prism54_set_wap, /* SIOCSIWAP */ | ||
2535 | (iw_handler) prism54_get_wap, /* SIOCGIWAP */ | ||
2536 | (iw_handler) NULL, /* -- hole -- */ | ||
2537 | (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */ | ||
2538 | (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ | ||
2539 | (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ | ||
2540 | (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ | ||
2541 | (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ | ||
2542 | (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ | ||
2543 | (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ | ||
2544 | (iw_handler) NULL, /* -- hole -- */ | ||
2545 | (iw_handler) NULL, /* -- hole -- */ | ||
2546 | (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ | ||
2547 | (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ | ||
2548 | (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ | ||
2549 | (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ | ||
2550 | (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ | ||
2551 | (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ | ||
2552 | (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ | ||
2553 | (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ | ||
2554 | (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ | ||
2555 | (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ | ||
2556 | (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ | ||
2557 | (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ | ||
2558 | (iw_handler) NULL, /* SIOCSIWPOWER */ | ||
2559 | (iw_handler) NULL, /* SIOCGIWPOWER */ | ||
2560 | }; | ||
2561 | |||
2562 | /* The low order bit identify a SET (0) or a GET (1) ioctl. */ | ||
2563 | |||
2564 | #define PRISM54_RESET SIOCIWFIRSTPRIV | ||
2565 | #define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1 | ||
2566 | #define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2 | ||
2567 | #define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3 | ||
2568 | #define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4 | ||
2569 | |||
2570 | #define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6 | ||
2571 | |||
2572 | #define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8 | ||
2573 | |||
2574 | #define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10 | ||
2575 | |||
2576 | #define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11 | ||
2577 | #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 | ||
2578 | |||
2579 | #define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14 | ||
2580 | #define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15 | ||
2581 | #define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16 | ||
2582 | |||
2583 | #define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 | ||
2584 | #define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18 | ||
2585 | #define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20 | ||
2586 | #define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22 | ||
2587 | |||
2588 | #define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23 | ||
2589 | #define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24 | ||
2590 | |||
2591 | #define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } | ||
2592 | #define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } | ||
2593 | #define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } | ||
2594 | #define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x } | ||
2595 | |||
2596 | #define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x) | ||
2597 | #define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x) | ||
2598 | #define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x) | ||
2599 | |||
2600 | /* Note : limited to 128 private ioctls (wireless tools 26) */ | ||
2601 | |||
2602 | static const struct iw_priv_args prism54_private_args[] = { | ||
2603 | /*{ cmd, set_args, get_args, name } */ | ||
2604 | {PRISM54_RESET, 0, 0, "reset"}, | ||
2605 | {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
2606 | "get_prismhdr"}, | ||
2607 | {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2608 | "set_prismhdr"}, | ||
2609 | {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
2610 | "getPolicy"}, | ||
2611 | {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2612 | "setPolicy"}, | ||
2613 | {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, | ||
2614 | {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2615 | "addMac"}, | ||
2616 | {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2617 | "delMac"}, | ||
2618 | {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2619 | "kickMac"}, | ||
2620 | {PRISM54_KICK_ALL, 0, 0, "kickAll"}, | ||
2621 | {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
2622 | "get_wpa"}, | ||
2623 | {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2624 | "set_wpa"}, | ||
2625 | {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, | ||
2626 | "dbg_oid"}, | ||
2627 | {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"}, | ||
2628 | {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"}, | ||
2629 | /* --- sub-ioctls handlers --- */ | ||
2630 | {PRISM54_GET_OID, | ||
2631 | 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""}, | ||
2632 | {PRISM54_SET_OID_U32, | ||
2633 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, | ||
2634 | {PRISM54_SET_OID_STR, | ||
2635 | IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, | ||
2636 | {PRISM54_SET_OID_ADDR, | ||
2637 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, | ||
2638 | /* --- sub-ioctls definitions --- */ | ||
2639 | IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"), | ||
2640 | IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"), | ||
2641 | IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"), | ||
2642 | IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"), | ||
2643 | IWPRIV_U32(DOT11_OID_STATE, "state"), | ||
2644 | IWPRIV_U32(DOT11_OID_AID, "aid"), | ||
2645 | |||
2646 | IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"), | ||
2647 | |||
2648 | IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"), | ||
2649 | IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"), | ||
2650 | IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"), | ||
2651 | |||
2652 | IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"), | ||
2653 | IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"), | ||
2654 | IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"), | ||
2655 | |||
2656 | IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"), | ||
2657 | |||
2658 | IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"), | ||
2659 | IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"), | ||
2660 | IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"), | ||
2661 | IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"), | ||
2662 | IWPRIV_U32(DOT11_OID_PSM, "psm"), | ||
2663 | |||
2664 | IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"), | ||
2665 | IWPRIV_U32(DOT11_OID_CLIENTS, "clients"), | ||
2666 | IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"), | ||
2667 | IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"), | ||
2668 | IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"), | ||
2669 | IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"), | ||
2670 | IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"), | ||
2671 | IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"), | ||
2672 | IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"), | ||
2673 | IWPRIV_GET(DOT11_OID_RATES, "rates"), | ||
2674 | IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"), | ||
2675 | IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"), | ||
2676 | IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"), | ||
2677 | |||
2678 | IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"), | ||
2679 | IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"), | ||
2680 | IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"), | ||
2681 | IWPRIV_U32(DOT11_OID_PROFILES, "profile"), | ||
2682 | IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"), | ||
2683 | IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"), | ||
2684 | |||
2685 | IWPRIV_GET(DOT11_OID_BSSS, "bsss"), | ||
2686 | IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"), | ||
2687 | IWPRIV_U32(OID_INL_MODE, "mode"), | ||
2688 | IWPRIV_U32(OID_INL_CONFIG, "config"), | ||
2689 | IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"), | ||
2690 | IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"), | ||
2691 | IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"), | ||
2692 | }; | ||
2693 | |||
2694 | static const iw_handler prism54_private_handler[] = { | ||
2695 | (iw_handler) prism54_reset, | ||
2696 | (iw_handler) prism54_get_policy, | ||
2697 | (iw_handler) prism54_set_policy, | ||
2698 | (iw_handler) prism54_get_mac, | ||
2699 | (iw_handler) prism54_add_mac, | ||
2700 | (iw_handler) NULL, | ||
2701 | (iw_handler) prism54_del_mac, | ||
2702 | (iw_handler) NULL, | ||
2703 | (iw_handler) prism54_kick_mac, | ||
2704 | (iw_handler) NULL, | ||
2705 | (iw_handler) prism54_kick_all, | ||
2706 | (iw_handler) prism54_get_wpa, | ||
2707 | (iw_handler) prism54_set_wpa, | ||
2708 | (iw_handler) NULL, | ||
2709 | (iw_handler) prism54_debug_oid, | ||
2710 | (iw_handler) prism54_debug_get_oid, | ||
2711 | (iw_handler) prism54_debug_set_oid, | ||
2712 | (iw_handler) prism54_get_oid, | ||
2713 | (iw_handler) prism54_set_u32, | ||
2714 | (iw_handler) NULL, | ||
2715 | (iw_handler) prism54_set_raw, | ||
2716 | (iw_handler) NULL, | ||
2717 | (iw_handler) prism54_set_raw, | ||
2718 | (iw_handler) prism54_get_prismhdr, | ||
2719 | (iw_handler) prism54_set_prismhdr, | ||
2720 | }; | ||
2721 | |||
2722 | const struct iw_handler_def prism54_handler_def = { | ||
2723 | .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), | ||
2724 | .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), | ||
2725 | .num_private_args = | ||
2726 | sizeof (prism54_private_args) / sizeof (struct iw_priv_args), | ||
2727 | .standard = (iw_handler *) prism54_handler, | ||
2728 | .private = (iw_handler *) prism54_private_handler, | ||
2729 | .private_args = (struct iw_priv_args *) prism54_private_args, | ||
2730 | #if WIRELESS_EXT == 16 | ||
2731 | .spy_offset = offsetof(islpci_private, spy_data), | ||
2732 | #endif /* WIRELESS_EXT == 16 */ | ||
2733 | }; | ||
2734 | |||
2735 | /* For wpa_supplicant */ | ||
2736 | |||
2737 | int | ||
2738 | prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) | ||
2739 | { | ||
2740 | struct iwreq *wrq = (struct iwreq *) rq; | ||
2741 | int ret = -1; | ||
2742 | switch (cmd) { | ||
2743 | case PRISM54_HOSTAPD: | ||
2744 | if (!capable(CAP_NET_ADMIN)) | ||
2745 | return -EPERM; | ||
2746 | ret = prism54_hostapd(ndev, &wrq->u.data); | ||
2747 | return ret; | ||
2748 | } | ||
2749 | return -EOPNOTSUPP; | ||
2750 | } | ||
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h new file mode 100644 index 000000000000..46d5cde80c85 --- /dev/null +++ b/drivers/net/wireless/prism54/isl_ioctl.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * (C) 2003 Aurelien Alleaume <slts@free.fr> | ||
5 | * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> | ||
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 | ||
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 | #ifndef _ISL_IOCTL_H | ||
23 | #define _ISL_IOCTL_H | ||
24 | |||
25 | #include "islpci_mgt.h" | ||
26 | #include "islpci_dev.h" | ||
27 | |||
28 | #include <net/iw_handler.h> /* New driver API */ | ||
29 | |||
30 | #define SUPPORTED_WIRELESS_EXT 16 | ||
31 | |||
32 | void prism54_mib_init(islpci_private *); | ||
33 | |||
34 | struct iw_statistics *prism54_get_wireless_stats(struct net_device *); | ||
35 | void prism54_update_stats(islpci_private *); | ||
36 | |||
37 | void prism54_acl_init(struct islpci_acl *); | ||
38 | void prism54_acl_clean(struct islpci_acl *); | ||
39 | |||
40 | void prism54_process_trap(void *); | ||
41 | |||
42 | void prism54_wpa_ie_init(islpci_private *priv); | ||
43 | void prism54_wpa_ie_clean(islpci_private *priv); | ||
44 | |||
45 | int prism54_set_mac_address(struct net_device *, void *); | ||
46 | |||
47 | int prism54_ioctl(struct net_device *, struct ifreq *, int); | ||
48 | |||
49 | extern const struct iw_handler_def prism54_handler_def; | ||
50 | |||
51 | #endif /* _ISL_IOCTL_H */ | ||
diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h new file mode 100644 index 000000000000..419edf7ccf1a --- /dev/null +++ b/drivers/net/wireless/prism54/isl_oid.h | |||
@@ -0,0 +1,507 @@ | |||
1 | /* | ||
2 | * | ||
3 | * | ||
4 | * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> | ||
5 | * Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
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 | ||
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 | #if !defined(_ISL_OID_H) | ||
24 | #define _ISL_OID_H | ||
25 | |||
26 | /* | ||
27 | * MIB related constant and structure definitions for communicating | ||
28 | * with the device firmware | ||
29 | */ | ||
30 | |||
31 | struct obj_ssid { | ||
32 | u8 length; | ||
33 | char octets[33]; | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | struct obj_key { | ||
37 | u8 type; /* dot11_priv_t */ | ||
38 | u8 length; | ||
39 | char key[32]; | ||
40 | } __attribute__ ((packed)); | ||
41 | |||
42 | struct obj_mlme { | ||
43 | u8 address[6]; | ||
44 | u16 id; | ||
45 | u16 state; | ||
46 | u16 code; | ||
47 | } __attribute__ ((packed)); | ||
48 | |||
49 | struct obj_mlmeex { | ||
50 | u8 address[6]; | ||
51 | u16 id; | ||
52 | u16 state; | ||
53 | u16 code; | ||
54 | u16 size; | ||
55 | u8 data[0]; | ||
56 | } __attribute__ ((packed)); | ||
57 | |||
58 | struct obj_buffer { | ||
59 | u32 size; | ||
60 | u32 addr; /* 32bit bus address */ | ||
61 | } __attribute__ ((packed)); | ||
62 | |||
63 | struct obj_bss { | ||
64 | u8 address[6]; | ||
65 | int:16; /* padding */ | ||
66 | |||
67 | char state; | ||
68 | char reserved; | ||
69 | short age; | ||
70 | |||
71 | char quality; | ||
72 | char rssi; | ||
73 | |||
74 | struct obj_ssid ssid; | ||
75 | short channel; | ||
76 | char beacon_period; | ||
77 | char dtim_period; | ||
78 | short capinfo; | ||
79 | short rates; | ||
80 | short basic_rates; | ||
81 | int:16; /* padding */ | ||
82 | } __attribute__ ((packed)); | ||
83 | |||
84 | struct obj_bsslist { | ||
85 | u32 nr; | ||
86 | struct obj_bss bsslist[0]; | ||
87 | } __attribute__ ((packed)); | ||
88 | |||
89 | struct obj_frequencies { | ||
90 | u16 nr; | ||
91 | u16 mhz[0]; | ||
92 | } __attribute__ ((packed)); | ||
93 | |||
94 | struct obj_attachment { | ||
95 | char type; | ||
96 | char reserved; | ||
97 | short id; | ||
98 | short size; | ||
99 | char data[0]; | ||
100 | } __attribute__((packed)); | ||
101 | |||
102 | /* | ||
103 | * in case everything's ok, the inlined function below will be | ||
104 | * optimized away by the compiler... | ||
105 | */ | ||
106 | static inline void | ||
107 | __bug_on_wrong_struct_sizes(void) | ||
108 | { | ||
109 | BUG_ON(sizeof (struct obj_ssid) != 34); | ||
110 | BUG_ON(sizeof (struct obj_key) != 34); | ||
111 | BUG_ON(sizeof (struct obj_mlme) != 12); | ||
112 | BUG_ON(sizeof (struct obj_mlmeex) != 14); | ||
113 | BUG_ON(sizeof (struct obj_buffer) != 8); | ||
114 | BUG_ON(sizeof (struct obj_bss) != 60); | ||
115 | BUG_ON(sizeof (struct obj_bsslist) != 4); | ||
116 | BUG_ON(sizeof (struct obj_frequencies) != 2); | ||
117 | } | ||
118 | |||
119 | enum dot11_state_t { | ||
120 | DOT11_STATE_NONE = 0, | ||
121 | DOT11_STATE_AUTHING = 1, | ||
122 | DOT11_STATE_AUTH = 2, | ||
123 | DOT11_STATE_ASSOCING = 3, | ||
124 | |||
125 | DOT11_STATE_ASSOC = 5, | ||
126 | DOT11_STATE_IBSS = 6, | ||
127 | DOT11_STATE_WDS = 7 | ||
128 | }; | ||
129 | |||
130 | enum dot11_bsstype_t { | ||
131 | DOT11_BSSTYPE_NONE = 0, | ||
132 | DOT11_BSSTYPE_INFRA = 1, | ||
133 | DOT11_BSSTYPE_IBSS = 2, | ||
134 | DOT11_BSSTYPE_ANY = 3 | ||
135 | }; | ||
136 | |||
137 | enum dot11_auth_t { | ||
138 | DOT11_AUTH_NONE = 0, | ||
139 | DOT11_AUTH_OS = 1, | ||
140 | DOT11_AUTH_SK = 2, | ||
141 | DOT11_AUTH_BOTH = 3 | ||
142 | }; | ||
143 | |||
144 | enum dot11_mlme_t { | ||
145 | DOT11_MLME_AUTO = 0, | ||
146 | DOT11_MLME_INTERMEDIATE = 1, | ||
147 | DOT11_MLME_EXTENDED = 2 | ||
148 | }; | ||
149 | |||
150 | enum dot11_priv_t { | ||
151 | DOT11_PRIV_WEP = 0, | ||
152 | DOT11_PRIV_TKIP = 1 | ||
153 | }; | ||
154 | |||
155 | /* Prism "Nitro" / Frameburst / "Packet Frame Grouping" | ||
156 | * Value is in microseconds. Represents the # microseconds | ||
157 | * the firmware will take to group frames before sending out then out | ||
158 | * together with a CSMA contention. Without this all frames are | ||
159 | * sent with a CSMA contention. | ||
160 | * Bibliography: | ||
161 | * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html | ||
162 | */ | ||
163 | enum dot11_maxframeburst_t { | ||
164 | /* Values for DOT11_OID_MAXFRAMEBURST */ | ||
165 | DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */ | ||
166 | DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */ | ||
167 | DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */ | ||
168 | DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max, | ||
169 | * Note: firmware allows for greater values. This is a | ||
170 | * recommended max. I'll update this as I find | ||
171 | * out what the real MAX is. Also note that you don't necessarily | ||
172 | * get better results with a greater value here. | ||
173 | */ | ||
174 | }; | ||
175 | |||
176 | /* Support for 802.11 long and short frame preambles. | ||
177 | * Long preamble uses 128-bit sync field, 8-bit CRC | ||
178 | * Short preamble uses 56-bit sync field, 16-bit CRC | ||
179 | * | ||
180 | * 802.11a -- not sure, both optionally ? | ||
181 | * 802.11b supports long and optionally short | ||
182 | * 802.11g supports both */ | ||
183 | enum dot11_preamblesettings_t { | ||
184 | DOT11_PREAMBLESETTING_LONG = 0, | ||
185 | /* Allows *only* long 802.11 preambles */ | ||
186 | DOT11_PREAMBLESETTING_SHORT = 1, | ||
187 | /* Allows *only* short 802.11 preambles */ | ||
188 | DOT11_PREAMBLESETTING_DYNAMIC = 2 | ||
189 | /* AutomatiGically set */ | ||
190 | }; | ||
191 | |||
192 | /* Support for 802.11 slot timing (time between packets). | ||
193 | * | ||
194 | * Long uses 802.11a slot timing (9 usec ?) | ||
195 | * Short uses 802.11b slot timing (20 use ?) */ | ||
196 | enum dot11_slotsettings_t { | ||
197 | DOT11_SLOTSETTINGS_LONG = 0, | ||
198 | /* Allows *only* long 802.11b slot timing */ | ||
199 | DOT11_SLOTSETTINGS_SHORT = 1, | ||
200 | /* Allows *only* long 802.11a slot timing */ | ||
201 | DOT11_SLOTSETTINGS_DYNAMIC = 2 | ||
202 | /* AutomatiGically set */ | ||
203 | }; | ||
204 | |||
205 | /* All you need to know, ERP is "Extended Rate PHY". | ||
206 | * An Extended Rate PHY (ERP) STA or AP shall support three different | ||
207 | * preamble and header formats: | ||
208 | * Long preamble (refer to above) | ||
209 | * Short preamble (refer to above) | ||
210 | * OFDM preamble ( ? ) | ||
211 | * | ||
212 | * I'm assuming here Protection tells the AP | ||
213 | * to be careful, a STA which cannot handle the long pre-amble | ||
214 | * has joined. | ||
215 | */ | ||
216 | enum do11_nonerpstatus_t { | ||
217 | DOT11_ERPSTAT_NONEPRESENT = 0, | ||
218 | DOT11_ERPSTAT_USEPROTECTION = 1 | ||
219 | }; | ||
220 | |||
221 | /* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-* | ||
222 | * The key here is DOT11 NON ERP NEVER protects against | ||
223 | * NON ERP STA's. You *don't* want this unless | ||
224 | * you know what you are doing. It means you will only | ||
225 | * get Extended Rate capabilities */ | ||
226 | enum dot11_nonerpprotection_t { | ||
227 | DOT11_NONERP_NEVER = 0, | ||
228 | DOT11_NONERP_ALWAYS = 1, | ||
229 | DOT11_NONERP_DYNAMIC = 2 | ||
230 | }; | ||
231 | |||
232 | /* Preset OID configuration for 802.11 modes | ||
233 | * Note: DOT11_OID_CW[MIN|MAX] hold the values of the | ||
234 | * DCS MIN|MAX backoff used */ | ||
235 | enum dot11_profile_t { /* And set/allowed values */ | ||
236 | /* Allowed values for DOT11_OID_PROFILES */ | ||
237 | DOT11_PROFILE_B_ONLY = 0, | ||
238 | /* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps | ||
239 | * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC | ||
240 | * DOT11_OID_CWMIN: 31 | ||
241 | * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC | ||
242 | * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG | ||
243 | */ | ||
244 | DOT11_PROFILE_MIXED_G_WIFI = 1, | ||
245 | /* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs | ||
246 | * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC | ||
247 | * DOT11_OID_CWMIN: 15 | ||
248 | * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC | ||
249 | * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC | ||
250 | */ | ||
251 | DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */ | ||
252 | /* Same as Profile MIXED_G_WIFI */ | ||
253 | DOT11_PROFILE_G_ONLY = 3, | ||
254 | /* Same as Profile MIXED_G_WIFI */ | ||
255 | DOT11_PROFILE_TEST = 4, | ||
256 | /* Same as Profile MIXED_G_WIFI except: | ||
257 | * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT | ||
258 | * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER | ||
259 | * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT | ||
260 | */ | ||
261 | DOT11_PROFILE_B_WIFI = 5, | ||
262 | /* Same as Profile B_ONLY */ | ||
263 | DOT11_PROFILE_A_ONLY = 6, | ||
264 | /* Same as Profile MIXED_G_WIFI except: | ||
265 | * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs | ||
266 | */ | ||
267 | DOT11_PROFILE_MIXED_SHORT = 7 | ||
268 | /* Same as MIXED_G_WIFI */ | ||
269 | }; | ||
270 | |||
271 | |||
272 | /* The dot11d conformance level configures the 802.11d conformance levels. | ||
273 | * The following conformance levels exist:*/ | ||
274 | enum oid_inl_conformance_t { | ||
275 | OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */ | ||
276 | OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */ | ||
277 | OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to | ||
278 | * determine channel AND/OR just make assumption that active | ||
279 | * channels are valid channels */ | ||
280 | }; | ||
281 | |||
282 | enum oid_inl_mode_t { | ||
283 | INL_MODE_NONE = -1, | ||
284 | INL_MODE_PROMISCUOUS = 0, | ||
285 | INL_MODE_CLIENT = 1, | ||
286 | INL_MODE_AP = 2, | ||
287 | INL_MODE_SNIFFER = 3 | ||
288 | }; | ||
289 | |||
290 | enum oid_inl_config_t { | ||
291 | INL_CONFIG_NOTHING = 0x00, | ||
292 | INL_CONFIG_MANUALRUN = 0x01, | ||
293 | INL_CONFIG_FRAMETRAP = 0x02, | ||
294 | INL_CONFIG_RXANNEX = 0x04, | ||
295 | INL_CONFIG_TXANNEX = 0x08, | ||
296 | INL_CONFIG_WDS = 0x10 | ||
297 | }; | ||
298 | |||
299 | enum oid_inl_phycap_t { | ||
300 | INL_PHYCAP_2400MHZ = 1, | ||
301 | INL_PHYCAP_5000MHZ = 2, | ||
302 | INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */ | ||
303 | }; | ||
304 | |||
305 | |||
306 | enum oid_num_t { | ||
307 | GEN_OID_MACADDRESS = 0, | ||
308 | GEN_OID_LINKSTATE, | ||
309 | GEN_OID_WATCHDOG, | ||
310 | GEN_OID_MIBOP, | ||
311 | GEN_OID_OPTIONS, | ||
312 | GEN_OID_LEDCONFIG, | ||
313 | |||
314 | /* 802.11 */ | ||
315 | DOT11_OID_BSSTYPE, | ||
316 | DOT11_OID_BSSID, | ||
317 | DOT11_OID_SSID, | ||
318 | DOT11_OID_STATE, | ||
319 | DOT11_OID_AID, | ||
320 | DOT11_OID_COUNTRYSTRING, | ||
321 | DOT11_OID_SSIDOVERRIDE, | ||
322 | |||
323 | DOT11_OID_MEDIUMLIMIT, | ||
324 | DOT11_OID_BEACONPERIOD, | ||
325 | DOT11_OID_DTIMPERIOD, | ||
326 | DOT11_OID_ATIMWINDOW, | ||
327 | DOT11_OID_LISTENINTERVAL, | ||
328 | DOT11_OID_CFPPERIOD, | ||
329 | DOT11_OID_CFPDURATION, | ||
330 | |||
331 | DOT11_OID_AUTHENABLE, | ||
332 | DOT11_OID_PRIVACYINVOKED, | ||
333 | DOT11_OID_EXUNENCRYPTED, | ||
334 | DOT11_OID_DEFKEYID, | ||
335 | DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ | ||
336 | DOT11_OID_STAKEY, | ||
337 | DOT11_OID_REKEYTHRESHOLD, | ||
338 | DOT11_OID_STASC, | ||
339 | |||
340 | DOT11_OID_PRIVTXREJECTED, | ||
341 | DOT11_OID_PRIVRXPLAIN, | ||
342 | DOT11_OID_PRIVRXFAILED, | ||
343 | DOT11_OID_PRIVRXNOKEY, | ||
344 | |||
345 | DOT11_OID_RTSTHRESH, | ||
346 | DOT11_OID_FRAGTHRESH, | ||
347 | DOT11_OID_SHORTRETRIES, | ||
348 | DOT11_OID_LONGRETRIES, | ||
349 | DOT11_OID_MAXTXLIFETIME, | ||
350 | DOT11_OID_MAXRXLIFETIME, | ||
351 | DOT11_OID_AUTHRESPTIMEOUT, | ||
352 | DOT11_OID_ASSOCRESPTIMEOUT, | ||
353 | |||
354 | DOT11_OID_ALOFT_TABLE, | ||
355 | DOT11_OID_ALOFT_CTRL_TABLE, | ||
356 | DOT11_OID_ALOFT_RETREAT, | ||
357 | DOT11_OID_ALOFT_PROGRESS, | ||
358 | DOT11_OID_ALOFT_FIXEDRATE, | ||
359 | DOT11_OID_ALOFT_RSSIGRAPH, | ||
360 | DOT11_OID_ALOFT_CONFIG, | ||
361 | |||
362 | DOT11_OID_VDCFX, | ||
363 | DOT11_OID_MAXFRAMEBURST, | ||
364 | |||
365 | DOT11_OID_PSM, | ||
366 | DOT11_OID_CAMTIMEOUT, | ||
367 | DOT11_OID_RECEIVEDTIMS, | ||
368 | DOT11_OID_ROAMPREFERENCE, | ||
369 | |||
370 | DOT11_OID_BRIDGELOCAL, | ||
371 | DOT11_OID_CLIENTS, | ||
372 | DOT11_OID_CLIENTSASSOCIATED, | ||
373 | DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ | ||
374 | |||
375 | DOT11_OID_CLIENTFIND, | ||
376 | DOT11_OID_WDSLINKADD, | ||
377 | DOT11_OID_WDSLINKREMOVE, | ||
378 | DOT11_OID_EAPAUTHSTA, | ||
379 | DOT11_OID_EAPUNAUTHSTA, | ||
380 | DOT11_OID_DOT1XENABLE, | ||
381 | DOT11_OID_MICFAILURE, | ||
382 | DOT11_OID_REKEYINDICATE, | ||
383 | |||
384 | DOT11_OID_MPDUTXSUCCESSFUL, | ||
385 | DOT11_OID_MPDUTXONERETRY, | ||
386 | DOT11_OID_MPDUTXMULTIPLERETRIES, | ||
387 | DOT11_OID_MPDUTXFAILED, | ||
388 | DOT11_OID_MPDURXSUCCESSFUL, | ||
389 | DOT11_OID_MPDURXDUPS, | ||
390 | DOT11_OID_RTSSUCCESSFUL, | ||
391 | DOT11_OID_RTSFAILED, | ||
392 | DOT11_OID_ACKFAILED, | ||
393 | DOT11_OID_FRAMERECEIVES, | ||
394 | DOT11_OID_FRAMEERRORS, | ||
395 | DOT11_OID_FRAMEABORTS, | ||
396 | DOT11_OID_FRAMEABORTSPHY, | ||
397 | |||
398 | DOT11_OID_SLOTTIME, | ||
399 | DOT11_OID_CWMIN, /* MIN DCS backoff */ | ||
400 | DOT11_OID_CWMAX, /* MAX DCS backoff */ | ||
401 | DOT11_OID_ACKWINDOW, | ||
402 | DOT11_OID_ANTENNARX, | ||
403 | DOT11_OID_ANTENNATX, | ||
404 | DOT11_OID_ANTENNADIVERSITY, | ||
405 | DOT11_OID_CHANNEL, | ||
406 | DOT11_OID_EDTHRESHOLD, | ||
407 | DOT11_OID_PREAMBLESETTINGS, | ||
408 | DOT11_OID_RATES, | ||
409 | DOT11_OID_CCAMODESUPPORTED, | ||
410 | DOT11_OID_CCAMODE, | ||
411 | DOT11_OID_RSSIVECTOR, | ||
412 | DOT11_OID_OUTPUTPOWERTABLE, | ||
413 | DOT11_OID_OUTPUTPOWER, | ||
414 | DOT11_OID_SUPPORTEDRATES, | ||
415 | DOT11_OID_FREQUENCY, | ||
416 | DOT11_OID_SUPPORTEDFREQUENCIES, | ||
417 | DOT11_OID_NOISEFLOOR, | ||
418 | DOT11_OID_FREQUENCYACTIVITY, | ||
419 | DOT11_OID_IQCALIBRATIONTABLE, | ||
420 | DOT11_OID_NONERPPROTECTION, | ||
421 | DOT11_OID_SLOTSETTINGS, | ||
422 | DOT11_OID_NONERPTIMEOUT, | ||
423 | DOT11_OID_PROFILES, | ||
424 | DOT11_OID_EXTENDEDRATES, | ||
425 | |||
426 | DOT11_OID_DEAUTHENTICATE, | ||
427 | DOT11_OID_AUTHENTICATE, | ||
428 | DOT11_OID_DISASSOCIATE, | ||
429 | DOT11_OID_ASSOCIATE, | ||
430 | DOT11_OID_SCAN, | ||
431 | DOT11_OID_BEACON, | ||
432 | DOT11_OID_PROBE, | ||
433 | DOT11_OID_DEAUTHENTICATEEX, | ||
434 | DOT11_OID_AUTHENTICATEEX, | ||
435 | DOT11_OID_DISASSOCIATEEX, | ||
436 | DOT11_OID_ASSOCIATEEX, | ||
437 | DOT11_OID_REASSOCIATE, | ||
438 | DOT11_OID_REASSOCIATEEX, | ||
439 | |||
440 | DOT11_OID_NONERPSTATUS, | ||
441 | |||
442 | DOT11_OID_STATIMEOUT, | ||
443 | DOT11_OID_MLMEAUTOLEVEL, | ||
444 | DOT11_OID_BSSTIMEOUT, | ||
445 | DOT11_OID_ATTACHMENT, | ||
446 | DOT11_OID_PSMBUFFER, | ||
447 | |||
448 | DOT11_OID_BSSS, | ||
449 | DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ | ||
450 | DOT11_OID_BSSFIND, | ||
451 | DOT11_OID_BSSLIST, | ||
452 | |||
453 | OID_INL_TUNNEL, | ||
454 | OID_INL_MEMADDR, | ||
455 | OID_INL_MEMORY, | ||
456 | OID_INL_MODE, | ||
457 | OID_INL_COMPONENT_NR, | ||
458 | OID_INL_VERSION, | ||
459 | OID_INL_INTERFACE_ID, | ||
460 | OID_INL_COMPONENT_ID, | ||
461 | OID_INL_CONFIG, | ||
462 | OID_INL_DOT11D_CONFORMANCE, | ||
463 | OID_INL_PHYCAPABILITIES, | ||
464 | OID_INL_OUTPUTPOWER, | ||
465 | |||
466 | OID_NUM_LAST | ||
467 | }; | ||
468 | |||
469 | #define OID_FLAG_CACHED 0x80 | ||
470 | #define OID_FLAG_TYPE 0x7f | ||
471 | |||
472 | #define OID_TYPE_U32 0x01 | ||
473 | #define OID_TYPE_SSID 0x02 | ||
474 | #define OID_TYPE_KEY 0x03 | ||
475 | #define OID_TYPE_BUFFER 0x04 | ||
476 | #define OID_TYPE_BSS 0x05 | ||
477 | #define OID_TYPE_BSSLIST 0x06 | ||
478 | #define OID_TYPE_FREQUENCIES 0x07 | ||
479 | #define OID_TYPE_MLME 0x08 | ||
480 | #define OID_TYPE_MLMEEX 0x09 | ||
481 | #define OID_TYPE_ADDR 0x0A | ||
482 | #define OID_TYPE_RAW 0x0B | ||
483 | #define OID_TYPE_ATTACH 0x0C | ||
484 | |||
485 | /* OID_TYPE_MLMEEX is special because of a variable size field when sending. | ||
486 | * Not yet implemented (not used in driver anyway). | ||
487 | */ | ||
488 | |||
489 | struct oid_t { | ||
490 | enum oid_num_t oid; | ||
491 | short range; /* to define a range of oid */ | ||
492 | short size; /* max size of the associated data */ | ||
493 | char flags; | ||
494 | }; | ||
495 | |||
496 | union oid_res_t { | ||
497 | void *ptr; | ||
498 | u32 u; | ||
499 | }; | ||
500 | |||
501 | #define IWMAX_BITRATES 20 | ||
502 | #define IWMAX_BSS 24 | ||
503 | #define IWMAX_FREQ 30 | ||
504 | #define PRIV_STR_SIZE 1024 | ||
505 | |||
506 | #endif /* !defined(_ISL_OID_H) */ | ||
507 | /* EOF */ | ||
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c new file mode 100644 index 000000000000..efab07e9e24e --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_dev.c | |||
@@ -0,0 +1,956 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> | ||
5 | * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> | ||
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 | ||
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 | #include <linux/version.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/if_arp.h> | ||
30 | |||
31 | #include <asm/io.h> | ||
32 | |||
33 | #include "prismcompat.h" | ||
34 | #include "isl_38xx.h" | ||
35 | #include "isl_ioctl.h" | ||
36 | #include "islpci_dev.h" | ||
37 | #include "islpci_mgt.h" | ||
38 | #include "islpci_eth.h" | ||
39 | #include "oid_mgt.h" | ||
40 | |||
41 | #define ISL3877_IMAGE_FILE "isl3877" | ||
42 | #define ISL3886_IMAGE_FILE "isl3886" | ||
43 | #define ISL3890_IMAGE_FILE "isl3890" | ||
44 | |||
45 | static int prism54_bring_down(islpci_private *); | ||
46 | static int islpci_alloc_memory(islpci_private *); | ||
47 | static struct net_device_stats *islpci_statistics(struct net_device *); | ||
48 | |||
49 | /* Temporary dummy MAC address to use until firmware is loaded. | ||
50 | * The idea there is that some tools (such as nameif) may query | ||
51 | * the MAC address before the netdev is 'open'. By using a valid | ||
52 | * OUI prefix, they can process the netdev properly. | ||
53 | * Of course, this is not the final/real MAC address. It doesn't | ||
54 | * matter, as you are suppose to be able to change it anytime via | ||
55 | * ndev->set_mac_address. Jean II */ | ||
56 | static const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 }; | ||
57 | |||
58 | static int | ||
59 | isl_upload_firmware(islpci_private *priv) | ||
60 | { | ||
61 | u32 reg, rc; | ||
62 | void __iomem *device_base = priv->device_base; | ||
63 | |||
64 | /* clear the RAMBoot and the Reset bit */ | ||
65 | reg = readl(device_base + ISL38XX_CTRL_STAT_REG); | ||
66 | reg &= ~ISL38XX_CTRL_STAT_RESET; | ||
67 | reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; | ||
68 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
69 | wmb(); | ||
70 | udelay(ISL38XX_WRITEIO_DELAY); | ||
71 | |||
72 | /* set the Reset bit without reading the register ! */ | ||
73 | reg |= ISL38XX_CTRL_STAT_RESET; | ||
74 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
75 | wmb(); | ||
76 | udelay(ISL38XX_WRITEIO_DELAY); | ||
77 | |||
78 | /* clear the Reset bit */ | ||
79 | reg &= ~ISL38XX_CTRL_STAT_RESET; | ||
80 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
81 | wmb(); | ||
82 | |||
83 | /* wait a while for the device to reboot */ | ||
84 | mdelay(50); | ||
85 | |||
86 | { | ||
87 | const struct firmware *fw_entry = NULL; | ||
88 | long fw_len; | ||
89 | const u32 *fw_ptr; | ||
90 | |||
91 | rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV); | ||
92 | if (rc) { | ||
93 | printk(KERN_ERR | ||
94 | "%s: request_firmware() failed for '%s'\n", | ||
95 | "prism54", priv->firmware); | ||
96 | return rc; | ||
97 | } | ||
98 | /* prepare the Direct Memory Base register */ | ||
99 | reg = ISL38XX_DEV_FIRMWARE_ADDRES; | ||
100 | |||
101 | fw_ptr = (u32 *) fw_entry->data; | ||
102 | fw_len = fw_entry->size; | ||
103 | |||
104 | if (fw_len % 4) { | ||
105 | printk(KERN_ERR | ||
106 | "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", | ||
107 | "prism54", priv->firmware); | ||
108 | release_firmware(fw_entry); | ||
109 | return -EILSEQ; /* Illegal byte sequence */; | ||
110 | } | ||
111 | |||
112 | while (fw_len > 0) { | ||
113 | long _fw_len = | ||
114 | (fw_len > | ||
115 | ISL38XX_MEMORY_WINDOW_SIZE) ? | ||
116 | ISL38XX_MEMORY_WINDOW_SIZE : fw_len; | ||
117 | u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; | ||
118 | |||
119 | /* set the cards base address for writting the data */ | ||
120 | isl38xx_w32_flush(device_base, reg, | ||
121 | ISL38XX_DIR_MEM_BASE_REG); | ||
122 | wmb(); /* be paranoid */ | ||
123 | |||
124 | /* increment the write address for next iteration */ | ||
125 | reg += _fw_len; | ||
126 | fw_len -= _fw_len; | ||
127 | |||
128 | /* write the data to the Direct Memory Window 32bit-wise */ | ||
129 | /* memcpy_toio() doesn't guarantee 32bit writes :-| */ | ||
130 | while (_fw_len > 0) { | ||
131 | /* use non-swapping writel() */ | ||
132 | __raw_writel(*fw_ptr, dev_fw_ptr); | ||
133 | fw_ptr++, dev_fw_ptr++; | ||
134 | _fw_len -= 4; | ||
135 | } | ||
136 | |||
137 | /* flush PCI posting */ | ||
138 | (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); | ||
139 | wmb(); /* be paranoid again */ | ||
140 | |||
141 | BUG_ON(_fw_len != 0); | ||
142 | } | ||
143 | |||
144 | BUG_ON(fw_len != 0); | ||
145 | |||
146 | /* Firmware version is at offset 40 (also for "newmac") */ | ||
147 | printk(KERN_DEBUG "%s: firmware version: %.8s\n", | ||
148 | priv->ndev->name, fw_entry->data + 40); | ||
149 | |||
150 | release_firmware(fw_entry); | ||
151 | } | ||
152 | |||
153 | /* now reset the device | ||
154 | * clear the Reset & ClkRun bit, set the RAMBoot bit */ | ||
155 | reg = readl(device_base + ISL38XX_CTRL_STAT_REG); | ||
156 | reg &= ~ISL38XX_CTRL_STAT_CLKRUN; | ||
157 | reg &= ~ISL38XX_CTRL_STAT_RESET; | ||
158 | reg |= ISL38XX_CTRL_STAT_RAMBOOT; | ||
159 | isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); | ||
160 | wmb(); | ||
161 | udelay(ISL38XX_WRITEIO_DELAY); | ||
162 | |||
163 | /* set the reset bit latches the host override and RAMBoot bits | ||
164 | * into the device for operation when the reset bit is reset */ | ||
165 | reg |= ISL38XX_CTRL_STAT_RESET; | ||
166 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
167 | /* don't do flush PCI posting here! */ | ||
168 | wmb(); | ||
169 | udelay(ISL38XX_WRITEIO_DELAY); | ||
170 | |||
171 | /* clear the reset bit should start the whole circus */ | ||
172 | reg &= ~ISL38XX_CTRL_STAT_RESET; | ||
173 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
174 | /* don't do flush PCI posting here! */ | ||
175 | wmb(); | ||
176 | udelay(ISL38XX_WRITEIO_DELAY); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | /****************************************************************************** | ||
182 | Device Interrupt Handler | ||
183 | ******************************************************************************/ | ||
184 | |||
185 | irqreturn_t | ||
186 | islpci_interrupt(int irq, void *config, struct pt_regs *regs) | ||
187 | { | ||
188 | u32 reg; | ||
189 | islpci_private *priv = config; | ||
190 | struct net_device *ndev = priv->ndev; | ||
191 | void __iomem *device = priv->device_base; | ||
192 | int powerstate = ISL38XX_PSM_POWERSAVE_STATE; | ||
193 | |||
194 | /* lock the interrupt handler */ | ||
195 | spin_lock(&priv->slock); | ||
196 | |||
197 | /* received an interrupt request on a shared IRQ line | ||
198 | * first check whether the device is in sleep mode */ | ||
199 | reg = readl(device + ISL38XX_CTRL_STAT_REG); | ||
200 | if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) | ||
201 | /* device is in sleep mode, IRQ was generated by someone else */ | ||
202 | { | ||
203 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
204 | DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); | ||
205 | #endif | ||
206 | spin_unlock(&priv->slock); | ||
207 | return IRQ_NONE; | ||
208 | } | ||
209 | |||
210 | |||
211 | /* check whether there is any source of interrupt on the device */ | ||
212 | reg = readl(device + ISL38XX_INT_IDENT_REG); | ||
213 | |||
214 | /* also check the contents of the Interrupt Enable Register, because this | ||
215 | * will filter out interrupt sources from other devices on the same irq ! */ | ||
216 | reg &= readl(device + ISL38XX_INT_EN_REG); | ||
217 | reg &= ISL38XX_INT_SOURCES; | ||
218 | |||
219 | if (reg != 0) { | ||
220 | if (islpci_get_state(priv) != PRV_STATE_SLEEP) | ||
221 | powerstate = ISL38XX_PSM_ACTIVE_STATE; | ||
222 | |||
223 | /* reset the request bits in the Identification register */ | ||
224 | isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); | ||
225 | |||
226 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
227 | DEBUG(SHOW_FUNCTION_CALLS, | ||
228 | "IRQ: Identification register 0x%p 0x%x \n", device, reg); | ||
229 | #endif | ||
230 | |||
231 | /* check for each bit in the register separately */ | ||
232 | if (reg & ISL38XX_INT_IDENT_UPDATE) { | ||
233 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
234 | /* Queue has been updated */ | ||
235 | DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); | ||
236 | |||
237 | DEBUG(SHOW_QUEUE_INDEXES, | ||
238 | "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", | ||
239 | le32_to_cpu(priv->control_block-> | ||
240 | driver_curr_frag[0]), | ||
241 | le32_to_cpu(priv->control_block-> | ||
242 | driver_curr_frag[1]), | ||
243 | le32_to_cpu(priv->control_block-> | ||
244 | driver_curr_frag[2]), | ||
245 | le32_to_cpu(priv->control_block-> | ||
246 | driver_curr_frag[3]), | ||
247 | le32_to_cpu(priv->control_block-> | ||
248 | driver_curr_frag[4]), | ||
249 | le32_to_cpu(priv->control_block-> | ||
250 | driver_curr_frag[5]) | ||
251 | ); | ||
252 | |||
253 | DEBUG(SHOW_QUEUE_INDEXES, | ||
254 | "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", | ||
255 | le32_to_cpu(priv->control_block-> | ||
256 | device_curr_frag[0]), | ||
257 | le32_to_cpu(priv->control_block-> | ||
258 | device_curr_frag[1]), | ||
259 | le32_to_cpu(priv->control_block-> | ||
260 | device_curr_frag[2]), | ||
261 | le32_to_cpu(priv->control_block-> | ||
262 | device_curr_frag[3]), | ||
263 | le32_to_cpu(priv->control_block-> | ||
264 | device_curr_frag[4]), | ||
265 | le32_to_cpu(priv->control_block-> | ||
266 | device_curr_frag[5]) | ||
267 | ); | ||
268 | #endif | ||
269 | |||
270 | /* cleanup the data low transmit queue */ | ||
271 | islpci_eth_cleanup_transmit(priv, priv->control_block); | ||
272 | |||
273 | /* device is in active state, update the | ||
274 | * powerstate flag if necessary */ | ||
275 | powerstate = ISL38XX_PSM_ACTIVE_STATE; | ||
276 | |||
277 | /* check all three queues in priority order | ||
278 | * call the PIMFOR receive function until the | ||
279 | * queue is empty */ | ||
280 | if (isl38xx_in_queue(priv->control_block, | ||
281 | ISL38XX_CB_RX_MGMTQ) != 0) { | ||
282 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
283 | DEBUG(SHOW_TRACING, | ||
284 | "Received frame in Management Queue\n"); | ||
285 | #endif | ||
286 | islpci_mgt_receive(ndev); | ||
287 | |||
288 | islpci_mgt_cleanup_transmit(ndev); | ||
289 | |||
290 | /* Refill slots in receive queue */ | ||
291 | islpci_mgmt_rx_fill(ndev); | ||
292 | |||
293 | /* no need to trigger the device, next | ||
294 | islpci_mgt_transaction does it */ | ||
295 | } | ||
296 | |||
297 | while (isl38xx_in_queue(priv->control_block, | ||
298 | ISL38XX_CB_RX_DATA_LQ) != 0) { | ||
299 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
300 | DEBUG(SHOW_TRACING, | ||
301 | "Received frame in Data Low Queue \n"); | ||
302 | #endif | ||
303 | islpci_eth_receive(priv); | ||
304 | } | ||
305 | |||
306 | /* check whether the data transmit queues were full */ | ||
307 | if (priv->data_low_tx_full) { | ||
308 | /* check whether the transmit is not full anymore */ | ||
309 | if (ISL38XX_CB_TX_QSIZE - | ||
310 | isl38xx_in_queue(priv->control_block, | ||
311 | ISL38XX_CB_TX_DATA_LQ) >= | ||
312 | ISL38XX_MIN_QTHRESHOLD) { | ||
313 | /* nope, the driver is ready for more network frames */ | ||
314 | netif_wake_queue(priv->ndev); | ||
315 | |||
316 | /* reset the full flag */ | ||
317 | priv->data_low_tx_full = 0; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if (reg & ISL38XX_INT_IDENT_INIT) { | ||
323 | /* Device has been initialized */ | ||
324 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
325 | DEBUG(SHOW_TRACING, | ||
326 | "IRQ: Init flag, device initialized \n"); | ||
327 | #endif | ||
328 | wake_up(&priv->reset_done); | ||
329 | } | ||
330 | |||
331 | if (reg & ISL38XX_INT_IDENT_SLEEP) { | ||
332 | /* Device intends to move to powersave state */ | ||
333 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
334 | DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n"); | ||
335 | #endif | ||
336 | isl38xx_handle_sleep_request(priv->control_block, | ||
337 | &powerstate, | ||
338 | priv->device_base); | ||
339 | } | ||
340 | |||
341 | if (reg & ISL38XX_INT_IDENT_WAKEUP) { | ||
342 | /* Device has been woken up to active state */ | ||
343 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
344 | DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n"); | ||
345 | #endif | ||
346 | |||
347 | isl38xx_handle_wakeup(priv->control_block, | ||
348 | &powerstate, priv->device_base); | ||
349 | } | ||
350 | } else { | ||
351 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
352 | DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); | ||
353 | #endif | ||
354 | spin_unlock(&priv->slock); | ||
355 | return IRQ_NONE; | ||
356 | } | ||
357 | |||
358 | /* sleep -> ready */ | ||
359 | if (islpci_get_state(priv) == PRV_STATE_SLEEP | ||
360 | && powerstate == ISL38XX_PSM_ACTIVE_STATE) | ||
361 | islpci_set_state(priv, PRV_STATE_READY); | ||
362 | |||
363 | /* !sleep -> sleep */ | ||
364 | if (islpci_get_state(priv) != PRV_STATE_SLEEP | ||
365 | && powerstate == ISL38XX_PSM_POWERSAVE_STATE) | ||
366 | islpci_set_state(priv, PRV_STATE_SLEEP); | ||
367 | |||
368 | /* unlock the interrupt handler */ | ||
369 | spin_unlock(&priv->slock); | ||
370 | |||
371 | return IRQ_HANDLED; | ||
372 | } | ||
373 | |||
374 | /****************************************************************************** | ||
375 | Network Interface Control & Statistical functions | ||
376 | ******************************************************************************/ | ||
377 | static int | ||
378 | islpci_open(struct net_device *ndev) | ||
379 | { | ||
380 | u32 rc; | ||
381 | islpci_private *priv = netdev_priv(ndev); | ||
382 | |||
383 | /* reset data structures, upload firmware and reset device */ | ||
384 | rc = islpci_reset(priv,1); | ||
385 | if (rc) { | ||
386 | prism54_bring_down(priv); | ||
387 | return rc; /* Returns informative message */ | ||
388 | } | ||
389 | |||
390 | netif_start_queue(ndev); | ||
391 | /* netif_mark_up( ndev ); */ | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static int | ||
397 | islpci_close(struct net_device *ndev) | ||
398 | { | ||
399 | islpci_private *priv = netdev_priv(ndev); | ||
400 | |||
401 | printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name); | ||
402 | |||
403 | netif_stop_queue(ndev); | ||
404 | |||
405 | return prism54_bring_down(priv); | ||
406 | } | ||
407 | |||
408 | static int | ||
409 | prism54_bring_down(islpci_private *priv) | ||
410 | { | ||
411 | void __iomem *device_base = priv->device_base; | ||
412 | u32 reg; | ||
413 | /* we are going to shutdown the device */ | ||
414 | islpci_set_state(priv, PRV_STATE_PREBOOT); | ||
415 | |||
416 | /* disable all device interrupts in case they weren't */ | ||
417 | isl38xx_disable_interrupts(priv->device_base); | ||
418 | |||
419 | /* For safety reasons, we may want to ensure that no DMA transfer is | ||
420 | * currently in progress by emptying the TX and RX queues. */ | ||
421 | |||
422 | /* wait until interrupts have finished executing on other CPUs */ | ||
423 | synchronize_irq(priv->pdev->irq); | ||
424 | |||
425 | reg = readl(device_base + ISL38XX_CTRL_STAT_REG); | ||
426 | reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); | ||
427 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
428 | wmb(); | ||
429 | udelay(ISL38XX_WRITEIO_DELAY); | ||
430 | |||
431 | reg |= ISL38XX_CTRL_STAT_RESET; | ||
432 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
433 | wmb(); | ||
434 | udelay(ISL38XX_WRITEIO_DELAY); | ||
435 | |||
436 | /* clear the Reset bit */ | ||
437 | reg &= ~ISL38XX_CTRL_STAT_RESET; | ||
438 | writel(reg, device_base + ISL38XX_CTRL_STAT_REG); | ||
439 | wmb(); | ||
440 | |||
441 | /* wait a while for the device to reset */ | ||
442 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
443 | schedule_timeout(50*HZ/1000); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int | ||
449 | islpci_upload_fw(islpci_private *priv) | ||
450 | { | ||
451 | islpci_state_t old_state; | ||
452 | u32 rc; | ||
453 | |||
454 | old_state = islpci_set_state(priv, PRV_STATE_BOOT); | ||
455 | |||
456 | printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); | ||
457 | |||
458 | rc = isl_upload_firmware(priv); | ||
459 | if (rc) { | ||
460 | /* error uploading the firmware */ | ||
461 | printk(KERN_ERR "%s: could not upload firmware ('%s')\n", | ||
462 | priv->ndev->name, priv->firmware); | ||
463 | |||
464 | islpci_set_state(priv, old_state); | ||
465 | return rc; | ||
466 | } | ||
467 | |||
468 | printk(KERN_DEBUG "%s: firmware upload complete\n", | ||
469 | priv->ndev->name); | ||
470 | |||
471 | islpci_set_state(priv, PRV_STATE_POSTBOOT); | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int | ||
477 | islpci_reset_if(islpci_private *priv) | ||
478 | { | ||
479 | long remaining; | ||
480 | int result = -ETIME; | ||
481 | int count; | ||
482 | |||
483 | DEFINE_WAIT(wait); | ||
484 | prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); | ||
485 | |||
486 | /* now the last step is to reset the interface */ | ||
487 | isl38xx_interface_reset(priv->device_base, priv->device_host_address); | ||
488 | islpci_set_state(priv, PRV_STATE_PREINIT); | ||
489 | |||
490 | for(count = 0; count < 2 && result; count++) { | ||
491 | /* The software reset acknowledge needs about 220 msec here. | ||
492 | * Be conservative and wait for up to one second. */ | ||
493 | |||
494 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
495 | remaining = schedule_timeout(HZ); | ||
496 | |||
497 | if(remaining > 0) { | ||
498 | result = 0; | ||
499 | break; | ||
500 | } | ||
501 | |||
502 | /* If we're here it's because our IRQ hasn't yet gone through. | ||
503 | * Retry a bit more... | ||
504 | */ | ||
505 | printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n", | ||
506 | priv->ndev->name); | ||
507 | } | ||
508 | |||
509 | finish_wait(&priv->reset_done, &wait); | ||
510 | |||
511 | if (result) { | ||
512 | printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); | ||
513 | return result; | ||
514 | } | ||
515 | |||
516 | islpci_set_state(priv, PRV_STATE_INIT); | ||
517 | |||
518 | /* Now that the device is 100% up, let's allow | ||
519 | * for the other interrupts -- | ||
520 | * NOTE: this is not *yet* true since we've only allowed the | ||
521 | * INIT interrupt on the IRQ line. We can perhaps poll | ||
522 | * the IRQ line until we know for sure the reset went through */ | ||
523 | isl38xx_enable_common_interrupts(priv->device_base); | ||
524 | |||
525 | down_write(&priv->mib_sem); | ||
526 | result = mgt_commit(priv); | ||
527 | if (result) { | ||
528 | printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); | ||
529 | up_write(&priv->mib_sem); | ||
530 | return result; | ||
531 | } | ||
532 | up_write(&priv->mib_sem); | ||
533 | |||
534 | islpci_set_state(priv, PRV_STATE_READY); | ||
535 | |||
536 | printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | int | ||
541 | islpci_reset(islpci_private *priv, int reload_firmware) | ||
542 | { | ||
543 | isl38xx_control_block *cb = /* volatile not needed */ | ||
544 | (isl38xx_control_block *) priv->control_block; | ||
545 | unsigned counter; | ||
546 | int rc; | ||
547 | |||
548 | if (reload_firmware) | ||
549 | islpci_set_state(priv, PRV_STATE_PREBOOT); | ||
550 | else | ||
551 | islpci_set_state(priv, PRV_STATE_POSTBOOT); | ||
552 | |||
553 | printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); | ||
554 | |||
555 | /* disable all device interrupts in case they weren't */ | ||
556 | isl38xx_disable_interrupts(priv->device_base); | ||
557 | |||
558 | /* flush all management queues */ | ||
559 | priv->index_mgmt_tx = 0; | ||
560 | priv->index_mgmt_rx = 0; | ||
561 | |||
562 | /* clear the indexes in the frame pointer */ | ||
563 | for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { | ||
564 | cb->driver_curr_frag[counter] = cpu_to_le32(0); | ||
565 | cb->device_curr_frag[counter] = cpu_to_le32(0); | ||
566 | } | ||
567 | |||
568 | /* reset the mgmt receive queue */ | ||
569 | for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { | ||
570 | isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; | ||
571 | frag->size = cpu_to_le16(MGMT_FRAME_SIZE); | ||
572 | frag->flags = 0; | ||
573 | frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr); | ||
574 | } | ||
575 | |||
576 | for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { | ||
577 | cb->rx_data_low[counter].address = | ||
578 | cpu_to_le32((u32) priv->pci_map_rx_address[counter]); | ||
579 | } | ||
580 | |||
581 | /* since the receive queues are filled with empty fragments, now we can | ||
582 | * set the corresponding indexes in the Control Block */ | ||
583 | priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = | ||
584 | cpu_to_le32(ISL38XX_CB_RX_QSIZE); | ||
585 | priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = | ||
586 | cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); | ||
587 | |||
588 | /* reset the remaining real index registers and full flags */ | ||
589 | priv->free_data_rx = 0; | ||
590 | priv->free_data_tx = 0; | ||
591 | priv->data_low_tx_full = 0; | ||
592 | |||
593 | if (reload_firmware) { /* Should we load the firmware ? */ | ||
594 | /* now that the data structures are cleaned up, upload | ||
595 | * firmware and reset interface */ | ||
596 | rc = islpci_upload_fw(priv); | ||
597 | if (rc) { | ||
598 | printk(KERN_ERR "%s: islpci_reset: failure\n", | ||
599 | priv->ndev->name); | ||
600 | return rc; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /* finally reset interface */ | ||
605 | rc = islpci_reset_if(priv); | ||
606 | if (rc) | ||
607 | printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); | ||
608 | return rc; | ||
609 | } | ||
610 | |||
611 | static struct net_device_stats * | ||
612 | islpci_statistics(struct net_device *ndev) | ||
613 | { | ||
614 | islpci_private *priv = netdev_priv(ndev); | ||
615 | |||
616 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
617 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n"); | ||
618 | #endif | ||
619 | |||
620 | return &priv->statistics; | ||
621 | } | ||
622 | |||
623 | /****************************************************************************** | ||
624 | Network device configuration functions | ||
625 | ******************************************************************************/ | ||
626 | static int | ||
627 | islpci_alloc_memory(islpci_private *priv) | ||
628 | { | ||
629 | int counter; | ||
630 | |||
631 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
632 | printk(KERN_DEBUG "islpci_alloc_memory\n"); | ||
633 | #endif | ||
634 | |||
635 | /* remap the PCI device base address to accessable */ | ||
636 | if (!(priv->device_base = | ||
637 | ioremap(pci_resource_start(priv->pdev, 0), | ||
638 | ISL38XX_PCI_MEM_SIZE))) { | ||
639 | /* error in remapping the PCI device memory address range */ | ||
640 | printk(KERN_ERR "PCI memory remapping failed \n"); | ||
641 | return -1; | ||
642 | } | ||
643 | |||
644 | /* memory layout for consistent DMA region: | ||
645 | * | ||
646 | * Area 1: Control Block for the device interface | ||
647 | * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that | ||
648 | * the number of supported stations in the AP determines the minimal | ||
649 | * size of the buffer ! | ||
650 | */ | ||
651 | |||
652 | /* perform the allocation */ | ||
653 | priv->driver_mem_address = pci_alloc_consistent(priv->pdev, | ||
654 | HOST_MEM_BLOCK, | ||
655 | &priv-> | ||
656 | device_host_address); | ||
657 | |||
658 | if (!priv->driver_mem_address) { | ||
659 | /* error allocating the block of PCI memory */ | ||
660 | printk(KERN_ERR "%s: could not allocate DMA memory, aborting!", | ||
661 | "prism54"); | ||
662 | return -1; | ||
663 | } | ||
664 | |||
665 | /* assign the Control Block to the first address of the allocated area */ | ||
666 | priv->control_block = | ||
667 | (isl38xx_control_block *) priv->driver_mem_address; | ||
668 | |||
669 | /* set the Power Save Buffer pointer directly behind the CB */ | ||
670 | priv->device_psm_buffer = | ||
671 | priv->device_host_address + CONTROL_BLOCK_SIZE; | ||
672 | |||
673 | /* make sure all buffer pointers are initialized */ | ||
674 | for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { | ||
675 | priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0); | ||
676 | priv->control_block->device_curr_frag[counter] = cpu_to_le32(0); | ||
677 | } | ||
678 | |||
679 | priv->index_mgmt_rx = 0; | ||
680 | memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx)); | ||
681 | memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx)); | ||
682 | |||
683 | /* allocate rx queue for management frames */ | ||
684 | if (islpci_mgmt_rx_fill(priv->ndev) < 0) | ||
685 | goto out_free; | ||
686 | |||
687 | /* now get the data rx skb's */ | ||
688 | memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx)); | ||
689 | memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address)); | ||
690 | |||
691 | for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { | ||
692 | struct sk_buff *skb; | ||
693 | |||
694 | /* allocate an sk_buff for received data frames storage | ||
695 | * each frame on receive size consists of 1 fragment | ||
696 | * include any required allignment operations */ | ||
697 | if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) { | ||
698 | /* error allocating an sk_buff structure elements */ | ||
699 | printk(KERN_ERR "Error allocating skb.\n"); | ||
700 | skb = NULL; | ||
701 | goto out_free; | ||
702 | } | ||
703 | skb_reserve(skb, (4 - (long) skb->data) & 0x03); | ||
704 | /* add the new allocated sk_buff to the buffer array */ | ||
705 | priv->data_low_rx[counter] = skb; | ||
706 | |||
707 | /* map the allocated skb data area to pci */ | ||
708 | priv->pci_map_rx_address[counter] = | ||
709 | pci_map_single(priv->pdev, (void *) skb->data, | ||
710 | MAX_FRAGMENT_SIZE_RX + 2, | ||
711 | PCI_DMA_FROMDEVICE); | ||
712 | if (!priv->pci_map_rx_address[counter]) { | ||
713 | /* error mapping the buffer to device | ||
714 | accessable memory address */ | ||
715 | printk(KERN_ERR "failed to map skb DMA'able\n"); | ||
716 | goto out_free; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | prism54_acl_init(&priv->acl); | ||
721 | prism54_wpa_ie_init(priv); | ||
722 | if (mgt_init(priv)) | ||
723 | goto out_free; | ||
724 | |||
725 | return 0; | ||
726 | out_free: | ||
727 | islpci_free_memory(priv); | ||
728 | return -1; | ||
729 | } | ||
730 | |||
731 | int | ||
732 | islpci_free_memory(islpci_private *priv) | ||
733 | { | ||
734 | int counter; | ||
735 | |||
736 | if (priv->device_base) | ||
737 | iounmap(priv->device_base); | ||
738 | priv->device_base = NULL; | ||
739 | |||
740 | /* free consistent DMA area... */ | ||
741 | if (priv->driver_mem_address) | ||
742 | pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, | ||
743 | priv->driver_mem_address, | ||
744 | priv->device_host_address); | ||
745 | |||
746 | /* clear some dangling pointers */ | ||
747 | priv->driver_mem_address = NULL; | ||
748 | priv->device_host_address = 0; | ||
749 | priv->device_psm_buffer = 0; | ||
750 | priv->control_block = NULL; | ||
751 | |||
752 | /* clean up mgmt rx buffers */ | ||
753 | for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { | ||
754 | struct islpci_membuf *buf = &priv->mgmt_rx[counter]; | ||
755 | if (buf->pci_addr) | ||
756 | pci_unmap_single(priv->pdev, buf->pci_addr, | ||
757 | buf->size, PCI_DMA_FROMDEVICE); | ||
758 | buf->pci_addr = 0; | ||
759 | if (buf->mem) | ||
760 | kfree(buf->mem); | ||
761 | buf->size = 0; | ||
762 | buf->mem = NULL; | ||
763 | } | ||
764 | |||
765 | /* clean up data rx buffers */ | ||
766 | for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { | ||
767 | if (priv->pci_map_rx_address[counter]) | ||
768 | pci_unmap_single(priv->pdev, | ||
769 | priv->pci_map_rx_address[counter], | ||
770 | MAX_FRAGMENT_SIZE_RX + 2, | ||
771 | PCI_DMA_FROMDEVICE); | ||
772 | priv->pci_map_rx_address[counter] = 0; | ||
773 | |||
774 | if (priv->data_low_rx[counter]) | ||
775 | dev_kfree_skb(priv->data_low_rx[counter]); | ||
776 | priv->data_low_rx[counter] = NULL; | ||
777 | } | ||
778 | |||
779 | /* Free the acces control list and the WPA list */ | ||
780 | prism54_acl_clean(&priv->acl); | ||
781 | prism54_wpa_ie_clean(priv); | ||
782 | mgt_clean(priv); | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | #if 0 | ||
788 | static void | ||
789 | islpci_set_multicast_list(struct net_device *dev) | ||
790 | { | ||
791 | /* put device into promisc mode and let network layer handle it */ | ||
792 | } | ||
793 | #endif | ||
794 | |||
795 | struct net_device * | ||
796 | islpci_setup(struct pci_dev *pdev) | ||
797 | { | ||
798 | islpci_private *priv; | ||
799 | struct net_device *ndev = alloc_etherdev(sizeof (islpci_private)); | ||
800 | |||
801 | if (!ndev) | ||
802 | return ndev; | ||
803 | |||
804 | SET_MODULE_OWNER(ndev); | ||
805 | pci_set_drvdata(pdev, ndev); | ||
806 | #if defined(SET_NETDEV_DEV) | ||
807 | SET_NETDEV_DEV(ndev, &pdev->dev); | ||
808 | #endif | ||
809 | |||
810 | /* setup the structure members */ | ||
811 | ndev->base_addr = pci_resource_start(pdev, 0); | ||
812 | ndev->irq = pdev->irq; | ||
813 | |||
814 | /* initialize the function pointers */ | ||
815 | ndev->open = &islpci_open; | ||
816 | ndev->stop = &islpci_close; | ||
817 | ndev->get_stats = &islpci_statistics; | ||
818 | ndev->get_wireless_stats = &prism54_get_wireless_stats; | ||
819 | ndev->do_ioctl = &prism54_ioctl; | ||
820 | ndev->wireless_handlers = | ||
821 | (struct iw_handler_def *) &prism54_handler_def; | ||
822 | |||
823 | ndev->hard_start_xmit = &islpci_eth_transmit; | ||
824 | /* ndev->set_multicast_list = &islpci_set_multicast_list; */ | ||
825 | ndev->addr_len = ETH_ALEN; | ||
826 | ndev->set_mac_address = &prism54_set_mac_address; | ||
827 | /* Get a non-zero dummy MAC address for nameif. Jean II */ | ||
828 | memcpy(ndev->dev_addr, dummy_mac, 6); | ||
829 | |||
830 | #ifdef HAVE_TX_TIMEOUT | ||
831 | ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT; | ||
832 | ndev->tx_timeout = &islpci_eth_tx_timeout; | ||
833 | #endif | ||
834 | |||
835 | /* allocate a private device structure to the network device */ | ||
836 | priv = netdev_priv(ndev); | ||
837 | priv->ndev = ndev; | ||
838 | priv->pdev = pdev; | ||
839 | priv->monitor_type = ARPHRD_IEEE80211; | ||
840 | priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? | ||
841 | priv->monitor_type : ARPHRD_ETHER; | ||
842 | |||
843 | #if WIRELESS_EXT > 16 | ||
844 | /* Add pointers to enable iwspy support. */ | ||
845 | priv->wireless_data.spy_data = &priv->spy_data; | ||
846 | ndev->wireless_data = &priv->wireless_data; | ||
847 | #endif /* WIRELESS_EXT > 16 */ | ||
848 | |||
849 | /* save the start and end address of the PCI memory area */ | ||
850 | ndev->mem_start = (unsigned long) priv->device_base; | ||
851 | ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; | ||
852 | |||
853 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
854 | DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base); | ||
855 | #endif | ||
856 | |||
857 | init_waitqueue_head(&priv->reset_done); | ||
858 | |||
859 | /* init the queue read locks, process wait counter */ | ||
860 | sema_init(&priv->mgmt_sem, 1); | ||
861 | priv->mgmt_received = NULL; | ||
862 | init_waitqueue_head(&priv->mgmt_wqueue); | ||
863 | sema_init(&priv->stats_sem, 1); | ||
864 | spin_lock_init(&priv->slock); | ||
865 | |||
866 | /* init state machine with off#1 state */ | ||
867 | priv->state = PRV_STATE_OFF; | ||
868 | priv->state_off = 1; | ||
869 | |||
870 | /* initialize workqueue's */ | ||
871 | INIT_WORK(&priv->stats_work, | ||
872 | (void (*)(void *)) prism54_update_stats, priv); | ||
873 | priv->stats_timestamp = 0; | ||
874 | |||
875 | INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv); | ||
876 | priv->reset_task_pending = 0; | ||
877 | |||
878 | /* allocate various memory areas */ | ||
879 | if (islpci_alloc_memory(priv)) | ||
880 | goto do_free_netdev; | ||
881 | |||
882 | /* select the firmware file depending on the device id */ | ||
883 | switch (pdev->device) { | ||
884 | case 0x3877: | ||
885 | strcpy(priv->firmware, ISL3877_IMAGE_FILE); | ||
886 | break; | ||
887 | |||
888 | case 0x3886: | ||
889 | strcpy(priv->firmware, ISL3886_IMAGE_FILE); | ||
890 | break; | ||
891 | |||
892 | default: | ||
893 | strcpy(priv->firmware, ISL3890_IMAGE_FILE); | ||
894 | break; | ||
895 | } | ||
896 | |||
897 | if (register_netdev(ndev)) { | ||
898 | DEBUG(SHOW_ERROR_MESSAGES, | ||
899 | "ERROR: register_netdev() failed \n"); | ||
900 | goto do_islpci_free_memory; | ||
901 | } | ||
902 | |||
903 | return ndev; | ||
904 | |||
905 | do_islpci_free_memory: | ||
906 | islpci_free_memory(priv); | ||
907 | do_free_netdev: | ||
908 | pci_set_drvdata(pdev, NULL); | ||
909 | free_netdev(ndev); | ||
910 | priv = NULL; | ||
911 | return NULL; | ||
912 | } | ||
913 | |||
914 | islpci_state_t | ||
915 | islpci_set_state(islpci_private *priv, islpci_state_t new_state) | ||
916 | { | ||
917 | islpci_state_t old_state; | ||
918 | |||
919 | /* lock */ | ||
920 | old_state = priv->state; | ||
921 | |||
922 | /* this means either a race condition or some serious error in | ||
923 | * the driver code */ | ||
924 | switch (new_state) { | ||
925 | case PRV_STATE_OFF: | ||
926 | priv->state_off++; | ||
927 | default: | ||
928 | priv->state = new_state; | ||
929 | break; | ||
930 | |||
931 | case PRV_STATE_PREBOOT: | ||
932 | /* there are actually many off-states, enumerated by | ||
933 | * state_off */ | ||
934 | if (old_state == PRV_STATE_OFF) | ||
935 | priv->state_off--; | ||
936 | |||
937 | /* only if hw_unavailable is zero now it means we either | ||
938 | * were in off#1 state, or came here from | ||
939 | * somewhere else */ | ||
940 | if (!priv->state_off) | ||
941 | priv->state = new_state; | ||
942 | break; | ||
943 | }; | ||
944 | #if 0 | ||
945 | printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n", | ||
946 | priv->ndev->name, old_state, new_state, priv->state_off); | ||
947 | #endif | ||
948 | |||
949 | /* invariants */ | ||
950 | BUG_ON(priv->state_off < 0); | ||
951 | BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF)); | ||
952 | BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF)); | ||
953 | |||
954 | /* unlock */ | ||
955 | return old_state; | ||
956 | } | ||
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h new file mode 100644 index 000000000000..32a1019f1b36 --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_dev.h | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> | ||
5 | * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> | ||
6 | * Copyright (C) 2003 Aurelien Alleaume <slts@free.fr> | ||
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 | ||
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 _ISLPCI_DEV_H | ||
24 | #define _ISLPCI_DEV_H | ||
25 | |||
26 | #include <linux/version.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/wireless.h> | ||
29 | #include <net/iw_handler.h> | ||
30 | #include <linux/list.h> | ||
31 | |||
32 | #include "isl_38xx.h" | ||
33 | #include "isl_oid.h" | ||
34 | #include "islpci_mgt.h" | ||
35 | |||
36 | /* some states might not be superflous and may be removed when | ||
37 | design is finalized (hvr) */ | ||
38 | typedef enum { | ||
39 | PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ | ||
40 | PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ | ||
41 | PRV_STATE_BOOT, /* boot state (fw upload, run fw) */ | ||
42 | PRV_STATE_POSTBOOT, /* after boot state, need reset now */ | ||
43 | PRV_STATE_PREINIT, /* pre-init state */ | ||
44 | PRV_STATE_INIT, /* init state (restore MIB backup to device) */ | ||
45 | PRV_STATE_READY, /* driver&device are in operational state */ | ||
46 | PRV_STATE_SLEEP /* device in sleep mode */ | ||
47 | } islpci_state_t; | ||
48 | |||
49 | /* ACL using MAC address */ | ||
50 | struct mac_entry { | ||
51 | struct list_head _list; | ||
52 | char addr[ETH_ALEN]; | ||
53 | }; | ||
54 | |||
55 | struct islpci_acl { | ||
56 | enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; | ||
57 | struct list_head mac_list; /* a list of mac_entry */ | ||
58 | int size; /* size of queue */ | ||
59 | struct semaphore sem; /* accessed in ioctls and trap_work */ | ||
60 | }; | ||
61 | |||
62 | struct islpci_membuf { | ||
63 | int size; /* size of memory */ | ||
64 | void *mem; /* address of memory as seen by CPU */ | ||
65 | dma_addr_t pci_addr; /* address of memory as seen by device */ | ||
66 | }; | ||
67 | |||
68 | #define MAX_BSS_WPA_IE_COUNT 64 | ||
69 | #define MAX_WPA_IE_LEN 64 | ||
70 | struct islpci_bss_wpa_ie { | ||
71 | struct list_head list; | ||
72 | unsigned long last_update; | ||
73 | u8 bssid[ETH_ALEN]; | ||
74 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
75 | size_t wpa_ie_len; | ||
76 | |||
77 | }; | ||
78 | |||
79 | typedef struct { | ||
80 | spinlock_t slock; /* generic spinlock; */ | ||
81 | |||
82 | u32 priv_oid; | ||
83 | |||
84 | /* our mib cache */ | ||
85 | u32 iw_mode; | ||
86 | struct rw_semaphore mib_sem; | ||
87 | void **mib; | ||
88 | char nickname[IW_ESSID_MAX_SIZE+1]; | ||
89 | |||
90 | /* Take care of the wireless stats */ | ||
91 | struct work_struct stats_work; | ||
92 | struct semaphore stats_sem; | ||
93 | /* remember when we last updated the stats */ | ||
94 | unsigned long stats_timestamp; | ||
95 | /* The first is accessed under semaphore locking. | ||
96 | * The second is the clean one we return to iwconfig. | ||
97 | */ | ||
98 | struct iw_statistics local_iwstatistics; | ||
99 | struct iw_statistics iwstatistics; | ||
100 | |||
101 | struct iw_spy_data spy_data; /* iwspy support */ | ||
102 | |||
103 | #if WIRELESS_EXT > 16 | ||
104 | struct iw_public_data wireless_data; | ||
105 | #endif /* WIRELESS_EXT > 16 */ | ||
106 | |||
107 | int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ | ||
108 | |||
109 | struct islpci_acl acl; | ||
110 | |||
111 | /* PCI bus allocation & configuration members */ | ||
112 | struct pci_dev *pdev; /* PCI structure information */ | ||
113 | char firmware[33]; | ||
114 | |||
115 | void __iomem *device_base; /* ioremapped device base address */ | ||
116 | |||
117 | /* consistent DMA region */ | ||
118 | void *driver_mem_address; /* base DMA address */ | ||
119 | dma_addr_t device_host_address; /* base DMA address (bus address) */ | ||
120 | dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */ | ||
121 | |||
122 | /* our network_device structure */ | ||
123 | struct net_device *ndev; | ||
124 | |||
125 | /* device queue interface members */ | ||
126 | struct isl38xx_cb *control_block; /* device control block | ||
127 | (== driver_mem_address!) */ | ||
128 | |||
129 | /* Each queue has three indexes: | ||
130 | * free/index_mgmt/data_rx/tx (called index, see below), | ||
131 | * driver_curr_frag, and device_curr_frag (in the control block) | ||
132 | * All indexes are ever-increasing, but interpreted modulo the | ||
133 | * device queue size when used. | ||
134 | * index <= device_curr_frag <= driver_curr_frag at all times | ||
135 | * For rx queues, [index, device_curr_frag) contains fragments | ||
136 | * that the interrupt processing needs to handle (owned by driver). | ||
137 | * [device_curr_frag, driver_curr_frag) is the free space in the | ||
138 | * rx queue, waiting for data (owned by device). The driver | ||
139 | * increments driver_curr_frag to indicate to the device that more | ||
140 | * buffers are available. | ||
141 | * If device_curr_frag == driver_curr_frag, no more rx buffers are | ||
142 | * available, and the rx DMA engine of the device is halted. | ||
143 | * For tx queues, [index, device_curr_frag) contains fragments | ||
144 | * where tx is done; they need to be freed (owned by driver). | ||
145 | * [device_curr_frag, driver_curr_frag) contains the frames | ||
146 | * that are being transferred (owned by device). The driver | ||
147 | * increments driver_curr_frag to indicate that more tx work | ||
148 | * needs to be done. | ||
149 | */ | ||
150 | u32 index_mgmt_rx; /* real index mgmt rx queue */ | ||
151 | u32 index_mgmt_tx; /* read index mgmt tx queue */ | ||
152 | u32 free_data_rx; /* free pointer data rx queue */ | ||
153 | u32 free_data_tx; /* free pointer data tx queue */ | ||
154 | u32 data_low_tx_full; /* full detected flag */ | ||
155 | |||
156 | /* frame memory buffers for the device queues */ | ||
157 | struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE]; | ||
158 | struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE]; | ||
159 | struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE]; | ||
160 | struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE]; | ||
161 | dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE]; | ||
162 | dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE]; | ||
163 | |||
164 | /* driver network interface members */ | ||
165 | struct net_device_stats statistics; | ||
166 | |||
167 | /* wait for a reset interrupt */ | ||
168 | wait_queue_head_t reset_done; | ||
169 | |||
170 | /* used by islpci_mgt_transaction */ | ||
171 | struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */ | ||
172 | struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ | ||
173 | wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ | ||
174 | |||
175 | /* state machine */ | ||
176 | islpci_state_t state; | ||
177 | int state_off; /* enumeration of off-state, if 0 then | ||
178 | * we're not in any off-state */ | ||
179 | |||
180 | /* WPA stuff */ | ||
181 | int wpa; /* WPA mode enabled */ | ||
182 | struct list_head bss_wpa_list; | ||
183 | int num_bss_wpa; | ||
184 | struct semaphore wpa_sem; | ||
185 | |||
186 | struct work_struct reset_task; | ||
187 | int reset_task_pending; | ||
188 | } islpci_private; | ||
189 | |||
190 | static inline islpci_state_t | ||
191 | islpci_get_state(islpci_private *priv) | ||
192 | { | ||
193 | /* lock */ | ||
194 | return priv->state; | ||
195 | /* unlock */ | ||
196 | } | ||
197 | |||
198 | islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); | ||
199 | |||
200 | #define ISLPCI_TX_TIMEOUT (2*HZ) | ||
201 | |||
202 | irqreturn_t islpci_interrupt(int, void *, struct pt_regs *); | ||
203 | |||
204 | int prism54_post_setup(islpci_private *, int); | ||
205 | int islpci_reset(islpci_private *, int); | ||
206 | |||
207 | static inline void | ||
208 | islpci_trigger(islpci_private *priv) | ||
209 | { | ||
210 | isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP, | ||
211 | priv->device_base); | ||
212 | } | ||
213 | |||
214 | int islpci_free_memory(islpci_private *); | ||
215 | struct net_device *islpci_setup(struct pci_dev *); | ||
216 | #endif /* _ISLPCI_DEV_H */ | ||
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c new file mode 100644 index 000000000000..5952e9960499 --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_eth.c | |||
@@ -0,0 +1,519 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
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 | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/version.h> | ||
21 | #include <linux/module.h> | ||
22 | |||
23 | #include <linux/pci.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/if_arp.h> | ||
28 | |||
29 | #include "prismcompat.h" | ||
30 | #include "isl_38xx.h" | ||
31 | #include "islpci_eth.h" | ||
32 | #include "islpci_mgt.h" | ||
33 | #include "oid_mgt.h" | ||
34 | |||
35 | /****************************************************************************** | ||
36 | Network Interface functions | ||
37 | ******************************************************************************/ | ||
38 | void | ||
39 | islpci_eth_cleanup_transmit(islpci_private *priv, | ||
40 | isl38xx_control_block *control_block) | ||
41 | { | ||
42 | struct sk_buff *skb; | ||
43 | u32 index; | ||
44 | |||
45 | /* compare the control block read pointer with the free pointer */ | ||
46 | while (priv->free_data_tx != | ||
47 | le32_to_cpu(control_block-> | ||
48 | device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) { | ||
49 | /* read the index of the first fragment to be freed */ | ||
50 | index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE; | ||
51 | |||
52 | /* check for holes in the arrays caused by multi fragment frames | ||
53 | * searching for the last fragment of a frame */ | ||
54 | if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { | ||
55 | /* entry is the last fragment of a frame | ||
56 | * free the skb structure and unmap pci memory */ | ||
57 | skb = priv->data_low_tx[index]; | ||
58 | |||
59 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
60 | DEBUG(SHOW_TRACING, | ||
61 | "cleanup skb %p skb->data %p skb->len %u truesize %u\n ", | ||
62 | skb, skb->data, skb->len, skb->truesize); | ||
63 | #endif | ||
64 | |||
65 | pci_unmap_single(priv->pdev, | ||
66 | priv->pci_map_tx_address[index], | ||
67 | skb->len, PCI_DMA_TODEVICE); | ||
68 | dev_kfree_skb_irq(skb); | ||
69 | skb = NULL; | ||
70 | } | ||
71 | /* increment the free data low queue pointer */ | ||
72 | priv->free_data_tx++; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | int | ||
77 | islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) | ||
78 | { | ||
79 | islpci_private *priv = netdev_priv(ndev); | ||
80 | isl38xx_control_block *cb = priv->control_block; | ||
81 | u32 index; | ||
82 | dma_addr_t pci_map_address; | ||
83 | int frame_size; | ||
84 | isl38xx_fragment *fragment; | ||
85 | int offset; | ||
86 | struct sk_buff *newskb; | ||
87 | int newskb_offset; | ||
88 | unsigned long flags; | ||
89 | unsigned char wds_mac[6]; | ||
90 | u32 curr_frag; | ||
91 | int err = 0; | ||
92 | |||
93 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
94 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); | ||
95 | #endif | ||
96 | |||
97 | /* lock the driver code */ | ||
98 | spin_lock_irqsave(&priv->slock, flags); | ||
99 | |||
100 | /* determine the amount of fragments needed to store the frame */ | ||
101 | |||
102 | frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; | ||
103 | if (init_wds) | ||
104 | frame_size += 6; | ||
105 | |||
106 | /* check whether the destination queue has enough fragments for the frame */ | ||
107 | curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); | ||
108 | if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { | ||
109 | printk(KERN_ERR "%s: transmit device queue full when awake\n", | ||
110 | ndev->name); | ||
111 | netif_stop_queue(ndev); | ||
112 | |||
113 | /* trigger the device */ | ||
114 | isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, | ||
115 | ISL38XX_DEV_INT_REG); | ||
116 | udelay(ISL38XX_WRITEIO_DELAY); | ||
117 | |||
118 | err = -EBUSY; | ||
119 | goto drop_free; | ||
120 | } | ||
121 | /* Check alignment and WDS frame formatting. The start of the packet should | ||
122 | * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes | ||
123 | * and add WDS address information */ | ||
124 | if (likely(((long) skb->data & 0x03) | init_wds)) { | ||
125 | /* get the number of bytes to add and re-allign */ | ||
126 | offset = (4 - (long) skb->data) & 0x03; | ||
127 | offset += init_wds ? 6 : 0; | ||
128 | |||
129 | /* check whether the current skb can be used */ | ||
130 | if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { | ||
131 | unsigned char *src = skb->data; | ||
132 | |||
133 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
134 | DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, | ||
135 | init_wds); | ||
136 | #endif | ||
137 | |||
138 | /* align the buffer on 4-byte boundary */ | ||
139 | skb_reserve(skb, (4 - (long) skb->data) & 0x03); | ||
140 | if (init_wds) { | ||
141 | /* wds requires an additional address field of 6 bytes */ | ||
142 | skb_put(skb, 6); | ||
143 | #ifdef ISLPCI_ETH_DEBUG | ||
144 | printk("islpci_eth_transmit:wds_mac\n"); | ||
145 | #endif | ||
146 | memmove(skb->data + 6, src, skb->len); | ||
147 | memcpy(skb->data, wds_mac, 6); | ||
148 | } else { | ||
149 | memmove(skb->data, src, skb->len); | ||
150 | } | ||
151 | |||
152 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
153 | DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data, | ||
154 | src, skb->len); | ||
155 | #endif | ||
156 | } else { | ||
157 | newskb = | ||
158 | dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); | ||
159 | if (unlikely(newskb == NULL)) { | ||
160 | printk(KERN_ERR "%s: Cannot allocate skb\n", | ||
161 | ndev->name); | ||
162 | err = -ENOMEM; | ||
163 | goto drop_free; | ||
164 | } | ||
165 | newskb_offset = (4 - (long) newskb->data) & 0x03; | ||
166 | |||
167 | /* Check if newskb->data is aligned */ | ||
168 | if (newskb_offset) | ||
169 | skb_reserve(newskb, newskb_offset); | ||
170 | |||
171 | skb_put(newskb, init_wds ? skb->len + 6 : skb->len); | ||
172 | if (init_wds) { | ||
173 | memcpy(newskb->data + 6, skb->data, skb->len); | ||
174 | memcpy(newskb->data, wds_mac, 6); | ||
175 | #ifdef ISLPCI_ETH_DEBUG | ||
176 | printk("islpci_eth_transmit:wds_mac\n"); | ||
177 | #endif | ||
178 | } else | ||
179 | memcpy(newskb->data, skb->data, skb->len); | ||
180 | |||
181 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
182 | DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", | ||
183 | newskb->data, skb->data, skb->len, init_wds); | ||
184 | #endif | ||
185 | |||
186 | newskb->dev = skb->dev; | ||
187 | dev_kfree_skb(skb); | ||
188 | skb = newskb; | ||
189 | } | ||
190 | } | ||
191 | /* display the buffer contents for debugging */ | ||
192 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
193 | DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); | ||
194 | display_buffer((char *) skb->data, skb->len); | ||
195 | #endif | ||
196 | |||
197 | /* map the skb buffer to pci memory for DMA operation */ | ||
198 | pci_map_address = pci_map_single(priv->pdev, | ||
199 | (void *) skb->data, skb->len, | ||
200 | PCI_DMA_TODEVICE); | ||
201 | if (unlikely(pci_map_address == 0)) { | ||
202 | printk(KERN_WARNING "%s: cannot map buffer to PCI\n", | ||
203 | ndev->name); | ||
204 | |||
205 | err = -EIO; | ||
206 | goto drop_free; | ||
207 | } | ||
208 | /* Place the fragment in the control block structure. */ | ||
209 | index = curr_frag % ISL38XX_CB_TX_QSIZE; | ||
210 | fragment = &cb->tx_data_low[index]; | ||
211 | |||
212 | priv->pci_map_tx_address[index] = pci_map_address; | ||
213 | /* store the skb address for future freeing */ | ||
214 | priv->data_low_tx[index] = skb; | ||
215 | /* set the proper fragment start address and size information */ | ||
216 | fragment->size = cpu_to_le16(frame_size); | ||
217 | fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ | ||
218 | fragment->address = cpu_to_le32(pci_map_address); | ||
219 | curr_frag++; | ||
220 | |||
221 | /* The fragment address in the control block must have been | ||
222 | * written before announcing the frame buffer to device. */ | ||
223 | wmb(); | ||
224 | cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); | ||
225 | |||
226 | if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD | ||
227 | > ISL38XX_CB_TX_QSIZE) { | ||
228 | /* stop sends from upper layers */ | ||
229 | netif_stop_queue(ndev); | ||
230 | |||
231 | /* set the full flag for the transmission queue */ | ||
232 | priv->data_low_tx_full = 1; | ||
233 | } | ||
234 | |||
235 | /* trigger the device */ | ||
236 | islpci_trigger(priv); | ||
237 | |||
238 | /* unlock the driver code */ | ||
239 | spin_unlock_irqrestore(&priv->slock, flags); | ||
240 | |||
241 | /* set the transmission time */ | ||
242 | ndev->trans_start = jiffies; | ||
243 | priv->statistics.tx_packets++; | ||
244 | priv->statistics.tx_bytes += skb->len; | ||
245 | |||
246 | return 0; | ||
247 | |||
248 | drop_free: | ||
249 | /* free the skbuf structure before aborting */ | ||
250 | dev_kfree_skb(skb); | ||
251 | skb = NULL; | ||
252 | |||
253 | priv->statistics.tx_dropped++; | ||
254 | spin_unlock_irqrestore(&priv->slock, flags); | ||
255 | return err; | ||
256 | } | ||
257 | |||
258 | static inline int | ||
259 | islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) | ||
260 | { | ||
261 | /* The card reports full 802.11 packets but with a 20 bytes | ||
262 | * header and without the FCS. But there a is a bit that | ||
263 | * indicates if the packet is corrupted :-) */ | ||
264 | struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data; | ||
265 | if (hdr->flags & 0x01) | ||
266 | /* This one is bad. Drop it ! */ | ||
267 | return -1; | ||
268 | if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) { | ||
269 | struct avs_80211_1_header *avs; | ||
270 | /* extract the relevant data from the header */ | ||
271 | u32 clock = le32_to_cpu(hdr->clock); | ||
272 | u8 rate = hdr->rate; | ||
273 | u16 freq = le16_to_cpu(hdr->freq); | ||
274 | u8 rssi = hdr->rssi; | ||
275 | |||
276 | skb_pull(*skb, sizeof (struct rfmon_header)); | ||
277 | |||
278 | if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) { | ||
279 | struct sk_buff *newskb = skb_copy_expand(*skb, | ||
280 | sizeof (struct | ||
281 | avs_80211_1_header), | ||
282 | 0, GFP_ATOMIC); | ||
283 | if (newskb) { | ||
284 | dev_kfree_skb_irq(*skb); | ||
285 | *skb = newskb; | ||
286 | } else | ||
287 | return -1; | ||
288 | /* This behavior is not very subtile... */ | ||
289 | } | ||
290 | |||
291 | /* make room for the new header and fill it. */ | ||
292 | avs = | ||
293 | (struct avs_80211_1_header *) skb_push(*skb, | ||
294 | sizeof (struct | ||
295 | avs_80211_1_header)); | ||
296 | |||
297 | avs->version = cpu_to_be32(P80211CAPTURE_VERSION); | ||
298 | avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); | ||
299 | avs->mactime = cpu_to_be64(le64_to_cpu(clock)); | ||
300 | avs->hosttime = cpu_to_be64(jiffies); | ||
301 | avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */ | ||
302 | avs->channel = cpu_to_be32(channel_of_freq(freq)); | ||
303 | avs->datarate = cpu_to_be32(rate * 5); | ||
304 | avs->antenna = cpu_to_be32(0); /*unknown */ | ||
305 | avs->priority = cpu_to_be32(0); /*unknown */ | ||
306 | avs->ssi_type = cpu_to_be32(3); /*2: dBm, 3: raw RSSI */ | ||
307 | avs->ssi_signal = cpu_to_be32(rssi & 0x7f); | ||
308 | avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise); /*better than 'undefined', I assume */ | ||
309 | avs->preamble = cpu_to_be32(0); /*unknown */ | ||
310 | avs->encoding = cpu_to_be32(0); /*unknown */ | ||
311 | } else | ||
312 | skb_pull(*skb, sizeof (struct rfmon_header)); | ||
313 | |||
314 | (*skb)->protocol = htons(ETH_P_802_2); | ||
315 | (*skb)->mac.raw = (*skb)->data; | ||
316 | (*skb)->pkt_type = PACKET_OTHERHOST; | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | int | ||
322 | islpci_eth_receive(islpci_private *priv) | ||
323 | { | ||
324 | struct net_device *ndev = priv->ndev; | ||
325 | isl38xx_control_block *control_block = priv->control_block; | ||
326 | struct sk_buff *skb; | ||
327 | u16 size; | ||
328 | u32 index, offset; | ||
329 | unsigned char *src; | ||
330 | int discard = 0; | ||
331 | |||
332 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
333 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n"); | ||
334 | #endif | ||
335 | |||
336 | /* the device has written an Ethernet frame in the data area | ||
337 | * of the sk_buff without updating the structure, do it now */ | ||
338 | index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE; | ||
339 | size = le16_to_cpu(control_block->rx_data_low[index].size); | ||
340 | skb = priv->data_low_rx[index]; | ||
341 | offset = ((unsigned long) | ||
342 | le32_to_cpu(control_block->rx_data_low[index].address) - | ||
343 | (unsigned long) skb->data) & 3; | ||
344 | |||
345 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
346 | DEBUG(SHOW_TRACING, | ||
347 | "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ", | ||
348 | control_block->rx_data_low[priv->free_data_rx].address, skb->data, | ||
349 | skb->len, offset, skb->truesize); | ||
350 | #endif | ||
351 | |||
352 | /* delete the streaming DMA mapping before processing the skb */ | ||
353 | pci_unmap_single(priv->pdev, | ||
354 | priv->pci_map_rx_address[index], | ||
355 | MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); | ||
356 | |||
357 | /* update the skb structure and allign the buffer */ | ||
358 | skb_put(skb, size); | ||
359 | if (offset) { | ||
360 | /* shift the buffer allocation offset bytes to get the right frame */ | ||
361 | skb_pull(skb, 2); | ||
362 | skb_put(skb, 2); | ||
363 | } | ||
364 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
365 | /* display the buffer contents for debugging */ | ||
366 | DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); | ||
367 | display_buffer((char *) skb->data, skb->len); | ||
368 | #endif | ||
369 | |||
370 | /* check whether WDS is enabled and whether the data frame is a WDS frame */ | ||
371 | |||
372 | if (init_wds) { | ||
373 | /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */ | ||
374 | src = skb->data + 6; | ||
375 | memmove(skb->data, src, skb->len - 6); | ||
376 | skb_trim(skb, skb->len - 6); | ||
377 | } | ||
378 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
379 | DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb); | ||
380 | DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len); | ||
381 | |||
382 | /* display the buffer contents for debugging */ | ||
383 | DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); | ||
384 | display_buffer((char *) skb->data, skb->len); | ||
385 | #endif | ||
386 | |||
387 | /* do some additional sk_buff and network layer parameters */ | ||
388 | skb->dev = ndev; | ||
389 | |||
390 | /* take care of monitor mode and spy monitoring. */ | ||
391 | if (unlikely(priv->iw_mode == IW_MODE_MONITOR)) | ||
392 | discard = islpci_monitor_rx(priv, &skb); | ||
393 | else { | ||
394 | if (unlikely(skb->data[2 * ETH_ALEN] == 0)) { | ||
395 | /* The packet has a rx_annex. Read it for spy monitoring, Then | ||
396 | * remove it, while keeping the 2 leading MAC addr. | ||
397 | */ | ||
398 | struct iw_quality wstats; | ||
399 | struct rx_annex_header *annex = | ||
400 | (struct rx_annex_header *) skb->data; | ||
401 | wstats.level = annex->rfmon.rssi; | ||
402 | /* The noise value can be a bit outdated if nobody's | ||
403 | * reading wireless stats... */ | ||
404 | wstats.noise = priv->local_iwstatistics.qual.noise; | ||
405 | wstats.qual = wstats.level - wstats.noise; | ||
406 | wstats.updated = 0x07; | ||
407 | /* Update spy records */ | ||
408 | wireless_spy_update(ndev, annex->addr2, &wstats); | ||
409 | |||
410 | memcpy(skb->data + sizeof (struct rfmon_header), | ||
411 | skb->data, 2 * ETH_ALEN); | ||
412 | skb_pull(skb, sizeof (struct rfmon_header)); | ||
413 | } | ||
414 | skb->protocol = eth_type_trans(skb, ndev); | ||
415 | } | ||
416 | skb->ip_summed = CHECKSUM_NONE; | ||
417 | priv->statistics.rx_packets++; | ||
418 | priv->statistics.rx_bytes += size; | ||
419 | |||
420 | /* deliver the skb to the network layer */ | ||
421 | #ifdef ISLPCI_ETH_DEBUG | ||
422 | printk | ||
423 | ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", | ||
424 | skb->data[0], skb->data[1], skb->data[2], skb->data[3], | ||
425 | skb->data[4], skb->data[5]); | ||
426 | #endif | ||
427 | if (unlikely(discard)) { | ||
428 | dev_kfree_skb_irq(skb); | ||
429 | skb = NULL; | ||
430 | } else | ||
431 | netif_rx(skb); | ||
432 | |||
433 | /* increment the read index for the rx data low queue */ | ||
434 | priv->free_data_rx++; | ||
435 | |||
436 | /* add one or more sk_buff structures */ | ||
437 | while (index = | ||
438 | le32_to_cpu(control_block-> | ||
439 | driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]), | ||
440 | index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) { | ||
441 | /* allocate an sk_buff for received data frames storage | ||
442 | * include any required allignment operations */ | ||
443 | skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2); | ||
444 | if (unlikely(skb == NULL)) { | ||
445 | /* error allocating an sk_buff structure elements */ | ||
446 | DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n"); | ||
447 | break; | ||
448 | } | ||
449 | skb_reserve(skb, (4 - (long) skb->data) & 0x03); | ||
450 | /* store the new skb structure pointer */ | ||
451 | index = index % ISL38XX_CB_RX_QSIZE; | ||
452 | priv->data_low_rx[index] = skb; | ||
453 | |||
454 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
455 | DEBUG(SHOW_TRACING, | ||
456 | "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ", | ||
457 | skb, skb->data, skb->len, index, skb->truesize); | ||
458 | #endif | ||
459 | |||
460 | /* set the streaming DMA mapping for proper PCI bus operation */ | ||
461 | priv->pci_map_rx_address[index] = | ||
462 | pci_map_single(priv->pdev, (void *) skb->data, | ||
463 | MAX_FRAGMENT_SIZE_RX + 2, | ||
464 | PCI_DMA_FROMDEVICE); | ||
465 | if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) { | ||
466 | /* error mapping the buffer to device accessable memory address */ | ||
467 | DEBUG(SHOW_ERROR_MESSAGES, | ||
468 | "Error mapping DMA address\n"); | ||
469 | |||
470 | /* free the skbuf structure before aborting */ | ||
471 | dev_kfree_skb_irq((struct sk_buff *) skb); | ||
472 | skb = NULL; | ||
473 | break; | ||
474 | } | ||
475 | /* update the fragment address */ | ||
476 | control_block->rx_data_low[index].address = cpu_to_le32((u32) | ||
477 | priv-> | ||
478 | pci_map_rx_address | ||
479 | [index]); | ||
480 | wmb(); | ||
481 | |||
482 | /* increment the driver read pointer */ | ||
483 | add_le32p((u32 *) &control_block-> | ||
484 | driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); | ||
485 | } | ||
486 | |||
487 | /* trigger the device */ | ||
488 | islpci_trigger(priv); | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | void | ||
494 | islpci_do_reset_and_wake(void *data) | ||
495 | { | ||
496 | islpci_private *priv = (islpci_private *) data; | ||
497 | islpci_reset(priv, 1); | ||
498 | netif_wake_queue(priv->ndev); | ||
499 | priv->reset_task_pending = 0; | ||
500 | } | ||
501 | |||
502 | void | ||
503 | islpci_eth_tx_timeout(struct net_device *ndev) | ||
504 | { | ||
505 | islpci_private *priv = netdev_priv(ndev); | ||
506 | struct net_device_stats *statistics = &priv->statistics; | ||
507 | |||
508 | /* increment the transmit error counter */ | ||
509 | statistics->tx_errors++; | ||
510 | |||
511 | printk(KERN_WARNING "%s: tx_timeout", ndev->name); | ||
512 | if (!priv->reset_task_pending) { | ||
513 | priv->reset_task_pending = 1; | ||
514 | printk(", scheduling a reset"); | ||
515 | netif_stop_queue(ndev); | ||
516 | schedule_work(&priv->reset_task); | ||
517 | } | ||
518 | printk("\n"); | ||
519 | } | ||
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h new file mode 100644 index 000000000000..bc9d7a60b8d6 --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_eth.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
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 | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #ifndef _ISLPCI_ETH_H | ||
21 | #define _ISLPCI_ETH_H | ||
22 | |||
23 | #include "isl_38xx.h" | ||
24 | #include "islpci_dev.h" | ||
25 | |||
26 | struct rfmon_header { | ||
27 | u16 unk0; /* = 0x0000 */ | ||
28 | u16 length; /* = 0x1400 */ | ||
29 | u32 clock; /* 1MHz clock */ | ||
30 | u8 flags; | ||
31 | u8 unk1; | ||
32 | u8 rate; | ||
33 | u8 unk2; | ||
34 | u16 freq; | ||
35 | u16 unk3; | ||
36 | u8 rssi; | ||
37 | u8 padding[3]; | ||
38 | } __attribute__ ((packed)); | ||
39 | |||
40 | struct rx_annex_header { | ||
41 | u8 addr1[ETH_ALEN]; | ||
42 | u8 addr2[ETH_ALEN]; | ||
43 | struct rfmon_header rfmon; | ||
44 | } __attribute__ ((packed)); | ||
45 | |||
46 | /* wlan-ng (and hopefully others) AVS header, version one. Fields in | ||
47 | * network byte order. */ | ||
48 | #define P80211CAPTURE_VERSION 0x80211001 | ||
49 | |||
50 | struct avs_80211_1_header { | ||
51 | uint32_t version; | ||
52 | uint32_t length; | ||
53 | uint64_t mactime; | ||
54 | uint64_t hosttime; | ||
55 | uint32_t phytype; | ||
56 | uint32_t channel; | ||
57 | uint32_t datarate; | ||
58 | uint32_t antenna; | ||
59 | uint32_t priority; | ||
60 | uint32_t ssi_type; | ||
61 | int32_t ssi_signal; | ||
62 | int32_t ssi_noise; | ||
63 | uint32_t preamble; | ||
64 | uint32_t encoding; | ||
65 | }; | ||
66 | |||
67 | void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); | ||
68 | int islpci_eth_transmit(struct sk_buff *, struct net_device *); | ||
69 | int islpci_eth_receive(islpci_private *); | ||
70 | void islpci_eth_tx_timeout(struct net_device *); | ||
71 | void islpci_do_reset_and_wake(void *data); | ||
72 | |||
73 | #endif /* _ISL_GEN_H */ | ||
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c new file mode 100644 index 000000000000..efd4d213ac3d --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_hotplug.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> | ||
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 | ||
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 | |||
21 | #include <linux/version.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/init.h> /* For __init, __exit */ | ||
26 | |||
27 | #include "prismcompat.h" | ||
28 | #include "islpci_dev.h" | ||
29 | #include "islpci_mgt.h" /* for pc_debug */ | ||
30 | #include "isl_oid.h" | ||
31 | |||
32 | #define DRV_NAME "prism54" | ||
33 | #define DRV_VERSION "1.2" | ||
34 | |||
35 | MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>"); | ||
36 | MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | static int init_pcitm = 0; | ||
40 | module_param(init_pcitm, int, 0); | ||
41 | |||
42 | /* In this order: vendor, device, subvendor, subdevice, class, class_mask, | ||
43 | * driver_data | ||
44 | * If you have an update for this please contact prism54-devel@prism54.org | ||
45 | * The latest list can be found at http://prism54.org/supported_cards.php */ | ||
46 | static const struct pci_device_id prism54_id_tbl[] = { | ||
47 | /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ | ||
48 | { | ||
49 | 0x1260, 0x3890, | ||
50 | PCI_ANY_ID, PCI_ANY_ID, | ||
51 | 0, 0, 0 | ||
52 | }, | ||
53 | |||
54 | /* 3COM 3CRWE154G72 Wireless LAN adapter */ | ||
55 | { | ||
56 | 0x10b7, 0x6001, | ||
57 | PCI_ANY_ID, PCI_ANY_ID, | ||
58 | 0, 0, 0 | ||
59 | }, | ||
60 | |||
61 | /* Intersil PRISM Indigo Wireless LAN adapter */ | ||
62 | { | ||
63 | 0x1260, 0x3877, | ||
64 | PCI_ANY_ID, PCI_ANY_ID, | ||
65 | 0, 0, 0 | ||
66 | }, | ||
67 | |||
68 | /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ | ||
69 | { | ||
70 | 0x1260, 0x3886, | ||
71 | PCI_ANY_ID, PCI_ANY_ID, | ||
72 | 0, 0, 0 | ||
73 | }, | ||
74 | |||
75 | /* End of list */ | ||
76 | {0,0,0,0,0,0,0} | ||
77 | }; | ||
78 | |||
79 | /* register the device with the Hotplug facilities of the kernel */ | ||
80 | MODULE_DEVICE_TABLE(pci, prism54_id_tbl); | ||
81 | |||
82 | static int prism54_probe(struct pci_dev *, const struct pci_device_id *); | ||
83 | static void prism54_remove(struct pci_dev *); | ||
84 | static int prism54_suspend(struct pci_dev *, u32 state); | ||
85 | static int prism54_resume(struct pci_dev *); | ||
86 | |||
87 | static struct pci_driver prism54_driver = { | ||
88 | .name = DRV_NAME, | ||
89 | .id_table = prism54_id_tbl, | ||
90 | .probe = prism54_probe, | ||
91 | .remove = prism54_remove, | ||
92 | .suspend = prism54_suspend, | ||
93 | .resume = prism54_resume, | ||
94 | /* .enable_wake ; we don't support this yet */ | ||
95 | }; | ||
96 | |||
97 | /****************************************************************************** | ||
98 | Module initialization functions | ||
99 | ******************************************************************************/ | ||
100 | |||
101 | int | ||
102 | prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
103 | { | ||
104 | struct net_device *ndev; | ||
105 | u8 latency_tmr; | ||
106 | u32 mem_addr; | ||
107 | islpci_private *priv; | ||
108 | int rvalue; | ||
109 | |||
110 | /* Enable the pci device */ | ||
111 | if (pci_enable_device(pdev)) { | ||
112 | printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); | ||
113 | return -ENODEV; | ||
114 | } | ||
115 | |||
116 | /* check whether the latency timer is set correctly */ | ||
117 | pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); | ||
118 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
119 | DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); | ||
120 | #endif | ||
121 | if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { | ||
122 | /* set the latency timer */ | ||
123 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, | ||
124 | PCIDEVICE_LATENCY_TIMER_VAL); | ||
125 | } | ||
126 | |||
127 | /* enable PCI DMA */ | ||
128 | if (pci_set_dma_mask(pdev, 0xffffffff)) { | ||
129 | printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); | ||
130 | goto do_pci_disable_device; | ||
131 | } | ||
132 | |||
133 | /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) | ||
134 | * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) | ||
135 | * The RETRY_TIMEOUT is used to set the number of retries that the core, as a | ||
136 | * Master, will perform before abandoning a cycle. The default value for | ||
137 | * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new | ||
138 | * devices. A write of zero to the RETRY_TIMEOUT register disables this | ||
139 | * function to allow use with any non-compliant legacy devices that may | ||
140 | * execute more retries. | ||
141 | * | ||
142 | * Writing zero to both these two registers will disable both timeouts and | ||
143 | * *can* solve problems caused by devices that are slow to respond. | ||
144 | * Make this configurable - MSW | ||
145 | */ | ||
146 | if ( init_pcitm >= 0 ) { | ||
147 | pci_write_config_byte(pdev, 0x40, (u8)init_pcitm); | ||
148 | pci_write_config_byte(pdev, 0x41, (u8)init_pcitm); | ||
149 | } else { | ||
150 | printk(KERN_INFO "PCI TRDY/RETRY unchanged\n"); | ||
151 | } | ||
152 | |||
153 | /* request the pci device I/O regions */ | ||
154 | rvalue = pci_request_regions(pdev, DRV_NAME); | ||
155 | if (rvalue) { | ||
156 | printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", | ||
157 | DRV_NAME, rvalue); | ||
158 | goto do_pci_disable_device; | ||
159 | } | ||
160 | |||
161 | /* check if the memory window is indeed set */ | ||
162 | rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); | ||
163 | if (rvalue || !mem_addr) { | ||
164 | printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", | ||
165 | DRV_NAME); | ||
166 | goto do_pci_release_regions; | ||
167 | } | ||
168 | |||
169 | /* enable PCI bus-mastering */ | ||
170 | DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); | ||
171 | pci_set_master(pdev); | ||
172 | |||
173 | /* enable MWI */ | ||
174 | pci_set_mwi(pdev); | ||
175 | |||
176 | /* setup the network device interface and its structure */ | ||
177 | if (!(ndev = islpci_setup(pdev))) { | ||
178 | /* error configuring the driver as a network device */ | ||
179 | printk(KERN_ERR "%s: could not configure network device\n", | ||
180 | DRV_NAME); | ||
181 | goto do_pci_release_regions; | ||
182 | } | ||
183 | |||
184 | priv = netdev_priv(ndev); | ||
185 | islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ | ||
186 | |||
187 | /* card is in unknown state yet, might have some interrupts pending */ | ||
188 | isl38xx_disable_interrupts(priv->device_base); | ||
189 | |||
190 | /* request for the interrupt before uploading the firmware */ | ||
191 | rvalue = request_irq(pdev->irq, &islpci_interrupt, | ||
192 | SA_SHIRQ, ndev->name, priv); | ||
193 | |||
194 | if (rvalue) { | ||
195 | /* error, could not hook the handler to the irq */ | ||
196 | printk(KERN_ERR "%s: could not install IRQ handler\n", | ||
197 | ndev->name); | ||
198 | goto do_unregister_netdev; | ||
199 | } | ||
200 | |||
201 | /* firmware upload is triggered in islpci_open */ | ||
202 | |||
203 | return 0; | ||
204 | |||
205 | do_unregister_netdev: | ||
206 | unregister_netdev(ndev); | ||
207 | islpci_free_memory(priv); | ||
208 | pci_set_drvdata(pdev, NULL); | ||
209 | free_netdev(ndev); | ||
210 | priv = NULL; | ||
211 | do_pci_release_regions: | ||
212 | pci_release_regions(pdev); | ||
213 | do_pci_disable_device: | ||
214 | pci_disable_device(pdev); | ||
215 | return -EIO; | ||
216 | } | ||
217 | |||
218 | /* set by cleanup_module */ | ||
219 | static volatile int __in_cleanup_module = 0; | ||
220 | |||
221 | /* this one removes one(!!) instance only */ | ||
222 | void | ||
223 | prism54_remove(struct pci_dev *pdev) | ||
224 | { | ||
225 | struct net_device *ndev = pci_get_drvdata(pdev); | ||
226 | islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; | ||
227 | BUG_ON(!priv); | ||
228 | |||
229 | if (!__in_cleanup_module) { | ||
230 | printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); | ||
231 | islpci_set_state(priv, PRV_STATE_OFF); | ||
232 | } | ||
233 | |||
234 | printk(KERN_DEBUG "%s: removing device\n", ndev->name); | ||
235 | |||
236 | unregister_netdev(ndev); | ||
237 | |||
238 | /* free the interrupt request */ | ||
239 | |||
240 | if (islpci_get_state(priv) != PRV_STATE_OFF) { | ||
241 | isl38xx_disable_interrupts(priv->device_base); | ||
242 | islpci_set_state(priv, PRV_STATE_OFF); | ||
243 | /* This bellow causes a lockup at rmmod time. It might be | ||
244 | * because some interrupts still linger after rmmod time, | ||
245 | * see bug #17 */ | ||
246 | /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ | ||
247 | } | ||
248 | |||
249 | free_irq(pdev->irq, priv); | ||
250 | |||
251 | /* free the PCI memory and unmap the remapped page */ | ||
252 | islpci_free_memory(priv); | ||
253 | |||
254 | pci_set_drvdata(pdev, NULL); | ||
255 | free_netdev(ndev); | ||
256 | priv = NULL; | ||
257 | |||
258 | pci_release_regions(pdev); | ||
259 | |||
260 | pci_disable_device(pdev); | ||
261 | } | ||
262 | |||
263 | int | ||
264 | prism54_suspend(struct pci_dev *pdev, u32 state) | ||
265 | { | ||
266 | struct net_device *ndev = pci_get_drvdata(pdev); | ||
267 | islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; | ||
268 | BUG_ON(!priv); | ||
269 | |||
270 | printk(KERN_NOTICE "%s: got suspend request (state %d)\n", | ||
271 | ndev->name, state); | ||
272 | |||
273 | pci_save_state(pdev); | ||
274 | |||
275 | /* tell the device not to trigger interrupts for now... */ | ||
276 | isl38xx_disable_interrupts(priv->device_base); | ||
277 | |||
278 | /* from now on assume the hardware was already powered down | ||
279 | and don't touch it anymore */ | ||
280 | islpci_set_state(priv, PRV_STATE_OFF); | ||
281 | |||
282 | netif_stop_queue(ndev); | ||
283 | netif_device_detach(ndev); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | int | ||
289 | prism54_resume(struct pci_dev *pdev) | ||
290 | { | ||
291 | struct net_device *ndev = pci_get_drvdata(pdev); | ||
292 | islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; | ||
293 | BUG_ON(!priv); | ||
294 | |||
295 | pci_enable_device(pdev); | ||
296 | |||
297 | printk(KERN_NOTICE "%s: got resume request\n", ndev->name); | ||
298 | |||
299 | pci_restore_state(pdev); | ||
300 | |||
301 | /* alright let's go into the PREBOOT state */ | ||
302 | islpci_reset(priv, 1); | ||
303 | |||
304 | netif_device_attach(ndev); | ||
305 | netif_start_queue(ndev); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int __init | ||
311 | prism54_module_init(void) | ||
312 | { | ||
313 | printk(KERN_INFO "Loaded %s driver, version %s\n", | ||
314 | DRV_NAME, DRV_VERSION); | ||
315 | |||
316 | __bug_on_wrong_struct_sizes (); | ||
317 | |||
318 | return pci_module_init(&prism54_driver); | ||
319 | } | ||
320 | |||
321 | /* by the time prism54_module_exit() terminates, as a postcondition | ||
322 | * all instances will have been destroyed by calls to | ||
323 | * prism54_remove() */ | ||
324 | static void __exit | ||
325 | prism54_module_exit(void) | ||
326 | { | ||
327 | __in_cleanup_module = 1; | ||
328 | |||
329 | pci_unregister_driver(&prism54_driver); | ||
330 | |||
331 | printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME); | ||
332 | |||
333 | __in_cleanup_module = 0; | ||
334 | } | ||
335 | |||
336 | /* register entry points */ | ||
337 | module_init(prism54_module_init); | ||
338 | module_exit(prism54_module_exit); | ||
339 | /* EOF */ | ||
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c new file mode 100644 index 000000000000..b6f2e5a223be --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_mgt.c | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net> | ||
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 | ||
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 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/pci.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <linux/if_arp.h> | ||
29 | |||
30 | #include "prismcompat.h" | ||
31 | #include "isl_38xx.h" | ||
32 | #include "islpci_mgt.h" | ||
33 | #include "isl_oid.h" /* additional types and defs for isl38xx fw */ | ||
34 | #include "isl_ioctl.h" | ||
35 | |||
36 | #include <net/iw_handler.h> | ||
37 | |||
38 | /****************************************************************************** | ||
39 | Global variable definition section | ||
40 | ******************************************************************************/ | ||
41 | int pc_debug = VERBOSE; | ||
42 | module_param(pc_debug, int, 0); | ||
43 | |||
44 | /****************************************************************************** | ||
45 | Driver general functions | ||
46 | ******************************************************************************/ | ||
47 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
48 | void | ||
49 | display_buffer(char *buffer, int length) | ||
50 | { | ||
51 | if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0) | ||
52 | return; | ||
53 | |||
54 | while (length > 0) { | ||
55 | printk("[%02x]", *buffer & 255); | ||
56 | length--; | ||
57 | buffer++; | ||
58 | } | ||
59 | |||
60 | printk("\n"); | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | /***************************************************************************** | ||
65 | Queue handling for management frames | ||
66 | ******************************************************************************/ | ||
67 | |||
68 | /* | ||
69 | * Helper function to create a PIMFOR management frame header. | ||
70 | */ | ||
71 | static void | ||
72 | pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h) | ||
73 | { | ||
74 | h->version = PIMFOR_VERSION; | ||
75 | h->operation = operation; | ||
76 | h->device_id = PIMFOR_DEV_ID_MHLI_MIB; | ||
77 | h->flags = 0; | ||
78 | h->oid = cpu_to_be32(oid); | ||
79 | h->length = cpu_to_be32(length); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Helper function to analyze a PIMFOR management frame header. | ||
84 | */ | ||
85 | static pimfor_header_t * | ||
86 | pimfor_decode_header(void *data, int len) | ||
87 | { | ||
88 | pimfor_header_t *h = data; | ||
89 | |||
90 | while ((void *) h < data + len) { | ||
91 | if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) { | ||
92 | le32_to_cpus(&h->oid); | ||
93 | le32_to_cpus(&h->length); | ||
94 | } else { | ||
95 | be32_to_cpus(&h->oid); | ||
96 | be32_to_cpus(&h->length); | ||
97 | } | ||
98 | if (h->oid != OID_INL_TUNNEL) | ||
99 | return h; | ||
100 | h++; | ||
101 | } | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Fill the receive queue for management frames with fresh buffers. | ||
107 | */ | ||
108 | int | ||
109 | islpci_mgmt_rx_fill(struct net_device *ndev) | ||
110 | { | ||
111 | islpci_private *priv = netdev_priv(ndev); | ||
112 | isl38xx_control_block *cb = /* volatile not needed */ | ||
113 | (isl38xx_control_block *) priv->control_block; | ||
114 | u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]); | ||
115 | |||
116 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
117 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n"); | ||
118 | #endif | ||
119 | |||
120 | while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) { | ||
121 | u32 index = curr % ISL38XX_CB_MGMT_QSIZE; | ||
122 | struct islpci_membuf *buf = &priv->mgmt_rx[index]; | ||
123 | isl38xx_fragment *frag = &cb->rx_data_mgmt[index]; | ||
124 | |||
125 | if (buf->mem == NULL) { | ||
126 | buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC); | ||
127 | if (!buf->mem) { | ||
128 | printk(KERN_WARNING | ||
129 | "Error allocating management frame.\n"); | ||
130 | return -ENOMEM; | ||
131 | } | ||
132 | buf->size = MGMT_FRAME_SIZE; | ||
133 | } | ||
134 | if (buf->pci_addr == 0) { | ||
135 | buf->pci_addr = pci_map_single(priv->pdev, buf->mem, | ||
136 | MGMT_FRAME_SIZE, | ||
137 | PCI_DMA_FROMDEVICE); | ||
138 | if (!buf->pci_addr) { | ||
139 | printk(KERN_WARNING | ||
140 | "Failed to make memory DMA'able\n."); | ||
141 | return -ENOMEM; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* be safe: always reset control block information */ | ||
146 | frag->size = cpu_to_le16(MGMT_FRAME_SIZE); | ||
147 | frag->flags = 0; | ||
148 | frag->address = cpu_to_le32(buf->pci_addr); | ||
149 | curr++; | ||
150 | |||
151 | /* The fragment address in the control block must have | ||
152 | * been written before announcing the frame buffer to | ||
153 | * device */ | ||
154 | wmb(); | ||
155 | cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr); | ||
156 | } | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Create and transmit a management frame using "operation" and "oid", | ||
162 | * with arguments data/length. | ||
163 | * We either return an error and free the frame, or we return 0 and | ||
164 | * islpci_mgt_cleanup_transmit() frees the frame in the tx-done | ||
165 | * interrupt. | ||
166 | */ | ||
167 | static int | ||
168 | islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, | ||
169 | void *data, int length) | ||
170 | { | ||
171 | islpci_private *priv = netdev_priv(ndev); | ||
172 | isl38xx_control_block *cb = | ||
173 | (isl38xx_control_block *) priv->control_block; | ||
174 | void *p; | ||
175 | int err = -EINVAL; | ||
176 | unsigned long flags; | ||
177 | isl38xx_fragment *frag; | ||
178 | struct islpci_membuf buf; | ||
179 | u32 curr_frag; | ||
180 | int index; | ||
181 | int frag_len = length + PIMFOR_HEADER_SIZE; | ||
182 | |||
183 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
184 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n"); | ||
185 | #endif | ||
186 | |||
187 | if (frag_len > MGMT_FRAME_SIZE) { | ||
188 | printk(KERN_DEBUG "%s: mgmt frame too large %d\n", | ||
189 | ndev->name, frag_len); | ||
190 | goto error; | ||
191 | } | ||
192 | |||
193 | err = -ENOMEM; | ||
194 | p = buf.mem = kmalloc(frag_len, GFP_KERNEL); | ||
195 | if (!buf.mem) { | ||
196 | printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n", | ||
197 | ndev->name); | ||
198 | goto error; | ||
199 | } | ||
200 | buf.size = frag_len; | ||
201 | |||
202 | /* create the header directly in the fragment data area */ | ||
203 | pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p); | ||
204 | p += PIMFOR_HEADER_SIZE; | ||
205 | |||
206 | if (data) | ||
207 | memcpy(p, data, length); | ||
208 | else | ||
209 | memset(p, 0, length); | ||
210 | |||
211 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
212 | { | ||
213 | pimfor_header_t *h = buf.mem; | ||
214 | DEBUG(SHOW_PIMFOR_FRAMES, | ||
215 | "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n", | ||
216 | h->operation, oid, h->device_id, h->flags, length); | ||
217 | |||
218 | /* display the buffer contents for debugging */ | ||
219 | display_buffer((char *) h, sizeof (pimfor_header_t)); | ||
220 | display_buffer(p, length); | ||
221 | } | ||
222 | #endif | ||
223 | |||
224 | err = -ENOMEM; | ||
225 | buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, | ||
226 | PCI_DMA_TODEVICE); | ||
227 | if (!buf.pci_addr) { | ||
228 | printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", | ||
229 | ndev->name); | ||
230 | goto error_free; | ||
231 | } | ||
232 | |||
233 | /* Protect the control block modifications against interrupts. */ | ||
234 | spin_lock_irqsave(&priv->slock, flags); | ||
235 | curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]); | ||
236 | if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) { | ||
237 | printk(KERN_WARNING "%s: mgmt tx queue is still full\n", | ||
238 | ndev->name); | ||
239 | goto error_unlock; | ||
240 | } | ||
241 | |||
242 | /* commit the frame to the tx device queue */ | ||
243 | index = curr_frag % ISL38XX_CB_MGMT_QSIZE; | ||
244 | priv->mgmt_tx[index] = buf; | ||
245 | frag = &cb->tx_data_mgmt[index]; | ||
246 | frag->size = cpu_to_le16(frag_len); | ||
247 | frag->flags = 0; /* for any other than the last fragment, set to 1 */ | ||
248 | frag->address = cpu_to_le32(buf.pci_addr); | ||
249 | |||
250 | /* The fragment address in the control block must have | ||
251 | * been written before announcing the frame buffer to | ||
252 | * device */ | ||
253 | wmb(); | ||
254 | cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1); | ||
255 | spin_unlock_irqrestore(&priv->slock, flags); | ||
256 | |||
257 | /* trigger the device */ | ||
258 | islpci_trigger(priv); | ||
259 | return 0; | ||
260 | |||
261 | error_unlock: | ||
262 | spin_unlock_irqrestore(&priv->slock, flags); | ||
263 | error_free: | ||
264 | kfree(buf.mem); | ||
265 | error: | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Receive a management frame from the device. | ||
271 | * This can be an arbitrary number of traps, and at most one response | ||
272 | * frame for a previous request sent via islpci_mgt_transmit(). | ||
273 | */ | ||
274 | int | ||
275 | islpci_mgt_receive(struct net_device *ndev) | ||
276 | { | ||
277 | islpci_private *priv = netdev_priv(ndev); | ||
278 | isl38xx_control_block *cb = | ||
279 | (isl38xx_control_block *) priv->control_block; | ||
280 | u32 curr_frag; | ||
281 | |||
282 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
283 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n"); | ||
284 | #endif | ||
285 | |||
286 | /* Only once per interrupt, determine fragment range to | ||
287 | * process. This avoids an endless loop (i.e. lockup) if | ||
288 | * frames come in faster than we can process them. */ | ||
289 | curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]); | ||
290 | barrier(); | ||
291 | |||
292 | for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) { | ||
293 | pimfor_header_t *header; | ||
294 | u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE; | ||
295 | struct islpci_membuf *buf = &priv->mgmt_rx[index]; | ||
296 | u16 frag_len; | ||
297 | int size; | ||
298 | struct islpci_mgmtframe *frame; | ||
299 | |||
300 | /* I have no idea (and no documentation) if flags != 0 | ||
301 | * is possible. Drop the frame, reuse the buffer. */ | ||
302 | if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) { | ||
303 | printk(KERN_WARNING "%s: unknown flags 0x%04x\n", | ||
304 | ndev->name, | ||
305 | le16_to_cpu(cb->rx_data_mgmt[index].flags)); | ||
306 | continue; | ||
307 | } | ||
308 | |||
309 | /* The device only returns the size of the header(s) here. */ | ||
310 | frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size); | ||
311 | |||
312 | /* | ||
313 | * We appear to have no way to tell the device the | ||
314 | * size of a receive buffer. Thus, if this check | ||
315 | * triggers, we likely have kernel heap corruption. */ | ||
316 | if (frag_len > MGMT_FRAME_SIZE) { | ||
317 | printk(KERN_WARNING | ||
318 | "%s: Bogus packet size of %d (%#x).\n", | ||
319 | ndev->name, frag_len, frag_len); | ||
320 | frag_len = MGMT_FRAME_SIZE; | ||
321 | } | ||
322 | |||
323 | /* Ensure the results of device DMA are visible to the CPU. */ | ||
324 | pci_dma_sync_single_for_cpu(priv->pdev, buf->pci_addr, | ||
325 | buf->size, PCI_DMA_FROMDEVICE); | ||
326 | |||
327 | /* Perform endianess conversion for PIMFOR header in-place. */ | ||
328 | header = pimfor_decode_header(buf->mem, frag_len); | ||
329 | if (!header) { | ||
330 | printk(KERN_WARNING "%s: no PIMFOR header found\n", | ||
331 | ndev->name); | ||
332 | continue; | ||
333 | } | ||
334 | |||
335 | /* The device ID from the PIMFOR packet received from | ||
336 | * the MVC is always 0. We forward a sensible device_id. | ||
337 | * Not that anyone upstream would care... */ | ||
338 | header->device_id = priv->ndev->ifindex; | ||
339 | |||
340 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
341 | DEBUG(SHOW_PIMFOR_FRAMES, | ||
342 | "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n", | ||
343 | header->operation, header->oid, header->device_id, | ||
344 | header->flags, header->length); | ||
345 | |||
346 | /* display the buffer contents for debugging */ | ||
347 | display_buffer((char *) header, PIMFOR_HEADER_SIZE); | ||
348 | display_buffer((char *) header + PIMFOR_HEADER_SIZE, | ||
349 | header->length); | ||
350 | #endif | ||
351 | |||
352 | /* nobody sends these */ | ||
353 | if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) { | ||
354 | printk(KERN_DEBUG | ||
355 | "%s: errant PIMFOR application frame\n", | ||
356 | ndev->name); | ||
357 | continue; | ||
358 | } | ||
359 | |||
360 | /* Determine frame size, skipping OID_INL_TUNNEL headers. */ | ||
361 | size = PIMFOR_HEADER_SIZE + header->length; | ||
362 | frame = kmalloc(sizeof (struct islpci_mgmtframe) + size, | ||
363 | GFP_ATOMIC); | ||
364 | if (!frame) { | ||
365 | printk(KERN_WARNING | ||
366 | "%s: Out of memory, cannot handle oid 0x%08x\n", | ||
367 | ndev->name, header->oid); | ||
368 | continue; | ||
369 | } | ||
370 | frame->ndev = ndev; | ||
371 | memcpy(&frame->buf, header, size); | ||
372 | frame->header = (pimfor_header_t *) frame->buf; | ||
373 | frame->data = frame->buf + PIMFOR_HEADER_SIZE; | ||
374 | |||
375 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
376 | DEBUG(SHOW_PIMFOR_FRAMES, | ||
377 | "frame: header: %p, data: %p, size: %d\n", | ||
378 | frame->header, frame->data, size); | ||
379 | #endif | ||
380 | |||
381 | if (header->operation == PIMFOR_OP_TRAP) { | ||
382 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
383 | printk(KERN_DEBUG | ||
384 | "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n", | ||
385 | header->oid, header->device_id, header->flags, | ||
386 | header->length); | ||
387 | #endif | ||
388 | |||
389 | /* Create work to handle trap out of interrupt | ||
390 | * context. */ | ||
391 | INIT_WORK(&frame->ws, prism54_process_trap, frame); | ||
392 | schedule_work(&frame->ws); | ||
393 | |||
394 | } else { | ||
395 | /* Signal the one waiting process that a response | ||
396 | * has been received. */ | ||
397 | if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) { | ||
398 | printk(KERN_WARNING | ||
399 | "%s: mgmt response not collected\n", | ||
400 | ndev->name); | ||
401 | kfree(frame); | ||
402 | } | ||
403 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
404 | DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n"); | ||
405 | #endif | ||
406 | wake_up(&priv->mgmt_wqueue); | ||
407 | } | ||
408 | |||
409 | } | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * Cleanup the transmit queue by freeing all frames handled by the device. | ||
416 | */ | ||
417 | void | ||
418 | islpci_mgt_cleanup_transmit(struct net_device *ndev) | ||
419 | { | ||
420 | islpci_private *priv = netdev_priv(ndev); | ||
421 | isl38xx_control_block *cb = /* volatile not needed */ | ||
422 | (isl38xx_control_block *) priv->control_block; | ||
423 | u32 curr_frag; | ||
424 | |||
425 | #if VERBOSE > SHOW_ERROR_MESSAGES | ||
426 | DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n"); | ||
427 | #endif | ||
428 | |||
429 | /* Only once per cleanup, determine fragment range to | ||
430 | * process. This avoids an endless loop (i.e. lockup) if | ||
431 | * the device became confused, incrementing device_curr_frag | ||
432 | * rapidly. */ | ||
433 | curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); | ||
434 | barrier(); | ||
435 | |||
436 | for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { | ||
437 | int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; | ||
438 | struct islpci_membuf *buf = &priv->mgmt_tx[index]; | ||
439 | pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, | ||
440 | PCI_DMA_TODEVICE); | ||
441 | buf->pci_addr = 0; | ||
442 | kfree(buf->mem); | ||
443 | buf->mem = NULL; | ||
444 | buf->size = 0; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * Perform one request-response transaction to the device. | ||
450 | */ | ||
451 | int | ||
452 | islpci_mgt_transaction(struct net_device *ndev, | ||
453 | int operation, unsigned long oid, | ||
454 | void *senddata, int sendlen, | ||
455 | struct islpci_mgmtframe **recvframe) | ||
456 | { | ||
457 | islpci_private *priv = netdev_priv(ndev); | ||
458 | const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; | ||
459 | long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; | ||
460 | int err; | ||
461 | DEFINE_WAIT(wait); | ||
462 | |||
463 | *recvframe = NULL; | ||
464 | |||
465 | if (down_interruptible(&priv->mgmt_sem)) | ||
466 | return -ERESTARTSYS; | ||
467 | |||
468 | prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); | ||
469 | err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); | ||
470 | if (err) | ||
471 | goto out; | ||
472 | |||
473 | err = -ETIMEDOUT; | ||
474 | while (timeout_left > 0) { | ||
475 | int timeleft; | ||
476 | struct islpci_mgmtframe *frame; | ||
477 | |||
478 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
479 | timeleft = schedule_timeout(wait_cycle_jiffies); | ||
480 | frame = xchg(&priv->mgmt_received, NULL); | ||
481 | if (frame) { | ||
482 | if (frame->header->oid == oid) { | ||
483 | *recvframe = frame; | ||
484 | err = 0; | ||
485 | goto out; | ||
486 | } else { | ||
487 | printk(KERN_DEBUG | ||
488 | "%s: expecting oid 0x%x, received 0x%x.\n", | ||
489 | ndev->name, (unsigned int) oid, | ||
490 | frame->header->oid); | ||
491 | kfree(frame); | ||
492 | frame = NULL; | ||
493 | } | ||
494 | } | ||
495 | if (timeleft == 0) { | ||
496 | printk(KERN_DEBUG | ||
497 | "%s: timeout waiting for mgmt response %lu, " | ||
498 | "triggering device\n", | ||
499 | ndev->name, timeout_left); | ||
500 | islpci_trigger(priv); | ||
501 | } | ||
502 | timeout_left += timeleft - wait_cycle_jiffies; | ||
503 | } | ||
504 | printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", | ||
505 | ndev->name); | ||
506 | |||
507 | /* TODO: we should reset the device here */ | ||
508 | out: | ||
509 | finish_wait(&priv->mgmt_wqueue, &wait); | ||
510 | up(&priv->mgmt_sem); | ||
511 | return err; | ||
512 | } | ||
513 | |||
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h new file mode 100644 index 000000000000..2982be3363ef --- /dev/null +++ b/drivers/net/wireless/prism54/islpci_mgt.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2002 Intersil Americas Inc. | ||
4 | * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> | ||
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 | ||
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 | |||
21 | #ifndef _ISLPCI_MGT_H | ||
22 | #define _ISLPCI_MGT_H | ||
23 | |||
24 | #include <linux/wireless.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | |||
27 | /* | ||
28 | * Function definitions | ||
29 | */ | ||
30 | |||
31 | #define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) | ||
32 | #define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) | ||
33 | |||
34 | extern int pc_debug; | ||
35 | #define init_wds 0 /* help compiler optimize away dead code */ | ||
36 | |||
37 | |||
38 | /* General driver definitions */ | ||
39 | #define PCIDEVICE_LATENCY_TIMER_MIN 0x40 | ||
40 | #define PCIDEVICE_LATENCY_TIMER_VAL 0x50 | ||
41 | |||
42 | /* Debugging verbose definitions */ | ||
43 | #define SHOW_NOTHING 0x00 /* overrules everything */ | ||
44 | #define SHOW_ANYTHING 0xFF | ||
45 | #define SHOW_ERROR_MESSAGES 0x01 | ||
46 | #define SHOW_TRAPS 0x02 | ||
47 | #define SHOW_FUNCTION_CALLS 0x04 | ||
48 | #define SHOW_TRACING 0x08 | ||
49 | #define SHOW_QUEUE_INDEXES 0x10 | ||
50 | #define SHOW_PIMFOR_FRAMES 0x20 | ||
51 | #define SHOW_BUFFER_CONTENTS 0x40 | ||
52 | #define VERBOSE 0x01 | ||
53 | |||
54 | /* Default card definitions */ | ||
55 | #define CARD_DEFAULT_CHANNEL 6 | ||
56 | #define CARD_DEFAULT_MODE INL_MODE_CLIENT | ||
57 | #define CARD_DEFAULT_IW_MODE IW_MODE_INFRA | ||
58 | #define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA | ||
59 | #define CARD_DEFAULT_CLIENT_SSID "" | ||
60 | #define CARD_DEFAULT_AP_SSID "default" | ||
61 | #define CARD_DEFAULT_KEY1 "default_key_1" | ||
62 | #define CARD_DEFAULT_KEY2 "default_key_2" | ||
63 | #define CARD_DEFAULT_KEY3 "default_key_3" | ||
64 | #define CARD_DEFAULT_KEY4 "default_key_4" | ||
65 | #define CARD_DEFAULT_WEP 0 | ||
66 | #define CARD_DEFAULT_FILTER 0 | ||
67 | #define CARD_DEFAULT_WDS 0 | ||
68 | #define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS | ||
69 | #define CARD_DEFAULT_DOT1X 0 | ||
70 | #define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO | ||
71 | #define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE | ||
72 | #define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI | ||
73 | #define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE | ||
74 | |||
75 | /* PIMFOR package definitions */ | ||
76 | #define PIMFOR_ETHERTYPE 0x8828 | ||
77 | #define PIMFOR_HEADER_SIZE 12 | ||
78 | #define PIMFOR_VERSION 1 | ||
79 | #define PIMFOR_OP_GET 0 | ||
80 | #define PIMFOR_OP_SET 1 | ||
81 | #define PIMFOR_OP_RESPONSE 2 | ||
82 | #define PIMFOR_OP_ERROR 3 | ||
83 | #define PIMFOR_OP_TRAP 4 | ||
84 | #define PIMFOR_OP_RESERVED 5 /* till 255 */ | ||
85 | #define PIMFOR_DEV_ID_MHLI_MIB 0 | ||
86 | #define PIMFOR_FLAG_APPLIC_ORIGIN 0x01 | ||
87 | #define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 | ||
88 | |||
89 | static inline void | ||
90 | add_le32p(u32 * le_number, u32 add) | ||
91 | { | ||
92 | *le_number = cpu_to_le32(le32_to_cpup(le_number) + add); | ||
93 | } | ||
94 | |||
95 | void display_buffer(char *, int); | ||
96 | |||
97 | /* | ||
98 | * Type definition section | ||
99 | * | ||
100 | * the structure defines only the header allowing copyless | ||
101 | * frame handling | ||
102 | */ | ||
103 | typedef struct { | ||
104 | u8 version; | ||
105 | u8 operation; | ||
106 | u32 oid; | ||
107 | u8 device_id; | ||
108 | u8 flags; | ||
109 | u32 length; | ||
110 | } __attribute__ ((packed)) | ||
111 | pimfor_header_t; | ||
112 | |||
113 | /* A received and interrupt-processed management frame, either for | ||
114 | * schedule_work(prism54_process_trap) or for priv->mgmt_received, | ||
115 | * processed by islpci_mgt_transaction(). */ | ||
116 | struct islpci_mgmtframe { | ||
117 | struct net_device *ndev; /* pointer to network device */ | ||
118 | pimfor_header_t *header; /* payload header, points into buf */ | ||
119 | void *data; /* payload ex header, points into buf */ | ||
120 | struct work_struct ws; /* argument for schedule_work() */ | ||
121 | char buf[0]; /* fragment buffer */ | ||
122 | }; | ||
123 | |||
124 | int | ||
125 | islpci_mgt_receive(struct net_device *ndev); | ||
126 | |||
127 | int | ||
128 | islpci_mgmt_rx_fill(struct net_device *ndev); | ||
129 | |||
130 | void | ||
131 | islpci_mgt_cleanup_transmit(struct net_device *ndev); | ||
132 | |||
133 | int | ||
134 | islpci_mgt_transaction(struct net_device *ndev, | ||
135 | int operation, unsigned long oid, | ||
136 | void *senddata, int sendlen, | ||
137 | struct islpci_mgmtframe **recvframe); | ||
138 | |||
139 | static inline void | ||
140 | islpci_mgt_release(struct islpci_mgmtframe *frame) | ||
141 | { | ||
142 | kfree(frame); | ||
143 | } | ||
144 | |||
145 | #endif /* _ISLPCI_MGT_H */ | ||
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c new file mode 100644 index 000000000000..12123e24b113 --- /dev/null +++ b/drivers/net/wireless/prism54/oid_mgt.c | |||
@@ -0,0 +1,907 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr> | ||
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 as published by | ||
6 | * the Free Software Foundation; either version 2 of the License | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "prismcompat.h" | ||
20 | #include "islpci_dev.h" | ||
21 | #include "islpci_mgt.h" | ||
22 | #include "isl_oid.h" | ||
23 | #include "oid_mgt.h" | ||
24 | #include "isl_ioctl.h" | ||
25 | |||
26 | /* to convert between channel and freq */ | ||
27 | static const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, | ||
28 | 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 | ||
29 | }; | ||
30 | |||
31 | int | ||
32 | channel_of_freq(int f) | ||
33 | { | ||
34 | int c = 0; | ||
35 | |||
36 | if ((f >= 2412) && (f <= 2484)) { | ||
37 | while ((c < 14) && (f != frequency_list_bg[c])) | ||
38 | c++; | ||
39 | return (c >= 14) ? 0 : ++c; | ||
40 | } else if ((f >= (int) 5000) && (f <= (int) 6000)) { | ||
41 | return ( (f - 5000) / 5 ); | ||
42 | } else | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | #define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t} | ||
47 | #define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED) | ||
48 | #define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32) | ||
49 | #define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32) | ||
50 | #define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME) | ||
51 | #define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX) | ||
52 | |||
53 | #define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0) | ||
54 | |||
55 | struct oid_t isl_oid[] = { | ||
56 | OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR), | ||
57 | OID_U32(GEN_OID_LINKSTATE, 0x00000001), | ||
58 | OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002), | ||
59 | OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003), | ||
60 | OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004), | ||
61 | OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005), | ||
62 | |||
63 | /* 802.11 */ | ||
64 | OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000), | ||
65 | OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW), | ||
66 | OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid, | ||
67 | OID_TYPE_SSID), | ||
68 | OID_U32(DOT11_OID_STATE, 0x10000003), | ||
69 | OID_U32(DOT11_OID_AID, 0x10000004), | ||
70 | OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW), | ||
71 | OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid, | ||
72 | OID_TYPE_SSID), | ||
73 | |||
74 | OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000), | ||
75 | OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001), | ||
76 | OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002), | ||
77 | OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003), | ||
78 | OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004), | ||
79 | OID_U32(DOT11_OID_CFPPERIOD, 0x11000005), | ||
80 | OID_U32(DOT11_OID_CFPDURATION, 0x11000006), | ||
81 | |||
82 | OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000), | ||
83 | OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001), | ||
84 | OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002), | ||
85 | OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003), | ||
86 | [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), | ||
87 | OID_FLAG_CACHED | OID_TYPE_KEY}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ | ||
88 | OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008), | ||
89 | OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009), | ||
90 | OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a), | ||
91 | |||
92 | OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000), | ||
93 | OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001), | ||
94 | OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002), | ||
95 | OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003), | ||
96 | |||
97 | OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000), | ||
98 | OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001), | ||
99 | OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002), | ||
100 | OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003), | ||
101 | OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004), | ||
102 | OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005), | ||
103 | OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006), | ||
104 | OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007), | ||
105 | |||
106 | OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000), | ||
107 | OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001), | ||
108 | OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002), | ||
109 | OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003), | ||
110 | OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004), | ||
111 | OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005), | ||
112 | OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006), | ||
113 | |||
114 | [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0}, | ||
115 | OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008), | ||
116 | |||
117 | OID_U32(DOT11_OID_PSM, 0x14000000), | ||
118 | OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001), | ||
119 | OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002), | ||
120 | OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003), | ||
121 | |||
122 | OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000), | ||
123 | OID_U32(DOT11_OID_CLIENTS, 0x15000001), | ||
124 | OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002), | ||
125 | [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ | ||
126 | |||
127 | OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR), | ||
128 | OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR), | ||
129 | OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR), | ||
130 | OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR), | ||
131 | OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR), | ||
132 | OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0), | ||
133 | OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1), | ||
134 | OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2), | ||
135 | |||
136 | OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000), | ||
137 | OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001), | ||
138 | OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002), | ||
139 | OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003), | ||
140 | OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004), | ||
141 | OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005), | ||
142 | OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006), | ||
143 | OID_U32(DOT11_OID_RTSFAILED, 0x16000007), | ||
144 | OID_U32(DOT11_OID_ACKFAILED, 0x16000008), | ||
145 | OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009), | ||
146 | OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A), | ||
147 | OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B), | ||
148 | OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C), | ||
149 | |||
150 | OID_U32(DOT11_OID_SLOTTIME, 0x17000000), | ||
151 | OID_U32(DOT11_OID_CWMIN, 0x17000001), | ||
152 | OID_U32(DOT11_OID_CWMAX, 0x17000002), | ||
153 | OID_U32(DOT11_OID_ACKWINDOW, 0x17000003), | ||
154 | OID_U32(DOT11_OID_ANTENNARX, 0x17000004), | ||
155 | OID_U32(DOT11_OID_ANTENNATX, 0x17000005), | ||
156 | OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006), | ||
157 | OID_U32_C(DOT11_OID_CHANNEL, 0x17000007), | ||
158 | OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008), | ||
159 | OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009), | ||
160 | OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1], | ||
161 | OID_TYPE_RAW), | ||
162 | OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B), | ||
163 | OID_U32(DOT11_OID_CCAMODE, 0x1700000C), | ||
164 | OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D), | ||
165 | OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E), | ||
166 | OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F), | ||
167 | OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010, | ||
168 | u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), | ||
169 | OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011), | ||
170 | [DOT11_OID_SUPPORTEDFREQUENCIES] = | ||
171 | {0x17000012, 0, sizeof (struct obj_frequencies) | ||
172 | + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES}, | ||
173 | |||
174 | OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013), | ||
175 | OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1], | ||
176 | OID_TYPE_RAW), | ||
177 | OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015), | ||
178 | OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016), | ||
179 | OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017), | ||
180 | OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018), | ||
181 | OID_U32(DOT11_OID_PROFILES, 0x17000019), | ||
182 | OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020, | ||
183 | u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), | ||
184 | |||
185 | OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000), | ||
186 | OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001), | ||
187 | OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002), | ||
188 | OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003), | ||
189 | OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004), | ||
190 | OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005), | ||
191 | OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006), | ||
192 | OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007), | ||
193 | OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008), | ||
194 | OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009), | ||
195 | OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A), | ||
196 | OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B), | ||
197 | OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C), | ||
198 | |||
199 | OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000), | ||
200 | |||
201 | OID_U32(DOT11_OID_STATIMEOUT, 0x19000000), | ||
202 | OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001), | ||
203 | OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002), | ||
204 | [DOT11_OID_ATTACHMENT] = {0x19000003, 0, | ||
205 | sizeof(struct obj_attachment), OID_TYPE_ATTACH}, | ||
206 | OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer, | ||
207 | OID_TYPE_BUFFER), | ||
208 | |||
209 | OID_U32(DOT11_OID_BSSS, 0x1C000000), | ||
210 | [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), | ||
211 | OID_TYPE_BSS}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ | ||
212 | OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS), | ||
213 | [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct | ||
214 | obj_bsslist) + | ||
215 | sizeof (struct obj_bss[IWMAX_BSS]), | ||
216 | OID_TYPE_BSSLIST}, | ||
217 | |||
218 | OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000), | ||
219 | OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001), | ||
220 | OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002), | ||
221 | OID_U32_C(OID_INL_MODE, 0xFF020003), | ||
222 | OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004), | ||
223 | OID_STRUCT(OID_INL_VERSION, 0xFF020005, u8[8], OID_TYPE_RAW), | ||
224 | OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006), | ||
225 | OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007), | ||
226 | OID_U32_C(OID_INL_CONFIG, 0xFF020008), | ||
227 | OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C), | ||
228 | OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D), | ||
229 | OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F), | ||
230 | |||
231 | }; | ||
232 | |||
233 | int | ||
234 | mgt_init(islpci_private *priv) | ||
235 | { | ||
236 | int i; | ||
237 | |||
238 | priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL); | ||
239 | if (!priv->mib) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *)); | ||
243 | |||
244 | /* Alloc the cache */ | ||
245 | for (i = 0; i < OID_NUM_LAST; i++) { | ||
246 | if (isl_oid[i].flags & OID_FLAG_CACHED) { | ||
247 | priv->mib[i] = kmalloc(isl_oid[i].size * | ||
248 | (isl_oid[i].range + 1), | ||
249 | GFP_KERNEL); | ||
250 | if (!priv->mib[i]) | ||
251 | return -ENOMEM; | ||
252 | memset(priv->mib[i], 0, | ||
253 | isl_oid[i].size * (isl_oid[i].range + 1)); | ||
254 | } else | ||
255 | priv->mib[i] = NULL; | ||
256 | } | ||
257 | |||
258 | init_rwsem(&priv->mib_sem); | ||
259 | prism54_mib_init(priv); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | void | ||
265 | mgt_clean(islpci_private *priv) | ||
266 | { | ||
267 | int i; | ||
268 | |||
269 | if (!priv->mib) | ||
270 | return; | ||
271 | for (i = 0; i < OID_NUM_LAST; i++) | ||
272 | if (priv->mib[i]) { | ||
273 | kfree(priv->mib[i]); | ||
274 | priv->mib[i] = NULL; | ||
275 | } | ||
276 | kfree(priv->mib); | ||
277 | priv->mib = NULL; | ||
278 | } | ||
279 | |||
280 | void | ||
281 | mgt_le_to_cpu(int type, void *data) | ||
282 | { | ||
283 | switch (type) { | ||
284 | case OID_TYPE_U32: | ||
285 | *(u32 *) data = le32_to_cpu(*(u32 *) data); | ||
286 | break; | ||
287 | case OID_TYPE_BUFFER:{ | ||
288 | struct obj_buffer *buff = data; | ||
289 | buff->size = le32_to_cpu(buff->size); | ||
290 | buff->addr = le32_to_cpu(buff->addr); | ||
291 | break; | ||
292 | } | ||
293 | case OID_TYPE_BSS:{ | ||
294 | struct obj_bss *bss = data; | ||
295 | bss->age = le16_to_cpu(bss->age); | ||
296 | bss->channel = le16_to_cpu(bss->channel); | ||
297 | bss->capinfo = le16_to_cpu(bss->capinfo); | ||
298 | bss->rates = le16_to_cpu(bss->rates); | ||
299 | bss->basic_rates = le16_to_cpu(bss->basic_rates); | ||
300 | break; | ||
301 | } | ||
302 | case OID_TYPE_BSSLIST:{ | ||
303 | struct obj_bsslist *list = data; | ||
304 | int i; | ||
305 | list->nr = le32_to_cpu(list->nr); | ||
306 | for (i = 0; i < list->nr; i++) | ||
307 | mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]); | ||
308 | break; | ||
309 | } | ||
310 | case OID_TYPE_FREQUENCIES:{ | ||
311 | struct obj_frequencies *freq = data; | ||
312 | int i; | ||
313 | freq->nr = le16_to_cpu(freq->nr); | ||
314 | for (i = 0; i < freq->nr; i++) | ||
315 | freq->mhz[i] = le16_to_cpu(freq->mhz[i]); | ||
316 | break; | ||
317 | } | ||
318 | case OID_TYPE_MLME:{ | ||
319 | struct obj_mlme *mlme = data; | ||
320 | mlme->id = le16_to_cpu(mlme->id); | ||
321 | mlme->state = le16_to_cpu(mlme->state); | ||
322 | mlme->code = le16_to_cpu(mlme->code); | ||
323 | break; | ||
324 | } | ||
325 | case OID_TYPE_MLMEEX:{ | ||
326 | struct obj_mlmeex *mlme = data; | ||
327 | mlme->id = le16_to_cpu(mlme->id); | ||
328 | mlme->state = le16_to_cpu(mlme->state); | ||
329 | mlme->code = le16_to_cpu(mlme->code); | ||
330 | mlme->size = le16_to_cpu(mlme->size); | ||
331 | break; | ||
332 | } | ||
333 | case OID_TYPE_ATTACH:{ | ||
334 | struct obj_attachment *attach = data; | ||
335 | attach->id = le16_to_cpu(attach->id); | ||
336 | attach->size = le16_to_cpu(attach->size);; | ||
337 | break; | ||
338 | } | ||
339 | case OID_TYPE_SSID: | ||
340 | case OID_TYPE_KEY: | ||
341 | case OID_TYPE_ADDR: | ||
342 | case OID_TYPE_RAW: | ||
343 | break; | ||
344 | default: | ||
345 | BUG(); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | mgt_cpu_to_le(int type, void *data) | ||
351 | { | ||
352 | switch (type) { | ||
353 | case OID_TYPE_U32: | ||
354 | *(u32 *) data = cpu_to_le32(*(u32 *) data); | ||
355 | break; | ||
356 | case OID_TYPE_BUFFER:{ | ||
357 | struct obj_buffer *buff = data; | ||
358 | buff->size = cpu_to_le32(buff->size); | ||
359 | buff->addr = cpu_to_le32(buff->addr); | ||
360 | break; | ||
361 | } | ||
362 | case OID_TYPE_BSS:{ | ||
363 | struct obj_bss *bss = data; | ||
364 | bss->age = cpu_to_le16(bss->age); | ||
365 | bss->channel = cpu_to_le16(bss->channel); | ||
366 | bss->capinfo = cpu_to_le16(bss->capinfo); | ||
367 | bss->rates = cpu_to_le16(bss->rates); | ||
368 | bss->basic_rates = cpu_to_le16(bss->basic_rates); | ||
369 | break; | ||
370 | } | ||
371 | case OID_TYPE_BSSLIST:{ | ||
372 | struct obj_bsslist *list = data; | ||
373 | int i; | ||
374 | list->nr = cpu_to_le32(list->nr); | ||
375 | for (i = 0; i < list->nr; i++) | ||
376 | mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]); | ||
377 | break; | ||
378 | } | ||
379 | case OID_TYPE_FREQUENCIES:{ | ||
380 | struct obj_frequencies *freq = data; | ||
381 | int i; | ||
382 | freq->nr = cpu_to_le16(freq->nr); | ||
383 | for (i = 0; i < freq->nr; i++) | ||
384 | freq->mhz[i] = cpu_to_le16(freq->mhz[i]); | ||
385 | break; | ||
386 | } | ||
387 | case OID_TYPE_MLME:{ | ||
388 | struct obj_mlme *mlme = data; | ||
389 | mlme->id = cpu_to_le16(mlme->id); | ||
390 | mlme->state = cpu_to_le16(mlme->state); | ||
391 | mlme->code = cpu_to_le16(mlme->code); | ||
392 | break; | ||
393 | } | ||
394 | case OID_TYPE_MLMEEX:{ | ||
395 | struct obj_mlmeex *mlme = data; | ||
396 | mlme->id = cpu_to_le16(mlme->id); | ||
397 | mlme->state = cpu_to_le16(mlme->state); | ||
398 | mlme->code = cpu_to_le16(mlme->code); | ||
399 | mlme->size = cpu_to_le16(mlme->size); | ||
400 | break; | ||
401 | } | ||
402 | case OID_TYPE_ATTACH:{ | ||
403 | struct obj_attachment *attach = data; | ||
404 | attach->id = cpu_to_le16(attach->id); | ||
405 | attach->size = cpu_to_le16(attach->size);; | ||
406 | break; | ||
407 | } | ||
408 | case OID_TYPE_SSID: | ||
409 | case OID_TYPE_KEY: | ||
410 | case OID_TYPE_ADDR: | ||
411 | case OID_TYPE_RAW: | ||
412 | break; | ||
413 | default: | ||
414 | BUG(); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | /* Note : data is modified during this function */ | ||
419 | |||
420 | int | ||
421 | mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) | ||
422 | { | ||
423 | int ret = 0; | ||
424 | struct islpci_mgmtframe *response = NULL; | ||
425 | int response_op = PIMFOR_OP_ERROR; | ||
426 | int dlen; | ||
427 | void *cache, *_data = data; | ||
428 | u32 oid; | ||
429 | |||
430 | BUG_ON(OID_NUM_LAST <= n); | ||
431 | BUG_ON(extra > isl_oid[n].range); | ||
432 | |||
433 | if (!priv->mib) | ||
434 | /* memory has been freed */ | ||
435 | return -1; | ||
436 | |||
437 | dlen = isl_oid[n].size; | ||
438 | cache = priv->mib[n]; | ||
439 | cache += (cache ? extra * dlen : 0); | ||
440 | oid = isl_oid[n].oid + extra; | ||
441 | |||
442 | if (_data == NULL) | ||
443 | /* we are requested to re-set a cached value */ | ||
444 | _data = cache; | ||
445 | else | ||
446 | mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data); | ||
447 | /* If we are going to write to the cache, we don't want anyone to read | ||
448 | * it -> acquire write lock. | ||
449 | * Else we could acquire a read lock to be sure we don't bother the | ||
450 | * commit process (which takes a write lock). But I'm not sure if it's | ||
451 | * needed. | ||
452 | */ | ||
453 | if (cache) | ||
454 | down_write(&priv->mib_sem); | ||
455 | |||
456 | if (islpci_get_state(priv) >= PRV_STATE_READY) { | ||
457 | ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, | ||
458 | _data, dlen, &response); | ||
459 | if (!ret) { | ||
460 | response_op = response->header->operation; | ||
461 | islpci_mgt_release(response); | ||
462 | } | ||
463 | if (ret || response_op == PIMFOR_OP_ERROR) | ||
464 | ret = -EIO; | ||
465 | } else if (!cache) | ||
466 | ret = -EIO; | ||
467 | |||
468 | if (cache) { | ||
469 | if (!ret && data) | ||
470 | memcpy(cache, _data, dlen); | ||
471 | up_write(&priv->mib_sem); | ||
472 | } | ||
473 | |||
474 | /* re-set given data to what it was */ | ||
475 | if (data) | ||
476 | mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); | ||
477 | |||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | /* None of these are cached */ | ||
482 | int | ||
483 | mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len) | ||
484 | { | ||
485 | int ret = 0; | ||
486 | struct islpci_mgmtframe *response; | ||
487 | int response_op = PIMFOR_OP_ERROR; | ||
488 | int dlen; | ||
489 | u32 oid; | ||
490 | |||
491 | BUG_ON(OID_NUM_LAST <= n); | ||
492 | |||
493 | dlen = isl_oid[n].size; | ||
494 | oid = isl_oid[n].oid; | ||
495 | |||
496 | mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data); | ||
497 | |||
498 | if (islpci_get_state(priv) >= PRV_STATE_READY) { | ||
499 | ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, | ||
500 | data, dlen + extra_len, &response); | ||
501 | if (!ret) { | ||
502 | response_op = response->header->operation; | ||
503 | islpci_mgt_release(response); | ||
504 | } | ||
505 | if (ret || response_op == PIMFOR_OP_ERROR) | ||
506 | ret = -EIO; | ||
507 | } else | ||
508 | ret = -EIO; | ||
509 | |||
510 | /* re-set given data to what it was */ | ||
511 | if (data) | ||
512 | mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | int | ||
518 | mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, | ||
519 | union oid_res_t *res) | ||
520 | { | ||
521 | |||
522 | int ret = -EIO; | ||
523 | int reslen = 0; | ||
524 | struct islpci_mgmtframe *response = NULL; | ||
525 | |||
526 | int dlen; | ||
527 | void *cache, *_res = NULL; | ||
528 | u32 oid; | ||
529 | |||
530 | BUG_ON(OID_NUM_LAST <= n); | ||
531 | BUG_ON(extra > isl_oid[n].range); | ||
532 | |||
533 | res->ptr = NULL; | ||
534 | |||
535 | if (!priv->mib) | ||
536 | /* memory has been freed */ | ||
537 | return -1; | ||
538 | |||
539 | dlen = isl_oid[n].size; | ||
540 | cache = priv->mib[n]; | ||
541 | cache += cache ? extra * dlen : 0; | ||
542 | oid = isl_oid[n].oid + extra; | ||
543 | reslen = dlen; | ||
544 | |||
545 | if (cache) | ||
546 | down_read(&priv->mib_sem); | ||
547 | |||
548 | if (islpci_get_state(priv) >= PRV_STATE_READY) { | ||
549 | ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, | ||
550 | oid, data, dlen, &response); | ||
551 | if (ret || !response || | ||
552 | response->header->operation == PIMFOR_OP_ERROR) { | ||
553 | if (response) | ||
554 | islpci_mgt_release(response); | ||
555 | ret = -EIO; | ||
556 | } | ||
557 | if (!ret) { | ||
558 | _res = response->data; | ||
559 | reslen = response->header->length; | ||
560 | } | ||
561 | } else if (cache) { | ||
562 | _res = cache; | ||
563 | ret = 0; | ||
564 | } | ||
565 | if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32) | ||
566 | res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res); | ||
567 | else { | ||
568 | res->ptr = kmalloc(reslen, GFP_KERNEL); | ||
569 | BUG_ON(res->ptr == NULL); | ||
570 | if (ret) | ||
571 | memset(res->ptr, 0, reslen); | ||
572 | else { | ||
573 | memcpy(res->ptr, _res, reslen); | ||
574 | mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, | ||
575 | res->ptr); | ||
576 | } | ||
577 | } | ||
578 | if (cache) | ||
579 | up_read(&priv->mib_sem); | ||
580 | |||
581 | if (response && !ret) | ||
582 | islpci_mgt_release(response); | ||
583 | |||
584 | if (reslen > isl_oid[n].size) | ||
585 | printk(KERN_DEBUG | ||
586 | "mgt_get_request(0x%x): received data length was bigger " | ||
587 | "than expected (%d > %d). Memory is probably corrupted...", | ||
588 | oid, reslen, isl_oid[n].size); | ||
589 | |||
590 | return ret; | ||
591 | } | ||
592 | |||
593 | /* lock outside */ | ||
594 | int | ||
595 | mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) | ||
596 | { | ||
597 | int i, ret = 0; | ||
598 | struct islpci_mgmtframe *response; | ||
599 | |||
600 | for (i = 0; i < n; i++) { | ||
601 | struct oid_t *t = &(isl_oid[l[i]]); | ||
602 | void *data = priv->mib[l[i]]; | ||
603 | int j = 0; | ||
604 | u32 oid = t->oid; | ||
605 | BUG_ON(data == NULL); | ||
606 | while (j <= t->range) { | ||
607 | int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, | ||
608 | oid, data, t->size, | ||
609 | &response); | ||
610 | if (response) { | ||
611 | r |= (response->header->operation == PIMFOR_OP_ERROR); | ||
612 | islpci_mgt_release(response); | ||
613 | } | ||
614 | if (r) | ||
615 | printk(KERN_ERR "%s: mgt_commit_list: failure. " | ||
616 | "oid=%08x err=%d\n", | ||
617 | priv->ndev->name, oid, r); | ||
618 | ret |= r; | ||
619 | j++; | ||
620 | oid++; | ||
621 | data += t->size; | ||
622 | } | ||
623 | } | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | /* Lock outside */ | ||
628 | |||
629 | void | ||
630 | mgt_set(islpci_private *priv, enum oid_num_t n, void *data) | ||
631 | { | ||
632 | BUG_ON(OID_NUM_LAST <= n); | ||
633 | BUG_ON(priv->mib[n] == NULL); | ||
634 | |||
635 | memcpy(priv->mib[n], data, isl_oid[n].size); | ||
636 | mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]); | ||
637 | } | ||
638 | |||
639 | void | ||
640 | mgt_get(islpci_private *priv, enum oid_num_t n, void *res) | ||
641 | { | ||
642 | BUG_ON(OID_NUM_LAST <= n); | ||
643 | BUG_ON(priv->mib[n] == NULL); | ||
644 | BUG_ON(res == NULL); | ||
645 | |||
646 | memcpy(res, priv->mib[n], isl_oid[n].size); | ||
647 | mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res); | ||
648 | } | ||
649 | |||
650 | /* Commits the cache. Lock outside. */ | ||
651 | |||
652 | static enum oid_num_t commit_part1[] = { | ||
653 | OID_INL_CONFIG, | ||
654 | OID_INL_MODE, | ||
655 | DOT11_OID_BSSTYPE, | ||
656 | DOT11_OID_CHANNEL, | ||
657 | DOT11_OID_MLMEAUTOLEVEL | ||
658 | }; | ||
659 | |||
660 | static enum oid_num_t commit_part2[] = { | ||
661 | DOT11_OID_SSID, | ||
662 | DOT11_OID_PSMBUFFER, | ||
663 | DOT11_OID_AUTHENABLE, | ||
664 | DOT11_OID_PRIVACYINVOKED, | ||
665 | DOT11_OID_EXUNENCRYPTED, | ||
666 | DOT11_OID_DEFKEYX, /* MULTIPLE */ | ||
667 | DOT11_OID_DEFKEYID, | ||
668 | DOT11_OID_DOT1XENABLE, | ||
669 | OID_INL_DOT11D_CONFORMANCE, | ||
670 | /* Do not initialize this - fw < 1.0.4.3 rejects it | ||
671 | OID_INL_OUTPUTPOWER, | ||
672 | */ | ||
673 | }; | ||
674 | |||
675 | /* update the MAC addr. */ | ||
676 | static int | ||
677 | mgt_update_addr(islpci_private *priv) | ||
678 | { | ||
679 | struct islpci_mgmtframe *res; | ||
680 | int ret; | ||
681 | |||
682 | ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, | ||
683 | isl_oid[GEN_OID_MACADDRESS].oid, NULL, | ||
684 | isl_oid[GEN_OID_MACADDRESS].size, &res); | ||
685 | |||
686 | if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR)) | ||
687 | memcpy(priv->ndev->dev_addr, res->data, 6); | ||
688 | else | ||
689 | ret = -EIO; | ||
690 | if (res) | ||
691 | islpci_mgt_release(res); | ||
692 | |||
693 | if (ret) | ||
694 | printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name); | ||
695 | return ret; | ||
696 | } | ||
697 | |||
698 | #define VEC_SIZE(a) (sizeof(a)/sizeof(a[0])) | ||
699 | |||
700 | int | ||
701 | mgt_commit(islpci_private *priv) | ||
702 | { | ||
703 | int rvalue; | ||
704 | u32 u; | ||
705 | |||
706 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
707 | return 0; | ||
708 | |||
709 | rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1)); | ||
710 | |||
711 | if (priv->iw_mode != IW_MODE_MONITOR) | ||
712 | rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2)); | ||
713 | |||
714 | u = OID_INL_MODE; | ||
715 | rvalue |= mgt_commit_list(priv, &u, 1); | ||
716 | rvalue |= mgt_update_addr(priv); | ||
717 | |||
718 | if (rvalue) { | ||
719 | /* some request have failed. The device might be in an | ||
720 | incoherent state. We should reset it ! */ | ||
721 | printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name); | ||
722 | } | ||
723 | return rvalue; | ||
724 | } | ||
725 | |||
726 | /* The following OIDs need to be "unlatched": | ||
727 | * | ||
728 | * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL | ||
729 | * FREQUENCY,EXTENDEDRATES. | ||
730 | * | ||
731 | * The way to do this is to set ESSID. Note though that they may get | ||
732 | * unlatch before though by setting another OID. */ | ||
733 | #if 0 | ||
734 | void | ||
735 | mgt_unlatch_all(islpci_private *priv) | ||
736 | { | ||
737 | u32 u; | ||
738 | int rvalue = 0; | ||
739 | |||
740 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
741 | return; | ||
742 | |||
743 | u = DOT11_OID_SSID; | ||
744 | rvalue = mgt_commit_list(priv, &u, 1); | ||
745 | /* Necessary if in MANUAL RUN mode? */ | ||
746 | #if 0 | ||
747 | u = OID_INL_MODE; | ||
748 | rvalue |= mgt_commit_list(priv, &u, 1); | ||
749 | |||
750 | u = DOT11_OID_MLMEAUTOLEVEL; | ||
751 | rvalue |= mgt_commit_list(priv, &u, 1); | ||
752 | |||
753 | u = OID_INL_MODE; | ||
754 | rvalue |= mgt_commit_list(priv, &u, 1); | ||
755 | #endif | ||
756 | |||
757 | if (rvalue) | ||
758 | printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name); | ||
759 | } | ||
760 | #endif | ||
761 | |||
762 | /* This will tell you if you are allowed to answer a mlme(ex) request .*/ | ||
763 | |||
764 | int | ||
765 | mgt_mlme_answer(islpci_private *priv) | ||
766 | { | ||
767 | u32 mlmeautolevel; | ||
768 | /* Acquire a read lock because if we are in a mode change, it's | ||
769 | * possible to answer true, while the card is leaving master to managed | ||
770 | * mode. Answering to a mlme in this situation could hang the card. | ||
771 | */ | ||
772 | down_read(&priv->mib_sem); | ||
773 | mlmeautolevel = | ||
774 | le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]); | ||
775 | up_read(&priv->mib_sem); | ||
776 | |||
777 | return ((priv->iw_mode == IW_MODE_MASTER) && | ||
778 | (mlmeautolevel >= DOT11_MLME_INTERMEDIATE)); | ||
779 | } | ||
780 | |||
781 | enum oid_num_t | ||
782 | mgt_oidtonum(u32 oid) | ||
783 | { | ||
784 | int i; | ||
785 | |||
786 | for (i = 0; i < OID_NUM_LAST; i++) | ||
787 | if (isl_oid[i].oid == oid) | ||
788 | return i; | ||
789 | |||
790 | printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid); | ||
791 | |||
792 | return OID_NUM_LAST; | ||
793 | } | ||
794 | |||
795 | int | ||
796 | mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str) | ||
797 | { | ||
798 | switch (isl_oid[n].flags & OID_FLAG_TYPE) { | ||
799 | case OID_TYPE_U32: | ||
800 | return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u); | ||
801 | break; | ||
802 | case OID_TYPE_BUFFER:{ | ||
803 | struct obj_buffer *buff = r->ptr; | ||
804 | return snprintf(str, PRIV_STR_SIZE, | ||
805 | "size=%u\naddr=0x%X\n", buff->size, | ||
806 | buff->addr); | ||
807 | } | ||
808 | break; | ||
809 | case OID_TYPE_BSS:{ | ||
810 | struct obj_bss *bss = r->ptr; | ||
811 | return snprintf(str, PRIV_STR_SIZE, | ||
812 | "age=%u\nchannel=%u\n" | ||
813 | "capinfo=0x%X\nrates=0x%X\n" | ||
814 | "basic_rates=0x%X\n", bss->age, | ||
815 | bss->channel, bss->capinfo, | ||
816 | bss->rates, bss->basic_rates); | ||
817 | } | ||
818 | break; | ||
819 | case OID_TYPE_BSSLIST:{ | ||
820 | struct obj_bsslist *list = r->ptr; | ||
821 | int i, k; | ||
822 | k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr); | ||
823 | for (i = 0; i < list->nr; i++) | ||
824 | k += snprintf(str + k, PRIV_STR_SIZE - k, | ||
825 | "bss[%u] : \nage=%u\nchannel=%u\n" | ||
826 | "capinfo=0x%X\nrates=0x%X\n" | ||
827 | "basic_rates=0x%X\n", | ||
828 | i, list->bsslist[i].age, | ||
829 | list->bsslist[i].channel, | ||
830 | list->bsslist[i].capinfo, | ||
831 | list->bsslist[i].rates, | ||
832 | list->bsslist[i].basic_rates); | ||
833 | return k; | ||
834 | } | ||
835 | break; | ||
836 | case OID_TYPE_FREQUENCIES:{ | ||
837 | struct obj_frequencies *freq = r->ptr; | ||
838 | int i, t; | ||
839 | printk("nr : %u\n", freq->nr); | ||
840 | t = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr); | ||
841 | for (i = 0; i < freq->nr; i++) | ||
842 | t += snprintf(str + t, PRIV_STR_SIZE - t, | ||
843 | "mhz[%u]=%u\n", i, freq->mhz[i]); | ||
844 | return t; | ||
845 | } | ||
846 | break; | ||
847 | case OID_TYPE_MLME:{ | ||
848 | struct obj_mlme *mlme = r->ptr; | ||
849 | return snprintf(str, PRIV_STR_SIZE, | ||
850 | "id=0x%X\nstate=0x%X\ncode=0x%X\n", | ||
851 | mlme->id, mlme->state, mlme->code); | ||
852 | } | ||
853 | break; | ||
854 | case OID_TYPE_MLMEEX:{ | ||
855 | struct obj_mlmeex *mlme = r->ptr; | ||
856 | return snprintf(str, PRIV_STR_SIZE, | ||
857 | "id=0x%X\nstate=0x%X\n" | ||
858 | "code=0x%X\nsize=0x%X\n", mlme->id, | ||
859 | mlme->state, mlme->code, mlme->size); | ||
860 | } | ||
861 | break; | ||
862 | case OID_TYPE_ATTACH:{ | ||
863 | struct obj_attachment *attach = r->ptr; | ||
864 | return snprintf(str, PRIV_STR_SIZE, | ||
865 | "id=%d\nsize=%d\n", | ||
866 | attach->id, | ||
867 | attach->size); | ||
868 | } | ||
869 | break; | ||
870 | case OID_TYPE_SSID:{ | ||
871 | struct obj_ssid *ssid = r->ptr; | ||
872 | return snprintf(str, PRIV_STR_SIZE, | ||
873 | "length=%u\noctets=%.*s\n", | ||
874 | ssid->length, ssid->length, | ||
875 | ssid->octets); | ||
876 | } | ||
877 | break; | ||
878 | case OID_TYPE_KEY:{ | ||
879 | struct obj_key *key = r->ptr; | ||
880 | int t, i; | ||
881 | t = snprintf(str, PRIV_STR_SIZE, | ||
882 | "type=0x%X\nlength=0x%X\nkey=0x", | ||
883 | key->type, key->length); | ||
884 | for (i = 0; i < key->length; i++) | ||
885 | t += snprintf(str + t, PRIV_STR_SIZE - t, | ||
886 | "%02X:", key->key[i]); | ||
887 | t += snprintf(str + t, PRIV_STR_SIZE - t, "\n"); | ||
888 | return t; | ||
889 | } | ||
890 | break; | ||
891 | case OID_TYPE_RAW: | ||
892 | case OID_TYPE_ADDR:{ | ||
893 | unsigned char *buff = r->ptr; | ||
894 | int t, i; | ||
895 | t = snprintf(str, PRIV_STR_SIZE, "hex data="); | ||
896 | for (i = 0; i < isl_oid[n].size; i++) | ||
897 | t += snprintf(str + t, PRIV_STR_SIZE - t, | ||
898 | "%02X:", buff[i]); | ||
899 | t += snprintf(str + t, PRIV_STR_SIZE - t, "\n"); | ||
900 | return t; | ||
901 | } | ||
902 | break; | ||
903 | default: | ||
904 | BUG(); | ||
905 | } | ||
906 | return 0; | ||
907 | } | ||
diff --git a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h new file mode 100644 index 000000000000..92c8a2d4acd8 --- /dev/null +++ b/drivers/net/wireless/prism54/oid_mgt.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 Aurelien Alleaume <slts@free.fr> | ||
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 as published by | ||
6 | * the Free Software Foundation; either version 2 of the License | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #if !defined(_OID_MGT_H) | ||
20 | #define _OID_MGT_H | ||
21 | |||
22 | #include "isl_oid.h" | ||
23 | #include "islpci_dev.h" | ||
24 | |||
25 | extern struct oid_t isl_oid[]; | ||
26 | |||
27 | int mgt_init(islpci_private *); | ||
28 | |||
29 | void mgt_clean(islpci_private *); | ||
30 | |||
31 | /* I don't know where to put these 2 */ | ||
32 | extern const int frequency_list_a[]; | ||
33 | int channel_of_freq(int); | ||
34 | |||
35 | void mgt_le_to_cpu(int, void *); | ||
36 | |||
37 | int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); | ||
38 | int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int); | ||
39 | |||
40 | |||
41 | int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, | ||
42 | union oid_res_t *); | ||
43 | |||
44 | int mgt_commit_list(islpci_private *, enum oid_num_t *, int); | ||
45 | |||
46 | void mgt_set(islpci_private *, enum oid_num_t, void *); | ||
47 | |||
48 | void mgt_get(islpci_private *, enum oid_num_t, void *); | ||
49 | |||
50 | int mgt_commit(islpci_private *); | ||
51 | |||
52 | int mgt_mlme_answer(islpci_private *); | ||
53 | |||
54 | enum oid_num_t mgt_oidtonum(u32 oid); | ||
55 | |||
56 | int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *); | ||
57 | |||
58 | #endif /* !defined(_OID_MGT_H) */ | ||
59 | /* EOF */ | ||
diff --git a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h new file mode 100644 index 000000000000..55541c01752e --- /dev/null +++ b/drivers/net/wireless/prism54/prismcompat.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * (C) 2004 Margit Schubert-While <margitsw@t-online.de> | ||
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 as published by | ||
6 | * the Free Software Foundation; either version 2 of the License | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * Compatibility header file to aid support of different kernel versions | ||
21 | */ | ||
22 | |||
23 | #ifdef PRISM54_COMPAT24 | ||
24 | #include "prismcompat24.h" | ||
25 | #else /* PRISM54_COMPAT24 */ | ||
26 | |||
27 | #ifndef _PRISM_COMPAT_H | ||
28 | #define _PRISM_COMPAT_H | ||
29 | |||
30 | #include <linux/device.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/config.h> | ||
33 | #include <linux/moduleparam.h> | ||
34 | #include <linux/workqueue.h> | ||
35 | #include <linux/compiler.h> | ||
36 | |||
37 | #ifndef __iomem | ||
38 | #define __iomem | ||
39 | #endif | ||
40 | |||
41 | #define PRISM_FW_PDEV &priv->pdev->dev | ||
42 | |||
43 | #endif /* _PRISM_COMPAT_H */ | ||
44 | #endif /* PRISM54_COMPAT24 */ | ||
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c new file mode 100644 index 000000000000..6e5bda56b8f8 --- /dev/null +++ b/drivers/net/wireless/ray_cs.c | |||
@@ -0,0 +1,2957 @@ | |||
1 | /*============================================================================= | ||
2 | * | ||
3 | * A PCMCIA client driver for the Raylink wireless LAN card. | ||
4 | * The starting point for this module was the skeleton.c in the | ||
5 | * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net | ||
6 | * | ||
7 | * | ||
8 | * Copyright (c) 1998 Corey Thomas (corey@world.std.com) | ||
9 | * | ||
10 | * This driver is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 only of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * It is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
22 | * | ||
23 | * Changes: | ||
24 | * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000 | ||
25 | * - reorganize kmallocs in ray_attach, checking all for failure | ||
26 | * and releasing the previous allocations if one fails | ||
27 | * | ||
28 | * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003 | ||
29 | * - Audit copy_to_user in ioctl(SIOCGIWESSID) | ||
30 | * | ||
31 | =============================================================================*/ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/proc_fs.h> | ||
37 | #include <linux/ptrace.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/timer.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/etherdevice.h> | ||
44 | #include <linux/if_arp.h> | ||
45 | #include <linux/ioport.h> | ||
46 | #include <linux/skbuff.h> | ||
47 | #include <linux/ethtool.h> | ||
48 | |||
49 | #include <pcmcia/version.h> | ||
50 | #include <pcmcia/cs_types.h> | ||
51 | #include <pcmcia/cs.h> | ||
52 | #include <pcmcia/cistpl.h> | ||
53 | #include <pcmcia/cisreg.h> | ||
54 | #include <pcmcia/ds.h> | ||
55 | #include <pcmcia/mem_op.h> | ||
56 | |||
57 | #include <linux/wireless.h> | ||
58 | |||
59 | #include <asm/io.h> | ||
60 | #include <asm/system.h> | ||
61 | #include <asm/byteorder.h> | ||
62 | #include <asm/uaccess.h> | ||
63 | |||
64 | /* Warning : these stuff will slow down the driver... */ | ||
65 | #define WIRELESS_SPY /* Enable spying addresses */ | ||
66 | /* Definitions we need for spy */ | ||
67 | typedef struct iw_statistics iw_stats; | ||
68 | typedef struct iw_quality iw_qual; | ||
69 | typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ | ||
70 | |||
71 | #include "rayctl.h" | ||
72 | #include "ray_cs.h" | ||
73 | |||
74 | /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If | ||
75 | you do not define PCMCIA_DEBUG at all, all the debug code will be | ||
76 | left out. If you compile with PCMCIA_DEBUG=0, the debug code will | ||
77 | be present but disabled -- but it can then be enabled for specific | ||
78 | modules at load time with a 'pc_debug=#' option to insmod. | ||
79 | */ | ||
80 | |||
81 | #ifdef RAYLINK_DEBUG | ||
82 | #define PCMCIA_DEBUG RAYLINK_DEBUG | ||
83 | #endif | ||
84 | #ifdef PCMCIA_DEBUG | ||
85 | static int ray_debug; | ||
86 | static int pc_debug = PCMCIA_DEBUG; | ||
87 | module_param(pc_debug, int, 0); | ||
88 | /* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */ | ||
89 | #define DEBUG(n, args...) if (pc_debug>(n)) printk(args); | ||
90 | #else | ||
91 | #define DEBUG(n, args...) | ||
92 | #endif | ||
93 | /** Prototypes based on PCMCIA skeleton driver *******************************/ | ||
94 | static void ray_config(dev_link_t *link); | ||
95 | static void ray_release(dev_link_t *link); | ||
96 | static int ray_event(event_t event, int priority, event_callback_args_t *args); | ||
97 | static dev_link_t *ray_attach(void); | ||
98 | static void ray_detach(dev_link_t *); | ||
99 | |||
100 | /***** Prototypes indicated by device structure ******************************/ | ||
101 | static int ray_dev_close(struct net_device *dev); | ||
102 | static int ray_dev_config(struct net_device *dev, struct ifmap *map); | ||
103 | static struct net_device_stats *ray_get_stats(struct net_device *dev); | ||
104 | static int ray_dev_init(struct net_device *dev); | ||
105 | static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | ||
106 | |||
107 | static struct ethtool_ops netdev_ethtool_ops; | ||
108 | |||
109 | static int ray_open(struct net_device *dev); | ||
110 | static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
111 | static void set_multicast_list(struct net_device *dev); | ||
112 | static void ray_update_multi_list(struct net_device *dev, int all); | ||
113 | static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, | ||
114 | unsigned char *data, int len); | ||
115 | static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, | ||
116 | unsigned char *data); | ||
117 | static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); | ||
118 | #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ | ||
119 | static iw_stats * ray_get_wireless_stats(struct net_device * dev); | ||
120 | #endif /* WIRELESS_EXT > 7 */ | ||
121 | |||
122 | /***** Prototypes for raylink functions **************************************/ | ||
123 | static int asc_to_int(char a); | ||
124 | static void authenticate(ray_dev_t *local); | ||
125 | static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type); | ||
126 | static void authenticate_timeout(u_long); | ||
127 | static int get_free_ccs(ray_dev_t *local); | ||
128 | static int get_free_tx_ccs(ray_dev_t *local); | ||
129 | static void init_startup_params(ray_dev_t *local); | ||
130 | static int parse_addr(char *in_str, UCHAR *out); | ||
131 | static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type); | ||
132 | static int ray_init(struct net_device *dev); | ||
133 | static int interrupt_ecf(ray_dev_t *local, int ccs); | ||
134 | static void ray_reset(struct net_device *dev); | ||
135 | static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len); | ||
136 | static void verify_dl_startup(u_long); | ||
137 | |||
138 | /* Prototypes for interrpt time functions **********************************/ | ||
139 | static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs); | ||
140 | static void clear_interrupt(ray_dev_t *local); | ||
141 | static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
142 | unsigned int pkt_addr, int rx_len); | ||
143 | static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); | ||
144 | static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); | ||
145 | static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); | ||
146 | static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
147 | unsigned int pkt_addr, int rx_len); | ||
148 | static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, | ||
149 | int rx_len); | ||
150 | static void associate(ray_dev_t *local); | ||
151 | |||
152 | /* Card command functions */ | ||
153 | static int dl_startup_params(struct net_device *dev); | ||
154 | static void join_net(u_long local); | ||
155 | static void start_net(u_long local); | ||
156 | /* void start_net(ray_dev_t *local); */ | ||
157 | |||
158 | /*===========================================================================*/ | ||
159 | /* Parameters that can be set with 'insmod' */ | ||
160 | |||
161 | /* ADHOC=0, Infrastructure=1 */ | ||
162 | static int net_type = ADHOC; | ||
163 | |||
164 | /* Hop dwell time in Kus (1024 us units defined by 802.11) */ | ||
165 | static int hop_dwell = 128; | ||
166 | |||
167 | /* Beacon period in Kus */ | ||
168 | static int beacon_period = 256; | ||
169 | |||
170 | /* power save mode (0 = off, 1 = save power) */ | ||
171 | static int psm; | ||
172 | |||
173 | /* String for network's Extended Service Set ID. 32 Characters max */ | ||
174 | static char *essid; | ||
175 | |||
176 | /* Default to encapsulation unless translation requested */ | ||
177 | static int translate = 1; | ||
178 | |||
179 | static int country = USA; | ||
180 | |||
181 | static int sniffer; | ||
182 | |||
183 | static int bc; | ||
184 | |||
185 | /* 48 bit physical card address if overriding card's real physical | ||
186 | * address is required. Since IEEE 802.11 addresses are 48 bits | ||
187 | * like ethernet, an int can't be used, so a string is used. To | ||
188 | * allow use of addresses starting with a decimal digit, the first | ||
189 | * character must be a letter and will be ignored. This letter is | ||
190 | * followed by up to 12 hex digits which are the address. If less | ||
191 | * than 12 digits are used, the address will be left filled with 0's. | ||
192 | * Note that bit 0 of the first byte is the broadcast bit, and evil | ||
193 | * things will happen if it is not 0 in a card address. | ||
194 | */ | ||
195 | static char *phy_addr = NULL; | ||
196 | |||
197 | |||
198 | /* The dev_info variable is the "key" that is used to match up this | ||
199 | device driver with appropriate cards, through the card configuration | ||
200 | database. | ||
201 | */ | ||
202 | static dev_info_t dev_info = "ray_cs"; | ||
203 | |||
204 | /* A linked list of "instances" of the ray device. Each actual | ||
205 | PCMCIA card corresponds to one device instance, and is described | ||
206 | by one dev_link_t structure (defined in ds.h). | ||
207 | */ | ||
208 | static dev_link_t *dev_list = NULL; | ||
209 | |||
210 | /* A dev_link_t structure has fields for most things that are needed | ||
211 | to keep track of a socket, but there will usually be some device | ||
212 | specific information that also needs to be kept track of. The | ||
213 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
214 | a device-specific private data structure, like this. | ||
215 | */ | ||
216 | static unsigned int ray_mem_speed = 500; | ||
217 | |||
218 | MODULE_AUTHOR("Corey Thomas <corey@world.std.com>"); | ||
219 | MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); | ||
220 | MODULE_LICENSE("GPL"); | ||
221 | |||
222 | module_param(net_type, int, 0); | ||
223 | module_param(hop_dwell, int, 0); | ||
224 | module_param(beacon_period, int, 0); | ||
225 | module_param(psm, int, 0); | ||
226 | module_param(essid, charp, 0); | ||
227 | module_param(translate, int, 0); | ||
228 | module_param(country, int, 0); | ||
229 | module_param(sniffer, int, 0); | ||
230 | module_param(bc, int, 0); | ||
231 | module_param(phy_addr, charp, 0); | ||
232 | module_param(ray_mem_speed, int, 0); | ||
233 | |||
234 | static UCHAR b5_default_startup_parms[] = { | ||
235 | 0, 0, /* Adhoc station */ | ||
236 | 'L','I','N','U','X', 0, 0, 0, /* 32 char ESSID */ | ||
237 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
238 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
239 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
240 | 1, 0, /* Active scan, CA Mode */ | ||
241 | 0, 0, 0, 0, 0, 0, /* No default MAC addr */ | ||
242 | 0x7f, 0xff, /* Frag threshold */ | ||
243 | 0x00, 0x80, /* Hop time 128 Kus*/ | ||
244 | 0x01, 0x00, /* Beacon period 256 Kus */ | ||
245 | 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout*/ | ||
246 | 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */ | ||
247 | 0x7f, 0xff, /* RTS threshold */ | ||
248 | 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */ | ||
249 | 0x05, /* assoc resp timeout thresh */ | ||
250 | 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max*/ | ||
251 | 0, /* Promiscuous mode */ | ||
252 | 0x0c, 0x0bd, /* Unique word */ | ||
253 | 0x32, /* Slot time */ | ||
254 | 0xff, 0xff, /* roam-low snr, low snr count */ | ||
255 | 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ | ||
256 | 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */ | ||
257 | /* b4 - b5 differences start here */ | ||
258 | 0x00, 0x3f, /* CW max */ | ||
259 | 0x00, 0x0f, /* CW min */ | ||
260 | 0x04, 0x08, /* Noise gain, limit offset */ | ||
261 | 0x28, 0x28, /* det rssi, med busy offsets */ | ||
262 | 7, /* det sync thresh */ | ||
263 | 0, 2, 2, /* test mode, min, max */ | ||
264 | 0, /* allow broadcast SSID probe resp */ | ||
265 | 0, 0, /* privacy must start, can join */ | ||
266 | 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */ | ||
267 | }; | ||
268 | |||
269 | static UCHAR b4_default_startup_parms[] = { | ||
270 | 0, 0, /* Adhoc station */ | ||
271 | 'L','I','N','U','X', 0, 0, 0, /* 32 char ESSID */ | ||
272 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
273 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
274 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
275 | 1, 0, /* Active scan, CA Mode */ | ||
276 | 0, 0, 0, 0, 0, 0, /* No default MAC addr */ | ||
277 | 0x7f, 0xff, /* Frag threshold */ | ||
278 | 0x02, 0x00, /* Hop time */ | ||
279 | 0x00, 0x01, /* Beacon period */ | ||
280 | 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout*/ | ||
281 | 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */ | ||
282 | 0x7f, 0xff, /* RTS threshold */ | ||
283 | 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */ | ||
284 | 0x05, /* assoc resp timeout thresh */ | ||
285 | 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max*/ | ||
286 | 0, /* Promiscuous mode */ | ||
287 | 0x0c, 0x0bd, /* Unique word */ | ||
288 | 0x4e, /* Slot time (TBD seems wrong)*/ | ||
289 | 0xff, 0xff, /* roam-low snr, low snr count */ | ||
290 | 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ | ||
291 | 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */ | ||
292 | /* b4 - b5 differences start here */ | ||
293 | 0x3f, 0x0f, /* CW max, min */ | ||
294 | 0x04, 0x08, /* Noise gain, limit offset */ | ||
295 | 0x28, 0x28, /* det rssi, med busy offsets */ | ||
296 | 7, /* det sync thresh */ | ||
297 | 0, 2, 2 /* test mode, min, max*/ | ||
298 | }; | ||
299 | /*===========================================================================*/ | ||
300 | static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0}; | ||
301 | |||
302 | static char hop_pattern_length[] = { 1, | ||
303 | USA_HOP_MOD, EUROPE_HOP_MOD, | ||
304 | JAPAN_HOP_MOD, KOREA_HOP_MOD, | ||
305 | SPAIN_HOP_MOD, FRANCE_HOP_MOD, | ||
306 | ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD, | ||
307 | JAPAN_TEST_HOP_MOD | ||
308 | }; | ||
309 | |||
310 | static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>"; | ||
311 | |||
312 | /*============================================================================= | ||
313 | ray_attach() creates an "instance" of the driver, allocating | ||
314 | local data structures for one device. The device is registered | ||
315 | with Card Services. | ||
316 | The dev_link structure is initialized, but we don't actually | ||
317 | configure the card at this point -- we wait until we receive a | ||
318 | card insertion event. | ||
319 | =============================================================================*/ | ||
320 | static dev_link_t *ray_attach(void) | ||
321 | { | ||
322 | client_reg_t client_reg; | ||
323 | dev_link_t *link; | ||
324 | ray_dev_t *local; | ||
325 | int ret; | ||
326 | struct net_device *dev; | ||
327 | |||
328 | DEBUG(1, "ray_attach()\n"); | ||
329 | |||
330 | /* Initialize the dev_link_t structure */ | ||
331 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
332 | |||
333 | if (!link) | ||
334 | return NULL; | ||
335 | |||
336 | /* Allocate space for private device-specific data */ | ||
337 | dev = alloc_etherdev(sizeof(ray_dev_t)); | ||
338 | |||
339 | if (!dev) | ||
340 | goto fail_alloc_dev; | ||
341 | |||
342 | local = dev->priv; | ||
343 | |||
344 | memset(link, 0, sizeof(struct dev_link_t)); | ||
345 | |||
346 | /* The io structure describes IO port mapping. None used here */ | ||
347 | link->io.NumPorts1 = 0; | ||
348 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
349 | link->io.IOAddrLines = 5; | ||
350 | |||
351 | /* Interrupt setup. For PCMCIA, driver takes what's given */ | ||
352 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
353 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
354 | link->irq.Handler = &ray_interrupt; | ||
355 | |||
356 | /* General socket configuration */ | ||
357 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
358 | link->conf.Vcc = 50; | ||
359 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
360 | link->conf.ConfigIndex = 1; | ||
361 | link->conf.Present = PRESENT_OPTION; | ||
362 | |||
363 | link->priv = dev; | ||
364 | link->irq.Instance = dev; | ||
365 | |||
366 | local->finder = link; | ||
367 | local->card_status = CARD_INSERTED; | ||
368 | local->authentication_state = UNAUTHENTICATED; | ||
369 | local->num_multi = 0; | ||
370 | DEBUG(2,"ray_attach link = %p, dev = %p, local = %p, intr = %p\n", | ||
371 | link,dev,local,&ray_interrupt); | ||
372 | |||
373 | /* Raylink entries in the device structure */ | ||
374 | dev->hard_start_xmit = &ray_dev_start_xmit; | ||
375 | dev->set_config = &ray_dev_config; | ||
376 | dev->get_stats = &ray_get_stats; | ||
377 | dev->do_ioctl = &ray_dev_ioctl; | ||
378 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | ||
379 | #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ | ||
380 | dev->get_wireless_stats = ray_get_wireless_stats; | ||
381 | #endif | ||
382 | |||
383 | dev->set_multicast_list = &set_multicast_list; | ||
384 | |||
385 | DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); | ||
386 | SET_MODULE_OWNER(dev); | ||
387 | dev->init = &ray_dev_init; | ||
388 | dev->open = &ray_open; | ||
389 | dev->stop = &ray_dev_close; | ||
390 | netif_stop_queue(dev); | ||
391 | |||
392 | /* Register with Card Services */ | ||
393 | link->next = dev_list; | ||
394 | dev_list = link; | ||
395 | client_reg.dev_info = &dev_info; | ||
396 | client_reg.EventMask = | ||
397 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
398 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
399 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
400 | client_reg.event_handler = &ray_event; | ||
401 | client_reg.Version = 0x0210; | ||
402 | client_reg.event_callback_args.client_data = link; | ||
403 | |||
404 | DEBUG(2,"ray_cs ray_attach calling pcmcia_register_client(...)\n"); | ||
405 | |||
406 | init_timer(&local->timer); | ||
407 | |||
408 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
409 | if (ret != 0) { | ||
410 | printk("ray_cs ray_attach RegisterClient unhappy - detaching\n"); | ||
411 | cs_error(link->handle, RegisterClient, ret); | ||
412 | ray_detach(link); | ||
413 | return NULL; | ||
414 | } | ||
415 | DEBUG(2,"ray_cs ray_attach ending\n"); | ||
416 | return link; | ||
417 | |||
418 | fail_alloc_dev: | ||
419 | kfree(link); | ||
420 | return NULL; | ||
421 | } /* ray_attach */ | ||
422 | /*============================================================================= | ||
423 | This deletes a driver "instance". The device is de-registered | ||
424 | with Card Services. If it has been released, all local data | ||
425 | structures are freed. Otherwise, the structures will be freed | ||
426 | when the device is released. | ||
427 | =============================================================================*/ | ||
428 | static void ray_detach(dev_link_t *link) | ||
429 | { | ||
430 | dev_link_t **linkp; | ||
431 | |||
432 | DEBUG(1, "ray_detach(0x%p)\n", link); | ||
433 | |||
434 | /* Locate device structure */ | ||
435 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
436 | if (*linkp == link) break; | ||
437 | if (*linkp == NULL) | ||
438 | return; | ||
439 | |||
440 | /* If the device is currently configured and active, we won't | ||
441 | actually delete it yet. Instead, it is marked so that when | ||
442 | the release() function is called, that will trigger a proper | ||
443 | detach(). | ||
444 | */ | ||
445 | if (link->state & DEV_CONFIG) | ||
446 | ray_release(link); | ||
447 | |||
448 | /* Break the link with Card Services */ | ||
449 | if (link->handle) | ||
450 | pcmcia_deregister_client(link->handle); | ||
451 | |||
452 | /* Unlink device structure, free pieces */ | ||
453 | *linkp = link->next; | ||
454 | if (link->priv) { | ||
455 | struct net_device *dev = link->priv; | ||
456 | if (link->dev) unregister_netdev(dev); | ||
457 | free_netdev(dev); | ||
458 | } | ||
459 | kfree(link); | ||
460 | DEBUG(2,"ray_cs ray_detach ending\n"); | ||
461 | } /* ray_detach */ | ||
462 | /*============================================================================= | ||
463 | ray_config() is run after a CARD_INSERTION event | ||
464 | is received, to configure the PCMCIA socket, and to make the | ||
465 | ethernet device available to the system. | ||
466 | =============================================================================*/ | ||
467 | #define CS_CHECK(fn, ret) \ | ||
468 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
469 | #define MAX_TUPLE_SIZE 128 | ||
470 | static void ray_config(dev_link_t *link) | ||
471 | { | ||
472 | client_handle_t handle = link->handle; | ||
473 | tuple_t tuple; | ||
474 | cisparse_t parse; | ||
475 | int last_fn = 0, last_ret = 0; | ||
476 | int i; | ||
477 | u_char buf[MAX_TUPLE_SIZE]; | ||
478 | win_req_t req; | ||
479 | memreq_t mem; | ||
480 | struct net_device *dev = (struct net_device *)link->priv; | ||
481 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
482 | |||
483 | DEBUG(1, "ray_config(0x%p)\n", link); | ||
484 | |||
485 | /* This reads the card's CONFIG tuple to find its configuration regs */ | ||
486 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
487 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
488 | tuple.TupleData = buf; | ||
489 | tuple.TupleDataMax = MAX_TUPLE_SIZE; | ||
490 | tuple.TupleOffset = 0; | ||
491 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
492 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
493 | link->conf.ConfigBase = parse.config.base; | ||
494 | link->conf.Present = parse.config.rmask[0]; | ||
495 | |||
496 | /* Determine card type and firmware version */ | ||
497 | buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; | ||
498 | tuple.DesiredTuple = CISTPL_VERS_1; | ||
499 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
500 | tuple.TupleData = buf; | ||
501 | tuple.TupleDataMax = MAX_TUPLE_SIZE; | ||
502 | tuple.TupleOffset = 2; | ||
503 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
504 | |||
505 | for (i=0; i<tuple.TupleDataLen - 4; i++) | ||
506 | if (buf[i] == 0) buf[i] = ' '; | ||
507 | printk(KERN_INFO "ray_cs Detected: %s\n",buf); | ||
508 | |||
509 | /* Configure card */ | ||
510 | link->state |= DEV_CONFIG; | ||
511 | |||
512 | /* Now allocate an interrupt line. Note that this does not | ||
513 | actually assign a handler to the interrupt. | ||
514 | */ | ||
515 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
516 | dev->irq = link->irq.AssignedIRQ; | ||
517 | |||
518 | /* This actually configures the PCMCIA socket -- setting up | ||
519 | the I/O windows and the interrupt mapping. | ||
520 | */ | ||
521 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
522 | |||
523 | /*** Set up 32k window for shared memory (transmit and control) ************/ | ||
524 | req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; | ||
525 | req.Base = 0; | ||
526 | req.Size = 0x8000; | ||
527 | req.AccessSpeed = ray_mem_speed; | ||
528 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); | ||
529 | mem.CardOffset = 0x0000; mem.Page = 0; | ||
530 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); | ||
531 | local->sram = ioremap(req.Base,req.Size); | ||
532 | |||
533 | /*** Set up 16k window for shared memory (receive buffer) ***************/ | ||
534 | req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; | ||
535 | req.Base = 0; | ||
536 | req.Size = 0x4000; | ||
537 | req.AccessSpeed = ray_mem_speed; | ||
538 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle)); | ||
539 | mem.CardOffset = 0x8000; mem.Page = 0; | ||
540 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); | ||
541 | local->rmem = ioremap(req.Base,req.Size); | ||
542 | |||
543 | /*** Set up window for attribute memory ***********************************/ | ||
544 | req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; | ||
545 | req.Base = 0; | ||
546 | req.Size = 0x1000; | ||
547 | req.AccessSpeed = ray_mem_speed; | ||
548 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle)); | ||
549 | mem.CardOffset = 0x0000; mem.Page = 0; | ||
550 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); | ||
551 | local->amem = ioremap(req.Base,req.Size); | ||
552 | |||
553 | DEBUG(3,"ray_config sram=%p\n",local->sram); | ||
554 | DEBUG(3,"ray_config rmem=%p\n",local->rmem); | ||
555 | DEBUG(3,"ray_config amem=%p\n",local->amem); | ||
556 | if (ray_init(dev) < 0) { | ||
557 | ray_release(link); | ||
558 | return; | ||
559 | } | ||
560 | |||
561 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
562 | i = register_netdev(dev); | ||
563 | if (i != 0) { | ||
564 | printk("ray_config register_netdev() failed\n"); | ||
565 | ray_release(link); | ||
566 | return; | ||
567 | } | ||
568 | |||
569 | strcpy(local->node.dev_name, dev->name); | ||
570 | link->dev = &local->node; | ||
571 | |||
572 | link->state &= ~DEV_CONFIG_PENDING; | ||
573 | printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", | ||
574 | dev->name, dev->irq); | ||
575 | for (i = 0; i < 6; i++) | ||
576 | printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); | ||
577 | |||
578 | return; | ||
579 | |||
580 | cs_failed: | ||
581 | cs_error(link->handle, last_fn, last_ret); | ||
582 | |||
583 | ray_release(link); | ||
584 | } /* ray_config */ | ||
585 | |||
586 | static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) | ||
587 | { | ||
588 | return dev->sram + CCS_BASE; | ||
589 | } | ||
590 | |||
591 | static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) | ||
592 | { | ||
593 | /* | ||
594 | * This looks nonsensical, since there is a separate | ||
595 | * RCS_BASE. But the difference between a "struct rcs" | ||
596 | * and a "struct ccs" ends up being in the _index_ off | ||
597 | * the base, so the base pointer is the same for both | ||
598 | * ccs/rcs. | ||
599 | */ | ||
600 | return dev->sram + CCS_BASE; | ||
601 | } | ||
602 | |||
603 | /*===========================================================================*/ | ||
604 | static int ray_init(struct net_device *dev) | ||
605 | { | ||
606 | int i; | ||
607 | UCHAR *p; | ||
608 | struct ccs __iomem *pccs; | ||
609 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
610 | dev_link_t *link = local->finder; | ||
611 | DEBUG(1, "ray_init(0x%p)\n", dev); | ||
612 | if (!(link->state & DEV_PRESENT)) { | ||
613 | DEBUG(0,"ray_init - device not present\n"); | ||
614 | return -1; | ||
615 | } | ||
616 | |||
617 | local->net_type = net_type; | ||
618 | local->sta_type = TYPE_STA; | ||
619 | |||
620 | /* Copy the startup results to local memory */ | ||
621 | memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\ | ||
622 | sizeof(struct startup_res_6)); | ||
623 | |||
624 | /* Check Power up test status and get mac address from card */ | ||
625 | if (local->startup_res.startup_word != 0x80) { | ||
626 | printk(KERN_INFO "ray_init ERROR card status = %2x\n", | ||
627 | local->startup_res.startup_word); | ||
628 | local->card_status = CARD_INIT_ERROR; | ||
629 | return -1; | ||
630 | } | ||
631 | |||
632 | local->fw_ver = local->startup_res.firmware_version[0]; | ||
633 | local->fw_bld = local->startup_res.firmware_version[1]; | ||
634 | local->fw_var = local->startup_res.firmware_version[2]; | ||
635 | DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld); | ||
636 | |||
637 | local->tib_length = 0x20; | ||
638 | if ((local->fw_ver == 5) && (local->fw_bld >= 30)) | ||
639 | local->tib_length = local->startup_res.tib_length; | ||
640 | DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length); | ||
641 | /* Initialize CCS's to buffer free state */ | ||
642 | pccs = ccs_base(local); | ||
643 | for (i=0; i<NUMBER_OF_CCS; i++) { | ||
644 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
645 | } | ||
646 | init_startup_params(local); | ||
647 | |||
648 | /* copy mac address to startup parameters */ | ||
649 | if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) | ||
650 | { | ||
651 | p = local->sparm.b4.a_mac_addr; | ||
652 | } | ||
653 | else | ||
654 | { | ||
655 | memcpy(&local->sparm.b4.a_mac_addr, | ||
656 | &local->startup_res.station_addr, ADDRLEN); | ||
657 | p = local->sparm.b4.a_mac_addr; | ||
658 | } | ||
659 | |||
660 | clear_interrupt(local); /* Clear any interrupt from the card */ | ||
661 | local->card_status = CARD_AWAITING_PARAM; | ||
662 | DEBUG(2,"ray_init ending\n"); | ||
663 | return 0; | ||
664 | } /* ray_init */ | ||
665 | /*===========================================================================*/ | ||
666 | /* Download startup parameters to the card and command it to read them */ | ||
667 | static int dl_startup_params(struct net_device *dev) | ||
668 | { | ||
669 | int ccsindex; | ||
670 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
671 | struct ccs __iomem *pccs; | ||
672 | dev_link_t *link = local->finder; | ||
673 | |||
674 | DEBUG(1,"dl_startup_params entered\n"); | ||
675 | if (!(link->state & DEV_PRESENT)) { | ||
676 | DEBUG(2,"ray_cs dl_startup_params - device not present\n"); | ||
677 | return -1; | ||
678 | } | ||
679 | |||
680 | /* Copy parameters to host to ECF area */ | ||
681 | if (local->fw_ver == 0x55) | ||
682 | memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, | ||
683 | sizeof(struct b4_startup_params)); | ||
684 | else | ||
685 | memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, | ||
686 | sizeof(struct b5_startup_params)); | ||
687 | |||
688 | |||
689 | /* Fill in the CCS fields for the ECF */ | ||
690 | if ((ccsindex = get_free_ccs(local)) < 0) return -1; | ||
691 | local->dl_param_ccs = ccsindex; | ||
692 | pccs = ccs_base(local) + ccsindex; | ||
693 | writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); | ||
694 | DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); | ||
695 | /* Interrupt the firmware to process the command */ | ||
696 | if (interrupt_ecf(local, ccsindex)) { | ||
697 | printk(KERN_INFO "ray dl_startup_params failed - " | ||
698 | "ECF not ready for intr\n"); | ||
699 | local->card_status = CARD_DL_PARAM_ERROR; | ||
700 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
701 | return -2; | ||
702 | } | ||
703 | local->card_status = CARD_DL_PARAM; | ||
704 | /* Start kernel timer to wait for dl startup to complete. */ | ||
705 | local->timer.expires = jiffies + HZ/2; | ||
706 | local->timer.data = (long)local; | ||
707 | local->timer.function = &verify_dl_startup; | ||
708 | add_timer(&local->timer); | ||
709 | DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n"); | ||
710 | return 0; | ||
711 | } /* dl_startup_params */ | ||
712 | /*===========================================================================*/ | ||
713 | static void init_startup_params(ray_dev_t *local) | ||
714 | { | ||
715 | int i; | ||
716 | |||
717 | if (country > JAPAN_TEST) country = USA; | ||
718 | else | ||
719 | if (country < USA) country = USA; | ||
720 | /* structure for hop time and beacon period is defined here using | ||
721 | * New 802.11D6.1 format. Card firmware is still using old format | ||
722 | * until version 6. | ||
723 | * Before After | ||
724 | * a_hop_time ms byte a_hop_time ms byte | ||
725 | * a_hop_time 2s byte a_hop_time ls byte | ||
726 | * a_hop_time ls byte a_beacon_period ms byte | ||
727 | * a_beacon_period a_beacon_period ls byte | ||
728 | * | ||
729 | * a_hop_time = uS a_hop_time = KuS | ||
730 | * a_beacon_period = hops a_beacon_period = KuS | ||
731 | */ /* 64ms = 010000 */ | ||
732 | if (local->fw_ver == 0x55) { | ||
733 | memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, | ||
734 | sizeof(struct b4_startup_params)); | ||
735 | /* Translate sane kus input values to old build 4/5 format */ | ||
736 | /* i = hop time in uS truncated to 3 bytes */ | ||
737 | i = (hop_dwell * 1024) & 0xffffff; | ||
738 | local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; | ||
739 | local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; | ||
740 | local->sparm.b4.a_beacon_period[0] = 0; | ||
741 | local->sparm.b4.a_beacon_period[1] = | ||
742 | ((beacon_period/hop_dwell) - 1) & 0xff; | ||
743 | local->sparm.b4.a_curr_country_code = country; | ||
744 | local->sparm.b4.a_hop_pattern_length = | ||
745 | hop_pattern_length[(int)country] - 1; | ||
746 | if (bc) | ||
747 | { | ||
748 | local->sparm.b4.a_ack_timeout = 0x50; | ||
749 | local->sparm.b4.a_sifs = 0x3f; | ||
750 | } | ||
751 | } | ||
752 | else { /* Version 5 uses real kus values */ | ||
753 | memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, | ||
754 | sizeof(struct b5_startup_params)); | ||
755 | |||
756 | local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; | ||
757 | local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; | ||
758 | local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff; | ||
759 | local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; | ||
760 | if (psm) | ||
761 | local->sparm.b5.a_power_mgt_state = 1; | ||
762 | local->sparm.b5.a_curr_country_code = country; | ||
763 | local->sparm.b5.a_hop_pattern_length = | ||
764 | hop_pattern_length[(int)country]; | ||
765 | } | ||
766 | |||
767 | local->sparm.b4.a_network_type = net_type & 0x01; | ||
768 | local->sparm.b4.a_acting_as_ap_status = TYPE_STA; | ||
769 | |||
770 | if (essid != NULL) | ||
771 | strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); | ||
772 | } /* init_startup_params */ | ||
773 | /*===========================================================================*/ | ||
774 | static void verify_dl_startup(u_long data) | ||
775 | { | ||
776 | ray_dev_t *local = (ray_dev_t *)data; | ||
777 | struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; | ||
778 | UCHAR status; | ||
779 | dev_link_t *link = local->finder; | ||
780 | |||
781 | if (!(link->state & DEV_PRESENT)) { | ||
782 | DEBUG(2,"ray_cs verify_dl_startup - device not present\n"); | ||
783 | return; | ||
784 | } | ||
785 | #ifdef PCMCIA_DEBUG | ||
786 | if (pc_debug > 2) { | ||
787 | int i; | ||
788 | printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n", | ||
789 | local->dl_param_ccs); | ||
790 | for (i=0; i<sizeof(struct b5_startup_params); i++) { | ||
791 | printk(" %2x", (unsigned int) readb(local->sram + HOST_TO_ECF_BASE + i)); | ||
792 | } | ||
793 | printk("\n"); | ||
794 | } | ||
795 | #endif | ||
796 | |||
797 | status = readb(&pccs->buffer_status); | ||
798 | if (status!= CCS_BUFFER_FREE) | ||
799 | { | ||
800 | printk(KERN_INFO "Download startup params failed. Status = %d\n", | ||
801 | status); | ||
802 | local->card_status = CARD_DL_PARAM_ERROR; | ||
803 | return; | ||
804 | } | ||
805 | if (local->sparm.b4.a_network_type == ADHOC) | ||
806 | start_net((u_long)local); | ||
807 | else | ||
808 | join_net((u_long)local); | ||
809 | |||
810 | return; | ||
811 | } /* end verify_dl_startup */ | ||
812 | /*===========================================================================*/ | ||
813 | /* Command card to start a network */ | ||
814 | static void start_net(u_long data) | ||
815 | { | ||
816 | ray_dev_t *local = (ray_dev_t *)data; | ||
817 | struct ccs __iomem *pccs; | ||
818 | int ccsindex; | ||
819 | dev_link_t *link = local->finder; | ||
820 | if (!(link->state & DEV_PRESENT)) { | ||
821 | DEBUG(2,"ray_cs start_net - device not present\n"); | ||
822 | return; | ||
823 | } | ||
824 | /* Fill in the CCS fields for the ECF */ | ||
825 | if ((ccsindex = get_free_ccs(local)) < 0) return; | ||
826 | pccs = ccs_base(local) + ccsindex; | ||
827 | writeb(CCS_START_NETWORK, &pccs->cmd); | ||
828 | writeb(0, &pccs->var.start_network.update_param); | ||
829 | /* Interrupt the firmware to process the command */ | ||
830 | if (interrupt_ecf(local, ccsindex)) { | ||
831 | DEBUG(1,"ray start net failed - card not ready for intr\n"); | ||
832 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
833 | return; | ||
834 | } | ||
835 | local->card_status = CARD_DOING_ACQ; | ||
836 | return; | ||
837 | } /* end start_net */ | ||
838 | /*===========================================================================*/ | ||
839 | /* Command card to join a network */ | ||
840 | static void join_net(u_long data) | ||
841 | { | ||
842 | ray_dev_t *local = (ray_dev_t *)data; | ||
843 | |||
844 | struct ccs __iomem *pccs; | ||
845 | int ccsindex; | ||
846 | dev_link_t *link = local->finder; | ||
847 | |||
848 | if (!(link->state & DEV_PRESENT)) { | ||
849 | DEBUG(2,"ray_cs join_net - device not present\n"); | ||
850 | return; | ||
851 | } | ||
852 | /* Fill in the CCS fields for the ECF */ | ||
853 | if ((ccsindex = get_free_ccs(local)) < 0) return; | ||
854 | pccs = ccs_base(local) + ccsindex; | ||
855 | writeb(CCS_JOIN_NETWORK, &pccs->cmd); | ||
856 | writeb(0, &pccs->var.join_network.update_param); | ||
857 | writeb(0, &pccs->var.join_network.net_initiated); | ||
858 | /* Interrupt the firmware to process the command */ | ||
859 | if (interrupt_ecf(local, ccsindex)) { | ||
860 | DEBUG(1,"ray join net failed - card not ready for intr\n"); | ||
861 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
862 | return; | ||
863 | } | ||
864 | local->card_status = CARD_DOING_ACQ; | ||
865 | return; | ||
866 | } | ||
867 | /*============================================================================ | ||
868 | After a card is removed, ray_release() will unregister the net | ||
869 | device, and release the PCMCIA configuration. If the device is | ||
870 | still open, this will be postponed until it is closed. | ||
871 | =============================================================================*/ | ||
872 | static void ray_release(dev_link_t *link) | ||
873 | { | ||
874 | struct net_device *dev = link->priv; | ||
875 | ray_dev_t *local = dev->priv; | ||
876 | int i; | ||
877 | |||
878 | DEBUG(1, "ray_release(0x%p)\n", link); | ||
879 | |||
880 | del_timer(&local->timer); | ||
881 | link->state &= ~DEV_CONFIG; | ||
882 | |||
883 | iounmap(local->sram); | ||
884 | iounmap(local->rmem); | ||
885 | iounmap(local->amem); | ||
886 | /* Do bother checking to see if these succeed or not */ | ||
887 | i = pcmcia_release_window(link->win); | ||
888 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i); | ||
889 | i = pcmcia_release_window(local->amem_handle); | ||
890 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); | ||
891 | i = pcmcia_release_window(local->rmem_handle); | ||
892 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); | ||
893 | i = pcmcia_release_configuration(link->handle); | ||
894 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i); | ||
895 | i = pcmcia_release_irq(link->handle, &link->irq); | ||
896 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); | ||
897 | |||
898 | DEBUG(2,"ray_release ending\n"); | ||
899 | } | ||
900 | |||
901 | /*============================================================================= | ||
902 | The card status event handler. Mostly, this schedules other | ||
903 | stuff to run after an event is received. A CARD_REMOVAL event | ||
904 | also sets some flags to discourage the net drivers from trying | ||
905 | to talk to the card any more. | ||
906 | |||
907 | When a CARD_REMOVAL event is received, we immediately set a flag | ||
908 | to block future accesses to this device. All the functions that | ||
909 | actually access the device should check this flag to make sure | ||
910 | the card is still present. | ||
911 | =============================================================================*/ | ||
912 | static int ray_event(event_t event, int priority, | ||
913 | event_callback_args_t *args) | ||
914 | { | ||
915 | dev_link_t *link = args->client_data; | ||
916 | struct net_device *dev = link->priv; | ||
917 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
918 | DEBUG(1, "ray_event(0x%06x)\n", event); | ||
919 | |||
920 | switch (event) { | ||
921 | case CS_EVENT_CARD_REMOVAL: | ||
922 | link->state &= ~DEV_PRESENT; | ||
923 | netif_device_detach(dev); | ||
924 | if (link->state & DEV_CONFIG) { | ||
925 | ray_release(link); | ||
926 | del_timer(&local->timer); | ||
927 | } | ||
928 | break; | ||
929 | case CS_EVENT_CARD_INSERTION: | ||
930 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
931 | ray_config(link); | ||
932 | break; | ||
933 | case CS_EVENT_PM_SUSPEND: | ||
934 | link->state |= DEV_SUSPEND; | ||
935 | /* Fall through... */ | ||
936 | case CS_EVENT_RESET_PHYSICAL: | ||
937 | if (link->state & DEV_CONFIG) { | ||
938 | if (link->open) | ||
939 | netif_device_detach(dev); | ||
940 | |||
941 | pcmcia_release_configuration(link->handle); | ||
942 | } | ||
943 | break; | ||
944 | case CS_EVENT_PM_RESUME: | ||
945 | link->state &= ~DEV_SUSPEND; | ||
946 | /* Fall through... */ | ||
947 | case CS_EVENT_CARD_RESET: | ||
948 | if (link->state & DEV_CONFIG) { | ||
949 | pcmcia_request_configuration(link->handle, &link->conf); | ||
950 | if (link->open) { | ||
951 | ray_reset(dev); | ||
952 | netif_device_attach(dev); | ||
953 | } | ||
954 | } | ||
955 | break; | ||
956 | } | ||
957 | return 0; | ||
958 | DEBUG(2,"ray_event ending\n"); | ||
959 | } /* ray_event */ | ||
960 | /*===========================================================================*/ | ||
961 | int ray_dev_init(struct net_device *dev) | ||
962 | { | ||
963 | #ifdef RAY_IMMEDIATE_INIT | ||
964 | int i; | ||
965 | #endif /* RAY_IMMEDIATE_INIT */ | ||
966 | ray_dev_t *local = dev->priv; | ||
967 | dev_link_t *link = local->finder; | ||
968 | |||
969 | DEBUG(1,"ray_dev_init(dev=%p)\n",dev); | ||
970 | if (!(link->state & DEV_PRESENT)) { | ||
971 | DEBUG(2,"ray_dev_init - device not present\n"); | ||
972 | return -1; | ||
973 | } | ||
974 | #ifdef RAY_IMMEDIATE_INIT | ||
975 | /* Download startup parameters */ | ||
976 | if ( (i = dl_startup_params(dev)) < 0) | ||
977 | { | ||
978 | printk(KERN_INFO "ray_dev_init dl_startup_params failed - " | ||
979 | "returns 0x%x\n",i); | ||
980 | return -1; | ||
981 | } | ||
982 | #else /* RAY_IMMEDIATE_INIT */ | ||
983 | /* Postpone the card init so that we can still configure the card, | ||
984 | * for example using the Wireless Extensions. The init will happen | ||
985 | * in ray_open() - Jean II */ | ||
986 | DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n", | ||
987 | local->card_status); | ||
988 | #endif /* RAY_IMMEDIATE_INIT */ | ||
989 | |||
990 | /* copy mac and broadcast addresses to linux device */ | ||
991 | memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); | ||
992 | memset(dev->broadcast, 0xff, ETH_ALEN); | ||
993 | |||
994 | DEBUG(2,"ray_dev_init ending\n"); | ||
995 | return 0; | ||
996 | } | ||
997 | /*===========================================================================*/ | ||
998 | static int ray_dev_config(struct net_device *dev, struct ifmap *map) | ||
999 | { | ||
1000 | ray_dev_t *local = dev->priv; | ||
1001 | dev_link_t *link = local->finder; | ||
1002 | /* Dummy routine to satisfy device structure */ | ||
1003 | DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); | ||
1004 | if (!(link->state & DEV_PRESENT)) { | ||
1005 | DEBUG(2,"ray_dev_config - device not present\n"); | ||
1006 | return -1; | ||
1007 | } | ||
1008 | |||
1009 | return 0; | ||
1010 | } | ||
1011 | /*===========================================================================*/ | ||
1012 | static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
1013 | { | ||
1014 | ray_dev_t *local = dev->priv; | ||
1015 | dev_link_t *link = local->finder; | ||
1016 | short length = skb->len; | ||
1017 | |||
1018 | if (!(link->state & DEV_PRESENT)) { | ||
1019 | DEBUG(2,"ray_dev_start_xmit - device not present\n"); | ||
1020 | return -1; | ||
1021 | } | ||
1022 | DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev); | ||
1023 | if (local->authentication_state == NEED_TO_AUTH) { | ||
1024 | DEBUG(0,"ray_cs Sending authentication request.\n"); | ||
1025 | if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) { | ||
1026 | local->authentication_state = AUTHENTICATED; | ||
1027 | netif_stop_queue(dev); | ||
1028 | return 1; | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | if (length < ETH_ZLEN) | ||
1033 | { | ||
1034 | skb = skb_padto(skb, ETH_ZLEN); | ||
1035 | if (skb == NULL) | ||
1036 | return 0; | ||
1037 | length = ETH_ZLEN; | ||
1038 | } | ||
1039 | switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) { | ||
1040 | case XMIT_NO_CCS: | ||
1041 | case XMIT_NEED_AUTH: | ||
1042 | netif_stop_queue(dev); | ||
1043 | return 1; | ||
1044 | case XMIT_NO_INTR: | ||
1045 | case XMIT_MSG_BAD: | ||
1046 | case XMIT_OK: | ||
1047 | default: | ||
1048 | dev->trans_start = jiffies; | ||
1049 | dev_kfree_skb(skb); | ||
1050 | return 0; | ||
1051 | } | ||
1052 | return 0; | ||
1053 | } /* ray_dev_start_xmit */ | ||
1054 | /*===========================================================================*/ | ||
1055 | static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, | ||
1056 | UCHAR msg_type) | ||
1057 | { | ||
1058 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1059 | struct ccs __iomem *pccs; | ||
1060 | int ccsindex; | ||
1061 | int offset; | ||
1062 | struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ | ||
1063 | short int addr; /* Address of xmit buffer in card space */ | ||
1064 | |||
1065 | DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); | ||
1066 | if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) | ||
1067 | { | ||
1068 | printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len); | ||
1069 | return XMIT_MSG_BAD; | ||
1070 | } | ||
1071 | switch (ccsindex = get_free_tx_ccs(local)) { | ||
1072 | case ECCSBUSY: | ||
1073 | DEBUG(2,"ray_hw_xmit tx_ccs table busy\n"); | ||
1074 | case ECCSFULL: | ||
1075 | DEBUG(2,"ray_hw_xmit No free tx ccs\n"); | ||
1076 | case ECARDGONE: | ||
1077 | netif_stop_queue(dev); | ||
1078 | return XMIT_NO_CCS; | ||
1079 | default: | ||
1080 | break; | ||
1081 | } | ||
1082 | addr = TX_BUF_BASE + (ccsindex << 11); | ||
1083 | |||
1084 | if (msg_type == DATA_TYPE) { | ||
1085 | local->stats.tx_bytes += len; | ||
1086 | local->stats.tx_packets++; | ||
1087 | } | ||
1088 | |||
1089 | ptx = local->sram + addr; | ||
1090 | |||
1091 | ray_build_header(local, ptx, msg_type, data); | ||
1092 | if (translate) { | ||
1093 | offset = translate_frame(local, ptx, data, len); | ||
1094 | } | ||
1095 | else { /* Encapsulate frame */ | ||
1096 | /* TBD TIB length will move address of ptx->var */ | ||
1097 | memcpy_toio(&ptx->var, data, len); | ||
1098 | offset = 0; | ||
1099 | } | ||
1100 | |||
1101 | /* fill in the CCS */ | ||
1102 | pccs = ccs_base(local) + ccsindex; | ||
1103 | len += TX_HEADER_LENGTH + offset; | ||
1104 | writeb(CCS_TX_REQUEST, &pccs->cmd); | ||
1105 | writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); | ||
1106 | writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); | ||
1107 | writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); | ||
1108 | writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]); | ||
1109 | /* TBD still need psm_cam? */ | ||
1110 | writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); | ||
1111 | writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); | ||
1112 | writeb(0, &pccs->var.tx_request.antenna); | ||
1113 | DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\ | ||
1114 | local->net_default_tx_rate); | ||
1115 | |||
1116 | /* Interrupt the firmware to process the command */ | ||
1117 | if (interrupt_ecf(local, ccsindex)) { | ||
1118 | DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n"); | ||
1119 | /* TBD very inefficient to copy packet to buffer, and then not | ||
1120 | send it, but the alternative is to queue the messages and that | ||
1121 | won't be done for a while. Maybe set tbusy until a CCS is free? | ||
1122 | */ | ||
1123 | writeb(CCS_BUFFER_FREE, &pccs->buffer_status); | ||
1124 | return XMIT_NO_INTR; | ||
1125 | } | ||
1126 | return XMIT_OK; | ||
1127 | } /* end ray_hw_xmit */ | ||
1128 | /*===========================================================================*/ | ||
1129 | static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, | ||
1130 | int len) | ||
1131 | { | ||
1132 | unsigned short int proto = ((struct ethhdr *)data)->h_proto; | ||
1133 | if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ | ||
1134 | DEBUG(3,"ray_cs translate_frame DIX II\n"); | ||
1135 | /* Copy LLC header to card buffer */ | ||
1136 | memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); | ||
1137 | memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); | ||
1138 | if ((proto == 0xf380) || (proto == 0x3781)) { | ||
1139 | /* This is the selective translation table, only 2 entries */ | ||
1140 | writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); | ||
1141 | } | ||
1142 | /* Copy body of ethernet packet without ethernet header */ | ||
1143 | memcpy_toio((void __iomem *)&ptx->var + sizeof(struct snaphdr_t), \ | ||
1144 | data + ETH_HLEN, len - ETH_HLEN); | ||
1145 | return (int) sizeof(struct snaphdr_t) - ETH_HLEN; | ||
1146 | } | ||
1147 | else { /* already 802 type, and proto is length */ | ||
1148 | DEBUG(3,"ray_cs translate_frame 802\n"); | ||
1149 | if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ | ||
1150 | DEBUG(3,"ray_cs translate_frame evil IPX\n"); | ||
1151 | memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); | ||
1152 | return 0 - ETH_HLEN; | ||
1153 | } | ||
1154 | memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); | ||
1155 | return 0 - ETH_HLEN; | ||
1156 | } | ||
1157 | /* TBD do other frame types */ | ||
1158 | } /* end translate_frame */ | ||
1159 | /*===========================================================================*/ | ||
1160 | static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, | ||
1161 | unsigned char *data) | ||
1162 | { | ||
1163 | writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); | ||
1164 | /*** IEEE 802.11 Address field assignments ************* | ||
1165 | TODS FROMDS addr_1 addr_2 addr_3 addr_4 | ||
1166 | Adhoc 0 0 dest src (terminal) BSSID N/A | ||
1167 | AP to Terminal 0 1 dest AP(BSSID) source N/A | ||
1168 | Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A | ||
1169 | AP to AP 1 1 dest AP src AP dest source | ||
1170 | *******************************************************/ | ||
1171 | if (local->net_type == ADHOC) { | ||
1172 | writeb(0, &ptx->mac.frame_ctl_2); | ||
1173 | memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, 2 * ADDRLEN); | ||
1174 | memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); | ||
1175 | } | ||
1176 | else /* infrastructure */ | ||
1177 | { | ||
1178 | if (local->sparm.b4.a_acting_as_ap_status) | ||
1179 | { | ||
1180 | writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2); | ||
1181 | memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN); | ||
1182 | memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); | ||
1183 | memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN); | ||
1184 | } | ||
1185 | else /* Terminal */ | ||
1186 | { | ||
1187 | writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2); | ||
1188 | memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN); | ||
1189 | memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, ADDRLEN); | ||
1190 | memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_dest, ADDRLEN); | ||
1191 | } | ||
1192 | } | ||
1193 | } /* end encapsulate_frame */ | ||
1194 | |||
1195 | |||
1196 | /*===========================================================================*/ | ||
1197 | |||
1198 | static void netdev_get_drvinfo(struct net_device *dev, | ||
1199 | struct ethtool_drvinfo *info) | ||
1200 | { | ||
1201 | strcpy(info->driver, "ray_cs"); | ||
1202 | } | ||
1203 | |||
1204 | static struct ethtool_ops netdev_ethtool_ops = { | ||
1205 | .get_drvinfo = netdev_get_drvinfo, | ||
1206 | }; | ||
1207 | |||
1208 | /*====================================================================*/ | ||
1209 | |||
1210 | static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1211 | { | ||
1212 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1213 | dev_link_t *link = local->finder; | ||
1214 | int err = 0; | ||
1215 | #if WIRELESS_EXT > 7 | ||
1216 | struct iwreq *wrq = (struct iwreq *) ifr; | ||
1217 | #endif /* WIRELESS_EXT > 7 */ | ||
1218 | #ifdef WIRELESS_SPY | ||
1219 | struct sockaddr address[IW_MAX_SPY]; | ||
1220 | #endif /* WIRELESS_SPY */ | ||
1221 | |||
1222 | if (!(link->state & DEV_PRESENT)) { | ||
1223 | DEBUG(2,"ray_dev_ioctl - device not present\n"); | ||
1224 | return -1; | ||
1225 | } | ||
1226 | DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd); | ||
1227 | /* Validate the command */ | ||
1228 | switch (cmd) | ||
1229 | { | ||
1230 | #if WIRELESS_EXT > 7 | ||
1231 | /* --------------- WIRELESS EXTENSIONS --------------- */ | ||
1232 | /* Get name */ | ||
1233 | case SIOCGIWNAME: | ||
1234 | strcpy(wrq->u.name, "IEEE 802.11-FH"); | ||
1235 | break; | ||
1236 | |||
1237 | /* Get frequency/channel */ | ||
1238 | case SIOCGIWFREQ: | ||
1239 | wrq->u.freq.m = local->sparm.b5.a_hop_pattern; | ||
1240 | wrq->u.freq.e = 0; | ||
1241 | break; | ||
1242 | |||
1243 | /* Set frequency/channel */ | ||
1244 | case SIOCSIWFREQ: | ||
1245 | /* Reject if card is already initialised */ | ||
1246 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1247 | { | ||
1248 | err = -EBUSY; | ||
1249 | break; | ||
1250 | } | ||
1251 | |||
1252 | /* Setting by channel number */ | ||
1253 | if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0)) | ||
1254 | err = -EOPNOTSUPP; | ||
1255 | else | ||
1256 | local->sparm.b5.a_hop_pattern = wrq->u.freq.m; | ||
1257 | break; | ||
1258 | |||
1259 | /* Get current network name (ESSID) */ | ||
1260 | case SIOCGIWESSID: | ||
1261 | if (wrq->u.data.pointer) | ||
1262 | { | ||
1263 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
1264 | /* Get the essid that was set */ | ||
1265 | memcpy(essid, local->sparm.b5.a_current_ess_id, | ||
1266 | IW_ESSID_MAX_SIZE); | ||
1267 | essid[IW_ESSID_MAX_SIZE] = '\0'; | ||
1268 | |||
1269 | /* Push it out ! */ | ||
1270 | wrq->u.data.length = strlen(essid) + 1; | ||
1271 | wrq->u.data.flags = 1; /* active */ | ||
1272 | if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid))) | ||
1273 | err = -EFAULT; | ||
1274 | } | ||
1275 | break; | ||
1276 | |||
1277 | /* Set desired network name (ESSID) */ | ||
1278 | case SIOCSIWESSID: | ||
1279 | /* Reject if card is already initialised */ | ||
1280 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1281 | { | ||
1282 | err = -EBUSY; | ||
1283 | break; | ||
1284 | } | ||
1285 | |||
1286 | if (wrq->u.data.pointer) | ||
1287 | { | ||
1288 | char card_essid[IW_ESSID_MAX_SIZE + 1]; | ||
1289 | |||
1290 | /* Check if we asked for `any' */ | ||
1291 | if(wrq->u.data.flags == 0) | ||
1292 | { | ||
1293 | /* Corey : can you do that ? */ | ||
1294 | err = -EOPNOTSUPP; | ||
1295 | } | ||
1296 | else | ||
1297 | { | ||
1298 | /* Check the size of the string */ | ||
1299 | if(wrq->u.data.length > | ||
1300 | IW_ESSID_MAX_SIZE + 1) | ||
1301 | { | ||
1302 | err = -E2BIG; | ||
1303 | break; | ||
1304 | } | ||
1305 | if (copy_from_user(card_essid, | ||
1306 | wrq->u.data.pointer, | ||
1307 | wrq->u.data.length)) { | ||
1308 | err = -EFAULT; | ||
1309 | break; | ||
1310 | } | ||
1311 | card_essid[IW_ESSID_MAX_SIZE] = '\0'; | ||
1312 | |||
1313 | /* Set the ESSID in the card */ | ||
1314 | memcpy(local->sparm.b5.a_current_ess_id, card_essid, | ||
1315 | IW_ESSID_MAX_SIZE); | ||
1316 | } | ||
1317 | } | ||
1318 | break; | ||
1319 | |||
1320 | /* Get current Access Point (BSSID in our case) */ | ||
1321 | case SIOCGIWAP: | ||
1322 | memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN); | ||
1323 | wrq->u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1324 | break; | ||
1325 | |||
1326 | /* Get the current bit-rate */ | ||
1327 | case SIOCGIWRATE: | ||
1328 | if(local->net_default_tx_rate == 3) | ||
1329 | wrq->u.bitrate.value = 2000000; /* Hum... */ | ||
1330 | else | ||
1331 | wrq->u.bitrate.value = local->net_default_tx_rate * 500000; | ||
1332 | wrq->u.bitrate.fixed = 0; /* We are in auto mode */ | ||
1333 | break; | ||
1334 | |||
1335 | /* Set the desired bit-rate */ | ||
1336 | case SIOCSIWRATE: | ||
1337 | /* Check if rate is in range */ | ||
1338 | if((wrq->u.bitrate.value != 1000000) && | ||
1339 | (wrq->u.bitrate.value != 2000000)) | ||
1340 | { | ||
1341 | err = -EINVAL; | ||
1342 | break; | ||
1343 | } | ||
1344 | /* Hack for 1.5 Mb/s instead of 2 Mb/s */ | ||
1345 | if((local->fw_ver == 0x55) && /* Please check */ | ||
1346 | (wrq->u.bitrate.value == 2000000)) | ||
1347 | local->net_default_tx_rate = 3; | ||
1348 | else | ||
1349 | local->net_default_tx_rate = wrq->u.bitrate.value/500000; | ||
1350 | break; | ||
1351 | |||
1352 | /* Get the current RTS threshold */ | ||
1353 | case SIOCGIWRTS: | ||
1354 | wrq->u.rts.value = (local->sparm.b5.a_rts_threshold[0] << 8) | ||
1355 | + local->sparm.b5.a_rts_threshold[1]; | ||
1356 | #if WIRELESS_EXT > 8 | ||
1357 | wrq->u.rts.disabled = (wrq->u.rts.value == 32767); | ||
1358 | #endif /* WIRELESS_EXT > 8 */ | ||
1359 | wrq->u.rts.fixed = 1; | ||
1360 | break; | ||
1361 | |||
1362 | /* Set the desired RTS threshold */ | ||
1363 | case SIOCSIWRTS: | ||
1364 | { | ||
1365 | int rthr = wrq->u.rts.value; | ||
1366 | |||
1367 | /* Reject if card is already initialised */ | ||
1368 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1369 | { | ||
1370 | err = -EBUSY; | ||
1371 | break; | ||
1372 | } | ||
1373 | |||
1374 | /* if(wrq->u.rts.fixed == 0) we should complain */ | ||
1375 | #if WIRELESS_EXT > 8 | ||
1376 | if(wrq->u.rts.disabled) | ||
1377 | rthr = 32767; | ||
1378 | else | ||
1379 | #endif /* WIRELESS_EXT > 8 */ | ||
1380 | if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ | ||
1381 | { | ||
1382 | err = -EINVAL; | ||
1383 | break; | ||
1384 | } | ||
1385 | local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; | ||
1386 | local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; | ||
1387 | } | ||
1388 | break; | ||
1389 | |||
1390 | /* Get the current fragmentation threshold */ | ||
1391 | case SIOCGIWFRAG: | ||
1392 | wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) | ||
1393 | + local->sparm.b5.a_frag_threshold[1]; | ||
1394 | #if WIRELESS_EXT > 8 | ||
1395 | wrq->u.frag.disabled = (wrq->u.frag.value == 32767); | ||
1396 | #endif /* WIRELESS_EXT > 8 */ | ||
1397 | wrq->u.frag.fixed = 1; | ||
1398 | break; | ||
1399 | |||
1400 | /* Set the desired fragmentation threshold */ | ||
1401 | case SIOCSIWFRAG: | ||
1402 | { | ||
1403 | int fthr = wrq->u.frag.value; | ||
1404 | |||
1405 | /* Reject if card is already initialised */ | ||
1406 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1407 | { | ||
1408 | err = -EBUSY; | ||
1409 | break; | ||
1410 | } | ||
1411 | |||
1412 | /* if(wrq->u.frag.fixed == 0) should complain */ | ||
1413 | #if WIRELESS_EXT > 8 | ||
1414 | if(wrq->u.frag.disabled) | ||
1415 | fthr = 32767; | ||
1416 | else | ||
1417 | #endif /* WIRELESS_EXT > 8 */ | ||
1418 | if((fthr < 256) || (fthr > 2347)) /* To check out ! */ | ||
1419 | { | ||
1420 | err = -EINVAL; | ||
1421 | break; | ||
1422 | } | ||
1423 | local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; | ||
1424 | local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; | ||
1425 | } | ||
1426 | break; | ||
1427 | |||
1428 | #endif /* WIRELESS_EXT > 7 */ | ||
1429 | #if WIRELESS_EXT > 8 | ||
1430 | |||
1431 | /* Get the current mode of operation */ | ||
1432 | case SIOCGIWMODE: | ||
1433 | if(local->sparm.b5.a_network_type) | ||
1434 | wrq->u.mode = IW_MODE_INFRA; | ||
1435 | else | ||
1436 | wrq->u.mode = IW_MODE_ADHOC; | ||
1437 | break; | ||
1438 | |||
1439 | /* Set the current mode of operation */ | ||
1440 | case SIOCSIWMODE: | ||
1441 | { | ||
1442 | char card_mode = 1; | ||
1443 | |||
1444 | /* Reject if card is already initialised */ | ||
1445 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1446 | { | ||
1447 | err = -EBUSY; | ||
1448 | break; | ||
1449 | } | ||
1450 | |||
1451 | switch (wrq->u.mode) | ||
1452 | { | ||
1453 | case IW_MODE_ADHOC: | ||
1454 | card_mode = 0; | ||
1455 | // Fall through | ||
1456 | case IW_MODE_INFRA: | ||
1457 | local->sparm.b5.a_network_type = card_mode; | ||
1458 | break; | ||
1459 | default: | ||
1460 | err = -EINVAL; | ||
1461 | } | ||
1462 | } | ||
1463 | break; | ||
1464 | |||
1465 | #endif /* WIRELESS_EXT > 8 */ | ||
1466 | #if WIRELESS_EXT > 7 | ||
1467 | /* ------------------ IWSPY SUPPORT ------------------ */ | ||
1468 | /* Define the range (variations) of above parameters */ | ||
1469 | case SIOCGIWRANGE: | ||
1470 | /* Basic checking... */ | ||
1471 | if(wrq->u.data.pointer != (caddr_t) 0) | ||
1472 | { | ||
1473 | struct iw_range range; | ||
1474 | memset((char *) &range, 0, sizeof(struct iw_range)); | ||
1475 | |||
1476 | /* Set the length (very important for backward compatibility) */ | ||
1477 | wrq->u.data.length = sizeof(struct iw_range); | ||
1478 | |||
1479 | #if WIRELESS_EXT > 10 | ||
1480 | /* Set the Wireless Extension versions */ | ||
1481 | range.we_version_compiled = WIRELESS_EXT; | ||
1482 | range.we_version_source = 9; | ||
1483 | #endif /* WIRELESS_EXT > 10 */ | ||
1484 | |||
1485 | /* Set information in the range struct */ | ||
1486 | range.throughput = 1.1 * 1000 * 1000; /* Put the right number here */ | ||
1487 | range.num_channels = hop_pattern_length[(int)country]; | ||
1488 | range.num_frequency = 0; | ||
1489 | range.max_qual.qual = 0; | ||
1490 | range.max_qual.level = 255; /* What's the correct value ? */ | ||
1491 | range.max_qual.noise = 255; /* Idem */ | ||
1492 | range.num_bitrates = 2; | ||
1493 | range.bitrate[0] = 1000000; /* 1 Mb/s */ | ||
1494 | range.bitrate[1] = 2000000; /* 2 Mb/s */ | ||
1495 | |||
1496 | /* Copy structure to the user buffer */ | ||
1497 | if(copy_to_user(wrq->u.data.pointer, &range, | ||
1498 | sizeof(struct iw_range))) | ||
1499 | err = -EFAULT; | ||
1500 | } | ||
1501 | break; | ||
1502 | |||
1503 | #ifdef WIRELESS_SPY | ||
1504 | /* Set addresses to spy */ | ||
1505 | case SIOCSIWSPY: | ||
1506 | /* Check the number of addresses */ | ||
1507 | if(wrq->u.data.length > IW_MAX_SPY) | ||
1508 | { | ||
1509 | err = -E2BIG; | ||
1510 | break; | ||
1511 | } | ||
1512 | local->spy_number = wrq->u.data.length; | ||
1513 | |||
1514 | /* If there is some addresses to copy */ | ||
1515 | if(local->spy_number > 0) | ||
1516 | { | ||
1517 | int i; | ||
1518 | |||
1519 | /* Copy addresses to the driver */ | ||
1520 | if(copy_from_user(address, wrq->u.data.pointer, | ||
1521 | sizeof(struct sockaddr) * local->spy_number)) | ||
1522 | { | ||
1523 | err = -EFAULT; | ||
1524 | break; | ||
1525 | } | ||
1526 | |||
1527 | /* Copy addresses to the lp structure */ | ||
1528 | for(i = 0; i < local->spy_number; i++) | ||
1529 | memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN); | ||
1530 | |||
1531 | /* Reset structure... */ | ||
1532 | memset(local->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); | ||
1533 | |||
1534 | #ifdef DEBUG_IOCTL_INFO | ||
1535 | printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); | ||
1536 | for(i = 0; i < local->spy_number; i++) | ||
1537 | printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1538 | local->spy_address[i][0], | ||
1539 | local->spy_address[i][1], | ||
1540 | local->spy_address[i][2], | ||
1541 | local->spy_address[i][3], | ||
1542 | local->spy_address[i][4], | ||
1543 | local->spy_address[i][5]); | ||
1544 | #endif /* DEBUG_IOCTL_INFO */ | ||
1545 | } | ||
1546 | break; | ||
1547 | |||
1548 | /* Get the spy list and spy stats */ | ||
1549 | case SIOCGIWSPY: | ||
1550 | /* Set the number of addresses */ | ||
1551 | wrq->u.data.length = local->spy_number; | ||
1552 | |||
1553 | /* If the user want to have the addresses back... */ | ||
1554 | if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) | ||
1555 | { | ||
1556 | int i; | ||
1557 | |||
1558 | /* Copy addresses from the lp structure */ | ||
1559 | for(i = 0; i < local->spy_number; i++) | ||
1560 | { | ||
1561 | memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN); | ||
1562 | address[i].sa_family = ARPHRD_ETHER; | ||
1563 | } | ||
1564 | |||
1565 | /* Copy addresses to the user buffer */ | ||
1566 | if(copy_to_user(wrq->u.data.pointer, address, | ||
1567 | sizeof(struct sockaddr) * local->spy_number)) | ||
1568 | { | ||
1569 | err = -EFAULT; | ||
1570 | break; | ||
1571 | } | ||
1572 | |||
1573 | /* Copy stats to the user buffer (just after) */ | ||
1574 | if(copy_to_user(wrq->u.data.pointer + | ||
1575 | (sizeof(struct sockaddr) * local->spy_number), | ||
1576 | local->spy_stat, sizeof(iw_qual) * local->spy_number)) | ||
1577 | { | ||
1578 | err = -EFAULT; | ||
1579 | break; | ||
1580 | } | ||
1581 | |||
1582 | /* Reset updated flags */ | ||
1583 | for(i = 0; i < local->spy_number; i++) | ||
1584 | local->spy_stat[i].updated = 0x0; | ||
1585 | } /* if(pointer != NULL) */ | ||
1586 | |||
1587 | break; | ||
1588 | #endif /* WIRELESS_SPY */ | ||
1589 | |||
1590 | /* ------------------ PRIVATE IOCTL ------------------ */ | ||
1591 | #ifndef SIOCIWFIRSTPRIV | ||
1592 | #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE | ||
1593 | #endif /* SIOCIWFIRSTPRIV */ | ||
1594 | #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ | ||
1595 | #define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */ | ||
1596 | #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ | ||
1597 | case SIOCSIPFRAMING: | ||
1598 | if(!capable(CAP_NET_ADMIN)) /* For private IOCTLs, we need to check permissions */ | ||
1599 | { | ||
1600 | err = -EPERM; | ||
1601 | break; | ||
1602 | } | ||
1603 | translate = *(wrq->u.name); /* Set framing mode */ | ||
1604 | break; | ||
1605 | case SIOCGIPFRAMING: | ||
1606 | *(wrq->u.name) = translate; | ||
1607 | break; | ||
1608 | case SIOCGIPCOUNTRY: | ||
1609 | *(wrq->u.name) = country; | ||
1610 | break; | ||
1611 | case SIOCGIWPRIV: | ||
1612 | /* Export our "private" intercace */ | ||
1613 | if(wrq->u.data.pointer != (caddr_t) 0) | ||
1614 | { | ||
1615 | struct iw_priv_args priv[] = | ||
1616 | { /* cmd, set_args, get_args, name */ | ||
1617 | { SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" }, | ||
1618 | { SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" }, | ||
1619 | { SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" }, | ||
1620 | }; | ||
1621 | /* Set the number of ioctl available */ | ||
1622 | wrq->u.data.length = 3; | ||
1623 | /* Copy structure to the user buffer */ | ||
1624 | if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, | ||
1625 | sizeof(priv))) | ||
1626 | err = -EFAULT; | ||
1627 | } | ||
1628 | break; | ||
1629 | #endif /* WIRELESS_EXT > 7 */ | ||
1630 | |||
1631 | |||
1632 | default: | ||
1633 | DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd); | ||
1634 | err = -EOPNOTSUPP; | ||
1635 | } | ||
1636 | return err; | ||
1637 | } /* end ray_dev_ioctl */ | ||
1638 | /*===========================================================================*/ | ||
1639 | #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ | ||
1640 | static iw_stats * ray_get_wireless_stats(struct net_device * dev) | ||
1641 | { | ||
1642 | ray_dev_t * local = (ray_dev_t *) dev->priv; | ||
1643 | dev_link_t *link = local->finder; | ||
1644 | struct status __iomem *p = local->sram + STATUS_BASE; | ||
1645 | |||
1646 | if(local == (ray_dev_t *) NULL) | ||
1647 | return (iw_stats *) NULL; | ||
1648 | |||
1649 | local->wstats.status = local->card_status; | ||
1650 | #ifdef WIRELESS_SPY | ||
1651 | if((local->spy_number > 0) && (local->sparm.b5.a_network_type == 0)) | ||
1652 | { | ||
1653 | /* Get it from the first node in spy list */ | ||
1654 | local->wstats.qual.qual = local->spy_stat[0].qual; | ||
1655 | local->wstats.qual.level = local->spy_stat[0].level; | ||
1656 | local->wstats.qual.noise = local->spy_stat[0].noise; | ||
1657 | local->wstats.qual.updated = local->spy_stat[0].updated; | ||
1658 | } | ||
1659 | #endif /* WIRELESS_SPY */ | ||
1660 | |||
1661 | if((link->state & DEV_PRESENT)) { | ||
1662 | local->wstats.qual.noise = readb(&p->rxnoise); | ||
1663 | local->wstats.qual.updated |= 4; | ||
1664 | } | ||
1665 | |||
1666 | return &local->wstats; | ||
1667 | } /* end ray_get_wireless_stats */ | ||
1668 | #endif /* WIRELESS_EXT > 7 */ | ||
1669 | /*===========================================================================*/ | ||
1670 | static int ray_open(struct net_device *dev) | ||
1671 | { | ||
1672 | dev_link_t *link; | ||
1673 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1674 | |||
1675 | DEBUG(1, "ray_open('%s')\n", dev->name); | ||
1676 | |||
1677 | for (link = dev_list; link; link = link->next) | ||
1678 | if (link->priv == dev) break; | ||
1679 | if (!DEV_OK(link)) { | ||
1680 | return -ENODEV; | ||
1681 | } | ||
1682 | |||
1683 | if (link->open == 0) local->num_multi = 0; | ||
1684 | link->open++; | ||
1685 | |||
1686 | /* If the card is not started, time to start it ! - Jean II */ | ||
1687 | if(local->card_status == CARD_AWAITING_PARAM) { | ||
1688 | int i; | ||
1689 | |||
1690 | DEBUG(1,"ray_open: doing init now !\n"); | ||
1691 | |||
1692 | /* Download startup parameters */ | ||
1693 | if ( (i = dl_startup_params(dev)) < 0) | ||
1694 | { | ||
1695 | printk(KERN_INFO "ray_dev_init dl_startup_params failed - " | ||
1696 | "returns 0x%x\n",i); | ||
1697 | return -1; | ||
1698 | } | ||
1699 | } | ||
1700 | |||
1701 | if (sniffer) netif_stop_queue(dev); | ||
1702 | else netif_start_queue(dev); | ||
1703 | |||
1704 | DEBUG(2,"ray_open ending\n"); | ||
1705 | return 0; | ||
1706 | } /* end ray_open */ | ||
1707 | /*===========================================================================*/ | ||
1708 | static int ray_dev_close(struct net_device *dev) | ||
1709 | { | ||
1710 | dev_link_t *link; | ||
1711 | |||
1712 | DEBUG(1, "ray_dev_close('%s')\n", dev->name); | ||
1713 | |||
1714 | for (link = dev_list; link; link = link->next) | ||
1715 | if (link->priv == dev) break; | ||
1716 | if (link == NULL) | ||
1717 | return -ENODEV; | ||
1718 | |||
1719 | link->open--; | ||
1720 | netif_stop_queue(dev); | ||
1721 | |||
1722 | /* In here, we should stop the hardware (stop card from beeing active) | ||
1723 | * and set local->card_status to CARD_AWAITING_PARAM, so that while the | ||
1724 | * card is closed we can chage its configuration. | ||
1725 | * Probably also need a COR reset to get sane state - Jean II */ | ||
1726 | |||
1727 | return 0; | ||
1728 | } /* end ray_dev_close */ | ||
1729 | /*===========================================================================*/ | ||
1730 | static void ray_reset(struct net_device *dev) { | ||
1731 | DEBUG(1,"ray_reset entered\n"); | ||
1732 | return; | ||
1733 | } | ||
1734 | /*===========================================================================*/ | ||
1735 | /* Cause a firmware interrupt if it is ready for one */ | ||
1736 | /* Return nonzero if not ready */ | ||
1737 | static int interrupt_ecf(ray_dev_t *local, int ccs) | ||
1738 | { | ||
1739 | int i = 50; | ||
1740 | dev_link_t *link = local->finder; | ||
1741 | |||
1742 | if (!(link->state & DEV_PRESENT)) { | ||
1743 | DEBUG(2,"ray_cs interrupt_ecf - device not present\n"); | ||
1744 | return -1; | ||
1745 | } | ||
1746 | DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs); | ||
1747 | |||
1748 | while ( i && | ||
1749 | (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET)) | ||
1750 | i--; | ||
1751 | if (i == 0) { | ||
1752 | DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n"); | ||
1753 | return -1; | ||
1754 | } | ||
1755 | /* Fill the mailbox, then kick the card */ | ||
1756 | writeb(ccs, local->sram + SCB_BASE); | ||
1757 | writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); | ||
1758 | return 0; | ||
1759 | } /* interrupt_ecf */ | ||
1760 | /*===========================================================================*/ | ||
1761 | /* Get next free transmit CCS */ | ||
1762 | /* Return - index of current tx ccs */ | ||
1763 | static int get_free_tx_ccs(ray_dev_t *local) | ||
1764 | { | ||
1765 | int i; | ||
1766 | struct ccs __iomem *pccs = ccs_base(local); | ||
1767 | dev_link_t *link = local->finder; | ||
1768 | |||
1769 | if (!(link->state & DEV_PRESENT)) { | ||
1770 | DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n"); | ||
1771 | return ECARDGONE; | ||
1772 | } | ||
1773 | |||
1774 | if (test_and_set_bit(0,&local->tx_ccs_lock)) { | ||
1775 | DEBUG(1,"ray_cs tx_ccs_lock busy\n"); | ||
1776 | return ECCSBUSY; | ||
1777 | } | ||
1778 | |||
1779 | for (i=0; i < NUMBER_OF_TX_CCS; i++) { | ||
1780 | if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { | ||
1781 | writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); | ||
1782 | writeb(CCS_END_LIST, &(pccs+i)->link); | ||
1783 | local->tx_ccs_lock = 0; | ||
1784 | return i; | ||
1785 | } | ||
1786 | } | ||
1787 | local->tx_ccs_lock = 0; | ||
1788 | DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n"); | ||
1789 | return ECCSFULL; | ||
1790 | } /* get_free_tx_ccs */ | ||
1791 | /*===========================================================================*/ | ||
1792 | /* Get next free CCS */ | ||
1793 | /* Return - index of current ccs */ | ||
1794 | static int get_free_ccs(ray_dev_t *local) | ||
1795 | { | ||
1796 | int i; | ||
1797 | struct ccs __iomem *pccs = ccs_base(local); | ||
1798 | dev_link_t *link = local->finder; | ||
1799 | |||
1800 | if (!(link->state & DEV_PRESENT)) { | ||
1801 | DEBUG(2,"ray_cs get_free_ccs - device not present\n"); | ||
1802 | return ECARDGONE; | ||
1803 | } | ||
1804 | if (test_and_set_bit(0,&local->ccs_lock)) { | ||
1805 | DEBUG(1,"ray_cs ccs_lock busy\n"); | ||
1806 | return ECCSBUSY; | ||
1807 | } | ||
1808 | |||
1809 | for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { | ||
1810 | if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { | ||
1811 | writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); | ||
1812 | writeb(CCS_END_LIST, &(pccs+i)->link); | ||
1813 | local->ccs_lock = 0; | ||
1814 | return i; | ||
1815 | } | ||
1816 | } | ||
1817 | local->ccs_lock = 0; | ||
1818 | DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n"); | ||
1819 | return ECCSFULL; | ||
1820 | } /* get_free_ccs */ | ||
1821 | /*===========================================================================*/ | ||
1822 | static void authenticate_timeout(u_long data) | ||
1823 | { | ||
1824 | ray_dev_t *local = (ray_dev_t *)data; | ||
1825 | del_timer(&local->timer); | ||
1826 | printk(KERN_INFO "ray_cs Authentication with access point failed" | ||
1827 | " - timeout\n"); | ||
1828 | join_net((u_long)local); | ||
1829 | } | ||
1830 | /*===========================================================================*/ | ||
1831 | static int asc_to_int(char a) | ||
1832 | { | ||
1833 | if (a < '0') return -1; | ||
1834 | if (a <= '9') return (a - '0'); | ||
1835 | if (a < 'A') return -1; | ||
1836 | if (a <= 'F') return (10 + a - 'A'); | ||
1837 | if (a < 'a') return -1; | ||
1838 | if (a <= 'f') return (10 + a - 'a'); | ||
1839 | return -1; | ||
1840 | } | ||
1841 | /*===========================================================================*/ | ||
1842 | static int parse_addr(char *in_str, UCHAR *out) | ||
1843 | { | ||
1844 | int len; | ||
1845 | int i,j,k; | ||
1846 | int status; | ||
1847 | |||
1848 | if (in_str == NULL) return 0; | ||
1849 | if ((len = strlen(in_str)) < 2) return 0; | ||
1850 | memset(out, 0, ADDRLEN); | ||
1851 | |||
1852 | status = 1; | ||
1853 | j = len - 1; | ||
1854 | if (j > 12) j = 12; | ||
1855 | i = 5; | ||
1856 | |||
1857 | while (j > 0) | ||
1858 | { | ||
1859 | if ((k = asc_to_int(in_str[j--])) != -1) out[i] = k; | ||
1860 | else return 0; | ||
1861 | |||
1862 | if (j == 0) break; | ||
1863 | if ((k = asc_to_int(in_str[j--])) != -1) out[i] += k << 4; | ||
1864 | else return 0; | ||
1865 | if (!i--) break; | ||
1866 | } | ||
1867 | return status; | ||
1868 | } | ||
1869 | /*===========================================================================*/ | ||
1870 | static struct net_device_stats *ray_get_stats(struct net_device *dev) | ||
1871 | { | ||
1872 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1873 | dev_link_t *link = local->finder; | ||
1874 | struct status __iomem *p = local->sram + STATUS_BASE; | ||
1875 | if (!(link->state & DEV_PRESENT)) { | ||
1876 | DEBUG(2,"ray_cs net_device_stats - device not present\n"); | ||
1877 | return &local->stats; | ||
1878 | } | ||
1879 | if (readb(&p->mrx_overflow_for_host)) | ||
1880 | { | ||
1881 | local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow)); | ||
1882 | writeb(0,&p->mrx_overflow); | ||
1883 | writeb(0,&p->mrx_overflow_for_host); | ||
1884 | } | ||
1885 | if (readb(&p->mrx_checksum_error_for_host)) | ||
1886 | { | ||
1887 | local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error)); | ||
1888 | writeb(0,&p->mrx_checksum_error); | ||
1889 | writeb(0,&p->mrx_checksum_error_for_host); | ||
1890 | } | ||
1891 | if (readb(&p->rx_hec_error_for_host)) | ||
1892 | { | ||
1893 | local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error)); | ||
1894 | writeb(0,&p->rx_hec_error); | ||
1895 | writeb(0,&p->rx_hec_error_for_host); | ||
1896 | } | ||
1897 | return &local->stats; | ||
1898 | } | ||
1899 | /*===========================================================================*/ | ||
1900 | static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) | ||
1901 | { | ||
1902 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1903 | dev_link_t *link = local->finder; | ||
1904 | int ccsindex; | ||
1905 | int i; | ||
1906 | struct ccs __iomem *pccs; | ||
1907 | |||
1908 | if (!(link->state & DEV_PRESENT)) { | ||
1909 | DEBUG(2,"ray_update_parm - device not present\n"); | ||
1910 | return; | ||
1911 | } | ||
1912 | |||
1913 | if ((ccsindex = get_free_ccs(local)) < 0) | ||
1914 | { | ||
1915 | DEBUG(0,"ray_update_parm - No free ccs\n"); | ||
1916 | return; | ||
1917 | } | ||
1918 | pccs = ccs_base(local) + ccsindex; | ||
1919 | writeb(CCS_UPDATE_PARAMS, &pccs->cmd); | ||
1920 | writeb(objid, &pccs->var.update_param.object_id); | ||
1921 | writeb(1, &pccs->var.update_param.number_objects); | ||
1922 | writeb(0, &pccs->var.update_param.failure_cause); | ||
1923 | for (i=0; i<len; i++) { | ||
1924 | writeb(value[i], local->sram + HOST_TO_ECF_BASE); | ||
1925 | } | ||
1926 | /* Interrupt the firmware to process the command */ | ||
1927 | if (interrupt_ecf(local, ccsindex)) { | ||
1928 | DEBUG(0,"ray_cs associate failed - ECF not ready for intr\n"); | ||
1929 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
1930 | } | ||
1931 | } | ||
1932 | /*===========================================================================*/ | ||
1933 | static void ray_update_multi_list(struct net_device *dev, int all) | ||
1934 | { | ||
1935 | struct dev_mc_list *dmi, **dmip; | ||
1936 | int ccsindex; | ||
1937 | struct ccs __iomem *pccs; | ||
1938 | int i = 0; | ||
1939 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1940 | dev_link_t *link = local->finder; | ||
1941 | void __iomem *p = local->sram + HOST_TO_ECF_BASE; | ||
1942 | |||
1943 | if (!(link->state & DEV_PRESENT)) { | ||
1944 | DEBUG(2,"ray_update_multi_list - device not present\n"); | ||
1945 | return; | ||
1946 | } | ||
1947 | else | ||
1948 | DEBUG(2,"ray_update_multi_list(%p)\n",dev); | ||
1949 | if ((ccsindex = get_free_ccs(local)) < 0) | ||
1950 | { | ||
1951 | DEBUG(1,"ray_update_multi - No free ccs\n"); | ||
1952 | return; | ||
1953 | } | ||
1954 | pccs = ccs_base(local) + ccsindex; | ||
1955 | writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); | ||
1956 | |||
1957 | if (all) { | ||
1958 | writeb(0xff, &pccs->var); | ||
1959 | local->num_multi = 0xff; | ||
1960 | } | ||
1961 | else { | ||
1962 | /* Copy the kernel's list of MC addresses to card */ | ||
1963 | for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) { | ||
1964 | memcpy_toio(p, dmi->dmi_addr, ETH_ALEN); | ||
1965 | DEBUG(1,"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]); | ||
1966 | p += ETH_ALEN; | ||
1967 | i++; | ||
1968 | } | ||
1969 | if (i > 256/ADDRLEN) i = 256/ADDRLEN; | ||
1970 | writeb((UCHAR)i, &pccs->var); | ||
1971 | DEBUG(1,"ray_cs update_multi %d addresses in list\n", i); | ||
1972 | /* Interrupt the firmware to process the command */ | ||
1973 | local->num_multi = i; | ||
1974 | } | ||
1975 | if (interrupt_ecf(local, ccsindex)) { | ||
1976 | DEBUG(1,"ray_cs update_multi failed - ECF not ready for intr\n"); | ||
1977 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
1978 | } | ||
1979 | } /* end ray_update_multi_list */ | ||
1980 | /*===========================================================================*/ | ||
1981 | static void set_multicast_list(struct net_device *dev) | ||
1982 | { | ||
1983 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1984 | UCHAR promisc; | ||
1985 | |||
1986 | DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev); | ||
1987 | |||
1988 | if (dev->flags & IFF_PROMISC) | ||
1989 | { | ||
1990 | if (local->sparm.b5.a_promiscuous_mode == 0) { | ||
1991 | DEBUG(1,"ray_cs set_multicast_list promisc on\n"); | ||
1992 | local->sparm.b5.a_promiscuous_mode = 1; | ||
1993 | promisc = 1; | ||
1994 | ray_update_parm(dev, OBJID_promiscuous_mode, \ | ||
1995 | &promisc, sizeof(promisc)); | ||
1996 | } | ||
1997 | } | ||
1998 | else { | ||
1999 | if (local->sparm.b5.a_promiscuous_mode == 1) { | ||
2000 | DEBUG(1,"ray_cs set_multicast_list promisc off\n"); | ||
2001 | local->sparm.b5.a_promiscuous_mode = 0; | ||
2002 | promisc = 0; | ||
2003 | ray_update_parm(dev, OBJID_promiscuous_mode, \ | ||
2004 | &promisc, sizeof(promisc)); | ||
2005 | } | ||
2006 | } | ||
2007 | |||
2008 | if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1); | ||
2009 | else | ||
2010 | { | ||
2011 | if (local->num_multi != dev->mc_count) ray_update_multi_list(dev, 0); | ||
2012 | } | ||
2013 | } /* end set_multicast_list */ | ||
2014 | /*============================================================================= | ||
2015 | * All routines below here are run at interrupt time. | ||
2016 | =============================================================================*/ | ||
2017 | static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
2018 | { | ||
2019 | struct net_device *dev = (struct net_device *)dev_id; | ||
2020 | dev_link_t *link; | ||
2021 | ray_dev_t *local; | ||
2022 | struct ccs __iomem *pccs; | ||
2023 | struct rcs __iomem *prcs; | ||
2024 | UCHAR rcsindex; | ||
2025 | UCHAR tmp; | ||
2026 | UCHAR cmd; | ||
2027 | UCHAR status; | ||
2028 | |||
2029 | if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ | ||
2030 | return IRQ_NONE; | ||
2031 | |||
2032 | DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); | ||
2033 | |||
2034 | local = (ray_dev_t *)dev->priv; | ||
2035 | link = (dev_link_t *)local->finder; | ||
2036 | if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { | ||
2037 | DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); | ||
2038 | return IRQ_NONE; | ||
2039 | } | ||
2040 | rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); | ||
2041 | |||
2042 | if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) | ||
2043 | { | ||
2044 | DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); | ||
2045 | clear_interrupt(local); | ||
2046 | return IRQ_HANDLED; | ||
2047 | } | ||
2048 | if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */ | ||
2049 | { | ||
2050 | pccs = ccs_base(local) + rcsindex; | ||
2051 | cmd = readb(&pccs->cmd); | ||
2052 | status = readb(&pccs->buffer_status); | ||
2053 | switch (cmd) | ||
2054 | { | ||
2055 | case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ | ||
2056 | del_timer(&local->timer); | ||
2057 | if (status == CCS_COMMAND_COMPLETE) { | ||
2058 | DEBUG(1,"ray_cs interrupt download_startup_parameters OK\n"); | ||
2059 | } | ||
2060 | else { | ||
2061 | DEBUG(1,"ray_cs interrupt download_startup_parameters fail\n"); | ||
2062 | } | ||
2063 | break; | ||
2064 | case CCS_UPDATE_PARAMS: | ||
2065 | DEBUG(1,"ray_cs interrupt update params done\n"); | ||
2066 | if (status != CCS_COMMAND_COMPLETE) { | ||
2067 | tmp = readb(&pccs->var.update_param.failure_cause); | ||
2068 | DEBUG(0,"ray_cs interrupt update params failed - reason %d\n",tmp); | ||
2069 | } | ||
2070 | break; | ||
2071 | case CCS_REPORT_PARAMS: | ||
2072 | DEBUG(1,"ray_cs interrupt report params done\n"); | ||
2073 | break; | ||
2074 | case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ | ||
2075 | DEBUG(1,"ray_cs interrupt CCS Update Multicast List done\n"); | ||
2076 | break; | ||
2077 | case CCS_UPDATE_POWER_SAVINGS_MODE: | ||
2078 | DEBUG(1,"ray_cs interrupt update power save mode done\n"); | ||
2079 | break; | ||
2080 | case CCS_START_NETWORK: | ||
2081 | case CCS_JOIN_NETWORK: | ||
2082 | if (status == CCS_COMMAND_COMPLETE) { | ||
2083 | if (readb(&pccs->var.start_network.net_initiated) == 1) { | ||
2084 | DEBUG(0,"ray_cs interrupt network \"%s\" started\n",\ | ||
2085 | local->sparm.b4.a_current_ess_id); | ||
2086 | } | ||
2087 | else { | ||
2088 | DEBUG(0,"ray_cs interrupt network \"%s\" joined\n",\ | ||
2089 | local->sparm.b4.a_current_ess_id); | ||
2090 | } | ||
2091 | memcpy_fromio(&local->bss_id,pccs->var.start_network.bssid,ADDRLEN); | ||
2092 | |||
2093 | if (local->fw_ver == 0x55) local->net_default_tx_rate = 3; | ||
2094 | else local->net_default_tx_rate = | ||
2095 | readb(&pccs->var.start_network.net_default_tx_rate); | ||
2096 | local->encryption = readb(&pccs->var.start_network.encryption); | ||
2097 | if (!sniffer && (local->net_type == INFRA) | ||
2098 | && !(local->sparm.b4.a_acting_as_ap_status)) { | ||
2099 | authenticate(local); | ||
2100 | } | ||
2101 | local->card_status = CARD_ACQ_COMPLETE; | ||
2102 | } | ||
2103 | else { | ||
2104 | local->card_status = CARD_ACQ_FAILED; | ||
2105 | |||
2106 | del_timer(&local->timer); | ||
2107 | local->timer.expires = jiffies + HZ*5; | ||
2108 | local->timer.data = (long)local; | ||
2109 | if (status == CCS_START_NETWORK) { | ||
2110 | DEBUG(0,"ray_cs interrupt network \"%s\" start failed\n",\ | ||
2111 | local->sparm.b4.a_current_ess_id); | ||
2112 | local->timer.function = &start_net; | ||
2113 | } | ||
2114 | else { | ||
2115 | DEBUG(0,"ray_cs interrupt network \"%s\" join failed\n",\ | ||
2116 | local->sparm.b4.a_current_ess_id); | ||
2117 | local->timer.function = &join_net; | ||
2118 | } | ||
2119 | add_timer(&local->timer); | ||
2120 | } | ||
2121 | break; | ||
2122 | case CCS_START_ASSOCIATION: | ||
2123 | if (status == CCS_COMMAND_COMPLETE) { | ||
2124 | local->card_status = CARD_ASSOC_COMPLETE; | ||
2125 | DEBUG(0,"ray_cs association successful\n"); | ||
2126 | } | ||
2127 | else | ||
2128 | { | ||
2129 | DEBUG(0,"ray_cs association failed,\n"); | ||
2130 | local->card_status = CARD_ASSOC_FAILED; | ||
2131 | join_net((u_long)local); | ||
2132 | } | ||
2133 | break; | ||
2134 | case CCS_TX_REQUEST: | ||
2135 | if (status == CCS_COMMAND_COMPLETE) { | ||
2136 | DEBUG(3,"ray_cs interrupt tx request complete\n"); | ||
2137 | } | ||
2138 | else { | ||
2139 | DEBUG(1,"ray_cs interrupt tx request failed\n"); | ||
2140 | } | ||
2141 | if (!sniffer) netif_start_queue(dev); | ||
2142 | netif_wake_queue(dev); | ||
2143 | break; | ||
2144 | case CCS_TEST_MEMORY: | ||
2145 | DEBUG(1,"ray_cs interrupt mem test done\n"); | ||
2146 | break; | ||
2147 | case CCS_SHUTDOWN: | ||
2148 | DEBUG(1,"ray_cs interrupt Unexpected CCS returned - Shutdown\n"); | ||
2149 | break; | ||
2150 | case CCS_DUMP_MEMORY: | ||
2151 | DEBUG(1,"ray_cs interrupt dump memory done\n"); | ||
2152 | break; | ||
2153 | case CCS_START_TIMER: | ||
2154 | DEBUG(2,"ray_cs interrupt DING - raylink timer expired\n"); | ||
2155 | break; | ||
2156 | default: | ||
2157 | DEBUG(1,"ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",\ | ||
2158 | rcsindex, cmd); | ||
2159 | } | ||
2160 | writeb(CCS_BUFFER_FREE, &pccs->buffer_status); | ||
2161 | } | ||
2162 | else /* It's an RCS */ | ||
2163 | { | ||
2164 | prcs = rcs_base(local) + rcsindex; | ||
2165 | |||
2166 | switch (readb(&prcs->interrupt_id)) | ||
2167 | { | ||
2168 | case PROCESS_RX_PACKET: | ||
2169 | ray_rx(dev, local, prcs); | ||
2170 | break; | ||
2171 | case REJOIN_NET_COMPLETE: | ||
2172 | DEBUG(1,"ray_cs interrupt rejoin net complete\n"); | ||
2173 | local->card_status = CARD_ACQ_COMPLETE; | ||
2174 | /* do we need to clear tx buffers CCS's? */ | ||
2175 | if (local->sparm.b4.a_network_type == ADHOC) { | ||
2176 | if (!sniffer) netif_start_queue(dev); | ||
2177 | } | ||
2178 | else { | ||
2179 | memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN); | ||
2180 | DEBUG(1,"ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",\ | ||
2181 | local->bss_id[0], local->bss_id[1], local->bss_id[2],\ | ||
2182 | local->bss_id[3], local->bss_id[4], local->bss_id[5]); | ||
2183 | if (!sniffer) authenticate(local); | ||
2184 | } | ||
2185 | break; | ||
2186 | case ROAMING_INITIATED: | ||
2187 | DEBUG(1,"ray_cs interrupt roaming initiated\n"); | ||
2188 | netif_stop_queue(dev); | ||
2189 | local->card_status = CARD_DOING_ACQ; | ||
2190 | break; | ||
2191 | case JAPAN_CALL_SIGN_RXD: | ||
2192 | DEBUG(1,"ray_cs interrupt japan call sign rx\n"); | ||
2193 | break; | ||
2194 | default: | ||
2195 | DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\ | ||
2196 | rcsindex, (unsigned int) readb(&prcs->interrupt_id)); | ||
2197 | break; | ||
2198 | } | ||
2199 | writeb(CCS_BUFFER_FREE, &prcs->buffer_status); | ||
2200 | } | ||
2201 | clear_interrupt(local); | ||
2202 | return IRQ_HANDLED; | ||
2203 | } /* ray_interrupt */ | ||
2204 | /*===========================================================================*/ | ||
2205 | static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs) | ||
2206 | { | ||
2207 | int rx_len; | ||
2208 | unsigned int pkt_addr; | ||
2209 | void __iomem *pmsg; | ||
2210 | DEBUG(4,"ray_rx process rx packet\n"); | ||
2211 | |||
2212 | /* Calculate address of packet within Rx buffer */ | ||
2213 | pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) | ||
2214 | + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END; | ||
2215 | /* Length of first packet fragment */ | ||
2216 | rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8) | ||
2217 | + readb(&prcs->var.rx_packet.rx_data_length[1]); | ||
2218 | |||
2219 | local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev); | ||
2220 | pmsg = local->rmem + pkt_addr; | ||
2221 | switch(readb(pmsg)) | ||
2222 | { | ||
2223 | case DATA_TYPE: | ||
2224 | DEBUG(4,"ray_rx data type\n"); | ||
2225 | rx_data(dev, prcs, pkt_addr, rx_len); | ||
2226 | break; | ||
2227 | case AUTHENTIC_TYPE: | ||
2228 | DEBUG(4,"ray_rx authentic type\n"); | ||
2229 | if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); | ||
2230 | else rx_authenticate(local, prcs, pkt_addr, rx_len); | ||
2231 | break; | ||
2232 | case DEAUTHENTIC_TYPE: | ||
2233 | DEBUG(4,"ray_rx deauth type\n"); | ||
2234 | if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); | ||
2235 | else rx_deauthenticate(local, prcs, pkt_addr, rx_len); | ||
2236 | break; | ||
2237 | case NULL_MSG_TYPE: | ||
2238 | DEBUG(3,"ray_cs rx NULL msg\n"); | ||
2239 | break; | ||
2240 | case BEACON_TYPE: | ||
2241 | DEBUG(4,"ray_rx beacon type\n"); | ||
2242 | if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); | ||
2243 | |||
2244 | copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, | ||
2245 | rx_len < sizeof(struct beacon_rx) ? | ||
2246 | rx_len : sizeof(struct beacon_rx)); | ||
2247 | |||
2248 | local->beacon_rxed = 1; | ||
2249 | /* Get the statistics so the card counters never overflow */ | ||
2250 | ray_get_stats(dev); | ||
2251 | break; | ||
2252 | default: | ||
2253 | DEBUG(0,"ray_cs unknown pkt type %2x\n", (unsigned int) readb(pmsg)); | ||
2254 | break; | ||
2255 | } | ||
2256 | |||
2257 | } /* end ray_rx */ | ||
2258 | /*===========================================================================*/ | ||
2259 | static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, | ||
2260 | int rx_len) | ||
2261 | { | ||
2262 | struct sk_buff *skb = NULL; | ||
2263 | struct rcs __iomem *prcslink = prcs; | ||
2264 | ray_dev_t *local = dev->priv; | ||
2265 | UCHAR *rx_ptr; | ||
2266 | int total_len; | ||
2267 | int tmp; | ||
2268 | #ifdef WIRELESS_SPY | ||
2269 | int siglev = local->last_rsl; | ||
2270 | u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */ | ||
2271 | #endif | ||
2272 | |||
2273 | if (!sniffer) { | ||
2274 | if (translate) { | ||
2275 | /* TBD length needs fixing for translated header */ | ||
2276 | if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || | ||
2277 | rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) | ||
2278 | { | ||
2279 | DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len); | ||
2280 | return; | ||
2281 | } | ||
2282 | } | ||
2283 | else /* encapsulated ethernet */ { | ||
2284 | if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || | ||
2285 | rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) | ||
2286 | { | ||
2287 | DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len); | ||
2288 | return; | ||
2289 | } | ||
2290 | } | ||
2291 | } | ||
2292 | DEBUG(4,"ray_cs rx_data packet\n"); | ||
2293 | /* If fragmented packet, verify sizes of fragments add up */ | ||
2294 | if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { | ||
2295 | DEBUG(1,"ray_cs rx'ed fragment\n"); | ||
2296 | tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) | ||
2297 | + readb(&prcs->var.rx_packet.totalpacketlength[1]); | ||
2298 | total_len = tmp; | ||
2299 | prcslink = prcs; | ||
2300 | do { | ||
2301 | tmp -= (readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) | ||
2302 | + readb(&prcslink->var.rx_packet.rx_data_length[1]); | ||
2303 | if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF | ||
2304 | || tmp < 0) break; | ||
2305 | prcslink = rcs_base(local) | ||
2306 | + readb(&prcslink->link_field); | ||
2307 | } while (1); | ||
2308 | |||
2309 | if (tmp < 0) | ||
2310 | { | ||
2311 | DEBUG(0,"ray_cs rx_data fragment lengths don't add up\n"); | ||
2312 | local->stats.rx_dropped++; | ||
2313 | release_frag_chain(local, prcs); | ||
2314 | return; | ||
2315 | } | ||
2316 | } | ||
2317 | else { /* Single unfragmented packet */ | ||
2318 | total_len = rx_len; | ||
2319 | } | ||
2320 | |||
2321 | skb = dev_alloc_skb( total_len+5 ); | ||
2322 | if (skb == NULL) | ||
2323 | { | ||
2324 | DEBUG(0,"ray_cs rx_data could not allocate skb\n"); | ||
2325 | local->stats.rx_dropped++; | ||
2326 | if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) | ||
2327 | release_frag_chain(local, prcs); | ||
2328 | return; | ||
2329 | } | ||
2330 | skb_reserve( skb, 2); /* Align IP on 16 byte (TBD check this)*/ | ||
2331 | skb->dev = dev; | ||
2332 | |||
2333 | DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len); | ||
2334 | |||
2335 | /************************/ | ||
2336 | /* Reserve enough room for the whole damn packet. */ | ||
2337 | rx_ptr = skb_put( skb, total_len); | ||
2338 | /* Copy the whole packet to sk_buff */ | ||
2339 | rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); | ||
2340 | /* Get source address */ | ||
2341 | #ifdef WIRELESS_SPY | ||
2342 | memcpy(linksrcaddr, ((struct mac_header *)skb->data)->addr_2, ETH_ALEN); | ||
2343 | #endif | ||
2344 | /* Now, deal with encapsulation/translation/sniffer */ | ||
2345 | if (!sniffer) { | ||
2346 | if (!translate) { | ||
2347 | /* Encapsulated ethernet, so just lop off 802.11 MAC header */ | ||
2348 | /* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */ | ||
2349 | skb_pull( skb, RX_MAC_HEADER_LENGTH); | ||
2350 | } | ||
2351 | else { | ||
2352 | /* Do translation */ | ||
2353 | untranslate(local, skb, total_len); | ||
2354 | } | ||
2355 | } | ||
2356 | else | ||
2357 | { /* sniffer mode, so just pass whole packet */ }; | ||
2358 | |||
2359 | /************************/ | ||
2360 | /* Now pick up the rest of the fragments if any */ | ||
2361 | tmp = 17; | ||
2362 | if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { | ||
2363 | prcslink = prcs; | ||
2364 | DEBUG(1,"ray_cs rx_data in fragment loop\n"); | ||
2365 | do { | ||
2366 | prcslink = rcs_base(local) | ||
2367 | + readb(&prcslink->var.rx_packet.next_frag_rcs_index); | ||
2368 | rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) | ||
2369 | + readb(&prcslink->var.rx_packet.rx_data_length[1])) | ||
2370 | & RX_BUFF_END; | ||
2371 | pkt_addr = (( readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << 8) | ||
2372 | + readb(&prcslink->var.rx_packet.rx_data_ptr[1])) | ||
2373 | & RX_BUFF_END; | ||
2374 | |||
2375 | rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len); | ||
2376 | |||
2377 | } while (tmp-- && | ||
2378 | readb(&prcslink->var.rx_packet.next_frag_rcs_index) != 0xFF); | ||
2379 | release_frag_chain(local, prcs); | ||
2380 | } | ||
2381 | |||
2382 | skb->protocol = eth_type_trans(skb,dev); | ||
2383 | netif_rx(skb); | ||
2384 | dev->last_rx = jiffies; | ||
2385 | local->stats.rx_packets++; | ||
2386 | local->stats.rx_bytes += total_len; | ||
2387 | |||
2388 | /* Gather signal strength per address */ | ||
2389 | #ifdef WIRELESS_SPY | ||
2390 | /* For the Access Point or the node having started the ad-hoc net | ||
2391 | * note : ad-hoc work only in some specific configurations, but we | ||
2392 | * kludge in ray_get_wireless_stats... */ | ||
2393 | if(!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) | ||
2394 | { | ||
2395 | /* Update statistics */ | ||
2396 | /*local->wstats.qual.qual = none ? */ | ||
2397 | local->wstats.qual.level = siglev; | ||
2398 | /*local->wstats.qual.noise = none ? */ | ||
2399 | local->wstats.qual.updated = 0x2; | ||
2400 | } | ||
2401 | /* Now, for the addresses in the spy list */ | ||
2402 | { | ||
2403 | int i; | ||
2404 | /* Look all addresses */ | ||
2405 | for(i = 0; i < local->spy_number; i++) | ||
2406 | /* If match */ | ||
2407 | if(!memcmp(linksrcaddr, local->spy_address[i], ETH_ALEN)) | ||
2408 | { | ||
2409 | /* Update statistics */ | ||
2410 | /*local->spy_stat[i].qual = none ? */ | ||
2411 | local->spy_stat[i].level = siglev; | ||
2412 | /*local->spy_stat[i].noise = none ? */ | ||
2413 | local->spy_stat[i].updated = 0x2; | ||
2414 | } | ||
2415 | } | ||
2416 | #endif /* WIRELESS_SPY */ | ||
2417 | } /* end rx_data */ | ||
2418 | /*===========================================================================*/ | ||
2419 | static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) | ||
2420 | { | ||
2421 | snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH); | ||
2422 | struct mac_header *pmac = (struct mac_header *)skb->data; | ||
2423 | unsigned short type = *(unsigned short *)psnap->ethertype; | ||
2424 | unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff; | ||
2425 | unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff; | ||
2426 | int delta; | ||
2427 | struct ethhdr *peth; | ||
2428 | UCHAR srcaddr[ADDRLEN]; | ||
2429 | UCHAR destaddr[ADDRLEN]; | ||
2430 | |||
2431 | if (pmac->frame_ctl_2 & FC2_FROM_DS) { | ||
2432 | if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */ | ||
2433 | memcpy(destaddr, pmac->addr_3, ADDRLEN); | ||
2434 | memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN); | ||
2435 | } else { /* AP to terminal */ | ||
2436 | memcpy(destaddr, pmac->addr_1, ADDRLEN); | ||
2437 | memcpy(srcaddr, pmac->addr_3, ADDRLEN); | ||
2438 | } | ||
2439 | } else { /* Terminal to AP */ | ||
2440 | if (pmac->frame_ctl_2 & FC2_TO_DS) { | ||
2441 | memcpy(destaddr, pmac->addr_3, ADDRLEN); | ||
2442 | memcpy(srcaddr, pmac->addr_2, ADDRLEN); | ||
2443 | } else { /* Adhoc */ | ||
2444 | memcpy(destaddr, pmac->addr_1, ADDRLEN); | ||
2445 | memcpy(srcaddr, pmac->addr_2, ADDRLEN); | ||
2446 | } | ||
2447 | } | ||
2448 | |||
2449 | #ifdef PCMCIA_DEBUG | ||
2450 | if (pc_debug > 3) { | ||
2451 | int i; | ||
2452 | printk(KERN_DEBUG "skb->data before untranslate"); | ||
2453 | for (i=0;i<64;i++) | ||
2454 | printk("%02x ",skb->data[i]); | ||
2455 | printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n", | ||
2456 | type,xsap,org); | ||
2457 | printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data); | ||
2458 | } | ||
2459 | #endif | ||
2460 | |||
2461 | if ( xsap != SNAP_ID) { | ||
2462 | /* not a snap type so leave it alone */ | ||
2463 | DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff); | ||
2464 | |||
2465 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | ||
2466 | peth = (struct ethhdr *)(skb->data + delta); | ||
2467 | peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); | ||
2468 | } | ||
2469 | else { /* Its a SNAP */ | ||
2470 | if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC */ | ||
2471 | DEBUG(3,"ray_cs untranslate Bridge encap\n"); | ||
2472 | delta = RX_MAC_HEADER_LENGTH | ||
2473 | + sizeof(struct snaphdr_t) - ETH_HLEN; | ||
2474 | peth = (struct ethhdr *)(skb->data + delta); | ||
2475 | peth->h_proto = type; | ||
2476 | } | ||
2477 | else { | ||
2478 | if (org == RFC1042_ENCAP) { | ||
2479 | switch (type) { | ||
2480 | case RAY_IPX_TYPE: | ||
2481 | case APPLEARP_TYPE: | ||
2482 | DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n"); | ||
2483 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | ||
2484 | peth = (struct ethhdr *)(skb->data + delta); | ||
2485 | peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); | ||
2486 | break; | ||
2487 | default: | ||
2488 | DEBUG(3,"ray_cs untranslate RFC default\n"); | ||
2489 | delta = RX_MAC_HEADER_LENGTH + | ||
2490 | sizeof(struct snaphdr_t) - ETH_HLEN; | ||
2491 | peth = (struct ethhdr *)(skb->data + delta); | ||
2492 | peth->h_proto = type; | ||
2493 | break; | ||
2494 | } | ||
2495 | } | ||
2496 | else { | ||
2497 | printk("ray_cs untranslate very confused by packet\n"); | ||
2498 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | ||
2499 | peth = (struct ethhdr *)(skb->data + delta); | ||
2500 | peth->h_proto = type; | ||
2501 | } | ||
2502 | } | ||
2503 | } | ||
2504 | /* TBD reserve skb_reserve(skb, delta); */ | ||
2505 | skb_pull(skb, delta); | ||
2506 | DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data); | ||
2507 | memcpy(peth->h_dest, destaddr, ADDRLEN); | ||
2508 | memcpy(peth->h_source, srcaddr, ADDRLEN); | ||
2509 | #ifdef PCMCIA_DEBUG | ||
2510 | if (pc_debug > 3) { | ||
2511 | int i; | ||
2512 | printk(KERN_DEBUG "skb->data after untranslate:"); | ||
2513 | for (i=0;i<64;i++) | ||
2514 | printk("%02x ",skb->data[i]); | ||
2515 | printk("\n"); | ||
2516 | } | ||
2517 | #endif | ||
2518 | } /* end untranslate */ | ||
2519 | /*===========================================================================*/ | ||
2520 | /* Copy data from circular receive buffer to PC memory. | ||
2521 | * dest = destination address in PC memory | ||
2522 | * pkt_addr = source address in receive buffer | ||
2523 | * len = length of packet to copy | ||
2524 | */ | ||
2525 | static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length) | ||
2526 | { | ||
2527 | int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1); | ||
2528 | if (wrap_bytes <= 0) | ||
2529 | { | ||
2530 | memcpy_fromio(dest,local->rmem + pkt_addr,length); | ||
2531 | } | ||
2532 | else /* Packet wrapped in circular buffer */ | ||
2533 | { | ||
2534 | memcpy_fromio(dest,local->rmem+pkt_addr,length - wrap_bytes); | ||
2535 | memcpy_fromio(dest + length - wrap_bytes, local->rmem, wrap_bytes); | ||
2536 | } | ||
2537 | return length; | ||
2538 | } | ||
2539 | /*===========================================================================*/ | ||
2540 | static void release_frag_chain(ray_dev_t *local, struct rcs __iomem * prcs) | ||
2541 | { | ||
2542 | struct rcs __iomem *prcslink = prcs; | ||
2543 | int tmp = 17; | ||
2544 | unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); | ||
2545 | |||
2546 | while (tmp--) { | ||
2547 | writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); | ||
2548 | if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { | ||
2549 | DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); | ||
2550 | break; | ||
2551 | } | ||
2552 | prcslink = rcs_base(local) + rcsindex; | ||
2553 | rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); | ||
2554 | } | ||
2555 | writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); | ||
2556 | } | ||
2557 | /*===========================================================================*/ | ||
2558 | static void authenticate(ray_dev_t *local) | ||
2559 | { | ||
2560 | dev_link_t *link = local->finder; | ||
2561 | DEBUG(0,"ray_cs Starting authentication.\n"); | ||
2562 | if (!(link->state & DEV_PRESENT)) { | ||
2563 | DEBUG(2,"ray_cs authenticate - device not present\n"); | ||
2564 | return; | ||
2565 | } | ||
2566 | |||
2567 | del_timer(&local->timer); | ||
2568 | if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) { | ||
2569 | local->timer.function = &join_net; | ||
2570 | } | ||
2571 | else { | ||
2572 | local->timer.function = &authenticate_timeout; | ||
2573 | } | ||
2574 | local->timer.expires = jiffies + HZ*2; | ||
2575 | local->timer.data = (long)local; | ||
2576 | add_timer(&local->timer); | ||
2577 | local->authentication_state = AWAITING_RESPONSE; | ||
2578 | } /* end authenticate */ | ||
2579 | /*===========================================================================*/ | ||
2580 | static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
2581 | unsigned int pkt_addr, int rx_len) | ||
2582 | { | ||
2583 | UCHAR buff[256]; | ||
2584 | struct rx_msg *msg = (struct rx_msg *)buff; | ||
2585 | |||
2586 | del_timer(&local->timer); | ||
2587 | |||
2588 | copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); | ||
2589 | /* if we are trying to get authenticated */ | ||
2590 | if (local->sparm.b4.a_network_type == ADHOC) { | ||
2591 | DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]); | ||
2592 | if (msg->var[2] == 1) { | ||
2593 | DEBUG(0,"ray_cs Sending authentication response.\n"); | ||
2594 | if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { | ||
2595 | local->authentication_state = NEED_TO_AUTH; | ||
2596 | memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN); | ||
2597 | } | ||
2598 | } | ||
2599 | } | ||
2600 | else /* Infrastructure network */ | ||
2601 | { | ||
2602 | if (local->authentication_state == AWAITING_RESPONSE) { | ||
2603 | /* Verify authentication sequence #2 and success */ | ||
2604 | if (msg->var[2] == 2) { | ||
2605 | if ((msg->var[3] | msg->var[4]) == 0) { | ||
2606 | DEBUG(1,"Authentication successful\n"); | ||
2607 | local->card_status = CARD_AUTH_COMPLETE; | ||
2608 | associate(local); | ||
2609 | local->authentication_state = AUTHENTICATED; | ||
2610 | } | ||
2611 | else { | ||
2612 | DEBUG(0,"Authentication refused\n"); | ||
2613 | local->card_status = CARD_AUTH_REFUSED; | ||
2614 | join_net((u_long)local); | ||
2615 | local->authentication_state = UNAUTHENTICATED; | ||
2616 | } | ||
2617 | } | ||
2618 | } | ||
2619 | } | ||
2620 | |||
2621 | } /* end rx_authenticate */ | ||
2622 | /*===========================================================================*/ | ||
2623 | static void associate(ray_dev_t *local) | ||
2624 | { | ||
2625 | struct ccs __iomem *pccs; | ||
2626 | dev_link_t *link = local->finder; | ||
2627 | struct net_device *dev = link->priv; | ||
2628 | int ccsindex; | ||
2629 | if (!(link->state & DEV_PRESENT)) { | ||
2630 | DEBUG(2,"ray_cs associate - device not present\n"); | ||
2631 | return; | ||
2632 | } | ||
2633 | /* If no tx buffers available, return*/ | ||
2634 | if ((ccsindex = get_free_ccs(local)) < 0) | ||
2635 | { | ||
2636 | /* TBD should never be here but... what if we are? */ | ||
2637 | DEBUG(1,"ray_cs associate - No free ccs\n"); | ||
2638 | return; | ||
2639 | } | ||
2640 | DEBUG(1,"ray_cs Starting association with access point\n"); | ||
2641 | pccs = ccs_base(local) + ccsindex; | ||
2642 | /* fill in the CCS */ | ||
2643 | writeb(CCS_START_ASSOCIATION, &pccs->cmd); | ||
2644 | /* Interrupt the firmware to process the command */ | ||
2645 | if (interrupt_ecf(local, ccsindex)) { | ||
2646 | DEBUG(1,"ray_cs associate failed - ECF not ready for intr\n"); | ||
2647 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
2648 | |||
2649 | del_timer(&local->timer); | ||
2650 | local->timer.expires = jiffies + HZ*2; | ||
2651 | local->timer.data = (long)local; | ||
2652 | local->timer.function = &join_net; | ||
2653 | add_timer(&local->timer); | ||
2654 | local->card_status = CARD_ASSOC_FAILED; | ||
2655 | return; | ||
2656 | } | ||
2657 | if (!sniffer) netif_start_queue(dev); | ||
2658 | |||
2659 | } /* end associate */ | ||
2660 | /*===========================================================================*/ | ||
2661 | static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
2662 | unsigned int pkt_addr, int rx_len) | ||
2663 | { | ||
2664 | /* UCHAR buff[256]; | ||
2665 | struct rx_msg *msg = (struct rx_msg *)buff; | ||
2666 | */ | ||
2667 | DEBUG(0,"Deauthentication frame received\n"); | ||
2668 | local->authentication_state = UNAUTHENTICATED; | ||
2669 | /* Need to reauthenticate or rejoin depending on reason code */ | ||
2670 | /* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); | ||
2671 | */ | ||
2672 | } | ||
2673 | /*===========================================================================*/ | ||
2674 | static void clear_interrupt(ray_dev_t *local) | ||
2675 | { | ||
2676 | writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET); | ||
2677 | } | ||
2678 | /*===========================================================================*/ | ||
2679 | #ifdef CONFIG_PROC_FS | ||
2680 | #define MAXDATA (PAGE_SIZE - 80) | ||
2681 | |||
2682 | static char *card_status[] = { | ||
2683 | "Card inserted - uninitialized", /* 0 */ | ||
2684 | "Card not downloaded", /* 1 */ | ||
2685 | "Waiting for download parameters", /* 2 */ | ||
2686 | "Card doing acquisition", /* 3 */ | ||
2687 | "Acquisition complete", /* 4 */ | ||
2688 | "Authentication complete", /* 5 */ | ||
2689 | "Association complete", /* 6 */ | ||
2690 | "???", "???", "???", "???", /* 7 8 9 10 undefined */ | ||
2691 | "Card init error", /* 11 */ | ||
2692 | "Download parameters error", /* 12 */ | ||
2693 | "???", /* 13 */ | ||
2694 | "Acquisition failed", /* 14 */ | ||
2695 | "Authentication refused", /* 15 */ | ||
2696 | "Association failed" /* 16 */ | ||
2697 | }; | ||
2698 | |||
2699 | static char *nettype[] = {"Adhoc", "Infra "}; | ||
2700 | static char *framing[] = {"Encapsulation", "Translation"} | ||
2701 | ; | ||
2702 | /*===========================================================================*/ | ||
2703 | static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) | ||
2704 | { | ||
2705 | /* Print current values which are not available via other means | ||
2706 | * eg ifconfig | ||
2707 | */ | ||
2708 | int i; | ||
2709 | dev_link_t *link; | ||
2710 | struct net_device *dev; | ||
2711 | ray_dev_t *local; | ||
2712 | UCHAR *p; | ||
2713 | struct freq_hop_element *pfh; | ||
2714 | UCHAR c[33]; | ||
2715 | |||
2716 | link = dev_list; | ||
2717 | if (!link) | ||
2718 | return 0; | ||
2719 | dev = (struct net_device *)link->priv; | ||
2720 | if (!dev) | ||
2721 | return 0; | ||
2722 | local = (ray_dev_t *)dev->priv; | ||
2723 | if (!local) | ||
2724 | return 0; | ||
2725 | |||
2726 | len = 0; | ||
2727 | |||
2728 | len += sprintf(buf + len, "Raylink Wireless LAN driver status\n"); | ||
2729 | len += sprintf(buf + len, "%s\n", rcsid); | ||
2730 | /* build 4 does not report version, and field is 0x55 after memtest */ | ||
2731 | len += sprintf(buf + len, "Firmware version = "); | ||
2732 | if (local->fw_ver == 0x55) | ||
2733 | len += sprintf(buf + len, "4 - Use dump_cis for more details\n"); | ||
2734 | else | ||
2735 | len += sprintf(buf + len, "%2d.%02d.%02d\n", | ||
2736 | local->fw_ver, local->fw_bld, local->fw_var); | ||
2737 | |||
2738 | for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i]; | ||
2739 | c[32] = 0; | ||
2740 | len += sprintf(buf + len, "%s network ESSID = \"%s\"\n", | ||
2741 | nettype[local->sparm.b5.a_network_type], c); | ||
2742 | |||
2743 | p = local->bss_id; | ||
2744 | len += sprintf(buf + len, | ||
2745 | "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
2746 | p[0],p[1],p[2],p[3],p[4],p[5]); | ||
2747 | |||
2748 | len += sprintf(buf + len, "Country code = %d\n", | ||
2749 | local->sparm.b5.a_curr_country_code); | ||
2750 | |||
2751 | i = local->card_status; | ||
2752 | if (i < 0) i = 10; | ||
2753 | if (i > 16) i = 10; | ||
2754 | len += sprintf(buf + len, "Card status = %s\n", card_status[i]); | ||
2755 | |||
2756 | len += sprintf(buf + len, "Framing mode = %s\n",framing[translate]); | ||
2757 | |||
2758 | len += sprintf(buf + len, "Last pkt signal lvl = %d\n", local->last_rsl); | ||
2759 | |||
2760 | if (local->beacon_rxed) { | ||
2761 | /* Pull some fields out of last beacon received */ | ||
2762 | len += sprintf(buf + len, "Beacon Interval = %d Kus\n", | ||
2763 | local->last_bcn.beacon_intvl[0] | ||
2764 | + 256 * local->last_bcn.beacon_intvl[1]); | ||
2765 | |||
2766 | p = local->last_bcn.elements; | ||
2767 | if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2; | ||
2768 | else { | ||
2769 | len += sprintf(buf + len, "Parse beacon failed at essid element id = %d\n",p[0]); | ||
2770 | return len; | ||
2771 | } | ||
2772 | |||
2773 | if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) { | ||
2774 | len += sprintf(buf + len, "Supported rate codes = "); | ||
2775 | for (i=2; i<p[1] + 2; i++) | ||
2776 | len += sprintf(buf + len, "0x%02x ", p[i]); | ||
2777 | len += sprintf(buf + len, "\n"); | ||
2778 | p += p[1] + 2; | ||
2779 | } | ||
2780 | else { | ||
2781 | len += sprintf(buf + len, "Parse beacon failed at rates element\n"); | ||
2782 | return len; | ||
2783 | } | ||
2784 | |||
2785 | if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) { | ||
2786 | pfh = (struct freq_hop_element *)p; | ||
2787 | len += sprintf(buf + len, "Hop dwell = %d Kus\n", | ||
2788 | pfh->dwell_time[0] + 256 * pfh->dwell_time[1]); | ||
2789 | len += sprintf(buf + len, "Hop set = %d \n", pfh->hop_set); | ||
2790 | len += sprintf(buf + len, "Hop pattern = %d \n", pfh->hop_pattern); | ||
2791 | len += sprintf(buf + len, "Hop index = %d \n", pfh->hop_index); | ||
2792 | p += p[1] + 2; | ||
2793 | } | ||
2794 | else { | ||
2795 | len += sprintf(buf + len, "Parse beacon failed at FH param element\n"); | ||
2796 | return len; | ||
2797 | } | ||
2798 | } else { | ||
2799 | len += sprintf(buf + len, "No beacons received\n"); | ||
2800 | } | ||
2801 | return len; | ||
2802 | } | ||
2803 | |||
2804 | #endif | ||
2805 | /*===========================================================================*/ | ||
2806 | static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) | ||
2807 | { | ||
2808 | int addr; | ||
2809 | struct ccs __iomem *pccs; | ||
2810 | struct tx_msg __iomem *ptx; | ||
2811 | int ccsindex; | ||
2812 | |||
2813 | /* If no tx buffers available, return */ | ||
2814 | if ((ccsindex = get_free_tx_ccs(local)) < 0) | ||
2815 | { | ||
2816 | DEBUG(1,"ray_cs send authenticate - No free tx ccs\n"); | ||
2817 | return -1; | ||
2818 | } | ||
2819 | |||
2820 | pccs = ccs_base(local) + ccsindex; | ||
2821 | |||
2822 | /* Address in card space */ | ||
2823 | addr = TX_BUF_BASE + (ccsindex << 11); | ||
2824 | /* fill in the CCS */ | ||
2825 | writeb(CCS_TX_REQUEST, &pccs->cmd); | ||
2826 | writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr); | ||
2827 | writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1); | ||
2828 | writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length); | ||
2829 | writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1); | ||
2830 | writeb(0, &pccs->var.tx_request.pow_sav_mode); | ||
2831 | |||
2832 | ptx = local->sram + addr; | ||
2833 | /* fill in the mac header */ | ||
2834 | writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); | ||
2835 | writeb(0, &ptx->mac.frame_ctl_2); | ||
2836 | |||
2837 | memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN); | ||
2838 | memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN); | ||
2839 | memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); | ||
2840 | |||
2841 | /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */ | ||
2842 | memset_io(ptx->var, 0, 6); | ||
2843 | writeb(auth_type & 0xff, ptx->var + 2); | ||
2844 | |||
2845 | /* Interrupt the firmware to process the command */ | ||
2846 | if (interrupt_ecf(local, ccsindex)) { | ||
2847 | DEBUG(1,"ray_cs send authentication request failed - ECF not ready for intr\n"); | ||
2848 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
2849 | return -1; | ||
2850 | } | ||
2851 | return 0; | ||
2852 | } /* End build_auth_frame */ | ||
2853 | |||
2854 | /*===========================================================================*/ | ||
2855 | #ifdef CONFIG_PROC_FS | ||
2856 | static void raycs_write(const char *name, write_proc_t *w, void *data) | ||
2857 | { | ||
2858 | struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL); | ||
2859 | if (entry) { | ||
2860 | entry->write_proc = w; | ||
2861 | entry->data = data; | ||
2862 | } | ||
2863 | } | ||
2864 | |||
2865 | static int write_essid(struct file *file, const char __user *buffer, unsigned long count, void *data) | ||
2866 | { | ||
2867 | static char proc_essid[33]; | ||
2868 | int len = count; | ||
2869 | |||
2870 | if (len > 32) | ||
2871 | len = 32; | ||
2872 | memset(proc_essid, 0, 33); | ||
2873 | if (copy_from_user(proc_essid, buffer, len)) | ||
2874 | return -EFAULT; | ||
2875 | essid = proc_essid; | ||
2876 | return count; | ||
2877 | } | ||
2878 | |||
2879 | static int write_int(struct file *file, const char __user *buffer, unsigned long count, void *data) | ||
2880 | { | ||
2881 | static char proc_number[10]; | ||
2882 | char *p; | ||
2883 | int nr, len; | ||
2884 | |||
2885 | if (!count) | ||
2886 | return 0; | ||
2887 | |||
2888 | if (count > 9) | ||
2889 | return -EINVAL; | ||
2890 | if (copy_from_user(proc_number, buffer, count)) | ||
2891 | return -EFAULT; | ||
2892 | p = proc_number; | ||
2893 | nr = 0; | ||
2894 | len = count; | ||
2895 | do { | ||
2896 | unsigned int c = *p - '0'; | ||
2897 | if (c > 9) | ||
2898 | return -EINVAL; | ||
2899 | nr = nr*10 + c; | ||
2900 | p++; | ||
2901 | } while (--len); | ||
2902 | *(int *)data = nr; | ||
2903 | return count; | ||
2904 | } | ||
2905 | #endif | ||
2906 | |||
2907 | static struct pcmcia_driver ray_driver = { | ||
2908 | .owner = THIS_MODULE, | ||
2909 | .drv = { | ||
2910 | .name = "ray_cs", | ||
2911 | }, | ||
2912 | .attach = ray_attach, | ||
2913 | .detach = ray_detach, | ||
2914 | }; | ||
2915 | |||
2916 | static int __init init_ray_cs(void) | ||
2917 | { | ||
2918 | int rc; | ||
2919 | |||
2920 | DEBUG(1, "%s\n", rcsid); | ||
2921 | rc = pcmcia_register_driver(&ray_driver); | ||
2922 | DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc); | ||
2923 | |||
2924 | #ifdef CONFIG_PROC_FS | ||
2925 | proc_mkdir("driver/ray_cs", NULL); | ||
2926 | |||
2927 | create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_read); | ||
2928 | raycs_write("driver/ray_cs/essid", write_essid, NULL); | ||
2929 | raycs_write("driver/ray_cs/net_type", write_int, &net_type); | ||
2930 | raycs_write("driver/ray_cs/translate", write_int, &translate); | ||
2931 | #endif | ||
2932 | if (translate != 0) translate = 1; | ||
2933 | return 0; | ||
2934 | } /* init_ray_cs */ | ||
2935 | |||
2936 | /*===========================================================================*/ | ||
2937 | |||
2938 | static void __exit exit_ray_cs(void) | ||
2939 | { | ||
2940 | DEBUG(0, "ray_cs: cleanup_module\n"); | ||
2941 | |||
2942 | #ifdef CONFIG_PROC_FS | ||
2943 | remove_proc_entry("driver/ray_cs/ray_cs", NULL); | ||
2944 | remove_proc_entry("driver/ray_cs/essid", NULL); | ||
2945 | remove_proc_entry("driver/ray_cs/net_type", NULL); | ||
2946 | remove_proc_entry("driver/ray_cs/translate", NULL); | ||
2947 | remove_proc_entry("driver/ray_cs", NULL); | ||
2948 | #endif | ||
2949 | |||
2950 | pcmcia_unregister_driver(&ray_driver); | ||
2951 | BUG_ON(dev_list != NULL); | ||
2952 | } /* exit_ray_cs */ | ||
2953 | |||
2954 | module_init(init_ray_cs); | ||
2955 | module_exit(exit_ray_cs); | ||
2956 | |||
2957 | /*===========================================================================*/ | ||
diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h new file mode 100644 index 000000000000..c77afa14fa86 --- /dev/null +++ b/drivers/net/wireless/ray_cs.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* Raytheon wireless LAN PCMCIA card driver for Linux | ||
2 | A PCMCIA client driver for the Raylink wireless network card | ||
3 | Written by Corey Thomas | ||
4 | */ | ||
5 | |||
6 | #ifndef RAYLINK_H | ||
7 | |||
8 | struct beacon_rx { | ||
9 | struct mac_header mac; | ||
10 | UCHAR timestamp[8]; | ||
11 | UCHAR beacon_intvl[2]; | ||
12 | UCHAR capability[2]; | ||
13 | UCHAR elements[sizeof(struct essid_element) | ||
14 | + sizeof(struct rates_element) | ||
15 | + sizeof(struct freq_hop_element) | ||
16 | + sizeof(struct japan_call_sign_element) | ||
17 | + sizeof(struct tim_element)]; | ||
18 | }; | ||
19 | |||
20 | /* Return values for get_free{,_tx}_ccs */ | ||
21 | #define ECCSFULL (-1) | ||
22 | #define ECCSBUSY (-2) | ||
23 | #define ECARDGONE (-3) | ||
24 | |||
25 | typedef struct ray_dev_t { | ||
26 | int card_status; | ||
27 | int authentication_state; | ||
28 | dev_node_t node; | ||
29 | window_handle_t amem_handle; /* handle to window for attribute memory */ | ||
30 | window_handle_t rmem_handle; /* handle to window for rx buffer on card */ | ||
31 | void __iomem *sram; /* pointer to beginning of shared RAM */ | ||
32 | void __iomem *amem; /* pointer to attribute mem window */ | ||
33 | void __iomem *rmem; /* pointer to receive buffer window */ | ||
34 | dev_link_t *finder; /* pointer back to dev_link_t for card */ | ||
35 | struct timer_list timer; | ||
36 | long tx_ccs_lock; | ||
37 | long ccs_lock; | ||
38 | int dl_param_ccs; | ||
39 | union { | ||
40 | struct b4_startup_params b4; | ||
41 | struct b5_startup_params b5; | ||
42 | } sparm; | ||
43 | int timeout_flag; | ||
44 | UCHAR supported_rates[8]; | ||
45 | UCHAR japan_call_sign[12]; | ||
46 | struct startup_res_6 startup_res; | ||
47 | int num_multi; | ||
48 | /* Network parameters from start/join */ | ||
49 | UCHAR bss_id[6]; | ||
50 | UCHAR auth_id[6]; | ||
51 | UCHAR net_default_tx_rate; | ||
52 | UCHAR encryption; | ||
53 | struct net_device_stats stats; | ||
54 | |||
55 | UCHAR net_type; | ||
56 | UCHAR sta_type; | ||
57 | UCHAR fw_ver; | ||
58 | UCHAR fw_bld; | ||
59 | UCHAR fw_var; | ||
60 | UCHAR ASIC_version; | ||
61 | UCHAR assoc_id[2]; | ||
62 | UCHAR tib_length; | ||
63 | UCHAR last_rsl; | ||
64 | int beacon_rxed; | ||
65 | struct beacon_rx last_bcn; | ||
66 | #ifdef WIRELESS_EXT | ||
67 | iw_stats wstats; /* Wireless specific stats */ | ||
68 | #endif | ||
69 | #ifdef WIRELESS_SPY | ||
70 | int spy_number; /* Number of addresses to spy */ | ||
71 | mac_addr spy_address[IW_MAX_SPY + 1]; /* The addresses to spy */ | ||
72 | iw_qual spy_stat[IW_MAX_SPY + 1]; /* Statistics gathered */ | ||
73 | #endif /* WIRELESS_SPY */ | ||
74 | |||
75 | } ray_dev_t; | ||
76 | /*****************************************************************************/ | ||
77 | |||
78 | #endif /* RAYLINK_H */ | ||
diff --git a/drivers/net/wireless/rayctl.h b/drivers/net/wireless/rayctl.h new file mode 100644 index 000000000000..49d9b267bc0f --- /dev/null +++ b/drivers/net/wireless/rayctl.h | |||
@@ -0,0 +1,732 @@ | |||
1 | #ifndef RAYLINK_H | ||
2 | |||
3 | typedef unsigned char UCHAR; | ||
4 | |||
5 | /****** IEEE 802.11 constants ************************************************/ | ||
6 | #define ADDRLEN 6 | ||
7 | /* Frame control 1 bit fields */ | ||
8 | #define PROTOCOL_VER 0x00 | ||
9 | #define DATA_TYPE 0x08 | ||
10 | #define ASSOC_REQ_TYPE 0x00 | ||
11 | #define ASSOC_RESP_TYPE 0x10 | ||
12 | #define REASSOC_REQ_TYPE 0x20 | ||
13 | #define REASSOC_RESP_TYPE 0x30 | ||
14 | #define NULL_MSG_TYPE 0x48 | ||
15 | #define BEACON_TYPE 0x80 | ||
16 | #define DISASSOC_TYPE 0xA0 | ||
17 | #define PSPOLL_TYPE 0xA4 | ||
18 | #define AUTHENTIC_TYPE 0xB0 | ||
19 | #define DEAUTHENTIC_TYPE 0xC0 | ||
20 | /* Frame control 2 bit fields */ | ||
21 | #define FC2_TO_DS 0x01 | ||
22 | #define FC2_FROM_DS 0x02 | ||
23 | #define FC2_MORE_FRAG 0x04 | ||
24 | #define FC2_RETRY 0x08 | ||
25 | #define FC2_PSM 0x10 | ||
26 | #define FC2_MORE_DATA 0x20 | ||
27 | #define FC2_WEP 0x40 | ||
28 | #define FC2_ORDER 0x80 | ||
29 | /*****************************************************************************/ | ||
30 | /* 802.11 element ID's and lengths */ | ||
31 | #define C_BP_CAPABILITY_ESS 0x01 | ||
32 | #define C_BP_CAPABILITY_IBSS 0x02 | ||
33 | #define C_BP_CAPABILITY_CF_POLLABLE 0x04 | ||
34 | #define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08 | ||
35 | #define C_BP_CAPABILITY_PRIVACY 0x10 | ||
36 | |||
37 | #define C_ESSID_ELEMENT_ID 0 | ||
38 | #define C_ESSID_ELEMENT_MAX_LENGTH 32 | ||
39 | |||
40 | #define C_SUPPORTED_RATES_ELEMENT_ID 1 | ||
41 | #define C_SUPPORTED_RATES_ELEMENT_LENGTH 2 | ||
42 | |||
43 | #define C_FH_PARAM_SET_ELEMENT_ID 2 | ||
44 | #define C_FH_PARAM_SET_ELEMENT_LNGTH 5 | ||
45 | |||
46 | #define C_CF_PARAM_SET_ELEMENT_ID 4 | ||
47 | #define C_CF_PARAM_SET_ELEMENT_LNGTH 6 | ||
48 | |||
49 | #define C_TIM_ELEMENT_ID 5 | ||
50 | #define C_TIM_BITMAP_LENGTH 251 | ||
51 | #define C_TIM_BMCAST_BIT 0x01 | ||
52 | |||
53 | #define C_IBSS_ELEMENT_ID 6 | ||
54 | #define C_IBSS_ELEMENT_LENGTH 2 | ||
55 | |||
56 | #define C_JAPAN_CALL_SIGN_ELEMENT_ID 51 | ||
57 | #define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12 | ||
58 | |||
59 | #define C_DISASSOC_REASON_CODE_LEN 2 | ||
60 | #define C_DISASSOC_REASON_CODE_DEFAULT 8 | ||
61 | |||
62 | #define C_CRC_LEN 4 | ||
63 | #define C_NUM_SUPPORTED_RATES 8 | ||
64 | /****** IEEE 802.11 mac header for type data packets *************************/ | ||
65 | struct mac_header { | ||
66 | UCHAR frame_ctl_1; | ||
67 | UCHAR frame_ctl_2; | ||
68 | UCHAR duration_lsb; | ||
69 | UCHAR duration_msb; | ||
70 | UCHAR addr_1[ADDRLEN]; | ||
71 | UCHAR addr_2[ADDRLEN]; | ||
72 | UCHAR addr_3[ADDRLEN]; | ||
73 | UCHAR seq_frag_num[2]; | ||
74 | /* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */ | ||
75 | }; | ||
76 | /****** IEEE 802.11 frame element structures *********************************/ | ||
77 | struct essid_element | ||
78 | { | ||
79 | UCHAR id; | ||
80 | UCHAR length; | ||
81 | UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH]; | ||
82 | }; | ||
83 | struct rates_element | ||
84 | { | ||
85 | UCHAR id; | ||
86 | UCHAR length; | ||
87 | UCHAR value[8]; | ||
88 | }; | ||
89 | struct freq_hop_element | ||
90 | { | ||
91 | UCHAR id; | ||
92 | UCHAR length; | ||
93 | UCHAR dwell_time[2]; | ||
94 | UCHAR hop_set; | ||
95 | UCHAR hop_pattern; | ||
96 | UCHAR hop_index; | ||
97 | }; | ||
98 | struct tim_element | ||
99 | { | ||
100 | UCHAR id; | ||
101 | UCHAR length; | ||
102 | UCHAR dtim_count; | ||
103 | UCHAR dtim_period; | ||
104 | UCHAR bitmap_control; | ||
105 | UCHAR tim[C_TIM_BITMAP_LENGTH]; | ||
106 | }; | ||
107 | struct ibss_element | ||
108 | { | ||
109 | UCHAR id; | ||
110 | UCHAR length; | ||
111 | UCHAR atim_window[2]; | ||
112 | }; | ||
113 | struct japan_call_sign_element | ||
114 | { | ||
115 | UCHAR id; | ||
116 | UCHAR length; | ||
117 | UCHAR call_sign[12]; | ||
118 | }; | ||
119 | /****** Beacon message structures ********************************************/ | ||
120 | /* .elements is a large lump of max size because elements are variable size */ | ||
121 | struct infra_beacon | ||
122 | { | ||
123 | UCHAR timestamp[8]; | ||
124 | UCHAR beacon_intvl[2]; | ||
125 | UCHAR capability[2]; | ||
126 | UCHAR elements[sizeof(struct essid_element) | ||
127 | + sizeof(struct rates_element) | ||
128 | + sizeof(struct freq_hop_element) | ||
129 | + sizeof(struct japan_call_sign_element) | ||
130 | + sizeof(struct tim_element)]; | ||
131 | }; | ||
132 | struct adhoc_beacon | ||
133 | { | ||
134 | UCHAR timestamp[8]; | ||
135 | UCHAR beacon_intvl[2]; | ||
136 | UCHAR capability[2]; | ||
137 | UCHAR elements[sizeof(struct essid_element) | ||
138 | + sizeof(struct rates_element) | ||
139 | + sizeof(struct freq_hop_element) | ||
140 | + sizeof(struct japan_call_sign_element) | ||
141 | + sizeof(struct ibss_element)]; | ||
142 | }; | ||
143 | /*****************************************************************************/ | ||
144 | /*****************************************************************************/ | ||
145 | /* #define C_MAC_HDR_2_WEP 0x40 */ | ||
146 | /* TX/RX CCS constants */ | ||
147 | #define TX_HEADER_LENGTH 0x1C | ||
148 | #define RX_MAC_HEADER_LENGTH 0x18 | ||
149 | #define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6) | ||
150 | #define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) | ||
151 | #define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) | ||
152 | #define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2) | ||
153 | #define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) | ||
154 | #define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) | ||
155 | #define FCS_LEN 4 | ||
156 | |||
157 | #define ADHOC 0 | ||
158 | #define INFRA 1 | ||
159 | |||
160 | #define TYPE_STA 0 | ||
161 | #define TYPE_AP 1 | ||
162 | |||
163 | #define PASSIVE_SCAN 1 | ||
164 | #define ACTIVE_SCAN 1 | ||
165 | |||
166 | #define PSM_CAM 0 | ||
167 | |||
168 | /* Country codes */ | ||
169 | #define USA 1 | ||
170 | #define EUROPE 2 | ||
171 | #define JAPAN 3 | ||
172 | #define KOREA 4 | ||
173 | #define SPAIN 5 | ||
174 | #define FRANCE 6 | ||
175 | #define ISRAEL 7 | ||
176 | #define AUSTRALIA 8 | ||
177 | #define JAPAN_TEST 9 | ||
178 | |||
179 | /* Hop pattern lengths */ | ||
180 | #define USA_HOP_MOD 79 | ||
181 | #define EUROPE_HOP_MOD 79 | ||
182 | #define JAPAN_HOP_MOD 23 | ||
183 | #define KOREA_HOP_MOD 23 | ||
184 | #define SPAIN_HOP_MOD 27 | ||
185 | #define FRANCE_HOP_MOD 35 | ||
186 | #define ISRAEL_HOP_MOD 35 | ||
187 | #define AUSTRALIA_HOP_MOD 47 | ||
188 | #define JAPAN_TEST_HOP_MOD 23 | ||
189 | |||
190 | #define ESSID_SIZE 32 | ||
191 | /**********************************************************************/ | ||
192 | /* CIS Register Constants */ | ||
193 | #define CIS_OFFSET 0x0f00 | ||
194 | /* Configuration Option Register (0x0F00) */ | ||
195 | #define COR_OFFSET 0x00 | ||
196 | #define COR_SOFT_RESET 0x80 | ||
197 | #define COR_LEVEL_IRQ 0x40 | ||
198 | #define COR_CONFIG_NUM 0x01 | ||
199 | #define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM) | ||
200 | |||
201 | /* Card Configuration and Status Register (0x0F01) */ | ||
202 | #define CCSR_OFFSET 0x01 | ||
203 | #define CCSR_HOST_INTR_PENDING 0x01 | ||
204 | #define CCSR_POWER_DOWN 0x04 | ||
205 | |||
206 | /* HCS Interrupt Register (0x0F05) */ | ||
207 | #define HCS_INTR_OFFSET 0x05 | ||
208 | /* #define HCS_INTR_OFFSET 0x0A */ | ||
209 | #define HCS_INTR_CLEAR 0x00 | ||
210 | |||
211 | /* ECF Interrupt Register (0x0F06) */ | ||
212 | #define ECF_INTR_OFFSET 0x06 | ||
213 | /* #define ECF_INTR_OFFSET 0x0C */ | ||
214 | #define ECF_INTR_SET 0x01 | ||
215 | |||
216 | /* Authorization Register 0 (0x0F08) */ | ||
217 | #define AUTH_0_ON 0x57 | ||
218 | |||
219 | /* Authorization Register 1 (0x0F09) */ | ||
220 | #define AUTH_1_ON 0x82 | ||
221 | |||
222 | /* Program Mode Register (0x0F0A) */ | ||
223 | #define PC2PM 0x02 | ||
224 | #define PC2CAL 0x10 | ||
225 | #define PC2MLSE 0x20 | ||
226 | |||
227 | /* PC Test Mode Register (0x0F0B) */ | ||
228 | #define PC_TEST_MODE 0x08 | ||
229 | |||
230 | /* Frequency Control Word (0x0F10) */ | ||
231 | /* Range 0x02 - 0xA6 */ | ||
232 | |||
233 | /* Test Mode Control 1-4 (0x0F14 - 0x0F17) */ | ||
234 | |||
235 | /**********************************************************************/ | ||
236 | |||
237 | /* Shared RAM Area */ | ||
238 | #define SCB_BASE 0x0000 | ||
239 | #define STATUS_BASE 0x0100 | ||
240 | #define HOST_TO_ECF_BASE 0x0200 | ||
241 | #define ECF_TO_HOST_BASE 0x0300 | ||
242 | #define CCS_BASE 0x0400 | ||
243 | #define RCS_BASE 0x0800 | ||
244 | #define INFRA_TIM_BASE 0x0C00 | ||
245 | #define SSID_LIST_BASE 0x0D00 | ||
246 | #define TX_BUF_BASE 0x1000 | ||
247 | #define RX_BUF_BASE 0x8000 | ||
248 | |||
249 | #define NUMBER_OF_CCS 64 | ||
250 | #define NUMBER_OF_RCS 64 | ||
251 | /*#define NUMBER_OF_TX_CCS 14 */ | ||
252 | #define NUMBER_OF_TX_CCS 14 | ||
253 | |||
254 | #define TX_BUF_SIZE (2048 - sizeof(struct tx_msg)) | ||
255 | #define RX_BUFF_END 0x3FFF | ||
256 | /* Values for buffer_status */ | ||
257 | #define CCS_BUFFER_FREE 0 | ||
258 | #define CCS_BUFFER_BUSY 1 | ||
259 | #define CCS_COMMAND_COMPLETE 2 | ||
260 | #define CCS_COMMAND_FAILED 3 | ||
261 | |||
262 | /* Values for cmd */ | ||
263 | #define CCS_DOWNLOAD_STARTUP_PARAMS 1 | ||
264 | #define CCS_UPDATE_PARAMS 2 | ||
265 | #define CCS_REPORT_PARAMS 3 | ||
266 | #define CCS_UPDATE_MULTICAST_LIST 4 | ||
267 | #define CCS_UPDATE_POWER_SAVINGS_MODE 5 | ||
268 | #define CCS_START_NETWORK 6 | ||
269 | #define CCS_JOIN_NETWORK 7 | ||
270 | #define CCS_START_ASSOCIATION 8 | ||
271 | #define CCS_TX_REQUEST 9 | ||
272 | #define CCS_TEST_MEMORY 0xa | ||
273 | #define CCS_SHUTDOWN 0xb | ||
274 | #define CCS_DUMP_MEMORY 0xc | ||
275 | #define CCS_START_TIMER 0xe | ||
276 | #define CCS_LAST_CMD CCS_START_TIMER | ||
277 | |||
278 | /* Values for link field */ | ||
279 | #define CCS_END_LIST 0xff | ||
280 | |||
281 | /* values for buffer_status field */ | ||
282 | #define RCS_BUFFER_FREE 0 | ||
283 | #define RCS_BUFFER_BUSY 1 | ||
284 | #define RCS_COMPLETE 2 | ||
285 | #define RCS_FAILED 3 | ||
286 | #define RCS_BUFFER_RELEASE 0xFF | ||
287 | |||
288 | /* values for interrupt_id field */ | ||
289 | #define PROCESS_RX_PACKET 0x80 /* */ | ||
290 | #define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */ | ||
291 | #define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */ | ||
292 | #define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */ | ||
293 | |||
294 | /*****************************************************************************/ | ||
295 | /* Memory types for dump memory command */ | ||
296 | #define C_MEM_PROG 0 | ||
297 | #define C_MEM_XDATA 1 | ||
298 | #define C_MEM_SFR 2 | ||
299 | #define C_MEM_IDATA 3 | ||
300 | |||
301 | /*** Return values for hw_xmit **********/ | ||
302 | #define XMIT_OK (0) | ||
303 | #define XMIT_MSG_BAD (-1) | ||
304 | #define XMIT_NO_CCS (-2) | ||
305 | #define XMIT_NO_INTR (-3) | ||
306 | #define XMIT_NEED_AUTH (-4) | ||
307 | |||
308 | /*** Values for card status */ | ||
309 | #define CARD_INSERTED (0) | ||
310 | |||
311 | #define CARD_AWAITING_PARAM (1) | ||
312 | #define CARD_INIT_ERROR (11) | ||
313 | |||
314 | #define CARD_DL_PARAM (2) | ||
315 | #define CARD_DL_PARAM_ERROR (12) | ||
316 | |||
317 | #define CARD_DOING_ACQ (3) | ||
318 | |||
319 | #define CARD_ACQ_COMPLETE (4) | ||
320 | #define CARD_ACQ_FAILED (14) | ||
321 | |||
322 | #define CARD_AUTH_COMPLETE (5) | ||
323 | #define CARD_AUTH_REFUSED (15) | ||
324 | |||
325 | #define CARD_ASSOC_COMPLETE (6) | ||
326 | #define CARD_ASSOC_FAILED (16) | ||
327 | |||
328 | /*** Values for authentication_state ***********************************/ | ||
329 | #define UNAUTHENTICATED (0) | ||
330 | #define AWAITING_RESPONSE (1) | ||
331 | #define AUTHENTICATED (2) | ||
332 | #define NEED_TO_AUTH (3) | ||
333 | |||
334 | /*** Values for authentication type ************************************/ | ||
335 | #define OPEN_AUTH_REQUEST (1) | ||
336 | #define OPEN_AUTH_RESPONSE (2) | ||
337 | #define BROADCAST_DEAUTH (0xc0) | ||
338 | /*** Values for timer functions ****************************************/ | ||
339 | #define TODO_NOTHING (0) | ||
340 | #define TODO_VERIFY_DL_START (-1) | ||
341 | #define TODO_START_NET (-2) | ||
342 | #define TODO_JOIN_NET (-3) | ||
343 | #define TODO_AUTHENTICATE_TIMEOUT (-4) | ||
344 | #define TODO_SEND_CCS (-5) | ||
345 | /***********************************************************************/ | ||
346 | /* Parameter passing structure for update/report parameter CCS's */ | ||
347 | struct object_id { | ||
348 | void *object_addr; | ||
349 | unsigned char object_length; | ||
350 | }; | ||
351 | |||
352 | #define OBJID_network_type 0 | ||
353 | #define OBJID_acting_as_ap_status 1 | ||
354 | #define OBJID_current_ess_id 2 | ||
355 | #define OBJID_scanning_mode 3 | ||
356 | #define OBJID_power_mgt_state 4 | ||
357 | #define OBJID_mac_address 5 | ||
358 | #define OBJID_frag_threshold 6 | ||
359 | #define OBJID_hop_time 7 | ||
360 | #define OBJID_beacon_period 8 | ||
361 | #define OBJID_dtim_period 9 | ||
362 | #define OBJID_retry_max 10 | ||
363 | #define OBJID_ack_timeout 11 | ||
364 | #define OBJID_sifs 12 | ||
365 | #define OBJID_difs 13 | ||
366 | #define OBJID_pifs 14 | ||
367 | #define OBJID_rts_threshold 15 | ||
368 | #define OBJID_scan_dwell_time 16 | ||
369 | #define OBJID_max_scan_dwell_time 17 | ||
370 | #define OBJID_assoc_resp_timeout 18 | ||
371 | #define OBJID_adhoc_scan_cycle_max 19 | ||
372 | #define OBJID_infra_scan_cycle_max 20 | ||
373 | #define OBJID_infra_super_cycle_max 21 | ||
374 | #define OBJID_promiscuous_mode 22 | ||
375 | #define OBJID_unique_word 23 | ||
376 | #define OBJID_slot_time 24 | ||
377 | #define OBJID_roaming_low_snr 25 | ||
378 | #define OBJID_low_snr_count_thresh 26 | ||
379 | #define OBJID_infra_missed_bcn 27 | ||
380 | #define OBJID_adhoc_missed_bcn 28 | ||
381 | #define OBJID_curr_country_code 29 | ||
382 | #define OBJID_hop_pattern 30 | ||
383 | #define OBJID_reserved 31 | ||
384 | #define OBJID_cw_max_msb 32 | ||
385 | #define OBJID_cw_min_msb 33 | ||
386 | #define OBJID_noise_filter_gain 34 | ||
387 | #define OBJID_noise_limit_offset 35 | ||
388 | #define OBJID_det_rssi_thresh_offset 36 | ||
389 | #define OBJID_med_busy_thresh_offset 37 | ||
390 | #define OBJID_det_sync_thresh 38 | ||
391 | #define OBJID_test_mode 39 | ||
392 | #define OBJID_test_min_chan_num 40 | ||
393 | #define OBJID_test_max_chan_num 41 | ||
394 | #define OBJID_allow_bcast_ID_prbrsp 42 | ||
395 | #define OBJID_privacy_must_start 43 | ||
396 | #define OBJID_privacy_can_join 44 | ||
397 | #define OBJID_basic_rate_set 45 | ||
398 | |||
399 | /**** Configuration/Status/Control Area ***************************/ | ||
400 | /* System Control Block (SCB) Area | ||
401 | * Located at Shared RAM offset 0 | ||
402 | */ | ||
403 | struct scb { | ||
404 | UCHAR ccs_index; | ||
405 | UCHAR rcs_index; | ||
406 | }; | ||
407 | |||
408 | /****** Status area at Shared RAM offset 0x0100 ******************************/ | ||
409 | struct status { | ||
410 | UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/ | ||
411 | UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/ | ||
412 | UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/ | ||
413 | UCHAR reserved1; | ||
414 | short mrx_overflow; /* ECF increments on rx overflow */ | ||
415 | short mrx_checksum_error; /* ECF increments on rx CRC error */ | ||
416 | short rx_hec_error; /* ECF incs on mac header CRC error */ | ||
417 | UCHAR rxnoise; /* Average RSL measurement */ | ||
418 | }; | ||
419 | |||
420 | /****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/ | ||
421 | struct host_to_ecf_area { | ||
422 | |||
423 | }; | ||
424 | |||
425 | /****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/ | ||
426 | struct startup_res_518 { | ||
427 | UCHAR startup_word; | ||
428 | UCHAR station_addr[ADDRLEN]; | ||
429 | UCHAR calc_prog_chksum; | ||
430 | UCHAR calc_cis_chksum; | ||
431 | UCHAR ecf_spare[7]; | ||
432 | UCHAR japan_call_sign[12]; | ||
433 | }; | ||
434 | |||
435 | struct startup_res_6 { | ||
436 | UCHAR startup_word; | ||
437 | UCHAR station_addr[ADDRLEN]; | ||
438 | UCHAR reserved; | ||
439 | UCHAR supp_rates[8]; | ||
440 | UCHAR japan_call_sign[12]; | ||
441 | UCHAR calc_prog_chksum; | ||
442 | UCHAR calc_cis_chksum; | ||
443 | UCHAR firmware_version[3]; | ||
444 | UCHAR asic_version; | ||
445 | UCHAR tib_length; | ||
446 | }; | ||
447 | |||
448 | struct start_join_net_params { | ||
449 | UCHAR net_type; | ||
450 | UCHAR ssid[ESSID_SIZE]; | ||
451 | UCHAR reserved; | ||
452 | UCHAR privacy_can_join; | ||
453 | }; | ||
454 | |||
455 | /****** Command Control Structure area at Shared ram offset 0x0400 ***********/ | ||
456 | /* Structures for command specific parameters (ccs.var) */ | ||
457 | struct update_param_cmd { | ||
458 | UCHAR object_id; | ||
459 | UCHAR number_objects; | ||
460 | UCHAR failure_cause; | ||
461 | }; | ||
462 | struct report_param_cmd { | ||
463 | UCHAR object_id; | ||
464 | UCHAR number_objects; | ||
465 | UCHAR failure_cause; | ||
466 | UCHAR length; | ||
467 | }; | ||
468 | struct start_network_cmd { | ||
469 | UCHAR update_param; | ||
470 | UCHAR bssid[ADDRLEN]; | ||
471 | UCHAR net_initiated; | ||
472 | UCHAR net_default_tx_rate; | ||
473 | UCHAR encryption; | ||
474 | }; | ||
475 | struct join_network_cmd { | ||
476 | UCHAR update_param; | ||
477 | UCHAR bssid[ADDRLEN]; | ||
478 | UCHAR net_initiated; | ||
479 | UCHAR net_default_tx_rate; | ||
480 | UCHAR encryption; | ||
481 | }; | ||
482 | struct tx_requested_cmd { | ||
483 | |||
484 | UCHAR tx_data_ptr[2]; | ||
485 | UCHAR tx_data_length[2]; | ||
486 | UCHAR host_reserved[2]; | ||
487 | UCHAR reserved[3]; | ||
488 | UCHAR tx_rate; | ||
489 | UCHAR pow_sav_mode; | ||
490 | UCHAR retries; | ||
491 | UCHAR antenna; | ||
492 | }; | ||
493 | struct tx_requested_cmd_4 { | ||
494 | |||
495 | UCHAR tx_data_ptr[2]; | ||
496 | UCHAR tx_data_length[2]; | ||
497 | UCHAR dest_addr[ADDRLEN]; | ||
498 | UCHAR pow_sav_mode; | ||
499 | UCHAR retries; | ||
500 | UCHAR station_id; | ||
501 | }; | ||
502 | struct memory_dump_cmd { | ||
503 | UCHAR memory_type; | ||
504 | UCHAR memory_ptr[2]; | ||
505 | UCHAR length; | ||
506 | }; | ||
507 | struct update_association_cmd { | ||
508 | UCHAR status; | ||
509 | UCHAR aid[2]; | ||
510 | }; | ||
511 | struct start_timer_cmd { | ||
512 | UCHAR duration[2]; | ||
513 | }; | ||
514 | |||
515 | struct ccs { | ||
516 | UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */ | ||
517 | /* 2 = command complete, 3 = failed */ | ||
518 | UCHAR cmd; /* command to ECF */ | ||
519 | UCHAR link; /* link to next CCS, FF=end of list */ | ||
520 | /* command specific parameters */ | ||
521 | union { | ||
522 | char reserved[13]; | ||
523 | struct update_param_cmd update_param; | ||
524 | struct report_param_cmd report_param; | ||
525 | UCHAR nummulticast; | ||
526 | UCHAR mode; | ||
527 | struct start_network_cmd start_network; | ||
528 | struct join_network_cmd join_network; | ||
529 | struct tx_requested_cmd tx_request; | ||
530 | struct memory_dump_cmd memory_dump; | ||
531 | struct update_association_cmd update_assoc; | ||
532 | struct start_timer_cmd start_timer; | ||
533 | } var; | ||
534 | }; | ||
535 | |||
536 | /*****************************************************************************/ | ||
537 | /* Transmit buffer structures */ | ||
538 | struct tib_structure { | ||
539 | UCHAR ccs_index; | ||
540 | UCHAR psm; | ||
541 | UCHAR pass_fail; | ||
542 | UCHAR retry_count; | ||
543 | UCHAR max_retries; | ||
544 | UCHAR frags_remaining; | ||
545 | UCHAR no_rb; | ||
546 | UCHAR rts_reqd; | ||
547 | UCHAR csma_tx_cntrl_2; | ||
548 | UCHAR sifs_tx_cntrl_2; | ||
549 | UCHAR tx_dma_addr_1[2]; | ||
550 | UCHAR tx_dma_addr_2[2]; | ||
551 | UCHAR var_dur_2mhz[2]; | ||
552 | UCHAR var_dur_1mhz[2]; | ||
553 | UCHAR max_dur_2mhz[2]; | ||
554 | UCHAR max_dur_1mhz[2]; | ||
555 | UCHAR hdr_len; | ||
556 | UCHAR max_frag_len[2]; | ||
557 | UCHAR var_len[2]; | ||
558 | UCHAR phy_hdr_4; | ||
559 | UCHAR mac_hdr_1; | ||
560 | UCHAR mac_hdr_2; | ||
561 | UCHAR sid[2]; | ||
562 | }; | ||
563 | |||
564 | struct phy_header { | ||
565 | UCHAR sfd[2]; | ||
566 | UCHAR hdr_3; | ||
567 | UCHAR hdr_4; | ||
568 | }; | ||
569 | struct rx_msg { | ||
570 | struct mac_header mac; | ||
571 | UCHAR var[1]; | ||
572 | }; | ||
573 | |||
574 | struct tx_msg { | ||
575 | struct tib_structure tib; | ||
576 | struct phy_header phy; | ||
577 | struct mac_header mac; | ||
578 | UCHAR var[1]; | ||
579 | }; | ||
580 | |||
581 | /****** ECF Receive Control Stucture (RCS) Area at Shared RAM offset 0x0800 */ | ||
582 | /* Structures for command specific parameters (rcs.var) */ | ||
583 | struct rx_packet_cmd { | ||
584 | UCHAR rx_data_ptr[2]; | ||
585 | UCHAR rx_data_length[2]; | ||
586 | UCHAR rx_sig_lev; | ||
587 | UCHAR next_frag_rcs_index; | ||
588 | UCHAR totalpacketlength[2]; | ||
589 | }; | ||
590 | struct rejoin_net_cmplt_cmd { | ||
591 | UCHAR reserved; | ||
592 | UCHAR bssid[ADDRLEN]; | ||
593 | }; | ||
594 | struct japan_call_sign_rxd { | ||
595 | UCHAR rxd_call_sign[8]; | ||
596 | UCHAR reserved[5]; | ||
597 | }; | ||
598 | |||
599 | struct rcs { | ||
600 | UCHAR buffer_status; | ||
601 | UCHAR interrupt_id; | ||
602 | UCHAR link_field; | ||
603 | /* command specific parameters */ | ||
604 | union { | ||
605 | UCHAR reserved[13]; | ||
606 | struct rx_packet_cmd rx_packet; | ||
607 | struct rejoin_net_cmplt_cmd rejoin_net_complete; | ||
608 | struct japan_call_sign_rxd japan_call_sign; | ||
609 | } var; | ||
610 | }; | ||
611 | |||
612 | /****** Startup parameter structures for both versions of firmware ***********/ | ||
613 | struct b4_startup_params { | ||
614 | UCHAR a_network_type; /* C_ADHOC, C_INFRA */ | ||
615 | UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ | ||
616 | UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ | ||
617 | UCHAR a_scanning_mode; /* passive 0, active 1 */ | ||
618 | UCHAR a_power_mgt_state; /* CAM 0, */ | ||
619 | UCHAR a_mac_addr[ADDRLEN]; /* */ | ||
620 | UCHAR a_frag_threshold[2]; /* 512 */ | ||
621 | UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ | ||
622 | UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ | ||
623 | UCHAR a_dtim_period; /* in beacons */ | ||
624 | UCHAR a_retry_max; /* */ | ||
625 | UCHAR a_ack_timeout; /* */ | ||
626 | UCHAR a_sifs; /* */ | ||
627 | UCHAR a_difs; /* */ | ||
628 | UCHAR a_pifs; /* */ | ||
629 | UCHAR a_rts_threshold[2]; /* */ | ||
630 | UCHAR a_scan_dwell_time[2]; /* */ | ||
631 | UCHAR a_max_scan_dwell_time[2]; /* */ | ||
632 | UCHAR a_assoc_resp_timeout_thresh; /* */ | ||
633 | UCHAR a_adhoc_scan_cycle_max; /* */ | ||
634 | UCHAR a_infra_scan_cycle_max; /* */ | ||
635 | UCHAR a_infra_super_scan_cycle_max; /* */ | ||
636 | UCHAR a_promiscuous_mode; /* */ | ||
637 | UCHAR a_unique_word[2]; /* */ | ||
638 | UCHAR a_slot_time; /* */ | ||
639 | UCHAR a_roaming_low_snr_thresh; /* */ | ||
640 | UCHAR a_low_snr_count_thresh; /* */ | ||
641 | UCHAR a_infra_missed_bcn_thresh; /* */ | ||
642 | UCHAR a_adhoc_missed_bcn_thresh; /* */ | ||
643 | UCHAR a_curr_country_code; /* C_USA */ | ||
644 | UCHAR a_hop_pattern; /* */ | ||
645 | UCHAR a_hop_pattern_length; /* */ | ||
646 | /* b4 - b5 differences start here */ | ||
647 | UCHAR a_cw_max; /* */ | ||
648 | UCHAR a_cw_min; /* */ | ||
649 | UCHAR a_noise_filter_gain; /* */ | ||
650 | UCHAR a_noise_limit_offset; /* */ | ||
651 | UCHAR a_det_rssi_thresh_offset; /* */ | ||
652 | UCHAR a_med_busy_thresh_offset; /* */ | ||
653 | UCHAR a_det_sync_thresh; /* */ | ||
654 | UCHAR a_test_mode; /* */ | ||
655 | UCHAR a_test_min_chan_num; /* */ | ||
656 | UCHAR a_test_max_chan_num; /* */ | ||
657 | UCHAR a_rx_tx_delay; /* */ | ||
658 | UCHAR a_current_bss_id[ADDRLEN]; /* */ | ||
659 | UCHAR a_hop_set; /* */ | ||
660 | }; | ||
661 | struct b5_startup_params { | ||
662 | UCHAR a_network_type; /* C_ADHOC, C_INFRA */ | ||
663 | UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ | ||
664 | UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ | ||
665 | UCHAR a_scanning_mode; /* passive 0, active 1 */ | ||
666 | UCHAR a_power_mgt_state; /* CAM 0, */ | ||
667 | UCHAR a_mac_addr[ADDRLEN]; /* */ | ||
668 | UCHAR a_frag_threshold[2]; /* 512 */ | ||
669 | UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ | ||
670 | UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ | ||
671 | UCHAR a_dtim_period; /* in beacons */ | ||
672 | UCHAR a_retry_max; /* 4 */ | ||
673 | UCHAR a_ack_timeout; /* */ | ||
674 | UCHAR a_sifs; /* */ | ||
675 | UCHAR a_difs; /* */ | ||
676 | UCHAR a_pifs; /* */ | ||
677 | UCHAR a_rts_threshold[2]; /* */ | ||
678 | UCHAR a_scan_dwell_time[2]; /* */ | ||
679 | UCHAR a_max_scan_dwell_time[2]; /* */ | ||
680 | UCHAR a_assoc_resp_timeout_thresh; /* */ | ||
681 | UCHAR a_adhoc_scan_cycle_max; /* */ | ||
682 | UCHAR a_infra_scan_cycle_max; /* */ | ||
683 | UCHAR a_infra_super_scan_cycle_max; /* */ | ||
684 | UCHAR a_promiscuous_mode; /* */ | ||
685 | UCHAR a_unique_word[2]; /* */ | ||
686 | UCHAR a_slot_time; /* */ | ||
687 | UCHAR a_roaming_low_snr_thresh; /* */ | ||
688 | UCHAR a_low_snr_count_thresh; /* */ | ||
689 | UCHAR a_infra_missed_bcn_thresh; /* */ | ||
690 | UCHAR a_adhoc_missed_bcn_thresh; /* */ | ||
691 | UCHAR a_curr_country_code; /* C_USA */ | ||
692 | UCHAR a_hop_pattern; /* */ | ||
693 | UCHAR a_hop_pattern_length; /* */ | ||
694 | /* b4 - b5 differences start here */ | ||
695 | UCHAR a_cw_max[2]; /* */ | ||
696 | UCHAR a_cw_min[2]; /* */ | ||
697 | UCHAR a_noise_filter_gain; /* */ | ||
698 | UCHAR a_noise_limit_offset; /* */ | ||
699 | UCHAR a_det_rssi_thresh_offset; /* */ | ||
700 | UCHAR a_med_busy_thresh_offset; /* */ | ||
701 | UCHAR a_det_sync_thresh; /* */ | ||
702 | UCHAR a_test_mode; /* */ | ||
703 | UCHAR a_test_min_chan_num; /* */ | ||
704 | UCHAR a_test_max_chan_num; /* */ | ||
705 | UCHAR a_allow_bcast_SSID_probe_rsp; | ||
706 | UCHAR a_privacy_must_start; | ||
707 | UCHAR a_privacy_can_join; | ||
708 | UCHAR a_basic_rate_set[8]; | ||
709 | }; | ||
710 | |||
711 | /*****************************************************************************/ | ||
712 | #define RAY_IOCG_PARMS (SIOCDEVPRIVATE) | ||
713 | #define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1) | ||
714 | #define RAY_DO_CMD (SIOCDEVPRIVATE + 2) | ||
715 | |||
716 | /****** ethernet <-> 802.11 translation **************************************/ | ||
717 | typedef struct snaphdr_t | ||
718 | { | ||
719 | UCHAR dsap; | ||
720 | UCHAR ssap; | ||
721 | UCHAR ctrl; | ||
722 | UCHAR org[3]; | ||
723 | UCHAR ethertype[2]; | ||
724 | } snaphdr_t; | ||
725 | |||
726 | #define BRIDGE_ENCAP 0xf80000 | ||
727 | #define RFC1042_ENCAP 0 | ||
728 | #define SNAP_ID 0x0003aaaa | ||
729 | #define RAY_IPX_TYPE 0x8137 | ||
730 | #define APPLEARP_TYPE 0x80f3 | ||
731 | /*****************************************************************************/ | ||
732 | #endif /* #ifndef RAYLINK_H */ | ||
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c new file mode 100644 index 000000000000..ec8cf29ffced --- /dev/null +++ b/drivers/net/wireless/strip.c | |||
@@ -0,0 +1,2843 @@ | |||
1 | /* | ||
2 | * Copyright 1996 The Board of Trustees of The Leland Stanford | ||
3 | * Junior University. All Rights Reserved. | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this | ||
6 | * software and its documentation for any purpose and without | ||
7 | * fee is hereby granted, provided that the above copyright | ||
8 | * notice appear in all copies. Stanford University | ||
9 | * makes no representations about the suitability of this | ||
10 | * software for any purpose. It is provided "as is" without | ||
11 | * express or implied warranty. | ||
12 | * | ||
13 | * strip.c This module implements Starmode Radio IP (STRIP) | ||
14 | * for kernel-based devices like TTY. It interfaces between a | ||
15 | * raw TTY, and the kernel's INET protocol layers (via DDI). | ||
16 | * | ||
17 | * Version: @(#)strip.c 1.3 July 1997 | ||
18 | * | ||
19 | * Author: Stuart Cheshire <cheshire@cs.stanford.edu> | ||
20 | * | ||
21 | * Fixes: v0.9 12th Feb 1996 (SC) | ||
22 | * New byte stuffing (2+6 run-length encoding) | ||
23 | * New watchdog timer task | ||
24 | * New Protocol key (SIP0) | ||
25 | * | ||
26 | * v0.9.1 3rd March 1996 (SC) | ||
27 | * Changed to dynamic device allocation -- no more compile | ||
28 | * time (or boot time) limit on the number of STRIP devices. | ||
29 | * | ||
30 | * v0.9.2 13th March 1996 (SC) | ||
31 | * Uses arp cache lookups (but doesn't send arp packets yet) | ||
32 | * | ||
33 | * v0.9.3 17th April 1996 (SC) | ||
34 | * Fixed bug where STR_ERROR flag was getting set unneccessarily | ||
35 | * (causing otherwise good packets to be unneccessarily dropped) | ||
36 | * | ||
37 | * v0.9.4 27th April 1996 (SC) | ||
38 | * First attempt at using "&COMMAND" Starmode AT commands | ||
39 | * | ||
40 | * v0.9.5 29th May 1996 (SC) | ||
41 | * First attempt at sending (unicast) ARP packets | ||
42 | * | ||
43 | * v0.9.6 5th June 1996 (Elliot) | ||
44 | * Put "message level" tags in every "printk" statement | ||
45 | * | ||
46 | * v0.9.7 13th June 1996 (laik) | ||
47 | * Added support for the /proc fs | ||
48 | * | ||
49 | * v0.9.8 July 1996 (Mema) | ||
50 | * Added packet logging | ||
51 | * | ||
52 | * v1.0 November 1996 (SC) | ||
53 | * Fixed (severe) memory leaks in the /proc fs code | ||
54 | * Fixed race conditions in the logging code | ||
55 | * | ||
56 | * v1.1 January 1997 (SC) | ||
57 | * Deleted packet logging (use tcpdump instead) | ||
58 | * Added support for Metricom Firmware v204 features | ||
59 | * (like message checksums) | ||
60 | * | ||
61 | * v1.2 January 1997 (SC) | ||
62 | * Put portables list back in | ||
63 | * | ||
64 | * v1.3 July 1997 (SC) | ||
65 | * Made STRIP driver set the radio's baud rate automatically. | ||
66 | * It is no longer necessarily to manually set the radio's | ||
67 | * rate permanently to 115200 -- the driver handles setting | ||
68 | * the rate automatically. | ||
69 | */ | ||
70 | |||
71 | #ifdef MODULE | ||
72 | static const char StripVersion[] = "1.3A-STUART.CHESHIRE-MODULAR"; | ||
73 | #else | ||
74 | static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; | ||
75 | #endif | ||
76 | |||
77 | #define TICKLE_TIMERS 0 | ||
78 | #define EXT_COUNTERS 1 | ||
79 | |||
80 | |||
81 | /************************************************************************/ | ||
82 | /* Header files */ | ||
83 | |||
84 | #include <linux/config.h> | ||
85 | #include <linux/kernel.h> | ||
86 | #include <linux/module.h> | ||
87 | #include <linux/init.h> | ||
88 | #include <linux/bitops.h> | ||
89 | #include <asm/system.h> | ||
90 | #include <asm/uaccess.h> | ||
91 | |||
92 | # include <linux/ctype.h> | ||
93 | #include <linux/string.h> | ||
94 | #include <linux/mm.h> | ||
95 | #include <linux/interrupt.h> | ||
96 | #include <linux/in.h> | ||
97 | #include <linux/tty.h> | ||
98 | #include <linux/errno.h> | ||
99 | #include <linux/netdevice.h> | ||
100 | #include <linux/inetdevice.h> | ||
101 | #include <linux/etherdevice.h> | ||
102 | #include <linux/skbuff.h> | ||
103 | #include <linux/if_arp.h> | ||
104 | #include <linux/if_strip.h> | ||
105 | #include <linux/proc_fs.h> | ||
106 | #include <linux/seq_file.h> | ||
107 | #include <linux/serial.h> | ||
108 | #include <linux/serialP.h> | ||
109 | #include <linux/rcupdate.h> | ||
110 | #include <net/arp.h> | ||
111 | |||
112 | #include <linux/ip.h> | ||
113 | #include <linux/tcp.h> | ||
114 | #include <linux/time.h> | ||
115 | |||
116 | |||
117 | /************************************************************************/ | ||
118 | /* Useful structures and definitions */ | ||
119 | |||
120 | /* | ||
121 | * A MetricomKey identifies the protocol being carried inside a Metricom | ||
122 | * Starmode packet. | ||
123 | */ | ||
124 | |||
125 | typedef union { | ||
126 | __u8 c[4]; | ||
127 | __u32 l; | ||
128 | } MetricomKey; | ||
129 | |||
130 | /* | ||
131 | * An IP address can be viewed as four bytes in memory (which is what it is) or as | ||
132 | * a single 32-bit long (which is convenient for assignment, equality testing etc.) | ||
133 | */ | ||
134 | |||
135 | typedef union { | ||
136 | __u8 b[4]; | ||
137 | __u32 l; | ||
138 | } IPaddr; | ||
139 | |||
140 | /* | ||
141 | * A MetricomAddressString is used to hold a printable representation of | ||
142 | * a Metricom address. | ||
143 | */ | ||
144 | |||
145 | typedef struct { | ||
146 | __u8 c[24]; | ||
147 | } MetricomAddressString; | ||
148 | |||
149 | /* Encapsulation can expand packet of size x to 65/64x + 1 | ||
150 | * Sent packet looks like "<CR>*<address>*<key><encaps payload><CR>" | ||
151 | * 1 1 1-18 1 4 ? 1 | ||
152 | * eg. <CR>*0000-1234*SIP0<encaps payload><CR> | ||
153 | * We allow 31 bytes for the stars, the key, the address and the <CR>s | ||
154 | */ | ||
155 | #define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) | ||
156 | |||
157 | /* | ||
158 | * A STRIP_Header is never really sent over the radio, but making a dummy | ||
159 | * header for internal use within the kernel that looks like an Ethernet | ||
160 | * header makes certain other software happier. For example, tcpdump | ||
161 | * already understands Ethernet headers. | ||
162 | */ | ||
163 | |||
164 | typedef struct { | ||
165 | MetricomAddress dst_addr; /* Destination address, e.g. "0000-1234" */ | ||
166 | MetricomAddress src_addr; /* Source address, e.g. "0000-5678" */ | ||
167 | unsigned short protocol; /* The protocol type, using Ethernet codes */ | ||
168 | } STRIP_Header; | ||
169 | |||
170 | typedef struct { | ||
171 | char c[60]; | ||
172 | } MetricomNode; | ||
173 | |||
174 | #define NODE_TABLE_SIZE 32 | ||
175 | typedef struct { | ||
176 | struct timeval timestamp; | ||
177 | int num_nodes; | ||
178 | MetricomNode node[NODE_TABLE_SIZE]; | ||
179 | } MetricomNodeTable; | ||
180 | |||
181 | enum { FALSE = 0, TRUE = 1 }; | ||
182 | |||
183 | /* | ||
184 | * Holds the radio's firmware version. | ||
185 | */ | ||
186 | typedef struct { | ||
187 | char c[50]; | ||
188 | } FirmwareVersion; | ||
189 | |||
190 | /* | ||
191 | * Holds the radio's serial number. | ||
192 | */ | ||
193 | typedef struct { | ||
194 | char c[18]; | ||
195 | } SerialNumber; | ||
196 | |||
197 | /* | ||
198 | * Holds the radio's battery voltage. | ||
199 | */ | ||
200 | typedef struct { | ||
201 | char c[11]; | ||
202 | } BatteryVoltage; | ||
203 | |||
204 | typedef struct { | ||
205 | char c[8]; | ||
206 | } char8; | ||
207 | |||
208 | enum { | ||
209 | NoStructure = 0, /* Really old firmware */ | ||
210 | StructuredMessages = 1, /* Parsable AT response msgs */ | ||
211 | ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ | ||
212 | } FirmwareLevel; | ||
213 | |||
214 | struct strip { | ||
215 | int magic; | ||
216 | /* | ||
217 | * These are pointers to the malloc()ed frame buffers. | ||
218 | */ | ||
219 | |||
220 | unsigned char *rx_buff; /* buffer for received IP packet */ | ||
221 | unsigned char *sx_buff; /* buffer for received serial data */ | ||
222 | int sx_count; /* received serial data counter */ | ||
223 | int sx_size; /* Serial buffer size */ | ||
224 | unsigned char *tx_buff; /* transmitter buffer */ | ||
225 | unsigned char *tx_head; /* pointer to next byte to XMIT */ | ||
226 | int tx_left; /* bytes left in XMIT queue */ | ||
227 | int tx_size; /* Serial buffer size */ | ||
228 | |||
229 | /* | ||
230 | * STRIP interface statistics. | ||
231 | */ | ||
232 | |||
233 | unsigned long rx_packets; /* inbound frames counter */ | ||
234 | unsigned long tx_packets; /* outbound frames counter */ | ||
235 | unsigned long rx_errors; /* Parity, etc. errors */ | ||
236 | unsigned long tx_errors; /* Planned stuff */ | ||
237 | unsigned long rx_dropped; /* No memory for skb */ | ||
238 | unsigned long tx_dropped; /* When MTU change */ | ||
239 | unsigned long rx_over_errors; /* Frame bigger then STRIP buf. */ | ||
240 | |||
241 | unsigned long pps_timer; /* Timer to determine pps */ | ||
242 | unsigned long rx_pps_count; /* Counter to determine pps */ | ||
243 | unsigned long tx_pps_count; /* Counter to determine pps */ | ||
244 | unsigned long sx_pps_count; /* Counter to determine pps */ | ||
245 | unsigned long rx_average_pps; /* rx packets per second * 8 */ | ||
246 | unsigned long tx_average_pps; /* tx packets per second * 8 */ | ||
247 | unsigned long sx_average_pps; /* sent packets per second * 8 */ | ||
248 | |||
249 | #ifdef EXT_COUNTERS | ||
250 | unsigned long rx_bytes; /* total received bytes */ | ||
251 | unsigned long tx_bytes; /* total received bytes */ | ||
252 | unsigned long rx_rbytes; /* bytes thru radio i/f */ | ||
253 | unsigned long tx_rbytes; /* bytes thru radio i/f */ | ||
254 | unsigned long rx_sbytes; /* tot bytes thru serial i/f */ | ||
255 | unsigned long tx_sbytes; /* tot bytes thru serial i/f */ | ||
256 | unsigned long rx_ebytes; /* tot stat/err bytes */ | ||
257 | unsigned long tx_ebytes; /* tot stat/err bytes */ | ||
258 | #endif | ||
259 | |||
260 | /* | ||
261 | * Internal variables. | ||
262 | */ | ||
263 | |||
264 | struct list_head list; /* Linked list of devices */ | ||
265 | |||
266 | int discard; /* Set if serial error */ | ||
267 | int working; /* Is radio working correctly? */ | ||
268 | int firmware_level; /* Message structuring level */ | ||
269 | int next_command; /* Next periodic command */ | ||
270 | unsigned int user_baud; /* The user-selected baud rate */ | ||
271 | int mtu; /* Our mtu (to spot changes!) */ | ||
272 | long watchdog_doprobe; /* Next time to test the radio */ | ||
273 | long watchdog_doreset; /* Time to do next reset */ | ||
274 | long gratuitous_arp; /* Time to send next ARP refresh */ | ||
275 | long arp_interval; /* Next ARP interval */ | ||
276 | struct timer_list idle_timer; /* For periodic wakeup calls */ | ||
277 | MetricomAddress true_dev_addr; /* True address of radio */ | ||
278 | int manual_dev_addr; /* Hack: See note below */ | ||
279 | |||
280 | FirmwareVersion firmware_version; /* The radio's firmware version */ | ||
281 | SerialNumber serial_number; /* The radio's serial number */ | ||
282 | BatteryVoltage battery_voltage; /* The radio's battery voltage */ | ||
283 | |||
284 | /* | ||
285 | * Other useful structures. | ||
286 | */ | ||
287 | |||
288 | struct tty_struct *tty; /* ptr to TTY structure */ | ||
289 | struct net_device *dev; /* Our device structure */ | ||
290 | |||
291 | /* | ||
292 | * Neighbour radio records | ||
293 | */ | ||
294 | |||
295 | MetricomNodeTable portables; | ||
296 | MetricomNodeTable poletops; | ||
297 | }; | ||
298 | |||
299 | /* | ||
300 | * Note: manual_dev_addr hack | ||
301 | * | ||
302 | * It is not possible to change the hardware address of a Metricom radio, | ||
303 | * or to send packets with a user-specified hardware source address, thus | ||
304 | * trying to manually set a hardware source address is a questionable | ||
305 | * thing to do. However, if the user *does* manually set the hardware | ||
306 | * source address of a STRIP interface, then the kernel will believe it, | ||
307 | * and use it in certain places. For example, the hardware address listed | ||
308 | * by ifconfig will be the manual address, not the true one. | ||
309 | * (Both addresses are listed in /proc/net/strip.) | ||
310 | * Also, ARP packets will be sent out giving the user-specified address as | ||
311 | * the source address, not the real address. This is dangerous, because | ||
312 | * it means you won't receive any replies -- the ARP replies will go to | ||
313 | * the specified address, which will be some other radio. The case where | ||
314 | * this is useful is when that other radio is also connected to the same | ||
315 | * machine. This allows you to connect a pair of radios to one machine, | ||
316 | * and to use one exclusively for inbound traffic, and the other | ||
317 | * exclusively for outbound traffic. Pretty neat, huh? | ||
318 | * | ||
319 | * Here's the full procedure to set this up: | ||
320 | * | ||
321 | * 1. "slattach" two interfaces, e.g. st0 for outgoing packets, | ||
322 | * and st1 for incoming packets | ||
323 | * | ||
324 | * 2. "ifconfig" st0 (outbound radio) to have the hardware address | ||
325 | * which is the real hardware address of st1 (inbound radio). | ||
326 | * Now when it sends out packets, it will masquerade as st1, and | ||
327 | * replies will be sent to that radio, which is exactly what we want. | ||
328 | * | ||
329 | * 3. Set the route table entry ("route add default ..." or | ||
330 | * "route add -net ...", as appropriate) to send packets via the st0 | ||
331 | * interface (outbound radio). Do not add any route which sends packets | ||
332 | * out via the st1 interface -- that radio is for inbound traffic only. | ||
333 | * | ||
334 | * 4. "ifconfig" st1 (inbound radio) to have hardware address zero. | ||
335 | * This tells the STRIP driver to "shut down" that interface and not | ||
336 | * send any packets through it. In particular, it stops sending the | ||
337 | * periodic gratuitous ARP packets that a STRIP interface normally sends. | ||
338 | * Also, when packets arrive on that interface, it will search the | ||
339 | * interface list to see if there is another interface who's manual | ||
340 | * hardware address matches its own real address (i.e. st0 in this | ||
341 | * example) and if so it will transfer ownership of the skbuff to | ||
342 | * that interface, so that it looks to the kernel as if the packet | ||
343 | * arrived on that interface. This is necessary because when the | ||
344 | * kernel sends an ARP packet on st0, it expects to get a reply on | ||
345 | * st0, and if it sees the reply come from st1 then it will ignore | ||
346 | * it (to be accurate, it puts the entry in the ARP table, but | ||
347 | * labelled in such a way that st0 can't use it). | ||
348 | * | ||
349 | * Thanks to Petros Maniatis for coming up with the idea of splitting | ||
350 | * inbound and outbound traffic between two interfaces, which turned | ||
351 | * out to be really easy to implement, even if it is a bit of a hack. | ||
352 | * | ||
353 | * Having set a manual address on an interface, you can restore it | ||
354 | * to automatic operation (where the address is automatically kept | ||
355 | * consistent with the real address of the radio) by setting a manual | ||
356 | * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF" | ||
357 | * This 'turns off' manual override mode for the device address. | ||
358 | * | ||
359 | * Note: The IEEE 802 headers reported in tcpdump will show the *real* | ||
360 | * radio addresses the packets were sent and received from, so that you | ||
361 | * can see what is really going on with packets, and which interfaces | ||
362 | * they are really going through. | ||
363 | */ | ||
364 | |||
365 | |||
366 | /************************************************************************/ | ||
367 | /* Constants */ | ||
368 | |||
369 | /* | ||
370 | * CommandString1 works on all radios | ||
371 | * Other CommandStrings are only used with firmware that provides structured responses. | ||
372 | * | ||
373 | * ats319=1 Enables Info message for node additions and deletions | ||
374 | * ats319=2 Enables Info message for a new best node | ||
375 | * ats319=4 Enables checksums | ||
376 | * ats319=8 Enables ACK messages | ||
377 | */ | ||
378 | |||
379 | static const int MaxCommandStringLength = 32; | ||
380 | static const int CompatibilityCommand = 1; | ||
381 | |||
382 | static const char CommandString0[] = "*&COMMAND*ATS319=7"; /* Turn on checksums & info messages */ | ||
383 | static const char CommandString1[] = "*&COMMAND*ATS305?"; /* Query radio name */ | ||
384 | static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery voltage */ | ||
385 | static const char CommandString3[] = "*&COMMAND*ATS300?"; /* Query version information */ | ||
386 | static const char CommandString4[] = "*&COMMAND*ATS311?"; /* Query poletop list */ | ||
387 | static const char CommandString5[] = "*&COMMAND*AT~LA"; /* Query portables list */ | ||
388 | typedef struct { | ||
389 | const char *string; | ||
390 | long length; | ||
391 | } StringDescriptor; | ||
392 | |||
393 | static const StringDescriptor CommandString[] = { | ||
394 | {CommandString0, sizeof(CommandString0) - 1}, | ||
395 | {CommandString1, sizeof(CommandString1) - 1}, | ||
396 | {CommandString2, sizeof(CommandString2) - 1}, | ||
397 | {CommandString3, sizeof(CommandString3) - 1}, | ||
398 | {CommandString4, sizeof(CommandString4) - 1}, | ||
399 | {CommandString5, sizeof(CommandString5) - 1} | ||
400 | }; | ||
401 | |||
402 | #define GOT_ALL_RADIO_INFO(S) \ | ||
403 | ((S)->firmware_version.c[0] && \ | ||
404 | (S)->battery_voltage.c[0] && \ | ||
405 | memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address))) | ||
406 | |||
407 | static const char hextable[16] = "0123456789ABCDEF"; | ||
408 | |||
409 | static const MetricomAddress zero_address; | ||
410 | static const MetricomAddress broadcast_address = | ||
411 | { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; | ||
412 | |||
413 | static const MetricomKey SIP0Key = { "SIP0" }; | ||
414 | static const MetricomKey ARP0Key = { "ARP0" }; | ||
415 | static const MetricomKey ATR_Key = { "ATR " }; | ||
416 | static const MetricomKey ACK_Key = { "ACK_" }; | ||
417 | static const MetricomKey INF_Key = { "INF_" }; | ||
418 | static const MetricomKey ERR_Key = { "ERR_" }; | ||
419 | |||
420 | static const long MaxARPInterval = 60 * HZ; /* One minute */ | ||
421 | |||
422 | /* | ||
423 | * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for | ||
424 | * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion | ||
425 | * for STRIP encoding, that translates to a maximum payload MTU of 1155. | ||
426 | * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes | ||
427 | * long, including IP header, UDP header, and NFS header. Setting the STRIP | ||
428 | * MTU to 1152 allows us to send default sized NFS packets without fragmentation. | ||
429 | */ | ||
430 | static const unsigned short MAX_SEND_MTU = 1152; | ||
431 | static const unsigned short MAX_RECV_MTU = 1500; /* Hoping for Ethernet sized packets in the future! */ | ||
432 | static const unsigned short DEFAULT_STRIP_MTU = 1152; | ||
433 | static const int STRIP_MAGIC = 0x5303; | ||
434 | static const long LongTime = 0x7FFFFFFF; | ||
435 | |||
436 | /************************************************************************/ | ||
437 | /* Global variables */ | ||
438 | |||
439 | static LIST_HEAD(strip_list); | ||
440 | static DEFINE_SPINLOCK(strip_lock); | ||
441 | |||
442 | /************************************************************************/ | ||
443 | /* Macros */ | ||
444 | |||
445 | /* Returns TRUE if text T begins with prefix P */ | ||
446 | #define has_prefix(T,L,P) (((L) >= sizeof(P)-1) && !strncmp((T), (P), sizeof(P)-1)) | ||
447 | |||
448 | /* Returns TRUE if text T of length L is equal to string S */ | ||
449 | #define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1)) | ||
450 | |||
451 | #define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' : \ | ||
452 | (X)>='a' && (X)<='f' ? (X)-'a'+10 : \ | ||
453 | (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 ) | ||
454 | |||
455 | #define READHEX16(X) ((__u16)(READHEX(X))) | ||
456 | |||
457 | #define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0) | ||
458 | |||
459 | #define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)])) | ||
460 | |||
461 | #define JIFFIE_TO_SEC(X) ((X) / HZ) | ||
462 | |||
463 | |||
464 | /************************************************************************/ | ||
465 | /* Utility routines */ | ||
466 | |||
467 | static int arp_query(unsigned char *haddr, u32 paddr, | ||
468 | struct net_device *dev) | ||
469 | { | ||
470 | struct neighbour *neighbor_entry; | ||
471 | |||
472 | neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev); | ||
473 | |||
474 | if (neighbor_entry != NULL) { | ||
475 | neighbor_entry->used = jiffies; | ||
476 | if (neighbor_entry->nud_state & NUD_VALID) { | ||
477 | memcpy(haddr, neighbor_entry->ha, dev->addr_len); | ||
478 | return 1; | ||
479 | } | ||
480 | } | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static void DumpData(char *msg, struct strip *strip_info, __u8 * ptr, | ||
485 | __u8 * end) | ||
486 | { | ||
487 | static const int MAX_DumpData = 80; | ||
488 | __u8 pkt_text[MAX_DumpData], *p = pkt_text; | ||
489 | |||
490 | *p++ = '\"'; | ||
491 | |||
492 | while (ptr < end && p < &pkt_text[MAX_DumpData - 4]) { | ||
493 | if (*ptr == '\\') { | ||
494 | *p++ = '\\'; | ||
495 | *p++ = '\\'; | ||
496 | } else { | ||
497 | if (*ptr >= 32 && *ptr <= 126) { | ||
498 | *p++ = *ptr; | ||
499 | } else { | ||
500 | sprintf(p, "\\%02X", *ptr); | ||
501 | p += 3; | ||
502 | } | ||
503 | } | ||
504 | ptr++; | ||
505 | } | ||
506 | |||
507 | if (ptr == end) | ||
508 | *p++ = '\"'; | ||
509 | *p++ = 0; | ||
510 | |||
511 | printk(KERN_INFO "%s: %-13s%s\n", strip_info->dev->name, msg, pkt_text); | ||
512 | } | ||
513 | |||
514 | |||
515 | /************************************************************************/ | ||
516 | /* Byte stuffing/unstuffing routines */ | ||
517 | |||
518 | /* Stuffing scheme: | ||
519 | * 00 Unused (reserved character) | ||
520 | * 01-3F Run of 2-64 different characters | ||
521 | * 40-7F Run of 1-64 different characters plus a single zero at the end | ||
522 | * 80-BF Run of 1-64 of the same character | ||
523 | * C0-FF Run of 1-64 zeroes (ASCII 0) | ||
524 | */ | ||
525 | |||
526 | typedef enum { | ||
527 | Stuff_Diff = 0x00, | ||
528 | Stuff_DiffZero = 0x40, | ||
529 | Stuff_Same = 0x80, | ||
530 | Stuff_Zero = 0xC0, | ||
531 | Stuff_NoCode = 0xFF, /* Special code, meaning no code selected */ | ||
532 | |||
533 | Stuff_CodeMask = 0xC0, | ||
534 | Stuff_CountMask = 0x3F, | ||
535 | Stuff_MaxCount = 0x3F, | ||
536 | Stuff_Magic = 0x0D /* The value we are eliminating */ | ||
537 | } StuffingCode; | ||
538 | |||
539 | /* StuffData encodes the data starting at "src" for "length" bytes. | ||
540 | * It writes it to the buffer pointed to by "dst" (which must be at least | ||
541 | * as long as 1 + 65/64 of the input length). The output may be up to 1.6% | ||
542 | * larger than the input for pathological input, but will usually be smaller. | ||
543 | * StuffData returns the new value of the dst pointer as its result. | ||
544 | * "code_ptr_ptr" points to a "__u8 *" which is used to hold encoding state | ||
545 | * between calls, allowing an encoded packet to be incrementally built up | ||
546 | * from small parts. On the first call, the "__u8 *" pointed to should be | ||
547 | * initialized to NULL; between subsequent calls the calling routine should | ||
548 | * leave the value alone and simply pass it back unchanged so that the | ||
549 | * encoder can recover its current state. | ||
550 | */ | ||
551 | |||
552 | #define StuffData_FinishBlock(X) \ | ||
553 | (*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode) | ||
554 | |||
555 | static __u8 *StuffData(__u8 * src, __u32 length, __u8 * dst, | ||
556 | __u8 ** code_ptr_ptr) | ||
557 | { | ||
558 | __u8 *end = src + length; | ||
559 | __u8 *code_ptr = *code_ptr_ptr; | ||
560 | __u8 code = Stuff_NoCode, count = 0; | ||
561 | |||
562 | if (!length) | ||
563 | return (dst); | ||
564 | |||
565 | if (code_ptr) { | ||
566 | /* | ||
567 | * Recover state from last call, if applicable | ||
568 | */ | ||
569 | code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask; | ||
570 | count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask; | ||
571 | } | ||
572 | |||
573 | while (src < end) { | ||
574 | switch (code) { | ||
575 | /* Stuff_NoCode: If no current code, select one */ | ||
576 | case Stuff_NoCode: | ||
577 | /* Record where we're going to put this code */ | ||
578 | code_ptr = dst++; | ||
579 | count = 0; /* Reset the count (zero means one instance) */ | ||
580 | /* Tentatively start a new block */ | ||
581 | if (*src == 0) { | ||
582 | code = Stuff_Zero; | ||
583 | src++; | ||
584 | } else { | ||
585 | code = Stuff_Same; | ||
586 | *dst++ = *src++ ^ Stuff_Magic; | ||
587 | } | ||
588 | /* Note: We optimistically assume run of same -- */ | ||
589 | /* which will be fixed later in Stuff_Same */ | ||
590 | /* if it turns out not to be true. */ | ||
591 | break; | ||
592 | |||
593 | /* Stuff_Zero: We already have at least one zero encoded */ | ||
594 | case Stuff_Zero: | ||
595 | /* If another zero, count it, else finish this code block */ | ||
596 | if (*src == 0) { | ||
597 | count++; | ||
598 | src++; | ||
599 | } else { | ||
600 | StuffData_FinishBlock(Stuff_Zero + count); | ||
601 | } | ||
602 | break; | ||
603 | |||
604 | /* Stuff_Same: We already have at least one byte encoded */ | ||
605 | case Stuff_Same: | ||
606 | /* If another one the same, count it */ | ||
607 | if ((*src ^ Stuff_Magic) == code_ptr[1]) { | ||
608 | count++; | ||
609 | src++; | ||
610 | break; | ||
611 | } | ||
612 | /* else, this byte does not match this block. */ | ||
613 | /* If we already have two or more bytes encoded, finish this code block */ | ||
614 | if (count) { | ||
615 | StuffData_FinishBlock(Stuff_Same + count); | ||
616 | break; | ||
617 | } | ||
618 | /* else, we only have one so far, so switch to Stuff_Diff code */ | ||
619 | code = Stuff_Diff; | ||
620 | /* and fall through to Stuff_Diff case below | ||
621 | * Note cunning cleverness here: case Stuff_Diff compares | ||
622 | * the current character with the previous two to see if it | ||
623 | * has a run of three the same. Won't this be an error if | ||
624 | * there aren't two previous characters stored to compare with? | ||
625 | * No. Because we know the current character is *not* the same | ||
626 | * as the previous one, the first test below will necessarily | ||
627 | * fail and the send half of the "if" won't be executed. | ||
628 | */ | ||
629 | |||
630 | /* Stuff_Diff: We have at least two *different* bytes encoded */ | ||
631 | case Stuff_Diff: | ||
632 | /* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */ | ||
633 | if (*src == 0) { | ||
634 | StuffData_FinishBlock(Stuff_DiffZero + | ||
635 | count); | ||
636 | } | ||
637 | /* else, if we have three in a row, it is worth starting a Stuff_Same block */ | ||
638 | else if ((*src ^ Stuff_Magic) == dst[-1] | ||
639 | && dst[-1] == dst[-2]) { | ||
640 | /* Back off the last two characters we encoded */ | ||
641 | code += count - 2; | ||
642 | /* Note: "Stuff_Diff + 0" is an illegal code */ | ||
643 | if (code == Stuff_Diff + 0) { | ||
644 | code = Stuff_Same + 0; | ||
645 | } | ||
646 | StuffData_FinishBlock(code); | ||
647 | code_ptr = dst - 2; | ||
648 | /* dst[-1] already holds the correct value */ | ||
649 | count = 2; /* 2 means three bytes encoded */ | ||
650 | code = Stuff_Same; | ||
651 | } | ||
652 | /* else, another different byte, so add it to the block */ | ||
653 | else { | ||
654 | *dst++ = *src ^ Stuff_Magic; | ||
655 | count++; | ||
656 | } | ||
657 | src++; /* Consume the byte */ | ||
658 | break; | ||
659 | } | ||
660 | if (count == Stuff_MaxCount) { | ||
661 | StuffData_FinishBlock(code + count); | ||
662 | } | ||
663 | } | ||
664 | if (code == Stuff_NoCode) { | ||
665 | *code_ptr_ptr = NULL; | ||
666 | } else { | ||
667 | *code_ptr_ptr = code_ptr; | ||
668 | StuffData_FinishBlock(code + count); | ||
669 | } | ||
670 | return (dst); | ||
671 | } | ||
672 | |||
673 | /* | ||
674 | * UnStuffData decodes the data at "src", up to (but not including) "end". | ||
675 | * It writes the decoded data into the buffer pointed to by "dst", up to a | ||
676 | * maximum of "dst_length", and returns the new value of "src" so that a | ||
677 | * follow-on call can read more data, continuing from where the first left off. | ||
678 | * | ||
679 | * There are three types of results: | ||
680 | * 1. The source data runs out before extracting "dst_length" bytes: | ||
681 | * UnStuffData returns NULL to indicate failure. | ||
682 | * 2. The source data produces exactly "dst_length" bytes: | ||
683 | * UnStuffData returns new_src = end to indicate that all bytes were consumed. | ||
684 | * 3. "dst_length" bytes are extracted, with more remaining. | ||
685 | * UnStuffData returns new_src < end to indicate that there are more bytes | ||
686 | * to be read. | ||
687 | * | ||
688 | * Note: The decoding may be destructive, in that it may alter the source | ||
689 | * data in the process of decoding it (this is necessary to allow a follow-on | ||
690 | * call to resume correctly). | ||
691 | */ | ||
692 | |||
693 | static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst, | ||
694 | __u32 dst_length) | ||
695 | { | ||
696 | __u8 *dst_end = dst + dst_length; | ||
697 | /* Sanity check */ | ||
698 | if (!src || !end || !dst || !dst_length) | ||
699 | return (NULL); | ||
700 | while (src < end && dst < dst_end) { | ||
701 | int count = (*src ^ Stuff_Magic) & Stuff_CountMask; | ||
702 | switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) { | ||
703 | case Stuff_Diff: | ||
704 | if (src + 1 + count >= end) | ||
705 | return (NULL); | ||
706 | do { | ||
707 | *dst++ = *++src ^ Stuff_Magic; | ||
708 | } | ||
709 | while (--count >= 0 && dst < dst_end); | ||
710 | if (count < 0) | ||
711 | src += 1; | ||
712 | else { | ||
713 | if (count == 0) | ||
714 | *src = Stuff_Same ^ Stuff_Magic; | ||
715 | else | ||
716 | *src = | ||
717 | (Stuff_Diff + | ||
718 | count) ^ Stuff_Magic; | ||
719 | } | ||
720 | break; | ||
721 | case Stuff_DiffZero: | ||
722 | if (src + 1 + count >= end) | ||
723 | return (NULL); | ||
724 | do { | ||
725 | *dst++ = *++src ^ Stuff_Magic; | ||
726 | } | ||
727 | while (--count >= 0 && dst < dst_end); | ||
728 | if (count < 0) | ||
729 | *src = Stuff_Zero ^ Stuff_Magic; | ||
730 | else | ||
731 | *src = | ||
732 | (Stuff_DiffZero + count) ^ Stuff_Magic; | ||
733 | break; | ||
734 | case Stuff_Same: | ||
735 | if (src + 1 >= end) | ||
736 | return (NULL); | ||
737 | do { | ||
738 | *dst++ = src[1] ^ Stuff_Magic; | ||
739 | } | ||
740 | while (--count >= 0 && dst < dst_end); | ||
741 | if (count < 0) | ||
742 | src += 2; | ||
743 | else | ||
744 | *src = (Stuff_Same + count) ^ Stuff_Magic; | ||
745 | break; | ||
746 | case Stuff_Zero: | ||
747 | do { | ||
748 | *dst++ = 0; | ||
749 | } | ||
750 | while (--count >= 0 && dst < dst_end); | ||
751 | if (count < 0) | ||
752 | src += 1; | ||
753 | else | ||
754 | *src = (Stuff_Zero + count) ^ Stuff_Magic; | ||
755 | break; | ||
756 | } | ||
757 | } | ||
758 | if (dst < dst_end) | ||
759 | return (NULL); | ||
760 | else | ||
761 | return (src); | ||
762 | } | ||
763 | |||
764 | |||
765 | /************************************************************************/ | ||
766 | /* General routines for STRIP */ | ||
767 | |||
768 | /* | ||
769 | * get_baud returns the current baud rate, as one of the constants defined in | ||
770 | * termbits.h | ||
771 | * If the user has issued a baud rate override using the 'setserial' command | ||
772 | * and the logical current rate is set to 38.4, then the true baud rate | ||
773 | * currently in effect (57.6 or 115.2) is returned. | ||
774 | */ | ||
775 | static unsigned int get_baud(struct tty_struct *tty) | ||
776 | { | ||
777 | if (!tty || !tty->termios) | ||
778 | return (0); | ||
779 | if ((tty->termios->c_cflag & CBAUD) == B38400 && tty->driver_data) { | ||
780 | struct async_struct *info = | ||
781 | (struct async_struct *) tty->driver_data; | ||
782 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | ||
783 | return (B57600); | ||
784 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | ||
785 | return (B115200); | ||
786 | } | ||
787 | return (tty->termios->c_cflag & CBAUD); | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * set_baud sets the baud rate to the rate defined by baudcode | ||
792 | * Note: The rate B38400 should be avoided, because the user may have | ||
793 | * issued a 'setserial' speed override to map that to a different speed. | ||
794 | * We could achieve a true rate of 38400 if we needed to by cancelling | ||
795 | * any user speed override that is in place, but that might annoy the | ||
796 | * user, so it is simplest to just avoid using 38400. | ||
797 | */ | ||
798 | static void set_baud(struct tty_struct *tty, unsigned int baudcode) | ||
799 | { | ||
800 | struct termios old_termios = *(tty->termios); | ||
801 | tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */ | ||
802 | tty->termios->c_cflag |= baudcode; /* Set the new baud setting */ | ||
803 | tty->driver->set_termios(tty, &old_termios); | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * Convert a string to a Metricom Address. | ||
808 | */ | ||
809 | |||
810 | #define IS_RADIO_ADDRESS(p) ( \ | ||
811 | isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ | ||
812 | (p)[4] == '-' && \ | ||
813 | isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) | ||
814 | |||
815 | static int string_to_radio_address(MetricomAddress * addr, __u8 * p) | ||
816 | { | ||
817 | if (!IS_RADIO_ADDRESS(p)) | ||
818 | return (1); | ||
819 | addr->c[0] = 0; | ||
820 | addr->c[1] = 0; | ||
821 | addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); | ||
822 | addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); | ||
823 | addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); | ||
824 | addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); | ||
825 | return (0); | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * Convert a Metricom Address to a string. | ||
830 | */ | ||
831 | |||
832 | static __u8 *radio_address_to_string(const MetricomAddress * addr, | ||
833 | MetricomAddressString * p) | ||
834 | { | ||
835 | sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], | ||
836 | addr->c[4], addr->c[5]); | ||
837 | return (p->c); | ||
838 | } | ||
839 | |||
840 | /* | ||
841 | * Note: Must make sure sx_size is big enough to receive a stuffed | ||
842 | * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's | ||
843 | * big enough to receive a large radio neighbour list (currently 4K). | ||
844 | */ | ||
845 | |||
846 | static int allocate_buffers(struct strip *strip_info, int mtu) | ||
847 | { | ||
848 | struct net_device *dev = strip_info->dev; | ||
849 | int sx_size = max_t(int, STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096); | ||
850 | int tx_size = STRIP_ENCAP_SIZE(mtu) + MaxCommandStringLength; | ||
851 | __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC); | ||
852 | __u8 *s = kmalloc(sx_size, GFP_ATOMIC); | ||
853 | __u8 *t = kmalloc(tx_size, GFP_ATOMIC); | ||
854 | if (r && s && t) { | ||
855 | strip_info->rx_buff = r; | ||
856 | strip_info->sx_buff = s; | ||
857 | strip_info->tx_buff = t; | ||
858 | strip_info->sx_size = sx_size; | ||
859 | strip_info->tx_size = tx_size; | ||
860 | strip_info->mtu = dev->mtu = mtu; | ||
861 | return (1); | ||
862 | } | ||
863 | if (r) | ||
864 | kfree(r); | ||
865 | if (s) | ||
866 | kfree(s); | ||
867 | if (t) | ||
868 | kfree(t); | ||
869 | return (0); | ||
870 | } | ||
871 | |||
872 | /* | ||
873 | * MTU has been changed by the IP layer. | ||
874 | * We could be in | ||
875 | * an upcall from the tty driver, or in an ip packet queue. | ||
876 | */ | ||
877 | static int strip_change_mtu(struct net_device *dev, int new_mtu) | ||
878 | { | ||
879 | struct strip *strip_info = netdev_priv(dev); | ||
880 | int old_mtu = strip_info->mtu; | ||
881 | unsigned char *orbuff = strip_info->rx_buff; | ||
882 | unsigned char *osbuff = strip_info->sx_buff; | ||
883 | unsigned char *otbuff = strip_info->tx_buff; | ||
884 | |||
885 | if (new_mtu > MAX_SEND_MTU) { | ||
886 | printk(KERN_ERR | ||
887 | "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", | ||
888 | strip_info->dev->name, MAX_SEND_MTU); | ||
889 | return -EINVAL; | ||
890 | } | ||
891 | |||
892 | spin_lock_bh(&strip_lock); | ||
893 | if (!allocate_buffers(strip_info, new_mtu)) { | ||
894 | printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", | ||
895 | strip_info->dev->name); | ||
896 | spin_unlock_bh(&strip_lock); | ||
897 | return -ENOMEM; | ||
898 | } | ||
899 | |||
900 | if (strip_info->sx_count) { | ||
901 | if (strip_info->sx_count <= strip_info->sx_size) | ||
902 | memcpy(strip_info->sx_buff, osbuff, | ||
903 | strip_info->sx_count); | ||
904 | else { | ||
905 | strip_info->discard = strip_info->sx_count; | ||
906 | strip_info->rx_over_errors++; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | if (strip_info->tx_left) { | ||
911 | if (strip_info->tx_left <= strip_info->tx_size) | ||
912 | memcpy(strip_info->tx_buff, strip_info->tx_head, | ||
913 | strip_info->tx_left); | ||
914 | else { | ||
915 | strip_info->tx_left = 0; | ||
916 | strip_info->tx_dropped++; | ||
917 | } | ||
918 | } | ||
919 | strip_info->tx_head = strip_info->tx_buff; | ||
920 | spin_unlock_bh(&strip_lock); | ||
921 | |||
922 | printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", | ||
923 | strip_info->dev->name, old_mtu, strip_info->mtu); | ||
924 | |||
925 | if (orbuff) | ||
926 | kfree(orbuff); | ||
927 | if (osbuff) | ||
928 | kfree(osbuff); | ||
929 | if (otbuff) | ||
930 | kfree(otbuff); | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static void strip_unlock(struct strip *strip_info) | ||
936 | { | ||
937 | /* | ||
938 | * Set the timer to go off in one second. | ||
939 | */ | ||
940 | strip_info->idle_timer.expires = jiffies + 1 * HZ; | ||
941 | add_timer(&strip_info->idle_timer); | ||
942 | netif_wake_queue(strip_info->dev); | ||
943 | } | ||
944 | |||
945 | |||
946 | |||
947 | /* | ||
948 | * If the time is in the near future, time_delta prints the number of | ||
949 | * seconds to go into the buffer and returns the address of the buffer. | ||
950 | * If the time is not in the near future, it returns the address of the | ||
951 | * string "Not scheduled" The buffer must be long enough to contain the | ||
952 | * ascii representation of the number plus 9 charactes for the " seconds" | ||
953 | * and the null character. | ||
954 | */ | ||
955 | #ifdef CONFIG_PROC_FS | ||
956 | static char *time_delta(char buffer[], long time) | ||
957 | { | ||
958 | time -= jiffies; | ||
959 | if (time > LongTime / 2) | ||
960 | return ("Not scheduled"); | ||
961 | if (time < 0) | ||
962 | time = 0; /* Don't print negative times */ | ||
963 | sprintf(buffer, "%ld seconds", time / HZ); | ||
964 | return (buffer); | ||
965 | } | ||
966 | |||
967 | /* get Nth element of the linked list */ | ||
968 | static struct strip *strip_get_idx(loff_t pos) | ||
969 | { | ||
970 | struct list_head *l; | ||
971 | int i = 0; | ||
972 | |||
973 | list_for_each_rcu(l, &strip_list) { | ||
974 | if (pos == i) | ||
975 | return list_entry(l, struct strip, list); | ||
976 | ++i; | ||
977 | } | ||
978 | return NULL; | ||
979 | } | ||
980 | |||
981 | static void *strip_seq_start(struct seq_file *seq, loff_t *pos) | ||
982 | { | ||
983 | rcu_read_lock(); | ||
984 | return *pos ? strip_get_idx(*pos - 1) : SEQ_START_TOKEN; | ||
985 | } | ||
986 | |||
987 | static void *strip_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
988 | { | ||
989 | struct list_head *l; | ||
990 | struct strip *s; | ||
991 | |||
992 | ++*pos; | ||
993 | if (v == SEQ_START_TOKEN) | ||
994 | return strip_get_idx(1); | ||
995 | |||
996 | s = v; | ||
997 | l = &s->list; | ||
998 | list_for_each_continue_rcu(l, &strip_list) { | ||
999 | return list_entry(l, struct strip, list); | ||
1000 | } | ||
1001 | return NULL; | ||
1002 | } | ||
1003 | |||
1004 | static void strip_seq_stop(struct seq_file *seq, void *v) | ||
1005 | { | ||
1006 | rcu_read_unlock(); | ||
1007 | } | ||
1008 | |||
1009 | static void strip_seq_neighbours(struct seq_file *seq, | ||
1010 | const MetricomNodeTable * table, | ||
1011 | const char *title) | ||
1012 | { | ||
1013 | /* We wrap this in a do/while loop, so if the table changes */ | ||
1014 | /* while we're reading it, we just go around and try again. */ | ||
1015 | struct timeval t; | ||
1016 | |||
1017 | do { | ||
1018 | int i; | ||
1019 | t = table->timestamp; | ||
1020 | if (table->num_nodes) | ||
1021 | seq_printf(seq, "\n %s\n", title); | ||
1022 | for (i = 0; i < table->num_nodes; i++) { | ||
1023 | MetricomNode node; | ||
1024 | |||
1025 | spin_lock_bh(&strip_lock); | ||
1026 | node = table->node[i]; | ||
1027 | spin_unlock_bh(&strip_lock); | ||
1028 | seq_printf(seq, " %s\n", node.c); | ||
1029 | } | ||
1030 | } while (table->timestamp.tv_sec != t.tv_sec | ||
1031 | || table->timestamp.tv_usec != t.tv_usec); | ||
1032 | } | ||
1033 | |||
1034 | /* | ||
1035 | * This function prints radio status information via the seq_file | ||
1036 | * interface. The interface takes care of buffer size and over | ||
1037 | * run issues. | ||
1038 | * | ||
1039 | * The buffer in seq_file is PAGESIZE (4K) | ||
1040 | * so this routine should never print more or it will get truncated. | ||
1041 | * With the maximum of 32 portables and 32 poletops | ||
1042 | * reported, the routine outputs 3107 bytes into the buffer. | ||
1043 | */ | ||
1044 | static void strip_seq_status_info(struct seq_file *seq, | ||
1045 | const struct strip *strip_info) | ||
1046 | { | ||
1047 | char temp[32]; | ||
1048 | MetricomAddressString addr_string; | ||
1049 | |||
1050 | /* First, we must copy all of our data to a safe place, */ | ||
1051 | /* in case a serial interrupt comes in and changes it. */ | ||
1052 | int tx_left = strip_info->tx_left; | ||
1053 | unsigned long rx_average_pps = strip_info->rx_average_pps; | ||
1054 | unsigned long tx_average_pps = strip_info->tx_average_pps; | ||
1055 | unsigned long sx_average_pps = strip_info->sx_average_pps; | ||
1056 | int working = strip_info->working; | ||
1057 | int firmware_level = strip_info->firmware_level; | ||
1058 | long watchdog_doprobe = strip_info->watchdog_doprobe; | ||
1059 | long watchdog_doreset = strip_info->watchdog_doreset; | ||
1060 | long gratuitous_arp = strip_info->gratuitous_arp; | ||
1061 | long arp_interval = strip_info->arp_interval; | ||
1062 | FirmwareVersion firmware_version = strip_info->firmware_version; | ||
1063 | SerialNumber serial_number = strip_info->serial_number; | ||
1064 | BatteryVoltage battery_voltage = strip_info->battery_voltage; | ||
1065 | char *if_name = strip_info->dev->name; | ||
1066 | MetricomAddress true_dev_addr = strip_info->true_dev_addr; | ||
1067 | MetricomAddress dev_dev_addr = | ||
1068 | *(MetricomAddress *) strip_info->dev->dev_addr; | ||
1069 | int manual_dev_addr = strip_info->manual_dev_addr; | ||
1070 | #ifdef EXT_COUNTERS | ||
1071 | unsigned long rx_bytes = strip_info->rx_bytes; | ||
1072 | unsigned long tx_bytes = strip_info->tx_bytes; | ||
1073 | unsigned long rx_rbytes = strip_info->rx_rbytes; | ||
1074 | unsigned long tx_rbytes = strip_info->tx_rbytes; | ||
1075 | unsigned long rx_sbytes = strip_info->rx_sbytes; | ||
1076 | unsigned long tx_sbytes = strip_info->tx_sbytes; | ||
1077 | unsigned long rx_ebytes = strip_info->rx_ebytes; | ||
1078 | unsigned long tx_ebytes = strip_info->tx_ebytes; | ||
1079 | #endif | ||
1080 | |||
1081 | seq_printf(seq, "\nInterface name\t\t%s\n", if_name); | ||
1082 | seq_printf(seq, " Radio working:\t\t%s\n", working ? "Yes" : "No"); | ||
1083 | radio_address_to_string(&true_dev_addr, &addr_string); | ||
1084 | seq_printf(seq, " Radio address:\t\t%s\n", addr_string.c); | ||
1085 | if (manual_dev_addr) { | ||
1086 | radio_address_to_string(&dev_dev_addr, &addr_string); | ||
1087 | seq_printf(seq, " Device address:\t%s\n", addr_string.c); | ||
1088 | } | ||
1089 | seq_printf(seq, " Firmware version:\t%s", !working ? "Unknown" : | ||
1090 | !firmware_level ? "Should be upgraded" : | ||
1091 | firmware_version.c); | ||
1092 | if (firmware_level >= ChecksummedMessages) | ||
1093 | seq_printf(seq, " (Checksums Enabled)"); | ||
1094 | seq_printf(seq, "\n"); | ||
1095 | seq_printf(seq, " Serial number:\t\t%s\n", serial_number.c); | ||
1096 | seq_printf(seq, " Battery voltage:\t%s\n", battery_voltage.c); | ||
1097 | seq_printf(seq, " Transmit queue (bytes):%d\n", tx_left); | ||
1098 | seq_printf(seq, " Receive packet rate: %ld packets per second\n", | ||
1099 | rx_average_pps / 8); | ||
1100 | seq_printf(seq, " Transmit packet rate: %ld packets per second\n", | ||
1101 | tx_average_pps / 8); | ||
1102 | seq_printf(seq, " Sent packet rate: %ld packets per second\n", | ||
1103 | sx_average_pps / 8); | ||
1104 | seq_printf(seq, " Next watchdog probe:\t%s\n", | ||
1105 | time_delta(temp, watchdog_doprobe)); | ||
1106 | seq_printf(seq, " Next watchdog reset:\t%s\n", | ||
1107 | time_delta(temp, watchdog_doreset)); | ||
1108 | seq_printf(seq, " Next gratuitous ARP:\t"); | ||
1109 | |||
1110 | if (!memcmp | ||
1111 | (strip_info->dev->dev_addr, zero_address.c, | ||
1112 | sizeof(zero_address))) | ||
1113 | seq_printf(seq, "Disabled\n"); | ||
1114 | else { | ||
1115 | seq_printf(seq, "%s\n", time_delta(temp, gratuitous_arp)); | ||
1116 | seq_printf(seq, " Next ARP interval:\t%ld seconds\n", | ||
1117 | JIFFIE_TO_SEC(arp_interval)); | ||
1118 | } | ||
1119 | |||
1120 | if (working) { | ||
1121 | #ifdef EXT_COUNTERS | ||
1122 | seq_printf(seq, "\n"); | ||
1123 | seq_printf(seq, | ||
1124 | " Total bytes: \trx:\t%lu\ttx:\t%lu\n", | ||
1125 | rx_bytes, tx_bytes); | ||
1126 | seq_printf(seq, | ||
1127 | " thru radio: \trx:\t%lu\ttx:\t%lu\n", | ||
1128 | rx_rbytes, tx_rbytes); | ||
1129 | seq_printf(seq, | ||
1130 | " thru serial port: \trx:\t%lu\ttx:\t%lu\n", | ||
1131 | rx_sbytes, tx_sbytes); | ||
1132 | seq_printf(seq, | ||
1133 | " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n", | ||
1134 | rx_ebytes, tx_ebytes); | ||
1135 | #endif | ||
1136 | strip_seq_neighbours(seq, &strip_info->poletops, | ||
1137 | "Poletops:"); | ||
1138 | strip_seq_neighbours(seq, &strip_info->portables, | ||
1139 | "Portables:"); | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | /* | ||
1144 | * This function is exports status information from the STRIP driver through | ||
1145 | * the /proc file system. | ||
1146 | */ | ||
1147 | static int strip_seq_show(struct seq_file *seq, void *v) | ||
1148 | { | ||
1149 | if (v == SEQ_START_TOKEN) | ||
1150 | seq_printf(seq, "strip_version: %s\n", StripVersion); | ||
1151 | else | ||
1152 | strip_seq_status_info(seq, (const struct strip *)v); | ||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | static struct seq_operations strip_seq_ops = { | ||
1158 | .start = strip_seq_start, | ||
1159 | .next = strip_seq_next, | ||
1160 | .stop = strip_seq_stop, | ||
1161 | .show = strip_seq_show, | ||
1162 | }; | ||
1163 | |||
1164 | static int strip_seq_open(struct inode *inode, struct file *file) | ||
1165 | { | ||
1166 | return seq_open(file, &strip_seq_ops); | ||
1167 | } | ||
1168 | |||
1169 | static struct file_operations strip_seq_fops = { | ||
1170 | .owner = THIS_MODULE, | ||
1171 | .open = strip_seq_open, | ||
1172 | .read = seq_read, | ||
1173 | .llseek = seq_lseek, | ||
1174 | .release = seq_release, | ||
1175 | }; | ||
1176 | #endif | ||
1177 | |||
1178 | |||
1179 | |||
1180 | /************************************************************************/ | ||
1181 | /* Sending routines */ | ||
1182 | |||
1183 | static void ResetRadio(struct strip *strip_info) | ||
1184 | { | ||
1185 | struct tty_struct *tty = strip_info->tty; | ||
1186 | static const char init[] = "ate0q1dt**starmode\r**"; | ||
1187 | StringDescriptor s = { init, sizeof(init) - 1 }; | ||
1188 | |||
1189 | /* | ||
1190 | * If the radio isn't working anymore, | ||
1191 | * we should clear the old status information. | ||
1192 | */ | ||
1193 | if (strip_info->working) { | ||
1194 | printk(KERN_INFO "%s: No response: Resetting radio.\n", | ||
1195 | strip_info->dev->name); | ||
1196 | strip_info->firmware_version.c[0] = '\0'; | ||
1197 | strip_info->serial_number.c[0] = '\0'; | ||
1198 | strip_info->battery_voltage.c[0] = '\0'; | ||
1199 | strip_info->portables.num_nodes = 0; | ||
1200 | do_gettimeofday(&strip_info->portables.timestamp); | ||
1201 | strip_info->poletops.num_nodes = 0; | ||
1202 | do_gettimeofday(&strip_info->poletops.timestamp); | ||
1203 | } | ||
1204 | |||
1205 | strip_info->pps_timer = jiffies; | ||
1206 | strip_info->rx_pps_count = 0; | ||
1207 | strip_info->tx_pps_count = 0; | ||
1208 | strip_info->sx_pps_count = 0; | ||
1209 | strip_info->rx_average_pps = 0; | ||
1210 | strip_info->tx_average_pps = 0; | ||
1211 | strip_info->sx_average_pps = 0; | ||
1212 | |||
1213 | /* Mark radio address as unknown */ | ||
1214 | *(MetricomAddress *) & strip_info->true_dev_addr = zero_address; | ||
1215 | if (!strip_info->manual_dev_addr) | ||
1216 | *(MetricomAddress *) strip_info->dev->dev_addr = | ||
1217 | zero_address; | ||
1218 | strip_info->working = FALSE; | ||
1219 | strip_info->firmware_level = NoStructure; | ||
1220 | strip_info->next_command = CompatibilityCommand; | ||
1221 | strip_info->watchdog_doprobe = jiffies + 10 * HZ; | ||
1222 | strip_info->watchdog_doreset = jiffies + 1 * HZ; | ||
1223 | |||
1224 | /* If the user has selected a baud rate above 38.4 see what magic we have to do */ | ||
1225 | if (strip_info->user_baud > B38400) { | ||
1226 | /* | ||
1227 | * Subtle stuff: Pay attention :-) | ||
1228 | * If the serial port is currently at the user's selected (>38.4) rate, | ||
1229 | * then we temporarily switch to 19.2 and issue the ATS304 command | ||
1230 | * to tell the radio to switch to the user's selected rate. | ||
1231 | * If the serial port is not currently at that rate, that means we just | ||
1232 | * issued the ATS304 command last time through, so this time we restore | ||
1233 | * the user's selected rate and issue the normal starmode reset string. | ||
1234 | */ | ||
1235 | if (strip_info->user_baud == get_baud(tty)) { | ||
1236 | static const char b0[] = "ate0q1s304=57600\r"; | ||
1237 | static const char b1[] = "ate0q1s304=115200\r"; | ||
1238 | static const StringDescriptor baudstring[2] = | ||
1239 | { {b0, sizeof(b0) - 1} | ||
1240 | , {b1, sizeof(b1) - 1} | ||
1241 | }; | ||
1242 | set_baud(tty, B19200); | ||
1243 | if (strip_info->user_baud == B57600) | ||
1244 | s = baudstring[0]; | ||
1245 | else if (strip_info->user_baud == B115200) | ||
1246 | s = baudstring[1]; | ||
1247 | else | ||
1248 | s = baudstring[1]; /* For now */ | ||
1249 | } else | ||
1250 | set_baud(tty, strip_info->user_baud); | ||
1251 | } | ||
1252 | |||
1253 | tty->driver->write(tty, s.string, s.length); | ||
1254 | #ifdef EXT_COUNTERS | ||
1255 | strip_info->tx_ebytes += s.length; | ||
1256 | #endif | ||
1257 | } | ||
1258 | |||
1259 | /* | ||
1260 | * Called by the driver when there's room for more data. If we have | ||
1261 | * more packets to send, we send them here. | ||
1262 | */ | ||
1263 | |||
1264 | static void strip_write_some_more(struct tty_struct *tty) | ||
1265 | { | ||
1266 | struct strip *strip_info = (struct strip *) tty->disc_data; | ||
1267 | |||
1268 | /* First make sure we're connected. */ | ||
1269 | if (!strip_info || strip_info->magic != STRIP_MAGIC || | ||
1270 | !netif_running(strip_info->dev)) | ||
1271 | return; | ||
1272 | |||
1273 | if (strip_info->tx_left > 0) { | ||
1274 | int num_written = | ||
1275 | tty->driver->write(tty, strip_info->tx_head, | ||
1276 | strip_info->tx_left); | ||
1277 | strip_info->tx_left -= num_written; | ||
1278 | strip_info->tx_head += num_written; | ||
1279 | #ifdef EXT_COUNTERS | ||
1280 | strip_info->tx_sbytes += num_written; | ||
1281 | #endif | ||
1282 | } else { /* Else start transmission of another packet */ | ||
1283 | |||
1284 | tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); | ||
1285 | strip_unlock(strip_info); | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | static __u8 *add_checksum(__u8 * buffer, __u8 * end) | ||
1290 | { | ||
1291 | __u16 sum = 0; | ||
1292 | __u8 *p = buffer; | ||
1293 | while (p < end) | ||
1294 | sum += *p++; | ||
1295 | end[3] = hextable[sum & 0xF]; | ||
1296 | sum >>= 4; | ||
1297 | end[2] = hextable[sum & 0xF]; | ||
1298 | sum >>= 4; | ||
1299 | end[1] = hextable[sum & 0xF]; | ||
1300 | sum >>= 4; | ||
1301 | end[0] = hextable[sum & 0xF]; | ||
1302 | return (end + 4); | ||
1303 | } | ||
1304 | |||
1305 | static unsigned char *strip_make_packet(unsigned char *buffer, | ||
1306 | struct strip *strip_info, | ||
1307 | struct sk_buff *skb) | ||
1308 | { | ||
1309 | __u8 *ptr = buffer; | ||
1310 | __u8 *stuffstate = NULL; | ||
1311 | STRIP_Header *header = (STRIP_Header *) skb->data; | ||
1312 | MetricomAddress haddr = header->dst_addr; | ||
1313 | int len = skb->len - sizeof(STRIP_Header); | ||
1314 | MetricomKey key; | ||
1315 | |||
1316 | /*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len); */ | ||
1317 | |||
1318 | if (header->protocol == htons(ETH_P_IP)) | ||
1319 | key = SIP0Key; | ||
1320 | else if (header->protocol == htons(ETH_P_ARP)) | ||
1321 | key = ARP0Key; | ||
1322 | else { | ||
1323 | printk(KERN_ERR | ||
1324 | "%s: strip_make_packet: Unknown packet type 0x%04X\n", | ||
1325 | strip_info->dev->name, ntohs(header->protocol)); | ||
1326 | return (NULL); | ||
1327 | } | ||
1328 | |||
1329 | if (len > strip_info->mtu) { | ||
1330 | printk(KERN_ERR | ||
1331 | "%s: Dropping oversized transmit packet: %d bytes\n", | ||
1332 | strip_info->dev->name, len); | ||
1333 | return (NULL); | ||
1334 | } | ||
1335 | |||
1336 | /* | ||
1337 | * If we're sending to ourselves, discard the packet. | ||
1338 | * (Metricom radios choke if they try to send a packet to their own address.) | ||
1339 | */ | ||
1340 | if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) { | ||
1341 | printk(KERN_ERR "%s: Dropping packet addressed to self\n", | ||
1342 | strip_info->dev->name); | ||
1343 | return (NULL); | ||
1344 | } | ||
1345 | |||
1346 | /* | ||
1347 | * If this is a broadcast packet, send it to our designated Metricom | ||
1348 | * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) | ||
1349 | */ | ||
1350 | if (haddr.c[0] == 0xFF) { | ||
1351 | u32 brd = 0; | ||
1352 | struct in_device *in_dev; | ||
1353 | |||
1354 | rcu_read_lock(); | ||
1355 | in_dev = __in_dev_get(strip_info->dev); | ||
1356 | if (in_dev == NULL) { | ||
1357 | rcu_read_unlock(); | ||
1358 | return NULL; | ||
1359 | } | ||
1360 | if (in_dev->ifa_list) | ||
1361 | brd = in_dev->ifa_list->ifa_broadcast; | ||
1362 | rcu_read_unlock(); | ||
1363 | |||
1364 | /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ | ||
1365 | if (!arp_query(haddr.c, brd, strip_info->dev)) { | ||
1366 | printk(KERN_ERR | ||
1367 | "%s: Unable to send packet (no broadcast hub configured)\n", | ||
1368 | strip_info->dev->name); | ||
1369 | return (NULL); | ||
1370 | } | ||
1371 | /* | ||
1372 | * If we are the broadcast hub, don't bother sending to ourselves. | ||
1373 | * (Metricom radios choke if they try to send a packet to their own address.) | ||
1374 | */ | ||
1375 | if (!memcmp | ||
1376 | (haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) | ||
1377 | return (NULL); | ||
1378 | } | ||
1379 | |||
1380 | *ptr++ = 0x0D; | ||
1381 | *ptr++ = '*'; | ||
1382 | *ptr++ = hextable[haddr.c[2] >> 4]; | ||
1383 | *ptr++ = hextable[haddr.c[2] & 0xF]; | ||
1384 | *ptr++ = hextable[haddr.c[3] >> 4]; | ||
1385 | *ptr++ = hextable[haddr.c[3] & 0xF]; | ||
1386 | *ptr++ = '-'; | ||
1387 | *ptr++ = hextable[haddr.c[4] >> 4]; | ||
1388 | *ptr++ = hextable[haddr.c[4] & 0xF]; | ||
1389 | *ptr++ = hextable[haddr.c[5] >> 4]; | ||
1390 | *ptr++ = hextable[haddr.c[5] & 0xF]; | ||
1391 | *ptr++ = '*'; | ||
1392 | *ptr++ = key.c[0]; | ||
1393 | *ptr++ = key.c[1]; | ||
1394 | *ptr++ = key.c[2]; | ||
1395 | *ptr++ = key.c[3]; | ||
1396 | |||
1397 | ptr = | ||
1398 | StuffData(skb->data + sizeof(STRIP_Header), len, ptr, | ||
1399 | &stuffstate); | ||
1400 | |||
1401 | if (strip_info->firmware_level >= ChecksummedMessages) | ||
1402 | ptr = add_checksum(buffer + 1, ptr); | ||
1403 | |||
1404 | *ptr++ = 0x0D; | ||
1405 | return (ptr); | ||
1406 | } | ||
1407 | |||
1408 | static void strip_send(struct strip *strip_info, struct sk_buff *skb) | ||
1409 | { | ||
1410 | MetricomAddress haddr; | ||
1411 | unsigned char *ptr = strip_info->tx_buff; | ||
1412 | int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0; | ||
1413 | int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0 | ||
1414 | && !doreset; | ||
1415 | u32 addr, brd; | ||
1416 | |||
1417 | /* | ||
1418 | * 1. If we have a packet, encapsulate it and put it in the buffer | ||
1419 | */ | ||
1420 | if (skb) { | ||
1421 | char *newptr = strip_make_packet(ptr, strip_info, skb); | ||
1422 | strip_info->tx_pps_count++; | ||
1423 | if (!newptr) | ||
1424 | strip_info->tx_dropped++; | ||
1425 | else { | ||
1426 | ptr = newptr; | ||
1427 | strip_info->sx_pps_count++; | ||
1428 | strip_info->tx_packets++; /* Count another successful packet */ | ||
1429 | #ifdef EXT_COUNTERS | ||
1430 | strip_info->tx_bytes += skb->len; | ||
1431 | strip_info->tx_rbytes += ptr - strip_info->tx_buff; | ||
1432 | #endif | ||
1433 | /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr); */ | ||
1434 | /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr); */ | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | /* | ||
1439 | * 2. If it is time for another tickle, tack it on, after the packet | ||
1440 | */ | ||
1441 | if (doprobe) { | ||
1442 | StringDescriptor ts = CommandString[strip_info->next_command]; | ||
1443 | #if TICKLE_TIMERS | ||
1444 | { | ||
1445 | struct timeval tv; | ||
1446 | do_gettimeofday(&tv); | ||
1447 | printk(KERN_INFO "**** Sending tickle string %d at %02d.%06d\n", | ||
1448 | strip_info->next_command, tv.tv_sec % 100, | ||
1449 | tv.tv_usec); | ||
1450 | } | ||
1451 | #endif | ||
1452 | if (ptr == strip_info->tx_buff) | ||
1453 | *ptr++ = 0x0D; | ||
1454 | |||
1455 | *ptr++ = '*'; /* First send "**" to provoke an error message */ | ||
1456 | *ptr++ = '*'; | ||
1457 | |||
1458 | /* Then add the command */ | ||
1459 | memcpy(ptr, ts.string, ts.length); | ||
1460 | |||
1461 | /* Add a checksum ? */ | ||
1462 | if (strip_info->firmware_level < ChecksummedMessages) | ||
1463 | ptr += ts.length; | ||
1464 | else | ||
1465 | ptr = add_checksum(ptr, ptr + ts.length); | ||
1466 | |||
1467 | *ptr++ = 0x0D; /* Terminate the command with a <CR> */ | ||
1468 | |||
1469 | /* Cycle to next periodic command? */ | ||
1470 | if (strip_info->firmware_level >= StructuredMessages) | ||
1471 | if (++strip_info->next_command >= | ||
1472 | ARRAY_SIZE(CommandString)) | ||
1473 | strip_info->next_command = 0; | ||
1474 | #ifdef EXT_COUNTERS | ||
1475 | strip_info->tx_ebytes += ts.length; | ||
1476 | #endif | ||
1477 | strip_info->watchdog_doprobe = jiffies + 10 * HZ; | ||
1478 | strip_info->watchdog_doreset = jiffies + 1 * HZ; | ||
1479 | /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev->name); */ | ||
1480 | } | ||
1481 | |||
1482 | /* | ||
1483 | * 3. Set up the strip_info ready to send the data (if any). | ||
1484 | */ | ||
1485 | strip_info->tx_head = strip_info->tx_buff; | ||
1486 | strip_info->tx_left = ptr - strip_info->tx_buff; | ||
1487 | strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); | ||
1488 | |||
1489 | /* | ||
1490 | * 4. Debugging check to make sure we're not overflowing the buffer. | ||
1491 | */ | ||
1492 | if (strip_info->tx_size - strip_info->tx_left < 20) | ||
1493 | printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", | ||
1494 | strip_info->dev->name, strip_info->tx_left, | ||
1495 | strip_info->tx_size - strip_info->tx_left); | ||
1496 | |||
1497 | /* | ||
1498 | * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in | ||
1499 | * the buffer, strip_write_some_more will send it after the reset has finished | ||
1500 | */ | ||
1501 | if (doreset) { | ||
1502 | ResetRadio(strip_info); | ||
1503 | return; | ||
1504 | } | ||
1505 | |||
1506 | if (1) { | ||
1507 | struct in_device *in_dev; | ||
1508 | |||
1509 | brd = addr = 0; | ||
1510 | rcu_read_lock(); | ||
1511 | in_dev = __in_dev_get(strip_info->dev); | ||
1512 | if (in_dev) { | ||
1513 | if (in_dev->ifa_list) { | ||
1514 | brd = in_dev->ifa_list->ifa_broadcast; | ||
1515 | addr = in_dev->ifa_list->ifa_local; | ||
1516 | } | ||
1517 | } | ||
1518 | rcu_read_unlock(); | ||
1519 | } | ||
1520 | |||
1521 | |||
1522 | /* | ||
1523 | * 6. If it is time for a periodic ARP, queue one up to be sent. | ||
1524 | * We only do this if: | ||
1525 | * 1. The radio is working | ||
1526 | * 2. It's time to send another periodic ARP | ||
1527 | * 3. We really know what our address is (and it is not manually set to zero) | ||
1528 | * 4. We have a designated broadcast address configured | ||
1529 | * If we queue up an ARP packet when we don't have a designated broadcast | ||
1530 | * address configured, then the packet will just have to be discarded in | ||
1531 | * strip_make_packet. This is not fatal, but it causes misleading information | ||
1532 | * to be displayed in tcpdump. tcpdump will report that periodic APRs are | ||
1533 | * being sent, when in fact they are not, because they are all being dropped | ||
1534 | * in the strip_make_packet routine. | ||
1535 | */ | ||
1536 | if (strip_info->working | ||
1537 | && (long) jiffies - strip_info->gratuitous_arp >= 0 | ||
1538 | && memcmp(strip_info->dev->dev_addr, zero_address.c, | ||
1539 | sizeof(zero_address)) | ||
1540 | && arp_query(haddr.c, brd, strip_info->dev)) { | ||
1541 | /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", | ||
1542 | strip_info->dev->name, strip_info->arp_interval / HZ); */ | ||
1543 | strip_info->gratuitous_arp = | ||
1544 | jiffies + strip_info->arp_interval; | ||
1545 | strip_info->arp_interval *= 2; | ||
1546 | if (strip_info->arp_interval > MaxARPInterval) | ||
1547 | strip_info->arp_interval = MaxARPInterval; | ||
1548 | if (addr) | ||
1549 | arp_send(ARPOP_REPLY, ETH_P_ARP, addr, /* Target address of ARP packet is our address */ | ||
1550 | strip_info->dev, /* Device to send packet on */ | ||
1551 | addr, /* Source IP address this ARP packet comes from */ | ||
1552 | NULL, /* Destination HW address is NULL (broadcast it) */ | ||
1553 | strip_info->dev->dev_addr, /* Source HW address is our HW address */ | ||
1554 | strip_info->dev->dev_addr); /* Target HW address is our HW address (redundant) */ | ||
1555 | } | ||
1556 | |||
1557 | /* | ||
1558 | * 7. All ready. Start the transmission | ||
1559 | */ | ||
1560 | strip_write_some_more(strip_info->tty); | ||
1561 | } | ||
1562 | |||
1563 | /* Encapsulate a datagram and kick it into a TTY queue. */ | ||
1564 | static int strip_xmit(struct sk_buff *skb, struct net_device *dev) | ||
1565 | { | ||
1566 | struct strip *strip_info = netdev_priv(dev); | ||
1567 | |||
1568 | if (!netif_running(dev)) { | ||
1569 | printk(KERN_ERR "%s: xmit call when iface is down\n", | ||
1570 | dev->name); | ||
1571 | return (1); | ||
1572 | } | ||
1573 | |||
1574 | netif_stop_queue(dev); | ||
1575 | |||
1576 | del_timer(&strip_info->idle_timer); | ||
1577 | |||
1578 | |||
1579 | if (jiffies - strip_info->pps_timer > HZ) { | ||
1580 | unsigned long t = jiffies - strip_info->pps_timer; | ||
1581 | unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t; | ||
1582 | unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t; | ||
1583 | unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t / 2) / t; | ||
1584 | |||
1585 | strip_info->pps_timer = jiffies; | ||
1586 | strip_info->rx_pps_count = 0; | ||
1587 | strip_info->tx_pps_count = 0; | ||
1588 | strip_info->sx_pps_count = 0; | ||
1589 | |||
1590 | strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2; | ||
1591 | strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2; | ||
1592 | strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2; | ||
1593 | |||
1594 | if (rx_pps_count / 8 >= 10) | ||
1595 | printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n", | ||
1596 | strip_info->dev->name, rx_pps_count / 8); | ||
1597 | if (tx_pps_count / 8 >= 10) | ||
1598 | printk(KERN_INFO "%s: WARNING: Tx %ld packets per second.\n", | ||
1599 | strip_info->dev->name, tx_pps_count / 8); | ||
1600 | if (sx_pps_count / 8 >= 10) | ||
1601 | printk(KERN_INFO "%s: WARNING: Sending %ld packets per second.\n", | ||
1602 | strip_info->dev->name, sx_pps_count / 8); | ||
1603 | } | ||
1604 | |||
1605 | spin_lock_bh(&strip_lock); | ||
1606 | |||
1607 | strip_send(strip_info, skb); | ||
1608 | |||
1609 | spin_unlock_bh(&strip_lock); | ||
1610 | |||
1611 | if (skb) | ||
1612 | dev_kfree_skb(skb); | ||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | /* | ||
1617 | * IdleTask periodically calls strip_xmit, so even when we have no IP packets | ||
1618 | * to send for an extended period of time, the watchdog processing still gets | ||
1619 | * done to ensure that the radio stays in Starmode | ||
1620 | */ | ||
1621 | |||
1622 | static void strip_IdleTask(unsigned long parameter) | ||
1623 | { | ||
1624 | strip_xmit(NULL, (struct net_device *) parameter); | ||
1625 | } | ||
1626 | |||
1627 | /* | ||
1628 | * Create the MAC header for an arbitrary protocol layer | ||
1629 | * | ||
1630 | * saddr!=NULL means use this specific address (n/a for Metricom) | ||
1631 | * saddr==NULL means use default device source address | ||
1632 | * daddr!=NULL means use this destination address | ||
1633 | * daddr==NULL means leave destination address alone | ||
1634 | * (e.g. unresolved arp -- kernel will call | ||
1635 | * rebuild_header later to fill in the address) | ||
1636 | */ | ||
1637 | |||
1638 | static int strip_header(struct sk_buff *skb, struct net_device *dev, | ||
1639 | unsigned short type, void *daddr, void *saddr, | ||
1640 | unsigned len) | ||
1641 | { | ||
1642 | struct strip *strip_info = netdev_priv(dev); | ||
1643 | STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header)); | ||
1644 | |||
1645 | /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, | ||
1646 | type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : ""); */ | ||
1647 | |||
1648 | header->src_addr = strip_info->true_dev_addr; | ||
1649 | header->protocol = htons(type); | ||
1650 | |||
1651 | /*HexDump("strip_header", netdev_priv(dev), skb->data, skb->data + skb->len); */ | ||
1652 | |||
1653 | if (!daddr) | ||
1654 | return (-dev->hard_header_len); | ||
1655 | |||
1656 | header->dst_addr = *(MetricomAddress *) daddr; | ||
1657 | return (dev->hard_header_len); | ||
1658 | } | ||
1659 | |||
1660 | /* | ||
1661 | * Rebuild the MAC header. This is called after an ARP | ||
1662 | * (or in future other address resolution) has completed on this | ||
1663 | * sk_buff. We now let ARP fill in the other fields. | ||
1664 | * I think this should return zero if packet is ready to send, | ||
1665 | * or non-zero if it needs more time to do an address lookup | ||
1666 | */ | ||
1667 | |||
1668 | static int strip_rebuild_header(struct sk_buff *skb) | ||
1669 | { | ||
1670 | #ifdef CONFIG_INET | ||
1671 | STRIP_Header *header = (STRIP_Header *) skb->data; | ||
1672 | |||
1673 | /* Arp find returns zero if if knows the address, */ | ||
1674 | /* or if it doesn't know the address it sends an ARP packet and returns non-zero */ | ||
1675 | return arp_find(header->dst_addr.c, skb) ? 1 : 0; | ||
1676 | #else | ||
1677 | return 0; | ||
1678 | #endif | ||
1679 | } | ||
1680 | |||
1681 | |||
1682 | /************************************************************************/ | ||
1683 | /* Receiving routines */ | ||
1684 | |||
1685 | static int strip_receive_room(struct tty_struct *tty) | ||
1686 | { | ||
1687 | return 0x10000; /* We can handle an infinite amount of data. :-) */ | ||
1688 | } | ||
1689 | |||
1690 | /* | ||
1691 | * This function parses the response to the ATS300? command, | ||
1692 | * extracting the radio version and serial number. | ||
1693 | */ | ||
1694 | static void get_radio_version(struct strip *strip_info, __u8 * ptr, __u8 * end) | ||
1695 | { | ||
1696 | __u8 *p, *value_begin, *value_end; | ||
1697 | int len; | ||
1698 | |||
1699 | /* Determine the beginning of the second line of the payload */ | ||
1700 | p = ptr; | ||
1701 | while (p < end && *p != 10) | ||
1702 | p++; | ||
1703 | if (p >= end) | ||
1704 | return; | ||
1705 | p++; | ||
1706 | value_begin = p; | ||
1707 | |||
1708 | /* Determine the end of line */ | ||
1709 | while (p < end && *p != 10) | ||
1710 | p++; | ||
1711 | if (p >= end) | ||
1712 | return; | ||
1713 | value_end = p; | ||
1714 | p++; | ||
1715 | |||
1716 | len = value_end - value_begin; | ||
1717 | len = min_t(int, len, sizeof(FirmwareVersion) - 1); | ||
1718 | if (strip_info->firmware_version.c[0] == 0) | ||
1719 | printk(KERN_INFO "%s: Radio Firmware: %.*s\n", | ||
1720 | strip_info->dev->name, len, value_begin); | ||
1721 | sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); | ||
1722 | |||
1723 | /* Look for the first colon */ | ||
1724 | while (p < end && *p != ':') | ||
1725 | p++; | ||
1726 | if (p >= end) | ||
1727 | return; | ||
1728 | /* Skip over the space */ | ||
1729 | p += 2; | ||
1730 | len = sizeof(SerialNumber) - 1; | ||
1731 | if (p + len <= end) { | ||
1732 | sprintf(strip_info->serial_number.c, "%.*s", len, p); | ||
1733 | } else { | ||
1734 | printk(KERN_DEBUG | ||
1735 | "STRIP: radio serial number shorter (%zd) than expected (%d)\n", | ||
1736 | end - p, len); | ||
1737 | } | ||
1738 | } | ||
1739 | |||
1740 | /* | ||
1741 | * This function parses the response to the ATS325? command, | ||
1742 | * extracting the radio battery voltage. | ||
1743 | */ | ||
1744 | static void get_radio_voltage(struct strip *strip_info, __u8 * ptr, __u8 * end) | ||
1745 | { | ||
1746 | int len; | ||
1747 | |||
1748 | len = sizeof(BatteryVoltage) - 1; | ||
1749 | if (ptr + len <= end) { | ||
1750 | sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); | ||
1751 | } else { | ||
1752 | printk(KERN_DEBUG | ||
1753 | "STRIP: radio voltage string shorter (%zd) than expected (%d)\n", | ||
1754 | end - ptr, len); | ||
1755 | } | ||
1756 | } | ||
1757 | |||
1758 | /* | ||
1759 | * This function parses the responses to the AT~LA and ATS311 commands, | ||
1760 | * which list the radio's neighbours. | ||
1761 | */ | ||
1762 | static void get_radio_neighbours(MetricomNodeTable * table, __u8 * ptr, __u8 * end) | ||
1763 | { | ||
1764 | table->num_nodes = 0; | ||
1765 | while (ptr < end && table->num_nodes < NODE_TABLE_SIZE) { | ||
1766 | MetricomNode *node = &table->node[table->num_nodes++]; | ||
1767 | char *dst = node->c, *limit = dst + sizeof(*node) - 1; | ||
1768 | while (ptr < end && *ptr <= 32) | ||
1769 | ptr++; | ||
1770 | while (ptr < end && dst < limit && *ptr != 10) | ||
1771 | *dst++ = *ptr++; | ||
1772 | *dst++ = 0; | ||
1773 | while (ptr < end && ptr[-1] != 10) | ||
1774 | ptr++; | ||
1775 | } | ||
1776 | do_gettimeofday(&table->timestamp); | ||
1777 | } | ||
1778 | |||
1779 | static int get_radio_address(struct strip *strip_info, __u8 * p) | ||
1780 | { | ||
1781 | MetricomAddress addr; | ||
1782 | |||
1783 | if (string_to_radio_address(&addr, p)) | ||
1784 | return (1); | ||
1785 | |||
1786 | /* See if our radio address has changed */ | ||
1787 | if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr))) { | ||
1788 | MetricomAddressString addr_string; | ||
1789 | radio_address_to_string(&addr, &addr_string); | ||
1790 | printk(KERN_INFO "%s: Radio address = %s\n", | ||
1791 | strip_info->dev->name, addr_string.c); | ||
1792 | strip_info->true_dev_addr = addr; | ||
1793 | if (!strip_info->manual_dev_addr) | ||
1794 | *(MetricomAddress *) strip_info->dev->dev_addr = | ||
1795 | addr; | ||
1796 | /* Give the radio a few seconds to get its head straight, then send an arp */ | ||
1797 | strip_info->gratuitous_arp = jiffies + 15 * HZ; | ||
1798 | strip_info->arp_interval = 1 * HZ; | ||
1799 | } | ||
1800 | return (0); | ||
1801 | } | ||
1802 | |||
1803 | static int verify_checksum(struct strip *strip_info) | ||
1804 | { | ||
1805 | __u8 *p = strip_info->sx_buff; | ||
1806 | __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4; | ||
1807 | u_short sum = | ||
1808 | (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) | | ||
1809 | (READHEX16(end[2]) << 4) | (READHEX16(end[3])); | ||
1810 | while (p < end) | ||
1811 | sum -= *p++; | ||
1812 | if (sum == 0 && strip_info->firmware_level == StructuredMessages) { | ||
1813 | strip_info->firmware_level = ChecksummedMessages; | ||
1814 | printk(KERN_INFO "%s: Radio provides message checksums\n", | ||
1815 | strip_info->dev->name); | ||
1816 | } | ||
1817 | return (sum == 0); | ||
1818 | } | ||
1819 | |||
1820 | static void RecvErr(char *msg, struct strip *strip_info) | ||
1821 | { | ||
1822 | __u8 *ptr = strip_info->sx_buff; | ||
1823 | __u8 *end = strip_info->sx_buff + strip_info->sx_count; | ||
1824 | DumpData(msg, strip_info, ptr, end); | ||
1825 | strip_info->rx_errors++; | ||
1826 | } | ||
1827 | |||
1828 | static void RecvErr_Message(struct strip *strip_info, __u8 * sendername, | ||
1829 | const __u8 * msg, u_long len) | ||
1830 | { | ||
1831 | if (has_prefix(msg, len, "001")) { /* Not in StarMode! */ | ||
1832 | RecvErr("Error Msg:", strip_info); | ||
1833 | printk(KERN_INFO "%s: Radio %s is not in StarMode\n", | ||
1834 | strip_info->dev->name, sendername); | ||
1835 | } | ||
1836 | |||
1837 | else if (has_prefix(msg, len, "002")) { /* Remap handle */ | ||
1838 | /* We ignore "Remap handle" messages for now */ | ||
1839 | } | ||
1840 | |||
1841 | else if (has_prefix(msg, len, "003")) { /* Can't resolve name */ | ||
1842 | RecvErr("Error Msg:", strip_info); | ||
1843 | printk(KERN_INFO "%s: Destination radio name is unknown\n", | ||
1844 | strip_info->dev->name); | ||
1845 | } | ||
1846 | |||
1847 | else if (has_prefix(msg, len, "004")) { /* Name too small or missing */ | ||
1848 | strip_info->watchdog_doreset = jiffies + LongTime; | ||
1849 | #if TICKLE_TIMERS | ||
1850 | { | ||
1851 | struct timeval tv; | ||
1852 | do_gettimeofday(&tv); | ||
1853 | printk(KERN_INFO | ||
1854 | "**** Got ERR_004 response at %02d.%06d\n", | ||
1855 | tv.tv_sec % 100, tv.tv_usec); | ||
1856 | } | ||
1857 | #endif | ||
1858 | if (!strip_info->working) { | ||
1859 | strip_info->working = TRUE; | ||
1860 | printk(KERN_INFO "%s: Radio now in starmode\n", | ||
1861 | strip_info->dev->name); | ||
1862 | /* | ||
1863 | * If the radio has just entered a working state, we should do our first | ||
1864 | * probe ASAP, so that we find out our radio address etc. without delay. | ||
1865 | */ | ||
1866 | strip_info->watchdog_doprobe = jiffies; | ||
1867 | } | ||
1868 | if (strip_info->firmware_level == NoStructure && sendername) { | ||
1869 | strip_info->firmware_level = StructuredMessages; | ||
1870 | strip_info->next_command = 0; /* Try to enable checksums ASAP */ | ||
1871 | printk(KERN_INFO | ||
1872 | "%s: Radio provides structured messages\n", | ||
1873 | strip_info->dev->name); | ||
1874 | } | ||
1875 | if (strip_info->firmware_level >= StructuredMessages) { | ||
1876 | /* | ||
1877 | * If this message has a valid checksum on the end, then the call to verify_checksum | ||
1878 | * will elevate the firmware_level to ChecksummedMessages for us. (The actual return | ||
1879 | * code from verify_checksum is ignored here.) | ||
1880 | */ | ||
1881 | verify_checksum(strip_info); | ||
1882 | /* | ||
1883 | * If the radio has structured messages but we don't yet have all our information about it, | ||
1884 | * we should do probes without delay, until we have gathered all the information | ||
1885 | */ | ||
1886 | if (!GOT_ALL_RADIO_INFO(strip_info)) | ||
1887 | strip_info->watchdog_doprobe = jiffies; | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | else if (has_prefix(msg, len, "005")) /* Bad count specification */ | ||
1892 | RecvErr("Error Msg:", strip_info); | ||
1893 | |||
1894 | else if (has_prefix(msg, len, "006")) /* Header too big */ | ||
1895 | RecvErr("Error Msg:", strip_info); | ||
1896 | |||
1897 | else if (has_prefix(msg, len, "007")) { /* Body too big */ | ||
1898 | RecvErr("Error Msg:", strip_info); | ||
1899 | printk(KERN_ERR | ||
1900 | "%s: Error! Packet size too big for radio.\n", | ||
1901 | strip_info->dev->name); | ||
1902 | } | ||
1903 | |||
1904 | else if (has_prefix(msg, len, "008")) { /* Bad character in name */ | ||
1905 | RecvErr("Error Msg:", strip_info); | ||
1906 | printk(KERN_ERR | ||
1907 | "%s: Radio name contains illegal character\n", | ||
1908 | strip_info->dev->name); | ||
1909 | } | ||
1910 | |||
1911 | else if (has_prefix(msg, len, "009")) /* No count or line terminator */ | ||
1912 | RecvErr("Error Msg:", strip_info); | ||
1913 | |||
1914 | else if (has_prefix(msg, len, "010")) /* Invalid checksum */ | ||
1915 | RecvErr("Error Msg:", strip_info); | ||
1916 | |||
1917 | else if (has_prefix(msg, len, "011")) /* Checksum didn't match */ | ||
1918 | RecvErr("Error Msg:", strip_info); | ||
1919 | |||
1920 | else if (has_prefix(msg, len, "012")) /* Failed to transmit packet */ | ||
1921 | RecvErr("Error Msg:", strip_info); | ||
1922 | |||
1923 | else | ||
1924 | RecvErr("Error Msg:", strip_info); | ||
1925 | } | ||
1926 | |||
1927 | static void process_AT_response(struct strip *strip_info, __u8 * ptr, | ||
1928 | __u8 * end) | ||
1929 | { | ||
1930 | u_long len; | ||
1931 | __u8 *p = ptr; | ||
1932 | while (p < end && p[-1] != 10) | ||
1933 | p++; /* Skip past first newline character */ | ||
1934 | /* Now ptr points to the AT command, and p points to the text of the response. */ | ||
1935 | len = p - ptr; | ||
1936 | |||
1937 | #if TICKLE_TIMERS | ||
1938 | { | ||
1939 | struct timeval tv; | ||
1940 | do_gettimeofday(&tv); | ||
1941 | printk(KERN_INFO "**** Got AT response %.7s at %02d.%06d\n", | ||
1942 | ptr, tv.tv_sec % 100, tv.tv_usec); | ||
1943 | } | ||
1944 | #endif | ||
1945 | |||
1946 | if (has_prefix(ptr, len, "ATS300?")) | ||
1947 | get_radio_version(strip_info, p, end); | ||
1948 | else if (has_prefix(ptr, len, "ATS305?")) | ||
1949 | get_radio_address(strip_info, p); | ||
1950 | else if (has_prefix(ptr, len, "ATS311?")) | ||
1951 | get_radio_neighbours(&strip_info->poletops, p, end); | ||
1952 | else if (has_prefix(ptr, len, "ATS319=7")) | ||
1953 | verify_checksum(strip_info); | ||
1954 | else if (has_prefix(ptr, len, "ATS325?")) | ||
1955 | get_radio_voltage(strip_info, p, end); | ||
1956 | else if (has_prefix(ptr, len, "AT~LA")) | ||
1957 | get_radio_neighbours(&strip_info->portables, p, end); | ||
1958 | else | ||
1959 | RecvErr("Unknown AT Response:", strip_info); | ||
1960 | } | ||
1961 | |||
1962 | static void process_ACK(struct strip *strip_info, __u8 * ptr, __u8 * end) | ||
1963 | { | ||
1964 | /* Currently we don't do anything with ACKs from the radio */ | ||
1965 | } | ||
1966 | |||
1967 | static void process_Info(struct strip *strip_info, __u8 * ptr, __u8 * end) | ||
1968 | { | ||
1969 | if (ptr + 16 > end) | ||
1970 | RecvErr("Bad Info Msg:", strip_info); | ||
1971 | } | ||
1972 | |||
1973 | static struct net_device *get_strip_dev(struct strip *strip_info) | ||
1974 | { | ||
1975 | /* If our hardware address is *manually set* to zero, and we know our */ | ||
1976 | /* real radio hardware address, try to find another strip device that has been */ | ||
1977 | /* manually set to that address that we can 'transfer ownership' of this packet to */ | ||
1978 | if (strip_info->manual_dev_addr && | ||
1979 | !memcmp(strip_info->dev->dev_addr, zero_address.c, | ||
1980 | sizeof(zero_address)) | ||
1981 | && memcmp(&strip_info->true_dev_addr, zero_address.c, | ||
1982 | sizeof(zero_address))) { | ||
1983 | struct net_device *dev; | ||
1984 | read_lock_bh(&dev_base_lock); | ||
1985 | dev = dev_base; | ||
1986 | while (dev) { | ||
1987 | if (dev->type == strip_info->dev->type && | ||
1988 | !memcmp(dev->dev_addr, | ||
1989 | &strip_info->true_dev_addr, | ||
1990 | sizeof(MetricomAddress))) { | ||
1991 | printk(KERN_INFO | ||
1992 | "%s: Transferred packet ownership to %s.\n", | ||
1993 | strip_info->dev->name, dev->name); | ||
1994 | read_unlock_bh(&dev_base_lock); | ||
1995 | return (dev); | ||
1996 | } | ||
1997 | dev = dev->next; | ||
1998 | } | ||
1999 | read_unlock_bh(&dev_base_lock); | ||
2000 | } | ||
2001 | return (strip_info->dev); | ||
2002 | } | ||
2003 | |||
2004 | /* | ||
2005 | * Send one completely decapsulated datagram to the next layer. | ||
2006 | */ | ||
2007 | |||
2008 | static void deliver_packet(struct strip *strip_info, STRIP_Header * header, | ||
2009 | __u16 packetlen) | ||
2010 | { | ||
2011 | struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); | ||
2012 | if (!skb) { | ||
2013 | printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", | ||
2014 | strip_info->dev->name); | ||
2015 | strip_info->rx_dropped++; | ||
2016 | } else { | ||
2017 | memcpy(skb_put(skb, sizeof(STRIP_Header)), header, | ||
2018 | sizeof(STRIP_Header)); | ||
2019 | memcpy(skb_put(skb, packetlen), strip_info->rx_buff, | ||
2020 | packetlen); | ||
2021 | skb->dev = get_strip_dev(strip_info); | ||
2022 | skb->protocol = header->protocol; | ||
2023 | skb->mac.raw = skb->data; | ||
2024 | |||
2025 | /* Having put a fake header on the front of the sk_buff for the */ | ||
2026 | /* benefit of tools like tcpdump, skb_pull now 'consumes' that */ | ||
2027 | /* fake header before we hand the packet up to the next layer. */ | ||
2028 | skb_pull(skb, sizeof(STRIP_Header)); | ||
2029 | |||
2030 | /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */ | ||
2031 | strip_info->rx_packets++; | ||
2032 | strip_info->rx_pps_count++; | ||
2033 | #ifdef EXT_COUNTERS | ||
2034 | strip_info->rx_bytes += packetlen; | ||
2035 | #endif | ||
2036 | skb->dev->last_rx = jiffies; | ||
2037 | netif_rx(skb); | ||
2038 | } | ||
2039 | } | ||
2040 | |||
2041 | static void process_IP_packet(struct strip *strip_info, | ||
2042 | STRIP_Header * header, __u8 * ptr, | ||
2043 | __u8 * end) | ||
2044 | { | ||
2045 | __u16 packetlen; | ||
2046 | |||
2047 | /* Decode start of the IP packet header */ | ||
2048 | ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); | ||
2049 | if (!ptr) { | ||
2050 | RecvErr("IP Packet too short", strip_info); | ||
2051 | return; | ||
2052 | } | ||
2053 | |||
2054 | packetlen = ((__u16) strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; | ||
2055 | |||
2056 | if (packetlen > MAX_RECV_MTU) { | ||
2057 | printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n", | ||
2058 | strip_info->dev->name, packetlen); | ||
2059 | strip_info->rx_dropped++; | ||
2060 | return; | ||
2061 | } | ||
2062 | |||
2063 | /*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev->name, packetlen); */ | ||
2064 | |||
2065 | /* Decode remainder of the IP packet */ | ||
2066 | ptr = | ||
2067 | UnStuffData(ptr, end, strip_info->rx_buff + 4, packetlen - 4); | ||
2068 | if (!ptr) { | ||
2069 | RecvErr("IP Packet too short", strip_info); | ||
2070 | return; | ||
2071 | } | ||
2072 | |||
2073 | if (ptr < end) { | ||
2074 | RecvErr("IP Packet too long", strip_info); | ||
2075 | return; | ||
2076 | } | ||
2077 | |||
2078 | header->protocol = htons(ETH_P_IP); | ||
2079 | |||
2080 | deliver_packet(strip_info, header, packetlen); | ||
2081 | } | ||
2082 | |||
2083 | static void process_ARP_packet(struct strip *strip_info, | ||
2084 | STRIP_Header * header, __u8 * ptr, | ||
2085 | __u8 * end) | ||
2086 | { | ||
2087 | __u16 packetlen; | ||
2088 | struct arphdr *arphdr = (struct arphdr *) strip_info->rx_buff; | ||
2089 | |||
2090 | /* Decode start of the ARP packet */ | ||
2091 | ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); | ||
2092 | if (!ptr) { | ||
2093 | RecvErr("ARP Packet too short", strip_info); | ||
2094 | return; | ||
2095 | } | ||
2096 | |||
2097 | packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; | ||
2098 | |||
2099 | if (packetlen > MAX_RECV_MTU) { | ||
2100 | printk(KERN_INFO | ||
2101 | "%s: Dropping oversized received ARP packet: %d bytes\n", | ||
2102 | strip_info->dev->name, packetlen); | ||
2103 | strip_info->rx_dropped++; | ||
2104 | return; | ||
2105 | } | ||
2106 | |||
2107 | /*printk(KERN_INFO "%s: Got %d byte ARP %s\n", | ||
2108 | strip_info->dev->name, packetlen, | ||
2109 | ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply"); */ | ||
2110 | |||
2111 | /* Decode remainder of the ARP packet */ | ||
2112 | ptr = | ||
2113 | UnStuffData(ptr, end, strip_info->rx_buff + 8, packetlen - 8); | ||
2114 | if (!ptr) { | ||
2115 | RecvErr("ARP Packet too short", strip_info); | ||
2116 | return; | ||
2117 | } | ||
2118 | |||
2119 | if (ptr < end) { | ||
2120 | RecvErr("ARP Packet too long", strip_info); | ||
2121 | return; | ||
2122 | } | ||
2123 | |||
2124 | header->protocol = htons(ETH_P_ARP); | ||
2125 | |||
2126 | deliver_packet(strip_info, header, packetlen); | ||
2127 | } | ||
2128 | |||
2129 | /* | ||
2130 | * process_text_message processes a <CR>-terminated block of data received | ||
2131 | * from the radio that doesn't begin with a '*' character. All normal | ||
2132 | * Starmode communication messages with the radio begin with a '*', | ||
2133 | * so any text that does not indicates a serial port error, a radio that | ||
2134 | * is in Hayes command mode instead of Starmode, or a radio with really | ||
2135 | * old firmware that doesn't frame its Starmode responses properly. | ||
2136 | */ | ||
2137 | static void process_text_message(struct strip *strip_info) | ||
2138 | { | ||
2139 | __u8 *msg = strip_info->sx_buff; | ||
2140 | int len = strip_info->sx_count; | ||
2141 | |||
2142 | /* Check for anything that looks like it might be our radio name */ | ||
2143 | /* (This is here for backwards compatibility with old firmware) */ | ||
2144 | if (len == 9 && get_radio_address(strip_info, msg) == 0) | ||
2145 | return; | ||
2146 | |||
2147 | if (text_equal(msg, len, "OK")) | ||
2148 | return; /* Ignore 'OK' responses from prior commands */ | ||
2149 | if (text_equal(msg, len, "ERROR")) | ||
2150 | return; /* Ignore 'ERROR' messages */ | ||
2151 | if (has_prefix(msg, len, "ate0q1")) | ||
2152 | return; /* Ignore character echo back from the radio */ | ||
2153 | |||
2154 | /* Catch other error messages */ | ||
2155 | /* (This is here for backwards compatibility with old firmware) */ | ||
2156 | if (has_prefix(msg, len, "ERR_")) { | ||
2157 | RecvErr_Message(strip_info, NULL, &msg[4], len - 4); | ||
2158 | return; | ||
2159 | } | ||
2160 | |||
2161 | RecvErr("No initial *", strip_info); | ||
2162 | } | ||
2163 | |||
2164 | /* | ||
2165 | * process_message processes a <CR>-terminated block of data received | ||
2166 | * from the radio. If the radio is not in Starmode or has old firmware, | ||
2167 | * it may be a line of text in response to an AT command. Ideally, with | ||
2168 | * a current radio that's properly in Starmode, all data received should | ||
2169 | * be properly framed and checksummed radio message blocks, containing | ||
2170 | * either a starmode packet, or a other communication from the radio | ||
2171 | * firmware, like "INF_" Info messages and &COMMAND responses. | ||
2172 | */ | ||
2173 | static void process_message(struct strip *strip_info) | ||
2174 | { | ||
2175 | STRIP_Header header = { zero_address, zero_address, 0 }; | ||
2176 | __u8 *ptr = strip_info->sx_buff; | ||
2177 | __u8 *end = strip_info->sx_buff + strip_info->sx_count; | ||
2178 | __u8 sendername[32], *sptr = sendername; | ||
2179 | MetricomKey key; | ||
2180 | |||
2181 | /*HexDump("Receiving", strip_info, ptr, end); */ | ||
2182 | |||
2183 | /* Check for start of address marker, and then skip over it */ | ||
2184 | if (*ptr == '*') | ||
2185 | ptr++; | ||
2186 | else { | ||
2187 | process_text_message(strip_info); | ||
2188 | return; | ||
2189 | } | ||
2190 | |||
2191 | /* Copy out the return address */ | ||
2192 | while (ptr < end && *ptr != '*' | ||
2193 | && sptr < ARRAY_END(sendername) - 1) | ||
2194 | *sptr++ = *ptr++; | ||
2195 | *sptr = 0; /* Null terminate the sender name */ | ||
2196 | |||
2197 | /* Check for end of address marker, and skip over it */ | ||
2198 | if (ptr >= end || *ptr != '*') { | ||
2199 | RecvErr("No second *", strip_info); | ||
2200 | return; | ||
2201 | } | ||
2202 | ptr++; /* Skip the second '*' */ | ||
2203 | |||
2204 | /* If the sender name is "&COMMAND", ignore this 'packet' */ | ||
2205 | /* (This is here for backwards compatibility with old firmware) */ | ||
2206 | if (!strcmp(sendername, "&COMMAND")) { | ||
2207 | strip_info->firmware_level = NoStructure; | ||
2208 | strip_info->next_command = CompatibilityCommand; | ||
2209 | return; | ||
2210 | } | ||
2211 | |||
2212 | if (ptr + 4 > end) { | ||
2213 | RecvErr("No proto key", strip_info); | ||
2214 | return; | ||
2215 | } | ||
2216 | |||
2217 | /* Get the protocol key out of the buffer */ | ||
2218 | key.c[0] = *ptr++; | ||
2219 | key.c[1] = *ptr++; | ||
2220 | key.c[2] = *ptr++; | ||
2221 | key.c[3] = *ptr++; | ||
2222 | |||
2223 | /* If we're using checksums, verify the checksum at the end of the packet */ | ||
2224 | if (strip_info->firmware_level >= ChecksummedMessages) { | ||
2225 | end -= 4; /* Chop the last four bytes off the packet (they're the checksum) */ | ||
2226 | if (ptr > end) { | ||
2227 | RecvErr("Missing Checksum", strip_info); | ||
2228 | return; | ||
2229 | } | ||
2230 | if (!verify_checksum(strip_info)) { | ||
2231 | RecvErr("Bad Checksum", strip_info); | ||
2232 | return; | ||
2233 | } | ||
2234 | } | ||
2235 | |||
2236 | /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev->name, sendername); */ | ||
2237 | |||
2238 | /* | ||
2239 | * Fill in (pseudo) source and destination addresses in the packet. | ||
2240 | * We assume that the destination address was our address (the radio does not | ||
2241 | * tell us this). If the radio supplies a source address, then we use it. | ||
2242 | */ | ||
2243 | header.dst_addr = strip_info->true_dev_addr; | ||
2244 | string_to_radio_address(&header.src_addr, sendername); | ||
2245 | |||
2246 | #ifdef EXT_COUNTERS | ||
2247 | if (key.l == SIP0Key.l) { | ||
2248 | strip_info->rx_rbytes += (end - ptr); | ||
2249 | process_IP_packet(strip_info, &header, ptr, end); | ||
2250 | } else if (key.l == ARP0Key.l) { | ||
2251 | strip_info->rx_rbytes += (end - ptr); | ||
2252 | process_ARP_packet(strip_info, &header, ptr, end); | ||
2253 | } else if (key.l == ATR_Key.l) { | ||
2254 | strip_info->rx_ebytes += (end - ptr); | ||
2255 | process_AT_response(strip_info, ptr, end); | ||
2256 | } else if (key.l == ACK_Key.l) { | ||
2257 | strip_info->rx_ebytes += (end - ptr); | ||
2258 | process_ACK(strip_info, ptr, end); | ||
2259 | } else if (key.l == INF_Key.l) { | ||
2260 | strip_info->rx_ebytes += (end - ptr); | ||
2261 | process_Info(strip_info, ptr, end); | ||
2262 | } else if (key.l == ERR_Key.l) { | ||
2263 | strip_info->rx_ebytes += (end - ptr); | ||
2264 | RecvErr_Message(strip_info, sendername, ptr, end - ptr); | ||
2265 | } else | ||
2266 | RecvErr("Unrecognized protocol key", strip_info); | ||
2267 | #else | ||
2268 | if (key.l == SIP0Key.l) | ||
2269 | process_IP_packet(strip_info, &header, ptr, end); | ||
2270 | else if (key.l == ARP0Key.l) | ||
2271 | process_ARP_packet(strip_info, &header, ptr, end); | ||
2272 | else if (key.l == ATR_Key.l) | ||
2273 | process_AT_response(strip_info, ptr, end); | ||
2274 | else if (key.l == ACK_Key.l) | ||
2275 | process_ACK(strip_info, ptr, end); | ||
2276 | else if (key.l == INF_Key.l) | ||
2277 | process_Info(strip_info, ptr, end); | ||
2278 | else if (key.l == ERR_Key.l) | ||
2279 | RecvErr_Message(strip_info, sendername, ptr, end - ptr); | ||
2280 | else | ||
2281 | RecvErr("Unrecognized protocol key", strip_info); | ||
2282 | #endif | ||
2283 | } | ||
2284 | |||
2285 | #define TTYERROR(X) ((X) == TTY_BREAK ? "Break" : \ | ||
2286 | (X) == TTY_FRAME ? "Framing Error" : \ | ||
2287 | (X) == TTY_PARITY ? "Parity Error" : \ | ||
2288 | (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error") | ||
2289 | |||
2290 | /* | ||
2291 | * Handle the 'receiver data ready' interrupt. | ||
2292 | * This function is called by the 'tty_io' module in the kernel when | ||
2293 | * a block of STRIP data has been received, which can now be decapsulated | ||
2294 | * and sent on to some IP layer for further processing. | ||
2295 | */ | ||
2296 | |||
2297 | static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, | ||
2298 | char *fp, int count) | ||
2299 | { | ||
2300 | struct strip *strip_info = (struct strip *) tty->disc_data; | ||
2301 | const unsigned char *end = cp + count; | ||
2302 | |||
2303 | if (!strip_info || strip_info->magic != STRIP_MAGIC | ||
2304 | || !netif_running(strip_info->dev)) | ||
2305 | return; | ||
2306 | |||
2307 | spin_lock_bh(&strip_lock); | ||
2308 | #if 0 | ||
2309 | { | ||
2310 | struct timeval tv; | ||
2311 | do_gettimeofday(&tv); | ||
2312 | printk(KERN_INFO | ||
2313 | "**** strip_receive_buf: %3d bytes at %02d.%06d\n", | ||
2314 | count, tv.tv_sec % 100, tv.tv_usec); | ||
2315 | } | ||
2316 | #endif | ||
2317 | |||
2318 | #ifdef EXT_COUNTERS | ||
2319 | strip_info->rx_sbytes += count; | ||
2320 | #endif | ||
2321 | |||
2322 | /* Read the characters out of the buffer */ | ||
2323 | while (cp < end) { | ||
2324 | if (fp && *fp) | ||
2325 | printk(KERN_INFO "%s: %s on serial port\n", | ||
2326 | strip_info->dev->name, TTYERROR(*fp)); | ||
2327 | if (fp && *fp++ && !strip_info->discard) { /* If there's a serial error, record it */ | ||
2328 | /* If we have some characters in the buffer, discard them */ | ||
2329 | strip_info->discard = strip_info->sx_count; | ||
2330 | strip_info->rx_errors++; | ||
2331 | } | ||
2332 | |||
2333 | /* Leading control characters (CR, NL, Tab, etc.) are ignored */ | ||
2334 | if (strip_info->sx_count > 0 || *cp >= ' ') { | ||
2335 | if (*cp == 0x0D) { /* If end of packet, decide what to do with it */ | ||
2336 | if (strip_info->sx_count > 3000) | ||
2337 | printk(KERN_INFO | ||
2338 | "%s: Cut a %d byte packet (%zd bytes remaining)%s\n", | ||
2339 | strip_info->dev->name, | ||
2340 | strip_info->sx_count, | ||
2341 | end - cp - 1, | ||
2342 | strip_info-> | ||
2343 | discard ? " (discarded)" : | ||
2344 | ""); | ||
2345 | if (strip_info->sx_count > | ||
2346 | strip_info->sx_size) { | ||
2347 | strip_info->rx_over_errors++; | ||
2348 | printk(KERN_INFO | ||
2349 | "%s: sx_buff overflow (%d bytes total)\n", | ||
2350 | strip_info->dev->name, | ||
2351 | strip_info->sx_count); | ||
2352 | } else if (strip_info->discard) | ||
2353 | printk(KERN_INFO | ||
2354 | "%s: Discarding bad packet (%d/%d)\n", | ||
2355 | strip_info->dev->name, | ||
2356 | strip_info->discard, | ||
2357 | strip_info->sx_count); | ||
2358 | else | ||
2359 | process_message(strip_info); | ||
2360 | strip_info->discard = 0; | ||
2361 | strip_info->sx_count = 0; | ||
2362 | } else { | ||
2363 | /* Make sure we have space in the buffer */ | ||
2364 | if (strip_info->sx_count < | ||
2365 | strip_info->sx_size) | ||
2366 | strip_info->sx_buff[strip_info-> | ||
2367 | sx_count] = | ||
2368 | *cp; | ||
2369 | strip_info->sx_count++; | ||
2370 | } | ||
2371 | } | ||
2372 | cp++; | ||
2373 | } | ||
2374 | spin_unlock_bh(&strip_lock); | ||
2375 | } | ||
2376 | |||
2377 | |||
2378 | /************************************************************************/ | ||
2379 | /* General control routines */ | ||
2380 | |||
2381 | static int set_mac_address(struct strip *strip_info, | ||
2382 | MetricomAddress * addr) | ||
2383 | { | ||
2384 | /* | ||
2385 | * We're using a manually specified address if the address is set | ||
2386 | * to anything other than all ones. Setting the address to all ones | ||
2387 | * disables manual mode and goes back to automatic address determination | ||
2388 | * (tracking the true address that the radio has). | ||
2389 | */ | ||
2390 | strip_info->manual_dev_addr = | ||
2391 | memcmp(addr->c, broadcast_address.c, | ||
2392 | sizeof(broadcast_address)); | ||
2393 | if (strip_info->manual_dev_addr) | ||
2394 | *(MetricomAddress *) strip_info->dev->dev_addr = *addr; | ||
2395 | else | ||
2396 | *(MetricomAddress *) strip_info->dev->dev_addr = | ||
2397 | strip_info->true_dev_addr; | ||
2398 | return 0; | ||
2399 | } | ||
2400 | |||
2401 | static int strip_set_mac_address(struct net_device *dev, void *addr) | ||
2402 | { | ||
2403 | struct strip *strip_info = netdev_priv(dev); | ||
2404 | struct sockaddr *sa = addr; | ||
2405 | printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name); | ||
2406 | set_mac_address(strip_info, (MetricomAddress *) sa->sa_data); | ||
2407 | return 0; | ||
2408 | } | ||
2409 | |||
2410 | static struct net_device_stats *strip_get_stats(struct net_device *dev) | ||
2411 | { | ||
2412 | struct strip *strip_info = netdev_priv(dev); | ||
2413 | static struct net_device_stats stats; | ||
2414 | |||
2415 | memset(&stats, 0, sizeof(struct net_device_stats)); | ||
2416 | |||
2417 | stats.rx_packets = strip_info->rx_packets; | ||
2418 | stats.tx_packets = strip_info->tx_packets; | ||
2419 | stats.rx_dropped = strip_info->rx_dropped; | ||
2420 | stats.tx_dropped = strip_info->tx_dropped; | ||
2421 | stats.tx_errors = strip_info->tx_errors; | ||
2422 | stats.rx_errors = strip_info->rx_errors; | ||
2423 | stats.rx_over_errors = strip_info->rx_over_errors; | ||
2424 | return (&stats); | ||
2425 | } | ||
2426 | |||
2427 | |||
2428 | /************************************************************************/ | ||
2429 | /* Opening and closing */ | ||
2430 | |||
2431 | /* | ||
2432 | * Here's the order things happen: | ||
2433 | * When the user runs "slattach -p strip ..." | ||
2434 | * 1. The TTY module calls strip_open | ||
2435 | * 2. strip_open calls strip_alloc | ||
2436 | * 3. strip_alloc calls register_netdev | ||
2437 | * 4. register_netdev calls strip_dev_init | ||
2438 | * 5. then strip_open finishes setting up the strip_info | ||
2439 | * | ||
2440 | * When the user runs "ifconfig st<x> up address netmask ..." | ||
2441 | * 6. strip_open_low gets called | ||
2442 | * | ||
2443 | * When the user runs "ifconfig st<x> down" | ||
2444 | * 7. strip_close_low gets called | ||
2445 | * | ||
2446 | * When the user kills the slattach process | ||
2447 | * 8. strip_close gets called | ||
2448 | * 9. strip_close calls dev_close | ||
2449 | * 10. if the device is still up, then dev_close calls strip_close_low | ||
2450 | * 11. strip_close calls strip_free | ||
2451 | */ | ||
2452 | |||
2453 | /* Open the low-level part of the STRIP channel. Easy! */ | ||
2454 | |||
2455 | static int strip_open_low(struct net_device *dev) | ||
2456 | { | ||
2457 | struct strip *strip_info = netdev_priv(dev); | ||
2458 | |||
2459 | if (strip_info->tty == NULL) | ||
2460 | return (-ENODEV); | ||
2461 | |||
2462 | if (!allocate_buffers(strip_info, dev->mtu)) | ||
2463 | return (-ENOMEM); | ||
2464 | |||
2465 | strip_info->sx_count = 0; | ||
2466 | strip_info->tx_left = 0; | ||
2467 | |||
2468 | strip_info->discard = 0; | ||
2469 | strip_info->working = FALSE; | ||
2470 | strip_info->firmware_level = NoStructure; | ||
2471 | strip_info->next_command = CompatibilityCommand; | ||
2472 | strip_info->user_baud = get_baud(strip_info->tty); | ||
2473 | |||
2474 | printk(KERN_INFO "%s: Initializing Radio.\n", | ||
2475 | strip_info->dev->name); | ||
2476 | ResetRadio(strip_info); | ||
2477 | strip_info->idle_timer.expires = jiffies + 1 * HZ; | ||
2478 | add_timer(&strip_info->idle_timer); | ||
2479 | netif_wake_queue(dev); | ||
2480 | return (0); | ||
2481 | } | ||
2482 | |||
2483 | |||
2484 | /* | ||
2485 | * Close the low-level part of the STRIP channel. Easy! | ||
2486 | */ | ||
2487 | |||
2488 | static int strip_close_low(struct net_device *dev) | ||
2489 | { | ||
2490 | struct strip *strip_info = netdev_priv(dev); | ||
2491 | |||
2492 | if (strip_info->tty == NULL) | ||
2493 | return -EBUSY; | ||
2494 | strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); | ||
2495 | |||
2496 | netif_stop_queue(dev); | ||
2497 | |||
2498 | /* | ||
2499 | * Free all STRIP frame buffers. | ||
2500 | */ | ||
2501 | if (strip_info->rx_buff) { | ||
2502 | kfree(strip_info->rx_buff); | ||
2503 | strip_info->rx_buff = NULL; | ||
2504 | } | ||
2505 | if (strip_info->sx_buff) { | ||
2506 | kfree(strip_info->sx_buff); | ||
2507 | strip_info->sx_buff = NULL; | ||
2508 | } | ||
2509 | if (strip_info->tx_buff) { | ||
2510 | kfree(strip_info->tx_buff); | ||
2511 | strip_info->tx_buff = NULL; | ||
2512 | } | ||
2513 | del_timer(&strip_info->idle_timer); | ||
2514 | return 0; | ||
2515 | } | ||
2516 | |||
2517 | /* | ||
2518 | * This routine is called by DDI when the | ||
2519 | * (dynamically assigned) device is registered | ||
2520 | */ | ||
2521 | |||
2522 | static void strip_dev_setup(struct net_device *dev) | ||
2523 | { | ||
2524 | /* | ||
2525 | * Finish setting up the DEVICE info. | ||
2526 | */ | ||
2527 | |||
2528 | SET_MODULE_OWNER(dev); | ||
2529 | |||
2530 | dev->trans_start = 0; | ||
2531 | dev->last_rx = 0; | ||
2532 | dev->tx_queue_len = 30; /* Drop after 30 frames queued */ | ||
2533 | |||
2534 | dev->flags = 0; | ||
2535 | dev->mtu = DEFAULT_STRIP_MTU; | ||
2536 | dev->type = ARPHRD_METRICOM; /* dtang */ | ||
2537 | dev->hard_header_len = sizeof(STRIP_Header); | ||
2538 | /* | ||
2539 | * dev->priv Already holds a pointer to our struct strip | ||
2540 | */ | ||
2541 | |||
2542 | *(MetricomAddress *) & dev->broadcast = broadcast_address; | ||
2543 | dev->dev_addr[0] = 0; | ||
2544 | dev->addr_len = sizeof(MetricomAddress); | ||
2545 | |||
2546 | /* | ||
2547 | * Pointers to interface service routines. | ||
2548 | */ | ||
2549 | |||
2550 | dev->open = strip_open_low; | ||
2551 | dev->stop = strip_close_low; | ||
2552 | dev->hard_start_xmit = strip_xmit; | ||
2553 | dev->hard_header = strip_header; | ||
2554 | dev->rebuild_header = strip_rebuild_header; | ||
2555 | dev->set_mac_address = strip_set_mac_address; | ||
2556 | dev->get_stats = strip_get_stats; | ||
2557 | dev->change_mtu = strip_change_mtu; | ||
2558 | } | ||
2559 | |||
2560 | /* | ||
2561 | * Free a STRIP channel. | ||
2562 | */ | ||
2563 | |||
2564 | static void strip_free(struct strip *strip_info) | ||
2565 | { | ||
2566 | spin_lock_bh(&strip_lock); | ||
2567 | list_del_rcu(&strip_info->list); | ||
2568 | spin_unlock_bh(&strip_lock); | ||
2569 | |||
2570 | strip_info->magic = 0; | ||
2571 | |||
2572 | free_netdev(strip_info->dev); | ||
2573 | } | ||
2574 | |||
2575 | |||
2576 | /* | ||
2577 | * Allocate a new free STRIP channel | ||
2578 | */ | ||
2579 | static struct strip *strip_alloc(void) | ||
2580 | { | ||
2581 | struct list_head *n; | ||
2582 | struct net_device *dev; | ||
2583 | struct strip *strip_info; | ||
2584 | |||
2585 | dev = alloc_netdev(sizeof(struct strip), "st%d", | ||
2586 | strip_dev_setup); | ||
2587 | |||
2588 | if (!dev) | ||
2589 | return NULL; /* If no more memory, return */ | ||
2590 | |||
2591 | |||
2592 | strip_info = dev->priv; | ||
2593 | strip_info->dev = dev; | ||
2594 | |||
2595 | strip_info->magic = STRIP_MAGIC; | ||
2596 | strip_info->tty = NULL; | ||
2597 | |||
2598 | strip_info->gratuitous_arp = jiffies + LongTime; | ||
2599 | strip_info->arp_interval = 0; | ||
2600 | init_timer(&strip_info->idle_timer); | ||
2601 | strip_info->idle_timer.data = (long) dev; | ||
2602 | strip_info->idle_timer.function = strip_IdleTask; | ||
2603 | |||
2604 | |||
2605 | spin_lock_bh(&strip_lock); | ||
2606 | rescan: | ||
2607 | /* | ||
2608 | * Search the list to find where to put our new entry | ||
2609 | * (and in the process decide what channel number it is | ||
2610 | * going to be) | ||
2611 | */ | ||
2612 | list_for_each(n, &strip_list) { | ||
2613 | struct strip *s = hlist_entry(n, struct strip, list); | ||
2614 | |||
2615 | if (s->dev->base_addr == dev->base_addr) { | ||
2616 | ++dev->base_addr; | ||
2617 | goto rescan; | ||
2618 | } | ||
2619 | } | ||
2620 | |||
2621 | sprintf(dev->name, "st%ld", dev->base_addr); | ||
2622 | |||
2623 | list_add_tail_rcu(&strip_info->list, &strip_list); | ||
2624 | spin_unlock_bh(&strip_lock); | ||
2625 | |||
2626 | return strip_info; | ||
2627 | } | ||
2628 | |||
2629 | /* | ||
2630 | * Open the high-level part of the STRIP channel. | ||
2631 | * This function is called by the TTY module when the | ||
2632 | * STRIP line discipline is called for. Because we are | ||
2633 | * sure the tty line exists, we only have to link it to | ||
2634 | * a free STRIP channel... | ||
2635 | */ | ||
2636 | |||
2637 | static int strip_open(struct tty_struct *tty) | ||
2638 | { | ||
2639 | struct strip *strip_info = (struct strip *) tty->disc_data; | ||
2640 | |||
2641 | /* | ||
2642 | * First make sure we're not already connected. | ||
2643 | */ | ||
2644 | |||
2645 | if (strip_info && strip_info->magic == STRIP_MAGIC) | ||
2646 | return -EEXIST; | ||
2647 | |||
2648 | /* | ||
2649 | * OK. Find a free STRIP channel to use. | ||
2650 | */ | ||
2651 | if ((strip_info = strip_alloc()) == NULL) | ||
2652 | return -ENFILE; | ||
2653 | |||
2654 | /* | ||
2655 | * Register our newly created device so it can be ifconfig'd | ||
2656 | * strip_dev_init() will be called as a side-effect | ||
2657 | */ | ||
2658 | |||
2659 | if (register_netdev(strip_info->dev) != 0) { | ||
2660 | printk(KERN_ERR "strip: register_netdev() failed.\n"); | ||
2661 | strip_free(strip_info); | ||
2662 | return -ENFILE; | ||
2663 | } | ||
2664 | |||
2665 | strip_info->tty = tty; | ||
2666 | tty->disc_data = strip_info; | ||
2667 | if (tty->driver->flush_buffer) | ||
2668 | tty->driver->flush_buffer(tty); | ||
2669 | |||
2670 | /* | ||
2671 | * Restore default settings | ||
2672 | */ | ||
2673 | |||
2674 | strip_info->dev->type = ARPHRD_METRICOM; /* dtang */ | ||
2675 | |||
2676 | /* | ||
2677 | * Set tty options | ||
2678 | */ | ||
2679 | |||
2680 | tty->termios->c_iflag |= IGNBRK | IGNPAR; /* Ignore breaks and parity errors. */ | ||
2681 | tty->termios->c_cflag |= CLOCAL; /* Ignore modem control signals. */ | ||
2682 | tty->termios->c_cflag &= ~HUPCL; /* Don't close on hup */ | ||
2683 | |||
2684 | printk(KERN_INFO "STRIP: device \"%s\" activated\n", | ||
2685 | strip_info->dev->name); | ||
2686 | |||
2687 | /* | ||
2688 | * Done. We have linked the TTY line to a channel. | ||
2689 | */ | ||
2690 | return (strip_info->dev->base_addr); | ||
2691 | } | ||
2692 | |||
2693 | /* | ||
2694 | * Close down a STRIP channel. | ||
2695 | * This means flushing out any pending queues, and then restoring the | ||
2696 | * TTY line discipline to what it was before it got hooked to STRIP | ||
2697 | * (which usually is TTY again). | ||
2698 | */ | ||
2699 | |||
2700 | static void strip_close(struct tty_struct *tty) | ||
2701 | { | ||
2702 | struct strip *strip_info = (struct strip *) tty->disc_data; | ||
2703 | |||
2704 | /* | ||
2705 | * First make sure we're connected. | ||
2706 | */ | ||
2707 | |||
2708 | if (!strip_info || strip_info->magic != STRIP_MAGIC) | ||
2709 | return; | ||
2710 | |||
2711 | unregister_netdev(strip_info->dev); | ||
2712 | |||
2713 | tty->disc_data = NULL; | ||
2714 | strip_info->tty = NULL; | ||
2715 | printk(KERN_INFO "STRIP: device \"%s\" closed down\n", | ||
2716 | strip_info->dev->name); | ||
2717 | strip_free(strip_info); | ||
2718 | tty->disc_data = NULL; | ||
2719 | } | ||
2720 | |||
2721 | |||
2722 | /************************************************************************/ | ||
2723 | /* Perform I/O control calls on an active STRIP channel. */ | ||
2724 | |||
2725 | static int strip_ioctl(struct tty_struct *tty, struct file *file, | ||
2726 | unsigned int cmd, unsigned long arg) | ||
2727 | { | ||
2728 | struct strip *strip_info = (struct strip *) tty->disc_data; | ||
2729 | |||
2730 | /* | ||
2731 | * First make sure we're connected. | ||
2732 | */ | ||
2733 | |||
2734 | if (!strip_info || strip_info->magic != STRIP_MAGIC) | ||
2735 | return -EINVAL; | ||
2736 | |||
2737 | switch (cmd) { | ||
2738 | case SIOCGIFNAME: | ||
2739 | if(copy_to_user((void __user *) arg, strip_info->dev->name, strlen(strip_info->dev->name) + 1)) | ||
2740 | return -EFAULT; | ||
2741 | break; | ||
2742 | case SIOCSIFHWADDR: | ||
2743 | { | ||
2744 | MetricomAddress addr; | ||
2745 | //printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev->name); | ||
2746 | if(copy_from_user(&addr, (void __user *) arg, sizeof(MetricomAddress))) | ||
2747 | return -EFAULT; | ||
2748 | return set_mac_address(strip_info, &addr); | ||
2749 | } | ||
2750 | /* | ||
2751 | * Allow stty to read, but not set, the serial port | ||
2752 | */ | ||
2753 | |||
2754 | case TCGETS: | ||
2755 | case TCGETA: | ||
2756 | return n_tty_ioctl(tty, file, cmd, arg); | ||
2757 | break; | ||
2758 | default: | ||
2759 | return -ENOIOCTLCMD; | ||
2760 | break; | ||
2761 | } | ||
2762 | return 0; | ||
2763 | } | ||
2764 | |||
2765 | |||
2766 | /************************************************************************/ | ||
2767 | /* Initialization */ | ||
2768 | |||
2769 | static struct tty_ldisc strip_ldisc = { | ||
2770 | .magic = TTY_LDISC_MAGIC, | ||
2771 | .name = "strip", | ||
2772 | .owner = THIS_MODULE, | ||
2773 | .open = strip_open, | ||
2774 | .close = strip_close, | ||
2775 | .ioctl = strip_ioctl, | ||
2776 | .receive_buf = strip_receive_buf, | ||
2777 | .receive_room = strip_receive_room, | ||
2778 | .write_wakeup = strip_write_some_more, | ||
2779 | }; | ||
2780 | |||
2781 | /* | ||
2782 | * Initialize the STRIP driver. | ||
2783 | * This routine is called at boot time, to bootstrap the multi-channel | ||
2784 | * STRIP driver | ||
2785 | */ | ||
2786 | |||
2787 | static char signon[] __initdata = | ||
2788 | KERN_INFO "STRIP: Version %s (unlimited channels)\n"; | ||
2789 | |||
2790 | static int __init strip_init_driver(void) | ||
2791 | { | ||
2792 | int status; | ||
2793 | |||
2794 | printk(signon, StripVersion); | ||
2795 | |||
2796 | |||
2797 | /* | ||
2798 | * Fill in our line protocol discipline, and register it | ||
2799 | */ | ||
2800 | if ((status = tty_register_ldisc(N_STRIP, &strip_ldisc))) | ||
2801 | printk(KERN_ERR "STRIP: can't register line discipline (err = %d)\n", | ||
2802 | status); | ||
2803 | |||
2804 | /* | ||
2805 | * Register the status file with /proc | ||
2806 | */ | ||
2807 | proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops); | ||
2808 | |||
2809 | return status; | ||
2810 | } | ||
2811 | |||
2812 | module_init(strip_init_driver); | ||
2813 | |||
2814 | static const char signoff[] __exitdata = | ||
2815 | KERN_INFO "STRIP: Module Unloaded\n"; | ||
2816 | |||
2817 | static void __exit strip_exit_driver(void) | ||
2818 | { | ||
2819 | int i; | ||
2820 | struct list_head *p,*n; | ||
2821 | |||
2822 | /* module ref count rules assure that all entries are unregistered */ | ||
2823 | list_for_each_safe(p, n, &strip_list) { | ||
2824 | struct strip *s = list_entry(p, struct strip, list); | ||
2825 | strip_free(s); | ||
2826 | } | ||
2827 | |||
2828 | /* Unregister with the /proc/net file here. */ | ||
2829 | proc_net_remove("strip"); | ||
2830 | |||
2831 | if ((i = tty_register_ldisc(N_STRIP, NULL))) | ||
2832 | printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); | ||
2833 | |||
2834 | printk(signoff); | ||
2835 | } | ||
2836 | |||
2837 | module_exit(strip_exit_driver); | ||
2838 | |||
2839 | MODULE_AUTHOR("Stuart Cheshire <cheshire@cs.stanford.edu>"); | ||
2840 | MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver"); | ||
2841 | MODULE_LICENSE("Dual BSD/GPL"); | ||
2842 | |||
2843 | MODULE_SUPPORTED_DEVICE("Starmode Radio IP (STRIP) modem"); | ||
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt new file mode 100644 index 000000000000..32234018de72 --- /dev/null +++ b/drivers/net/wireless/todo.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | Wireless Todo | ||
2 | ------------- | ||
3 | |||
4 | 1) Bring other kernel Wireless LAN drivers here | ||
5 | Completed | ||
6 | |||
7 | 2) Bring new Wireless LAN driver not yet in the kernel there | ||
8 | See my web page for details | ||
9 | In particular : HostAP | ||
10 | |||
11 | 3) Misc | ||
12 | o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete | ||
13 | o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete | ||
14 | |||
15 | Jean II | ||
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c new file mode 100644 index 000000000000..7a5e20a17890 --- /dev/null +++ b/drivers/net/wireless/wavelan.c | |||
@@ -0,0 +1,4452 @@ | |||
1 | /* | ||
2 | * WaveLAN ISA driver | ||
3 | * | ||
4 | * Jean II - HPLB '96 | ||
5 | * | ||
6 | * Reorganisation and extension of the driver. | ||
7 | * Original copyright follows (also see the end of this file). | ||
8 | * See wavelan.p.h for details. | ||
9 | * | ||
10 | * | ||
11 | * | ||
12 | * AT&T GIS (nee NCR) WaveLAN card: | ||
13 | * An Ethernet-like radio transceiver | ||
14 | * controlled by an Intel 82586 coprocessor. | ||
15 | */ | ||
16 | |||
17 | #include "wavelan.p.h" /* Private header */ | ||
18 | |||
19 | /************************* MISC SUBROUTINES **************************/ | ||
20 | /* | ||
21 | * Subroutines which won't fit in one of the following category | ||
22 | * (WaveLAN modem or i82586) | ||
23 | */ | ||
24 | |||
25 | /*------------------------------------------------------------------*/ | ||
26 | /* | ||
27 | * Translate irq number to PSA irq parameter | ||
28 | */ | ||
29 | static u8 wv_irq_to_psa(int irq) | ||
30 | { | ||
31 | if (irq < 0 || irq >= NELS(irqvals)) | ||
32 | return 0; | ||
33 | |||
34 | return irqvals[irq]; | ||
35 | } | ||
36 | |||
37 | /*------------------------------------------------------------------*/ | ||
38 | /* | ||
39 | * Translate PSA irq parameter to irq number | ||
40 | */ | ||
41 | static int __init wv_psa_to_irq(u8 irqval) | ||
42 | { | ||
43 | int irq; | ||
44 | |||
45 | for (irq = 0; irq < NELS(irqvals); irq++) | ||
46 | if (irqvals[irq] == irqval) | ||
47 | return irq; | ||
48 | |||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | #ifdef STRUCT_CHECK | ||
53 | /*------------------------------------------------------------------*/ | ||
54 | /* | ||
55 | * Sanity routine to verify the sizes of the various WaveLAN interface | ||
56 | * structures. | ||
57 | */ | ||
58 | static char *wv_struct_check(void) | ||
59 | { | ||
60 | #define SC(t,s,n) if (sizeof(t) != s) return(n); | ||
61 | |||
62 | SC(psa_t, PSA_SIZE, "psa_t"); | ||
63 | SC(mmw_t, MMW_SIZE, "mmw_t"); | ||
64 | SC(mmr_t, MMR_SIZE, "mmr_t"); | ||
65 | SC(ha_t, HA_SIZE, "ha_t"); | ||
66 | |||
67 | #undef SC | ||
68 | |||
69 | return ((char *) NULL); | ||
70 | } /* wv_struct_check */ | ||
71 | #endif /* STRUCT_CHECK */ | ||
72 | |||
73 | /********************* HOST ADAPTER SUBROUTINES *********************/ | ||
74 | /* | ||
75 | * Useful subroutines to manage the WaveLAN ISA interface | ||
76 | * | ||
77 | * One major difference with the PCMCIA hardware (except the port mapping) | ||
78 | * is that we have to keep the state of the Host Control Register | ||
79 | * because of the interrupt enable & bus size flags. | ||
80 | */ | ||
81 | |||
82 | /*------------------------------------------------------------------*/ | ||
83 | /* | ||
84 | * Read from card's Host Adaptor Status Register. | ||
85 | */ | ||
86 | static inline u16 hasr_read(unsigned long ioaddr) | ||
87 | { | ||
88 | return (inw(HASR(ioaddr))); | ||
89 | } /* hasr_read */ | ||
90 | |||
91 | /*------------------------------------------------------------------*/ | ||
92 | /* | ||
93 | * Write to card's Host Adapter Command Register. | ||
94 | */ | ||
95 | static inline void hacr_write(unsigned long ioaddr, u16 hacr) | ||
96 | { | ||
97 | outw(hacr, HACR(ioaddr)); | ||
98 | } /* hacr_write */ | ||
99 | |||
100 | /*------------------------------------------------------------------*/ | ||
101 | /* | ||
102 | * Write to card's Host Adapter Command Register. Include a delay for | ||
103 | * those times when it is needed. | ||
104 | */ | ||
105 | static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr) | ||
106 | { | ||
107 | hacr_write(ioaddr, hacr); | ||
108 | /* delay might only be needed sometimes */ | ||
109 | mdelay(1); | ||
110 | } /* hacr_write_slow */ | ||
111 | |||
112 | /*------------------------------------------------------------------*/ | ||
113 | /* | ||
114 | * Set the channel attention bit. | ||
115 | */ | ||
116 | static inline void set_chan_attn(unsigned long ioaddr, u16 hacr) | ||
117 | { | ||
118 | hacr_write(ioaddr, hacr | HACR_CA); | ||
119 | } /* set_chan_attn */ | ||
120 | |||
121 | /*------------------------------------------------------------------*/ | ||
122 | /* | ||
123 | * Reset, and then set host adaptor into default mode. | ||
124 | */ | ||
125 | static inline void wv_hacr_reset(unsigned long ioaddr) | ||
126 | { | ||
127 | hacr_write_slow(ioaddr, HACR_RESET); | ||
128 | hacr_write(ioaddr, HACR_DEFAULT); | ||
129 | } /* wv_hacr_reset */ | ||
130 | |||
131 | /*------------------------------------------------------------------*/ | ||
132 | /* | ||
133 | * Set the I/O transfer over the ISA bus to 8-bit mode | ||
134 | */ | ||
135 | static inline void wv_16_off(unsigned long ioaddr, u16 hacr) | ||
136 | { | ||
137 | hacr &= ~HACR_16BITS; | ||
138 | hacr_write(ioaddr, hacr); | ||
139 | } /* wv_16_off */ | ||
140 | |||
141 | /*------------------------------------------------------------------*/ | ||
142 | /* | ||
143 | * Set the I/O transfer over the ISA bus to 8-bit mode | ||
144 | */ | ||
145 | static inline void wv_16_on(unsigned long ioaddr, u16 hacr) | ||
146 | { | ||
147 | hacr |= HACR_16BITS; | ||
148 | hacr_write(ioaddr, hacr); | ||
149 | } /* wv_16_on */ | ||
150 | |||
151 | /*------------------------------------------------------------------*/ | ||
152 | /* | ||
153 | * Disable interrupts on the WaveLAN hardware. | ||
154 | * (called by wv_82586_stop()) | ||
155 | */ | ||
156 | static inline void wv_ints_off(struct net_device * dev) | ||
157 | { | ||
158 | net_local *lp = (net_local *) dev->priv; | ||
159 | unsigned long ioaddr = dev->base_addr; | ||
160 | |||
161 | lp->hacr &= ~HACR_INTRON; | ||
162 | hacr_write(ioaddr, lp->hacr); | ||
163 | } /* wv_ints_off */ | ||
164 | |||
165 | /*------------------------------------------------------------------*/ | ||
166 | /* | ||
167 | * Enable interrupts on the WaveLAN hardware. | ||
168 | * (called by wv_hw_reset()) | ||
169 | */ | ||
170 | static inline void wv_ints_on(struct net_device * dev) | ||
171 | { | ||
172 | net_local *lp = (net_local *) dev->priv; | ||
173 | unsigned long ioaddr = dev->base_addr; | ||
174 | |||
175 | lp->hacr |= HACR_INTRON; | ||
176 | hacr_write(ioaddr, lp->hacr); | ||
177 | } /* wv_ints_on */ | ||
178 | |||
179 | /******************* MODEM MANAGEMENT SUBROUTINES *******************/ | ||
180 | /* | ||
181 | * Useful subroutines to manage the modem of the WaveLAN | ||
182 | */ | ||
183 | |||
184 | /*------------------------------------------------------------------*/ | ||
185 | /* | ||
186 | * Read the Parameter Storage Area from the WaveLAN card's memory | ||
187 | */ | ||
188 | /* | ||
189 | * Read bytes from the PSA. | ||
190 | */ | ||
191 | static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ | ||
192 | u8 * b, /* buffer to fill */ | ||
193 | int n) | ||
194 | { /* size to read */ | ||
195 | wv_16_off(ioaddr, hacr); | ||
196 | |||
197 | while (n-- > 0) { | ||
198 | outw(o, PIOR2(ioaddr)); | ||
199 | o++; | ||
200 | *b++ = inb(PIOP2(ioaddr)); | ||
201 | } | ||
202 | |||
203 | wv_16_on(ioaddr, hacr); | ||
204 | } /* psa_read */ | ||
205 | |||
206 | /*------------------------------------------------------------------*/ | ||
207 | /* | ||
208 | * Write the Parameter Storage Area to the WaveLAN card's memory. | ||
209 | */ | ||
210 | static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ | ||
211 | u8 * b, /* Buffer in memory */ | ||
212 | int n) | ||
213 | { /* Length of buffer */ | ||
214 | int count = 0; | ||
215 | |||
216 | wv_16_off(ioaddr, hacr); | ||
217 | |||
218 | while (n-- > 0) { | ||
219 | outw(o, PIOR2(ioaddr)); | ||
220 | o++; | ||
221 | |||
222 | outb(*b, PIOP2(ioaddr)); | ||
223 | b++; | ||
224 | |||
225 | /* Wait for the memory to finish its write cycle */ | ||
226 | count = 0; | ||
227 | while ((count++ < 100) && | ||
228 | (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); | ||
229 | } | ||
230 | |||
231 | wv_16_on(ioaddr, hacr); | ||
232 | } /* psa_write */ | ||
233 | |||
234 | #ifdef SET_PSA_CRC | ||
235 | /*------------------------------------------------------------------*/ | ||
236 | /* | ||
237 | * Calculate the PSA CRC | ||
238 | * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code | ||
239 | * NOTE: By specifying a length including the CRC position the | ||
240 | * returned value should be zero. (i.e. a correct checksum in the PSA) | ||
241 | * | ||
242 | * The Windows drivers don't use the CRC, but the AP and the PtP tool | ||
243 | * depend on it. | ||
244 | */ | ||
245 | static inline u16 psa_crc(u8 * psa, /* The PSA */ | ||
246 | int size) | ||
247 | { /* Number of short for CRC */ | ||
248 | int byte_cnt; /* Loop on the PSA */ | ||
249 | u16 crc_bytes = 0; /* Data in the PSA */ | ||
250 | int bit_cnt; /* Loop on the bits of the short */ | ||
251 | |||
252 | for (byte_cnt = 0; byte_cnt < size; byte_cnt++) { | ||
253 | crc_bytes ^= psa[byte_cnt]; /* Its an xor */ | ||
254 | |||
255 | for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) { | ||
256 | if (crc_bytes & 0x0001) | ||
257 | crc_bytes = (crc_bytes >> 1) ^ 0xA001; | ||
258 | else | ||
259 | crc_bytes >>= 1; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | return crc_bytes; | ||
264 | } /* psa_crc */ | ||
265 | #endif /* SET_PSA_CRC */ | ||
266 | |||
267 | /*------------------------------------------------------------------*/ | ||
268 | /* | ||
269 | * update the checksum field in the Wavelan's PSA | ||
270 | */ | ||
271 | static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) | ||
272 | { | ||
273 | #ifdef SET_PSA_CRC | ||
274 | psa_t psa; | ||
275 | u16 crc; | ||
276 | |||
277 | /* read the parameter storage area */ | ||
278 | psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); | ||
279 | |||
280 | /* update the checksum */ | ||
281 | crc = psa_crc((unsigned char *) &psa, | ||
282 | sizeof(psa) - sizeof(psa.psa_crc[0]) - | ||
283 | sizeof(psa.psa_crc[1]) | ||
284 | - sizeof(psa.psa_crc_status)); | ||
285 | |||
286 | psa.psa_crc[0] = crc & 0xFF; | ||
287 | psa.psa_crc[1] = (crc & 0xFF00) >> 8; | ||
288 | |||
289 | /* Write it ! */ | ||
290 | psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa, | ||
291 | (unsigned char *) &psa.psa_crc, 2); | ||
292 | |||
293 | #ifdef DEBUG_IOCTL_INFO | ||
294 | printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", | ||
295 | dev->name, psa.psa_crc[0], psa.psa_crc[1]); | ||
296 | |||
297 | /* Check again (luxury !) */ | ||
298 | crc = psa_crc((unsigned char *) &psa, | ||
299 | sizeof(psa) - sizeof(psa.psa_crc_status)); | ||
300 | |||
301 | if (crc != 0) | ||
302 | printk(KERN_WARNING | ||
303 | "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", | ||
304 | dev->name); | ||
305 | #endif /* DEBUG_IOCTL_INFO */ | ||
306 | #endif /* SET_PSA_CRC */ | ||
307 | } /* update_psa_checksum */ | ||
308 | |||
309 | /*------------------------------------------------------------------*/ | ||
310 | /* | ||
311 | * Write 1 byte to the MMC. | ||
312 | */ | ||
313 | static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d) | ||
314 | { | ||
315 | int count = 0; | ||
316 | |||
317 | /* Wait for MMC to go idle */ | ||
318 | while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) | ||
319 | udelay(10); | ||
320 | |||
321 | outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); | ||
322 | } | ||
323 | |||
324 | /*------------------------------------------------------------------*/ | ||
325 | /* | ||
326 | * Routine to write bytes to the Modem Management Controller. | ||
327 | * We start at the end because it is the way it should be! | ||
328 | */ | ||
329 | static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n) | ||
330 | { | ||
331 | o += n; | ||
332 | b += n; | ||
333 | |||
334 | while (n-- > 0) | ||
335 | mmc_out(ioaddr, --o, *(--b)); | ||
336 | } /* mmc_write */ | ||
337 | |||
338 | /*------------------------------------------------------------------*/ | ||
339 | /* | ||
340 | * Read a byte from the MMC. | ||
341 | * Optimised version for 1 byte, avoid using memory. | ||
342 | */ | ||
343 | static inline u8 mmc_in(unsigned long ioaddr, u16 o) | ||
344 | { | ||
345 | int count = 0; | ||
346 | |||
347 | while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) | ||
348 | udelay(10); | ||
349 | outw(o << 1, MMCR(ioaddr)); | ||
350 | |||
351 | while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) | ||
352 | udelay(10); | ||
353 | return (u8) (inw(MMCR(ioaddr)) >> 8); | ||
354 | } | ||
355 | |||
356 | /*------------------------------------------------------------------*/ | ||
357 | /* | ||
358 | * Routine to read bytes from the Modem Management Controller. | ||
359 | * The implementation is complicated by a lack of address lines, | ||
360 | * which prevents decoding of the low-order bit. | ||
361 | * (code has just been moved in the above function) | ||
362 | * We start at the end because it is the way it should be! | ||
363 | */ | ||
364 | static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n) | ||
365 | { | ||
366 | o += n; | ||
367 | b += n; | ||
368 | |||
369 | while (n-- > 0) | ||
370 | *(--b) = mmc_in(ioaddr, --o); | ||
371 | } /* mmc_read */ | ||
372 | |||
373 | /*------------------------------------------------------------------*/ | ||
374 | /* | ||
375 | * Get the type of encryption available. | ||
376 | */ | ||
377 | static inline int mmc_encr(unsigned long ioaddr) | ||
378 | { /* I/O port of the card */ | ||
379 | int temp; | ||
380 | |||
381 | temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); | ||
382 | if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) | ||
383 | return 0; | ||
384 | else | ||
385 | return temp; | ||
386 | } | ||
387 | |||
388 | /*------------------------------------------------------------------*/ | ||
389 | /* | ||
390 | * Wait for the frequency EEPROM to complete a command. | ||
391 | * I hope this one will be optimally inlined. | ||
392 | */ | ||
393 | static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */ | ||
394 | int delay, /* Base delay to wait for */ | ||
395 | int number) | ||
396 | { /* Number of time to wait */ | ||
397 | int count = 0; /* Wait only a limited time */ | ||
398 | |||
399 | while ((count++ < number) && | ||
400 | (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
401 | MMR_FEE_STATUS_BUSY)) udelay(delay); | ||
402 | } | ||
403 | |||
404 | /*------------------------------------------------------------------*/ | ||
405 | /* | ||
406 | * Read bytes from the Frequency EEPROM (frequency select cards). | ||
407 | */ | ||
408 | static void fee_read(unsigned long ioaddr, /* I/O port of the card */ | ||
409 | u16 o, /* destination offset */ | ||
410 | u16 * b, /* data buffer */ | ||
411 | int n) | ||
412 | { /* number of registers */ | ||
413 | b += n; /* Position at the end of the area */ | ||
414 | |||
415 | /* Write the address */ | ||
416 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
417 | |||
418 | /* Loop on all buffer */ | ||
419 | while (n-- > 0) { | ||
420 | /* Write the read command */ | ||
421 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
422 | MMW_FEE_CTRL_READ); | ||
423 | |||
424 | /* Wait until EEPROM is ready (should be quick). */ | ||
425 | fee_wait(ioaddr, 10, 100); | ||
426 | |||
427 | /* Read the value. */ | ||
428 | *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | | ||
429 | mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | #ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ | ||
434 | |||
435 | /*------------------------------------------------------------------*/ | ||
436 | /* | ||
437 | * Write bytes from the Frequency EEPROM (frequency select cards). | ||
438 | * This is a bit complicated, because the frequency EEPROM has to | ||
439 | * be unprotected and the write enabled. | ||
440 | * Jean II | ||
441 | */ | ||
442 | static void fee_write(unsigned long ioaddr, /* I/O port of the card */ | ||
443 | u16 o, /* destination offset */ | ||
444 | u16 * b, /* data buffer */ | ||
445 | int n) | ||
446 | { /* number of registers */ | ||
447 | b += n; /* Position at the end of the area. */ | ||
448 | |||
449 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
450 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
451 | /* Ask to read the protected register */ | ||
452 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); | ||
453 | |||
454 | fee_wait(ioaddr, 10, 100); | ||
455 | |||
456 | /* Read the protected register. */ | ||
457 | printk("Protected 2: %02X-%02X\n", | ||
458 | mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), | ||
459 | mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); | ||
460 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
461 | |||
462 | /* Enable protected register. */ | ||
463 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
464 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); | ||
465 | |||
466 | fee_wait(ioaddr, 10, 100); | ||
467 | |||
468 | /* Unprotect area. */ | ||
469 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); | ||
470 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
471 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
472 | /* or use: */ | ||
473 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); | ||
474 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
475 | |||
476 | fee_wait(ioaddr, 10, 100); | ||
477 | #endif /* EEPROM_IS_PROTECTED */ | ||
478 | |||
479 | /* Write enable. */ | ||
480 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
481 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); | ||
482 | |||
483 | fee_wait(ioaddr, 10, 100); | ||
484 | |||
485 | /* Write the EEPROM address. */ | ||
486 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
487 | |||
488 | /* Loop on all buffer */ | ||
489 | while (n-- > 0) { | ||
490 | /* Write the value. */ | ||
491 | mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); | ||
492 | mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); | ||
493 | |||
494 | /* Write the write command. */ | ||
495 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
496 | MMW_FEE_CTRL_WRITE); | ||
497 | |||
498 | /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ | ||
499 | mdelay(10); | ||
500 | fee_wait(ioaddr, 10, 100); | ||
501 | } | ||
502 | |||
503 | /* Write disable. */ | ||
504 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); | ||
505 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); | ||
506 | |||
507 | fee_wait(ioaddr, 10, 100); | ||
508 | |||
509 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
510 | /* Reprotect EEPROM. */ | ||
511 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); | ||
512 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
513 | |||
514 | fee_wait(ioaddr, 10, 100); | ||
515 | #endif /* EEPROM_IS_PROTECTED */ | ||
516 | } | ||
517 | #endif /* WIRELESS_EXT */ | ||
518 | |||
519 | /************************ I82586 SUBROUTINES *************************/ | ||
520 | /* | ||
521 | * Useful subroutines to manage the Ethernet controller | ||
522 | */ | ||
523 | |||
524 | /*------------------------------------------------------------------*/ | ||
525 | /* | ||
526 | * Read bytes from the on-board RAM. | ||
527 | * Why does inlining this function make it fail? | ||
528 | */ | ||
529 | static /*inline */ void obram_read(unsigned long ioaddr, | ||
530 | u16 o, u8 * b, int n) | ||
531 | { | ||
532 | outw(o, PIOR1(ioaddr)); | ||
533 | insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); | ||
534 | } | ||
535 | |||
536 | /*------------------------------------------------------------------*/ | ||
537 | /* | ||
538 | * Write bytes to the on-board RAM. | ||
539 | */ | ||
540 | static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) | ||
541 | { | ||
542 | outw(o, PIOR1(ioaddr)); | ||
543 | outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); | ||
544 | } | ||
545 | |||
546 | /*------------------------------------------------------------------*/ | ||
547 | /* | ||
548 | * Acknowledge the reading of the status issued by the i82586. | ||
549 | */ | ||
550 | static void wv_ack(struct net_device * dev) | ||
551 | { | ||
552 | net_local *lp = (net_local *) dev->priv; | ||
553 | unsigned long ioaddr = dev->base_addr; | ||
554 | u16 scb_cs; | ||
555 | int i; | ||
556 | |||
557 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), | ||
558 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
559 | scb_cs &= SCB_ST_INT; | ||
560 | |||
561 | if (scb_cs == 0) | ||
562 | return; | ||
563 | |||
564 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
565 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
566 | |||
567 | set_chan_attn(ioaddr, lp->hacr); | ||
568 | |||
569 | for (i = 1000; i > 0; i--) { | ||
570 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
571 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
572 | if (scb_cs == 0) | ||
573 | break; | ||
574 | |||
575 | udelay(10); | ||
576 | } | ||
577 | udelay(100); | ||
578 | |||
579 | #ifdef DEBUG_CONFIG_ERROR | ||
580 | if (i <= 0) | ||
581 | printk(KERN_INFO | ||
582 | "%s: wv_ack(): board not accepting command.\n", | ||
583 | dev->name); | ||
584 | #endif | ||
585 | } | ||
586 | |||
587 | /*------------------------------------------------------------------*/ | ||
588 | /* | ||
589 | * Set channel attention bit and busy wait until command has | ||
590 | * completed, then acknowledge completion of the command. | ||
591 | */ | ||
592 | static inline int wv_synchronous_cmd(struct net_device * dev, const char *str) | ||
593 | { | ||
594 | net_local *lp = (net_local *) dev->priv; | ||
595 | unsigned long ioaddr = dev->base_addr; | ||
596 | u16 scb_cmd; | ||
597 | ach_t cb; | ||
598 | int i; | ||
599 | |||
600 | scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; | ||
601 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
602 | (unsigned char *) &scb_cmd, sizeof(scb_cmd)); | ||
603 | |||
604 | set_chan_attn(ioaddr, lp->hacr); | ||
605 | |||
606 | for (i = 1000; i > 0; i--) { | ||
607 | obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, | ||
608 | sizeof(cb)); | ||
609 | if (cb.ac_status & AC_SFLD_C) | ||
610 | break; | ||
611 | |||
612 | udelay(10); | ||
613 | } | ||
614 | udelay(100); | ||
615 | |||
616 | if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) { | ||
617 | #ifdef DEBUG_CONFIG_ERROR | ||
618 | printk(KERN_INFO "%s: %s failed; status = 0x%x\n", | ||
619 | dev->name, str, cb.ac_status); | ||
620 | #endif | ||
621 | #ifdef DEBUG_I82586_SHOW | ||
622 | wv_scb_show(ioaddr); | ||
623 | #endif | ||
624 | return -1; | ||
625 | } | ||
626 | |||
627 | /* Ack the status */ | ||
628 | wv_ack(dev); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | /*------------------------------------------------------------------*/ | ||
634 | /* | ||
635 | * Configuration commands completion interrupt. | ||
636 | * Check if done, and if OK. | ||
637 | */ | ||
638 | static inline int | ||
639 | wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) | ||
640 | { | ||
641 | unsigned short mcs_addr; | ||
642 | unsigned short status; | ||
643 | int ret; | ||
644 | |||
645 | #ifdef DEBUG_INTERRUPT_TRACE | ||
646 | printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); | ||
647 | #endif | ||
648 | |||
649 | mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) | ||
650 | + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); | ||
651 | |||
652 | /* Read the status of the last command (set mc list). */ | ||
653 | obram_read(ioaddr, acoff(mcs_addr, ac_status), | ||
654 | (unsigned char *) &status, sizeof(status)); | ||
655 | |||
656 | /* If not completed -> exit */ | ||
657 | if ((status & AC_SFLD_C) == 0) | ||
658 | ret = 0; /* Not ready to be scrapped */ | ||
659 | else { | ||
660 | #ifdef DEBUG_CONFIG_ERROR | ||
661 | unsigned short cfg_addr; | ||
662 | unsigned short ias_addr; | ||
663 | |||
664 | /* Check mc_config command */ | ||
665 | if ((status & AC_SFLD_OK) != AC_SFLD_OK) | ||
666 | printk(KERN_INFO | ||
667 | "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", | ||
668 | dev->name, status); | ||
669 | |||
670 | /* check ia-config command */ | ||
671 | ias_addr = mcs_addr - sizeof(ac_ias_t); | ||
672 | obram_read(ioaddr, acoff(ias_addr, ac_status), | ||
673 | (unsigned char *) &status, sizeof(status)); | ||
674 | if ((status & AC_SFLD_OK) != AC_SFLD_OK) | ||
675 | printk(KERN_INFO | ||
676 | "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", | ||
677 | dev->name, status); | ||
678 | |||
679 | /* Check config command. */ | ||
680 | cfg_addr = ias_addr - sizeof(ac_cfg_t); | ||
681 | obram_read(ioaddr, acoff(cfg_addr, ac_status), | ||
682 | (unsigned char *) &status, sizeof(status)); | ||
683 | if ((status & AC_SFLD_OK) != AC_SFLD_OK) | ||
684 | printk(KERN_INFO | ||
685 | "%s: wv_config_complete(): configure failed; status = 0x%x\n", | ||
686 | dev->name, status); | ||
687 | #endif /* DEBUG_CONFIG_ERROR */ | ||
688 | |||
689 | ret = 1; /* Ready to be scrapped */ | ||
690 | } | ||
691 | |||
692 | #ifdef DEBUG_INTERRUPT_TRACE | ||
693 | printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, | ||
694 | ret); | ||
695 | #endif | ||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | /*------------------------------------------------------------------*/ | ||
700 | /* | ||
701 | * Command completion interrupt. | ||
702 | * Reclaim as many freed tx buffers as we can. | ||
703 | * (called in wavelan_interrupt()). | ||
704 | * Note : the spinlock is already grabbed for us. | ||
705 | */ | ||
706 | static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) | ||
707 | { | ||
708 | int nreaped = 0; | ||
709 | |||
710 | #ifdef DEBUG_INTERRUPT_TRACE | ||
711 | printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); | ||
712 | #endif | ||
713 | |||
714 | /* Loop on all the transmit buffers */ | ||
715 | while (lp->tx_first_in_use != I82586NULL) { | ||
716 | unsigned short tx_status; | ||
717 | |||
718 | /* Read the first transmit buffer */ | ||
719 | obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), | ||
720 | (unsigned char *) &tx_status, | ||
721 | sizeof(tx_status)); | ||
722 | |||
723 | /* If not completed -> exit */ | ||
724 | if ((tx_status & AC_SFLD_C) == 0) | ||
725 | break; | ||
726 | |||
727 | /* Hack for reconfiguration */ | ||
728 | if (tx_status == 0xFFFF) | ||
729 | if (!wv_config_complete(dev, ioaddr, lp)) | ||
730 | break; /* Not completed */ | ||
731 | |||
732 | /* We now remove this buffer */ | ||
733 | nreaped++; | ||
734 | --lp->tx_n_in_use; | ||
735 | |||
736 | /* | ||
737 | if (lp->tx_n_in_use > 0) | ||
738 | printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); | ||
739 | */ | ||
740 | |||
741 | /* Was it the last one? */ | ||
742 | if (lp->tx_n_in_use <= 0) | ||
743 | lp->tx_first_in_use = I82586NULL; | ||
744 | else { | ||
745 | /* Next one in the chain */ | ||
746 | lp->tx_first_in_use += TXBLOCKZ; | ||
747 | if (lp->tx_first_in_use >= | ||
748 | OFFSET_CU + | ||
749 | NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= | ||
750 | NTXBLOCKS * TXBLOCKZ; | ||
751 | } | ||
752 | |||
753 | /* Hack for reconfiguration */ | ||
754 | if (tx_status == 0xFFFF) | ||
755 | continue; | ||
756 | |||
757 | /* Now, check status of the finished command */ | ||
758 | if (tx_status & AC_SFLD_OK) { | ||
759 | int ncollisions; | ||
760 | |||
761 | lp->stats.tx_packets++; | ||
762 | ncollisions = tx_status & AC_SFLD_MAXCOL; | ||
763 | lp->stats.collisions += ncollisions; | ||
764 | #ifdef DEBUG_TX_INFO | ||
765 | if (ncollisions > 0) | ||
766 | printk(KERN_DEBUG | ||
767 | "%s: wv_complete(): tx completed after %d collisions.\n", | ||
768 | dev->name, ncollisions); | ||
769 | #endif | ||
770 | } else { | ||
771 | lp->stats.tx_errors++; | ||
772 | if (tx_status & AC_SFLD_S10) { | ||
773 | lp->stats.tx_carrier_errors++; | ||
774 | #ifdef DEBUG_TX_FAIL | ||
775 | printk(KERN_DEBUG | ||
776 | "%s: wv_complete(): tx error: no CS.\n", | ||
777 | dev->name); | ||
778 | #endif | ||
779 | } | ||
780 | if (tx_status & AC_SFLD_S9) { | ||
781 | lp->stats.tx_carrier_errors++; | ||
782 | #ifdef DEBUG_TX_FAIL | ||
783 | printk(KERN_DEBUG | ||
784 | "%s: wv_complete(): tx error: lost CTS.\n", | ||
785 | dev->name); | ||
786 | #endif | ||
787 | } | ||
788 | if (tx_status & AC_SFLD_S8) { | ||
789 | lp->stats.tx_fifo_errors++; | ||
790 | #ifdef DEBUG_TX_FAIL | ||
791 | printk(KERN_DEBUG | ||
792 | "%s: wv_complete(): tx error: slow DMA.\n", | ||
793 | dev->name); | ||
794 | #endif | ||
795 | } | ||
796 | if (tx_status & AC_SFLD_S6) { | ||
797 | lp->stats.tx_heartbeat_errors++; | ||
798 | #ifdef DEBUG_TX_FAIL | ||
799 | printk(KERN_DEBUG | ||
800 | "%s: wv_complete(): tx error: heart beat.\n", | ||
801 | dev->name); | ||
802 | #endif | ||
803 | } | ||
804 | if (tx_status & AC_SFLD_S5) { | ||
805 | lp->stats.tx_aborted_errors++; | ||
806 | #ifdef DEBUG_TX_FAIL | ||
807 | printk(KERN_DEBUG | ||
808 | "%s: wv_complete(): tx error: too many collisions.\n", | ||
809 | dev->name); | ||
810 | #endif | ||
811 | } | ||
812 | } | ||
813 | |||
814 | #ifdef DEBUG_TX_INFO | ||
815 | printk(KERN_DEBUG | ||
816 | "%s: wv_complete(): tx completed, tx_status 0x%04x\n", | ||
817 | dev->name, tx_status); | ||
818 | #endif | ||
819 | } | ||
820 | |||
821 | #ifdef DEBUG_INTERRUPT_INFO | ||
822 | if (nreaped > 1) | ||
823 | printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", | ||
824 | dev->name, nreaped); | ||
825 | #endif | ||
826 | |||
827 | /* | ||
828 | * Inform upper layers. | ||
829 | */ | ||
830 | if (lp->tx_n_in_use < NTXBLOCKS - 1) { | ||
831 | netif_wake_queue(dev); | ||
832 | } | ||
833 | #ifdef DEBUG_INTERRUPT_TRACE | ||
834 | printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); | ||
835 | #endif | ||
836 | return nreaped; | ||
837 | } | ||
838 | |||
839 | /*------------------------------------------------------------------*/ | ||
840 | /* | ||
841 | * Reconfigure the i82586, or at least ask for it. | ||
842 | * Because wv_82586_config uses a transmission buffer, we must do it | ||
843 | * when we are sure that there is one left, so we do it now | ||
844 | * or in wavelan_packet_xmit() (I can't find any better place, | ||
845 | * wavelan_interrupt is not an option), so you may experience | ||
846 | * delays sometimes. | ||
847 | */ | ||
848 | static inline void wv_82586_reconfig(struct net_device * dev) | ||
849 | { | ||
850 | net_local *lp = (net_local *) dev->priv; | ||
851 | unsigned long flags; | ||
852 | |||
853 | /* Arm the flag, will be cleard in wv_82586_config() */ | ||
854 | lp->reconfig_82586 = 1; | ||
855 | |||
856 | /* Check if we can do it now ! */ | ||
857 | if((netif_running(dev)) && !(netif_queue_stopped(dev))) { | ||
858 | spin_lock_irqsave(&lp->spinlock, flags); | ||
859 | /* May fail */ | ||
860 | wv_82586_config(dev); | ||
861 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
862 | } | ||
863 | else { | ||
864 | #ifdef DEBUG_CONFIG_INFO | ||
865 | printk(KERN_DEBUG | ||
866 | "%s: wv_82586_reconfig(): delayed (state = %lX)\n", | ||
867 | dev->name, dev->state); | ||
868 | #endif | ||
869 | } | ||
870 | } | ||
871 | |||
872 | /********************* DEBUG & INFO SUBROUTINES *********************/ | ||
873 | /* | ||
874 | * This routine is used in the code to show information for debugging. | ||
875 | * Most of the time, it dumps the contents of hardware structures. | ||
876 | */ | ||
877 | |||
878 | #ifdef DEBUG_PSA_SHOW | ||
879 | /*------------------------------------------------------------------*/ | ||
880 | /* | ||
881 | * Print the formatted contents of the Parameter Storage Area. | ||
882 | */ | ||
883 | static void wv_psa_show(psa_t * p) | ||
884 | { | ||
885 | printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); | ||
886 | printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", | ||
887 | p->psa_io_base_addr_1, | ||
888 | p->psa_io_base_addr_2, | ||
889 | p->psa_io_base_addr_3, p->psa_io_base_addr_4); | ||
890 | printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", | ||
891 | p->psa_rem_boot_addr_1, | ||
892 | p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); | ||
893 | printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); | ||
894 | printk("psa_int_req_no: %d\n", p->psa_int_req_no); | ||
895 | #ifdef DEBUG_SHOW_UNUSED | ||
896 | printk(KERN_DEBUG | ||
897 | "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
898 | p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], | ||
899 | p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], | ||
900 | p->psa_unused0[6]); | ||
901 | #endif /* DEBUG_SHOW_UNUSED */ | ||
902 | printk(KERN_DEBUG | ||
903 | "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
904 | p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], | ||
905 | p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3], | ||
906 | p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]); | ||
907 | printk(KERN_DEBUG | ||
908 | "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
909 | p->psa_local_mac_addr[0], p->psa_local_mac_addr[1], | ||
910 | p->psa_local_mac_addr[2], p->psa_local_mac_addr[3], | ||
911 | p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]); | ||
912 | printk(KERN_DEBUG "psa_univ_local_sel: %d, ", | ||
913 | p->psa_univ_local_sel); | ||
914 | printk("psa_comp_number: %d, ", p->psa_comp_number); | ||
915 | printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); | ||
916 | printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", | ||
917 | p->psa_feature_select); | ||
918 | printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); | ||
919 | printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); | ||
920 | printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); | ||
921 | printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], | ||
922 | p->psa_nwid[1]); | ||
923 | printk("psa_nwid_select: %d\n", p->psa_nwid_select); | ||
924 | printk(KERN_DEBUG "psa_encryption_select: %d, ", | ||
925 | p->psa_encryption_select); | ||
926 | printk | ||
927 | ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
928 | p->psa_encryption_key[0], p->psa_encryption_key[1], | ||
929 | p->psa_encryption_key[2], p->psa_encryption_key[3], | ||
930 | p->psa_encryption_key[4], p->psa_encryption_key[5], | ||
931 | p->psa_encryption_key[6], p->psa_encryption_key[7]); | ||
932 | printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); | ||
933 | printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", | ||
934 | p->psa_call_code[0]); | ||
935 | printk | ||
936 | ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
937 | p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2], | ||
938 | p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5], | ||
939 | p->psa_call_code[6], p->psa_call_code[7]); | ||
940 | #ifdef DEBUG_SHOW_UNUSED | ||
941 | printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", | ||
942 | p->psa_reserved[0], | ||
943 | p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]); | ||
944 | #endif /* DEBUG_SHOW_UNUSED */ | ||
945 | printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); | ||
946 | printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); | ||
947 | printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); | ||
948 | } /* wv_psa_show */ | ||
949 | #endif /* DEBUG_PSA_SHOW */ | ||
950 | |||
951 | #ifdef DEBUG_MMC_SHOW | ||
952 | /*------------------------------------------------------------------*/ | ||
953 | /* | ||
954 | * Print the formatted status of the Modem Management Controller. | ||
955 | * This function needs to be completed. | ||
956 | */ | ||
957 | static void wv_mmc_show(struct net_device * dev) | ||
958 | { | ||
959 | unsigned long ioaddr = dev->base_addr; | ||
960 | net_local *lp = (net_local *) dev->priv; | ||
961 | mmr_t m; | ||
962 | |||
963 | /* Basic check */ | ||
964 | if (hasr_read(ioaddr) & HASR_NO_CLK) { | ||
965 | printk(KERN_WARNING | ||
966 | "%s: wv_mmc_show: modem not connected\n", | ||
967 | dev->name); | ||
968 | return; | ||
969 | } | ||
970 | |||
971 | /* Read the mmc */ | ||
972 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); | ||
973 | mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); | ||
974 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); | ||
975 | |||
976 | #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ | ||
977 | /* Don't forget to update statistics */ | ||
978 | lp->wstats.discard.nwid += | ||
979 | (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
980 | #endif /* WIRELESS_EXT */ | ||
981 | |||
982 | printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); | ||
983 | #ifdef DEBUG_SHOW_UNUSED | ||
984 | printk(KERN_DEBUG | ||
985 | "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
986 | m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2], | ||
987 | m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5], | ||
988 | m.mmr_unused0[6], m.mmr_unused0[7]); | ||
989 | #endif /* DEBUG_SHOW_UNUSED */ | ||
990 | printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", | ||
991 | m.mmr_des_avail, m.mmr_des_status); | ||
992 | #ifdef DEBUG_SHOW_UNUSED | ||
993 | printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", | ||
994 | m.mmr_unused1[0], | ||
995 | m.mmr_unused1[1], | ||
996 | m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]); | ||
997 | #endif /* DEBUG_SHOW_UNUSED */ | ||
998 | printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", | ||
999 | m.mmr_dce_status, | ||
1000 | (m. | ||
1001 | mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? | ||
1002 | "energy detected," : "", | ||
1003 | (m. | ||
1004 | mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? | ||
1005 | "loop test indicated," : "", | ||
1006 | (m. | ||
1007 | mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? | ||
1008 | "transmitter on," : "", | ||
1009 | (m. | ||
1010 | mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? | ||
1011 | "jabber timer expired," : ""); | ||
1012 | printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id); | ||
1013 | #ifdef DEBUG_SHOW_UNUSED | ||
1014 | printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", | ||
1015 | m.mmr_unused2[0], m.mmr_unused2[1]); | ||
1016 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1017 | printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", | ||
1018 | (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, | ||
1019 | (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); | ||
1020 | printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", | ||
1021 | m.mmr_thr_pre_set & MMR_THR_PRE_SET, | ||
1022 | (m. | ||
1023 | mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : | ||
1024 | "below"); | ||
1025 | printk(KERN_DEBUG "signal_lvl: %d [%s], ", | ||
1026 | m.mmr_signal_lvl & MMR_SIGNAL_LVL, | ||
1027 | (m. | ||
1028 | mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : | ||
1029 | "no new msg"); | ||
1030 | printk("silence_lvl: %d [%s], ", | ||
1031 | m.mmr_silence_lvl & MMR_SILENCE_LVL, | ||
1032 | (m. | ||
1033 | mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : | ||
1034 | "no new update"); | ||
1035 | printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, | ||
1036 | (m. | ||
1037 | mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : | ||
1038 | "Antenna 0"); | ||
1039 | #ifdef DEBUG_SHOW_UNUSED | ||
1040 | printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); | ||
1041 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1042 | } /* wv_mmc_show */ | ||
1043 | #endif /* DEBUG_MMC_SHOW */ | ||
1044 | |||
1045 | #ifdef DEBUG_I82586_SHOW | ||
1046 | /*------------------------------------------------------------------*/ | ||
1047 | /* | ||
1048 | * Print the last block of the i82586 memory. | ||
1049 | */ | ||
1050 | static void wv_scb_show(unsigned long ioaddr) | ||
1051 | { | ||
1052 | scb_t scb; | ||
1053 | |||
1054 | obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, | ||
1055 | sizeof(scb)); | ||
1056 | |||
1057 | printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); | ||
1058 | |||
1059 | printk(KERN_DEBUG "status: "); | ||
1060 | printk("stat 0x%x[%s%s%s%s] ", | ||
1061 | (scb. | ||
1062 | scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | | ||
1063 | SCB_ST_RNR)) >> 12, | ||
1064 | (scb. | ||
1065 | scb_status & SCB_ST_CX) ? "command completion interrupt," : | ||
1066 | "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", | ||
1067 | (scb. | ||
1068 | scb_status & SCB_ST_CNA) ? "command unit not active," : "", | ||
1069 | (scb. | ||
1070 | scb_status & SCB_ST_RNR) ? "receiving unit not ready," : | ||
1071 | ""); | ||
1072 | printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, | ||
1073 | ((scb.scb_status & SCB_ST_CUS) == | ||
1074 | SCB_ST_CUS_IDLE) ? "idle" : "", | ||
1075 | ((scb.scb_status & SCB_ST_CUS) == | ||
1076 | SCB_ST_CUS_SUSP) ? "suspended" : "", | ||
1077 | ((scb.scb_status & SCB_ST_CUS) == | ||
1078 | SCB_ST_CUS_ACTV) ? "active" : ""); | ||
1079 | printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4, | ||
1080 | ((scb.scb_status & SCB_ST_RUS) == | ||
1081 | SCB_ST_RUS_IDLE) ? "idle" : "", | ||
1082 | ((scb.scb_status & SCB_ST_RUS) == | ||
1083 | SCB_ST_RUS_SUSP) ? "suspended" : "", | ||
1084 | ((scb.scb_status & SCB_ST_RUS) == | ||
1085 | SCB_ST_RUS_NRES) ? "no resources" : "", | ||
1086 | ((scb.scb_status & SCB_ST_RUS) == | ||
1087 | SCB_ST_RUS_RDY) ? "ready" : ""); | ||
1088 | |||
1089 | printk(KERN_DEBUG "command: "); | ||
1090 | printk("ack 0x%x[%s%s%s%s] ", | ||
1091 | (scb. | ||
1092 | scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | | ||
1093 | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, | ||
1094 | (scb. | ||
1095 | scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", | ||
1096 | (scb. | ||
1097 | scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", | ||
1098 | (scb. | ||
1099 | scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", | ||
1100 | (scb. | ||
1101 | scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); | ||
1102 | printk("cuc 0x%x[%s%s%s%s%s] ", | ||
1103 | (scb.scb_command & SCB_CMD_CUC) >> 8, | ||
1104 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1105 | SCB_CMD_CUC_NOP) ? "nop" : "", | ||
1106 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1107 | SCB_CMD_CUC_GO) ? "start cbl_offset" : "", | ||
1108 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1109 | SCB_CMD_CUC_RES) ? "resume execution" : "", | ||
1110 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1111 | SCB_CMD_CUC_SUS) ? "suspend execution" : "", | ||
1112 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1113 | SCB_CMD_CUC_ABT) ? "abort execution" : ""); | ||
1114 | printk("ruc 0x%x[%s%s%s%s%s]\n", | ||
1115 | (scb.scb_command & SCB_CMD_RUC) >> 4, | ||
1116 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1117 | SCB_CMD_RUC_NOP) ? "nop" : "", | ||
1118 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1119 | SCB_CMD_RUC_GO) ? "start rfa_offset" : "", | ||
1120 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1121 | SCB_CMD_RUC_RES) ? "resume reception" : "", | ||
1122 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1123 | SCB_CMD_RUC_SUS) ? "suspend reception" : "", | ||
1124 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1125 | SCB_CMD_RUC_ABT) ? "abort reception" : ""); | ||
1126 | |||
1127 | printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); | ||
1128 | printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); | ||
1129 | |||
1130 | printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); | ||
1131 | printk("alnerrs %d ", scb.scb_alnerrs); | ||
1132 | printk("rscerrs %d ", scb.scb_rscerrs); | ||
1133 | printk("ovrnerrs %d\n", scb.scb_ovrnerrs); | ||
1134 | } | ||
1135 | |||
1136 | /*------------------------------------------------------------------*/ | ||
1137 | /* | ||
1138 | * Print the formatted status of the i82586's receive unit. | ||
1139 | */ | ||
1140 | static void wv_ru_show(struct net_device * dev) | ||
1141 | { | ||
1142 | /* net_local *lp = (net_local *) dev->priv; */ | ||
1143 | |||
1144 | printk(KERN_DEBUG | ||
1145 | "##### WaveLAN i82586 receiver unit status: #####\n"); | ||
1146 | printk(KERN_DEBUG "ru:"); | ||
1147 | /* | ||
1148 | * Not implemented yet | ||
1149 | */ | ||
1150 | printk("\n"); | ||
1151 | } /* wv_ru_show */ | ||
1152 | |||
1153 | /*------------------------------------------------------------------*/ | ||
1154 | /* | ||
1155 | * Display info about one control block of the i82586 memory. | ||
1156 | */ | ||
1157 | static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) | ||
1158 | { | ||
1159 | unsigned long ioaddr; | ||
1160 | ac_tx_t actx; | ||
1161 | |||
1162 | ioaddr = dev->base_addr; | ||
1163 | |||
1164 | printk("%d: 0x%x:", i, p); | ||
1165 | |||
1166 | obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx)); | ||
1167 | printk(" status=0x%x,", actx.tx_h.ac_status); | ||
1168 | printk(" command=0x%x,", actx.tx_h.ac_command); | ||
1169 | |||
1170 | /* | ||
1171 | { | ||
1172 | tbd_t tbd; | ||
1173 | |||
1174 | obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); | ||
1175 | printk(" tbd_status=0x%x,", tbd.tbd_status); | ||
1176 | } | ||
1177 | */ | ||
1178 | |||
1179 | printk("|"); | ||
1180 | } | ||
1181 | |||
1182 | /*------------------------------------------------------------------*/ | ||
1183 | /* | ||
1184 | * Print status of the command unit of the i82586. | ||
1185 | */ | ||
1186 | static void wv_cu_show(struct net_device * dev) | ||
1187 | { | ||
1188 | net_local *lp = (net_local *) dev->priv; | ||
1189 | unsigned int i; | ||
1190 | u16 p; | ||
1191 | |||
1192 | printk(KERN_DEBUG | ||
1193 | "##### WaveLAN i82586 command unit status: #####\n"); | ||
1194 | |||
1195 | printk(KERN_DEBUG); | ||
1196 | for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) { | ||
1197 | wv_cu_show_one(dev, lp, i, p); | ||
1198 | |||
1199 | p += TXBLOCKZ; | ||
1200 | if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) | ||
1201 | p -= NTXBLOCKS * TXBLOCKZ; | ||
1202 | } | ||
1203 | printk("\n"); | ||
1204 | } | ||
1205 | #endif /* DEBUG_I82586_SHOW */ | ||
1206 | |||
1207 | #ifdef DEBUG_DEVICE_SHOW | ||
1208 | /*------------------------------------------------------------------*/ | ||
1209 | /* | ||
1210 | * Print the formatted status of the WaveLAN PCMCIA device driver. | ||
1211 | */ | ||
1212 | static void wv_dev_show(struct net_device * dev) | ||
1213 | { | ||
1214 | printk(KERN_DEBUG "dev:"); | ||
1215 | printk(" state=%lX,", dev->state); | ||
1216 | printk(" trans_start=%ld,", dev->trans_start); | ||
1217 | printk(" flags=0x%x,", dev->flags); | ||
1218 | printk("\n"); | ||
1219 | } /* wv_dev_show */ | ||
1220 | |||
1221 | /*------------------------------------------------------------------*/ | ||
1222 | /* | ||
1223 | * Print the formatted status of the WaveLAN PCMCIA device driver's | ||
1224 | * private information. | ||
1225 | */ | ||
1226 | static void wv_local_show(struct net_device * dev) | ||
1227 | { | ||
1228 | net_local *lp; | ||
1229 | |||
1230 | lp = (net_local *) dev->priv; | ||
1231 | |||
1232 | printk(KERN_DEBUG "local:"); | ||
1233 | printk(" tx_n_in_use=%d,", lp->tx_n_in_use); | ||
1234 | printk(" hacr=0x%x,", lp->hacr); | ||
1235 | printk(" rx_head=0x%x,", lp->rx_head); | ||
1236 | printk(" rx_last=0x%x,", lp->rx_last); | ||
1237 | printk(" tx_first_free=0x%x,", lp->tx_first_free); | ||
1238 | printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); | ||
1239 | printk("\n"); | ||
1240 | } /* wv_local_show */ | ||
1241 | #endif /* DEBUG_DEVICE_SHOW */ | ||
1242 | |||
1243 | #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) | ||
1244 | /*------------------------------------------------------------------*/ | ||
1245 | /* | ||
1246 | * Dump packet header (and content if necessary) on the screen | ||
1247 | */ | ||
1248 | static inline void wv_packet_info(u8 * p, /* Packet to dump */ | ||
1249 | int length, /* Length of the packet */ | ||
1250 | char *msg1, /* Name of the device */ | ||
1251 | char *msg2) | ||
1252 | { /* Name of the function */ | ||
1253 | int i; | ||
1254 | int maxi; | ||
1255 | |||
1256 | printk(KERN_DEBUG | ||
1257 | "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", | ||
1258 | msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); | ||
1259 | printk(KERN_DEBUG | ||
1260 | "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", | ||
1261 | msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], | ||
1262 | p[13]); | ||
1263 | |||
1264 | #ifdef DEBUG_PACKET_DUMP | ||
1265 | |||
1266 | printk(KERN_DEBUG "data=\""); | ||
1267 | |||
1268 | if ((maxi = length) > DEBUG_PACKET_DUMP) | ||
1269 | maxi = DEBUG_PACKET_DUMP; | ||
1270 | for (i = 14; i < maxi; i++) | ||
1271 | if (p[i] >= ' ' && p[i] <= '~') | ||
1272 | printk(" %c", p[i]); | ||
1273 | else | ||
1274 | printk("%02X", p[i]); | ||
1275 | if (maxi < length) | ||
1276 | printk(".."); | ||
1277 | printk("\"\n"); | ||
1278 | printk(KERN_DEBUG "\n"); | ||
1279 | #endif /* DEBUG_PACKET_DUMP */ | ||
1280 | } | ||
1281 | #endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ | ||
1282 | |||
1283 | /*------------------------------------------------------------------*/ | ||
1284 | /* | ||
1285 | * This is the information which is displayed by the driver at startup. | ||
1286 | * There are lots of flags for configuring it to your liking. | ||
1287 | */ | ||
1288 | static inline void wv_init_info(struct net_device * dev) | ||
1289 | { | ||
1290 | short ioaddr = dev->base_addr; | ||
1291 | net_local *lp = (net_local *) dev->priv; | ||
1292 | psa_t psa; | ||
1293 | int i; | ||
1294 | |||
1295 | /* Read the parameter storage area */ | ||
1296 | psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); | ||
1297 | |||
1298 | #ifdef DEBUG_PSA_SHOW | ||
1299 | wv_psa_show(&psa); | ||
1300 | #endif | ||
1301 | #ifdef DEBUG_MMC_SHOW | ||
1302 | wv_mmc_show(dev); | ||
1303 | #endif | ||
1304 | #ifdef DEBUG_I82586_SHOW | ||
1305 | wv_cu_show(dev); | ||
1306 | #endif | ||
1307 | |||
1308 | #ifdef DEBUG_BASIC_SHOW | ||
1309 | /* Now, let's go for the basic stuff. */ | ||
1310 | printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); | ||
1311 | for (i = 0; i < WAVELAN_ADDR_SIZE; i++) | ||
1312 | printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); | ||
1313 | printk(", IRQ %d", dev->irq); | ||
1314 | |||
1315 | /* Print current network ID. */ | ||
1316 | if (psa.psa_nwid_select) | ||
1317 | printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], | ||
1318 | psa.psa_nwid[1]); | ||
1319 | else | ||
1320 | printk(", nwid off"); | ||
1321 | |||
1322 | /* If 2.00 card */ | ||
1323 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
1324 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
1325 | unsigned short freq; | ||
1326 | |||
1327 | /* Ask the EEPROM to read the frequency from the first area. */ | ||
1328 | fee_read(ioaddr, 0x00, &freq, 1); | ||
1329 | |||
1330 | /* Print frequency */ | ||
1331 | printk(", 2.00, %ld", (freq >> 6) + 2400L); | ||
1332 | |||
1333 | /* Hack! */ | ||
1334 | if (freq & 0x20) | ||
1335 | printk(".5"); | ||
1336 | } else { | ||
1337 | printk(", PC"); | ||
1338 | switch (psa.psa_comp_number) { | ||
1339 | case PSA_COMP_PC_AT_915: | ||
1340 | case PSA_COMP_PC_AT_2400: | ||
1341 | printk("-AT"); | ||
1342 | break; | ||
1343 | case PSA_COMP_PC_MC_915: | ||
1344 | case PSA_COMP_PC_MC_2400: | ||
1345 | printk("-MC"); | ||
1346 | break; | ||
1347 | case PSA_COMP_PCMCIA_915: | ||
1348 | printk("MCIA"); | ||
1349 | break; | ||
1350 | default: | ||
1351 | printk("?"); | ||
1352 | } | ||
1353 | printk(", "); | ||
1354 | switch (psa.psa_subband) { | ||
1355 | case PSA_SUBBAND_915: | ||
1356 | printk("915"); | ||
1357 | break; | ||
1358 | case PSA_SUBBAND_2425: | ||
1359 | printk("2425"); | ||
1360 | break; | ||
1361 | case PSA_SUBBAND_2460: | ||
1362 | printk("2460"); | ||
1363 | break; | ||
1364 | case PSA_SUBBAND_2484: | ||
1365 | printk("2484"); | ||
1366 | break; | ||
1367 | case PSA_SUBBAND_2430_5: | ||
1368 | printk("2430.5"); | ||
1369 | break; | ||
1370 | default: | ||
1371 | printk("?"); | ||
1372 | } | ||
1373 | } | ||
1374 | |||
1375 | printk(" MHz\n"); | ||
1376 | #endif /* DEBUG_BASIC_SHOW */ | ||
1377 | |||
1378 | #ifdef DEBUG_VERSION_SHOW | ||
1379 | /* Print version information */ | ||
1380 | printk(KERN_NOTICE "%s", version); | ||
1381 | #endif | ||
1382 | } /* wv_init_info */ | ||
1383 | |||
1384 | /********************* IOCTL, STATS & RECONFIG *********************/ | ||
1385 | /* | ||
1386 | * We found here routines that are called by Linux on different | ||
1387 | * occasions after the configuration and not for transmitting data | ||
1388 | * These may be called when the user use ifconfig, /proc/net/dev | ||
1389 | * or wireless extensions | ||
1390 | */ | ||
1391 | |||
1392 | /*------------------------------------------------------------------*/ | ||
1393 | /* | ||
1394 | * Get the current Ethernet statistics. This may be called with the | ||
1395 | * card open or closed. | ||
1396 | * Used when the user read /proc/net/dev | ||
1397 | */ | ||
1398 | static en_stats *wavelan_get_stats(struct net_device * dev) | ||
1399 | { | ||
1400 | #ifdef DEBUG_IOCTL_TRACE | ||
1401 | printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); | ||
1402 | #endif | ||
1403 | |||
1404 | return (&((net_local *) dev->priv)->stats); | ||
1405 | } | ||
1406 | |||
1407 | /*------------------------------------------------------------------*/ | ||
1408 | /* | ||
1409 | * Set or clear the multicast filter for this adaptor. | ||
1410 | * num_addrs == -1 Promiscuous mode, receive all packets | ||
1411 | * num_addrs == 0 Normal mode, clear multicast list | ||
1412 | * num_addrs > 0 Multicast mode, receive normal and MC packets, | ||
1413 | * and do best-effort filtering. | ||
1414 | */ | ||
1415 | static void wavelan_set_multicast_list(struct net_device * dev) | ||
1416 | { | ||
1417 | net_local *lp = (net_local *) dev->priv; | ||
1418 | |||
1419 | #ifdef DEBUG_IOCTL_TRACE | ||
1420 | printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", | ||
1421 | dev->name); | ||
1422 | #endif | ||
1423 | |||
1424 | #ifdef DEBUG_IOCTL_INFO | ||
1425 | printk(KERN_DEBUG | ||
1426 | "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", | ||
1427 | dev->name, dev->flags, dev->mc_count); | ||
1428 | #endif | ||
1429 | |||
1430 | /* Are we asking for promiscuous mode, | ||
1431 | * or all multicast addresses (we don't have that!) | ||
1432 | * or too many multicast addresses for the hardware filter? */ | ||
1433 | if ((dev->flags & IFF_PROMISC) || | ||
1434 | (dev->flags & IFF_ALLMULTI) || | ||
1435 | (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { | ||
1436 | /* | ||
1437 | * Enable promiscuous mode: receive all packets. | ||
1438 | */ | ||
1439 | if (!lp->promiscuous) { | ||
1440 | lp->promiscuous = 1; | ||
1441 | lp->mc_count = 0; | ||
1442 | |||
1443 | wv_82586_reconfig(dev); | ||
1444 | |||
1445 | /* Tell the kernel that we are doing a really bad job. */ | ||
1446 | dev->flags |= IFF_PROMISC; | ||
1447 | } | ||
1448 | } else | ||
1449 | /* Are there multicast addresses to send? */ | ||
1450 | if (dev->mc_list != (struct dev_mc_list *) NULL) { | ||
1451 | /* | ||
1452 | * Disable promiscuous mode, but receive all packets | ||
1453 | * in multicast list | ||
1454 | */ | ||
1455 | #ifdef MULTICAST_AVOID | ||
1456 | if (lp->promiscuous || (dev->mc_count != lp->mc_count)) | ||
1457 | #endif | ||
1458 | { | ||
1459 | lp->promiscuous = 0; | ||
1460 | lp->mc_count = dev->mc_count; | ||
1461 | |||
1462 | wv_82586_reconfig(dev); | ||
1463 | } | ||
1464 | } else { | ||
1465 | /* | ||
1466 | * Switch to normal mode: disable promiscuous mode and | ||
1467 | * clear the multicast list. | ||
1468 | */ | ||
1469 | if (lp->promiscuous || lp->mc_count == 0) { | ||
1470 | lp->promiscuous = 0; | ||
1471 | lp->mc_count = 0; | ||
1472 | |||
1473 | wv_82586_reconfig(dev); | ||
1474 | } | ||
1475 | } | ||
1476 | #ifdef DEBUG_IOCTL_TRACE | ||
1477 | printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", | ||
1478 | dev->name); | ||
1479 | #endif | ||
1480 | } | ||
1481 | |||
1482 | /*------------------------------------------------------------------*/ | ||
1483 | /* | ||
1484 | * This function doesn't exist. | ||
1485 | * (Note : it was a nice way to test the reconfigure stuff...) | ||
1486 | */ | ||
1487 | #ifdef SET_MAC_ADDRESS | ||
1488 | static int wavelan_set_mac_address(struct net_device * dev, void *addr) | ||
1489 | { | ||
1490 | struct sockaddr *mac = addr; | ||
1491 | |||
1492 | /* Copy the address. */ | ||
1493 | memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); | ||
1494 | |||
1495 | /* Reconfigure the beast. */ | ||
1496 | wv_82586_reconfig(dev); | ||
1497 | |||
1498 | return 0; | ||
1499 | } | ||
1500 | #endif /* SET_MAC_ADDRESS */ | ||
1501 | |||
1502 | #ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ | ||
1503 | |||
1504 | /*------------------------------------------------------------------*/ | ||
1505 | /* | ||
1506 | * Frequency setting (for hardware capable of it) | ||
1507 | * It's a bit complicated and you don't really want to look into it. | ||
1508 | * (called in wavelan_ioctl) | ||
1509 | */ | ||
1510 | static inline int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ | ||
1511 | iw_freq * frequency) | ||
1512 | { | ||
1513 | const int BAND_NUM = 10; /* Number of bands */ | ||
1514 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ | ||
1515 | #ifdef DEBUG_IOCTL_INFO | ||
1516 | int i; | ||
1517 | #endif | ||
1518 | |||
1519 | /* Setting by frequency */ | ||
1520 | /* Theoretically, you may set any frequency between | ||
1521 | * the two limits with a 0.5 MHz precision. In practice, | ||
1522 | * I don't want you to have trouble with local regulations. | ||
1523 | */ | ||
1524 | if ((frequency->e == 1) && | ||
1525 | (frequency->m >= (int) 2.412e8) | ||
1526 | && (frequency->m <= (int) 2.487e8)) { | ||
1527 | freq = ((frequency->m / 10000) - 24000L) / 5; | ||
1528 | } | ||
1529 | |||
1530 | /* Setting by channel (same as wfreqsel) */ | ||
1531 | /* Warning: each channel is 22 MHz wide, so some of the channels | ||
1532 | * will interfere. */ | ||
1533 | if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { | ||
1534 | /* Get frequency offset. */ | ||
1535 | freq = channel_bands[frequency->m] >> 1; | ||
1536 | } | ||
1537 | |||
1538 | /* Verify that the frequency is allowed. */ | ||
1539 | if (freq != 0L) { | ||
1540 | u16 table[10]; /* Authorized frequency table */ | ||
1541 | |||
1542 | /* Read the frequency table. */ | ||
1543 | fee_read(ioaddr, 0x71, table, 10); | ||
1544 | |||
1545 | #ifdef DEBUG_IOCTL_INFO | ||
1546 | printk(KERN_DEBUG "Frequency table: "); | ||
1547 | for (i = 0; i < 10; i++) { | ||
1548 | printk(" %04X", table[i]); | ||
1549 | } | ||
1550 | printk("\n"); | ||
1551 | #endif | ||
1552 | |||
1553 | /* Look in the table to see whether the frequency is allowed. */ | ||
1554 | if (!(table[9 - ((freq - 24) / 16)] & | ||
1555 | (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ | ||
1556 | } else | ||
1557 | return -EINVAL; | ||
1558 | |||
1559 | /* if we get a usable frequency */ | ||
1560 | if (freq != 0L) { | ||
1561 | unsigned short area[16]; | ||
1562 | unsigned short dac[2]; | ||
1563 | unsigned short area_verify[16]; | ||
1564 | unsigned short dac_verify[2]; | ||
1565 | /* Corresponding gain (in the power adjust value table) | ||
1566 | * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 | ||
1567 | * and WCIN062D.DOC, page 6.2.9. */ | ||
1568 | unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; | ||
1569 | int power_band = 0; /* Selected band */ | ||
1570 | unsigned short power_adjust; /* Correct value */ | ||
1571 | |||
1572 | /* Search for the gain. */ | ||
1573 | power_band = 0; | ||
1574 | while ((freq > power_limit[power_band]) && | ||
1575 | (power_limit[++power_band] != 0)); | ||
1576 | |||
1577 | /* Read the first area. */ | ||
1578 | fee_read(ioaddr, 0x00, area, 16); | ||
1579 | |||
1580 | /* Read the DAC. */ | ||
1581 | fee_read(ioaddr, 0x60, dac, 2); | ||
1582 | |||
1583 | /* Read the new power adjust value. */ | ||
1584 | fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, | ||
1585 | 1); | ||
1586 | if (power_band & 0x1) | ||
1587 | power_adjust >>= 8; | ||
1588 | else | ||
1589 | power_adjust &= 0xFF; | ||
1590 | |||
1591 | #ifdef DEBUG_IOCTL_INFO | ||
1592 | printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); | ||
1593 | for (i = 0; i < 16; i++) { | ||
1594 | printk(" %04X", area[i]); | ||
1595 | } | ||
1596 | printk("\n"); | ||
1597 | |||
1598 | printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", | ||
1599 | dac[0], dac[1]); | ||
1600 | #endif | ||
1601 | |||
1602 | /* Frequency offset (for info only) */ | ||
1603 | area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); | ||
1604 | |||
1605 | /* Receiver Principle main divider coefficient */ | ||
1606 | area[3] = (freq >> 1) + 2400L - 352L; | ||
1607 | area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1608 | |||
1609 | /* Transmitter Main divider coefficient */ | ||
1610 | area[13] = (freq >> 1) + 2400L; | ||
1611 | area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1612 | |||
1613 | /* Other parts of the area are flags, bit streams or unused. */ | ||
1614 | |||
1615 | /* Set the value in the DAC. */ | ||
1616 | dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); | ||
1617 | dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); | ||
1618 | |||
1619 | /* Write the first area. */ | ||
1620 | fee_write(ioaddr, 0x00, area, 16); | ||
1621 | |||
1622 | /* Write the DAC. */ | ||
1623 | fee_write(ioaddr, 0x60, dac, 2); | ||
1624 | |||
1625 | /* We now should verify here that the writing of the EEPROM went OK. */ | ||
1626 | |||
1627 | /* Reread the first area. */ | ||
1628 | fee_read(ioaddr, 0x00, area_verify, 16); | ||
1629 | |||
1630 | /* Reread the DAC. */ | ||
1631 | fee_read(ioaddr, 0x60, dac_verify, 2); | ||
1632 | |||
1633 | /* Compare. */ | ||
1634 | if (memcmp(area, area_verify, 16 * 2) || | ||
1635 | memcmp(dac, dac_verify, 2 * 2)) { | ||
1636 | #ifdef DEBUG_IOCTL_ERROR | ||
1637 | printk(KERN_INFO | ||
1638 | "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); | ||
1639 | #endif | ||
1640 | return -EOPNOTSUPP; | ||
1641 | } | ||
1642 | |||
1643 | /* We must download the frequency parameters to the | ||
1644 | * synthesizers (from the EEPROM - area 1) | ||
1645 | * Note: as the EEPROM is automatically decremented, we set the end | ||
1646 | * if the area... */ | ||
1647 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); | ||
1648 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
1649 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1650 | |||
1651 | /* Wait until the download is finished. */ | ||
1652 | fee_wait(ioaddr, 100, 100); | ||
1653 | |||
1654 | /* We must now download the power adjust value (gain) to | ||
1655 | * the synthesizers (from the EEPROM - area 7 - DAC). */ | ||
1656 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); | ||
1657 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
1658 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1659 | |||
1660 | /* Wait for the download to finish. */ | ||
1661 | fee_wait(ioaddr, 100, 100); | ||
1662 | |||
1663 | #ifdef DEBUG_IOCTL_INFO | ||
1664 | /* Verification of what we have done */ | ||
1665 | |||
1666 | printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); | ||
1667 | for (i = 0; i < 16; i++) { | ||
1668 | printk(" %04X", area_verify[i]); | ||
1669 | } | ||
1670 | printk("\n"); | ||
1671 | |||
1672 | printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", | ||
1673 | dac_verify[0], dac_verify[1]); | ||
1674 | #endif | ||
1675 | |||
1676 | return 0; | ||
1677 | } else | ||
1678 | return -EINVAL; /* Bah, never get there... */ | ||
1679 | } | ||
1680 | |||
1681 | /*------------------------------------------------------------------*/ | ||
1682 | /* | ||
1683 | * Give the list of available frequencies. | ||
1684 | */ | ||
1685 | static inline int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ | ||
1686 | iw_freq * list, /* List of frequencies to fill */ | ||
1687 | int max) | ||
1688 | { /* Maximum number of frequencies */ | ||
1689 | u16 table[10]; /* Authorized frequency table */ | ||
1690 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ | ||
1691 | int i; /* index in the table */ | ||
1692 | int c = 0; /* Channel number */ | ||
1693 | |||
1694 | /* Read the frequency table. */ | ||
1695 | fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); | ||
1696 | |||
1697 | /* Check all frequencies. */ | ||
1698 | i = 0; | ||
1699 | for (freq = 0; freq < 150; freq++) | ||
1700 | /* Look in the table if the frequency is allowed */ | ||
1701 | if (table[9 - (freq / 16)] & (1 << (freq % 16))) { | ||
1702 | /* Compute approximate channel number */ | ||
1703 | while ((((channel_bands[c] >> 1) - 24) < freq) && | ||
1704 | (c < NELS(channel_bands))) | ||
1705 | c++; | ||
1706 | list[i].i = c; /* Set the list index */ | ||
1707 | |||
1708 | /* put in the list */ | ||
1709 | list[i].m = (((freq + 24) * 5) + 24000L) * 10000; | ||
1710 | list[i++].e = 1; | ||
1711 | |||
1712 | /* Check number. */ | ||
1713 | if (i >= max) | ||
1714 | return (i); | ||
1715 | } | ||
1716 | |||
1717 | return (i); | ||
1718 | } | ||
1719 | |||
1720 | #ifdef IW_WIRELESS_SPY | ||
1721 | /*------------------------------------------------------------------*/ | ||
1722 | /* | ||
1723 | * Gather wireless spy statistics: for each packet, compare the source | ||
1724 | * address with our list, and if they match, get the statistics. | ||
1725 | * Sorry, but this function really needs the wireless extensions. | ||
1726 | */ | ||
1727 | static inline void wl_spy_gather(struct net_device * dev, | ||
1728 | u8 * mac, /* MAC address */ | ||
1729 | u8 * stats) /* Statistics to gather */ | ||
1730 | { | ||
1731 | struct iw_quality wstats; | ||
1732 | |||
1733 | wstats.qual = stats[2] & MMR_SGNL_QUAL; | ||
1734 | wstats.level = stats[0] & MMR_SIGNAL_LVL; | ||
1735 | wstats.noise = stats[1] & MMR_SILENCE_LVL; | ||
1736 | wstats.updated = 0x7; | ||
1737 | |||
1738 | /* Update spy records */ | ||
1739 | wireless_spy_update(dev, mac, &wstats); | ||
1740 | } | ||
1741 | #endif /* IW_WIRELESS_SPY */ | ||
1742 | |||
1743 | #ifdef HISTOGRAM | ||
1744 | /*------------------------------------------------------------------*/ | ||
1745 | /* | ||
1746 | * This function calculates a histogram of the signal level. | ||
1747 | * As the noise is quite constant, it's like doing it on the SNR. | ||
1748 | * We have defined a set of interval (lp->his_range), and each time | ||
1749 | * the level goes in that interval, we increment the count (lp->his_sum). | ||
1750 | * With this histogram you may detect if one WaveLAN is really weak, | ||
1751 | * or you may also calculate the mean and standard deviation of the level. | ||
1752 | */ | ||
1753 | static inline void wl_his_gather(struct net_device * dev, u8 * stats) | ||
1754 | { /* Statistics to gather */ | ||
1755 | net_local *lp = (net_local *) dev->priv; | ||
1756 | u8 level = stats[0] & MMR_SIGNAL_LVL; | ||
1757 | int i; | ||
1758 | |||
1759 | /* Find the correct interval. */ | ||
1760 | i = 0; | ||
1761 | while ((i < (lp->his_number - 1)) | ||
1762 | && (level >= lp->his_range[i++])); | ||
1763 | |||
1764 | /* Increment interval counter. */ | ||
1765 | (lp->his_sum[i])++; | ||
1766 | } | ||
1767 | #endif /* HISTOGRAM */ | ||
1768 | |||
1769 | /*------------------------------------------------------------------*/ | ||
1770 | /* | ||
1771 | * Wireless Handler : get protocol name | ||
1772 | */ | ||
1773 | static int wavelan_get_name(struct net_device *dev, | ||
1774 | struct iw_request_info *info, | ||
1775 | union iwreq_data *wrqu, | ||
1776 | char *extra) | ||
1777 | { | ||
1778 | strcpy(wrqu->name, "WaveLAN"); | ||
1779 | return 0; | ||
1780 | } | ||
1781 | |||
1782 | /*------------------------------------------------------------------*/ | ||
1783 | /* | ||
1784 | * Wireless Handler : set NWID | ||
1785 | */ | ||
1786 | static int wavelan_set_nwid(struct net_device *dev, | ||
1787 | struct iw_request_info *info, | ||
1788 | union iwreq_data *wrqu, | ||
1789 | char *extra) | ||
1790 | { | ||
1791 | unsigned long ioaddr = dev->base_addr; | ||
1792 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
1793 | psa_t psa; | ||
1794 | mm_t m; | ||
1795 | unsigned long flags; | ||
1796 | int ret = 0; | ||
1797 | |||
1798 | /* Disable interrupts and save flags. */ | ||
1799 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1800 | |||
1801 | /* Set NWID in WaveLAN. */ | ||
1802 | if (!wrqu->nwid.disabled) { | ||
1803 | /* Set NWID in psa */ | ||
1804 | psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; | ||
1805 | psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; | ||
1806 | psa.psa_nwid_select = 0x01; | ||
1807 | psa_write(ioaddr, lp->hacr, | ||
1808 | (char *) psa.psa_nwid - (char *) &psa, | ||
1809 | (unsigned char *) psa.psa_nwid, 3); | ||
1810 | |||
1811 | /* Set NWID in mmc. */ | ||
1812 | m.w.mmw_netw_id_l = psa.psa_nwid[1]; | ||
1813 | m.w.mmw_netw_id_h = psa.psa_nwid[0]; | ||
1814 | mmc_write(ioaddr, | ||
1815 | (char *) &m.w.mmw_netw_id_l - | ||
1816 | (char *) &m, | ||
1817 | (unsigned char *) &m.w.mmw_netw_id_l, 2); | ||
1818 | mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); | ||
1819 | } else { | ||
1820 | /* Disable NWID in the psa. */ | ||
1821 | psa.psa_nwid_select = 0x00; | ||
1822 | psa_write(ioaddr, lp->hacr, | ||
1823 | (char *) &psa.psa_nwid_select - | ||
1824 | (char *) &psa, | ||
1825 | (unsigned char *) &psa.psa_nwid_select, | ||
1826 | 1); | ||
1827 | |||
1828 | /* Disable NWID in the mmc (no filtering). */ | ||
1829 | mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), | ||
1830 | MMW_LOOPT_SEL_DIS_NWID); | ||
1831 | } | ||
1832 | /* update the Wavelan checksum */ | ||
1833 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
1834 | |||
1835 | /* Enable interrupts and restore flags. */ | ||
1836 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1837 | |||
1838 | return ret; | ||
1839 | } | ||
1840 | |||
1841 | /*------------------------------------------------------------------*/ | ||
1842 | /* | ||
1843 | * Wireless Handler : get NWID | ||
1844 | */ | ||
1845 | static int wavelan_get_nwid(struct net_device *dev, | ||
1846 | struct iw_request_info *info, | ||
1847 | union iwreq_data *wrqu, | ||
1848 | char *extra) | ||
1849 | { | ||
1850 | unsigned long ioaddr = dev->base_addr; | ||
1851 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
1852 | psa_t psa; | ||
1853 | unsigned long flags; | ||
1854 | int ret = 0; | ||
1855 | |||
1856 | /* Disable interrupts and save flags. */ | ||
1857 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1858 | |||
1859 | /* Read the NWID. */ | ||
1860 | psa_read(ioaddr, lp->hacr, | ||
1861 | (char *) psa.psa_nwid - (char *) &psa, | ||
1862 | (unsigned char *) psa.psa_nwid, 3); | ||
1863 | wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; | ||
1864 | wrqu->nwid.disabled = !(psa.psa_nwid_select); | ||
1865 | wrqu->nwid.fixed = 1; /* Superfluous */ | ||
1866 | |||
1867 | /* Enable interrupts and restore flags. */ | ||
1868 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1869 | |||
1870 | return ret; | ||
1871 | } | ||
1872 | |||
1873 | /*------------------------------------------------------------------*/ | ||
1874 | /* | ||
1875 | * Wireless Handler : set frequency | ||
1876 | */ | ||
1877 | static int wavelan_set_freq(struct net_device *dev, | ||
1878 | struct iw_request_info *info, | ||
1879 | union iwreq_data *wrqu, | ||
1880 | char *extra) | ||
1881 | { | ||
1882 | unsigned long ioaddr = dev->base_addr; | ||
1883 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
1884 | unsigned long flags; | ||
1885 | int ret; | ||
1886 | |||
1887 | /* Disable interrupts and save flags. */ | ||
1888 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1889 | |||
1890 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
1891 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
1892 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
1893 | ret = wv_set_frequency(ioaddr, &(wrqu->freq)); | ||
1894 | else | ||
1895 | ret = -EOPNOTSUPP; | ||
1896 | |||
1897 | /* Enable interrupts and restore flags. */ | ||
1898 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1899 | |||
1900 | return ret; | ||
1901 | } | ||
1902 | |||
1903 | /*------------------------------------------------------------------*/ | ||
1904 | /* | ||
1905 | * Wireless Handler : get frequency | ||
1906 | */ | ||
1907 | static int wavelan_get_freq(struct net_device *dev, | ||
1908 | struct iw_request_info *info, | ||
1909 | union iwreq_data *wrqu, | ||
1910 | char *extra) | ||
1911 | { | ||
1912 | unsigned long ioaddr = dev->base_addr; | ||
1913 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
1914 | psa_t psa; | ||
1915 | unsigned long flags; | ||
1916 | int ret = 0; | ||
1917 | |||
1918 | /* Disable interrupts and save flags. */ | ||
1919 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1920 | |||
1921 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). | ||
1922 | * Does it work for everybody, especially old cards? */ | ||
1923 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
1924 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
1925 | unsigned short freq; | ||
1926 | |||
1927 | /* Ask the EEPROM to read the frequency from the first area. */ | ||
1928 | fee_read(ioaddr, 0x00, &freq, 1); | ||
1929 | wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; | ||
1930 | wrqu->freq.e = 1; | ||
1931 | } else { | ||
1932 | psa_read(ioaddr, lp->hacr, | ||
1933 | (char *) &psa.psa_subband - (char *) &psa, | ||
1934 | (unsigned char *) &psa.psa_subband, 1); | ||
1935 | |||
1936 | if (psa.psa_subband <= 4) { | ||
1937 | wrqu->freq.m = fixed_bands[psa.psa_subband]; | ||
1938 | wrqu->freq.e = (psa.psa_subband != 0); | ||
1939 | } else | ||
1940 | ret = -EOPNOTSUPP; | ||
1941 | } | ||
1942 | |||
1943 | /* Enable interrupts and restore flags. */ | ||
1944 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1945 | |||
1946 | return ret; | ||
1947 | } | ||
1948 | |||
1949 | /*------------------------------------------------------------------*/ | ||
1950 | /* | ||
1951 | * Wireless Handler : set level threshold | ||
1952 | */ | ||
1953 | static int wavelan_set_sens(struct net_device *dev, | ||
1954 | struct iw_request_info *info, | ||
1955 | union iwreq_data *wrqu, | ||
1956 | char *extra) | ||
1957 | { | ||
1958 | unsigned long ioaddr = dev->base_addr; | ||
1959 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
1960 | psa_t psa; | ||
1961 | unsigned long flags; | ||
1962 | int ret = 0; | ||
1963 | |||
1964 | /* Disable interrupts and save flags. */ | ||
1965 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1966 | |||
1967 | /* Set the level threshold. */ | ||
1968 | /* We should complain loudly if wrqu->sens.fixed = 0, because we | ||
1969 | * can't set auto mode... */ | ||
1970 | psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; | ||
1971 | psa_write(ioaddr, lp->hacr, | ||
1972 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
1973 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
1974 | /* update the Wavelan checksum */ | ||
1975 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
1976 | mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), | ||
1977 | psa.psa_thr_pre_set); | ||
1978 | |||
1979 | /* Enable interrupts and restore flags. */ | ||
1980 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1981 | |||
1982 | return ret; | ||
1983 | } | ||
1984 | |||
1985 | /*------------------------------------------------------------------*/ | ||
1986 | /* | ||
1987 | * Wireless Handler : get level threshold | ||
1988 | */ | ||
1989 | static int wavelan_get_sens(struct net_device *dev, | ||
1990 | struct iw_request_info *info, | ||
1991 | union iwreq_data *wrqu, | ||
1992 | char *extra) | ||
1993 | { | ||
1994 | unsigned long ioaddr = dev->base_addr; | ||
1995 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
1996 | psa_t psa; | ||
1997 | unsigned long flags; | ||
1998 | int ret = 0; | ||
1999 | |||
2000 | /* Disable interrupts and save flags. */ | ||
2001 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2002 | |||
2003 | /* Read the level threshold. */ | ||
2004 | psa_read(ioaddr, lp->hacr, | ||
2005 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
2006 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
2007 | wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; | ||
2008 | wrqu->sens.fixed = 1; | ||
2009 | |||
2010 | /* Enable interrupts and restore flags. */ | ||
2011 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2012 | |||
2013 | return ret; | ||
2014 | } | ||
2015 | |||
2016 | /*------------------------------------------------------------------*/ | ||
2017 | /* | ||
2018 | * Wireless Handler : set encryption key | ||
2019 | */ | ||
2020 | static int wavelan_set_encode(struct net_device *dev, | ||
2021 | struct iw_request_info *info, | ||
2022 | union iwreq_data *wrqu, | ||
2023 | char *extra) | ||
2024 | { | ||
2025 | unsigned long ioaddr = dev->base_addr; | ||
2026 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2027 | unsigned long flags; | ||
2028 | psa_t psa; | ||
2029 | int ret = 0; | ||
2030 | |||
2031 | /* Disable interrupts and save flags. */ | ||
2032 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2033 | |||
2034 | /* Check if capable of encryption */ | ||
2035 | if (!mmc_encr(ioaddr)) { | ||
2036 | ret = -EOPNOTSUPP; | ||
2037 | } | ||
2038 | |||
2039 | /* Check the size of the key */ | ||
2040 | if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { | ||
2041 | ret = -EINVAL; | ||
2042 | } | ||
2043 | |||
2044 | if(!ret) { | ||
2045 | /* Basic checking... */ | ||
2046 | if (wrqu->encoding.length == 8) { | ||
2047 | /* Copy the key in the driver */ | ||
2048 | memcpy(psa.psa_encryption_key, extra, | ||
2049 | wrqu->encoding.length); | ||
2050 | psa.psa_encryption_select = 1; | ||
2051 | |||
2052 | psa_write(ioaddr, lp->hacr, | ||
2053 | (char *) &psa.psa_encryption_select - | ||
2054 | (char *) &psa, | ||
2055 | (unsigned char *) &psa. | ||
2056 | psa_encryption_select, 8 + 1); | ||
2057 | |||
2058 | mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), | ||
2059 | MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); | ||
2060 | mmc_write(ioaddr, mmwoff(0, mmw_encr_key), | ||
2061 | (unsigned char *) &psa. | ||
2062 | psa_encryption_key, 8); | ||
2063 | } | ||
2064 | |||
2065 | /* disable encryption */ | ||
2066 | if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { | ||
2067 | psa.psa_encryption_select = 0; | ||
2068 | psa_write(ioaddr, lp->hacr, | ||
2069 | (char *) &psa.psa_encryption_select - | ||
2070 | (char *) &psa, | ||
2071 | (unsigned char *) &psa. | ||
2072 | psa_encryption_select, 1); | ||
2073 | |||
2074 | mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); | ||
2075 | } | ||
2076 | /* update the Wavelan checksum */ | ||
2077 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
2078 | } | ||
2079 | |||
2080 | /* Enable interrupts and restore flags. */ | ||
2081 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2082 | |||
2083 | return ret; | ||
2084 | } | ||
2085 | |||
2086 | /*------------------------------------------------------------------*/ | ||
2087 | /* | ||
2088 | * Wireless Handler : get encryption key | ||
2089 | */ | ||
2090 | static int wavelan_get_encode(struct net_device *dev, | ||
2091 | struct iw_request_info *info, | ||
2092 | union iwreq_data *wrqu, | ||
2093 | char *extra) | ||
2094 | { | ||
2095 | unsigned long ioaddr = dev->base_addr; | ||
2096 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2097 | psa_t psa; | ||
2098 | unsigned long flags; | ||
2099 | int ret = 0; | ||
2100 | |||
2101 | /* Disable interrupts and save flags. */ | ||
2102 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2103 | |||
2104 | /* Check if encryption is available */ | ||
2105 | if (!mmc_encr(ioaddr)) { | ||
2106 | ret = -EOPNOTSUPP; | ||
2107 | } else { | ||
2108 | /* Read the encryption key */ | ||
2109 | psa_read(ioaddr, lp->hacr, | ||
2110 | (char *) &psa.psa_encryption_select - | ||
2111 | (char *) &psa, | ||
2112 | (unsigned char *) &psa. | ||
2113 | psa_encryption_select, 1 + 8); | ||
2114 | |||
2115 | /* encryption is enabled ? */ | ||
2116 | if (psa.psa_encryption_select) | ||
2117 | wrqu->encoding.flags = IW_ENCODE_ENABLED; | ||
2118 | else | ||
2119 | wrqu->encoding.flags = IW_ENCODE_DISABLED; | ||
2120 | wrqu->encoding.flags |= mmc_encr(ioaddr); | ||
2121 | |||
2122 | /* Copy the key to the user buffer */ | ||
2123 | wrqu->encoding.length = 8; | ||
2124 | memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); | ||
2125 | } | ||
2126 | |||
2127 | /* Enable interrupts and restore flags. */ | ||
2128 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2129 | |||
2130 | return ret; | ||
2131 | } | ||
2132 | |||
2133 | /*------------------------------------------------------------------*/ | ||
2134 | /* | ||
2135 | * Wireless Handler : get range info | ||
2136 | */ | ||
2137 | static int wavelan_get_range(struct net_device *dev, | ||
2138 | struct iw_request_info *info, | ||
2139 | union iwreq_data *wrqu, | ||
2140 | char *extra) | ||
2141 | { | ||
2142 | unsigned long ioaddr = dev->base_addr; | ||
2143 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2144 | struct iw_range *range = (struct iw_range *) extra; | ||
2145 | unsigned long flags; | ||
2146 | int ret = 0; | ||
2147 | |||
2148 | /* Set the length (very important for backward compatibility) */ | ||
2149 | wrqu->data.length = sizeof(struct iw_range); | ||
2150 | |||
2151 | /* Set all the info we don't care or don't know about to zero */ | ||
2152 | memset(range, 0, sizeof(struct iw_range)); | ||
2153 | |||
2154 | /* Set the Wireless Extension versions */ | ||
2155 | range->we_version_compiled = WIRELESS_EXT; | ||
2156 | range->we_version_source = 9; | ||
2157 | |||
2158 | /* Set information in the range struct. */ | ||
2159 | range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ | ||
2160 | range->min_nwid = 0x0000; | ||
2161 | range->max_nwid = 0xFFFF; | ||
2162 | |||
2163 | range->sensitivity = 0x3F; | ||
2164 | range->max_qual.qual = MMR_SGNL_QUAL; | ||
2165 | range->max_qual.level = MMR_SIGNAL_LVL; | ||
2166 | range->max_qual.noise = MMR_SILENCE_LVL; | ||
2167 | range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ | ||
2168 | /* Need to get better values for those two */ | ||
2169 | range->avg_qual.level = 30; | ||
2170 | range->avg_qual.noise = 8; | ||
2171 | |||
2172 | range->num_bitrates = 1; | ||
2173 | range->bitrate[0] = 2000000; /* 2 Mb/s */ | ||
2174 | |||
2175 | /* Event capability (kernel + driver) */ | ||
2176 | range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | | ||
2177 | IW_EVENT_CAPA_MASK(0x8B04)); | ||
2178 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
2179 | |||
2180 | /* Disable interrupts and save flags. */ | ||
2181 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2182 | |||
2183 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
2184 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
2185 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
2186 | range->num_channels = 10; | ||
2187 | range->num_frequency = wv_frequency_list(ioaddr, range->freq, | ||
2188 | IW_MAX_FREQUENCIES); | ||
2189 | } else | ||
2190 | range->num_channels = range->num_frequency = 0; | ||
2191 | |||
2192 | /* Encryption supported ? */ | ||
2193 | if (mmc_encr(ioaddr)) { | ||
2194 | range->encoding_size[0] = 8; /* DES = 64 bits key */ | ||
2195 | range->num_encoding_sizes = 1; | ||
2196 | range->max_encoding_tokens = 1; /* Only one key possible */ | ||
2197 | } else { | ||
2198 | range->num_encoding_sizes = 0; | ||
2199 | range->max_encoding_tokens = 0; | ||
2200 | } | ||
2201 | |||
2202 | /* Enable interrupts and restore flags. */ | ||
2203 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2204 | |||
2205 | return ret; | ||
2206 | } | ||
2207 | |||
2208 | /*------------------------------------------------------------------*/ | ||
2209 | /* | ||
2210 | * Wireless Private Handler : set quality threshold | ||
2211 | */ | ||
2212 | static int wavelan_set_qthr(struct net_device *dev, | ||
2213 | struct iw_request_info *info, | ||
2214 | union iwreq_data *wrqu, | ||
2215 | char *extra) | ||
2216 | { | ||
2217 | unsigned long ioaddr = dev->base_addr; | ||
2218 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2219 | psa_t psa; | ||
2220 | unsigned long flags; | ||
2221 | |||
2222 | /* Disable interrupts and save flags. */ | ||
2223 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2224 | |||
2225 | psa.psa_quality_thr = *(extra) & 0x0F; | ||
2226 | psa_write(ioaddr, lp->hacr, | ||
2227 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2228 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2229 | /* update the Wavelan checksum */ | ||
2230 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
2231 | mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), | ||
2232 | psa.psa_quality_thr); | ||
2233 | |||
2234 | /* Enable interrupts and restore flags. */ | ||
2235 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2236 | |||
2237 | return 0; | ||
2238 | } | ||
2239 | |||
2240 | /*------------------------------------------------------------------*/ | ||
2241 | /* | ||
2242 | * Wireless Private Handler : get quality threshold | ||
2243 | */ | ||
2244 | static int wavelan_get_qthr(struct net_device *dev, | ||
2245 | struct iw_request_info *info, | ||
2246 | union iwreq_data *wrqu, | ||
2247 | char *extra) | ||
2248 | { | ||
2249 | unsigned long ioaddr = dev->base_addr; | ||
2250 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2251 | psa_t psa; | ||
2252 | unsigned long flags; | ||
2253 | |||
2254 | /* Disable interrupts and save flags. */ | ||
2255 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2256 | |||
2257 | psa_read(ioaddr, lp->hacr, | ||
2258 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2259 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2260 | *(extra) = psa.psa_quality_thr & 0x0F; | ||
2261 | |||
2262 | /* Enable interrupts and restore flags. */ | ||
2263 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2264 | |||
2265 | return 0; | ||
2266 | } | ||
2267 | |||
2268 | #ifdef HISTOGRAM | ||
2269 | /*------------------------------------------------------------------*/ | ||
2270 | /* | ||
2271 | * Wireless Private Handler : set histogram | ||
2272 | */ | ||
2273 | static int wavelan_set_histo(struct net_device *dev, | ||
2274 | struct iw_request_info *info, | ||
2275 | union iwreq_data *wrqu, | ||
2276 | char *extra) | ||
2277 | { | ||
2278 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2279 | |||
2280 | /* Check the number of intervals. */ | ||
2281 | if (wrqu->data.length > 16) { | ||
2282 | return(-E2BIG); | ||
2283 | } | ||
2284 | |||
2285 | /* Disable histo while we copy the addresses. | ||
2286 | * As we don't disable interrupts, we need to do this */ | ||
2287 | lp->his_number = 0; | ||
2288 | |||
2289 | /* Are there ranges to copy? */ | ||
2290 | if (wrqu->data.length > 0) { | ||
2291 | /* Copy interval ranges to the driver */ | ||
2292 | memcpy(lp->his_range, extra, wrqu->data.length); | ||
2293 | |||
2294 | { | ||
2295 | int i; | ||
2296 | printk(KERN_DEBUG "Histo :"); | ||
2297 | for(i = 0; i < wrqu->data.length; i++) | ||
2298 | printk(" %d", lp->his_range[i]); | ||
2299 | printk("\n"); | ||
2300 | } | ||
2301 | |||
2302 | /* Reset result structure. */ | ||
2303 | memset(lp->his_sum, 0x00, sizeof(long) * 16); | ||
2304 | } | ||
2305 | |||
2306 | /* Now we can set the number of ranges */ | ||
2307 | lp->his_number = wrqu->data.length; | ||
2308 | |||
2309 | return(0); | ||
2310 | } | ||
2311 | |||
2312 | /*------------------------------------------------------------------*/ | ||
2313 | /* | ||
2314 | * Wireless Private Handler : get histogram | ||
2315 | */ | ||
2316 | static int wavelan_get_histo(struct net_device *dev, | ||
2317 | struct iw_request_info *info, | ||
2318 | union iwreq_data *wrqu, | ||
2319 | char *extra) | ||
2320 | { | ||
2321 | net_local *lp = (net_local *) dev->priv; /* lp is not unused */ | ||
2322 | |||
2323 | /* Set the number of intervals. */ | ||
2324 | wrqu->data.length = lp->his_number; | ||
2325 | |||
2326 | /* Give back the distribution statistics */ | ||
2327 | if(lp->his_number > 0) | ||
2328 | memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); | ||
2329 | |||
2330 | return(0); | ||
2331 | } | ||
2332 | #endif /* HISTOGRAM */ | ||
2333 | |||
2334 | /*------------------------------------------------------------------*/ | ||
2335 | /* | ||
2336 | * Structures to export the Wireless Handlers | ||
2337 | */ | ||
2338 | |||
2339 | static const iw_handler wavelan_handler[] = | ||
2340 | { | ||
2341 | NULL, /* SIOCSIWNAME */ | ||
2342 | wavelan_get_name, /* SIOCGIWNAME */ | ||
2343 | wavelan_set_nwid, /* SIOCSIWNWID */ | ||
2344 | wavelan_get_nwid, /* SIOCGIWNWID */ | ||
2345 | wavelan_set_freq, /* SIOCSIWFREQ */ | ||
2346 | wavelan_get_freq, /* SIOCGIWFREQ */ | ||
2347 | NULL, /* SIOCSIWMODE */ | ||
2348 | NULL, /* SIOCGIWMODE */ | ||
2349 | wavelan_set_sens, /* SIOCSIWSENS */ | ||
2350 | wavelan_get_sens, /* SIOCGIWSENS */ | ||
2351 | NULL, /* SIOCSIWRANGE */ | ||
2352 | wavelan_get_range, /* SIOCGIWRANGE */ | ||
2353 | NULL, /* SIOCSIWPRIV */ | ||
2354 | NULL, /* SIOCGIWPRIV */ | ||
2355 | NULL, /* SIOCSIWSTATS */ | ||
2356 | NULL, /* SIOCGIWSTATS */ | ||
2357 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2358 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2359 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2360 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2361 | NULL, /* SIOCSIWAP */ | ||
2362 | NULL, /* SIOCGIWAP */ | ||
2363 | NULL, /* -- hole -- */ | ||
2364 | NULL, /* SIOCGIWAPLIST */ | ||
2365 | NULL, /* -- hole -- */ | ||
2366 | NULL, /* -- hole -- */ | ||
2367 | NULL, /* SIOCSIWESSID */ | ||
2368 | NULL, /* SIOCGIWESSID */ | ||
2369 | NULL, /* SIOCSIWNICKN */ | ||
2370 | NULL, /* SIOCGIWNICKN */ | ||
2371 | NULL, /* -- hole -- */ | ||
2372 | NULL, /* -- hole -- */ | ||
2373 | NULL, /* SIOCSIWRATE */ | ||
2374 | NULL, /* SIOCGIWRATE */ | ||
2375 | NULL, /* SIOCSIWRTS */ | ||
2376 | NULL, /* SIOCGIWRTS */ | ||
2377 | NULL, /* SIOCSIWFRAG */ | ||
2378 | NULL, /* SIOCGIWFRAG */ | ||
2379 | NULL, /* SIOCSIWTXPOW */ | ||
2380 | NULL, /* SIOCGIWTXPOW */ | ||
2381 | NULL, /* SIOCSIWRETRY */ | ||
2382 | NULL, /* SIOCGIWRETRY */ | ||
2383 | /* Bummer ! Why those are only at the end ??? */ | ||
2384 | wavelan_set_encode, /* SIOCSIWENCODE */ | ||
2385 | wavelan_get_encode, /* SIOCGIWENCODE */ | ||
2386 | }; | ||
2387 | |||
2388 | static const iw_handler wavelan_private_handler[] = | ||
2389 | { | ||
2390 | wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ | ||
2391 | wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ | ||
2392 | #ifdef HISTOGRAM | ||
2393 | wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ | ||
2394 | wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ | ||
2395 | #endif /* HISTOGRAM */ | ||
2396 | }; | ||
2397 | |||
2398 | static const struct iw_priv_args wavelan_private_args[] = { | ||
2399 | /*{ cmd, set_args, get_args, name } */ | ||
2400 | { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, | ||
2401 | { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, | ||
2402 | { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, | ||
2403 | { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, | ||
2404 | }; | ||
2405 | |||
2406 | static const struct iw_handler_def wavelan_handler_def = | ||
2407 | { | ||
2408 | .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), | ||
2409 | .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), | ||
2410 | .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), | ||
2411 | .standard = wavelan_handler, | ||
2412 | .private = wavelan_private_handler, | ||
2413 | .private_args = wavelan_private_args, | ||
2414 | .get_wireless_stats = wavelan_get_wireless_stats, | ||
2415 | }; | ||
2416 | |||
2417 | /*------------------------------------------------------------------*/ | ||
2418 | /* | ||
2419 | * Get wireless statistics. | ||
2420 | * Called by /proc/net/wireless | ||
2421 | */ | ||
2422 | static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) | ||
2423 | { | ||
2424 | unsigned long ioaddr = dev->base_addr; | ||
2425 | net_local *lp = (net_local *) dev->priv; | ||
2426 | mmr_t m; | ||
2427 | iw_stats *wstats; | ||
2428 | unsigned long flags; | ||
2429 | |||
2430 | #ifdef DEBUG_IOCTL_TRACE | ||
2431 | printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", | ||
2432 | dev->name); | ||
2433 | #endif | ||
2434 | |||
2435 | /* Check */ | ||
2436 | if (lp == (net_local *) NULL) | ||
2437 | return (iw_stats *) NULL; | ||
2438 | |||
2439 | /* Disable interrupts and save flags. */ | ||
2440 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2441 | |||
2442 | wstats = &lp->wstats; | ||
2443 | |||
2444 | /* Get data from the mmc. */ | ||
2445 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); | ||
2446 | |||
2447 | mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); | ||
2448 | mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, | ||
2449 | 2); | ||
2450 | mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, | ||
2451 | 4); | ||
2452 | |||
2453 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); | ||
2454 | |||
2455 | /* Copy data to wireless stuff. */ | ||
2456 | wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; | ||
2457 | wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; | ||
2458 | wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; | ||
2459 | wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; | ||
2460 | wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | ||
2461 | | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | ||
2462 | | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); | ||
2463 | wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
2464 | wstats->discard.code = 0L; | ||
2465 | wstats->discard.misc = 0L; | ||
2466 | |||
2467 | /* Enable interrupts and restore flags. */ | ||
2468 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2469 | |||
2470 | #ifdef DEBUG_IOCTL_TRACE | ||
2471 | printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", | ||
2472 | dev->name); | ||
2473 | #endif | ||
2474 | return &lp->wstats; | ||
2475 | } | ||
2476 | #endif /* WIRELESS_EXT */ | ||
2477 | |||
2478 | /************************* PACKET RECEPTION *************************/ | ||
2479 | /* | ||
2480 | * This part deals with receiving the packets. | ||
2481 | * The interrupt handler gets an interrupt when a packet has been | ||
2482 | * successfully received and calls this part. | ||
2483 | */ | ||
2484 | |||
2485 | /*------------------------------------------------------------------*/ | ||
2486 | /* | ||
2487 | * This routine does the actual copying of data (including the Ethernet | ||
2488 | * header structure) from the WaveLAN card to an sk_buff chain that | ||
2489 | * will be passed up to the network interface layer. NOTE: we | ||
2490 | * currently don't handle trailer protocols (neither does the rest of | ||
2491 | * the network interface), so if that is needed, it will (at least in | ||
2492 | * part) be added here. The contents of the receive ring buffer are | ||
2493 | * copied to a message chain that is then passed to the kernel. | ||
2494 | * | ||
2495 | * Note: if any errors occur, the packet is "dropped on the floor". | ||
2496 | * (called by wv_packet_rcv()) | ||
2497 | */ | ||
2498 | static inline void | ||
2499 | wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) | ||
2500 | { | ||
2501 | net_local *lp = (net_local *) dev->priv; | ||
2502 | unsigned long ioaddr = dev->base_addr; | ||
2503 | struct sk_buff *skb; | ||
2504 | |||
2505 | #ifdef DEBUG_RX_TRACE | ||
2506 | printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", | ||
2507 | dev->name, buf_off, sksize); | ||
2508 | #endif | ||
2509 | |||
2510 | /* Allocate buffer for the data */ | ||
2511 | if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) { | ||
2512 | #ifdef DEBUG_RX_ERROR | ||
2513 | printk(KERN_INFO | ||
2514 | "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", | ||
2515 | dev->name, sksize); | ||
2516 | #endif | ||
2517 | lp->stats.rx_dropped++; | ||
2518 | return; | ||
2519 | } | ||
2520 | |||
2521 | skb->dev = dev; | ||
2522 | |||
2523 | /* Copy the packet to the buffer. */ | ||
2524 | obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); | ||
2525 | skb->protocol = eth_type_trans(skb, dev); | ||
2526 | |||
2527 | #ifdef DEBUG_RX_INFO | ||
2528 | wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); | ||
2529 | #endif /* DEBUG_RX_INFO */ | ||
2530 | |||
2531 | /* Statistics-gathering and associated stuff. | ||
2532 | * It seem a bit messy with all the define, but it's really | ||
2533 | * simple... */ | ||
2534 | if ( | ||
2535 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
2536 | (lp->spy_data.spy_number > 0) || | ||
2537 | #endif /* IW_WIRELESS_SPY */ | ||
2538 | #ifdef HISTOGRAM | ||
2539 | (lp->his_number > 0) || | ||
2540 | #endif /* HISTOGRAM */ | ||
2541 | 0) { | ||
2542 | u8 stats[3]; /* signal level, noise level, signal quality */ | ||
2543 | |||
2544 | /* Read signal level, silence level and signal quality bytes */ | ||
2545 | /* Note: in the PCMCIA hardware, these are part of the frame. | ||
2546 | * It seems that for the ISA hardware, it's nowhere to be | ||
2547 | * found in the frame, so I'm obliged to do this (it has a | ||
2548 | * side effect on /proc/net/wireless). | ||
2549 | * Any ideas? | ||
2550 | */ | ||
2551 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); | ||
2552 | mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); | ||
2553 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); | ||
2554 | |||
2555 | #ifdef DEBUG_RX_INFO | ||
2556 | printk(KERN_DEBUG | ||
2557 | "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", | ||
2558 | dev->name, stats[0] & 0x3F, stats[1] & 0x3F, | ||
2559 | stats[2] & 0x0F); | ||
2560 | #endif | ||
2561 | |||
2562 | /* Spying stuff */ | ||
2563 | #ifdef IW_WIRELESS_SPY | ||
2564 | wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, | ||
2565 | stats); | ||
2566 | #endif /* IW_WIRELESS_SPY */ | ||
2567 | #ifdef HISTOGRAM | ||
2568 | wl_his_gather(dev, stats); | ||
2569 | #endif /* HISTOGRAM */ | ||
2570 | } | ||
2571 | |||
2572 | /* | ||
2573 | * Hand the packet to the network module. | ||
2574 | */ | ||
2575 | netif_rx(skb); | ||
2576 | |||
2577 | /* Keep statistics up to date */ | ||
2578 | dev->last_rx = jiffies; | ||
2579 | lp->stats.rx_packets++; | ||
2580 | lp->stats.rx_bytes += sksize; | ||
2581 | |||
2582 | #ifdef DEBUG_RX_TRACE | ||
2583 | printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); | ||
2584 | #endif | ||
2585 | } | ||
2586 | |||
2587 | /*------------------------------------------------------------------*/ | ||
2588 | /* | ||
2589 | * Transfer as many packets as we can | ||
2590 | * from the device RAM. | ||
2591 | * (called in wavelan_interrupt()). | ||
2592 | * Note : the spinlock is already grabbed for us. | ||
2593 | */ | ||
2594 | static inline void wv_receive(struct net_device * dev) | ||
2595 | { | ||
2596 | unsigned long ioaddr = dev->base_addr; | ||
2597 | net_local *lp = (net_local *) dev->priv; | ||
2598 | fd_t fd; | ||
2599 | rbd_t rbd; | ||
2600 | int nreaped = 0; | ||
2601 | |||
2602 | #ifdef DEBUG_RX_TRACE | ||
2603 | printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); | ||
2604 | #endif | ||
2605 | |||
2606 | /* Loop on each received packet. */ | ||
2607 | for (;;) { | ||
2608 | obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, | ||
2609 | sizeof(fd)); | ||
2610 | |||
2611 | /* Note about the status : | ||
2612 | * It start up to be 0 (the value we set). Then, when the RU | ||
2613 | * grab the buffer to prepare for reception, it sets the | ||
2614 | * FD_STATUS_B flag. When the RU has finished receiving the | ||
2615 | * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate | ||
2616 | * completion and set the other flags to indicate the eventual | ||
2617 | * errors. FD_STATUS_OK indicates that the reception was OK. | ||
2618 | */ | ||
2619 | |||
2620 | /* If the current frame is not complete, we have reached the end. */ | ||
2621 | if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) | ||
2622 | break; /* This is how we exit the loop. */ | ||
2623 | |||
2624 | nreaped++; | ||
2625 | |||
2626 | /* Check whether frame was correctly received. */ | ||
2627 | if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { | ||
2628 | /* Does the frame contain a pointer to the data? Let's check. */ | ||
2629 | if (fd.fd_rbd_offset != I82586NULL) { | ||
2630 | /* Read the receive buffer descriptor */ | ||
2631 | obram_read(ioaddr, fd.fd_rbd_offset, | ||
2632 | (unsigned char *) &rbd, | ||
2633 | sizeof(rbd)); | ||
2634 | |||
2635 | #ifdef DEBUG_RX_ERROR | ||
2636 | if ((rbd.rbd_status & RBD_STATUS_EOF) != | ||
2637 | RBD_STATUS_EOF) printk(KERN_INFO | ||
2638 | "%s: wv_receive(): missing EOF flag.\n", | ||
2639 | dev->name); | ||
2640 | |||
2641 | if ((rbd.rbd_status & RBD_STATUS_F) != | ||
2642 | RBD_STATUS_F) printk(KERN_INFO | ||
2643 | "%s: wv_receive(): missing F flag.\n", | ||
2644 | dev->name); | ||
2645 | #endif /* DEBUG_RX_ERROR */ | ||
2646 | |||
2647 | /* Read the packet and transmit to Linux */ | ||
2648 | wv_packet_read(dev, rbd.rbd_bufl, | ||
2649 | rbd. | ||
2650 | rbd_status & | ||
2651 | RBD_STATUS_ACNT); | ||
2652 | } | ||
2653 | #ifdef DEBUG_RX_ERROR | ||
2654 | else /* if frame has no data */ | ||
2655 | printk(KERN_INFO | ||
2656 | "%s: wv_receive(): frame has no data.\n", | ||
2657 | dev->name); | ||
2658 | #endif | ||
2659 | } else { /* If reception was no successful */ | ||
2660 | |||
2661 | lp->stats.rx_errors++; | ||
2662 | |||
2663 | #ifdef DEBUG_RX_INFO | ||
2664 | printk(KERN_DEBUG | ||
2665 | "%s: wv_receive(): frame not received successfully (%X).\n", | ||
2666 | dev->name, fd.fd_status); | ||
2667 | #endif | ||
2668 | |||
2669 | #ifdef DEBUG_RX_ERROR | ||
2670 | if ((fd.fd_status & FD_STATUS_S6) != 0) | ||
2671 | printk(KERN_INFO | ||
2672 | "%s: wv_receive(): no EOF flag.\n", | ||
2673 | dev->name); | ||
2674 | #endif | ||
2675 | |||
2676 | if ((fd.fd_status & FD_STATUS_S7) != 0) { | ||
2677 | lp->stats.rx_length_errors++; | ||
2678 | #ifdef DEBUG_RX_FAIL | ||
2679 | printk(KERN_DEBUG | ||
2680 | "%s: wv_receive(): frame too short.\n", | ||
2681 | dev->name); | ||
2682 | #endif | ||
2683 | } | ||
2684 | |||
2685 | if ((fd.fd_status & FD_STATUS_S8) != 0) { | ||
2686 | lp->stats.rx_over_errors++; | ||
2687 | #ifdef DEBUG_RX_FAIL | ||
2688 | printk(KERN_DEBUG | ||
2689 | "%s: wv_receive(): rx DMA overrun.\n", | ||
2690 | dev->name); | ||
2691 | #endif | ||
2692 | } | ||
2693 | |||
2694 | if ((fd.fd_status & FD_STATUS_S9) != 0) { | ||
2695 | lp->stats.rx_fifo_errors++; | ||
2696 | #ifdef DEBUG_RX_FAIL | ||
2697 | printk(KERN_DEBUG | ||
2698 | "%s: wv_receive(): ran out of resources.\n", | ||
2699 | dev->name); | ||
2700 | #endif | ||
2701 | } | ||
2702 | |||
2703 | if ((fd.fd_status & FD_STATUS_S10) != 0) { | ||
2704 | lp->stats.rx_frame_errors++; | ||
2705 | #ifdef DEBUG_RX_FAIL | ||
2706 | printk(KERN_DEBUG | ||
2707 | "%s: wv_receive(): alignment error.\n", | ||
2708 | dev->name); | ||
2709 | #endif | ||
2710 | } | ||
2711 | |||
2712 | if ((fd.fd_status & FD_STATUS_S11) != 0) { | ||
2713 | lp->stats.rx_crc_errors++; | ||
2714 | #ifdef DEBUG_RX_FAIL | ||
2715 | printk(KERN_DEBUG | ||
2716 | "%s: wv_receive(): CRC error.\n", | ||
2717 | dev->name); | ||
2718 | #endif | ||
2719 | } | ||
2720 | } | ||
2721 | |||
2722 | fd.fd_status = 0; | ||
2723 | obram_write(ioaddr, fdoff(lp->rx_head, fd_status), | ||
2724 | (unsigned char *) &fd.fd_status, | ||
2725 | sizeof(fd.fd_status)); | ||
2726 | |||
2727 | fd.fd_command = FD_COMMAND_EL; | ||
2728 | obram_write(ioaddr, fdoff(lp->rx_head, fd_command), | ||
2729 | (unsigned char *) &fd.fd_command, | ||
2730 | sizeof(fd.fd_command)); | ||
2731 | |||
2732 | fd.fd_command = 0; | ||
2733 | obram_write(ioaddr, fdoff(lp->rx_last, fd_command), | ||
2734 | (unsigned char *) &fd.fd_command, | ||
2735 | sizeof(fd.fd_command)); | ||
2736 | |||
2737 | lp->rx_last = lp->rx_head; | ||
2738 | lp->rx_head = fd.fd_link_offset; | ||
2739 | } /* for(;;) -> loop on all frames */ | ||
2740 | |||
2741 | #ifdef DEBUG_RX_INFO | ||
2742 | if (nreaped > 1) | ||
2743 | printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", | ||
2744 | dev->name, nreaped); | ||
2745 | #endif | ||
2746 | #ifdef DEBUG_RX_TRACE | ||
2747 | printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); | ||
2748 | #endif | ||
2749 | } | ||
2750 | |||
2751 | /*********************** PACKET TRANSMISSION ***********************/ | ||
2752 | /* | ||
2753 | * This part deals with sending packets through the WaveLAN. | ||
2754 | * | ||
2755 | */ | ||
2756 | |||
2757 | /*------------------------------------------------------------------*/ | ||
2758 | /* | ||
2759 | * This routine fills in the appropriate registers and memory | ||
2760 | * locations on the WaveLAN card and starts the card off on | ||
2761 | * the transmit. | ||
2762 | * | ||
2763 | * The principle: | ||
2764 | * Each block contains a transmit command, a NOP command, | ||
2765 | * a transmit block descriptor and a buffer. | ||
2766 | * The CU read the transmit block which point to the tbd, | ||
2767 | * read the tbd and the content of the buffer. | ||
2768 | * When it has finish with it, it goes to the next command | ||
2769 | * which in our case is the NOP. The NOP points on itself, | ||
2770 | * so the CU stop here. | ||
2771 | * When we add the next block, we modify the previous nop | ||
2772 | * to make it point on the new tx command. | ||
2773 | * Simple, isn't it ? | ||
2774 | * | ||
2775 | * (called in wavelan_packet_xmit()) | ||
2776 | */ | ||
2777 | static inline int wv_packet_write(struct net_device * dev, void *buf, short length) | ||
2778 | { | ||
2779 | net_local *lp = (net_local *) dev->priv; | ||
2780 | unsigned long ioaddr = dev->base_addr; | ||
2781 | unsigned short txblock; | ||
2782 | unsigned short txpred; | ||
2783 | unsigned short tx_addr; | ||
2784 | unsigned short nop_addr; | ||
2785 | unsigned short tbd_addr; | ||
2786 | unsigned short buf_addr; | ||
2787 | ac_tx_t tx; | ||
2788 | ac_nop_t nop; | ||
2789 | tbd_t tbd; | ||
2790 | int clen = length; | ||
2791 | unsigned long flags; | ||
2792 | |||
2793 | #ifdef DEBUG_TX_TRACE | ||
2794 | printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, | ||
2795 | length); | ||
2796 | #endif | ||
2797 | |||
2798 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2799 | |||
2800 | /* Check nothing bad has happened */ | ||
2801 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { | ||
2802 | #ifdef DEBUG_TX_ERROR | ||
2803 | printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", | ||
2804 | dev->name); | ||
2805 | #endif | ||
2806 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2807 | return 1; | ||
2808 | } | ||
2809 | |||
2810 | /* Calculate addresses of next block and previous block. */ | ||
2811 | txblock = lp->tx_first_free; | ||
2812 | txpred = txblock - TXBLOCKZ; | ||
2813 | if (txpred < OFFSET_CU) | ||
2814 | txpred += NTXBLOCKS * TXBLOCKZ; | ||
2815 | lp->tx_first_free += TXBLOCKZ; | ||
2816 | if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) | ||
2817 | lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; | ||
2818 | |||
2819 | lp->tx_n_in_use++; | ||
2820 | |||
2821 | /* Calculate addresses of the different parts of the block. */ | ||
2822 | tx_addr = txblock; | ||
2823 | nop_addr = tx_addr + sizeof(tx); | ||
2824 | tbd_addr = nop_addr + sizeof(nop); | ||
2825 | buf_addr = tbd_addr + sizeof(tbd); | ||
2826 | |||
2827 | /* | ||
2828 | * Transmit command | ||
2829 | */ | ||
2830 | tx.tx_h.ac_status = 0; | ||
2831 | obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), | ||
2832 | (unsigned char *) &tx.tx_h.ac_status, | ||
2833 | sizeof(tx.tx_h.ac_status)); | ||
2834 | |||
2835 | /* | ||
2836 | * NOP command | ||
2837 | */ | ||
2838 | nop.nop_h.ac_status = 0; | ||
2839 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
2840 | (unsigned char *) &nop.nop_h.ac_status, | ||
2841 | sizeof(nop.nop_h.ac_status)); | ||
2842 | nop.nop_h.ac_link = nop_addr; | ||
2843 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
2844 | (unsigned char *) &nop.nop_h.ac_link, | ||
2845 | sizeof(nop.nop_h.ac_link)); | ||
2846 | |||
2847 | /* | ||
2848 | * Transmit buffer descriptor | ||
2849 | */ | ||
2850 | tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); | ||
2851 | tbd.tbd_next_bd_offset = I82586NULL; | ||
2852 | tbd.tbd_bufl = buf_addr; | ||
2853 | tbd.tbd_bufh = 0; | ||
2854 | obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); | ||
2855 | |||
2856 | /* | ||
2857 | * Data | ||
2858 | */ | ||
2859 | obram_write(ioaddr, buf_addr, buf, length); | ||
2860 | |||
2861 | /* | ||
2862 | * Overwrite the predecessor NOP link | ||
2863 | * so that it points to this txblock. | ||
2864 | */ | ||
2865 | nop_addr = txpred + sizeof(tx); | ||
2866 | nop.nop_h.ac_status = 0; | ||
2867 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
2868 | (unsigned char *) &nop.nop_h.ac_status, | ||
2869 | sizeof(nop.nop_h.ac_status)); | ||
2870 | nop.nop_h.ac_link = txblock; | ||
2871 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
2872 | (unsigned char *) &nop.nop_h.ac_link, | ||
2873 | sizeof(nop.nop_h.ac_link)); | ||
2874 | |||
2875 | /* Make sure the watchdog will keep quiet for a while */ | ||
2876 | dev->trans_start = jiffies; | ||
2877 | |||
2878 | /* Keep stats up to date. */ | ||
2879 | lp->stats.tx_bytes += length; | ||
2880 | |||
2881 | if (lp->tx_first_in_use == I82586NULL) | ||
2882 | lp->tx_first_in_use = txblock; | ||
2883 | |||
2884 | if (lp->tx_n_in_use < NTXBLOCKS - 1) | ||
2885 | netif_wake_queue(dev); | ||
2886 | |||
2887 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2888 | |||
2889 | #ifdef DEBUG_TX_INFO | ||
2890 | wv_packet_info((u8 *) buf, length, dev->name, | ||
2891 | "wv_packet_write"); | ||
2892 | #endif /* DEBUG_TX_INFO */ | ||
2893 | |||
2894 | #ifdef DEBUG_TX_TRACE | ||
2895 | printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); | ||
2896 | #endif | ||
2897 | |||
2898 | return 0; | ||
2899 | } | ||
2900 | |||
2901 | /*------------------------------------------------------------------*/ | ||
2902 | /* | ||
2903 | * This routine is called when we want to send a packet (NET3 callback) | ||
2904 | * In this routine, we check if the harware is ready to accept | ||
2905 | * the packet. We also prevent reentrance. Then we call the function | ||
2906 | * to send the packet. | ||
2907 | */ | ||
2908 | static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) | ||
2909 | { | ||
2910 | net_local *lp = (net_local *) dev->priv; | ||
2911 | unsigned long flags; | ||
2912 | |||
2913 | #ifdef DEBUG_TX_TRACE | ||
2914 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, | ||
2915 | (unsigned) skb); | ||
2916 | #endif | ||
2917 | |||
2918 | /* | ||
2919 | * Block a timer-based transmit from overlapping. | ||
2920 | * In other words, prevent reentering this routine. | ||
2921 | */ | ||
2922 | netif_stop_queue(dev); | ||
2923 | |||
2924 | /* If somebody has asked to reconfigure the controller, | ||
2925 | * we can do it now. | ||
2926 | */ | ||
2927 | if (lp->reconfig_82586) { | ||
2928 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2929 | wv_82586_config(dev); | ||
2930 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2931 | /* Check that we can continue */ | ||
2932 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) | ||
2933 | return 1; | ||
2934 | } | ||
2935 | #ifdef DEBUG_TX_ERROR | ||
2936 | if (skb->next) | ||
2937 | printk(KERN_INFO "skb has next\n"); | ||
2938 | #endif | ||
2939 | |||
2940 | /* Do we need some padding? */ | ||
2941 | /* Note : on wireless the propagation time is in the order of 1us, | ||
2942 | * and we don't have the Ethernet specific requirement of beeing | ||
2943 | * able to detect collisions, therefore in theory we don't really | ||
2944 | * need to pad. Jean II */ | ||
2945 | if (skb->len < ETH_ZLEN) { | ||
2946 | skb = skb_padto(skb, ETH_ZLEN); | ||
2947 | if (skb == NULL) | ||
2948 | return 0; | ||
2949 | } | ||
2950 | |||
2951 | /* Write packet on the card */ | ||
2952 | if(wv_packet_write(dev, skb->data, skb->len)) | ||
2953 | return 1; /* We failed */ | ||
2954 | |||
2955 | dev_kfree_skb(skb); | ||
2956 | |||
2957 | #ifdef DEBUG_TX_TRACE | ||
2958 | printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); | ||
2959 | #endif | ||
2960 | return 0; | ||
2961 | } | ||
2962 | |||
2963 | /*********************** HARDWARE CONFIGURATION ***********************/ | ||
2964 | /* | ||
2965 | * This part does the real job of starting and configuring the hardware. | ||
2966 | */ | ||
2967 | |||
2968 | /*--------------------------------------------------------------------*/ | ||
2969 | /* | ||
2970 | * Routine to initialize the Modem Management Controller. | ||
2971 | * (called by wv_hw_reset()) | ||
2972 | */ | ||
2973 | static inline int wv_mmc_init(struct net_device * dev) | ||
2974 | { | ||
2975 | unsigned long ioaddr = dev->base_addr; | ||
2976 | net_local *lp = (net_local *) dev->priv; | ||
2977 | psa_t psa; | ||
2978 | mmw_t m; | ||
2979 | int configured; | ||
2980 | |||
2981 | #ifdef DEBUG_CONFIG_TRACE | ||
2982 | printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); | ||
2983 | #endif | ||
2984 | |||
2985 | /* Read the parameter storage area. */ | ||
2986 | psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); | ||
2987 | |||
2988 | #ifdef USE_PSA_CONFIG | ||
2989 | configured = psa.psa_conf_status & 1; | ||
2990 | #else | ||
2991 | configured = 0; | ||
2992 | #endif | ||
2993 | |||
2994 | /* Is the PSA is not configured */ | ||
2995 | if (!configured) { | ||
2996 | /* User will be able to configure NWID later (with iwconfig). */ | ||
2997 | psa.psa_nwid[0] = 0; | ||
2998 | psa.psa_nwid[1] = 0; | ||
2999 | |||
3000 | /* no NWID checking since NWID is not set */ | ||
3001 | psa.psa_nwid_select = 0; | ||
3002 | |||
3003 | /* Disable encryption */ | ||
3004 | psa.psa_encryption_select = 0; | ||
3005 | |||
3006 | /* Set to standard values: | ||
3007 | * 0x04 for AT, | ||
3008 | * 0x01 for MCA, | ||
3009 | * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) | ||
3010 | */ | ||
3011 | if (psa.psa_comp_number & 1) | ||
3012 | psa.psa_thr_pre_set = 0x01; | ||
3013 | else | ||
3014 | psa.psa_thr_pre_set = 0x04; | ||
3015 | psa.psa_quality_thr = 0x03; | ||
3016 | |||
3017 | /* It is configured */ | ||
3018 | psa.psa_conf_status |= 1; | ||
3019 | |||
3020 | #ifdef USE_PSA_CONFIG | ||
3021 | /* Write the psa. */ | ||
3022 | psa_write(ioaddr, lp->hacr, | ||
3023 | (char *) psa.psa_nwid - (char *) &psa, | ||
3024 | (unsigned char *) psa.psa_nwid, 4); | ||
3025 | psa_write(ioaddr, lp->hacr, | ||
3026 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
3027 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
3028 | psa_write(ioaddr, lp->hacr, | ||
3029 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
3030 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
3031 | psa_write(ioaddr, lp->hacr, | ||
3032 | (char *) &psa.psa_conf_status - (char *) &psa, | ||
3033 | (unsigned char *) &psa.psa_conf_status, 1); | ||
3034 | /* update the Wavelan checksum */ | ||
3035 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
3036 | #endif | ||
3037 | } | ||
3038 | |||
3039 | /* Zero the mmc structure. */ | ||
3040 | memset(&m, 0x00, sizeof(m)); | ||
3041 | |||
3042 | /* Copy PSA info to the mmc. */ | ||
3043 | m.mmw_netw_id_l = psa.psa_nwid[1]; | ||
3044 | m.mmw_netw_id_h = psa.psa_nwid[0]; | ||
3045 | |||
3046 | if (psa.psa_nwid_select & 1) | ||
3047 | m.mmw_loopt_sel = 0x00; | ||
3048 | else | ||
3049 | m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; | ||
3050 | |||
3051 | memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, | ||
3052 | sizeof(m.mmw_encr_key)); | ||
3053 | |||
3054 | if (psa.psa_encryption_select) | ||
3055 | m.mmw_encr_enable = | ||
3056 | MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; | ||
3057 | else | ||
3058 | m.mmw_encr_enable = 0; | ||
3059 | |||
3060 | m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; | ||
3061 | m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; | ||
3062 | |||
3063 | /* | ||
3064 | * Set default modem control parameters. | ||
3065 | * See NCR document 407-0024326 Rev. A. | ||
3066 | */ | ||
3067 | m.mmw_jabber_enable = 0x01; | ||
3068 | m.mmw_freeze = 0; | ||
3069 | m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; | ||
3070 | m.mmw_ifs = 0x20; | ||
3071 | m.mmw_mod_delay = 0x04; | ||
3072 | m.mmw_jam_time = 0x38; | ||
3073 | |||
3074 | m.mmw_des_io_invert = 0; | ||
3075 | m.mmw_decay_prm = 0; | ||
3076 | m.mmw_decay_updat_prm = 0; | ||
3077 | |||
3078 | /* Write all info to MMC. */ | ||
3079 | mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m)); | ||
3080 | |||
3081 | /* The following code starts the modem of the 2.00 frequency | ||
3082 | * selectable cards at power on. It's not strictly needed for the | ||
3083 | * following boots. | ||
3084 | * The original patch was by Joe Finney for the PCMCIA driver, but | ||
3085 | * I've cleaned it up a bit and added documentation. | ||
3086 | * Thanks to Loeke Brederveld from Lucent for the info. | ||
3087 | */ | ||
3088 | |||
3089 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) | ||
3090 | * Does it work for everybody, especially old cards? */ | ||
3091 | /* Note: WFREQSEL verifies that it is able to read a sensible | ||
3092 | * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID | ||
3093 | * is 0xA (Xilinx version) or 0xB (Ariadne version). | ||
3094 | * My test is more crude but does work. */ | ||
3095 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
3096 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
3097 | /* We must download the frequency parameters to the | ||
3098 | * synthesizers (from the EEPROM - area 1) | ||
3099 | * Note: as the EEPROM is automatically decremented, we set the end | ||
3100 | * if the area... */ | ||
3101 | m.mmw_fee_addr = 0x0F; | ||
3102 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3103 | mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, | ||
3104 | (unsigned char *) &m.mmw_fee_ctrl, 2); | ||
3105 | |||
3106 | /* Wait until the download is finished. */ | ||
3107 | fee_wait(ioaddr, 100, 100); | ||
3108 | |||
3109 | #ifdef DEBUG_CONFIG_INFO | ||
3110 | /* The frequency was in the last word downloaded. */ | ||
3111 | mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m, | ||
3112 | (unsigned char *) &m.mmw_fee_data_l, 2); | ||
3113 | |||
3114 | /* Print some info for the user. */ | ||
3115 | printk(KERN_DEBUG | ||
3116 | "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", | ||
3117 | dev->name, | ||
3118 | ((m. | ||
3119 | mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) * | ||
3120 | 5 / 2 + 24000L); | ||
3121 | #endif | ||
3122 | |||
3123 | /* We must now download the power adjust value (gain) to | ||
3124 | * the synthesizers (from the EEPROM - area 7 - DAC). */ | ||
3125 | m.mmw_fee_addr = 0x61; | ||
3126 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3127 | mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, | ||
3128 | (unsigned char *) &m.mmw_fee_ctrl, 2); | ||
3129 | |||
3130 | /* Wait until the download is finished. */ | ||
3131 | } | ||
3132 | /* if 2.00 card */ | ||
3133 | #ifdef DEBUG_CONFIG_TRACE | ||
3134 | printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); | ||
3135 | #endif | ||
3136 | return 0; | ||
3137 | } | ||
3138 | |||
3139 | /*------------------------------------------------------------------*/ | ||
3140 | /* | ||
3141 | * Construct the fd and rbd structures. | ||
3142 | * Start the receive unit. | ||
3143 | * (called by wv_hw_reset()) | ||
3144 | */ | ||
3145 | static inline int wv_ru_start(struct net_device * dev) | ||
3146 | { | ||
3147 | net_local *lp = (net_local *) dev->priv; | ||
3148 | unsigned long ioaddr = dev->base_addr; | ||
3149 | u16 scb_cs; | ||
3150 | fd_t fd; | ||
3151 | rbd_t rbd; | ||
3152 | u16 rx; | ||
3153 | u16 rx_next; | ||
3154 | int i; | ||
3155 | |||
3156 | #ifdef DEBUG_CONFIG_TRACE | ||
3157 | printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); | ||
3158 | #endif | ||
3159 | |||
3160 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), | ||
3161 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3162 | if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) | ||
3163 | return 0; | ||
3164 | |||
3165 | lp->rx_head = OFFSET_RU; | ||
3166 | |||
3167 | for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) { | ||
3168 | rx_next = | ||
3169 | (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; | ||
3170 | |||
3171 | fd.fd_status = 0; | ||
3172 | fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; | ||
3173 | fd.fd_link_offset = rx_next; | ||
3174 | fd.fd_rbd_offset = rx + sizeof(fd); | ||
3175 | obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd)); | ||
3176 | |||
3177 | rbd.rbd_status = 0; | ||
3178 | rbd.rbd_next_rbd_offset = I82586NULL; | ||
3179 | rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); | ||
3180 | rbd.rbd_bufh = 0; | ||
3181 | rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); | ||
3182 | obram_write(ioaddr, rx + sizeof(fd), | ||
3183 | (unsigned char *) &rbd, sizeof(rbd)); | ||
3184 | |||
3185 | lp->rx_last = rx; | ||
3186 | } | ||
3187 | |||
3188 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), | ||
3189 | (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); | ||
3190 | |||
3191 | scb_cs = SCB_CMD_RUC_GO; | ||
3192 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3193 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3194 | |||
3195 | set_chan_attn(ioaddr, lp->hacr); | ||
3196 | |||
3197 | for (i = 1000; i > 0; i--) { | ||
3198 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3199 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3200 | if (scb_cs == 0) | ||
3201 | break; | ||
3202 | |||
3203 | udelay(10); | ||
3204 | } | ||
3205 | |||
3206 | if (i <= 0) { | ||
3207 | #ifdef DEBUG_CONFIG_ERROR | ||
3208 | printk(KERN_INFO | ||
3209 | "%s: wavelan_ru_start(): board not accepting command.\n", | ||
3210 | dev->name); | ||
3211 | #endif | ||
3212 | return -1; | ||
3213 | } | ||
3214 | #ifdef DEBUG_CONFIG_TRACE | ||
3215 | printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); | ||
3216 | #endif | ||
3217 | return 0; | ||
3218 | } | ||
3219 | |||
3220 | /*------------------------------------------------------------------*/ | ||
3221 | /* | ||
3222 | * Initialise the transmit blocks. | ||
3223 | * Start the command unit executing the NOP | ||
3224 | * self-loop of the first transmit block. | ||
3225 | * | ||
3226 | * Here we create the list of send buffers used to transmit packets | ||
3227 | * between the PC and the command unit. For each buffer, we create a | ||
3228 | * buffer descriptor (pointing on the buffer), a transmit command | ||
3229 | * (pointing to the buffer descriptor) and a NOP command. | ||
3230 | * The transmit command is linked to the NOP, and the NOP to itself. | ||
3231 | * When we will have finished executing the transmit command, we will | ||
3232 | * then loop on the NOP. By releasing the NOP link to a new command, | ||
3233 | * we may send another buffer. | ||
3234 | * | ||
3235 | * (called by wv_hw_reset()) | ||
3236 | */ | ||
3237 | static inline int wv_cu_start(struct net_device * dev) | ||
3238 | { | ||
3239 | net_local *lp = (net_local *) dev->priv; | ||
3240 | unsigned long ioaddr = dev->base_addr; | ||
3241 | int i; | ||
3242 | u16 txblock; | ||
3243 | u16 first_nop; | ||
3244 | u16 scb_cs; | ||
3245 | |||
3246 | #ifdef DEBUG_CONFIG_TRACE | ||
3247 | printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); | ||
3248 | #endif | ||
3249 | |||
3250 | lp->tx_first_free = OFFSET_CU; | ||
3251 | lp->tx_first_in_use = I82586NULL; | ||
3252 | |||
3253 | for (i = 0, txblock = OFFSET_CU; | ||
3254 | i < NTXBLOCKS; i++, txblock += TXBLOCKZ) { | ||
3255 | ac_tx_t tx; | ||
3256 | ac_nop_t nop; | ||
3257 | tbd_t tbd; | ||
3258 | unsigned short tx_addr; | ||
3259 | unsigned short nop_addr; | ||
3260 | unsigned short tbd_addr; | ||
3261 | unsigned short buf_addr; | ||
3262 | |||
3263 | tx_addr = txblock; | ||
3264 | nop_addr = tx_addr + sizeof(tx); | ||
3265 | tbd_addr = nop_addr + sizeof(nop); | ||
3266 | buf_addr = tbd_addr + sizeof(tbd); | ||
3267 | |||
3268 | tx.tx_h.ac_status = 0; | ||
3269 | tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; | ||
3270 | tx.tx_h.ac_link = nop_addr; | ||
3271 | tx.tx_tbd_offset = tbd_addr; | ||
3272 | obram_write(ioaddr, tx_addr, (unsigned char *) &tx, | ||
3273 | sizeof(tx)); | ||
3274 | |||
3275 | nop.nop_h.ac_status = 0; | ||
3276 | nop.nop_h.ac_command = acmd_nop; | ||
3277 | nop.nop_h.ac_link = nop_addr; | ||
3278 | obram_write(ioaddr, nop_addr, (unsigned char *) &nop, | ||
3279 | sizeof(nop)); | ||
3280 | |||
3281 | tbd.tbd_status = TBD_STATUS_EOF; | ||
3282 | tbd.tbd_next_bd_offset = I82586NULL; | ||
3283 | tbd.tbd_bufl = buf_addr; | ||
3284 | tbd.tbd_bufh = 0; | ||
3285 | obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, | ||
3286 | sizeof(tbd)); | ||
3287 | } | ||
3288 | |||
3289 | first_nop = | ||
3290 | OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); | ||
3291 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), | ||
3292 | (unsigned char *) &first_nop, sizeof(first_nop)); | ||
3293 | |||
3294 | scb_cs = SCB_CMD_CUC_GO; | ||
3295 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3296 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3297 | |||
3298 | set_chan_attn(ioaddr, lp->hacr); | ||
3299 | |||
3300 | for (i = 1000; i > 0; i--) { | ||
3301 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3302 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3303 | if (scb_cs == 0) | ||
3304 | break; | ||
3305 | |||
3306 | udelay(10); | ||
3307 | } | ||
3308 | |||
3309 | if (i <= 0) { | ||
3310 | #ifdef DEBUG_CONFIG_ERROR | ||
3311 | printk(KERN_INFO | ||
3312 | "%s: wavelan_cu_start(): board not accepting command.\n", | ||
3313 | dev->name); | ||
3314 | #endif | ||
3315 | return -1; | ||
3316 | } | ||
3317 | |||
3318 | lp->tx_n_in_use = 0; | ||
3319 | netif_start_queue(dev); | ||
3320 | #ifdef DEBUG_CONFIG_TRACE | ||
3321 | printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); | ||
3322 | #endif | ||
3323 | return 0; | ||
3324 | } | ||
3325 | |||
3326 | /*------------------------------------------------------------------*/ | ||
3327 | /* | ||
3328 | * This routine does a standard configuration of the WaveLAN | ||
3329 | * controller (i82586). | ||
3330 | * | ||
3331 | * It initialises the scp, iscp and scb structure | ||
3332 | * The first two are just pointers to the next. | ||
3333 | * The last one is used for basic configuration and for basic | ||
3334 | * communication (interrupt status). | ||
3335 | * | ||
3336 | * (called by wv_hw_reset()) | ||
3337 | */ | ||
3338 | static inline int wv_82586_start(struct net_device * dev) | ||
3339 | { | ||
3340 | net_local *lp = (net_local *) dev->priv; | ||
3341 | unsigned long ioaddr = dev->base_addr; | ||
3342 | scp_t scp; /* system configuration pointer */ | ||
3343 | iscp_t iscp; /* intermediate scp */ | ||
3344 | scb_t scb; /* system control block */ | ||
3345 | ach_t cb; /* Action command header */ | ||
3346 | u8 zeroes[512]; | ||
3347 | int i; | ||
3348 | |||
3349 | #ifdef DEBUG_CONFIG_TRACE | ||
3350 | printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); | ||
3351 | #endif | ||
3352 | |||
3353 | /* | ||
3354 | * Clear the onboard RAM. | ||
3355 | */ | ||
3356 | memset(&zeroes[0], 0x00, sizeof(zeroes)); | ||
3357 | for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) | ||
3358 | obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); | ||
3359 | |||
3360 | /* | ||
3361 | * Construct the command unit structures: | ||
3362 | * scp, iscp, scb, cb. | ||
3363 | */ | ||
3364 | memset(&scp, 0x00, sizeof(scp)); | ||
3365 | scp.scp_sysbus = SCP_SY_16BBUS; | ||
3366 | scp.scp_iscpl = OFFSET_ISCP; | ||
3367 | obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp, | ||
3368 | sizeof(scp)); | ||
3369 | |||
3370 | memset(&iscp, 0x00, sizeof(iscp)); | ||
3371 | iscp.iscp_busy = 1; | ||
3372 | iscp.iscp_offset = OFFSET_SCB; | ||
3373 | obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, | ||
3374 | sizeof(iscp)); | ||
3375 | |||
3376 | /* Our first command is to reset the i82586. */ | ||
3377 | memset(&scb, 0x00, sizeof(scb)); | ||
3378 | scb.scb_command = SCB_CMD_RESET; | ||
3379 | scb.scb_cbl_offset = OFFSET_CU; | ||
3380 | scb.scb_rfa_offset = OFFSET_RU; | ||
3381 | obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb, | ||
3382 | sizeof(scb)); | ||
3383 | |||
3384 | set_chan_attn(ioaddr, lp->hacr); | ||
3385 | |||
3386 | /* Wait for command to finish. */ | ||
3387 | for (i = 1000; i > 0; i--) { | ||
3388 | obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, | ||
3389 | sizeof(iscp)); | ||
3390 | |||
3391 | if (iscp.iscp_busy == (unsigned short) 0) | ||
3392 | break; | ||
3393 | |||
3394 | udelay(10); | ||
3395 | } | ||
3396 | |||
3397 | if (i <= 0) { | ||
3398 | #ifdef DEBUG_CONFIG_ERROR | ||
3399 | printk(KERN_INFO | ||
3400 | "%s: wv_82586_start(): iscp_busy timeout.\n", | ||
3401 | dev->name); | ||
3402 | #endif | ||
3403 | return -1; | ||
3404 | } | ||
3405 | |||
3406 | /* Check command completion. */ | ||
3407 | for (i = 15; i > 0; i--) { | ||
3408 | obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, | ||
3409 | sizeof(scb)); | ||
3410 | |||
3411 | if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) | ||
3412 | break; | ||
3413 | |||
3414 | udelay(10); | ||
3415 | } | ||
3416 | |||
3417 | if (i <= 0) { | ||
3418 | #ifdef DEBUG_CONFIG_ERROR | ||
3419 | printk(KERN_INFO | ||
3420 | "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", | ||
3421 | dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); | ||
3422 | #endif | ||
3423 | return -1; | ||
3424 | } | ||
3425 | |||
3426 | wv_ack(dev); | ||
3427 | |||
3428 | /* Set the action command header. */ | ||
3429 | memset(&cb, 0x00, sizeof(cb)); | ||
3430 | cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); | ||
3431 | cb.ac_link = OFFSET_CU; | ||
3432 | obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); | ||
3433 | |||
3434 | if (wv_synchronous_cmd(dev, "diag()") == -1) | ||
3435 | return -1; | ||
3436 | |||
3437 | obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); | ||
3438 | if (cb.ac_status & AC_SFLD_FAIL) { | ||
3439 | #ifdef DEBUG_CONFIG_ERROR | ||
3440 | printk(KERN_INFO | ||
3441 | "%s: wv_82586_start(): i82586 Self Test failed.\n", | ||
3442 | dev->name); | ||
3443 | #endif | ||
3444 | return -1; | ||
3445 | } | ||
3446 | #ifdef DEBUG_I82586_SHOW | ||
3447 | wv_scb_show(ioaddr); | ||
3448 | #endif | ||
3449 | |||
3450 | #ifdef DEBUG_CONFIG_TRACE | ||
3451 | printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); | ||
3452 | #endif | ||
3453 | return 0; | ||
3454 | } | ||
3455 | |||
3456 | /*------------------------------------------------------------------*/ | ||
3457 | /* | ||
3458 | * This routine does a standard configuration of the WaveLAN | ||
3459 | * controller (i82586). | ||
3460 | * | ||
3461 | * This routine is a violent hack. We use the first free transmit block | ||
3462 | * to make our configuration. In the buffer area, we create the three | ||
3463 | * configuration commands (linked). We make the previous NOP point to | ||
3464 | * the beginning of the buffer instead of the tx command. After, we go | ||
3465 | * as usual to the NOP command. | ||
3466 | * Note that only the last command (mc_set) will generate an interrupt. | ||
3467 | * | ||
3468 | * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) | ||
3469 | */ | ||
3470 | static void wv_82586_config(struct net_device * dev) | ||
3471 | { | ||
3472 | net_local *lp = (net_local *) dev->priv; | ||
3473 | unsigned long ioaddr = dev->base_addr; | ||
3474 | unsigned short txblock; | ||
3475 | unsigned short txpred; | ||
3476 | unsigned short tx_addr; | ||
3477 | unsigned short nop_addr; | ||
3478 | unsigned short tbd_addr; | ||
3479 | unsigned short cfg_addr; | ||
3480 | unsigned short ias_addr; | ||
3481 | unsigned short mcs_addr; | ||
3482 | ac_tx_t tx; | ||
3483 | ac_nop_t nop; | ||
3484 | ac_cfg_t cfg; /* Configure action */ | ||
3485 | ac_ias_t ias; /* IA-setup action */ | ||
3486 | ac_mcs_t mcs; /* Multicast setup */ | ||
3487 | struct dev_mc_list *dmi; | ||
3488 | |||
3489 | #ifdef DEBUG_CONFIG_TRACE | ||
3490 | printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); | ||
3491 | #endif | ||
3492 | |||
3493 | /* Check nothing bad has happened */ | ||
3494 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { | ||
3495 | #ifdef DEBUG_CONFIG_ERROR | ||
3496 | printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", | ||
3497 | dev->name); | ||
3498 | #endif | ||
3499 | return; | ||
3500 | } | ||
3501 | |||
3502 | /* Calculate addresses of next block and previous block. */ | ||
3503 | txblock = lp->tx_first_free; | ||
3504 | txpred = txblock - TXBLOCKZ; | ||
3505 | if (txpred < OFFSET_CU) | ||
3506 | txpred += NTXBLOCKS * TXBLOCKZ; | ||
3507 | lp->tx_first_free += TXBLOCKZ; | ||
3508 | if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) | ||
3509 | lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; | ||
3510 | |||
3511 | lp->tx_n_in_use++; | ||
3512 | |||
3513 | /* Calculate addresses of the different parts of the block. */ | ||
3514 | tx_addr = txblock; | ||
3515 | nop_addr = tx_addr + sizeof(tx); | ||
3516 | tbd_addr = nop_addr + sizeof(nop); | ||
3517 | cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ | ||
3518 | ias_addr = cfg_addr + sizeof(cfg); | ||
3519 | mcs_addr = ias_addr + sizeof(ias); | ||
3520 | |||
3521 | /* | ||
3522 | * Transmit command | ||
3523 | */ | ||
3524 | tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ | ||
3525 | obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), | ||
3526 | (unsigned char *) &tx.tx_h.ac_status, | ||
3527 | sizeof(tx.tx_h.ac_status)); | ||
3528 | |||
3529 | /* | ||
3530 | * NOP command | ||
3531 | */ | ||
3532 | nop.nop_h.ac_status = 0; | ||
3533 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
3534 | (unsigned char *) &nop.nop_h.ac_status, | ||
3535 | sizeof(nop.nop_h.ac_status)); | ||
3536 | nop.nop_h.ac_link = nop_addr; | ||
3537 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
3538 | (unsigned char *) &nop.nop_h.ac_link, | ||
3539 | sizeof(nop.nop_h.ac_link)); | ||
3540 | |||
3541 | /* Create a configure action. */ | ||
3542 | memset(&cfg, 0x00, sizeof(cfg)); | ||
3543 | |||
3544 | /* | ||
3545 | * For Linux we invert AC_CFG_ALOC() so as to conform | ||
3546 | * to the way that net packets reach us from above. | ||
3547 | * (See also ac_tx_t.) | ||
3548 | * | ||
3549 | * Updated from Wavelan Manual WCIN085B | ||
3550 | */ | ||
3551 | cfg.cfg_byte_cnt = | ||
3552 | AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); | ||
3553 | cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); | ||
3554 | cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); | ||
3555 | cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | | ||
3556 | AC_CFG_ILPBCK(0) | | ||
3557 | AC_CFG_PRELEN(AC_CFG_PLEN_2) | | ||
3558 | AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); | ||
3559 | cfg.cfg_byte10 = AC_CFG_BOFMET(1) | | ||
3560 | AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); | ||
3561 | cfg.cfg_ifs = 0x20; | ||
3562 | cfg.cfg_slotl = 0x0C; | ||
3563 | cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0); | ||
3564 | cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | | ||
3565 | AC_CFG_BTSTF(0) | | ||
3566 | AC_CFG_CRC16(0) | | ||
3567 | AC_CFG_NCRC(0) | | ||
3568 | AC_CFG_TNCRS(1) | | ||
3569 | AC_CFG_MANCH(0) | | ||
3570 | AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous); | ||
3571 | cfg.cfg_byte15 = AC_CFG_ICDS(0) | | ||
3572 | AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0); | ||
3573 | /* | ||
3574 | cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); | ||
3575 | */ | ||
3576 | cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); | ||
3577 | |||
3578 | cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); | ||
3579 | cfg.cfg_h.ac_link = ias_addr; | ||
3580 | obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg)); | ||
3581 | |||
3582 | /* Set up the MAC address */ | ||
3583 | memset(&ias, 0x00, sizeof(ias)); | ||
3584 | ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); | ||
3585 | ias.ias_h.ac_link = mcs_addr; | ||
3586 | memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0], | ||
3587 | sizeof(ias.ias_addr)); | ||
3588 | obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias)); | ||
3589 | |||
3590 | /* Initialize adapter's Ethernet multicast addresses */ | ||
3591 | memset(&mcs, 0x00, sizeof(mcs)); | ||
3592 | mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); | ||
3593 | mcs.mcs_h.ac_link = nop_addr; | ||
3594 | mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; | ||
3595 | obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs)); | ||
3596 | |||
3597 | /* Any address to set? */ | ||
3598 | if (lp->mc_count) { | ||
3599 | for (dmi = dev->mc_list; dmi; dmi = dmi->next) | ||
3600 | outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr, | ||
3601 | WAVELAN_ADDR_SIZE >> 1); | ||
3602 | |||
3603 | #ifdef DEBUG_CONFIG_INFO | ||
3604 | printk(KERN_DEBUG | ||
3605 | "%s: wv_82586_config(): set %d multicast addresses:\n", | ||
3606 | dev->name, lp->mc_count); | ||
3607 | for (dmi = dev->mc_list; dmi; dmi = dmi->next) | ||
3608 | printk(KERN_DEBUG | ||
3609 | " %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
3610 | dmi->dmi_addr[0], dmi->dmi_addr[1], | ||
3611 | dmi->dmi_addr[2], dmi->dmi_addr[3], | ||
3612 | dmi->dmi_addr[4], dmi->dmi_addr[5]); | ||
3613 | #endif | ||
3614 | } | ||
3615 | |||
3616 | /* | ||
3617 | * Overwrite the predecessor NOP link | ||
3618 | * so that it points to the configure action. | ||
3619 | */ | ||
3620 | nop_addr = txpred + sizeof(tx); | ||
3621 | nop.nop_h.ac_status = 0; | ||
3622 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
3623 | (unsigned char *) &nop.nop_h.ac_status, | ||
3624 | sizeof(nop.nop_h.ac_status)); | ||
3625 | nop.nop_h.ac_link = cfg_addr; | ||
3626 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
3627 | (unsigned char *) &nop.nop_h.ac_link, | ||
3628 | sizeof(nop.nop_h.ac_link)); | ||
3629 | |||
3630 | /* Job done, clear the flag */ | ||
3631 | lp->reconfig_82586 = 0; | ||
3632 | |||
3633 | if (lp->tx_first_in_use == I82586NULL) | ||
3634 | lp->tx_first_in_use = txblock; | ||
3635 | |||
3636 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) | ||
3637 | netif_stop_queue(dev); | ||
3638 | |||
3639 | #ifdef DEBUG_CONFIG_TRACE | ||
3640 | printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); | ||
3641 | #endif | ||
3642 | } | ||
3643 | |||
3644 | /*------------------------------------------------------------------*/ | ||
3645 | /* | ||
3646 | * This routine, called by wavelan_close(), gracefully stops the | ||
3647 | * WaveLAN controller (i82586). | ||
3648 | * (called by wavelan_close()) | ||
3649 | */ | ||
3650 | static inline void wv_82586_stop(struct net_device * dev) | ||
3651 | { | ||
3652 | net_local *lp = (net_local *) dev->priv; | ||
3653 | unsigned long ioaddr = dev->base_addr; | ||
3654 | u16 scb_cmd; | ||
3655 | |||
3656 | #ifdef DEBUG_CONFIG_TRACE | ||
3657 | printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); | ||
3658 | #endif | ||
3659 | |||
3660 | /* Suspend both command unit and receive unit. */ | ||
3661 | scb_cmd = | ||
3662 | (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & | ||
3663 | SCB_CMD_RUC_SUS); | ||
3664 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3665 | (unsigned char *) &scb_cmd, sizeof(scb_cmd)); | ||
3666 | set_chan_attn(ioaddr, lp->hacr); | ||
3667 | |||
3668 | /* No more interrupts */ | ||
3669 | wv_ints_off(dev); | ||
3670 | |||
3671 | #ifdef DEBUG_CONFIG_TRACE | ||
3672 | printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); | ||
3673 | #endif | ||
3674 | } | ||
3675 | |||
3676 | /*------------------------------------------------------------------*/ | ||
3677 | /* | ||
3678 | * Totally reset the WaveLAN and restart it. | ||
3679 | * Performs the following actions: | ||
3680 | * 1. A power reset (reset DMA) | ||
3681 | * 2. Initialize the radio modem (using wv_mmc_init) | ||
3682 | * 3. Reset & Configure LAN controller (using wv_82586_start) | ||
3683 | * 4. Start the LAN controller's command unit | ||
3684 | * 5. Start the LAN controller's receive unit | ||
3685 | * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) | ||
3686 | */ | ||
3687 | static int wv_hw_reset(struct net_device * dev) | ||
3688 | { | ||
3689 | net_local *lp = (net_local *) dev->priv; | ||
3690 | unsigned long ioaddr = dev->base_addr; | ||
3691 | |||
3692 | #ifdef DEBUG_CONFIG_TRACE | ||
3693 | printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, | ||
3694 | (unsigned int) dev); | ||
3695 | #endif | ||
3696 | |||
3697 | /* Increase the number of resets done. */ | ||
3698 | lp->nresets++; | ||
3699 | |||
3700 | wv_hacr_reset(ioaddr); | ||
3701 | lp->hacr = HACR_DEFAULT; | ||
3702 | |||
3703 | if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0)) | ||
3704 | return -1; | ||
3705 | |||
3706 | /* Enable the card to send interrupts. */ | ||
3707 | wv_ints_on(dev); | ||
3708 | |||
3709 | /* Start card functions */ | ||
3710 | if (wv_cu_start(dev) < 0) | ||
3711 | return -1; | ||
3712 | |||
3713 | /* Setup the controller and parameters */ | ||
3714 | wv_82586_config(dev); | ||
3715 | |||
3716 | /* Finish configuration with the receive unit */ | ||
3717 | if (wv_ru_start(dev) < 0) | ||
3718 | return -1; | ||
3719 | |||
3720 | #ifdef DEBUG_CONFIG_TRACE | ||
3721 | printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); | ||
3722 | #endif | ||
3723 | return 0; | ||
3724 | } | ||
3725 | |||
3726 | /*------------------------------------------------------------------*/ | ||
3727 | /* | ||
3728 | * Check if there is a WaveLAN at the specific base address. | ||
3729 | * As a side effect, this reads the MAC address. | ||
3730 | * (called in wavelan_probe() and init_module()) | ||
3731 | */ | ||
3732 | static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) | ||
3733 | { | ||
3734 | int i; /* Loop counter */ | ||
3735 | |||
3736 | /* Check if the base address if available. */ | ||
3737 | if (!request_region(ioaddr, sizeof(ha_t), "wavelan probe")) | ||
3738 | return -EBUSY; /* ioaddr already used */ | ||
3739 | |||
3740 | /* Reset host interface */ | ||
3741 | wv_hacr_reset(ioaddr); | ||
3742 | |||
3743 | /* Read the MAC address from the parameter storage area. */ | ||
3744 | psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), | ||
3745 | mac, 6); | ||
3746 | |||
3747 | release_region(ioaddr, sizeof(ha_t)); | ||
3748 | |||
3749 | /* | ||
3750 | * Check the first three octets of the address for the manufacturer's code. | ||
3751 | * Note: if this can't find your WaveLAN card, you've got a | ||
3752 | * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on | ||
3753 | * how to configure your card. | ||
3754 | */ | ||
3755 | for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) | ||
3756 | if ((mac[0] == MAC_ADDRESSES[i][0]) && | ||
3757 | (mac[1] == MAC_ADDRESSES[i][1]) && | ||
3758 | (mac[2] == MAC_ADDRESSES[i][2])) | ||
3759 | return 0; | ||
3760 | |||
3761 | #ifdef DEBUG_CONFIG_INFO | ||
3762 | printk(KERN_WARNING | ||
3763 | "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", | ||
3764 | ioaddr, mac[0], mac[1], mac[2]); | ||
3765 | #endif | ||
3766 | return -ENODEV; | ||
3767 | } | ||
3768 | |||
3769 | /************************ INTERRUPT HANDLING ************************/ | ||
3770 | |||
3771 | /* | ||
3772 | * This function is the interrupt handler for the WaveLAN card. This | ||
3773 | * routine will be called whenever: | ||
3774 | */ | ||
3775 | static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
3776 | { | ||
3777 | struct net_device *dev; | ||
3778 | unsigned long ioaddr; | ||
3779 | net_local *lp; | ||
3780 | u16 hasr; | ||
3781 | u16 status; | ||
3782 | u16 ack_cmd; | ||
3783 | |||
3784 | dev = dev_id; | ||
3785 | |||
3786 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3787 | printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); | ||
3788 | #endif | ||
3789 | |||
3790 | lp = (net_local *) dev->priv; | ||
3791 | ioaddr = dev->base_addr; | ||
3792 | |||
3793 | #ifdef DEBUG_INTERRUPT_INFO | ||
3794 | /* Check state of our spinlock */ | ||
3795 | if(spin_is_locked(&lp->spinlock)) | ||
3796 | printk(KERN_DEBUG | ||
3797 | "%s: wavelan_interrupt(): spinlock is already locked !!!\n", | ||
3798 | dev->name); | ||
3799 | #endif | ||
3800 | |||
3801 | /* Prevent reentrancy. We need to do that because we may have | ||
3802 | * multiple interrupt handler running concurrently. | ||
3803 | * It is safe because interrupts are disabled before acquiring | ||
3804 | * the spinlock. */ | ||
3805 | spin_lock(&lp->spinlock); | ||
3806 | |||
3807 | /* We always had spurious interrupts at startup, but lately I | ||
3808 | * saw them comming *between* the request_irq() and the | ||
3809 | * spin_lock_irqsave() in wavelan_open(), so the spinlock | ||
3810 | * protection is no enough. | ||
3811 | * So, we also check lp->hacr that will tell us is we enabled | ||
3812 | * irqs or not (see wv_ints_on()). | ||
3813 | * We can't use netif_running(dev) because we depend on the | ||
3814 | * proper processing of the irq generated during the config. */ | ||
3815 | |||
3816 | /* Which interrupt it is ? */ | ||
3817 | hasr = hasr_read(ioaddr); | ||
3818 | |||
3819 | #ifdef DEBUG_INTERRUPT_INFO | ||
3820 | printk(KERN_INFO | ||
3821 | "%s: wavelan_interrupt(): hasr 0x%04x; hacr 0x%04x.\n", | ||
3822 | dev->name, hasr, lp->hacr); | ||
3823 | #endif | ||
3824 | |||
3825 | /* Check modem interrupt */ | ||
3826 | if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { | ||
3827 | u8 dce_status; | ||
3828 | |||
3829 | /* | ||
3830 | * Interrupt from the modem management controller. | ||
3831 | * This will clear it -- ignored for now. | ||
3832 | */ | ||
3833 | mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, | ||
3834 | sizeof(dce_status)); | ||
3835 | |||
3836 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3837 | printk(KERN_INFO | ||
3838 | "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", | ||
3839 | dev->name, dce_status); | ||
3840 | #endif | ||
3841 | } | ||
3842 | |||
3843 | /* Check if not controller interrupt */ | ||
3844 | if (((hasr & HASR_82586_INTR) == 0) || | ||
3845 | ((lp->hacr & HACR_82586_INT_ENABLE) == 0)) { | ||
3846 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3847 | printk(KERN_INFO | ||
3848 | "%s: wavelan_interrupt(): interrupt not coming from i82586 - hasr 0x%04x.\n", | ||
3849 | dev->name, hasr); | ||
3850 | #endif | ||
3851 | spin_unlock (&lp->spinlock); | ||
3852 | return IRQ_NONE; | ||
3853 | } | ||
3854 | |||
3855 | /* Read interrupt data. */ | ||
3856 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), | ||
3857 | (unsigned char *) &status, sizeof(status)); | ||
3858 | |||
3859 | /* | ||
3860 | * Acknowledge the interrupt(s). | ||
3861 | */ | ||
3862 | ack_cmd = status & SCB_ST_INT; | ||
3863 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3864 | (unsigned char *) &ack_cmd, sizeof(ack_cmd)); | ||
3865 | set_chan_attn(ioaddr, lp->hacr); | ||
3866 | |||
3867 | #ifdef DEBUG_INTERRUPT_INFO | ||
3868 | printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", | ||
3869 | dev->name, status); | ||
3870 | #endif | ||
3871 | |||
3872 | /* Command completed. */ | ||
3873 | if ((status & SCB_ST_CX) == SCB_ST_CX) { | ||
3874 | #ifdef DEBUG_INTERRUPT_INFO | ||
3875 | printk(KERN_DEBUG | ||
3876 | "%s: wavelan_interrupt(): command completed.\n", | ||
3877 | dev->name); | ||
3878 | #endif | ||
3879 | wv_complete(dev, ioaddr, lp); | ||
3880 | } | ||
3881 | |||
3882 | /* Frame received. */ | ||
3883 | if ((status & SCB_ST_FR) == SCB_ST_FR) { | ||
3884 | #ifdef DEBUG_INTERRUPT_INFO | ||
3885 | printk(KERN_DEBUG | ||
3886 | "%s: wavelan_interrupt(): received packet.\n", | ||
3887 | dev->name); | ||
3888 | #endif | ||
3889 | wv_receive(dev); | ||
3890 | } | ||
3891 | |||
3892 | /* Check the state of the command unit. */ | ||
3893 | if (((status & SCB_ST_CNA) == SCB_ST_CNA) || | ||
3894 | (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && | ||
3895 | (netif_running(dev)))) { | ||
3896 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3897 | printk(KERN_INFO | ||
3898 | "%s: wavelan_interrupt(): CU inactive -- restarting\n", | ||
3899 | dev->name); | ||
3900 | #endif | ||
3901 | wv_hw_reset(dev); | ||
3902 | } | ||
3903 | |||
3904 | /* Check the state of the command unit. */ | ||
3905 | if (((status & SCB_ST_RNR) == SCB_ST_RNR) || | ||
3906 | (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && | ||
3907 | (netif_running(dev)))) { | ||
3908 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3909 | printk(KERN_INFO | ||
3910 | "%s: wavelan_interrupt(): RU not ready -- restarting\n", | ||
3911 | dev->name); | ||
3912 | #endif | ||
3913 | wv_hw_reset(dev); | ||
3914 | } | ||
3915 | |||
3916 | /* Release spinlock */ | ||
3917 | spin_unlock (&lp->spinlock); | ||
3918 | |||
3919 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3920 | printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); | ||
3921 | #endif | ||
3922 | return IRQ_HANDLED; | ||
3923 | } | ||
3924 | |||
3925 | /*------------------------------------------------------------------*/ | ||
3926 | /* | ||
3927 | * Watchdog: when we start a transmission, a timer is set for us in the | ||
3928 | * kernel. If the transmission completes, this timer is disabled. If | ||
3929 | * the timer expires, we are called and we try to unlock the hardware. | ||
3930 | */ | ||
3931 | static void wavelan_watchdog(struct net_device * dev) | ||
3932 | { | ||
3933 | net_local * lp = (net_local *)dev->priv; | ||
3934 | u_long ioaddr = dev->base_addr; | ||
3935 | unsigned long flags; | ||
3936 | unsigned int nreaped; | ||
3937 | |||
3938 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3939 | printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); | ||
3940 | #endif | ||
3941 | |||
3942 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3943 | printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", | ||
3944 | dev->name); | ||
3945 | #endif | ||
3946 | |||
3947 | /* Check that we came here for something */ | ||
3948 | if (lp->tx_n_in_use <= 0) { | ||
3949 | return; | ||
3950 | } | ||
3951 | |||
3952 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3953 | |||
3954 | /* Try to see if some buffers are not free (in case we missed | ||
3955 | * an interrupt */ | ||
3956 | nreaped = wv_complete(dev, ioaddr, lp); | ||
3957 | |||
3958 | #ifdef DEBUG_INTERRUPT_INFO | ||
3959 | printk(KERN_DEBUG | ||
3960 | "%s: wavelan_watchdog(): %d reaped, %d remain.\n", | ||
3961 | dev->name, nreaped, lp->tx_n_in_use); | ||
3962 | #endif | ||
3963 | |||
3964 | #ifdef DEBUG_PSA_SHOW | ||
3965 | { | ||
3966 | psa_t psa; | ||
3967 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
3968 | wv_psa_show(&psa); | ||
3969 | } | ||
3970 | #endif | ||
3971 | #ifdef DEBUG_MMC_SHOW | ||
3972 | wv_mmc_show(dev); | ||
3973 | #endif | ||
3974 | #ifdef DEBUG_I82586_SHOW | ||
3975 | wv_cu_show(dev); | ||
3976 | #endif | ||
3977 | |||
3978 | /* If no buffer has been freed */ | ||
3979 | if (nreaped == 0) { | ||
3980 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3981 | printk(KERN_INFO | ||
3982 | "%s: wavelan_watchdog(): cleanup failed, trying reset\n", | ||
3983 | dev->name); | ||
3984 | #endif | ||
3985 | wv_hw_reset(dev); | ||
3986 | } | ||
3987 | |||
3988 | /* At this point, we should have some free Tx buffer ;-) */ | ||
3989 | if (lp->tx_n_in_use < NTXBLOCKS - 1) | ||
3990 | netif_wake_queue(dev); | ||
3991 | |||
3992 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3993 | |||
3994 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3995 | printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); | ||
3996 | #endif | ||
3997 | } | ||
3998 | |||
3999 | /********************* CONFIGURATION CALLBACKS *********************/ | ||
4000 | /* | ||
4001 | * Here are the functions called by the Linux networking code (NET3) | ||
4002 | * for initialization, configuration and deinstallations of the | ||
4003 | * WaveLAN ISA hardware. | ||
4004 | */ | ||
4005 | |||
4006 | /*------------------------------------------------------------------*/ | ||
4007 | /* | ||
4008 | * Configure and start up the WaveLAN PCMCIA adaptor. | ||
4009 | * Called by NET3 when it "opens" the device. | ||
4010 | */ | ||
4011 | static int wavelan_open(struct net_device * dev) | ||
4012 | { | ||
4013 | net_local * lp = (net_local *)dev->priv; | ||
4014 | unsigned long flags; | ||
4015 | |||
4016 | #ifdef DEBUG_CALLBACK_TRACE | ||
4017 | printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, | ||
4018 | (unsigned int) dev); | ||
4019 | #endif | ||
4020 | |||
4021 | /* Check irq */ | ||
4022 | if (dev->irq == 0) { | ||
4023 | #ifdef DEBUG_CONFIG_ERROR | ||
4024 | printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", | ||
4025 | dev->name); | ||
4026 | #endif | ||
4027 | return -ENXIO; | ||
4028 | } | ||
4029 | |||
4030 | if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) | ||
4031 | { | ||
4032 | #ifdef DEBUG_CONFIG_ERROR | ||
4033 | printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", | ||
4034 | dev->name); | ||
4035 | #endif | ||
4036 | return -EAGAIN; | ||
4037 | } | ||
4038 | |||
4039 | spin_lock_irqsave(&lp->spinlock, flags); | ||
4040 | |||
4041 | if (wv_hw_reset(dev) != -1) { | ||
4042 | netif_start_queue(dev); | ||
4043 | } else { | ||
4044 | free_irq(dev->irq, dev); | ||
4045 | #ifdef DEBUG_CONFIG_ERROR | ||
4046 | printk(KERN_INFO | ||
4047 | "%s: wavelan_open(): impossible to start the card\n", | ||
4048 | dev->name); | ||
4049 | #endif | ||
4050 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
4051 | return -EAGAIN; | ||
4052 | } | ||
4053 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
4054 | |||
4055 | #ifdef DEBUG_CALLBACK_TRACE | ||
4056 | printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); | ||
4057 | #endif | ||
4058 | return 0; | ||
4059 | } | ||
4060 | |||
4061 | /*------------------------------------------------------------------*/ | ||
4062 | /* | ||
4063 | * Shut down the WaveLAN ISA card. | ||
4064 | * Called by NET3 when it "closes" the device. | ||
4065 | */ | ||
4066 | static int wavelan_close(struct net_device * dev) | ||
4067 | { | ||
4068 | net_local *lp = (net_local *) dev->priv; | ||
4069 | unsigned long flags; | ||
4070 | |||
4071 | #ifdef DEBUG_CALLBACK_TRACE | ||
4072 | printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, | ||
4073 | (unsigned int) dev); | ||
4074 | #endif | ||
4075 | |||
4076 | netif_stop_queue(dev); | ||
4077 | |||
4078 | /* | ||
4079 | * Flush the Tx and disable Rx. | ||
4080 | */ | ||
4081 | spin_lock_irqsave(&lp->spinlock, flags); | ||
4082 | wv_82586_stop(dev); | ||
4083 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
4084 | |||
4085 | free_irq(dev->irq, dev); | ||
4086 | |||
4087 | #ifdef DEBUG_CALLBACK_TRACE | ||
4088 | printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); | ||
4089 | #endif | ||
4090 | return 0; | ||
4091 | } | ||
4092 | |||
4093 | /*------------------------------------------------------------------*/ | ||
4094 | /* | ||
4095 | * Probe an I/O address, and if the WaveLAN is there configure the | ||
4096 | * device structure | ||
4097 | * (called by wavelan_probe() and via init_module()). | ||
4098 | */ | ||
4099 | static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) | ||
4100 | { | ||
4101 | u8 irq_mask; | ||
4102 | int irq; | ||
4103 | net_local *lp; | ||
4104 | mac_addr mac; | ||
4105 | int err; | ||
4106 | |||
4107 | if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) | ||
4108 | return -EADDRINUSE; | ||
4109 | |||
4110 | err = wv_check_ioaddr(ioaddr, mac); | ||
4111 | if (err) | ||
4112 | goto out; | ||
4113 | |||
4114 | memcpy(dev->dev_addr, mac, 6); | ||
4115 | |||
4116 | dev->base_addr = ioaddr; | ||
4117 | |||
4118 | #ifdef DEBUG_CALLBACK_TRACE | ||
4119 | printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", | ||
4120 | dev->name, (unsigned int) dev, ioaddr); | ||
4121 | #endif | ||
4122 | |||
4123 | /* Check IRQ argument on command line. */ | ||
4124 | if (dev->irq != 0) { | ||
4125 | irq_mask = wv_irq_to_psa(dev->irq); | ||
4126 | |||
4127 | if (irq_mask == 0) { | ||
4128 | #ifdef DEBUG_CONFIG_ERROR | ||
4129 | printk(KERN_WARNING | ||
4130 | "%s: wavelan_config(): invalid IRQ %d ignored.\n", | ||
4131 | dev->name, dev->irq); | ||
4132 | #endif | ||
4133 | dev->irq = 0; | ||
4134 | } else { | ||
4135 | #ifdef DEBUG_CONFIG_INFO | ||
4136 | printk(KERN_DEBUG | ||
4137 | "%s: wavelan_config(): changing IRQ to %d\n", | ||
4138 | dev->name, dev->irq); | ||
4139 | #endif | ||
4140 | psa_write(ioaddr, HACR_DEFAULT, | ||
4141 | psaoff(0, psa_int_req_no), &irq_mask, 1); | ||
4142 | /* update the Wavelan checksum */ | ||
4143 | update_psa_checksum(dev, ioaddr, HACR_DEFAULT); | ||
4144 | wv_hacr_reset(ioaddr); | ||
4145 | } | ||
4146 | } | ||
4147 | |||
4148 | psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), | ||
4149 | &irq_mask, 1); | ||
4150 | if ((irq = wv_psa_to_irq(irq_mask)) == -1) { | ||
4151 | #ifdef DEBUG_CONFIG_ERROR | ||
4152 | printk(KERN_INFO | ||
4153 | "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", | ||
4154 | dev->name, irq_mask); | ||
4155 | #endif | ||
4156 | err = -EAGAIN; | ||
4157 | goto out; | ||
4158 | } | ||
4159 | |||
4160 | dev->irq = irq; | ||
4161 | |||
4162 | dev->mem_start = 0x0000; | ||
4163 | dev->mem_end = 0x0000; | ||
4164 | dev->if_port = 0; | ||
4165 | |||
4166 | /* Initialize device structures */ | ||
4167 | memset(dev->priv, 0, sizeof(net_local)); | ||
4168 | lp = (net_local *) dev->priv; | ||
4169 | |||
4170 | /* Back link to the device structure. */ | ||
4171 | lp->dev = dev; | ||
4172 | /* Add the device at the beginning of the linked list. */ | ||
4173 | lp->next = wavelan_list; | ||
4174 | wavelan_list = lp; | ||
4175 | |||
4176 | lp->hacr = HACR_DEFAULT; | ||
4177 | |||
4178 | /* Multicast stuff */ | ||
4179 | lp->promiscuous = 0; | ||
4180 | lp->mc_count = 0; | ||
4181 | |||
4182 | /* Init spinlock */ | ||
4183 | spin_lock_init(&lp->spinlock); | ||
4184 | |||
4185 | SET_MODULE_OWNER(dev); | ||
4186 | dev->open = wavelan_open; | ||
4187 | dev->stop = wavelan_close; | ||
4188 | dev->hard_start_xmit = wavelan_packet_xmit; | ||
4189 | dev->get_stats = wavelan_get_stats; | ||
4190 | dev->set_multicast_list = &wavelan_set_multicast_list; | ||
4191 | dev->tx_timeout = &wavelan_watchdog; | ||
4192 | dev->watchdog_timeo = WATCHDOG_JIFFIES; | ||
4193 | #ifdef SET_MAC_ADDRESS | ||
4194 | dev->set_mac_address = &wavelan_set_mac_address; | ||
4195 | #endif /* SET_MAC_ADDRESS */ | ||
4196 | |||
4197 | #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ | ||
4198 | dev->wireless_handlers = &wavelan_handler_def; | ||
4199 | lp->wireless_data.spy_data = &lp->spy_data; | ||
4200 | dev->wireless_data = &lp->wireless_data; | ||
4201 | #endif | ||
4202 | |||
4203 | dev->mtu = WAVELAN_MTU; | ||
4204 | |||
4205 | /* Display nice information. */ | ||
4206 | wv_init_info(dev); | ||
4207 | |||
4208 | #ifdef DEBUG_CALLBACK_TRACE | ||
4209 | printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); | ||
4210 | #endif | ||
4211 | return 0; | ||
4212 | out: | ||
4213 | release_region(ioaddr, sizeof(ha_t)); | ||
4214 | return err; | ||
4215 | } | ||
4216 | |||
4217 | /*------------------------------------------------------------------*/ | ||
4218 | /* | ||
4219 | * Check for a network adaptor of this type. Return '0' iff one | ||
4220 | * exists. There seem to be different interpretations of | ||
4221 | * the initial value of dev->base_addr. | ||
4222 | * We follow the example in drivers/net/ne.c. | ||
4223 | * (called in "Space.c") | ||
4224 | */ | ||
4225 | struct net_device * __init wavelan_probe(int unit) | ||
4226 | { | ||
4227 | struct net_device *dev; | ||
4228 | short base_addr; | ||
4229 | int def_irq; | ||
4230 | int i; | ||
4231 | int r = 0; | ||
4232 | |||
4233 | #ifdef STRUCT_CHECK | ||
4234 | if (wv_struct_check() != (char *) NULL) { | ||
4235 | printk(KERN_WARNING | ||
4236 | "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", | ||
4237 | dev->name, wv_struct_check()); | ||
4238 | return -ENODEV; | ||
4239 | } | ||
4240 | #endif /* STRUCT_CHECK */ | ||
4241 | |||
4242 | dev = alloc_etherdev(sizeof(net_local)); | ||
4243 | if (!dev) | ||
4244 | return ERR_PTR(-ENOMEM); | ||
4245 | |||
4246 | sprintf(dev->name, "eth%d", unit); | ||
4247 | netdev_boot_setup_check(dev); | ||
4248 | base_addr = dev->base_addr; | ||
4249 | def_irq = dev->irq; | ||
4250 | |||
4251 | #ifdef DEBUG_CALLBACK_TRACE | ||
4252 | printk(KERN_DEBUG | ||
4253 | "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", | ||
4254 | dev->name, dev, (unsigned int) dev->base_addr); | ||
4255 | #endif | ||
4256 | |||
4257 | /* Don't probe at all. */ | ||
4258 | if (base_addr < 0) { | ||
4259 | #ifdef DEBUG_CONFIG_ERROR | ||
4260 | printk(KERN_WARNING | ||
4261 | "%s: wavelan_probe(): invalid base address\n", | ||
4262 | dev->name); | ||
4263 | #endif | ||
4264 | r = -ENXIO; | ||
4265 | } else if (base_addr > 0x100) { /* Check a single specified location. */ | ||
4266 | r = wavelan_config(dev, base_addr); | ||
4267 | #ifdef DEBUG_CONFIG_INFO | ||
4268 | if (r != 0) | ||
4269 | printk(KERN_DEBUG | ||
4270 | "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", | ||
4271 | dev->name, base_addr); | ||
4272 | #endif | ||
4273 | |||
4274 | #ifdef DEBUG_CALLBACK_TRACE | ||
4275 | printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); | ||
4276 | #endif | ||
4277 | } else { /* Scan all possible addresses of the WaveLAN hardware. */ | ||
4278 | for (i = 0; i < NELS(iobase); i++) { | ||
4279 | dev->irq = def_irq; | ||
4280 | if (wavelan_config(dev, iobase[i]) == 0) { | ||
4281 | #ifdef DEBUG_CALLBACK_TRACE | ||
4282 | printk(KERN_DEBUG | ||
4283 | "%s: <-wavelan_probe()\n", | ||
4284 | dev->name); | ||
4285 | #endif | ||
4286 | break; | ||
4287 | } | ||
4288 | } | ||
4289 | if (i == NELS(iobase)) | ||
4290 | r = -ENODEV; | ||
4291 | } | ||
4292 | if (r) | ||
4293 | goto out; | ||
4294 | r = register_netdev(dev); | ||
4295 | if (r) | ||
4296 | goto out1; | ||
4297 | return dev; | ||
4298 | out1: | ||
4299 | release_region(dev->base_addr, sizeof(ha_t)); | ||
4300 | wavelan_list = wavelan_list->next; | ||
4301 | out: | ||
4302 | free_netdev(dev); | ||
4303 | return ERR_PTR(r); | ||
4304 | } | ||
4305 | |||
4306 | /****************************** MODULE ******************************/ | ||
4307 | /* | ||
4308 | * Module entry point: insertion and removal | ||
4309 | */ | ||
4310 | |||
4311 | #ifdef MODULE | ||
4312 | /*------------------------------------------------------------------*/ | ||
4313 | /* | ||
4314 | * Insertion of the module | ||
4315 | * I'm now quite proud of the multi-device support. | ||
4316 | */ | ||
4317 | int init_module(void) | ||
4318 | { | ||
4319 | int ret = -EIO; /* Return error if no cards found */ | ||
4320 | int i; | ||
4321 | |||
4322 | #ifdef DEBUG_MODULE_TRACE | ||
4323 | printk(KERN_DEBUG "-> init_module()\n"); | ||
4324 | #endif | ||
4325 | |||
4326 | /* If probing is asked */ | ||
4327 | if (io[0] == 0) { | ||
4328 | #ifdef DEBUG_CONFIG_ERROR | ||
4329 | printk(KERN_WARNING | ||
4330 | "WaveLAN init_module(): doing device probing (bad !)\n"); | ||
4331 | printk(KERN_WARNING | ||
4332 | "Specify base addresses while loading module to correct the problem\n"); | ||
4333 | #endif | ||
4334 | |||
4335 | /* Copy the basic set of address to be probed. */ | ||
4336 | for (i = 0; i < NELS(iobase); i++) | ||
4337 | io[i] = iobase[i]; | ||
4338 | } | ||
4339 | |||
4340 | |||
4341 | /* Loop on all possible base addresses. */ | ||
4342 | i = -1; | ||
4343 | while ((io[++i] != 0) && (i < NELS(io))) { | ||
4344 | struct net_device *dev = alloc_etherdev(sizeof(net_local)); | ||
4345 | if (!dev) | ||
4346 | break; | ||
4347 | if (name[i]) | ||
4348 | strcpy(dev->name, name[i]); /* Copy name */ | ||
4349 | dev->base_addr = io[i]; | ||
4350 | dev->irq = irq[i]; | ||
4351 | |||
4352 | /* Check if there is something at this base address. */ | ||
4353 | if (wavelan_config(dev, io[i]) == 0) { | ||
4354 | if (register_netdev(dev) != 0) { | ||
4355 | release_region(dev->base_addr, sizeof(ha_t)); | ||
4356 | wavelan_list = wavelan_list->next; | ||
4357 | } else { | ||
4358 | ret = 0; | ||
4359 | continue; | ||
4360 | } | ||
4361 | } | ||
4362 | free_netdev(dev); | ||
4363 | } | ||
4364 | |||
4365 | #ifdef DEBUG_CONFIG_ERROR | ||
4366 | if (!wavelan_list) | ||
4367 | printk(KERN_WARNING | ||
4368 | "WaveLAN init_module(): no device found\n"); | ||
4369 | #endif | ||
4370 | |||
4371 | #ifdef DEBUG_MODULE_TRACE | ||
4372 | printk(KERN_DEBUG "<- init_module()\n"); | ||
4373 | #endif | ||
4374 | return ret; | ||
4375 | } | ||
4376 | |||
4377 | /*------------------------------------------------------------------*/ | ||
4378 | /* | ||
4379 | * Removal of the module | ||
4380 | */ | ||
4381 | void cleanup_module(void) | ||
4382 | { | ||
4383 | #ifdef DEBUG_MODULE_TRACE | ||
4384 | printk(KERN_DEBUG "-> cleanup_module()\n"); | ||
4385 | #endif | ||
4386 | |||
4387 | /* Loop on all devices and release them. */ | ||
4388 | while (wavelan_list) { | ||
4389 | struct net_device *dev = wavelan_list->dev; | ||
4390 | |||
4391 | #ifdef DEBUG_CONFIG_INFO | ||
4392 | printk(KERN_DEBUG | ||
4393 | "%s: cleanup_module(): removing device at 0x%x\n", | ||
4394 | dev->name, (unsigned int) dev); | ||
4395 | #endif | ||
4396 | unregister_netdev(dev); | ||
4397 | |||
4398 | release_region(dev->base_addr, sizeof(ha_t)); | ||
4399 | wavelan_list = wavelan_list->next; | ||
4400 | |||
4401 | free_netdev(dev); | ||
4402 | } | ||
4403 | |||
4404 | #ifdef DEBUG_MODULE_TRACE | ||
4405 | printk(KERN_DEBUG "<- cleanup_module()\n"); | ||
4406 | #endif | ||
4407 | } | ||
4408 | #endif /* MODULE */ | ||
4409 | MODULE_LICENSE("GPL"); | ||
4410 | |||
4411 | /* | ||
4412 | * This software may only be used and distributed | ||
4413 | * according to the terms of the GNU General Public License. | ||
4414 | * | ||
4415 | * This software was developed as a component of the | ||
4416 | * Linux operating system. | ||
4417 | * It is based on other device drivers and information | ||
4418 | * either written or supplied by: | ||
4419 | * Ajay Bakre (bakre@paul.rutgers.edu), | ||
4420 | * Donald Becker (becker@scyld.com), | ||
4421 | * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), | ||
4422 | * Anders Klemets (klemets@it.kth.se), | ||
4423 | * Vladimir V. Kolpakov (w@stier.koenig.ru), | ||
4424 | * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), | ||
4425 | * Pauline Middelink (middelin@polyware.iaf.nl), | ||
4426 | * Robert Morris (rtm@das.harvard.edu), | ||
4427 | * Jean Tourrilhes (jt@hplb.hpl.hp.com), | ||
4428 | * Girish Welling (welling@paul.rutgers.edu), | ||
4429 | * | ||
4430 | * Thanks go also to: | ||
4431 | * James Ashton (jaa101@syseng.anu.edu.au), | ||
4432 | * Alan Cox (alan@redhat.com), | ||
4433 | * Allan Creighton (allanc@cs.usyd.edu.au), | ||
4434 | * Matthew Geier (matthew@cs.usyd.edu.au), | ||
4435 | * Remo di Giovanni (remo@cs.usyd.edu.au), | ||
4436 | * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), | ||
4437 | * Vipul Gupta (vgupta@cs.binghamton.edu), | ||
4438 | * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), | ||
4439 | * Tim Nicholson (tim@cs.usyd.edu.au), | ||
4440 | * Ian Parkin (ian@cs.usyd.edu.au), | ||
4441 | * John Rosenberg (johnr@cs.usyd.edu.au), | ||
4442 | * George Rossi (george@phm.gov.au), | ||
4443 | * Arthur Scott (arthur@cs.usyd.edu.au), | ||
4444 | * Peter Storey, | ||
4445 | * for their assistance and advice. | ||
4446 | * | ||
4447 | * Please send bug reports, updates, comments to: | ||
4448 | * | ||
4449 | * Bruce Janson Email: bruce@cs.usyd.edu.au | ||
4450 | * Basser Department of Computer Science Phone: +61-2-9351-3423 | ||
4451 | * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 | ||
4452 | */ | ||
diff --git a/drivers/net/wireless/wavelan.h b/drivers/net/wireless/wavelan.h new file mode 100644 index 000000000000..27172cde5a39 --- /dev/null +++ b/drivers/net/wireless/wavelan.h | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * WaveLAN ISA driver | ||
3 | * | ||
4 | * Jean II - HPLB '96 | ||
5 | * | ||
6 | * Reorganisation and extension of the driver. | ||
7 | * Original copyright follows. See wavelan.p.h for details. | ||
8 | * | ||
9 | * This file contains the declarations for the WaveLAN hardware. Note that | ||
10 | * the WaveLAN ISA includes a i82586 controller (see definitions in | ||
11 | * file i82586.h). | ||
12 | * | ||
13 | * The main difference between the ISA hardware and the PCMCIA one is | ||
14 | * the Ethernet controller (i82586 instead of i82593). | ||
15 | * The i82586 allows multiple transmit buffers. The PSA needs to be accessed | ||
16 | * through the host interface. | ||
17 | */ | ||
18 | |||
19 | #ifndef _WAVELAN_H | ||
20 | #define _WAVELAN_H | ||
21 | |||
22 | /************************** MAGIC NUMBERS ***************************/ | ||
23 | |||
24 | /* Detection of the WaveLAN card is done by reading the MAC | ||
25 | * address from the card and checking it. If you have a non-AT&T | ||
26 | * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), | ||
27 | * you might need to modify this part to accommodate your hardware. | ||
28 | */ | ||
29 | static const char MAC_ADDRESSES[][3] = | ||
30 | { | ||
31 | { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ | ||
32 | { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ | ||
33 | { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ | ||
34 | { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ | ||
35 | /* Add your card here and send me the patch! */ | ||
36 | }; | ||
37 | |||
38 | #define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ | ||
39 | |||
40 | #define WAVELAN_MTU 1500 /* Maximum size of WaveLAN packet */ | ||
41 | |||
42 | #define MAXDATAZ (WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU) | ||
43 | |||
44 | /* | ||
45 | * Constants used to convert channels to frequencies | ||
46 | */ | ||
47 | |||
48 | /* Frequency available in the 2.0 modem, in units of 250 kHz | ||
49 | * (as read in the offset register of the dac area). | ||
50 | * Used to map channel numbers used by `wfreqsel' to frequencies | ||
51 | */ | ||
52 | static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, | ||
53 | 0xD0, 0xF0, 0xF8, 0x150 }; | ||
54 | |||
55 | /* Frequencies of the 1.0 modem (fixed frequencies). | ||
56 | * Use to map the PSA `subband' to a frequency | ||
57 | * Note : all frequencies apart from the first one need to be multiplied by 10 | ||
58 | */ | ||
59 | static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; | ||
60 | |||
61 | |||
62 | |||
63 | /*************************** PC INTERFACE ****************************/ | ||
64 | |||
65 | /* | ||
66 | * Host Adaptor structure. | ||
67 | * (base is board port address). | ||
68 | */ | ||
69 | typedef union hacs_u hacs_u; | ||
70 | union hacs_u | ||
71 | { | ||
72 | unsigned short hu_command; /* Command register */ | ||
73 | #define HACR_RESET 0x0001 /* Reset board */ | ||
74 | #define HACR_CA 0x0002 /* Set Channel Attention for 82586 */ | ||
75 | #define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */ | ||
76 | #define HACR_OUT0 0x0008 /* General purpose output pin 0 */ | ||
77 | /* not used - must be 1 */ | ||
78 | #define HACR_OUT1 0x0010 /* General purpose output pin 1 */ | ||
79 | /* not used - must be 1 */ | ||
80 | #define HACR_82586_INT_ENABLE 0x0020 /* Enable 82586 interrupts */ | ||
81 | #define HACR_MMC_INT_ENABLE 0x0040 /* Enable MMC interrupts */ | ||
82 | #define HACR_INTR_CLR_ENABLE 0x0080 /* Enable interrupt status read/clear */ | ||
83 | unsigned short hu_status; /* Status Register */ | ||
84 | #define HASR_82586_INTR 0x0001 /* Interrupt request from 82586 */ | ||
85 | #define HASR_MMC_INTR 0x0002 /* Interrupt request from MMC */ | ||
86 | #define HASR_MMC_BUSY 0x0004 /* MMC busy indication */ | ||
87 | #define HASR_PSA_BUSY 0x0008 /* LAN parameter storage area busy */ | ||
88 | }; | ||
89 | |||
90 | typedef struct ha_t ha_t; | ||
91 | struct ha_t | ||
92 | { | ||
93 | hacs_u ha_cs; /* Command and status registers */ | ||
94 | #define ha_command ha_cs.hu_command | ||
95 | #define ha_status ha_cs.hu_status | ||
96 | unsigned short ha_mmcr; /* Modem Management Ctrl Register */ | ||
97 | unsigned short ha_pior0; /* Program I/O Address Register Port 0 */ | ||
98 | unsigned short ha_piop0; /* Program I/O Port 0 */ | ||
99 | unsigned short ha_pior1; /* Program I/O Address Register Port 1 */ | ||
100 | unsigned short ha_piop1; /* Program I/O Port 1 */ | ||
101 | unsigned short ha_pior2; /* Program I/O Address Register Port 2 */ | ||
102 | unsigned short ha_piop2; /* Program I/O Port 2 */ | ||
103 | }; | ||
104 | |||
105 | #define HA_SIZE 16 | ||
106 | |||
107 | #define hoff(p,f) (unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0) | ||
108 | #define HACR(p) hoff(p, ha_command) | ||
109 | #define HASR(p) hoff(p, ha_status) | ||
110 | #define MMCR(p) hoff(p, ha_mmcr) | ||
111 | #define PIOR0(p) hoff(p, ha_pior0) | ||
112 | #define PIOP0(p) hoff(p, ha_piop0) | ||
113 | #define PIOR1(p) hoff(p, ha_pior1) | ||
114 | #define PIOP1(p) hoff(p, ha_piop1) | ||
115 | #define PIOR2(p) hoff(p, ha_pior2) | ||
116 | #define PIOP2(p) hoff(p, ha_piop2) | ||
117 | |||
118 | /* | ||
119 | * Program I/O Mode Register values. | ||
120 | */ | ||
121 | #define STATIC_PIO 0 /* Mode 1: static mode */ | ||
122 | /* RAM access ??? */ | ||
123 | #define AUTOINCR_PIO 1 /* Mode 2: auto increment mode */ | ||
124 | /* RAM access ??? */ | ||
125 | #define AUTODECR_PIO 2 /* Mode 3: auto decrement mode */ | ||
126 | /* RAM access ??? */ | ||
127 | #define PARAM_ACCESS_PIO 3 /* Mode 4: LAN parameter access mode */ | ||
128 | /* Parameter access. */ | ||
129 | #define PIO_MASK 3 /* register mask */ | ||
130 | #define PIOM(cmd,piono) ((u_short)cmd << 10 << (piono * 2)) | ||
131 | |||
132 | #define HACR_DEFAULT (HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2)) | ||
133 | #define HACR_INTRON (HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE) | ||
134 | |||
135 | /************************** MEMORY LAYOUT **************************/ | ||
136 | |||
137 | /* | ||
138 | * Onboard 64 k RAM layout. | ||
139 | * (Offsets from 0x0000.) | ||
140 | */ | ||
141 | #define OFFSET_RU 0x0000 /* 75% memory */ | ||
142 | #define OFFSET_CU 0xC000 /* 25% memory */ | ||
143 | #define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t)) | ||
144 | #define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t)) | ||
145 | #define OFFSET_SCP I82586_SCP_ADDR | ||
146 | |||
147 | #define RXBLOCKZ (sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ) | ||
148 | #define TXBLOCKZ (sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ) | ||
149 | |||
150 | #define NRXBLOCKS ((OFFSET_CU - OFFSET_RU) / RXBLOCKZ) | ||
151 | #define NTXBLOCKS ((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ) | ||
152 | |||
153 | /********************** PARAMETER STORAGE AREA **********************/ | ||
154 | |||
155 | /* | ||
156 | * Parameter Storage Area (PSA). | ||
157 | */ | ||
158 | typedef struct psa_t psa_t; | ||
159 | struct psa_t | ||
160 | { | ||
161 | unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ | ||
162 | unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ | ||
163 | unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ | ||
164 | unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ | ||
165 | unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ | ||
166 | unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ | ||
167 | unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ | ||
168 | unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ | ||
169 | unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ | ||
170 | unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ | ||
171 | |||
172 | unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ | ||
173 | unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ | ||
174 | unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ | ||
175 | #define PSA_UNIVERSAL 0 /* Universal (factory) */ | ||
176 | #define PSA_LOCAL 1 /* Local */ | ||
177 | unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */ | ||
178 | #define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ | ||
179 | #define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ | ||
180 | #define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ | ||
181 | #define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ | ||
182 | #define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ | ||
183 | unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ | ||
184 | unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ | ||
185 | #define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ | ||
186 | unsigned char psa_subband; /* [0x20] Subband */ | ||
187 | #define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ | ||
188 | #define PSA_SUBBAND_2425 1 /* 2425 MHz */ | ||
189 | #define PSA_SUBBAND_2460 2 /* 2460 MHz */ | ||
190 | #define PSA_SUBBAND_2484 3 /* 2484 MHz */ | ||
191 | #define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ | ||
192 | unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ | ||
193 | unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */ | ||
194 | unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ | ||
195 | unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */ | ||
196 | unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */ | ||
197 | unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ | ||
198 | unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ | ||
199 | unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ | ||
200 | unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ | ||
201 | unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ | ||
202 | unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ | ||
203 | unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ | ||
204 | unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ | ||
205 | }; | ||
206 | |||
207 | #define PSA_SIZE 64 | ||
208 | |||
209 | /* Calculate offset of a field in the above structure. | ||
210 | * Warning: only even addresses are used. */ | ||
211 | #define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) | ||
212 | |||
213 | /******************** MODEM MANAGEMENT INTERFACE ********************/ | ||
214 | |||
215 | /* | ||
216 | * Modem Management Controller (MMC) write structure. | ||
217 | */ | ||
218 | typedef struct mmw_t mmw_t; | ||
219 | struct mmw_t | ||
220 | { | ||
221 | unsigned char mmw_encr_key[8]; /* encryption key */ | ||
222 | unsigned char mmw_encr_enable; /* Enable or disable encryption. */ | ||
223 | #define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */ | ||
224 | #define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */ | ||
225 | unsigned char mmw_unused0[1]; /* unused */ | ||
226 | unsigned char mmw_des_io_invert; /* encryption option */ | ||
227 | #define MMW_DES_IO_INVERT_RES 0x0F /* reserved */ | ||
228 | #define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */ | ||
229 | unsigned char mmw_unused1[5]; /* unused */ | ||
230 | unsigned char mmw_loopt_sel; /* looptest selection */ | ||
231 | #define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */ | ||
232 | #define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */ | ||
233 | #define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */ | ||
234 | #define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ | ||
235 | #define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ | ||
236 | #define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ | ||
237 | #define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ | ||
238 | unsigned char mmw_jabber_enable; /* jabber timer enable */ | ||
239 | /* Abort transmissions > 200 ms */ | ||
240 | unsigned char mmw_freeze; /* freeze or unfreeze signal level */ | ||
241 | /* 0 : signal level & qual updated for every new message, 1 : frozen */ | ||
242 | unsigned char mmw_anten_sel; /* antenna selection */ | ||
243 | #define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ | ||
244 | #define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ | ||
245 | unsigned char mmw_ifs; /* inter frame spacing */ | ||
246 | /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ | ||
247 | unsigned char mmw_mod_delay; /* modem delay (synchro) */ | ||
248 | unsigned char mmw_jam_time; /* jamming time (after collision) */ | ||
249 | unsigned char mmw_unused2[1]; /* unused */ | ||
250 | unsigned char mmw_thr_pre_set; /* level threshold preset */ | ||
251 | /* Discard all packet with signal < this value (4) */ | ||
252 | unsigned char mmw_decay_prm; /* decay parameters */ | ||
253 | unsigned char mmw_decay_updat_prm; /* decay update parameters */ | ||
254 | unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ | ||
255 | /* Discard all packet with quality < this value (3) */ | ||
256 | unsigned char mmw_netw_id_l; /* NWID low order byte */ | ||
257 | unsigned char mmw_netw_id_h; /* NWID high order byte */ | ||
258 | /* Network ID or Domain : create virtual net on the air */ | ||
259 | |||
260 | /* 2.0 Hardware extension - frequency selection support */ | ||
261 | unsigned char mmw_mode_select; /* for analog tests (set to 0) */ | ||
262 | unsigned char mmw_unused3[1]; /* unused */ | ||
263 | unsigned char mmw_fee_ctrl; /* frequency EEPROM control */ | ||
264 | #define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */ | ||
265 | #define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */ | ||
266 | #define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */ | ||
267 | #define MMW_FEE_CTRL_READ 0x06 /* Read */ | ||
268 | #define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ | ||
269 | #define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */ | ||
270 | #define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */ | ||
271 | #define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ | ||
272 | #define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ | ||
273 | #define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ | ||
274 | #define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */ | ||
275 | #define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */ | ||
276 | #define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ | ||
277 | /* Never issue the PRDS command: it's irreversible! */ | ||
278 | |||
279 | unsigned char mmw_fee_addr; /* EEPROM address */ | ||
280 | #define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */ | ||
281 | #define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ | ||
282 | #define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ | ||
283 | #define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ | ||
284 | #define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ | ||
285 | #define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ | ||
286 | |||
287 | unsigned char mmw_fee_data_l; /* Write data to EEPROM. */ | ||
288 | unsigned char mmw_fee_data_h; /* high octet */ | ||
289 | unsigned char mmw_ext_ant; /* Setting for external antenna */ | ||
290 | #define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ | ||
291 | #define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ | ||
292 | #define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ | ||
293 | #define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ | ||
294 | #define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ | ||
295 | }; | ||
296 | |||
297 | #define MMW_SIZE 37 | ||
298 | |||
299 | #define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) | ||
300 | |||
301 | /* | ||
302 | * Modem Management Controller (MMC) read structure. | ||
303 | */ | ||
304 | typedef struct mmr_t mmr_t; | ||
305 | struct mmr_t | ||
306 | { | ||
307 | unsigned char mmr_unused0[8]; /* unused */ | ||
308 | unsigned char mmr_des_status; /* encryption status */ | ||
309 | unsigned char mmr_des_avail; /* encryption available (0x55 read) */ | ||
310 | #define MMR_DES_AVAIL_DES 0x55 /* DES available */ | ||
311 | #define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ | ||
312 | unsigned char mmr_des_io_invert; /* des I/O invert register */ | ||
313 | unsigned char mmr_unused1[5]; /* unused */ | ||
314 | unsigned char mmr_dce_status; /* DCE status */ | ||
315 | #define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ | ||
316 | #define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ | ||
317 | #define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ | ||
318 | #define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ | ||
319 | #define MMR_DCE_STATUS 0x0F /* mask to get the bits */ | ||
320 | unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ | ||
321 | unsigned char mmr_unused2[2]; /* unused */ | ||
322 | unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ | ||
323 | unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */ | ||
324 | /* Warning: read high-order octet first! */ | ||
325 | unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */ | ||
326 | unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */ | ||
327 | unsigned char mmr_thr_pre_set; /* level threshold preset */ | ||
328 | #define MMR_THR_PRE_SET 0x3F /* level threshold preset */ | ||
329 | #define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ | ||
330 | unsigned char mmr_signal_lvl; /* signal level */ | ||
331 | #define MMR_SIGNAL_LVL 0x3F /* signal level */ | ||
332 | #define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ | ||
333 | unsigned char mmr_silence_lvl; /* silence level (noise) */ | ||
334 | #define MMR_SILENCE_LVL 0x3F /* silence level */ | ||
335 | #define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ | ||
336 | unsigned char mmr_sgnl_qual; /* signal quality */ | ||
337 | #define MMR_SGNL_QUAL 0x0F /* signal quality */ | ||
338 | #define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ | ||
339 | unsigned char mmr_netw_id_l; /* NWID low order byte (?) */ | ||
340 | unsigned char mmr_unused3[3]; /* unused */ | ||
341 | |||
342 | /* 2.0 Hardware extension - frequency selection support */ | ||
343 | unsigned char mmr_fee_status; /* Status of frequency EEPROM */ | ||
344 | #define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */ | ||
345 | #define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ | ||
346 | #define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */ | ||
347 | unsigned char mmr_unused4[1]; /* unused */ | ||
348 | unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */ | ||
349 | unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */ | ||
350 | }; | ||
351 | |||
352 | #define MMR_SIZE 36 | ||
353 | |||
354 | #define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) | ||
355 | |||
356 | /* Make the two above structures one */ | ||
357 | typedef union mm_t | ||
358 | { | ||
359 | struct mmw_t w; /* Write to the mmc */ | ||
360 | struct mmr_t r; /* Read from the mmc */ | ||
361 | } mm_t; | ||
362 | |||
363 | #endif /* _WAVELAN_H */ | ||
364 | |||
365 | /* | ||
366 | * This software may only be used and distributed | ||
367 | * according to the terms of the GNU General Public License. | ||
368 | * | ||
369 | * For more details, see wavelan.c. | ||
370 | */ | ||
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h new file mode 100644 index 000000000000..509ff22a6caa --- /dev/null +++ b/drivers/net/wireless/wavelan.p.h | |||
@@ -0,0 +1,716 @@ | |||
1 | /* | ||
2 | * WaveLAN ISA driver | ||
3 | * | ||
4 | * Jean II - HPLB '96 | ||
5 | * | ||
6 | * Reorganisation and extension of the driver. | ||
7 | * | ||
8 | * This file contains all definitions and declarations necessary for the | ||
9 | * WaveLAN ISA driver. This file is a private header, so it should | ||
10 | * be included only in wavelan.c! | ||
11 | */ | ||
12 | |||
13 | #ifndef WAVELAN_P_H | ||
14 | #define WAVELAN_P_H | ||
15 | |||
16 | /************************** DOCUMENTATION ***************************/ | ||
17 | /* | ||
18 | * This driver provides a Linux interface to the WaveLAN ISA hardware. | ||
19 | * The WaveLAN is a product of Lucent (http://www.wavelan.com/). | ||
20 | * This division was formerly part of NCR and then AT&T. | ||
21 | * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean. | ||
22 | * | ||
23 | * To learn how to use this driver, read the NET3 HOWTO. | ||
24 | * If you want to exploit the many other functionalities, read the comments | ||
25 | * in the code. | ||
26 | * | ||
27 | * This driver is the result of the effort of many people (see below). | ||
28 | */ | ||
29 | |||
30 | /* ------------------------ SPECIFIC NOTES ------------------------ */ | ||
31 | /* | ||
32 | * Web page | ||
33 | * -------- | ||
34 | * I try to maintain a web page with the Wireless LAN Howto at : | ||
35 | * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html | ||
36 | * | ||
37 | * SMP | ||
38 | * --- | ||
39 | * We now are SMP compliant (I eventually fixed the remaining bugs). | ||
40 | * The driver has been tested on a dual P6-150 and survived my usual | ||
41 | * set of torture tests. | ||
42 | * Anyway, I spent enough time chasing interrupt re-entrancy during | ||
43 | * errors or reconfigure, and I designed the locked/unlocked sections | ||
44 | * of the driver with great care, and with the recent addition of | ||
45 | * the spinlock (thanks to the new API), we should be quite close to | ||
46 | * the truth. | ||
47 | * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), | ||
48 | * but better safe than sorry (especially at 2 Mb/s ;-). | ||
49 | * | ||
50 | * I have also looked into disabling only our interrupt on the card | ||
51 | * (via HACR) instead of all interrupts in the processor (via cli), | ||
52 | * so that other driver are not impacted, and it look like it's | ||
53 | * possible, but it's very tricky to do right (full of races). As | ||
54 | * the gain would be mostly for SMP systems, it can wait... | ||
55 | * | ||
56 | * Debugging and options | ||
57 | * --------------------- | ||
58 | * You will find below a set of '#define" allowing a very fine control | ||
59 | * on the driver behaviour and the debug messages printed. | ||
60 | * The main options are : | ||
61 | * o SET_PSA_CRC, to have your card correctly recognised by | ||
62 | * an access point and the Point-to-Point diagnostic tool. | ||
63 | * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) | ||
64 | * (otherwise we always start afresh with some defaults) | ||
65 | * | ||
66 | * wavelan.o is too darned big | ||
67 | * --------------------------- | ||
68 | * That's true! There is a very simple way to reduce the driver | ||
69 | * object by 33%! Comment out the following line: | ||
70 | * #include <linux/wireless.h> | ||
71 | * Other compile options can also reduce the size of it... | ||
72 | * | ||
73 | * MAC address and hardware detection: | ||
74 | * ----------------------------------- | ||
75 | * The detection code for the WaveLAN checks that the first three | ||
76 | * octets of the MAC address fit the company code. This type of | ||
77 | * detection works well for AT&T cards (because the AT&T code is | ||
78 | * hardcoded in wavelan.h), but of course will fail for other | ||
79 | * manufacturers. | ||
80 | * | ||
81 | * If you are sure that your card is derived from the WaveLAN, | ||
82 | * here is the way to configure it: | ||
83 | * 1) Get your MAC address | ||
84 | * a) With your card utilities (wfreqsel, instconf, etc.) | ||
85 | * b) With the driver: | ||
86 | * o compile the kernel with DEBUG_CONFIG_INFO enabled | ||
87 | * o Boot and look the card messages | ||
88 | * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) | ||
89 | * 3) Compile and verify | ||
90 | * 4) Send me the MAC code. I will include it in the next version. | ||
91 | * | ||
92 | */ | ||
93 | |||
94 | /* --------------------- WIRELESS EXTENSIONS --------------------- */ | ||
95 | /* | ||
96 | * This driver is the first to support "wireless extensions". | ||
97 | * This set of extensions provides a standard way to control the wireless | ||
98 | * characteristics of the hardware. Applications such as mobile IP may | ||
99 | * take advantage of it. | ||
100 | * | ||
101 | * You will need to enable the CONFIG_NET_RADIO define in the kernel | ||
102 | * configuration to enable the wireless extensions (this is the one | ||
103 | * giving access to the radio network device choice). | ||
104 | * | ||
105 | * It might also be a good idea as well to fetch the wireless tools to | ||
106 | * configure the device and play a bit. | ||
107 | */ | ||
108 | |||
109 | /* ---------------------------- FILES ---------------------------- */ | ||
110 | /* | ||
111 | * wavelan.c: actual code for the driver: C functions | ||
112 | * | ||
113 | * wavelan.p.h: private header: local types and variables for driver | ||
114 | * | ||
115 | * wavelan.h: description of the hardware interface and structs | ||
116 | * | ||
117 | * i82586.h: description of the Ethernet controller | ||
118 | */ | ||
119 | |||
120 | /* --------------------------- HISTORY --------------------------- */ | ||
121 | /* | ||
122 | * This is based on information in the drivers' headers. It may not be | ||
123 | * accurate, and I guarantee only my best effort. | ||
124 | * | ||
125 | * The history of the WaveLAN drivers is as complicated as the history of | ||
126 | * the WaveLAN itself (NCR -> AT&T -> Lucent). | ||
127 | * | ||
128 | * It all started with Anders Klemets <klemets@paul.rutgers.edu> | ||
129 | * writing a WaveLAN ISA driver for the Mach microkernel. Girish | ||
130 | * Welling <welling@paul.rutgers.edu> had also worked on it. | ||
131 | * Keith Moore modified this for the PCMCIA hardware. | ||
132 | * | ||
133 | * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI | ||
134 | * and added specific PCMCIA support (there is currently no equivalent | ||
135 | * of the PCMCIA package under BSD). | ||
136 | * | ||
137 | * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD. | ||
138 | * | ||
139 | * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux. | ||
140 | * | ||
141 | * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver | ||
142 | * (with help of the BSDI PCMCIA driver) for PCMCIA. | ||
143 | * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work. | ||
144 | * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start | ||
145 | * 2.00 cards correctly (2.4 GHz with frequency selection). | ||
146 | * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his | ||
147 | * PCMCIA package (and bug corrections). | ||
148 | * | ||
149 | * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some | ||
150 | * patches to the PCMCIA driver. Later, I added code in the ISA driver | ||
151 | * for Wireless Extensions and full support of frequency selection | ||
152 | * cards. Then, I did the same to the PCMCIA driver, and did some | ||
153 | * reorganisation. Finally, I came back to the ISA driver to | ||
154 | * upgrade it at the same level as the PCMCIA one and reorganise | ||
155 | * the code. | ||
156 | * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me | ||
157 | * much needed information on the WaveLAN hardware. | ||
158 | */ | ||
159 | |||
160 | /* The original copyrights and literature mention others' names and | ||
161 | * credits. I don't know what their part in this development was. | ||
162 | */ | ||
163 | |||
164 | /* By the way, for the copyright and legal stuff: | ||
165 | * almost everybody wrote code under the GNU or BSD license (or similar), | ||
166 | * and want their original copyright to remain somewhere in the | ||
167 | * code (for myself, I go with the GPL). | ||
168 | * Nobody wants to take responsibility for anything, except the fame. | ||
169 | */ | ||
170 | |||
171 | /* --------------------------- CREDITS --------------------------- */ | ||
172 | /* | ||
173 | * This software was developed as a component of the | ||
174 | * Linux operating system. | ||
175 | * It is based on other device drivers and information | ||
176 | * either written or supplied by: | ||
177 | * Ajay Bakre <bakre@paul.rutgers.edu>, | ||
178 | * Donald Becker <becker@cesdis.gsfc.nasa.gov>, | ||
179 | * Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>, | ||
180 | * Brent Elphick <belphick@uwaterloo.ca>, | ||
181 | * Anders Klemets <klemets@it.kth.se>, | ||
182 | * Vladimir V. Kolpakov <w@stier.koenig.ru>, | ||
183 | * Marc Meertens <Marc.Meertens@Utrecht.NCR.com>, | ||
184 | * Pauline Middelink <middelin@polyware.iaf.nl>, | ||
185 | * Robert Morris <rtm@das.harvard.edu>, | ||
186 | * Jean Tourrilhes <jt@hpl.hp.com>, | ||
187 | * Girish Welling <welling@paul.rutgers.edu>, | ||
188 | * Clark Woodworth <clark@hiway1.exit109.com> | ||
189 | * Yongguang Zhang <ygz@isl.hrl.hac.com> | ||
190 | * | ||
191 | * Thanks go also to: | ||
192 | * James Ashton <jaa101@syseng.anu.edu.au>, | ||
193 | * Alan Cox <alan@redhat.com>, | ||
194 | * Allan Creighton <allanc@cs.usyd.edu.au>, | ||
195 | * Matthew Geier <matthew@cs.usyd.edu.au>, | ||
196 | * Remo di Giovanni <remo@cs.usyd.edu.au>, | ||
197 | * Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>, | ||
198 | * Vipul Gupta <vgupta@cs.binghamton.edu>, | ||
199 | * Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>, | ||
200 | * Tim Nicholson <tim@cs.usyd.edu.au>, | ||
201 | * Ian Parkin <ian@cs.usyd.edu.au>, | ||
202 | * John Rosenberg <johnr@cs.usyd.edu.au>, | ||
203 | * George Rossi <george@phm.gov.au>, | ||
204 | * Arthur Scott <arthur@cs.usyd.edu.au>, | ||
205 | * Stanislav Sinyagin <stas@isf.ru> | ||
206 | * and Peter Storey for their assistance and advice. | ||
207 | * | ||
208 | * Additional Credits: | ||
209 | * | ||
210 | * My development has been done initially under Debian 1.1 (Linux 2.0.x) | ||
211 | * and now under Debian 2.2, initially with an HP Vectra XP/60, and now | ||
212 | * an HP Vectra XP/90. | ||
213 | * | ||
214 | */ | ||
215 | |||
216 | /* ------------------------- IMPROVEMENTS ------------------------- */ | ||
217 | /* | ||
218 | * I proudly present: | ||
219 | * | ||
220 | * Changes made in first pre-release: | ||
221 | * ---------------------------------- | ||
222 | * - reorganisation of the code, function name change | ||
223 | * - creation of private header (wavelan.p.h) | ||
224 | * - reorganised debug messages | ||
225 | * - more comments, history, etc. | ||
226 | * - mmc_init: configure the PSA if not done | ||
227 | * - mmc_init: correct default value of level threshold for PCMCIA | ||
228 | * - mmc_init: 2.00 detection better code for 2.00 initialization | ||
229 | * - better info at startup | ||
230 | * - IRQ setting (note: this setting is permanent) | ||
231 | * - watchdog: change strategy (and solve module removal problems) | ||
232 | * - add wireless extensions (ioctl and get_wireless_stats) | ||
233 | * get/set nwid/frequency on fly, info for /proc/net/wireless | ||
234 | * - more wireless extensions: SETSPY and GETSPY | ||
235 | * - make wireless extensions optional | ||
236 | * - private ioctl to set/get quality and level threshold, histogram | ||
237 | * - remove /proc/net/wavelan | ||
238 | * - suppress useless stuff from lp (net_local) | ||
239 | * - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) | ||
240 | * - add message level (debug stuff in /var/adm/debug and errors not | ||
241 | * displayed at console and still in /var/adm/messages) | ||
242 | * - multi device support | ||
243 | * - start fixing the probe (init code) | ||
244 | * - more inlines | ||
245 | * - man page | ||
246 | * - many other minor details and cleanups | ||
247 | * | ||
248 | * Changes made in second pre-release: | ||
249 | * ----------------------------------- | ||
250 | * - clean up init code (probe and module init) | ||
251 | * - better multiple device support (module) | ||
252 | * - name assignment (module) | ||
253 | * | ||
254 | * Changes made in third pre-release: | ||
255 | * ---------------------------------- | ||
256 | * - be more conservative on timers | ||
257 | * - preliminary support for multicast (I still lack some details) | ||
258 | * | ||
259 | * Changes made in fourth pre-release: | ||
260 | * ----------------------------------- | ||
261 | * - multicast (revisited and finished) | ||
262 | * - avoid reset in set_multicast_list (a really big hack) | ||
263 | * if somebody could apply this code for other i82586 based drivers | ||
264 | * - share onboard memory 75% RU and 25% CU (instead of 50/50) | ||
265 | * | ||
266 | * Changes made for release in 2.1.15: | ||
267 | * ----------------------------------- | ||
268 | * - change the detection code for multi manufacturer code support | ||
269 | * | ||
270 | * Changes made for release in 2.1.17: | ||
271 | * ----------------------------------- | ||
272 | * - update to wireless extensions changes | ||
273 | * - silly bug in card initial configuration (psa_conf_status) | ||
274 | * | ||
275 | * Changes made for release in 2.1.27 & 2.0.30: | ||
276 | * -------------------------------------------- | ||
277 | * - small bug in debug code (probably not the last one...) | ||
278 | * - remove extern keyword for wavelan_probe() | ||
279 | * - level threshold is now a standard wireless extension (version 4 !) | ||
280 | * - modules parameters types (new module interface) | ||
281 | * | ||
282 | * Changes made for release in 2.1.36: | ||
283 | * ----------------------------------- | ||
284 | * - byte count stats (courtesy of David Hinds) | ||
285 | * - remove dev_tint stuff (courtesy of David Hinds) | ||
286 | * - encryption setting from Brent Elphick (thanks a lot!) | ||
287 | * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) | ||
288 | * | ||
289 | * Other changes (not by me) : | ||
290 | * ------------------------- | ||
291 | * - Spelling and gramar "rectification". | ||
292 | * | ||
293 | * Changes made for release in 2.0.37 & 2.2.2 : | ||
294 | * ------------------------------------------ | ||
295 | * - Correct status in /proc/net/wireless | ||
296 | * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) | ||
297 | * - Module init code don't fail if we found at least one card in | ||
298 | * the address list (Karlis Peisenieks) | ||
299 | * - Missing parenthesis (Christopher Peterson) | ||
300 | * - Correct i82586 configuration parameters | ||
301 | * - Encryption initialisation bug (Robert McCormack) | ||
302 | * - New mac addresses detected in the probe | ||
303 | * - Increase watchdog for busy environments | ||
304 | * | ||
305 | * Changes made for release in 2.0.38 & 2.2.7 : | ||
306 | * ------------------------------------------ | ||
307 | * - Correct the reception logic to better report errors and avoid | ||
308 | * sending bogus packet up the stack | ||
309 | * - Delay RU config to avoid corrupting first received packet | ||
310 | * - Change config completion code (to actually check something) | ||
311 | * - Avoid reading out of bound in skbuf to transmit | ||
312 | * - Rectify a lot of (useless) debugging code | ||
313 | * - Change the way to `#ifdef SET_PSA_CRC' | ||
314 | * | ||
315 | * Changes made for release in 2.2.11 & 2.3.13 : | ||
316 | * ------------------------------------------- | ||
317 | * - Change e-mail and web page addresses | ||
318 | * - Watchdog timer is now correctly expressed in HZ, not in jiffies | ||
319 | * - Add channel number to the list of frequencies in range | ||
320 | * - Add the (short) list of bit-rates in range | ||
321 | * - Developp a new sensitivity... (sens.value & sens.fixed) | ||
322 | * | ||
323 | * Changes made for release in 2.2.14 & 2.3.23 : | ||
324 | * ------------------------------------------- | ||
325 | * - Fix check for root permission (break instead of exit) | ||
326 | * - New nwid & encoding setting (Wireless Extension 9) | ||
327 | * | ||
328 | * Changes made for release in 2.3.49 : | ||
329 | * ---------------------------------- | ||
330 | * - Indentation reformating (Alan) | ||
331 | * - Update to new network API (softnet - 2.3.43) : | ||
332 | * o replace dev->tbusy (Alan) | ||
333 | * o replace dev->tstart (Alan) | ||
334 | * o remove dev->interrupt (Alan) | ||
335 | * o add SMP locking via spinlock in splxx (me) | ||
336 | * o add spinlock in interrupt handler (me) | ||
337 | * o use kernel watchdog instead of ours (me) | ||
338 | * o increase watchdog timeout (kernel is more sensitive) (me) | ||
339 | * o verify that all the changes make sense and work (me) | ||
340 | * - Fixup a potential gotcha when reconfiguring and thighten a bit | ||
341 | * the interactions with Tx queue. | ||
342 | * | ||
343 | * Changes made for release in 2.4.0 : | ||
344 | * --------------------------------- | ||
345 | * - Fix spinlock stupid bugs that I left in. The driver is now SMP | ||
346 | * compliant and doesn't lockup at startup. | ||
347 | * | ||
348 | * Changes made for release in 2.5.2 : | ||
349 | * --------------------------------- | ||
350 | * - Use new driver API for Wireless Extensions : | ||
351 | * o got rid of wavelan_ioctl() | ||
352 | * o use a bunch of iw_handler instead | ||
353 | * | ||
354 | * Changes made for release in 2.5.35 : | ||
355 | * ---------------------------------- | ||
356 | * - Set dev->trans_start to avoid filling the logs | ||
357 | * - Handle better spurious/bogus interrupt | ||
358 | * - Avoid deadlocks in mmc_out()/mmc_in() | ||
359 | * | ||
360 | * Wishes & dreams: | ||
361 | * ---------------- | ||
362 | * - roaming (see Pcmcia driver) | ||
363 | */ | ||
364 | |||
365 | /***************************** INCLUDES *****************************/ | ||
366 | |||
367 | #include <linux/module.h> | ||
368 | |||
369 | #include <linux/kernel.h> | ||
370 | #include <linux/sched.h> | ||
371 | #include <linux/types.h> | ||
372 | #include <linux/fcntl.h> | ||
373 | #include <linux/interrupt.h> | ||
374 | #include <linux/stat.h> | ||
375 | #include <linux/ptrace.h> | ||
376 | #include <linux/ioport.h> | ||
377 | #include <linux/in.h> | ||
378 | #include <linux/string.h> | ||
379 | #include <linux/delay.h> | ||
380 | #include <linux/bitops.h> | ||
381 | #include <asm/system.h> | ||
382 | #include <asm/io.h> | ||
383 | #include <asm/dma.h> | ||
384 | #include <asm/uaccess.h> | ||
385 | #include <linux/errno.h> | ||
386 | #include <linux/netdevice.h> | ||
387 | #include <linux/etherdevice.h> | ||
388 | #include <linux/skbuff.h> | ||
389 | #include <linux/slab.h> | ||
390 | #include <linux/timer.h> | ||
391 | #include <linux/init.h> | ||
392 | |||
393 | #include <linux/wireless.h> /* Wireless extensions */ | ||
394 | #include <net/iw_handler.h> /* Wireless handlers */ | ||
395 | |||
396 | /* WaveLAN declarations */ | ||
397 | #include "i82586.h" | ||
398 | #include "wavelan.h" | ||
399 | |||
400 | /************************** DRIVER OPTIONS **************************/ | ||
401 | /* | ||
402 | * `#define' or `#undef' the following constant to change the behaviour | ||
403 | * of the driver... | ||
404 | */ | ||
405 | #undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ | ||
406 | #define USE_PSA_CONFIG /* Use info from the PSA. */ | ||
407 | #undef STRUCT_CHECK /* Verify padding of structures. */ | ||
408 | #undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ | ||
409 | #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ | ||
410 | #undef SET_MAC_ADDRESS /* Experimental */ | ||
411 | |||
412 | #ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ | ||
413 | /* Warning: this stuff will slow down the driver. */ | ||
414 | #define WIRELESS_SPY /* Enable spying addresses. */ | ||
415 | #undef HISTOGRAM /* Enable histogram of signal level. */ | ||
416 | #endif | ||
417 | |||
418 | /****************************** DEBUG ******************************/ | ||
419 | |||
420 | #undef DEBUG_MODULE_TRACE /* module insertion/removal */ | ||
421 | #undef DEBUG_CALLBACK_TRACE /* calls made by Linux */ | ||
422 | #undef DEBUG_INTERRUPT_TRACE /* calls to handler */ | ||
423 | #undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */ | ||
424 | #define DEBUG_INTERRUPT_ERROR /* problems */ | ||
425 | #undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ | ||
426 | #undef DEBUG_CONFIG_INFO /* what's going on */ | ||
427 | #define DEBUG_CONFIG_ERROR /* errors on configuration */ | ||
428 | #undef DEBUG_TX_TRACE /* transmission calls */ | ||
429 | #undef DEBUG_TX_INFO /* header of the transmitted packet */ | ||
430 | #undef DEBUG_TX_FAIL /* Normal failure conditions */ | ||
431 | #define DEBUG_TX_ERROR /* Unexpected conditions */ | ||
432 | #undef DEBUG_RX_TRACE /* transmission calls */ | ||
433 | #undef DEBUG_RX_INFO /* header of the received packet */ | ||
434 | #undef DEBUG_RX_FAIL /* Normal failure conditions */ | ||
435 | #define DEBUG_RX_ERROR /* Unexpected conditions */ | ||
436 | |||
437 | #undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ | ||
438 | #undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ | ||
439 | #undef DEBUG_IOCTL_INFO /* various debugging info */ | ||
440 | #define DEBUG_IOCTL_ERROR /* what's going wrong */ | ||
441 | #define DEBUG_BASIC_SHOW /* Show basic startup info. */ | ||
442 | #undef DEBUG_VERSION_SHOW /* Print version info. */ | ||
443 | #undef DEBUG_PSA_SHOW /* Dump PSA to screen. */ | ||
444 | #undef DEBUG_MMC_SHOW /* Dump mmc to screen. */ | ||
445 | #undef DEBUG_SHOW_UNUSED /* Show unused fields too. */ | ||
446 | #undef DEBUG_I82586_SHOW /* Show i82586 status. */ | ||
447 | #undef DEBUG_DEVICE_SHOW /* Show device parameters. */ | ||
448 | |||
449 | /************************ CONSTANTS & MACROS ************************/ | ||
450 | |||
451 | #ifdef DEBUG_VERSION_SHOW | ||
452 | static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; | ||
453 | #endif | ||
454 | |||
455 | /* Watchdog temporisation */ | ||
456 | #define WATCHDOG_JIFFIES (512*HZ/100) | ||
457 | |||
458 | /* Macro to get the number of elements in an array */ | ||
459 | #define NELS(a) (sizeof(a) / sizeof(a[0])) | ||
460 | |||
461 | /* ------------------------ PRIVATE IOCTL ------------------------ */ | ||
462 | |||
463 | #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ | ||
464 | #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ | ||
465 | |||
466 | #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ | ||
467 | #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ | ||
468 | |||
469 | /****************************** TYPES ******************************/ | ||
470 | |||
471 | /* Shortcuts */ | ||
472 | typedef struct net_device_stats en_stats; | ||
473 | typedef struct iw_statistics iw_stats; | ||
474 | typedef struct iw_quality iw_qual; | ||
475 | typedef struct iw_freq iw_freq; | ||
476 | typedef struct net_local net_local; | ||
477 | typedef struct timer_list timer_list; | ||
478 | |||
479 | /* Basic types */ | ||
480 | typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ | ||
481 | |||
482 | /* | ||
483 | * Static specific data for the interface. | ||
484 | * | ||
485 | * For each network interface, Linux keeps data in two structures: "device" | ||
486 | * keeps the generic data (same format for everybody) and "net_local" keeps | ||
487 | * additional specific data. | ||
488 | * Note that some of this specific data is in fact generic (en_stats, for | ||
489 | * example). | ||
490 | */ | ||
491 | struct net_local | ||
492 | { | ||
493 | net_local * next; /* linked list of the devices */ | ||
494 | struct net_device * dev; /* reverse link */ | ||
495 | spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ | ||
496 | en_stats stats; /* Ethernet interface statistics */ | ||
497 | int nresets; /* number of hardware resets */ | ||
498 | u_char reconfig_82586; /* We need to reconfigure the controller. */ | ||
499 | u_char promiscuous; /* promiscuous mode */ | ||
500 | int mc_count; /* number of multicast addresses */ | ||
501 | u_short hacr; /* current host interface state */ | ||
502 | |||
503 | int tx_n_in_use; | ||
504 | u_short rx_head; | ||
505 | u_short rx_last; | ||
506 | u_short tx_first_free; | ||
507 | u_short tx_first_in_use; | ||
508 | |||
509 | #ifdef WIRELESS_EXT | ||
510 | iw_stats wstats; /* Wireless-specific statistics */ | ||
511 | |||
512 | struct iw_spy_data spy_data; | ||
513 | struct iw_public_data wireless_data; | ||
514 | #endif | ||
515 | |||
516 | #ifdef HISTOGRAM | ||
517 | int his_number; /* number of intervals */ | ||
518 | u_char his_range[16]; /* boundaries of interval ]n-1; n] */ | ||
519 | u_long his_sum[16]; /* sum in interval */ | ||
520 | #endif /* HISTOGRAM */ | ||
521 | }; | ||
522 | |||
523 | /**************************** PROTOTYPES ****************************/ | ||
524 | |||
525 | /* ----------------------- MISC. SUBROUTINES ------------------------ */ | ||
526 | static u_char | ||
527 | wv_irq_to_psa(int); | ||
528 | static int | ||
529 | wv_psa_to_irq(u_char); | ||
530 | /* ------------------- HOST ADAPTER SUBROUTINES ------------------- */ | ||
531 | static inline u_short /* data */ | ||
532 | hasr_read(u_long); /* Read the host interface: base address */ | ||
533 | static inline void | ||
534 | hacr_write(u_long, /* Write to host interface: base address */ | ||
535 | u_short), /* data */ | ||
536 | hacr_write_slow(u_long, | ||
537 | u_short), | ||
538 | set_chan_attn(u_long, /* ioaddr */ | ||
539 | u_short), /* hacr */ | ||
540 | wv_hacr_reset(u_long), /* ioaddr */ | ||
541 | wv_16_off(u_long, /* ioaddr */ | ||
542 | u_short), /* hacr */ | ||
543 | wv_16_on(u_long, /* ioaddr */ | ||
544 | u_short), /* hacr */ | ||
545 | wv_ints_off(struct net_device *), | ||
546 | wv_ints_on(struct net_device *); | ||
547 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | ||
548 | static void | ||
549 | psa_read(u_long, /* Read the Parameter Storage Area. */ | ||
550 | u_short, /* hacr */ | ||
551 | int, /* offset in PSA */ | ||
552 | u_char *, /* buffer to fill */ | ||
553 | int), /* size to read */ | ||
554 | psa_write(u_long, /* Write to the PSA. */ | ||
555 | u_short, /* hacr */ | ||
556 | int, /* offset in PSA */ | ||
557 | u_char *, /* buffer in memory */ | ||
558 | int); /* length of buffer */ | ||
559 | static inline void | ||
560 | mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */ | ||
561 | u_short, | ||
562 | u_char), | ||
563 | mmc_write(u_long, /* Write n bytes to the MMC. */ | ||
564 | u_char, | ||
565 | u_char *, | ||
566 | int); | ||
567 | static inline u_char /* Read 1 byte from the MMC. */ | ||
568 | mmc_in(u_long, | ||
569 | u_short); | ||
570 | static inline void | ||
571 | mmc_read(u_long, /* Read n bytes from the MMC. */ | ||
572 | u_char, | ||
573 | u_char *, | ||
574 | int), | ||
575 | fee_wait(u_long, /* Wait for frequency EEPROM: base address */ | ||
576 | int, /* base delay to wait for */ | ||
577 | int); /* time to wait */ | ||
578 | static void | ||
579 | fee_read(u_long, /* Read the frequency EEPROM: base address */ | ||
580 | u_short, /* destination offset */ | ||
581 | u_short *, /* data buffer */ | ||
582 | int); /* number of registers */ | ||
583 | /* ---------------------- I82586 SUBROUTINES ----------------------- */ | ||
584 | static /*inline*/ void | ||
585 | obram_read(u_long, /* ioaddr */ | ||
586 | u_short, /* o */ | ||
587 | u_char *, /* b */ | ||
588 | int); /* n */ | ||
589 | static inline void | ||
590 | obram_write(u_long, /* ioaddr */ | ||
591 | u_short, /* o */ | ||
592 | u_char *, /* b */ | ||
593 | int); /* n */ | ||
594 | static void | ||
595 | wv_ack(struct net_device *); | ||
596 | static inline int | ||
597 | wv_synchronous_cmd(struct net_device *, | ||
598 | const char *), | ||
599 | wv_config_complete(struct net_device *, | ||
600 | u_long, | ||
601 | net_local *); | ||
602 | static int | ||
603 | wv_complete(struct net_device *, | ||
604 | u_long, | ||
605 | net_local *); | ||
606 | static inline void | ||
607 | wv_82586_reconfig(struct net_device *); | ||
608 | /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ | ||
609 | #ifdef DEBUG_I82586_SHOW | ||
610 | static void | ||
611 | wv_scb_show(unsigned short); | ||
612 | #endif | ||
613 | static inline void | ||
614 | wv_init_info(struct net_device *); /* display startup info */ | ||
615 | /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ | ||
616 | static en_stats * | ||
617 | wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ | ||
618 | static iw_stats * | ||
619 | wavelan_get_wireless_stats(struct net_device *); | ||
620 | static void | ||
621 | wavelan_set_multicast_list(struct net_device *); | ||
622 | /* ----------------------- PACKET RECEPTION ----------------------- */ | ||
623 | static inline void | ||
624 | wv_packet_read(struct net_device *, /* Read a packet from a frame. */ | ||
625 | u_short, | ||
626 | int), | ||
627 | wv_receive(struct net_device *); /* Read all packets waiting. */ | ||
628 | /* --------------------- PACKET TRANSMISSION --------------------- */ | ||
629 | static inline int | ||
630 | wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ | ||
631 | void *, | ||
632 | short); | ||
633 | static int | ||
634 | wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ | ||
635 | struct net_device *); | ||
636 | /* -------------------- HARDWARE CONFIGURATION -------------------- */ | ||
637 | static inline int | ||
638 | wv_mmc_init(struct net_device *), /* Initialize the modem. */ | ||
639 | wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ | ||
640 | wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ | ||
641 | wv_82586_start(struct net_device *); /* Start the i82586. */ | ||
642 | static void | ||
643 | wv_82586_config(struct net_device *); /* Configure the i82586. */ | ||
644 | static inline void | ||
645 | wv_82586_stop(struct net_device *); | ||
646 | static int | ||
647 | wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ | ||
648 | wv_check_ioaddr(u_long, /* ioaddr */ | ||
649 | u_char *); /* mac address (read) */ | ||
650 | /* ---------------------- INTERRUPT HANDLING ---------------------- */ | ||
651 | static irqreturn_t | ||
652 | wavelan_interrupt(int, /* interrupt handler */ | ||
653 | void *, | ||
654 | struct pt_regs *); | ||
655 | static void | ||
656 | wavelan_watchdog(struct net_device *); /* transmission watchdog */ | ||
657 | /* ------------------- CONFIGURATION CALLBACKS ------------------- */ | ||
658 | static int | ||
659 | wavelan_open(struct net_device *), /* Open the device. */ | ||
660 | wavelan_close(struct net_device *), /* Close the device. */ | ||
661 | wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ | ||
662 | extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ | ||
663 | |||
664 | /**************************** VARIABLES ****************************/ | ||
665 | |||
666 | /* | ||
667 | * This is the root of the linked list of WaveLAN drivers | ||
668 | * It is use to verify that we don't reuse the same base address | ||
669 | * for two different drivers and to clean up when removing the module. | ||
670 | */ | ||
671 | static net_local * wavelan_list = (net_local *) NULL; | ||
672 | |||
673 | /* | ||
674 | * This table is used to translate the PSA value to IRQ number | ||
675 | * and vice versa. | ||
676 | */ | ||
677 | static u_char irqvals[] = | ||
678 | { | ||
679 | 0, 0, 0, 0x01, | ||
680 | 0x02, 0x04, 0, 0x08, | ||
681 | 0, 0, 0x10, 0x20, | ||
682 | 0x40, 0, 0, 0x80, | ||
683 | }; | ||
684 | |||
685 | /* | ||
686 | * Table of the available I/O addresses (base addresses) for WaveLAN | ||
687 | */ | ||
688 | static unsigned short iobase[] = | ||
689 | { | ||
690 | #if 0 | ||
691 | /* Leave out 0x3C0 for now -- seems to clash with some video | ||
692 | * controllers. | ||
693 | * Leave out the others too -- we will always use 0x390 and leave | ||
694 | * 0x300 for the Ethernet device. | ||
695 | * Jean II: 0x3E0 is fine as well. | ||
696 | */ | ||
697 | 0x300, 0x390, 0x3E0, 0x3C0 | ||
698 | #endif /* 0 */ | ||
699 | 0x390, 0x3E0 | ||
700 | }; | ||
701 | |||
702 | #ifdef MODULE | ||
703 | /* Parameters set by insmod */ | ||
704 | static int io[4]; | ||
705 | static int irq[4]; | ||
706 | static char *name[4]; | ||
707 | module_param_array(io, int, NULL, 0); | ||
708 | module_param_array(irq, int, NULL, 0); | ||
709 | module_param_array(name, charp, NULL, 0); | ||
710 | |||
711 | MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required"); | ||
712 | MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)"); | ||
713 | MODULE_PARM_DESC(name, "WaveLAN interface neme(s)"); | ||
714 | #endif /* MODULE */ | ||
715 | |||
716 | #endif /* WAVELAN_P_H */ | ||
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c new file mode 100644 index 000000000000..ec8329788e49 --- /dev/null +++ b/drivers/net/wireless/wavelan_cs.c | |||
@@ -0,0 +1,4914 @@ | |||
1 | /* | ||
2 | * Wavelan Pcmcia driver | ||
3 | * | ||
4 | * Jean II - HPLB '96 | ||
5 | * | ||
6 | * Reorganisation and extension of the driver. | ||
7 | * Original copyright follow. See wavelan_cs.p.h for details. | ||
8 | * | ||
9 | * This code is derived from Anthony D. Joseph's code and all the changes here | ||
10 | * are also under the original copyright below. | ||
11 | * | ||
12 | * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and | ||
13 | * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services | ||
14 | * | ||
15 | * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added | ||
16 | * critical code in the routine to initialize the Modem Management Controller. | ||
17 | * | ||
18 | * Thanks to Alan Cox and Bruce Janson for their advice. | ||
19 | * | ||
20 | * -- Yunzhou Li (scip4166@nus.sg) | ||
21 | * | ||
22 | #ifdef WAVELAN_ROAMING | ||
23 | * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) | ||
24 | * based on patch by Joe Finney from Lancaster University. | ||
25 | #endif | ||
26 | * | ||
27 | * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An | ||
28 | * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. | ||
29 | * | ||
30 | * A non-shared memory PCMCIA ethernet driver for linux | ||
31 | * | ||
32 | * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) | ||
33 | * | ||
34 | * | ||
35 | * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) | ||
36 | * | ||
37 | * Apr 2 '98 made changes to bring the i82593 control/int handling in line | ||
38 | * with offical specs... | ||
39 | * | ||
40 | **************************************************************************** | ||
41 | * Copyright 1995 | ||
42 | * Anthony D. Joseph | ||
43 | * Massachusetts Institute of Technology | ||
44 | * | ||
45 | * Permission to use, copy, modify, and distribute this program | ||
46 | * for any purpose and without fee is hereby granted, provided | ||
47 | * that this copyright and permission notice appear on all copies | ||
48 | * and supporting documentation, the name of M.I.T. not be used | ||
49 | * in advertising or publicity pertaining to distribution of the | ||
50 | * program without specific prior permission, and notice be given | ||
51 | * in supporting documentation that copying and distribution is | ||
52 | * by permission of M.I.T. M.I.T. makes no representations about | ||
53 | * the suitability of this software for any purpose. It is pro- | ||
54 | * vided "as is" without express or implied warranty. | ||
55 | **************************************************************************** | ||
56 | * | ||
57 | */ | ||
58 | |||
59 | /* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ | ||
60 | #include "wavelan_cs.p.h" /* Private header */ | ||
61 | |||
62 | /************************* MISC SUBROUTINES **************************/ | ||
63 | /* | ||
64 | * Subroutines which won't fit in one of the following category | ||
65 | * (wavelan modem or i82593) | ||
66 | */ | ||
67 | |||
68 | #ifdef STRUCT_CHECK | ||
69 | /*------------------------------------------------------------------*/ | ||
70 | /* | ||
71 | * Sanity routine to verify the sizes of the various WaveLAN interface | ||
72 | * structures. | ||
73 | */ | ||
74 | static char * | ||
75 | wv_structuct_check(void) | ||
76 | { | ||
77 | #define SC(t,s,n) if (sizeof(t) != s) return(n); | ||
78 | |||
79 | SC(psa_t, PSA_SIZE, "psa_t"); | ||
80 | SC(mmw_t, MMW_SIZE, "mmw_t"); | ||
81 | SC(mmr_t, MMR_SIZE, "mmr_t"); | ||
82 | |||
83 | #undef SC | ||
84 | |||
85 | return((char *) NULL); | ||
86 | } /* wv_structuct_check */ | ||
87 | #endif /* STRUCT_CHECK */ | ||
88 | |||
89 | /******************* MODEM MANAGEMENT SUBROUTINES *******************/ | ||
90 | /* | ||
91 | * Useful subroutines to manage the modem of the wavelan | ||
92 | */ | ||
93 | |||
94 | /*------------------------------------------------------------------*/ | ||
95 | /* | ||
96 | * Read from card's Host Adaptor Status Register. | ||
97 | */ | ||
98 | static inline u_char | ||
99 | hasr_read(u_long base) | ||
100 | { | ||
101 | return(inb(HASR(base))); | ||
102 | } /* hasr_read */ | ||
103 | |||
104 | /*------------------------------------------------------------------*/ | ||
105 | /* | ||
106 | * Write to card's Host Adapter Command Register. | ||
107 | */ | ||
108 | static inline void | ||
109 | hacr_write(u_long base, | ||
110 | u_char hacr) | ||
111 | { | ||
112 | outb(hacr, HACR(base)); | ||
113 | } /* hacr_write */ | ||
114 | |||
115 | /*------------------------------------------------------------------*/ | ||
116 | /* | ||
117 | * Write to card's Host Adapter Command Register. Include a delay for | ||
118 | * those times when it is needed. | ||
119 | */ | ||
120 | static inline void | ||
121 | hacr_write_slow(u_long base, | ||
122 | u_char hacr) | ||
123 | { | ||
124 | hacr_write(base, hacr); | ||
125 | /* delay might only be needed sometimes */ | ||
126 | mdelay(1); | ||
127 | } /* hacr_write_slow */ | ||
128 | |||
129 | /*------------------------------------------------------------------*/ | ||
130 | /* | ||
131 | * Read the Parameter Storage Area from the WaveLAN card's memory | ||
132 | */ | ||
133 | static void | ||
134 | psa_read(struct net_device * dev, | ||
135 | int o, /* offset in PSA */ | ||
136 | u_char * b, /* buffer to fill */ | ||
137 | int n) /* size to read */ | ||
138 | { | ||
139 | net_local *lp = netdev_priv(dev); | ||
140 | u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); | ||
141 | |||
142 | while(n-- > 0) | ||
143 | { | ||
144 | *b++ = readb(ptr); | ||
145 | /* Due to a lack of address decode pins, the WaveLAN PCMCIA card | ||
146 | * only supports reading even memory addresses. That means the | ||
147 | * increment here MUST be two. | ||
148 | * Because of that, we can't use memcpy_fromio()... | ||
149 | */ | ||
150 | ptr += 2; | ||
151 | } | ||
152 | } /* psa_read */ | ||
153 | |||
154 | /*------------------------------------------------------------------*/ | ||
155 | /* | ||
156 | * Write the Paramter Storage Area to the WaveLAN card's memory | ||
157 | */ | ||
158 | static void | ||
159 | psa_write(struct net_device * dev, | ||
160 | int o, /* Offset in psa */ | ||
161 | u_char * b, /* Buffer in memory */ | ||
162 | int n) /* Length of buffer */ | ||
163 | { | ||
164 | net_local *lp = netdev_priv(dev); | ||
165 | u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); | ||
166 | int count = 0; | ||
167 | kio_addr_t base = dev->base_addr; | ||
168 | /* As there seem to have no flag PSA_BUSY as in the ISA model, we are | ||
169 | * oblige to verify this address to know when the PSA is ready... */ | ||
170 | volatile u_char __iomem *verify = lp->mem + PSA_ADDR + | ||
171 | (psaoff(0, psa_comp_number) << 1); | ||
172 | |||
173 | /* Authorize writting to PSA */ | ||
174 | hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); | ||
175 | |||
176 | while(n-- > 0) | ||
177 | { | ||
178 | /* write to PSA */ | ||
179 | writeb(*b++, ptr); | ||
180 | ptr += 2; | ||
181 | |||
182 | /* I don't have the spec, so I don't know what the correct | ||
183 | * sequence to write is. This hack seem to work for me... */ | ||
184 | count = 0; | ||
185 | while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) | ||
186 | mdelay(1); | ||
187 | } | ||
188 | |||
189 | /* Put the host interface back in standard state */ | ||
190 | hacr_write(base, HACR_DEFAULT); | ||
191 | } /* psa_write */ | ||
192 | |||
193 | #ifdef SET_PSA_CRC | ||
194 | /*------------------------------------------------------------------*/ | ||
195 | /* | ||
196 | * Calculate the PSA CRC | ||
197 | * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code | ||
198 | * NOTE: By specifying a length including the CRC position the | ||
199 | * returned value should be zero. (i.e. a correct checksum in the PSA) | ||
200 | * | ||
201 | * The Windows drivers don't use the CRC, but the AP and the PtP tool | ||
202 | * depend on it. | ||
203 | */ | ||
204 | static u_short | ||
205 | psa_crc(unsigned char * psa, /* The PSA */ | ||
206 | int size) /* Number of short for CRC */ | ||
207 | { | ||
208 | int byte_cnt; /* Loop on the PSA */ | ||
209 | u_short crc_bytes = 0; /* Data in the PSA */ | ||
210 | int bit_cnt; /* Loop on the bits of the short */ | ||
211 | |||
212 | for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) | ||
213 | { | ||
214 | crc_bytes ^= psa[byte_cnt]; /* Its an xor */ | ||
215 | |||
216 | for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) | ||
217 | { | ||
218 | if(crc_bytes & 0x0001) | ||
219 | crc_bytes = (crc_bytes >> 1) ^ 0xA001; | ||
220 | else | ||
221 | crc_bytes >>= 1 ; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return crc_bytes; | ||
226 | } /* psa_crc */ | ||
227 | #endif /* SET_PSA_CRC */ | ||
228 | |||
229 | /*------------------------------------------------------------------*/ | ||
230 | /* | ||
231 | * update the checksum field in the Wavelan's PSA | ||
232 | */ | ||
233 | static void | ||
234 | update_psa_checksum(struct net_device * dev) | ||
235 | { | ||
236 | #ifdef SET_PSA_CRC | ||
237 | psa_t psa; | ||
238 | u_short crc; | ||
239 | |||
240 | /* read the parameter storage area */ | ||
241 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
242 | |||
243 | /* update the checksum */ | ||
244 | crc = psa_crc((unsigned char *) &psa, | ||
245 | sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) | ||
246 | - sizeof(psa.psa_crc_status)); | ||
247 | |||
248 | psa.psa_crc[0] = crc & 0xFF; | ||
249 | psa.psa_crc[1] = (crc & 0xFF00) >> 8; | ||
250 | |||
251 | /* Write it ! */ | ||
252 | psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, | ||
253 | (unsigned char *)&psa.psa_crc, 2); | ||
254 | |||
255 | #ifdef DEBUG_IOCTL_INFO | ||
256 | printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", | ||
257 | dev->name, psa.psa_crc[0], psa.psa_crc[1]); | ||
258 | |||
259 | /* Check again (luxury !) */ | ||
260 | crc = psa_crc((unsigned char *) &psa, | ||
261 | sizeof(psa) - sizeof(psa.psa_crc_status)); | ||
262 | |||
263 | if(crc != 0) | ||
264 | printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); | ||
265 | #endif /* DEBUG_IOCTL_INFO */ | ||
266 | #endif /* SET_PSA_CRC */ | ||
267 | } /* update_psa_checksum */ | ||
268 | |||
269 | /*------------------------------------------------------------------*/ | ||
270 | /* | ||
271 | * Write 1 byte to the MMC. | ||
272 | */ | ||
273 | static inline void | ||
274 | mmc_out(u_long base, | ||
275 | u_short o, | ||
276 | u_char d) | ||
277 | { | ||
278 | int count = 0; | ||
279 | |||
280 | /* Wait for MMC to go idle */ | ||
281 | while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) | ||
282 | udelay(10); | ||
283 | |||
284 | outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); | ||
285 | outb(d, MMD(base)); | ||
286 | } | ||
287 | |||
288 | /*------------------------------------------------------------------*/ | ||
289 | /* | ||
290 | * Routine to write bytes to the Modem Management Controller. | ||
291 | * We start by the end because it is the way it should be ! | ||
292 | */ | ||
293 | static inline void | ||
294 | mmc_write(u_long base, | ||
295 | u_char o, | ||
296 | u_char * b, | ||
297 | int n) | ||
298 | { | ||
299 | o += n; | ||
300 | b += n; | ||
301 | |||
302 | while(n-- > 0 ) | ||
303 | mmc_out(base, --o, *(--b)); | ||
304 | } /* mmc_write */ | ||
305 | |||
306 | /*------------------------------------------------------------------*/ | ||
307 | /* | ||
308 | * Read 1 byte from the MMC. | ||
309 | * Optimised version for 1 byte, avoid using memory... | ||
310 | */ | ||
311 | static inline u_char | ||
312 | mmc_in(u_long base, | ||
313 | u_short o) | ||
314 | { | ||
315 | int count = 0; | ||
316 | |||
317 | while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) | ||
318 | udelay(10); | ||
319 | outb(o << 1, MMR(base)); /* Set the read address */ | ||
320 | |||
321 | outb(0, MMD(base)); /* Required dummy write */ | ||
322 | |||
323 | while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) | ||
324 | udelay(10); | ||
325 | return (u_char) (inb(MMD(base))); /* Now do the actual read */ | ||
326 | } | ||
327 | |||
328 | /*------------------------------------------------------------------*/ | ||
329 | /* | ||
330 | * Routine to read bytes from the Modem Management Controller. | ||
331 | * The implementation is complicated by a lack of address lines, | ||
332 | * which prevents decoding of the low-order bit. | ||
333 | * (code has just been moved in the above function) | ||
334 | * We start by the end because it is the way it should be ! | ||
335 | */ | ||
336 | static inline void | ||
337 | mmc_read(u_long base, | ||
338 | u_char o, | ||
339 | u_char * b, | ||
340 | int n) | ||
341 | { | ||
342 | o += n; | ||
343 | b += n; | ||
344 | |||
345 | while(n-- > 0) | ||
346 | *(--b) = mmc_in(base, --o); | ||
347 | } /* mmc_read */ | ||
348 | |||
349 | /*------------------------------------------------------------------*/ | ||
350 | /* | ||
351 | * Get the type of encryption available... | ||
352 | */ | ||
353 | static inline int | ||
354 | mmc_encr(u_long base) /* i/o port of the card */ | ||
355 | { | ||
356 | int temp; | ||
357 | |||
358 | temp = mmc_in(base, mmroff(0, mmr_des_avail)); | ||
359 | if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) | ||
360 | return 0; | ||
361 | else | ||
362 | return temp; | ||
363 | } | ||
364 | |||
365 | /*------------------------------------------------------------------*/ | ||
366 | /* | ||
367 | * Wait for the frequency EEprom to complete a command... | ||
368 | * I hope this one will be optimally inlined... | ||
369 | */ | ||
370 | static inline void | ||
371 | fee_wait(u_long base, /* i/o port of the card */ | ||
372 | int delay, /* Base delay to wait for */ | ||
373 | int number) /* Number of time to wait */ | ||
374 | { | ||
375 | int count = 0; /* Wait only a limited time */ | ||
376 | |||
377 | while((count++ < number) && | ||
378 | (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) | ||
379 | udelay(delay); | ||
380 | } | ||
381 | |||
382 | /*------------------------------------------------------------------*/ | ||
383 | /* | ||
384 | * Read bytes from the Frequency EEprom (frequency select cards). | ||
385 | */ | ||
386 | static void | ||
387 | fee_read(u_long base, /* i/o port of the card */ | ||
388 | u_short o, /* destination offset */ | ||
389 | u_short * b, /* data buffer */ | ||
390 | int n) /* number of registers */ | ||
391 | { | ||
392 | b += n; /* Position at the end of the area */ | ||
393 | |||
394 | /* Write the address */ | ||
395 | mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
396 | |||
397 | /* Loop on all buffer */ | ||
398 | while(n-- > 0) | ||
399 | { | ||
400 | /* Write the read command */ | ||
401 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); | ||
402 | |||
403 | /* Wait until EEprom is ready (should be quick !) */ | ||
404 | fee_wait(base, 10, 100); | ||
405 | |||
406 | /* Read the value */ | ||
407 | *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | | ||
408 | mmc_in(base, mmroff(0, mmr_fee_data_l))); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ | ||
413 | |||
414 | /*------------------------------------------------------------------*/ | ||
415 | /* | ||
416 | * Write bytes from the Frequency EEprom (frequency select cards). | ||
417 | * This is a bit complicated, because the frequency eeprom has to | ||
418 | * be unprotected and the write enabled. | ||
419 | * Jean II | ||
420 | */ | ||
421 | static void | ||
422 | fee_write(u_long base, /* i/o port of the card */ | ||
423 | u_short o, /* destination offset */ | ||
424 | u_short * b, /* data buffer */ | ||
425 | int n) /* number of registers */ | ||
426 | { | ||
427 | b += n; /* Position at the end of the area */ | ||
428 | |||
429 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
430 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
431 | /* Ask to read the protected register */ | ||
432 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); | ||
433 | |||
434 | fee_wait(base, 10, 100); | ||
435 | |||
436 | /* Read the protected register */ | ||
437 | printk("Protected 2 : %02X-%02X\n", | ||
438 | mmc_in(base, mmroff(0, mmr_fee_data_h)), | ||
439 | mmc_in(base, mmroff(0, mmr_fee_data_l))); | ||
440 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
441 | |||
442 | /* Enable protected register */ | ||
443 | mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
444 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); | ||
445 | |||
446 | fee_wait(base, 10, 100); | ||
447 | |||
448 | /* Unprotect area */ | ||
449 | mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); | ||
450 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
451 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
452 | /* Or use : */ | ||
453 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); | ||
454 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
455 | |||
456 | fee_wait(base, 10, 100); | ||
457 | #endif /* EEPROM_IS_PROTECTED */ | ||
458 | |||
459 | /* Write enable */ | ||
460 | mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
461 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); | ||
462 | |||
463 | fee_wait(base, 10, 100); | ||
464 | |||
465 | /* Write the EEprom address */ | ||
466 | mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
467 | |||
468 | /* Loop on all buffer */ | ||
469 | while(n-- > 0) | ||
470 | { | ||
471 | /* Write the value */ | ||
472 | mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); | ||
473 | mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); | ||
474 | |||
475 | /* Write the write command */ | ||
476 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); | ||
477 | |||
478 | /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ | ||
479 | mdelay(10); | ||
480 | fee_wait(base, 10, 100); | ||
481 | } | ||
482 | |||
483 | /* Write disable */ | ||
484 | mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); | ||
485 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); | ||
486 | |||
487 | fee_wait(base, 10, 100); | ||
488 | |||
489 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
490 | /* Reprotect EEprom */ | ||
491 | mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); | ||
492 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
493 | |||
494 | fee_wait(base, 10, 100); | ||
495 | #endif /* EEPROM_IS_PROTECTED */ | ||
496 | } | ||
497 | #endif /* WIRELESS_EXT */ | ||
498 | |||
499 | /******************* WaveLAN Roaming routines... ********************/ | ||
500 | |||
501 | #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ | ||
502 | |||
503 | unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00}; | ||
504 | |||
505 | void wv_roam_init(struct net_device *dev) | ||
506 | { | ||
507 | net_local *lp= netdev_priv(dev); | ||
508 | |||
509 | /* Do not remove this unless you have a good reason */ | ||
510 | printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" | ||
511 | " device %s !\n", dev->name, dev->name); | ||
512 | printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" | ||
513 | " of the Wavelan driver.\n"); | ||
514 | printk(KERN_NOTICE "It may work, but may also make the driver behave in" | ||
515 | " erratic ways or crash.\n"); | ||
516 | |||
517 | lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ | ||
518 | lp->wavepoint_table.num_wavepoints=0; | ||
519 | lp->wavepoint_table.locked=0; | ||
520 | lp->curr_point=NULL; /* No default WavePoint */ | ||
521 | lp->cell_search=0; | ||
522 | |||
523 | lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ | ||
524 | lp->cell_timer.function=wl_cell_expiry; | ||
525 | lp->cell_timer.expires=jiffies+CELL_TIMEOUT; | ||
526 | add_timer(&lp->cell_timer); | ||
527 | |||
528 | wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ | ||
529 | /* to build up a good WavePoint */ | ||
530 | /* table... */ | ||
531 | printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); | ||
532 | } | ||
533 | |||
534 | void wv_roam_cleanup(struct net_device *dev) | ||
535 | { | ||
536 | wavepoint_history *ptr,*old_ptr; | ||
537 | net_local *lp= netdev_priv(dev); | ||
538 | |||
539 | printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); | ||
540 | |||
541 | /* Fixme : maybe we should check that the timer exist before deleting it */ | ||
542 | del_timer(&lp->cell_timer); /* Remove cell expiry timer */ | ||
543 | ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ | ||
544 | while(ptr!=NULL) | ||
545 | { | ||
546 | old_ptr=ptr; | ||
547 | ptr=ptr->next; | ||
548 | wl_del_wavepoint(old_ptr,lp); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* Enable/Disable NWID promiscuous mode on a given device */ | ||
553 | void wv_nwid_filter(unsigned char mode, net_local *lp) | ||
554 | { | ||
555 | mm_t m; | ||
556 | unsigned long flags; | ||
557 | |||
558 | #ifdef WAVELAN_ROAMING_DEBUG | ||
559 | printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); | ||
560 | #endif | ||
561 | |||
562 | /* Disable interrupts & save flags */ | ||
563 | spin_lock_irqsave(&lp->spinlock, flags); | ||
564 | |||
565 | m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; | ||
566 | mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); | ||
567 | |||
568 | if(mode==NWID_PROMISC) | ||
569 | lp->cell_search=1; | ||
570 | else | ||
571 | lp->cell_search=0; | ||
572 | |||
573 | /* ReEnable interrupts & restore flags */ | ||
574 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
575 | } | ||
576 | |||
577 | /* Find a record in the WavePoint table matching a given NWID */ | ||
578 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) | ||
579 | { | ||
580 | wavepoint_history *ptr=lp->wavepoint_table.head; | ||
581 | |||
582 | while(ptr!=NULL){ | ||
583 | if(ptr->nwid==nwid) | ||
584 | return ptr; | ||
585 | ptr=ptr->next; | ||
586 | } | ||
587 | return NULL; | ||
588 | } | ||
589 | |||
590 | /* Create a new wavepoint table entry */ | ||
591 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) | ||
592 | { | ||
593 | wavepoint_history *new_wavepoint; | ||
594 | |||
595 | #ifdef WAVELAN_ROAMING_DEBUG | ||
596 | printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); | ||
597 | #endif | ||
598 | |||
599 | if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) | ||
600 | return NULL; | ||
601 | |||
602 | new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); | ||
603 | if(new_wavepoint==NULL) | ||
604 | return NULL; | ||
605 | |||
606 | new_wavepoint->nwid=nwid; /* New WavePoints NWID */ | ||
607 | new_wavepoint->average_fast=0; /* Running Averages..*/ | ||
608 | new_wavepoint->average_slow=0; | ||
609 | new_wavepoint->qualptr=0; /* Start of ringbuffer */ | ||
610 | new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ | ||
611 | memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ | ||
612 | |||
613 | new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ | ||
614 | new_wavepoint->prev=NULL; | ||
615 | |||
616 | if(lp->wavepoint_table.head!=NULL) | ||
617 | lp->wavepoint_table.head->prev=new_wavepoint; | ||
618 | |||
619 | lp->wavepoint_table.head=new_wavepoint; | ||
620 | |||
621 | lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ | ||
622 | |||
623 | return new_wavepoint; | ||
624 | } | ||
625 | |||
626 | /* Remove a wavepoint entry from WavePoint table */ | ||
627 | void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) | ||
628 | { | ||
629 | if(wavepoint==NULL) | ||
630 | return; | ||
631 | |||
632 | if(lp->curr_point==wavepoint) | ||
633 | lp->curr_point=NULL; | ||
634 | |||
635 | if(wavepoint->prev!=NULL) | ||
636 | wavepoint->prev->next=wavepoint->next; | ||
637 | |||
638 | if(wavepoint->next!=NULL) | ||
639 | wavepoint->next->prev=wavepoint->prev; | ||
640 | |||
641 | if(lp->wavepoint_table.head==wavepoint) | ||
642 | lp->wavepoint_table.head=wavepoint->next; | ||
643 | |||
644 | lp->wavepoint_table.num_wavepoints--; | ||
645 | kfree(wavepoint); | ||
646 | } | ||
647 | |||
648 | /* Timer callback function - checks WavePoint table for stale entries */ | ||
649 | void wl_cell_expiry(unsigned long data) | ||
650 | { | ||
651 | net_local *lp=(net_local *)data; | ||
652 | wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; | ||
653 | |||
654 | #if WAVELAN_ROAMING_DEBUG > 1 | ||
655 | printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); | ||
656 | #endif | ||
657 | |||
658 | if(lp->wavepoint_table.locked) | ||
659 | { | ||
660 | #if WAVELAN_ROAMING_DEBUG > 1 | ||
661 | printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); | ||
662 | #endif | ||
663 | |||
664 | lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ | ||
665 | add_timer(&lp->cell_timer); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | while(wavepoint!=NULL) | ||
670 | { | ||
671 | if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT)) | ||
672 | { | ||
673 | #ifdef WAVELAN_ROAMING_DEBUG | ||
674 | printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); | ||
675 | #endif | ||
676 | |||
677 | old_point=wavepoint; | ||
678 | wavepoint=wavepoint->next; | ||
679 | wl_del_wavepoint(old_point,lp); | ||
680 | } | ||
681 | else | ||
682 | wavepoint=wavepoint->next; | ||
683 | } | ||
684 | lp->cell_timer.expires=jiffies+CELL_TIMEOUT; | ||
685 | add_timer(&lp->cell_timer); | ||
686 | } | ||
687 | |||
688 | /* Update SNR history of a wavepoint */ | ||
689 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) | ||
690 | { | ||
691 | int i=0,num_missed=0,ptr=0; | ||
692 | int average_fast=0,average_slow=0; | ||
693 | |||
694 | num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed | ||
695 | any beacons? */ | ||
696 | if(num_missed) | ||
697 | for(i=0;i<num_missed;i++) | ||
698 | { | ||
699 | wavepoint->sigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ | ||
700 | wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ | ||
701 | } | ||
702 | wavepoint->last_seen=jiffies; /* Add beacon to history */ | ||
703 | wavepoint->last_seq=seq; | ||
704 | wavepoint->sigqual[wavepoint->qualptr++]=sigqual; | ||
705 | wavepoint->qualptr %=WAVEPOINT_HISTORY; | ||
706 | ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; | ||
707 | |||
708 | for(i=0;i<WAVEPOINT_FAST_HISTORY;i++) /* Update running averages */ | ||
709 | { | ||
710 | average_fast+=wavepoint->sigqual[ptr++]; | ||
711 | ptr %=WAVEPOINT_HISTORY; | ||
712 | } | ||
713 | |||
714 | average_slow=average_fast; | ||
715 | for(i=WAVEPOINT_FAST_HISTORY;i<WAVEPOINT_HISTORY;i++) | ||
716 | { | ||
717 | average_slow+=wavepoint->sigqual[ptr++]; | ||
718 | ptr %=WAVEPOINT_HISTORY; | ||
719 | } | ||
720 | |||
721 | wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; | ||
722 | wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; | ||
723 | } | ||
724 | |||
725 | /* Perform a handover to a new WavePoint */ | ||
726 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) | ||
727 | { | ||
728 | kio_addr_t base = lp->dev->base_addr; | ||
729 | mm_t m; | ||
730 | unsigned long flags; | ||
731 | |||
732 | if(wavepoint==lp->curr_point) /* Sanity check... */ | ||
733 | { | ||
734 | wv_nwid_filter(!NWID_PROMISC,lp); | ||
735 | return; | ||
736 | } | ||
737 | |||
738 | #ifdef WAVELAN_ROAMING_DEBUG | ||
739 | printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); | ||
740 | #endif | ||
741 | |||
742 | /* Disable interrupts & save flags */ | ||
743 | spin_lock_irqsave(&lp->spinlock, flags); | ||
744 | |||
745 | m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; | ||
746 | m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; | ||
747 | |||
748 | mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); | ||
749 | |||
750 | /* ReEnable interrupts & restore flags */ | ||
751 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
752 | |||
753 | wv_nwid_filter(!NWID_PROMISC,lp); | ||
754 | lp->curr_point=wavepoint; | ||
755 | } | ||
756 | |||
757 | /* Called when a WavePoint beacon is received */ | ||
758 | static inline void wl_roam_gather(struct net_device * dev, | ||
759 | u_char * hdr, /* Beacon header */ | ||
760 | u_char * stats) /* SNR, Signal quality | ||
761 | of packet */ | ||
762 | { | ||
763 | wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ | ||
764 | unsigned short nwid=ntohs(beacon->nwid); | ||
765 | unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ | ||
766 | wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ | ||
767 | net_local *lp = netdev_priv(dev); /* Device info */ | ||
768 | |||
769 | #ifdef I_NEED_THIS_FEATURE | ||
770 | /* Some people don't need this, some other may need it */ | ||
771 | nwid=nwid^ntohs(beacon->domain_id); | ||
772 | #endif | ||
773 | |||
774 | #if WAVELAN_ROAMING_DEBUG > 1 | ||
775 | printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); | ||
776 | printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); | ||
777 | #endif | ||
778 | |||
779 | lp->wavepoint_table.locked=1; /* <Mutex> */ | ||
780 | |||
781 | wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ | ||
782 | if(wavepoint==NULL) /* If no entry, Create a new one... */ | ||
783 | { | ||
784 | wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); | ||
785 | if(wavepoint==NULL) | ||
786 | goto out; | ||
787 | } | ||
788 | if(lp->curr_point==NULL) /* If this is the only WavePoint, */ | ||
789 | wv_roam_handover(wavepoint, lp); /* Jump on it! */ | ||
790 | |||
791 | wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history | ||
792 | stats. */ | ||
793 | |||
794 | if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ | ||
795 | if(!lp->cell_search) /* WavePoint is getting faint, */ | ||
796 | wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ | ||
797 | |||
798 | if(wavepoint->average_slow > | ||
799 | lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) | ||
800 | wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ | ||
801 | |||
802 | if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ | ||
803 | if(lp->cell_search) /* getting better, drop out of cell search mode */ | ||
804 | wv_nwid_filter(!NWID_PROMISC,lp); | ||
805 | |||
806 | out: | ||
807 | lp->wavepoint_table.locked=0; /* </MUTEX> :-) */ | ||
808 | } | ||
809 | |||
810 | /* Test this MAC frame a WavePoint beacon */ | ||
811 | static inline int WAVELAN_BEACON(unsigned char *data) | ||
812 | { | ||
813 | wavepoint_beacon *beacon= (wavepoint_beacon *)data; | ||
814 | static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; | ||
815 | |||
816 | if(memcmp(beacon,&beacon_template,9)==0) | ||
817 | return 1; | ||
818 | else | ||
819 | return 0; | ||
820 | } | ||
821 | #endif /* WAVELAN_ROAMING */ | ||
822 | |||
823 | /************************ I82593 SUBROUTINES *************************/ | ||
824 | /* | ||
825 | * Useful subroutines to manage the Ethernet controller | ||
826 | */ | ||
827 | |||
828 | /*------------------------------------------------------------------*/ | ||
829 | /* | ||
830 | * Routine to synchronously send a command to the i82593 chip. | ||
831 | * Should be called with interrupts disabled. | ||
832 | * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), | ||
833 | * wv_82593_config() & wv_diag()) | ||
834 | */ | ||
835 | static int | ||
836 | wv_82593_cmd(struct net_device * dev, | ||
837 | char * str, | ||
838 | int cmd, | ||
839 | int result) | ||
840 | { | ||
841 | kio_addr_t base = dev->base_addr; | ||
842 | int status; | ||
843 | int wait_completed; | ||
844 | long spin; | ||
845 | |||
846 | /* Spin until the chip finishes executing its current command (if any) */ | ||
847 | spin = 1000; | ||
848 | do | ||
849 | { | ||
850 | /* Time calibration of the loop */ | ||
851 | udelay(10); | ||
852 | |||
853 | /* Read the interrupt register */ | ||
854 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
855 | status = inb(LCSR(base)); | ||
856 | } | ||
857 | while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); | ||
858 | |||
859 | /* If the interrupt hasn't be posted */ | ||
860 | if(spin <= 0) | ||
861 | { | ||
862 | #ifdef DEBUG_INTERRUPT_ERROR | ||
863 | printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", | ||
864 | str, status); | ||
865 | #endif | ||
866 | return(FALSE); | ||
867 | } | ||
868 | |||
869 | /* Issue the command to the controller */ | ||
870 | outb(cmd, LCCR(base)); | ||
871 | |||
872 | /* If we don't have to check the result of the command | ||
873 | * Note : this mean that the irq handler will deal with that */ | ||
874 | if(result == SR0_NO_RESULT) | ||
875 | return(TRUE); | ||
876 | |||
877 | /* We are waiting for command completion */ | ||
878 | wait_completed = TRUE; | ||
879 | |||
880 | /* Busy wait while the LAN controller executes the command. */ | ||
881 | spin = 1000; | ||
882 | do | ||
883 | { | ||
884 | /* Time calibration of the loop */ | ||
885 | udelay(10); | ||
886 | |||
887 | /* Read the interrupt register */ | ||
888 | outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); | ||
889 | status = inb(LCSR(base)); | ||
890 | |||
891 | /* Check if there was an interrupt posted */ | ||
892 | if((status & SR0_INTERRUPT)) | ||
893 | { | ||
894 | /* Acknowledge the interrupt */ | ||
895 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); | ||
896 | |||
897 | /* Check if interrupt is a command completion */ | ||
898 | if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && | ||
899 | ((status & SR0_BOTH_RX_TX) != 0x0) && | ||
900 | !(status & SR0_RECEPTION)) | ||
901 | { | ||
902 | /* Signal command completion */ | ||
903 | wait_completed = FALSE; | ||
904 | } | ||
905 | else | ||
906 | { | ||
907 | /* Note : Rx interrupts will be handled later, because we can | ||
908 | * handle multiple Rx packets at once */ | ||
909 | #ifdef DEBUG_INTERRUPT_INFO | ||
910 | printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); | ||
911 | #endif | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | while(wait_completed && (spin-- > 0)); | ||
916 | |||
917 | /* If the interrupt hasn't be posted */ | ||
918 | if(wait_completed) | ||
919 | { | ||
920 | #ifdef DEBUG_INTERRUPT_ERROR | ||
921 | printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", | ||
922 | str, status); | ||
923 | #endif | ||
924 | return(FALSE); | ||
925 | } | ||
926 | |||
927 | /* Check the return code returned by the card (see above) against | ||
928 | * the expected return code provided by the caller */ | ||
929 | if((status & SR0_EVENT_MASK) != result) | ||
930 | { | ||
931 | #ifdef DEBUG_INTERRUPT_ERROR | ||
932 | printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", | ||
933 | str, status); | ||
934 | #endif | ||
935 | return(FALSE); | ||
936 | } | ||
937 | |||
938 | return(TRUE); | ||
939 | } /* wv_82593_cmd */ | ||
940 | |||
941 | /*------------------------------------------------------------------*/ | ||
942 | /* | ||
943 | * This routine does a 593 op-code number 7, and obtains the diagnose | ||
944 | * status for the WaveLAN. | ||
945 | */ | ||
946 | static inline int | ||
947 | wv_diag(struct net_device * dev) | ||
948 | { | ||
949 | int ret = FALSE; | ||
950 | |||
951 | if(wv_82593_cmd(dev, "wv_diag(): diagnose", | ||
952 | OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) | ||
953 | ret = TRUE; | ||
954 | |||
955 | #ifdef DEBUG_CONFIG_ERRORS | ||
956 | printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n"); | ||
957 | #endif | ||
958 | return(ret); | ||
959 | } /* wv_diag */ | ||
960 | |||
961 | /*------------------------------------------------------------------*/ | ||
962 | /* | ||
963 | * Routine to read len bytes from the i82593's ring buffer, starting at | ||
964 | * chip address addr. The results read from the chip are stored in buf. | ||
965 | * The return value is the address to use for next the call. | ||
966 | */ | ||
967 | static int | ||
968 | read_ringbuf(struct net_device * dev, | ||
969 | int addr, | ||
970 | char * buf, | ||
971 | int len) | ||
972 | { | ||
973 | kio_addr_t base = dev->base_addr; | ||
974 | int ring_ptr = addr; | ||
975 | int chunk_len; | ||
976 | char * buf_ptr = buf; | ||
977 | |||
978 | /* Get all the buffer */ | ||
979 | while(len > 0) | ||
980 | { | ||
981 | /* Position the Program I/O Register at the ring buffer pointer */ | ||
982 | outb(ring_ptr & 0xff, PIORL(base)); | ||
983 | outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); | ||
984 | |||
985 | /* First, determine how much we can read without wrapping around the | ||
986 | ring buffer */ | ||
987 | if((addr + len) < (RX_BASE + RX_SIZE)) | ||
988 | chunk_len = len; | ||
989 | else | ||
990 | chunk_len = RX_BASE + RX_SIZE - addr; | ||
991 | insb(PIOP(base), buf_ptr, chunk_len); | ||
992 | buf_ptr += chunk_len; | ||
993 | len -= chunk_len; | ||
994 | ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; | ||
995 | } | ||
996 | return(ring_ptr); | ||
997 | } /* read_ringbuf */ | ||
998 | |||
999 | /*------------------------------------------------------------------*/ | ||
1000 | /* | ||
1001 | * Reconfigure the i82593, or at least ask for it... | ||
1002 | * Because wv_82593_config use the transmission buffer, we must do it | ||
1003 | * when we are sure that there is no transmission, so we do it now | ||
1004 | * or in wavelan_packet_xmit() (I can't find any better place, | ||
1005 | * wavelan_interrupt is not an option...), so you may experience | ||
1006 | * some delay sometime... | ||
1007 | */ | ||
1008 | static inline void | ||
1009 | wv_82593_reconfig(struct net_device * dev) | ||
1010 | { | ||
1011 | net_local * lp = netdev_priv(dev); | ||
1012 | dev_link_t * link = lp->link; | ||
1013 | unsigned long flags; | ||
1014 | |||
1015 | /* Arm the flag, will be cleard in wv_82593_config() */ | ||
1016 | lp->reconfig_82593 = TRUE; | ||
1017 | |||
1018 | /* Check if we can do it now ! */ | ||
1019 | if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) | ||
1020 | { | ||
1021 | spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ | ||
1022 | wv_82593_config(dev); | ||
1023 | spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ | ||
1024 | } | ||
1025 | else | ||
1026 | { | ||
1027 | #ifdef DEBUG_IOCTL_INFO | ||
1028 | printk(KERN_DEBUG | ||
1029 | "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", | ||
1030 | dev->name, dev->state, link->open); | ||
1031 | #endif | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | /********************* DEBUG & INFO SUBROUTINES *********************/ | ||
1036 | /* | ||
1037 | * This routines are used in the code to show debug informations. | ||
1038 | * Most of the time, it dump the content of hardware structures... | ||
1039 | */ | ||
1040 | |||
1041 | #ifdef DEBUG_PSA_SHOW | ||
1042 | /*------------------------------------------------------------------*/ | ||
1043 | /* | ||
1044 | * Print the formatted contents of the Parameter Storage Area. | ||
1045 | */ | ||
1046 | static void | ||
1047 | wv_psa_show(psa_t * p) | ||
1048 | { | ||
1049 | printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); | ||
1050 | printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", | ||
1051 | p->psa_io_base_addr_1, | ||
1052 | p->psa_io_base_addr_2, | ||
1053 | p->psa_io_base_addr_3, | ||
1054 | p->psa_io_base_addr_4); | ||
1055 | printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", | ||
1056 | p->psa_rem_boot_addr_1, | ||
1057 | p->psa_rem_boot_addr_2, | ||
1058 | p->psa_rem_boot_addr_3); | ||
1059 | printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); | ||
1060 | printk("psa_int_req_no: %d\n", p->psa_int_req_no); | ||
1061 | #ifdef DEBUG_SHOW_UNUSED | ||
1062 | printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1063 | p->psa_unused0[0], | ||
1064 | p->psa_unused0[1], | ||
1065 | p->psa_unused0[2], | ||
1066 | p->psa_unused0[3], | ||
1067 | p->psa_unused0[4], | ||
1068 | p->psa_unused0[5], | ||
1069 | p->psa_unused0[6]); | ||
1070 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1071 | printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1072 | p->psa_univ_mac_addr[0], | ||
1073 | p->psa_univ_mac_addr[1], | ||
1074 | p->psa_univ_mac_addr[2], | ||
1075 | p->psa_univ_mac_addr[3], | ||
1076 | p->psa_univ_mac_addr[4], | ||
1077 | p->psa_univ_mac_addr[5]); | ||
1078 | printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1079 | p->psa_local_mac_addr[0], | ||
1080 | p->psa_local_mac_addr[1], | ||
1081 | p->psa_local_mac_addr[2], | ||
1082 | p->psa_local_mac_addr[3], | ||
1083 | p->psa_local_mac_addr[4], | ||
1084 | p->psa_local_mac_addr[5]); | ||
1085 | printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); | ||
1086 | printk("psa_comp_number: %d, ", p->psa_comp_number); | ||
1087 | printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); | ||
1088 | printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", | ||
1089 | p->psa_feature_select); | ||
1090 | printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); | ||
1091 | printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); | ||
1092 | printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); | ||
1093 | printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); | ||
1094 | printk("psa_nwid_select: %d\n", p->psa_nwid_select); | ||
1095 | printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); | ||
1096 | printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1097 | p->psa_encryption_key[0], | ||
1098 | p->psa_encryption_key[1], | ||
1099 | p->psa_encryption_key[2], | ||
1100 | p->psa_encryption_key[3], | ||
1101 | p->psa_encryption_key[4], | ||
1102 | p->psa_encryption_key[5], | ||
1103 | p->psa_encryption_key[6], | ||
1104 | p->psa_encryption_key[7]); | ||
1105 | printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); | ||
1106 | printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", | ||
1107 | p->psa_call_code[0]); | ||
1108 | printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1109 | p->psa_call_code[0], | ||
1110 | p->psa_call_code[1], | ||
1111 | p->psa_call_code[2], | ||
1112 | p->psa_call_code[3], | ||
1113 | p->psa_call_code[4], | ||
1114 | p->psa_call_code[5], | ||
1115 | p->psa_call_code[6], | ||
1116 | p->psa_call_code[7]); | ||
1117 | #ifdef DEBUG_SHOW_UNUSED | ||
1118 | printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", | ||
1119 | p->psa_reserved[0], | ||
1120 | p->psa_reserved[1], | ||
1121 | p->psa_reserved[2], | ||
1122 | p->psa_reserved[3]); | ||
1123 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1124 | printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); | ||
1125 | printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); | ||
1126 | printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); | ||
1127 | } /* wv_psa_show */ | ||
1128 | #endif /* DEBUG_PSA_SHOW */ | ||
1129 | |||
1130 | #ifdef DEBUG_MMC_SHOW | ||
1131 | /*------------------------------------------------------------------*/ | ||
1132 | /* | ||
1133 | * Print the formatted status of the Modem Management Controller. | ||
1134 | * This function need to be completed... | ||
1135 | */ | ||
1136 | static void | ||
1137 | wv_mmc_show(struct net_device * dev) | ||
1138 | { | ||
1139 | kio_addr_t base = dev->base_addr; | ||
1140 | net_local * lp = netdev_priv(dev); | ||
1141 | mmr_t m; | ||
1142 | |||
1143 | /* Basic check */ | ||
1144 | if(hasr_read(base) & HASR_NO_CLK) | ||
1145 | { | ||
1146 | printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", | ||
1147 | dev->name); | ||
1148 | return; | ||
1149 | } | ||
1150 | |||
1151 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1152 | |||
1153 | /* Read the mmc */ | ||
1154 | mmc_out(base, mmwoff(0, mmw_freeze), 1); | ||
1155 | mmc_read(base, 0, (u_char *)&m, sizeof(m)); | ||
1156 | mmc_out(base, mmwoff(0, mmw_freeze), 0); | ||
1157 | |||
1158 | #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ | ||
1159 | /* Don't forget to update statistics */ | ||
1160 | lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
1161 | #endif /* WIRELESS_EXT */ | ||
1162 | |||
1163 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1164 | |||
1165 | printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); | ||
1166 | #ifdef DEBUG_SHOW_UNUSED | ||
1167 | printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1168 | m.mmr_unused0[0], | ||
1169 | m.mmr_unused0[1], | ||
1170 | m.mmr_unused0[2], | ||
1171 | m.mmr_unused0[3], | ||
1172 | m.mmr_unused0[4], | ||
1173 | m.mmr_unused0[5], | ||
1174 | m.mmr_unused0[6], | ||
1175 | m.mmr_unused0[7]); | ||
1176 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1177 | printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n", | ||
1178 | m.mmr_des_avail, m.mmr_des_status); | ||
1179 | #ifdef DEBUG_SHOW_UNUSED | ||
1180 | printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", | ||
1181 | m.mmr_unused1[0], | ||
1182 | m.mmr_unused1[1], | ||
1183 | m.mmr_unused1[2], | ||
1184 | m.mmr_unused1[3], | ||
1185 | m.mmr_unused1[4]); | ||
1186 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1187 | printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", | ||
1188 | m.mmr_dce_status, | ||
1189 | (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", | ||
1190 | (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? | ||
1191 | "loop test indicated," : "", | ||
1192 | (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", | ||
1193 | (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? | ||
1194 | "jabber timer expired," : ""); | ||
1195 | printk(KERN_DEBUG "Dsp ID: %02X\n", | ||
1196 | m.mmr_dsp_id); | ||
1197 | #ifdef DEBUG_SHOW_UNUSED | ||
1198 | printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", | ||
1199 | m.mmr_unused2[0], | ||
1200 | m.mmr_unused2[1]); | ||
1201 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1202 | printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", | ||
1203 | (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, | ||
1204 | (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); | ||
1205 | printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", | ||
1206 | m.mmr_thr_pre_set & MMR_THR_PRE_SET, | ||
1207 | (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); | ||
1208 | printk(KERN_DEBUG "signal_lvl: %d [%s], ", | ||
1209 | m.mmr_signal_lvl & MMR_SIGNAL_LVL, | ||
1210 | (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); | ||
1211 | printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, | ||
1212 | (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); | ||
1213 | printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, | ||
1214 | (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); | ||
1215 | #ifdef DEBUG_SHOW_UNUSED | ||
1216 | printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); | ||
1217 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1218 | } /* wv_mmc_show */ | ||
1219 | #endif /* DEBUG_MMC_SHOW */ | ||
1220 | |||
1221 | #ifdef DEBUG_I82593_SHOW | ||
1222 | /*------------------------------------------------------------------*/ | ||
1223 | /* | ||
1224 | * Print the formatted status of the i82593's receive unit. | ||
1225 | */ | ||
1226 | static void | ||
1227 | wv_ru_show(struct net_device * dev) | ||
1228 | { | ||
1229 | net_local *lp = netdev_priv(dev); | ||
1230 | |||
1231 | printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); | ||
1232 | printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); | ||
1233 | /* | ||
1234 | * Not implemented yet... | ||
1235 | */ | ||
1236 | printk("\n"); | ||
1237 | } /* wv_ru_show */ | ||
1238 | #endif /* DEBUG_I82593_SHOW */ | ||
1239 | |||
1240 | #ifdef DEBUG_DEVICE_SHOW | ||
1241 | /*------------------------------------------------------------------*/ | ||
1242 | /* | ||
1243 | * Print the formatted status of the WaveLAN PCMCIA device driver. | ||
1244 | */ | ||
1245 | static void | ||
1246 | wv_dev_show(struct net_device * dev) | ||
1247 | { | ||
1248 | printk(KERN_DEBUG "dev:"); | ||
1249 | printk(" state=%lX,", dev->state); | ||
1250 | printk(" trans_start=%ld,", dev->trans_start); | ||
1251 | printk(" flags=0x%x,", dev->flags); | ||
1252 | printk("\n"); | ||
1253 | } /* wv_dev_show */ | ||
1254 | |||
1255 | /*------------------------------------------------------------------*/ | ||
1256 | /* | ||
1257 | * Print the formatted status of the WaveLAN PCMCIA device driver's | ||
1258 | * private information. | ||
1259 | */ | ||
1260 | static void | ||
1261 | wv_local_show(struct net_device * dev) | ||
1262 | { | ||
1263 | net_local *lp = netdev_priv(dev); | ||
1264 | |||
1265 | printk(KERN_DEBUG "local:"); | ||
1266 | /* | ||
1267 | * Not implemented yet... | ||
1268 | */ | ||
1269 | printk("\n"); | ||
1270 | } /* wv_local_show */ | ||
1271 | #endif /* DEBUG_DEVICE_SHOW */ | ||
1272 | |||
1273 | #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) | ||
1274 | /*------------------------------------------------------------------*/ | ||
1275 | /* | ||
1276 | * Dump packet header (and content if necessary) on the screen | ||
1277 | */ | ||
1278 | static inline void | ||
1279 | wv_packet_info(u_char * p, /* Packet to dump */ | ||
1280 | int length, /* Length of the packet */ | ||
1281 | char * msg1, /* Name of the device */ | ||
1282 | char * msg2) /* Name of the function */ | ||
1283 | { | ||
1284 | int i; | ||
1285 | int maxi; | ||
1286 | |||
1287 | printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", | ||
1288 | msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); | ||
1289 | printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", | ||
1290 | msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); | ||
1291 | |||
1292 | #ifdef DEBUG_PACKET_DUMP | ||
1293 | |||
1294 | printk(KERN_DEBUG "data=\""); | ||
1295 | |||
1296 | if((maxi = length) > DEBUG_PACKET_DUMP) | ||
1297 | maxi = DEBUG_PACKET_DUMP; | ||
1298 | for(i = 14; i < maxi; i++) | ||
1299 | if(p[i] >= ' ' && p[i] <= '~') | ||
1300 | printk(" %c", p[i]); | ||
1301 | else | ||
1302 | printk("%02X", p[i]); | ||
1303 | if(maxi < length) | ||
1304 | printk(".."); | ||
1305 | printk("\"\n"); | ||
1306 | printk(KERN_DEBUG "\n"); | ||
1307 | #endif /* DEBUG_PACKET_DUMP */ | ||
1308 | } | ||
1309 | #endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ | ||
1310 | |||
1311 | /*------------------------------------------------------------------*/ | ||
1312 | /* | ||
1313 | * This is the information which is displayed by the driver at startup | ||
1314 | * There is a lot of flag to configure it at your will... | ||
1315 | */ | ||
1316 | static inline void | ||
1317 | wv_init_info(struct net_device * dev) | ||
1318 | { | ||
1319 | kio_addr_t base = dev->base_addr; | ||
1320 | psa_t psa; | ||
1321 | int i; | ||
1322 | |||
1323 | /* Read the parameter storage area */ | ||
1324 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
1325 | |||
1326 | #ifdef DEBUG_PSA_SHOW | ||
1327 | wv_psa_show(&psa); | ||
1328 | #endif | ||
1329 | #ifdef DEBUG_MMC_SHOW | ||
1330 | wv_mmc_show(dev); | ||
1331 | #endif | ||
1332 | #ifdef DEBUG_I82593_SHOW | ||
1333 | wv_ru_show(dev); | ||
1334 | #endif | ||
1335 | |||
1336 | #ifdef DEBUG_BASIC_SHOW | ||
1337 | /* Now, let's go for the basic stuff */ | ||
1338 | printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr", | ||
1339 | dev->name, base, dev->irq); | ||
1340 | for(i = 0; i < WAVELAN_ADDR_SIZE; i++) | ||
1341 | printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); | ||
1342 | |||
1343 | /* Print current network id */ | ||
1344 | if(psa.psa_nwid_select) | ||
1345 | printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); | ||
1346 | else | ||
1347 | printk(", nwid off"); | ||
1348 | |||
1349 | /* If 2.00 card */ | ||
1350 | if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
1351 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
1352 | { | ||
1353 | unsigned short freq; | ||
1354 | |||
1355 | /* Ask the EEprom to read the frequency from the first area */ | ||
1356 | fee_read(base, 0x00 /* 1st area - frequency... */, | ||
1357 | &freq, 1); | ||
1358 | |||
1359 | /* Print frequency */ | ||
1360 | printk(", 2.00, %ld", (freq >> 6) + 2400L); | ||
1361 | |||
1362 | /* Hack !!! */ | ||
1363 | if(freq & 0x20) | ||
1364 | printk(".5"); | ||
1365 | } | ||
1366 | else | ||
1367 | { | ||
1368 | printk(", PCMCIA, "); | ||
1369 | switch (psa.psa_subband) | ||
1370 | { | ||
1371 | case PSA_SUBBAND_915: | ||
1372 | printk("915"); | ||
1373 | break; | ||
1374 | case PSA_SUBBAND_2425: | ||
1375 | printk("2425"); | ||
1376 | break; | ||
1377 | case PSA_SUBBAND_2460: | ||
1378 | printk("2460"); | ||
1379 | break; | ||
1380 | case PSA_SUBBAND_2484: | ||
1381 | printk("2484"); | ||
1382 | break; | ||
1383 | case PSA_SUBBAND_2430_5: | ||
1384 | printk("2430.5"); | ||
1385 | break; | ||
1386 | default: | ||
1387 | printk("unknown"); | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | printk(" MHz\n"); | ||
1392 | #endif /* DEBUG_BASIC_SHOW */ | ||
1393 | |||
1394 | #ifdef DEBUG_VERSION_SHOW | ||
1395 | /* Print version information */ | ||
1396 | printk(KERN_NOTICE "%s", version); | ||
1397 | #endif | ||
1398 | } /* wv_init_info */ | ||
1399 | |||
1400 | /********************* IOCTL, STATS & RECONFIG *********************/ | ||
1401 | /* | ||
1402 | * We found here routines that are called by Linux on differents | ||
1403 | * occasions after the configuration and not for transmitting data | ||
1404 | * These may be called when the user use ifconfig, /proc/net/dev | ||
1405 | * or wireless extensions | ||
1406 | */ | ||
1407 | |||
1408 | /*------------------------------------------------------------------*/ | ||
1409 | /* | ||
1410 | * Get the current ethernet statistics. This may be called with the | ||
1411 | * card open or closed. | ||
1412 | * Used when the user read /proc/net/dev | ||
1413 | */ | ||
1414 | static en_stats * | ||
1415 | wavelan_get_stats(struct net_device * dev) | ||
1416 | { | ||
1417 | #ifdef DEBUG_IOCTL_TRACE | ||
1418 | printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); | ||
1419 | #endif | ||
1420 | |||
1421 | return(&((net_local *)netdev_priv(dev))->stats); | ||
1422 | } | ||
1423 | |||
1424 | /*------------------------------------------------------------------*/ | ||
1425 | /* | ||
1426 | * Set or clear the multicast filter for this adaptor. | ||
1427 | * num_addrs == -1 Promiscuous mode, receive all packets | ||
1428 | * num_addrs == 0 Normal mode, clear multicast list | ||
1429 | * num_addrs > 0 Multicast mode, receive normal and MC packets, | ||
1430 | * and do best-effort filtering. | ||
1431 | */ | ||
1432 | |||
1433 | static void | ||
1434 | wavelan_set_multicast_list(struct net_device * dev) | ||
1435 | { | ||
1436 | net_local * lp = netdev_priv(dev); | ||
1437 | |||
1438 | #ifdef DEBUG_IOCTL_TRACE | ||
1439 | printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); | ||
1440 | #endif | ||
1441 | |||
1442 | #ifdef DEBUG_IOCTL_INFO | ||
1443 | printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", | ||
1444 | dev->name, dev->flags, dev->mc_count); | ||
1445 | #endif | ||
1446 | |||
1447 | if(dev->flags & IFF_PROMISC) | ||
1448 | { | ||
1449 | /* | ||
1450 | * Enable promiscuous mode: receive all packets. | ||
1451 | */ | ||
1452 | if(!lp->promiscuous) | ||
1453 | { | ||
1454 | lp->promiscuous = 1; | ||
1455 | lp->allmulticast = 0; | ||
1456 | lp->mc_count = 0; | ||
1457 | |||
1458 | wv_82593_reconfig(dev); | ||
1459 | |||
1460 | /* Tell the kernel that we are doing a really bad job... */ | ||
1461 | dev->flags |= IFF_PROMISC; | ||
1462 | } | ||
1463 | } | ||
1464 | else | ||
1465 | /* If all multicast addresses | ||
1466 | * or too much multicast addresses for the hardware filter */ | ||
1467 | if((dev->flags & IFF_ALLMULTI) || | ||
1468 | (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) | ||
1469 | { | ||
1470 | /* | ||
1471 | * Disable promiscuous mode, but active the all multicast mode | ||
1472 | */ | ||
1473 | if(!lp->allmulticast) | ||
1474 | { | ||
1475 | lp->promiscuous = 0; | ||
1476 | lp->allmulticast = 1; | ||
1477 | lp->mc_count = 0; | ||
1478 | |||
1479 | wv_82593_reconfig(dev); | ||
1480 | |||
1481 | /* Tell the kernel that we are doing a really bad job... */ | ||
1482 | dev->flags |= IFF_ALLMULTI; | ||
1483 | } | ||
1484 | } | ||
1485 | else | ||
1486 | /* If there is some multicast addresses to send */ | ||
1487 | if(dev->mc_list != (struct dev_mc_list *) NULL) | ||
1488 | { | ||
1489 | /* | ||
1490 | * Disable promiscuous mode, but receive all packets | ||
1491 | * in multicast list | ||
1492 | */ | ||
1493 | #ifdef MULTICAST_AVOID | ||
1494 | if(lp->promiscuous || lp->allmulticast || | ||
1495 | (dev->mc_count != lp->mc_count)) | ||
1496 | #endif | ||
1497 | { | ||
1498 | lp->promiscuous = 0; | ||
1499 | lp->allmulticast = 0; | ||
1500 | lp->mc_count = dev->mc_count; | ||
1501 | |||
1502 | wv_82593_reconfig(dev); | ||
1503 | } | ||
1504 | } | ||
1505 | else | ||
1506 | { | ||
1507 | /* | ||
1508 | * Switch to normal mode: disable promiscuous mode and | ||
1509 | * clear the multicast list. | ||
1510 | */ | ||
1511 | if(lp->promiscuous || lp->mc_count == 0) | ||
1512 | { | ||
1513 | lp->promiscuous = 0; | ||
1514 | lp->allmulticast = 0; | ||
1515 | lp->mc_count = 0; | ||
1516 | |||
1517 | wv_82593_reconfig(dev); | ||
1518 | } | ||
1519 | } | ||
1520 | #ifdef DEBUG_IOCTL_TRACE | ||
1521 | printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); | ||
1522 | #endif | ||
1523 | } | ||
1524 | |||
1525 | /*------------------------------------------------------------------*/ | ||
1526 | /* | ||
1527 | * This function doesn't exist... | ||
1528 | * (Note : it was a nice way to test the reconfigure stuff...) | ||
1529 | */ | ||
1530 | #ifdef SET_MAC_ADDRESS | ||
1531 | static int | ||
1532 | wavelan_set_mac_address(struct net_device * dev, | ||
1533 | void * addr) | ||
1534 | { | ||
1535 | struct sockaddr * mac = addr; | ||
1536 | |||
1537 | /* Copy the address */ | ||
1538 | memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); | ||
1539 | |||
1540 | /* Reconfig the beast */ | ||
1541 | wv_82593_reconfig(dev); | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | #endif /* SET_MAC_ADDRESS */ | ||
1546 | |||
1547 | #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ | ||
1548 | |||
1549 | /*------------------------------------------------------------------*/ | ||
1550 | /* | ||
1551 | * Frequency setting (for hardware able of it) | ||
1552 | * It's a bit complicated and you don't really want to look into it... | ||
1553 | */ | ||
1554 | static inline int | ||
1555 | wv_set_frequency(u_long base, /* i/o port of the card */ | ||
1556 | iw_freq * frequency) | ||
1557 | { | ||
1558 | const int BAND_NUM = 10; /* Number of bands */ | ||
1559 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ | ||
1560 | #ifdef DEBUG_IOCTL_INFO | ||
1561 | int i; | ||
1562 | #endif | ||
1563 | |||
1564 | /* Setting by frequency */ | ||
1565 | /* Theoritically, you may set any frequency between | ||
1566 | * the two limits with a 0.5 MHz precision. In practice, | ||
1567 | * I don't want you to have trouble with local | ||
1568 | * regulations... */ | ||
1569 | if((frequency->e == 1) && | ||
1570 | (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) | ||
1571 | { | ||
1572 | freq = ((frequency->m / 10000) - 24000L) / 5; | ||
1573 | } | ||
1574 | |||
1575 | /* Setting by channel (same as wfreqsel) */ | ||
1576 | /* Warning : each channel is 22MHz wide, so some of the channels | ||
1577 | * will interfere... */ | ||
1578 | if((frequency->e == 0) && | ||
1579 | (frequency->m >= 0) && (frequency->m < BAND_NUM)) | ||
1580 | { | ||
1581 | /* Get frequency offset. */ | ||
1582 | freq = channel_bands[frequency->m] >> 1; | ||
1583 | } | ||
1584 | |||
1585 | /* Verify if the frequency is allowed */ | ||
1586 | if(freq != 0L) | ||
1587 | { | ||
1588 | u_short table[10]; /* Authorized frequency table */ | ||
1589 | |||
1590 | /* Read the frequency table */ | ||
1591 | fee_read(base, 0x71 /* frequency table */, | ||
1592 | table, 10); | ||
1593 | |||
1594 | #ifdef DEBUG_IOCTL_INFO | ||
1595 | printk(KERN_DEBUG "Frequency table :"); | ||
1596 | for(i = 0; i < 10; i++) | ||
1597 | { | ||
1598 | printk(" %04X", | ||
1599 | table[i]); | ||
1600 | } | ||
1601 | printk("\n"); | ||
1602 | #endif | ||
1603 | |||
1604 | /* Look in the table if the frequency is allowed */ | ||
1605 | if(!(table[9 - ((freq - 24) / 16)] & | ||
1606 | (1 << ((freq - 24) % 16)))) | ||
1607 | return -EINVAL; /* not allowed */ | ||
1608 | } | ||
1609 | else | ||
1610 | return -EINVAL; | ||
1611 | |||
1612 | /* If we get a usable frequency */ | ||
1613 | if(freq != 0L) | ||
1614 | { | ||
1615 | unsigned short area[16]; | ||
1616 | unsigned short dac[2]; | ||
1617 | unsigned short area_verify[16]; | ||
1618 | unsigned short dac_verify[2]; | ||
1619 | /* Corresponding gain (in the power adjust value table) | ||
1620 | * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 | ||
1621 | * & WCIN062D.DOC, page 6.2.9 */ | ||
1622 | unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; | ||
1623 | int power_band = 0; /* Selected band */ | ||
1624 | unsigned short power_adjust; /* Correct value */ | ||
1625 | |||
1626 | /* Search for the gain */ | ||
1627 | power_band = 0; | ||
1628 | while((freq > power_limit[power_band]) && | ||
1629 | (power_limit[++power_band] != 0)) | ||
1630 | ; | ||
1631 | |||
1632 | /* Read the first area */ | ||
1633 | fee_read(base, 0x00, | ||
1634 | area, 16); | ||
1635 | |||
1636 | /* Read the DAC */ | ||
1637 | fee_read(base, 0x60, | ||
1638 | dac, 2); | ||
1639 | |||
1640 | /* Read the new power adjust value */ | ||
1641 | fee_read(base, 0x6B - (power_band >> 1), | ||
1642 | &power_adjust, 1); | ||
1643 | if(power_band & 0x1) | ||
1644 | power_adjust >>= 8; | ||
1645 | else | ||
1646 | power_adjust &= 0xFF; | ||
1647 | |||
1648 | #ifdef DEBUG_IOCTL_INFO | ||
1649 | printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); | ||
1650 | for(i = 0; i < 16; i++) | ||
1651 | { | ||
1652 | printk(" %04X", | ||
1653 | area[i]); | ||
1654 | } | ||
1655 | printk("\n"); | ||
1656 | |||
1657 | printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", | ||
1658 | dac[0], dac[1]); | ||
1659 | #endif | ||
1660 | |||
1661 | /* Frequency offset (for info only...) */ | ||
1662 | area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); | ||
1663 | |||
1664 | /* Receiver Principle main divider coefficient */ | ||
1665 | area[3] = (freq >> 1) + 2400L - 352L; | ||
1666 | area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1667 | |||
1668 | /* Transmitter Main divider coefficient */ | ||
1669 | area[13] = (freq >> 1) + 2400L; | ||
1670 | area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1671 | |||
1672 | /* Others part of the area are flags, bit streams or unused... */ | ||
1673 | |||
1674 | /* Set the value in the DAC */ | ||
1675 | dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); | ||
1676 | dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); | ||
1677 | |||
1678 | /* Write the first area */ | ||
1679 | fee_write(base, 0x00, | ||
1680 | area, 16); | ||
1681 | |||
1682 | /* Write the DAC */ | ||
1683 | fee_write(base, 0x60, | ||
1684 | dac, 2); | ||
1685 | |||
1686 | /* We now should verify here that the EEprom writting was ok */ | ||
1687 | |||
1688 | /* ReRead the first area */ | ||
1689 | fee_read(base, 0x00, | ||
1690 | area_verify, 16); | ||
1691 | |||
1692 | /* ReRead the DAC */ | ||
1693 | fee_read(base, 0x60, | ||
1694 | dac_verify, 2); | ||
1695 | |||
1696 | /* Compare */ | ||
1697 | if(memcmp(area, area_verify, 16 * 2) || | ||
1698 | memcmp(dac, dac_verify, 2 * 2)) | ||
1699 | { | ||
1700 | #ifdef DEBUG_IOCTL_ERROR | ||
1701 | printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); | ||
1702 | #endif | ||
1703 | return -EOPNOTSUPP; | ||
1704 | } | ||
1705 | |||
1706 | /* We must download the frequency parameters to the | ||
1707 | * synthetisers (from the EEprom - area 1) | ||
1708 | * Note : as the EEprom is auto decremented, we set the end | ||
1709 | * if the area... */ | ||
1710 | mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); | ||
1711 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), | ||
1712 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1713 | |||
1714 | /* Wait until the download is finished */ | ||
1715 | fee_wait(base, 100, 100); | ||
1716 | |||
1717 | /* We must now download the power adjust value (gain) to | ||
1718 | * the synthetisers (from the EEprom - area 7 - DAC) */ | ||
1719 | mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); | ||
1720 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), | ||
1721 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1722 | |||
1723 | /* Wait until the download is finished */ | ||
1724 | fee_wait(base, 100, 100); | ||
1725 | |||
1726 | #ifdef DEBUG_IOCTL_INFO | ||
1727 | /* Verification of what we have done... */ | ||
1728 | |||
1729 | printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); | ||
1730 | for(i = 0; i < 16; i++) | ||
1731 | { | ||
1732 | printk(" %04X", | ||
1733 | area_verify[i]); | ||
1734 | } | ||
1735 | printk("\n"); | ||
1736 | |||
1737 | printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", | ||
1738 | dac_verify[0], dac_verify[1]); | ||
1739 | #endif | ||
1740 | |||
1741 | return 0; | ||
1742 | } | ||
1743 | else | ||
1744 | return -EINVAL; /* Bah, never get there... */ | ||
1745 | } | ||
1746 | |||
1747 | /*------------------------------------------------------------------*/ | ||
1748 | /* | ||
1749 | * Give the list of available frequencies | ||
1750 | */ | ||
1751 | static inline int | ||
1752 | wv_frequency_list(u_long base, /* i/o port of the card */ | ||
1753 | iw_freq * list, /* List of frequency to fill */ | ||
1754 | int max) /* Maximum number of frequencies */ | ||
1755 | { | ||
1756 | u_short table[10]; /* Authorized frequency table */ | ||
1757 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ | ||
1758 | int i; /* index in the table */ | ||
1759 | const int BAND_NUM = 10; /* Number of bands */ | ||
1760 | int c = 0; /* Channel number */ | ||
1761 | |||
1762 | /* Read the frequency table */ | ||
1763 | fee_read(base, 0x71 /* frequency table */, | ||
1764 | table, 10); | ||
1765 | |||
1766 | /* Look all frequencies */ | ||
1767 | i = 0; | ||
1768 | for(freq = 0; freq < 150; freq++) | ||
1769 | /* Look in the table if the frequency is allowed */ | ||
1770 | if(table[9 - (freq / 16)] & (1 << (freq % 16))) | ||
1771 | { | ||
1772 | /* Compute approximate channel number */ | ||
1773 | while((((channel_bands[c] >> 1) - 24) < freq) && | ||
1774 | (c < BAND_NUM)) | ||
1775 | c++; | ||
1776 | list[i].i = c; /* Set the list index */ | ||
1777 | |||
1778 | /* put in the list */ | ||
1779 | list[i].m = (((freq + 24) * 5) + 24000L) * 10000; | ||
1780 | list[i++].e = 1; | ||
1781 | |||
1782 | /* Check number */ | ||
1783 | if(i >= max) | ||
1784 | return(i); | ||
1785 | } | ||
1786 | |||
1787 | return(i); | ||
1788 | } | ||
1789 | |||
1790 | #ifdef IW_WIRELESS_SPY | ||
1791 | /*------------------------------------------------------------------*/ | ||
1792 | /* | ||
1793 | * Gather wireless spy statistics : for each packet, compare the source | ||
1794 | * address with out list, and if match, get the stats... | ||
1795 | * Sorry, but this function really need wireless extensions... | ||
1796 | */ | ||
1797 | static inline void | ||
1798 | wl_spy_gather(struct net_device * dev, | ||
1799 | u_char * mac, /* MAC address */ | ||
1800 | u_char * stats) /* Statistics to gather */ | ||
1801 | { | ||
1802 | struct iw_quality wstats; | ||
1803 | |||
1804 | wstats.qual = stats[2] & MMR_SGNL_QUAL; | ||
1805 | wstats.level = stats[0] & MMR_SIGNAL_LVL; | ||
1806 | wstats.noise = stats[1] & MMR_SILENCE_LVL; | ||
1807 | wstats.updated = 0x7; | ||
1808 | |||
1809 | /* Update spy records */ | ||
1810 | wireless_spy_update(dev, mac, &wstats); | ||
1811 | } | ||
1812 | #endif /* IW_WIRELESS_SPY */ | ||
1813 | |||
1814 | #ifdef HISTOGRAM | ||
1815 | /*------------------------------------------------------------------*/ | ||
1816 | /* | ||
1817 | * This function calculate an histogram on the signal level. | ||
1818 | * As the noise is quite constant, it's like doing it on the SNR. | ||
1819 | * We have defined a set of interval (lp->his_range), and each time | ||
1820 | * the level goes in that interval, we increment the count (lp->his_sum). | ||
1821 | * With this histogram you may detect if one wavelan is really weak, | ||
1822 | * or you may also calculate the mean and standard deviation of the level... | ||
1823 | */ | ||
1824 | static inline void | ||
1825 | wl_his_gather(struct net_device * dev, | ||
1826 | u_char * stats) /* Statistics to gather */ | ||
1827 | { | ||
1828 | net_local * lp = netdev_priv(dev); | ||
1829 | u_char level = stats[0] & MMR_SIGNAL_LVL; | ||
1830 | int i; | ||
1831 | |||
1832 | /* Find the correct interval */ | ||
1833 | i = 0; | ||
1834 | while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) | ||
1835 | ; | ||
1836 | |||
1837 | /* Increment interval counter */ | ||
1838 | (lp->his_sum[i])++; | ||
1839 | } | ||
1840 | #endif /* HISTOGRAM */ | ||
1841 | |||
1842 | static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
1843 | { | ||
1844 | strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1); | ||
1845 | } | ||
1846 | |||
1847 | static struct ethtool_ops ops = { | ||
1848 | .get_drvinfo = wl_get_drvinfo | ||
1849 | }; | ||
1850 | |||
1851 | /*------------------------------------------------------------------*/ | ||
1852 | /* | ||
1853 | * Wireless Handler : get protocol name | ||
1854 | */ | ||
1855 | static int wavelan_get_name(struct net_device *dev, | ||
1856 | struct iw_request_info *info, | ||
1857 | union iwreq_data *wrqu, | ||
1858 | char *extra) | ||
1859 | { | ||
1860 | strcpy(wrqu->name, "WaveLAN"); | ||
1861 | return 0; | ||
1862 | } | ||
1863 | |||
1864 | /*------------------------------------------------------------------*/ | ||
1865 | /* | ||
1866 | * Wireless Handler : set NWID | ||
1867 | */ | ||
1868 | static int wavelan_set_nwid(struct net_device *dev, | ||
1869 | struct iw_request_info *info, | ||
1870 | union iwreq_data *wrqu, | ||
1871 | char *extra) | ||
1872 | { | ||
1873 | kio_addr_t base = dev->base_addr; | ||
1874 | net_local *lp = netdev_priv(dev); | ||
1875 | psa_t psa; | ||
1876 | mm_t m; | ||
1877 | unsigned long flags; | ||
1878 | int ret = 0; | ||
1879 | |||
1880 | /* Disable interrupts and save flags. */ | ||
1881 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1882 | |||
1883 | /* Set NWID in WaveLAN. */ | ||
1884 | if (!wrqu->nwid.disabled) { | ||
1885 | /* Set NWID in psa */ | ||
1886 | psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; | ||
1887 | psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; | ||
1888 | psa.psa_nwid_select = 0x01; | ||
1889 | psa_write(dev, | ||
1890 | (char *) psa.psa_nwid - (char *) &psa, | ||
1891 | (unsigned char *) psa.psa_nwid, 3); | ||
1892 | |||
1893 | /* Set NWID in mmc. */ | ||
1894 | m.w.mmw_netw_id_l = psa.psa_nwid[1]; | ||
1895 | m.w.mmw_netw_id_h = psa.psa_nwid[0]; | ||
1896 | mmc_write(base, | ||
1897 | (char *) &m.w.mmw_netw_id_l - | ||
1898 | (char *) &m, | ||
1899 | (unsigned char *) &m.w.mmw_netw_id_l, 2); | ||
1900 | mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); | ||
1901 | } else { | ||
1902 | /* Disable NWID in the psa. */ | ||
1903 | psa.psa_nwid_select = 0x00; | ||
1904 | psa_write(dev, | ||
1905 | (char *) &psa.psa_nwid_select - | ||
1906 | (char *) &psa, | ||
1907 | (unsigned char *) &psa.psa_nwid_select, | ||
1908 | 1); | ||
1909 | |||
1910 | /* Disable NWID in the mmc (no filtering). */ | ||
1911 | mmc_out(base, mmwoff(0, mmw_loopt_sel), | ||
1912 | MMW_LOOPT_SEL_DIS_NWID); | ||
1913 | } | ||
1914 | /* update the Wavelan checksum */ | ||
1915 | update_psa_checksum(dev); | ||
1916 | |||
1917 | /* Enable interrupts and restore flags. */ | ||
1918 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1919 | |||
1920 | return ret; | ||
1921 | } | ||
1922 | |||
1923 | /*------------------------------------------------------------------*/ | ||
1924 | /* | ||
1925 | * Wireless Handler : get NWID | ||
1926 | */ | ||
1927 | static int wavelan_get_nwid(struct net_device *dev, | ||
1928 | struct iw_request_info *info, | ||
1929 | union iwreq_data *wrqu, | ||
1930 | char *extra) | ||
1931 | { | ||
1932 | net_local *lp = netdev_priv(dev); | ||
1933 | psa_t psa; | ||
1934 | unsigned long flags; | ||
1935 | int ret = 0; | ||
1936 | |||
1937 | /* Disable interrupts and save flags. */ | ||
1938 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1939 | |||
1940 | /* Read the NWID. */ | ||
1941 | psa_read(dev, | ||
1942 | (char *) psa.psa_nwid - (char *) &psa, | ||
1943 | (unsigned char *) psa.psa_nwid, 3); | ||
1944 | wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; | ||
1945 | wrqu->nwid.disabled = !(psa.psa_nwid_select); | ||
1946 | wrqu->nwid.fixed = 1; /* Superfluous */ | ||
1947 | |||
1948 | /* Enable interrupts and restore flags. */ | ||
1949 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1950 | |||
1951 | return ret; | ||
1952 | } | ||
1953 | |||
1954 | /*------------------------------------------------------------------*/ | ||
1955 | /* | ||
1956 | * Wireless Handler : set frequency | ||
1957 | */ | ||
1958 | static int wavelan_set_freq(struct net_device *dev, | ||
1959 | struct iw_request_info *info, | ||
1960 | union iwreq_data *wrqu, | ||
1961 | char *extra) | ||
1962 | { | ||
1963 | kio_addr_t base = dev->base_addr; | ||
1964 | net_local *lp = netdev_priv(dev); | ||
1965 | unsigned long flags; | ||
1966 | int ret; | ||
1967 | |||
1968 | /* Disable interrupts and save flags. */ | ||
1969 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1970 | |||
1971 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
1972 | if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
1973 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
1974 | ret = wv_set_frequency(base, &(wrqu->freq)); | ||
1975 | else | ||
1976 | ret = -EOPNOTSUPP; | ||
1977 | |||
1978 | /* Enable interrupts and restore flags. */ | ||
1979 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1980 | |||
1981 | return ret; | ||
1982 | } | ||
1983 | |||
1984 | /*------------------------------------------------------------------*/ | ||
1985 | /* | ||
1986 | * Wireless Handler : get frequency | ||
1987 | */ | ||
1988 | static int wavelan_get_freq(struct net_device *dev, | ||
1989 | struct iw_request_info *info, | ||
1990 | union iwreq_data *wrqu, | ||
1991 | char *extra) | ||
1992 | { | ||
1993 | kio_addr_t base = dev->base_addr; | ||
1994 | net_local *lp = netdev_priv(dev); | ||
1995 | psa_t psa; | ||
1996 | unsigned long flags; | ||
1997 | int ret = 0; | ||
1998 | |||
1999 | /* Disable interrupts and save flags. */ | ||
2000 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2001 | |||
2002 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). | ||
2003 | * Does it work for everybody, especially old cards? */ | ||
2004 | if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
2005 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
2006 | unsigned short freq; | ||
2007 | |||
2008 | /* Ask the EEPROM to read the frequency from the first area. */ | ||
2009 | fee_read(base, 0x00, &freq, 1); | ||
2010 | wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; | ||
2011 | wrqu->freq.e = 1; | ||
2012 | } else { | ||
2013 | psa_read(dev, | ||
2014 | (char *) &psa.psa_subband - (char *) &psa, | ||
2015 | (unsigned char *) &psa.psa_subband, 1); | ||
2016 | |||
2017 | if (psa.psa_subband <= 4) { | ||
2018 | wrqu->freq.m = fixed_bands[psa.psa_subband]; | ||
2019 | wrqu->freq.e = (psa.psa_subband != 0); | ||
2020 | } else | ||
2021 | ret = -EOPNOTSUPP; | ||
2022 | } | ||
2023 | |||
2024 | /* Enable interrupts and restore flags. */ | ||
2025 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2026 | |||
2027 | return ret; | ||
2028 | } | ||
2029 | |||
2030 | /*------------------------------------------------------------------*/ | ||
2031 | /* | ||
2032 | * Wireless Handler : set level threshold | ||
2033 | */ | ||
2034 | static int wavelan_set_sens(struct net_device *dev, | ||
2035 | struct iw_request_info *info, | ||
2036 | union iwreq_data *wrqu, | ||
2037 | char *extra) | ||
2038 | { | ||
2039 | kio_addr_t base = dev->base_addr; | ||
2040 | net_local *lp = netdev_priv(dev); | ||
2041 | psa_t psa; | ||
2042 | unsigned long flags; | ||
2043 | int ret = 0; | ||
2044 | |||
2045 | /* Disable interrupts and save flags. */ | ||
2046 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2047 | |||
2048 | /* Set the level threshold. */ | ||
2049 | /* We should complain loudly if wrqu->sens.fixed = 0, because we | ||
2050 | * can't set auto mode... */ | ||
2051 | psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; | ||
2052 | psa_write(dev, | ||
2053 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
2054 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
2055 | /* update the Wavelan checksum */ | ||
2056 | update_psa_checksum(dev); | ||
2057 | mmc_out(base, mmwoff(0, mmw_thr_pre_set), | ||
2058 | psa.psa_thr_pre_set); | ||
2059 | |||
2060 | /* Enable interrupts and restore flags. */ | ||
2061 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2062 | |||
2063 | return ret; | ||
2064 | } | ||
2065 | |||
2066 | /*------------------------------------------------------------------*/ | ||
2067 | /* | ||
2068 | * Wireless Handler : get level threshold | ||
2069 | */ | ||
2070 | static int wavelan_get_sens(struct net_device *dev, | ||
2071 | struct iw_request_info *info, | ||
2072 | union iwreq_data *wrqu, | ||
2073 | char *extra) | ||
2074 | { | ||
2075 | net_local *lp = netdev_priv(dev); | ||
2076 | psa_t psa; | ||
2077 | unsigned long flags; | ||
2078 | int ret = 0; | ||
2079 | |||
2080 | /* Disable interrupts and save flags. */ | ||
2081 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2082 | |||
2083 | /* Read the level threshold. */ | ||
2084 | psa_read(dev, | ||
2085 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
2086 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
2087 | wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; | ||
2088 | wrqu->sens.fixed = 1; | ||
2089 | |||
2090 | /* Enable interrupts and restore flags. */ | ||
2091 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2092 | |||
2093 | return ret; | ||
2094 | } | ||
2095 | |||
2096 | /*------------------------------------------------------------------*/ | ||
2097 | /* | ||
2098 | * Wireless Handler : set encryption key | ||
2099 | */ | ||
2100 | static int wavelan_set_encode(struct net_device *dev, | ||
2101 | struct iw_request_info *info, | ||
2102 | union iwreq_data *wrqu, | ||
2103 | char *extra) | ||
2104 | { | ||
2105 | kio_addr_t base = dev->base_addr; | ||
2106 | net_local *lp = netdev_priv(dev); | ||
2107 | unsigned long flags; | ||
2108 | psa_t psa; | ||
2109 | int ret = 0; | ||
2110 | |||
2111 | /* Disable interrupts and save flags. */ | ||
2112 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2113 | |||
2114 | /* Check if capable of encryption */ | ||
2115 | if (!mmc_encr(base)) { | ||
2116 | ret = -EOPNOTSUPP; | ||
2117 | } | ||
2118 | |||
2119 | /* Check the size of the key */ | ||
2120 | if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { | ||
2121 | ret = -EINVAL; | ||
2122 | } | ||
2123 | |||
2124 | if(!ret) { | ||
2125 | /* Basic checking... */ | ||
2126 | if (wrqu->encoding.length == 8) { | ||
2127 | /* Copy the key in the driver */ | ||
2128 | memcpy(psa.psa_encryption_key, extra, | ||
2129 | wrqu->encoding.length); | ||
2130 | psa.psa_encryption_select = 1; | ||
2131 | |||
2132 | psa_write(dev, | ||
2133 | (char *) &psa.psa_encryption_select - | ||
2134 | (char *) &psa, | ||
2135 | (unsigned char *) &psa. | ||
2136 | psa_encryption_select, 8 + 1); | ||
2137 | |||
2138 | mmc_out(base, mmwoff(0, mmw_encr_enable), | ||
2139 | MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); | ||
2140 | mmc_write(base, mmwoff(0, mmw_encr_key), | ||
2141 | (unsigned char *) &psa. | ||
2142 | psa_encryption_key, 8); | ||
2143 | } | ||
2144 | |||
2145 | /* disable encryption */ | ||
2146 | if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { | ||
2147 | psa.psa_encryption_select = 0; | ||
2148 | psa_write(dev, | ||
2149 | (char *) &psa.psa_encryption_select - | ||
2150 | (char *) &psa, | ||
2151 | (unsigned char *) &psa. | ||
2152 | psa_encryption_select, 1); | ||
2153 | |||
2154 | mmc_out(base, mmwoff(0, mmw_encr_enable), 0); | ||
2155 | } | ||
2156 | /* update the Wavelan checksum */ | ||
2157 | update_psa_checksum(dev); | ||
2158 | } | ||
2159 | |||
2160 | /* Enable interrupts and restore flags. */ | ||
2161 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2162 | |||
2163 | return ret; | ||
2164 | } | ||
2165 | |||
2166 | /*------------------------------------------------------------------*/ | ||
2167 | /* | ||
2168 | * Wireless Handler : get encryption key | ||
2169 | */ | ||
2170 | static int wavelan_get_encode(struct net_device *dev, | ||
2171 | struct iw_request_info *info, | ||
2172 | union iwreq_data *wrqu, | ||
2173 | char *extra) | ||
2174 | { | ||
2175 | kio_addr_t base = dev->base_addr; | ||
2176 | net_local *lp = netdev_priv(dev); | ||
2177 | psa_t psa; | ||
2178 | unsigned long flags; | ||
2179 | int ret = 0; | ||
2180 | |||
2181 | /* Disable interrupts and save flags. */ | ||
2182 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2183 | |||
2184 | /* Check if encryption is available */ | ||
2185 | if (!mmc_encr(base)) { | ||
2186 | ret = -EOPNOTSUPP; | ||
2187 | } else { | ||
2188 | /* Read the encryption key */ | ||
2189 | psa_read(dev, | ||
2190 | (char *) &psa.psa_encryption_select - | ||
2191 | (char *) &psa, | ||
2192 | (unsigned char *) &psa. | ||
2193 | psa_encryption_select, 1 + 8); | ||
2194 | |||
2195 | /* encryption is enabled ? */ | ||
2196 | if (psa.psa_encryption_select) | ||
2197 | wrqu->encoding.flags = IW_ENCODE_ENABLED; | ||
2198 | else | ||
2199 | wrqu->encoding.flags = IW_ENCODE_DISABLED; | ||
2200 | wrqu->encoding.flags |= mmc_encr(base); | ||
2201 | |||
2202 | /* Copy the key to the user buffer */ | ||
2203 | wrqu->encoding.length = 8; | ||
2204 | memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); | ||
2205 | } | ||
2206 | |||
2207 | /* Enable interrupts and restore flags. */ | ||
2208 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2209 | |||
2210 | return ret; | ||
2211 | } | ||
2212 | |||
2213 | #ifdef WAVELAN_ROAMING_EXT | ||
2214 | /*------------------------------------------------------------------*/ | ||
2215 | /* | ||
2216 | * Wireless Handler : set ESSID (domain) | ||
2217 | */ | ||
2218 | static int wavelan_set_essid(struct net_device *dev, | ||
2219 | struct iw_request_info *info, | ||
2220 | union iwreq_data *wrqu, | ||
2221 | char *extra) | ||
2222 | { | ||
2223 | net_local *lp = netdev_priv(dev); | ||
2224 | unsigned long flags; | ||
2225 | int ret = 0; | ||
2226 | |||
2227 | /* Disable interrupts and save flags. */ | ||
2228 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2229 | |||
2230 | /* Check if disable */ | ||
2231 | if(wrqu->data.flags == 0) | ||
2232 | lp->filter_domains = 0; | ||
2233 | else { | ||
2234 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
2235 | char * endp; | ||
2236 | |||
2237 | /* Terminate the string */ | ||
2238 | memcpy(essid, extra, wrqu->data.length); | ||
2239 | essid[IW_ESSID_MAX_SIZE] = '\0'; | ||
2240 | |||
2241 | #ifdef DEBUG_IOCTL_INFO | ||
2242 | printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); | ||
2243 | #endif /* DEBUG_IOCTL_INFO */ | ||
2244 | |||
2245 | /* Convert to a number (note : Wavelan specific) */ | ||
2246 | lp->domain_id = simple_strtoul(essid, &endp, 16); | ||
2247 | /* Has it worked ? */ | ||
2248 | if(endp > essid) | ||
2249 | lp->filter_domains = 1; | ||
2250 | else { | ||
2251 | lp->filter_domains = 0; | ||
2252 | ret = -EINVAL; | ||
2253 | } | ||
2254 | } | ||
2255 | |||
2256 | /* Enable interrupts and restore flags. */ | ||
2257 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2258 | |||
2259 | return ret; | ||
2260 | } | ||
2261 | |||
2262 | /*------------------------------------------------------------------*/ | ||
2263 | /* | ||
2264 | * Wireless Handler : get ESSID (domain) | ||
2265 | */ | ||
2266 | static int wavelan_get_essid(struct net_device *dev, | ||
2267 | struct iw_request_info *info, | ||
2268 | union iwreq_data *wrqu, | ||
2269 | char *extra) | ||
2270 | { | ||
2271 | net_local *lp = netdev_priv(dev); | ||
2272 | |||
2273 | /* Is the domain ID active ? */ | ||
2274 | wrqu->data.flags = lp->filter_domains; | ||
2275 | |||
2276 | /* Copy Domain ID into a string (Wavelan specific) */ | ||
2277 | /* Sound crazy, be we can't have a snprintf in the kernel !!! */ | ||
2278 | sprintf(extra, "%lX", lp->domain_id); | ||
2279 | extra[IW_ESSID_MAX_SIZE] = '\0'; | ||
2280 | |||
2281 | /* Set the length */ | ||
2282 | wrqu->data.length = strlen(extra) + 1; | ||
2283 | |||
2284 | return 0; | ||
2285 | } | ||
2286 | |||
2287 | /*------------------------------------------------------------------*/ | ||
2288 | /* | ||
2289 | * Wireless Handler : set AP address | ||
2290 | */ | ||
2291 | static int wavelan_set_wap(struct net_device *dev, | ||
2292 | struct iw_request_info *info, | ||
2293 | union iwreq_data *wrqu, | ||
2294 | char *extra) | ||
2295 | { | ||
2296 | #ifdef DEBUG_IOCTL_INFO | ||
2297 | printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", | ||
2298 | wrqu->ap_addr.sa_data[0], | ||
2299 | wrqu->ap_addr.sa_data[1], | ||
2300 | wrqu->ap_addr.sa_data[2], | ||
2301 | wrqu->ap_addr.sa_data[3], | ||
2302 | wrqu->ap_addr.sa_data[4], | ||
2303 | wrqu->ap_addr.sa_data[5]); | ||
2304 | #endif /* DEBUG_IOCTL_INFO */ | ||
2305 | |||
2306 | return -EOPNOTSUPP; | ||
2307 | } | ||
2308 | |||
2309 | /*------------------------------------------------------------------*/ | ||
2310 | /* | ||
2311 | * Wireless Handler : get AP address | ||
2312 | */ | ||
2313 | static int wavelan_get_wap(struct net_device *dev, | ||
2314 | struct iw_request_info *info, | ||
2315 | union iwreq_data *wrqu, | ||
2316 | char *extra) | ||
2317 | { | ||
2318 | /* Should get the real McCoy instead of own Ethernet address */ | ||
2319 | memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); | ||
2320 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | ||
2321 | |||
2322 | return -EOPNOTSUPP; | ||
2323 | } | ||
2324 | #endif /* WAVELAN_ROAMING_EXT */ | ||
2325 | |||
2326 | #ifdef WAVELAN_ROAMING | ||
2327 | /*------------------------------------------------------------------*/ | ||
2328 | /* | ||
2329 | * Wireless Handler : set mode | ||
2330 | */ | ||
2331 | static int wavelan_set_mode(struct net_device *dev, | ||
2332 | struct iw_request_info *info, | ||
2333 | union iwreq_data *wrqu, | ||
2334 | char *extra) | ||
2335 | { | ||
2336 | net_local *lp = netdev_priv(dev); | ||
2337 | unsigned long flags; | ||
2338 | int ret = 0; | ||
2339 | |||
2340 | /* Disable interrupts and save flags. */ | ||
2341 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2342 | |||
2343 | /* Check mode */ | ||
2344 | switch(wrqu->mode) { | ||
2345 | case IW_MODE_ADHOC: | ||
2346 | if(do_roaming) { | ||
2347 | wv_roam_cleanup(dev); | ||
2348 | do_roaming = 0; | ||
2349 | } | ||
2350 | break; | ||
2351 | case IW_MODE_INFRA: | ||
2352 | if(!do_roaming) { | ||
2353 | wv_roam_init(dev); | ||
2354 | do_roaming = 1; | ||
2355 | } | ||
2356 | break; | ||
2357 | default: | ||
2358 | ret = -EINVAL; | ||
2359 | } | ||
2360 | |||
2361 | /* Enable interrupts and restore flags. */ | ||
2362 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2363 | |||
2364 | return ret; | ||
2365 | } | ||
2366 | |||
2367 | /*------------------------------------------------------------------*/ | ||
2368 | /* | ||
2369 | * Wireless Handler : get mode | ||
2370 | */ | ||
2371 | static int wavelan_get_mode(struct net_device *dev, | ||
2372 | struct iw_request_info *info, | ||
2373 | union iwreq_data *wrqu, | ||
2374 | char *extra) | ||
2375 | { | ||
2376 | if(do_roaming) | ||
2377 | wrqu->mode = IW_MODE_INFRA; | ||
2378 | else | ||
2379 | wrqu->mode = IW_MODE_ADHOC; | ||
2380 | |||
2381 | return 0; | ||
2382 | } | ||
2383 | #endif /* WAVELAN_ROAMING */ | ||
2384 | |||
2385 | /*------------------------------------------------------------------*/ | ||
2386 | /* | ||
2387 | * Wireless Handler : get range info | ||
2388 | */ | ||
2389 | static int wavelan_get_range(struct net_device *dev, | ||
2390 | struct iw_request_info *info, | ||
2391 | union iwreq_data *wrqu, | ||
2392 | char *extra) | ||
2393 | { | ||
2394 | kio_addr_t base = dev->base_addr; | ||
2395 | net_local *lp = netdev_priv(dev); | ||
2396 | struct iw_range *range = (struct iw_range *) extra; | ||
2397 | unsigned long flags; | ||
2398 | int ret = 0; | ||
2399 | |||
2400 | /* Set the length (very important for backward compatibility) */ | ||
2401 | wrqu->data.length = sizeof(struct iw_range); | ||
2402 | |||
2403 | /* Set all the info we don't care or don't know about to zero */ | ||
2404 | memset(range, 0, sizeof(struct iw_range)); | ||
2405 | |||
2406 | /* Set the Wireless Extension versions */ | ||
2407 | range->we_version_compiled = WIRELESS_EXT; | ||
2408 | range->we_version_source = 9; | ||
2409 | |||
2410 | /* Set information in the range struct. */ | ||
2411 | range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ | ||
2412 | range->min_nwid = 0x0000; | ||
2413 | range->max_nwid = 0xFFFF; | ||
2414 | |||
2415 | range->sensitivity = 0x3F; | ||
2416 | range->max_qual.qual = MMR_SGNL_QUAL; | ||
2417 | range->max_qual.level = MMR_SIGNAL_LVL; | ||
2418 | range->max_qual.noise = MMR_SILENCE_LVL; | ||
2419 | range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ | ||
2420 | /* Need to get better values for those two */ | ||
2421 | range->avg_qual.level = 30; | ||
2422 | range->avg_qual.noise = 8; | ||
2423 | |||
2424 | range->num_bitrates = 1; | ||
2425 | range->bitrate[0] = 2000000; /* 2 Mb/s */ | ||
2426 | |||
2427 | /* Event capability (kernel + driver) */ | ||
2428 | range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | | ||
2429 | IW_EVENT_CAPA_MASK(0x8B04) | | ||
2430 | IW_EVENT_CAPA_MASK(0x8B06)); | ||
2431 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
2432 | |||
2433 | /* Disable interrupts and save flags. */ | ||
2434 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2435 | |||
2436 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
2437 | if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
2438 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
2439 | range->num_channels = 10; | ||
2440 | range->num_frequency = wv_frequency_list(base, range->freq, | ||
2441 | IW_MAX_FREQUENCIES); | ||
2442 | } else | ||
2443 | range->num_channels = range->num_frequency = 0; | ||
2444 | |||
2445 | /* Encryption supported ? */ | ||
2446 | if (mmc_encr(base)) { | ||
2447 | range->encoding_size[0] = 8; /* DES = 64 bits key */ | ||
2448 | range->num_encoding_sizes = 1; | ||
2449 | range->max_encoding_tokens = 1; /* Only one key possible */ | ||
2450 | } else { | ||
2451 | range->num_encoding_sizes = 0; | ||
2452 | range->max_encoding_tokens = 0; | ||
2453 | } | ||
2454 | |||
2455 | /* Enable interrupts and restore flags. */ | ||
2456 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2457 | |||
2458 | return ret; | ||
2459 | } | ||
2460 | |||
2461 | /*------------------------------------------------------------------*/ | ||
2462 | /* | ||
2463 | * Wireless Private Handler : set quality threshold | ||
2464 | */ | ||
2465 | static int wavelan_set_qthr(struct net_device *dev, | ||
2466 | struct iw_request_info *info, | ||
2467 | union iwreq_data *wrqu, | ||
2468 | char *extra) | ||
2469 | { | ||
2470 | kio_addr_t base = dev->base_addr; | ||
2471 | net_local *lp = netdev_priv(dev); | ||
2472 | psa_t psa; | ||
2473 | unsigned long flags; | ||
2474 | |||
2475 | /* Disable interrupts and save flags. */ | ||
2476 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2477 | |||
2478 | psa.psa_quality_thr = *(extra) & 0x0F; | ||
2479 | psa_write(dev, | ||
2480 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2481 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2482 | /* update the Wavelan checksum */ | ||
2483 | update_psa_checksum(dev); | ||
2484 | mmc_out(base, mmwoff(0, mmw_quality_thr), | ||
2485 | psa.psa_quality_thr); | ||
2486 | |||
2487 | /* Enable interrupts and restore flags. */ | ||
2488 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2489 | |||
2490 | return 0; | ||
2491 | } | ||
2492 | |||
2493 | /*------------------------------------------------------------------*/ | ||
2494 | /* | ||
2495 | * Wireless Private Handler : get quality threshold | ||
2496 | */ | ||
2497 | static int wavelan_get_qthr(struct net_device *dev, | ||
2498 | struct iw_request_info *info, | ||
2499 | union iwreq_data *wrqu, | ||
2500 | char *extra) | ||
2501 | { | ||
2502 | net_local *lp = netdev_priv(dev); | ||
2503 | psa_t psa; | ||
2504 | unsigned long flags; | ||
2505 | |||
2506 | /* Disable interrupts and save flags. */ | ||
2507 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2508 | |||
2509 | psa_read(dev, | ||
2510 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2511 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2512 | *(extra) = psa.psa_quality_thr & 0x0F; | ||
2513 | |||
2514 | /* Enable interrupts and restore flags. */ | ||
2515 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2516 | |||
2517 | return 0; | ||
2518 | } | ||
2519 | |||
2520 | #ifdef WAVELAN_ROAMING | ||
2521 | /*------------------------------------------------------------------*/ | ||
2522 | /* | ||
2523 | * Wireless Private Handler : set roaming | ||
2524 | */ | ||
2525 | static int wavelan_set_roam(struct net_device *dev, | ||
2526 | struct iw_request_info *info, | ||
2527 | union iwreq_data *wrqu, | ||
2528 | char *extra) | ||
2529 | { | ||
2530 | net_local *lp = netdev_priv(dev); | ||
2531 | unsigned long flags; | ||
2532 | |||
2533 | /* Disable interrupts and save flags. */ | ||
2534 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2535 | |||
2536 | /* Note : should check if user == root */ | ||
2537 | if(do_roaming && (*extra)==0) | ||
2538 | wv_roam_cleanup(dev); | ||
2539 | else if(do_roaming==0 && (*extra)!=0) | ||
2540 | wv_roam_init(dev); | ||
2541 | |||
2542 | do_roaming = (*extra); | ||
2543 | |||
2544 | /* Enable interrupts and restore flags. */ | ||
2545 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2546 | |||
2547 | return 0; | ||
2548 | } | ||
2549 | |||
2550 | /*------------------------------------------------------------------*/ | ||
2551 | /* | ||
2552 | * Wireless Private Handler : get quality threshold | ||
2553 | */ | ||
2554 | static int wavelan_get_roam(struct net_device *dev, | ||
2555 | struct iw_request_info *info, | ||
2556 | union iwreq_data *wrqu, | ||
2557 | char *extra) | ||
2558 | { | ||
2559 | *(extra) = do_roaming; | ||
2560 | |||
2561 | return 0; | ||
2562 | } | ||
2563 | #endif /* WAVELAN_ROAMING */ | ||
2564 | |||
2565 | #ifdef HISTOGRAM | ||
2566 | /*------------------------------------------------------------------*/ | ||
2567 | /* | ||
2568 | * Wireless Private Handler : set histogram | ||
2569 | */ | ||
2570 | static int wavelan_set_histo(struct net_device *dev, | ||
2571 | struct iw_request_info *info, | ||
2572 | union iwreq_data *wrqu, | ||
2573 | char *extra) | ||
2574 | { | ||
2575 | net_local *lp = netdev_priv(dev); | ||
2576 | |||
2577 | /* Check the number of intervals. */ | ||
2578 | if (wrqu->data.length > 16) { | ||
2579 | return(-E2BIG); | ||
2580 | } | ||
2581 | |||
2582 | /* Disable histo while we copy the addresses. | ||
2583 | * As we don't disable interrupts, we need to do this */ | ||
2584 | lp->his_number = 0; | ||
2585 | |||
2586 | /* Are there ranges to copy? */ | ||
2587 | if (wrqu->data.length > 0) { | ||
2588 | /* Copy interval ranges to the driver */ | ||
2589 | memcpy(lp->his_range, extra, wrqu->data.length); | ||
2590 | |||
2591 | { | ||
2592 | int i; | ||
2593 | printk(KERN_DEBUG "Histo :"); | ||
2594 | for(i = 0; i < wrqu->data.length; i++) | ||
2595 | printk(" %d", lp->his_range[i]); | ||
2596 | printk("\n"); | ||
2597 | } | ||
2598 | |||
2599 | /* Reset result structure. */ | ||
2600 | memset(lp->his_sum, 0x00, sizeof(long) * 16); | ||
2601 | } | ||
2602 | |||
2603 | /* Now we can set the number of ranges */ | ||
2604 | lp->his_number = wrqu->data.length; | ||
2605 | |||
2606 | return(0); | ||
2607 | } | ||
2608 | |||
2609 | /*------------------------------------------------------------------*/ | ||
2610 | /* | ||
2611 | * Wireless Private Handler : get histogram | ||
2612 | */ | ||
2613 | static int wavelan_get_histo(struct net_device *dev, | ||
2614 | struct iw_request_info *info, | ||
2615 | union iwreq_data *wrqu, | ||
2616 | char *extra) | ||
2617 | { | ||
2618 | net_local *lp = netdev_priv(dev); | ||
2619 | |||
2620 | /* Set the number of intervals. */ | ||
2621 | wrqu->data.length = lp->his_number; | ||
2622 | |||
2623 | /* Give back the distribution statistics */ | ||
2624 | if(lp->his_number > 0) | ||
2625 | memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); | ||
2626 | |||
2627 | return(0); | ||
2628 | } | ||
2629 | #endif /* HISTOGRAM */ | ||
2630 | |||
2631 | /*------------------------------------------------------------------*/ | ||
2632 | /* | ||
2633 | * Structures to export the Wireless Handlers | ||
2634 | */ | ||
2635 | |||
2636 | static const struct iw_priv_args wavelan_private_args[] = { | ||
2637 | /*{ cmd, set_args, get_args, name } */ | ||
2638 | { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, | ||
2639 | { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, | ||
2640 | { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" }, | ||
2641 | { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, | ||
2642 | { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, | ||
2643 | { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, | ||
2644 | }; | ||
2645 | |||
2646 | static const iw_handler wavelan_handler[] = | ||
2647 | { | ||
2648 | NULL, /* SIOCSIWNAME */ | ||
2649 | wavelan_get_name, /* SIOCGIWNAME */ | ||
2650 | wavelan_set_nwid, /* SIOCSIWNWID */ | ||
2651 | wavelan_get_nwid, /* SIOCGIWNWID */ | ||
2652 | wavelan_set_freq, /* SIOCSIWFREQ */ | ||
2653 | wavelan_get_freq, /* SIOCGIWFREQ */ | ||
2654 | #ifdef WAVELAN_ROAMING | ||
2655 | wavelan_set_mode, /* SIOCSIWMODE */ | ||
2656 | wavelan_get_mode, /* SIOCGIWMODE */ | ||
2657 | #else /* WAVELAN_ROAMING */ | ||
2658 | NULL, /* SIOCSIWMODE */ | ||
2659 | NULL, /* SIOCGIWMODE */ | ||
2660 | #endif /* WAVELAN_ROAMING */ | ||
2661 | wavelan_set_sens, /* SIOCSIWSENS */ | ||
2662 | wavelan_get_sens, /* SIOCGIWSENS */ | ||
2663 | NULL, /* SIOCSIWRANGE */ | ||
2664 | wavelan_get_range, /* SIOCGIWRANGE */ | ||
2665 | NULL, /* SIOCSIWPRIV */ | ||
2666 | NULL, /* SIOCGIWPRIV */ | ||
2667 | NULL, /* SIOCSIWSTATS */ | ||
2668 | NULL, /* SIOCGIWSTATS */ | ||
2669 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2670 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2671 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2672 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2673 | #ifdef WAVELAN_ROAMING_EXT | ||
2674 | wavelan_set_wap, /* SIOCSIWAP */ | ||
2675 | wavelan_get_wap, /* SIOCGIWAP */ | ||
2676 | NULL, /* -- hole -- */ | ||
2677 | NULL, /* SIOCGIWAPLIST */ | ||
2678 | NULL, /* -- hole -- */ | ||
2679 | NULL, /* -- hole -- */ | ||
2680 | wavelan_set_essid, /* SIOCSIWESSID */ | ||
2681 | wavelan_get_essid, /* SIOCGIWESSID */ | ||
2682 | #else /* WAVELAN_ROAMING_EXT */ | ||
2683 | NULL, /* SIOCSIWAP */ | ||
2684 | NULL, /* SIOCGIWAP */ | ||
2685 | NULL, /* -- hole -- */ | ||
2686 | NULL, /* SIOCGIWAPLIST */ | ||
2687 | NULL, /* -- hole -- */ | ||
2688 | NULL, /* -- hole -- */ | ||
2689 | NULL, /* SIOCSIWESSID */ | ||
2690 | NULL, /* SIOCGIWESSID */ | ||
2691 | #endif /* WAVELAN_ROAMING_EXT */ | ||
2692 | NULL, /* SIOCSIWNICKN */ | ||
2693 | NULL, /* SIOCGIWNICKN */ | ||
2694 | NULL, /* -- hole -- */ | ||
2695 | NULL, /* -- hole -- */ | ||
2696 | NULL, /* SIOCSIWRATE */ | ||
2697 | NULL, /* SIOCGIWRATE */ | ||
2698 | NULL, /* SIOCSIWRTS */ | ||
2699 | NULL, /* SIOCGIWRTS */ | ||
2700 | NULL, /* SIOCSIWFRAG */ | ||
2701 | NULL, /* SIOCGIWFRAG */ | ||
2702 | NULL, /* SIOCSIWTXPOW */ | ||
2703 | NULL, /* SIOCGIWTXPOW */ | ||
2704 | NULL, /* SIOCSIWRETRY */ | ||
2705 | NULL, /* SIOCGIWRETRY */ | ||
2706 | wavelan_set_encode, /* SIOCSIWENCODE */ | ||
2707 | wavelan_get_encode, /* SIOCGIWENCODE */ | ||
2708 | }; | ||
2709 | |||
2710 | static const iw_handler wavelan_private_handler[] = | ||
2711 | { | ||
2712 | wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ | ||
2713 | wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ | ||
2714 | #ifdef WAVELAN_ROAMING | ||
2715 | wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */ | ||
2716 | wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */ | ||
2717 | #else /* WAVELAN_ROAMING */ | ||
2718 | NULL, /* SIOCIWFIRSTPRIV + 2 */ | ||
2719 | NULL, /* SIOCIWFIRSTPRIV + 3 */ | ||
2720 | #endif /* WAVELAN_ROAMING */ | ||
2721 | #ifdef HISTOGRAM | ||
2722 | wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */ | ||
2723 | wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */ | ||
2724 | #endif /* HISTOGRAM */ | ||
2725 | }; | ||
2726 | |||
2727 | static const struct iw_handler_def wavelan_handler_def = | ||
2728 | { | ||
2729 | .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), | ||
2730 | .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), | ||
2731 | .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), | ||
2732 | .standard = wavelan_handler, | ||
2733 | .private = wavelan_private_handler, | ||
2734 | .private_args = wavelan_private_args, | ||
2735 | .get_wireless_stats = wavelan_get_wireless_stats, | ||
2736 | }; | ||
2737 | |||
2738 | /*------------------------------------------------------------------*/ | ||
2739 | /* | ||
2740 | * Get wireless statistics | ||
2741 | * Called by /proc/net/wireless... | ||
2742 | */ | ||
2743 | static iw_stats * | ||
2744 | wavelan_get_wireless_stats(struct net_device * dev) | ||
2745 | { | ||
2746 | kio_addr_t base = dev->base_addr; | ||
2747 | net_local * lp = netdev_priv(dev); | ||
2748 | mmr_t m; | ||
2749 | iw_stats * wstats; | ||
2750 | unsigned long flags; | ||
2751 | |||
2752 | #ifdef DEBUG_IOCTL_TRACE | ||
2753 | printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); | ||
2754 | #endif | ||
2755 | |||
2756 | /* Disable interrupts & save flags */ | ||
2757 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2758 | |||
2759 | wstats = &lp->wstats; | ||
2760 | |||
2761 | /* Get data from the mmc */ | ||
2762 | mmc_out(base, mmwoff(0, mmw_freeze), 1); | ||
2763 | |||
2764 | mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); | ||
2765 | mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); | ||
2766 | mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); | ||
2767 | |||
2768 | mmc_out(base, mmwoff(0, mmw_freeze), 0); | ||
2769 | |||
2770 | /* Copy data to wireless stuff */ | ||
2771 | wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; | ||
2772 | wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; | ||
2773 | wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; | ||
2774 | wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; | ||
2775 | wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | | ||
2776 | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | | ||
2777 | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); | ||
2778 | wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
2779 | wstats->discard.code = 0L; | ||
2780 | wstats->discard.misc = 0L; | ||
2781 | |||
2782 | /* ReEnable interrupts & restore flags */ | ||
2783 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2784 | |||
2785 | #ifdef DEBUG_IOCTL_TRACE | ||
2786 | printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); | ||
2787 | #endif | ||
2788 | return &lp->wstats; | ||
2789 | } | ||
2790 | #endif /* WIRELESS_EXT */ | ||
2791 | |||
2792 | /************************* PACKET RECEPTION *************************/ | ||
2793 | /* | ||
2794 | * This part deal with receiving the packets. | ||
2795 | * The interrupt handler get an interrupt when a packet has been | ||
2796 | * successfully received and called this part... | ||
2797 | */ | ||
2798 | |||
2799 | /*------------------------------------------------------------------*/ | ||
2800 | /* | ||
2801 | * Calculate the starting address of the frame pointed to by the receive | ||
2802 | * frame pointer and verify that the frame seem correct | ||
2803 | * (called by wv_packet_rcv()) | ||
2804 | */ | ||
2805 | static inline int | ||
2806 | wv_start_of_frame(struct net_device * dev, | ||
2807 | int rfp, /* end of frame */ | ||
2808 | int wrap) /* start of buffer */ | ||
2809 | { | ||
2810 | kio_addr_t base = dev->base_addr; | ||
2811 | int rp; | ||
2812 | int len; | ||
2813 | |||
2814 | rp = (rfp - 5 + RX_SIZE) % RX_SIZE; | ||
2815 | outb(rp & 0xff, PIORL(base)); | ||
2816 | outb(((rp >> 8) & PIORH_MASK), PIORH(base)); | ||
2817 | len = inb(PIOP(base)); | ||
2818 | len |= inb(PIOP(base)) << 8; | ||
2819 | |||
2820 | /* Sanity checks on size */ | ||
2821 | /* Frame too big */ | ||
2822 | if(len > MAXDATAZ + 100) | ||
2823 | { | ||
2824 | #ifdef DEBUG_RX_ERROR | ||
2825 | printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", | ||
2826 | dev->name, rfp, len); | ||
2827 | #endif | ||
2828 | return(-1); | ||
2829 | } | ||
2830 | |||
2831 | /* Frame too short */ | ||
2832 | if(len < 7) | ||
2833 | { | ||
2834 | #ifdef DEBUG_RX_ERROR | ||
2835 | printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", | ||
2836 | dev->name, rfp, len); | ||
2837 | #endif | ||
2838 | return(-1); | ||
2839 | } | ||
2840 | |||
2841 | /* Wrap around buffer */ | ||
2842 | if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ | ||
2843 | { | ||
2844 | #ifdef DEBUG_RX_ERROR | ||
2845 | printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", | ||
2846 | dev->name, wrap, rfp, len); | ||
2847 | #endif | ||
2848 | return(-1); | ||
2849 | } | ||
2850 | |||
2851 | return((rp - len + RX_SIZE) % RX_SIZE); | ||
2852 | } /* wv_start_of_frame */ | ||
2853 | |||
2854 | /*------------------------------------------------------------------*/ | ||
2855 | /* | ||
2856 | * This routine does the actual copy of data (including the ethernet | ||
2857 | * header structure) from the WaveLAN card to an sk_buff chain that | ||
2858 | * will be passed up to the network interface layer. NOTE: We | ||
2859 | * currently don't handle trailer protocols (neither does the rest of | ||
2860 | * the network interface), so if that is needed, it will (at least in | ||
2861 | * part) be added here. The contents of the receive ring buffer are | ||
2862 | * copied to a message chain that is then passed to the kernel. | ||
2863 | * | ||
2864 | * Note: if any errors occur, the packet is "dropped on the floor" | ||
2865 | * (called by wv_packet_rcv()) | ||
2866 | */ | ||
2867 | static inline void | ||
2868 | wv_packet_read(struct net_device * dev, | ||
2869 | int fd_p, | ||
2870 | int sksize) | ||
2871 | { | ||
2872 | net_local * lp = netdev_priv(dev); | ||
2873 | struct sk_buff * skb; | ||
2874 | |||
2875 | #ifdef DEBUG_RX_TRACE | ||
2876 | printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", | ||
2877 | dev->name, fd_p, sksize); | ||
2878 | #endif | ||
2879 | |||
2880 | /* Allocate some buffer for the new packet */ | ||
2881 | if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) | ||
2882 | { | ||
2883 | #ifdef DEBUG_RX_ERROR | ||
2884 | printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", | ||
2885 | dev->name, sksize); | ||
2886 | #endif | ||
2887 | lp->stats.rx_dropped++; | ||
2888 | /* | ||
2889 | * Not only do we want to return here, but we also need to drop the | ||
2890 | * packet on the floor to clear the interrupt. | ||
2891 | */ | ||
2892 | return; | ||
2893 | } | ||
2894 | |||
2895 | skb->dev = dev; | ||
2896 | |||
2897 | skb_reserve(skb, 2); | ||
2898 | fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); | ||
2899 | skb->protocol = eth_type_trans(skb, dev); | ||
2900 | |||
2901 | #ifdef DEBUG_RX_INFO | ||
2902 | wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); | ||
2903 | #endif /* DEBUG_RX_INFO */ | ||
2904 | |||
2905 | /* Statistics gathering & stuff associated. | ||
2906 | * It seem a bit messy with all the define, but it's really simple... */ | ||
2907 | if( | ||
2908 | #ifdef IW_WIRELESS_SPY | ||
2909 | (lp->spy_data.spy_number > 0) || | ||
2910 | #endif /* IW_WIRELESS_SPY */ | ||
2911 | #ifdef HISTOGRAM | ||
2912 | (lp->his_number > 0) || | ||
2913 | #endif /* HISTOGRAM */ | ||
2914 | #ifdef WAVELAN_ROAMING | ||
2915 | (do_roaming) || | ||
2916 | #endif /* WAVELAN_ROAMING */ | ||
2917 | 0) | ||
2918 | { | ||
2919 | u_char stats[3]; /* Signal level, Noise level, Signal quality */ | ||
2920 | |||
2921 | /* read signal level, silence level and signal quality bytes */ | ||
2922 | fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, | ||
2923 | stats, 3); | ||
2924 | #ifdef DEBUG_RX_INFO | ||
2925 | printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", | ||
2926 | dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); | ||
2927 | #endif | ||
2928 | |||
2929 | #ifdef WAVELAN_ROAMING | ||
2930 | if(do_roaming) | ||
2931 | if(WAVELAN_BEACON(skb->data)) | ||
2932 | wl_roam_gather(dev, skb->data, stats); | ||
2933 | #endif /* WAVELAN_ROAMING */ | ||
2934 | |||
2935 | #ifdef WIRELESS_SPY | ||
2936 | wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); | ||
2937 | #endif /* WIRELESS_SPY */ | ||
2938 | #ifdef HISTOGRAM | ||
2939 | wl_his_gather(dev, stats); | ||
2940 | #endif /* HISTOGRAM */ | ||
2941 | } | ||
2942 | |||
2943 | /* | ||
2944 | * Hand the packet to the Network Module | ||
2945 | */ | ||
2946 | netif_rx(skb); | ||
2947 | |||
2948 | /* Keep stats up to date */ | ||
2949 | dev->last_rx = jiffies; | ||
2950 | lp->stats.rx_packets++; | ||
2951 | lp->stats.rx_bytes += sksize; | ||
2952 | |||
2953 | #ifdef DEBUG_RX_TRACE | ||
2954 | printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); | ||
2955 | #endif | ||
2956 | return; | ||
2957 | } | ||
2958 | |||
2959 | /*------------------------------------------------------------------*/ | ||
2960 | /* | ||
2961 | * This routine is called by the interrupt handler to initiate a | ||
2962 | * packet transfer from the card to the network interface layer above | ||
2963 | * this driver. This routine checks if a buffer has been successfully | ||
2964 | * received by the WaveLAN card. If so, the routine wv_packet_read is | ||
2965 | * called to do the actual transfer of the card's data including the | ||
2966 | * ethernet header into a packet consisting of an sk_buff chain. | ||
2967 | * (called by wavelan_interrupt()) | ||
2968 | * Note : the spinlock is already grabbed for us and irq are disabled. | ||
2969 | */ | ||
2970 | static inline void | ||
2971 | wv_packet_rcv(struct net_device * dev) | ||
2972 | { | ||
2973 | kio_addr_t base = dev->base_addr; | ||
2974 | net_local * lp = netdev_priv(dev); | ||
2975 | int newrfp; | ||
2976 | int rp; | ||
2977 | int len; | ||
2978 | int f_start; | ||
2979 | int status; | ||
2980 | int i593_rfp; | ||
2981 | int stat_ptr; | ||
2982 | u_char c[4]; | ||
2983 | |||
2984 | #ifdef DEBUG_RX_TRACE | ||
2985 | printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); | ||
2986 | #endif | ||
2987 | |||
2988 | /* Get the new receive frame pointer from the i82593 chip */ | ||
2989 | outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); | ||
2990 | i593_rfp = inb(LCSR(base)); | ||
2991 | i593_rfp |= inb(LCSR(base)) << 8; | ||
2992 | i593_rfp %= RX_SIZE; | ||
2993 | |||
2994 | /* Get the new receive frame pointer from the WaveLAN card. | ||
2995 | * It is 3 bytes more than the increment of the i82593 receive | ||
2996 | * frame pointer, for each packet. This is because it includes the | ||
2997 | * 3 roaming bytes added by the mmc. | ||
2998 | */ | ||
2999 | newrfp = inb(RPLL(base)); | ||
3000 | newrfp |= inb(RPLH(base)) << 8; | ||
3001 | newrfp %= RX_SIZE; | ||
3002 | |||
3003 | #ifdef DEBUG_RX_INFO | ||
3004 | printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", | ||
3005 | dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); | ||
3006 | #endif | ||
3007 | |||
3008 | #ifdef DEBUG_RX_ERROR | ||
3009 | /* If no new frame pointer... */ | ||
3010 | if(lp->overrunning || newrfp == lp->rfp) | ||
3011 | printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", | ||
3012 | dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); | ||
3013 | #endif | ||
3014 | |||
3015 | /* Read all frames (packets) received */ | ||
3016 | while(newrfp != lp->rfp) | ||
3017 | { | ||
3018 | /* A frame is composed of the packet, followed by a status word, | ||
3019 | * the length of the frame (word) and the mmc info (SNR & qual). | ||
3020 | * It's because the length is at the end that we can only scan | ||
3021 | * frames backward. */ | ||
3022 | |||
3023 | /* Find the first frame by skipping backwards over the frames */ | ||
3024 | rp = newrfp; /* End of last frame */ | ||
3025 | while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && | ||
3026 | (f_start != -1)) | ||
3027 | rp = f_start; | ||
3028 | |||
3029 | /* If we had a problem */ | ||
3030 | if(f_start == -1) | ||
3031 | { | ||
3032 | #ifdef DEBUG_RX_ERROR | ||
3033 | printk(KERN_INFO "wavelan_cs: cannot find start of frame "); | ||
3034 | printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", | ||
3035 | i593_rfp, lp->stop, newrfp, lp->rfp); | ||
3036 | #endif | ||
3037 | lp->rfp = rp; /* Get to the last usable frame */ | ||
3038 | continue; | ||
3039 | } | ||
3040 | |||
3041 | /* f_start point to the beggining of the first frame received | ||
3042 | * and rp to the beggining of the next one */ | ||
3043 | |||
3044 | /* Read status & length of the frame */ | ||
3045 | stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; | ||
3046 | stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); | ||
3047 | status = c[0] | (c[1] << 8); | ||
3048 | len = c[2] | (c[3] << 8); | ||
3049 | |||
3050 | /* Check status */ | ||
3051 | if((status & RX_RCV_OK) != RX_RCV_OK) | ||
3052 | { | ||
3053 | lp->stats.rx_errors++; | ||
3054 | if(status & RX_NO_SFD) | ||
3055 | lp->stats.rx_frame_errors++; | ||
3056 | if(status & RX_CRC_ERR) | ||
3057 | lp->stats.rx_crc_errors++; | ||
3058 | if(status & RX_OVRRUN) | ||
3059 | lp->stats.rx_over_errors++; | ||
3060 | |||
3061 | #ifdef DEBUG_RX_FAIL | ||
3062 | printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", | ||
3063 | dev->name, status); | ||
3064 | #endif | ||
3065 | } | ||
3066 | else | ||
3067 | /* Read the packet and transmit to Linux */ | ||
3068 | wv_packet_read(dev, f_start, len - 2); | ||
3069 | |||
3070 | /* One frame has been processed, skip it */ | ||
3071 | lp->rfp = rp; | ||
3072 | } | ||
3073 | |||
3074 | /* | ||
3075 | * Update the frame stop register, but set it to less than | ||
3076 | * the full 8K to allow space for 3 bytes of signal strength | ||
3077 | * per packet. | ||
3078 | */ | ||
3079 | lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; | ||
3080 | outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); | ||
3081 | outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); | ||
3082 | outb(OP1_SWIT_TO_PORT_0, LCCR(base)); | ||
3083 | |||
3084 | #ifdef DEBUG_RX_TRACE | ||
3085 | printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); | ||
3086 | #endif | ||
3087 | } | ||
3088 | |||
3089 | /*********************** PACKET TRANSMISSION ***********************/ | ||
3090 | /* | ||
3091 | * This part deal with sending packet through the wavelan | ||
3092 | * We copy the packet to the send buffer and then issue the send | ||
3093 | * command to the i82593. The result of this operation will be | ||
3094 | * checked in wavelan_interrupt() | ||
3095 | */ | ||
3096 | |||
3097 | /*------------------------------------------------------------------*/ | ||
3098 | /* | ||
3099 | * This routine fills in the appropriate registers and memory | ||
3100 | * locations on the WaveLAN card and starts the card off on | ||
3101 | * the transmit. | ||
3102 | * (called in wavelan_packet_xmit()) | ||
3103 | */ | ||
3104 | static inline void | ||
3105 | wv_packet_write(struct net_device * dev, | ||
3106 | void * buf, | ||
3107 | short length) | ||
3108 | { | ||
3109 | net_local * lp = netdev_priv(dev); | ||
3110 | kio_addr_t base = dev->base_addr; | ||
3111 | unsigned long flags; | ||
3112 | int clen = length; | ||
3113 | register u_short xmtdata_base = TX_BASE; | ||
3114 | |||
3115 | #ifdef DEBUG_TX_TRACE | ||
3116 | printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); | ||
3117 | #endif | ||
3118 | |||
3119 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3120 | |||
3121 | /* Write the length of data buffer followed by the buffer */ | ||
3122 | outb(xmtdata_base & 0xff, PIORL(base)); | ||
3123 | outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3124 | outb(clen & 0xff, PIOP(base)); /* lsb */ | ||
3125 | outb(clen >> 8, PIOP(base)); /* msb */ | ||
3126 | |||
3127 | /* Send the data */ | ||
3128 | outsb(PIOP(base), buf, clen); | ||
3129 | |||
3130 | /* Indicate end of transmit chain */ | ||
3131 | outb(OP0_NOP, PIOP(base)); | ||
3132 | /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ | ||
3133 | outb(OP0_NOP, PIOP(base)); | ||
3134 | |||
3135 | /* Reset the transmit DMA pointer */ | ||
3136 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3137 | hacr_write(base, HACR_DEFAULT); | ||
3138 | /* Send the transmit command */ | ||
3139 | wv_82593_cmd(dev, "wv_packet_write(): transmit", | ||
3140 | OP0_TRANSMIT, SR0_NO_RESULT); | ||
3141 | |||
3142 | /* Make sure the watchdog will keep quiet for a while */ | ||
3143 | dev->trans_start = jiffies; | ||
3144 | |||
3145 | /* Keep stats up to date */ | ||
3146 | lp->stats.tx_bytes += length; | ||
3147 | |||
3148 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3149 | |||
3150 | #ifdef DEBUG_TX_INFO | ||
3151 | wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); | ||
3152 | #endif /* DEBUG_TX_INFO */ | ||
3153 | |||
3154 | #ifdef DEBUG_TX_TRACE | ||
3155 | printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); | ||
3156 | #endif | ||
3157 | } | ||
3158 | |||
3159 | /*------------------------------------------------------------------*/ | ||
3160 | /* | ||
3161 | * This routine is called when we want to send a packet (NET3 callback) | ||
3162 | * In this routine, we check if the harware is ready to accept | ||
3163 | * the packet. We also prevent reentrance. Then, we call the function | ||
3164 | * to send the packet... | ||
3165 | */ | ||
3166 | static int | ||
3167 | wavelan_packet_xmit(struct sk_buff * skb, | ||
3168 | struct net_device * dev) | ||
3169 | { | ||
3170 | net_local * lp = netdev_priv(dev); | ||
3171 | unsigned long flags; | ||
3172 | |||
3173 | #ifdef DEBUG_TX_TRACE | ||
3174 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, | ||
3175 | (unsigned) skb); | ||
3176 | #endif | ||
3177 | |||
3178 | /* | ||
3179 | * Block a timer-based transmit from overlapping a previous transmit. | ||
3180 | * In other words, prevent reentering this routine. | ||
3181 | */ | ||
3182 | netif_stop_queue(dev); | ||
3183 | |||
3184 | /* If somebody has asked to reconfigure the controller, | ||
3185 | * we can do it now */ | ||
3186 | if(lp->reconfig_82593) | ||
3187 | { | ||
3188 | spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ | ||
3189 | wv_82593_config(dev); | ||
3190 | spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ | ||
3191 | /* Note : the configure procedure was totally synchronous, | ||
3192 | * so the Tx buffer is now free */ | ||
3193 | } | ||
3194 | |||
3195 | #ifdef DEBUG_TX_ERROR | ||
3196 | if (skb->next) | ||
3197 | printk(KERN_INFO "skb has next\n"); | ||
3198 | #endif | ||
3199 | |||
3200 | /* Check if we need some padding */ | ||
3201 | /* Note : on wireless the propagation time is in the order of 1us, | ||
3202 | * and we don't have the Ethernet specific requirement of beeing | ||
3203 | * able to detect collisions, therefore in theory we don't really | ||
3204 | * need to pad. Jean II */ | ||
3205 | if (skb->len < ETH_ZLEN) { | ||
3206 | skb = skb_padto(skb, ETH_ZLEN); | ||
3207 | if (skb == NULL) | ||
3208 | return 0; | ||
3209 | } | ||
3210 | |||
3211 | wv_packet_write(dev, skb->data, skb->len); | ||
3212 | |||
3213 | dev_kfree_skb(skb); | ||
3214 | |||
3215 | #ifdef DEBUG_TX_TRACE | ||
3216 | printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); | ||
3217 | #endif | ||
3218 | return(0); | ||
3219 | } | ||
3220 | |||
3221 | /********************** HARDWARE CONFIGURATION **********************/ | ||
3222 | /* | ||
3223 | * This part do the real job of starting and configuring the hardware. | ||
3224 | */ | ||
3225 | |||
3226 | /*------------------------------------------------------------------*/ | ||
3227 | /* | ||
3228 | * Routine to initialize the Modem Management Controller. | ||
3229 | * (called by wv_hw_config()) | ||
3230 | */ | ||
3231 | static inline int | ||
3232 | wv_mmc_init(struct net_device * dev) | ||
3233 | { | ||
3234 | kio_addr_t base = dev->base_addr; | ||
3235 | psa_t psa; | ||
3236 | mmw_t m; | ||
3237 | int configured; | ||
3238 | int i; /* Loop counter */ | ||
3239 | |||
3240 | #ifdef DEBUG_CONFIG_TRACE | ||
3241 | printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); | ||
3242 | #endif | ||
3243 | |||
3244 | /* Read the parameter storage area */ | ||
3245 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
3246 | |||
3247 | /* | ||
3248 | * Check the first three octets of the MAC addr for the manufacturer's code. | ||
3249 | * Note: If you get the error message below, you've got a | ||
3250 | * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on | ||
3251 | * how to configure your card... | ||
3252 | */ | ||
3253 | for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) | ||
3254 | if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && | ||
3255 | (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && | ||
3256 | (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) | ||
3257 | break; | ||
3258 | |||
3259 | /* If we have not found it... */ | ||
3260 | if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3)) | ||
3261 | { | ||
3262 | #ifdef DEBUG_CONFIG_ERRORS | ||
3263 | printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", | ||
3264 | dev->name, psa.psa_univ_mac_addr[0], | ||
3265 | psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); | ||
3266 | #endif | ||
3267 | return FALSE; | ||
3268 | } | ||
3269 | |||
3270 | /* Get the MAC address */ | ||
3271 | memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); | ||
3272 | |||
3273 | #ifdef USE_PSA_CONFIG | ||
3274 | configured = psa.psa_conf_status & 1; | ||
3275 | #else | ||
3276 | configured = 0; | ||
3277 | #endif | ||
3278 | |||
3279 | /* Is the PSA is not configured */ | ||
3280 | if(!configured) | ||
3281 | { | ||
3282 | /* User will be able to configure NWID after (with iwconfig) */ | ||
3283 | psa.psa_nwid[0] = 0; | ||
3284 | psa.psa_nwid[1] = 0; | ||
3285 | |||
3286 | /* As NWID is not set : no NWID checking */ | ||
3287 | psa.psa_nwid_select = 0; | ||
3288 | |||
3289 | /* Disable encryption */ | ||
3290 | psa.psa_encryption_select = 0; | ||
3291 | |||
3292 | /* Set to standard values | ||
3293 | * 0x04 for AT, | ||
3294 | * 0x01 for MCA, | ||
3295 | * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) | ||
3296 | */ | ||
3297 | if (psa.psa_comp_number & 1) | ||
3298 | psa.psa_thr_pre_set = 0x01; | ||
3299 | else | ||
3300 | psa.psa_thr_pre_set = 0x04; | ||
3301 | psa.psa_quality_thr = 0x03; | ||
3302 | |||
3303 | /* It is configured */ | ||
3304 | psa.psa_conf_status |= 1; | ||
3305 | |||
3306 | #ifdef USE_PSA_CONFIG | ||
3307 | /* Write the psa */ | ||
3308 | psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, | ||
3309 | (unsigned char *)psa.psa_nwid, 4); | ||
3310 | psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, | ||
3311 | (unsigned char *)&psa.psa_thr_pre_set, 1); | ||
3312 | psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, | ||
3313 | (unsigned char *)&psa.psa_quality_thr, 1); | ||
3314 | psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, | ||
3315 | (unsigned char *)&psa.psa_conf_status, 1); | ||
3316 | /* update the Wavelan checksum */ | ||
3317 | update_psa_checksum(dev); | ||
3318 | #endif /* USE_PSA_CONFIG */ | ||
3319 | } | ||
3320 | |||
3321 | /* Zero the mmc structure */ | ||
3322 | memset(&m, 0x00, sizeof(m)); | ||
3323 | |||
3324 | /* Copy PSA info to the mmc */ | ||
3325 | m.mmw_netw_id_l = psa.psa_nwid[1]; | ||
3326 | m.mmw_netw_id_h = psa.psa_nwid[0]; | ||
3327 | |||
3328 | if(psa.psa_nwid_select & 1) | ||
3329 | m.mmw_loopt_sel = 0x00; | ||
3330 | else | ||
3331 | m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; | ||
3332 | |||
3333 | memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, | ||
3334 | sizeof(m.mmw_encr_key)); | ||
3335 | |||
3336 | if(psa.psa_encryption_select) | ||
3337 | m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; | ||
3338 | else | ||
3339 | m.mmw_encr_enable = 0; | ||
3340 | |||
3341 | m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; | ||
3342 | m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; | ||
3343 | |||
3344 | /* | ||
3345 | * Set default modem control parameters. | ||
3346 | * See NCR document 407-0024326 Rev. A. | ||
3347 | */ | ||
3348 | m.mmw_jabber_enable = 0x01; | ||
3349 | m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; | ||
3350 | m.mmw_ifs = 0x20; | ||
3351 | m.mmw_mod_delay = 0x04; | ||
3352 | m.mmw_jam_time = 0x38; | ||
3353 | |||
3354 | m.mmw_des_io_invert = 0; | ||
3355 | m.mmw_freeze = 0; | ||
3356 | m.mmw_decay_prm = 0; | ||
3357 | m.mmw_decay_updat_prm = 0; | ||
3358 | |||
3359 | /* Write all info to mmc */ | ||
3360 | mmc_write(base, 0, (u_char *)&m, sizeof(m)); | ||
3361 | |||
3362 | /* The following code start the modem of the 2.00 frequency | ||
3363 | * selectable cards at power on. It's not strictly needed for the | ||
3364 | * following boots... | ||
3365 | * The original patch was by Joe Finney for the PCMCIA driver, but | ||
3366 | * I've cleaned it a bit and add documentation. | ||
3367 | * Thanks to Loeke Brederveld from Lucent for the info. | ||
3368 | */ | ||
3369 | |||
3370 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) | ||
3371 | * (does it work for everybody ? - especially old cards...) */ | ||
3372 | /* Note : WFREQSEL verify that it is able to read from EEprom | ||
3373 | * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID | ||
3374 | * is 0xA (Xilinx version) or 0xB (Ariadne version). | ||
3375 | * My test is more crude but do work... */ | ||
3376 | if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
3377 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
3378 | { | ||
3379 | /* We must download the frequency parameters to the | ||
3380 | * synthetisers (from the EEprom - area 1) | ||
3381 | * Note : as the EEprom is auto decremented, we set the end | ||
3382 | * if the area... */ | ||
3383 | m.mmw_fee_addr = 0x0F; | ||
3384 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3385 | mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, | ||
3386 | (unsigned char *)&m.mmw_fee_ctrl, 2); | ||
3387 | |||
3388 | /* Wait until the download is finished */ | ||
3389 | fee_wait(base, 100, 100); | ||
3390 | |||
3391 | #ifdef DEBUG_CONFIG_INFO | ||
3392 | /* The frequency was in the last word downloaded... */ | ||
3393 | mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, | ||
3394 | (unsigned char *)&m.mmw_fee_data_l, 2); | ||
3395 | |||
3396 | /* Print some info for the user */ | ||
3397 | printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", | ||
3398 | dev->name, | ||
3399 | ((m.mmw_fee_data_h << 4) | | ||
3400 | (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); | ||
3401 | #endif | ||
3402 | |||
3403 | /* We must now download the power adjust value (gain) to | ||
3404 | * the synthetisers (from the EEprom - area 7 - DAC) */ | ||
3405 | m.mmw_fee_addr = 0x61; | ||
3406 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3407 | mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, | ||
3408 | (unsigned char *)&m.mmw_fee_ctrl, 2); | ||
3409 | |||
3410 | /* Wait until the download is finished */ | ||
3411 | } /* if 2.00 card */ | ||
3412 | |||
3413 | #ifdef DEBUG_CONFIG_TRACE | ||
3414 | printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); | ||
3415 | #endif | ||
3416 | return TRUE; | ||
3417 | } | ||
3418 | |||
3419 | /*------------------------------------------------------------------*/ | ||
3420 | /* | ||
3421 | * Routine to gracefully turn off reception, and wait for any commands | ||
3422 | * to complete. | ||
3423 | * (called in wv_ru_start() and wavelan_close() and wavelan_event()) | ||
3424 | */ | ||
3425 | static int | ||
3426 | wv_ru_stop(struct net_device * dev) | ||
3427 | { | ||
3428 | kio_addr_t base = dev->base_addr; | ||
3429 | net_local * lp = netdev_priv(dev); | ||
3430 | unsigned long flags; | ||
3431 | int status; | ||
3432 | int spin; | ||
3433 | |||
3434 | #ifdef DEBUG_CONFIG_TRACE | ||
3435 | printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); | ||
3436 | #endif | ||
3437 | |||
3438 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3439 | |||
3440 | /* First, send the LAN controller a stop receive command */ | ||
3441 | wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", | ||
3442 | OP0_STOP_RCV, SR0_NO_RESULT); | ||
3443 | |||
3444 | /* Then, spin until the receive unit goes idle */ | ||
3445 | spin = 300; | ||
3446 | do | ||
3447 | { | ||
3448 | udelay(10); | ||
3449 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
3450 | status = inb(LCSR(base)); | ||
3451 | } | ||
3452 | while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); | ||
3453 | |||
3454 | /* Now, spin until the chip finishes executing its current command */ | ||
3455 | do | ||
3456 | { | ||
3457 | udelay(10); | ||
3458 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
3459 | status = inb(LCSR(base)); | ||
3460 | } | ||
3461 | while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); | ||
3462 | |||
3463 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3464 | |||
3465 | /* If there was a problem */ | ||
3466 | if(spin <= 0) | ||
3467 | { | ||
3468 | #ifdef DEBUG_CONFIG_ERRORS | ||
3469 | printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", | ||
3470 | dev->name); | ||
3471 | #endif | ||
3472 | return FALSE; | ||
3473 | } | ||
3474 | |||
3475 | #ifdef DEBUG_CONFIG_TRACE | ||
3476 | printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); | ||
3477 | #endif | ||
3478 | return TRUE; | ||
3479 | } /* wv_ru_stop */ | ||
3480 | |||
3481 | /*------------------------------------------------------------------*/ | ||
3482 | /* | ||
3483 | * This routine starts the receive unit running. First, it checks if | ||
3484 | * the card is actually ready. Then the card is instructed to receive | ||
3485 | * packets again. | ||
3486 | * (called in wv_hw_reset() & wavelan_open()) | ||
3487 | */ | ||
3488 | static int | ||
3489 | wv_ru_start(struct net_device * dev) | ||
3490 | { | ||
3491 | kio_addr_t base = dev->base_addr; | ||
3492 | net_local * lp = netdev_priv(dev); | ||
3493 | unsigned long flags; | ||
3494 | |||
3495 | #ifdef DEBUG_CONFIG_TRACE | ||
3496 | printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); | ||
3497 | #endif | ||
3498 | |||
3499 | /* | ||
3500 | * We need to start from a quiescent state. To do so, we could check | ||
3501 | * if the card is already running, but instead we just try to shut | ||
3502 | * it down. First, we disable reception (in case it was already enabled). | ||
3503 | */ | ||
3504 | if(!wv_ru_stop(dev)) | ||
3505 | return FALSE; | ||
3506 | |||
3507 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3508 | |||
3509 | /* Now we know that no command is being executed. */ | ||
3510 | |||
3511 | /* Set the receive frame pointer and stop pointer */ | ||
3512 | lp->rfp = 0; | ||
3513 | outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); | ||
3514 | |||
3515 | /* Reset ring management. This sets the receive frame pointer to 1 */ | ||
3516 | outb(OP1_RESET_RING_MNGMT, LCCR(base)); | ||
3517 | |||
3518 | #if 0 | ||
3519 | /* XXX the i82593 manual page 6-4 seems to indicate that the stop register | ||
3520 | should be set as below */ | ||
3521 | /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ | ||
3522 | #elif 0 | ||
3523 | /* but I set it 0 instead */ | ||
3524 | lp->stop = 0; | ||
3525 | #else | ||
3526 | /* but I set it to 3 bytes per packet less than 8K */ | ||
3527 | lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; | ||
3528 | #endif | ||
3529 | outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); | ||
3530 | outb(OP1_INT_ENABLE, LCCR(base)); | ||
3531 | outb(OP1_SWIT_TO_PORT_0, LCCR(base)); | ||
3532 | |||
3533 | /* Reset receive DMA pointer */ | ||
3534 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3535 | hacr_write_slow(base, HACR_DEFAULT); | ||
3536 | |||
3537 | /* Receive DMA on channel 1 */ | ||
3538 | wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", | ||
3539 | CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); | ||
3540 | |||
3541 | #ifdef DEBUG_I82593_SHOW | ||
3542 | { | ||
3543 | int status; | ||
3544 | int opri; | ||
3545 | int spin = 10000; | ||
3546 | |||
3547 | /* spin until the chip starts receiving */ | ||
3548 | do | ||
3549 | { | ||
3550 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
3551 | status = inb(LCSR(base)); | ||
3552 | if(spin-- <= 0) | ||
3553 | break; | ||
3554 | } | ||
3555 | while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && | ||
3556 | ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); | ||
3557 | printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", | ||
3558 | (status & SR3_RCV_STATE_MASK), i); | ||
3559 | } | ||
3560 | #endif | ||
3561 | |||
3562 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3563 | |||
3564 | #ifdef DEBUG_CONFIG_TRACE | ||
3565 | printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); | ||
3566 | #endif | ||
3567 | return TRUE; | ||
3568 | } | ||
3569 | |||
3570 | /*------------------------------------------------------------------*/ | ||
3571 | /* | ||
3572 | * This routine does a standard config of the WaveLAN controller (i82593). | ||
3573 | * In the ISA driver, this is integrated in wavelan_hardware_reset() | ||
3574 | * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) | ||
3575 | */ | ||
3576 | static int | ||
3577 | wv_82593_config(struct net_device * dev) | ||
3578 | { | ||
3579 | kio_addr_t base = dev->base_addr; | ||
3580 | net_local * lp = netdev_priv(dev); | ||
3581 | struct i82593_conf_block cfblk; | ||
3582 | int ret = TRUE; | ||
3583 | |||
3584 | #ifdef DEBUG_CONFIG_TRACE | ||
3585 | printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); | ||
3586 | #endif | ||
3587 | |||
3588 | /* Create & fill i82593 config block | ||
3589 | * | ||
3590 | * Now conform to Wavelan document WCIN085B | ||
3591 | */ | ||
3592 | memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); | ||
3593 | cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ | ||
3594 | cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ | ||
3595 | cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ | ||
3596 | cfblk.fifo_32 = 1; | ||
3597 | cfblk.throttle_enb = FALSE; | ||
3598 | cfblk.contin = TRUE; /* enable continuous mode */ | ||
3599 | cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ | ||
3600 | cfblk.addr_len = WAVELAN_ADDR_SIZE; | ||
3601 | cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ | ||
3602 | cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ | ||
3603 | cfblk.loopback = FALSE; | ||
3604 | cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ | ||
3605 | cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */ | ||
3606 | cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */ | ||
3607 | cfblk.ifrm_spc = 0x20; /* 32 bit times interframe spacing */ | ||
3608 | cfblk.slottim_low = 0x20; /* 32 bit times slot time */ | ||
3609 | cfblk.slottim_hi = 0x0; | ||
3610 | cfblk.max_retr = 15; | ||
3611 | cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ | ||
3612 | cfblk.bc_dis = FALSE; /* Enable broadcast reception */ | ||
3613 | cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ | ||
3614 | cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ | ||
3615 | cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ | ||
3616 | cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ | ||
3617 | cfblk.cs_filter = 0; /* CS is recognized immediately */ | ||
3618 | cfblk.crs_src = FALSE; /* External carrier sense */ | ||
3619 | cfblk.cd_filter = 0; /* CD is recognized immediately */ | ||
3620 | cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ | ||
3621 | cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ | ||
3622 | cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ | ||
3623 | cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ | ||
3624 | cfblk.artx = TRUE; /* Disable automatic retransmission */ | ||
3625 | cfblk.sarec = TRUE; /* Disable source addr trig of CD */ | ||
3626 | cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ | ||
3627 | cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ | ||
3628 | cfblk.lbpkpol = TRUE; /* Loopback pin active high */ | ||
3629 | cfblk.fdx = FALSE; /* Disable full duplex operation */ | ||
3630 | cfblk.dummy_6 = 0x3f; /* all ones */ | ||
3631 | cfblk.mult_ia = FALSE; /* No multiple individual addresses */ | ||
3632 | cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ | ||
3633 | cfblk.dummy_1 = TRUE; /* set to 1 */ | ||
3634 | cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ | ||
3635 | #ifdef MULTICAST_ALL | ||
3636 | cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ | ||
3637 | #else | ||
3638 | cfblk.mc_all = FALSE; /* No multicast all mode */ | ||
3639 | #endif | ||
3640 | cfblk.rcv_mon = 0; /* Monitor mode disabled */ | ||
3641 | cfblk.frag_acpt = TRUE; /* Do not accept fragments */ | ||
3642 | cfblk.tstrttrs = FALSE; /* No start transmission threshold */ | ||
3643 | cfblk.fretx = TRUE; /* FIFO automatic retransmission */ | ||
3644 | cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ | ||
3645 | cfblk.sttlen = TRUE; /* 6 byte status registers */ | ||
3646 | cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ | ||
3647 | cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ | ||
3648 | cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ | ||
3649 | cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ | ||
3650 | |||
3651 | #ifdef DEBUG_I82593_SHOW | ||
3652 | { | ||
3653 | u_char *c = (u_char *) &cfblk; | ||
3654 | int i; | ||
3655 | printk(KERN_DEBUG "wavelan_cs: config block:"); | ||
3656 | for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++) | ||
3657 | { | ||
3658 | if((i % 16) == 0) printk("\n" KERN_DEBUG); | ||
3659 | printk("%02x ", *c); | ||
3660 | } | ||
3661 | printk("\n"); | ||
3662 | } | ||
3663 | #endif | ||
3664 | |||
3665 | /* Copy the config block to the i82593 */ | ||
3666 | outb(TX_BASE & 0xff, PIORL(base)); | ||
3667 | outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3668 | outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ | ||
3669 | outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ | ||
3670 | outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); | ||
3671 | |||
3672 | /* reset transmit DMA pointer */ | ||
3673 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3674 | hacr_write(base, HACR_DEFAULT); | ||
3675 | if(!wv_82593_cmd(dev, "wv_82593_config(): configure", | ||
3676 | OP0_CONFIGURE, SR0_CONFIGURE_DONE)) | ||
3677 | ret = FALSE; | ||
3678 | |||
3679 | /* Initialize adapter's ethernet MAC address */ | ||
3680 | outb(TX_BASE & 0xff, PIORL(base)); | ||
3681 | outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3682 | outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ | ||
3683 | outb(0, PIOP(base)); /* byte count msb */ | ||
3684 | outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); | ||
3685 | |||
3686 | /* reset transmit DMA pointer */ | ||
3687 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3688 | hacr_write(base, HACR_DEFAULT); | ||
3689 | if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", | ||
3690 | OP0_IA_SETUP, SR0_IA_SETUP_DONE)) | ||
3691 | ret = FALSE; | ||
3692 | |||
3693 | #ifdef WAVELAN_ROAMING | ||
3694 | /* If roaming is enabled, join the "Beacon Request" multicast group... */ | ||
3695 | /* But only if it's not in there already! */ | ||
3696 | if(do_roaming) | ||
3697 | dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); | ||
3698 | #endif /* WAVELAN_ROAMING */ | ||
3699 | |||
3700 | /* If any multicast address to set */ | ||
3701 | if(lp->mc_count) | ||
3702 | { | ||
3703 | struct dev_mc_list * dmi; | ||
3704 | int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; | ||
3705 | |||
3706 | #ifdef DEBUG_CONFIG_INFO | ||
3707 | printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", | ||
3708 | dev->name, lp->mc_count); | ||
3709 | for(dmi=dev->mc_list; dmi; dmi=dmi->next) | ||
3710 | printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
3711 | dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], | ||
3712 | dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); | ||
3713 | #endif | ||
3714 | |||
3715 | /* Initialize adapter's ethernet multicast addresses */ | ||
3716 | outb(TX_BASE & 0xff, PIORL(base)); | ||
3717 | outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3718 | outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ | ||
3719 | outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ | ||
3720 | for(dmi=dev->mc_list; dmi; dmi=dmi->next) | ||
3721 | outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); | ||
3722 | |||
3723 | /* reset transmit DMA pointer */ | ||
3724 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3725 | hacr_write(base, HACR_DEFAULT); | ||
3726 | if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", | ||
3727 | OP0_MC_SETUP, SR0_MC_SETUP_DONE)) | ||
3728 | ret = FALSE; | ||
3729 | lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ | ||
3730 | } | ||
3731 | |||
3732 | /* Job done, clear the flag */ | ||
3733 | lp->reconfig_82593 = FALSE; | ||
3734 | |||
3735 | #ifdef DEBUG_CONFIG_TRACE | ||
3736 | printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); | ||
3737 | #endif | ||
3738 | return(ret); | ||
3739 | } | ||
3740 | |||
3741 | /*------------------------------------------------------------------*/ | ||
3742 | /* | ||
3743 | * Read the Access Configuration Register, perform a software reset, | ||
3744 | * and then re-enable the card's software. | ||
3745 | * | ||
3746 | * If I understand correctly : reset the pcmcia interface of the | ||
3747 | * wavelan. | ||
3748 | * (called by wv_config()) | ||
3749 | */ | ||
3750 | static inline int | ||
3751 | wv_pcmcia_reset(struct net_device * dev) | ||
3752 | { | ||
3753 | int i; | ||
3754 | conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; | ||
3755 | dev_link_t * link = ((net_local *)netdev_priv(dev))->link; | ||
3756 | |||
3757 | #ifdef DEBUG_CONFIG_TRACE | ||
3758 | printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); | ||
3759 | #endif | ||
3760 | |||
3761 | i = pcmcia_access_configuration_register(link->handle, ®); | ||
3762 | if(i != CS_SUCCESS) | ||
3763 | { | ||
3764 | cs_error(link->handle, AccessConfigurationRegister, i); | ||
3765 | return FALSE; | ||
3766 | } | ||
3767 | |||
3768 | #ifdef DEBUG_CONFIG_INFO | ||
3769 | printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", | ||
3770 | dev->name, (u_int) reg.Value); | ||
3771 | #endif | ||
3772 | |||
3773 | reg.Action = CS_WRITE; | ||
3774 | reg.Value = reg.Value | COR_SW_RESET; | ||
3775 | i = pcmcia_access_configuration_register(link->handle, ®); | ||
3776 | if(i != CS_SUCCESS) | ||
3777 | { | ||
3778 | cs_error(link->handle, AccessConfigurationRegister, i); | ||
3779 | return FALSE; | ||
3780 | } | ||
3781 | |||
3782 | reg.Action = CS_WRITE; | ||
3783 | reg.Value = COR_LEVEL_IRQ | COR_CONFIG; | ||
3784 | i = pcmcia_access_configuration_register(link->handle, ®); | ||
3785 | if(i != CS_SUCCESS) | ||
3786 | { | ||
3787 | cs_error(link->handle, AccessConfigurationRegister, i); | ||
3788 | return FALSE; | ||
3789 | } | ||
3790 | |||
3791 | #ifdef DEBUG_CONFIG_TRACE | ||
3792 | printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); | ||
3793 | #endif | ||
3794 | return TRUE; | ||
3795 | } | ||
3796 | |||
3797 | /*------------------------------------------------------------------*/ | ||
3798 | /* | ||
3799 | * wavelan_hw_config() is called after a CARD_INSERTION event is | ||
3800 | * received, to configure the wavelan hardware. | ||
3801 | * Note that the reception will be enabled in wavelan->open(), so the | ||
3802 | * device is configured but idle... | ||
3803 | * Performs the following actions: | ||
3804 | * 1. A pcmcia software reset (using wv_pcmcia_reset()) | ||
3805 | * 2. A power reset (reset DMA) | ||
3806 | * 3. Reset the LAN controller | ||
3807 | * 4. Initialize the radio modem (using wv_mmc_init) | ||
3808 | * 5. Configure LAN controller (using wv_82593_config) | ||
3809 | * 6. Perform a diagnostic on the LAN controller | ||
3810 | * (called by wavelan_event() & wv_hw_reset()) | ||
3811 | */ | ||
3812 | static int | ||
3813 | wv_hw_config(struct net_device * dev) | ||
3814 | { | ||
3815 | net_local * lp = netdev_priv(dev); | ||
3816 | kio_addr_t base = dev->base_addr; | ||
3817 | unsigned long flags; | ||
3818 | int ret = FALSE; | ||
3819 | |||
3820 | #ifdef DEBUG_CONFIG_TRACE | ||
3821 | printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); | ||
3822 | #endif | ||
3823 | |||
3824 | #ifdef STRUCT_CHECK | ||
3825 | if(wv_structuct_check() != (char *) NULL) | ||
3826 | { | ||
3827 | printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n", | ||
3828 | dev->name, wv_structuct_check()); | ||
3829 | return FALSE; | ||
3830 | } | ||
3831 | #endif /* STRUCT_CHECK == 1 */ | ||
3832 | |||
3833 | /* Reset the pcmcia interface */ | ||
3834 | if(wv_pcmcia_reset(dev) == FALSE) | ||
3835 | return FALSE; | ||
3836 | |||
3837 | /* Disable interrupts */ | ||
3838 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3839 | |||
3840 | /* Disguised goto ;-) */ | ||
3841 | do | ||
3842 | { | ||
3843 | /* Power UP the module + reset the modem + reset host adapter | ||
3844 | * (in fact, reset DMA channels) */ | ||
3845 | hacr_write_slow(base, HACR_RESET); | ||
3846 | hacr_write(base, HACR_DEFAULT); | ||
3847 | |||
3848 | /* Check if the module has been powered up... */ | ||
3849 | if(hasr_read(base) & HASR_NO_CLK) | ||
3850 | { | ||
3851 | #ifdef DEBUG_CONFIG_ERRORS | ||
3852 | printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", | ||
3853 | dev->name); | ||
3854 | #endif | ||
3855 | break; | ||
3856 | } | ||
3857 | |||
3858 | /* initialize the modem */ | ||
3859 | if(wv_mmc_init(dev) == FALSE) | ||
3860 | { | ||
3861 | #ifdef DEBUG_CONFIG_ERRORS | ||
3862 | printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", | ||
3863 | dev->name); | ||
3864 | #endif | ||
3865 | break; | ||
3866 | } | ||
3867 | |||
3868 | /* reset the LAN controller (i82593) */ | ||
3869 | outb(OP0_RESET, LCCR(base)); | ||
3870 | mdelay(1); /* A bit crude ! */ | ||
3871 | |||
3872 | /* Initialize the LAN controller */ | ||
3873 | if(wv_82593_config(dev) == FALSE) | ||
3874 | { | ||
3875 | #ifdef DEBUG_CONFIG_ERRORS | ||
3876 | printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", | ||
3877 | dev->name); | ||
3878 | #endif | ||
3879 | break; | ||
3880 | } | ||
3881 | |||
3882 | /* Diagnostic */ | ||
3883 | if(wv_diag(dev) == FALSE) | ||
3884 | { | ||
3885 | #ifdef DEBUG_CONFIG_ERRORS | ||
3886 | printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", | ||
3887 | dev->name); | ||
3888 | #endif | ||
3889 | break; | ||
3890 | } | ||
3891 | |||
3892 | /* | ||
3893 | * insert code for loopback test here | ||
3894 | */ | ||
3895 | |||
3896 | /* The device is now configured */ | ||
3897 | lp->configured = 1; | ||
3898 | ret = TRUE; | ||
3899 | } | ||
3900 | while(0); | ||
3901 | |||
3902 | /* Re-enable interrupts */ | ||
3903 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3904 | |||
3905 | #ifdef DEBUG_CONFIG_TRACE | ||
3906 | printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); | ||
3907 | #endif | ||
3908 | return(ret); | ||
3909 | } | ||
3910 | |||
3911 | /*------------------------------------------------------------------*/ | ||
3912 | /* | ||
3913 | * Totally reset the wavelan and restart it. | ||
3914 | * Performs the following actions: | ||
3915 | * 1. Call wv_hw_config() | ||
3916 | * 2. Start the LAN controller's receive unit | ||
3917 | * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) | ||
3918 | */ | ||
3919 | static inline void | ||
3920 | wv_hw_reset(struct net_device * dev) | ||
3921 | { | ||
3922 | net_local * lp = netdev_priv(dev); | ||
3923 | |||
3924 | #ifdef DEBUG_CONFIG_TRACE | ||
3925 | printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); | ||
3926 | #endif | ||
3927 | |||
3928 | lp->nresets++; | ||
3929 | lp->configured = 0; | ||
3930 | |||
3931 | /* Call wv_hw_config() for most of the reset & init stuff */ | ||
3932 | if(wv_hw_config(dev) == FALSE) | ||
3933 | return; | ||
3934 | |||
3935 | /* start receive unit */ | ||
3936 | wv_ru_start(dev); | ||
3937 | |||
3938 | #ifdef DEBUG_CONFIG_TRACE | ||
3939 | printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); | ||
3940 | #endif | ||
3941 | } | ||
3942 | |||
3943 | /*------------------------------------------------------------------*/ | ||
3944 | /* | ||
3945 | * wv_pcmcia_config() is called after a CARD_INSERTION event is | ||
3946 | * received, to configure the PCMCIA socket, and to make the ethernet | ||
3947 | * device available to the system. | ||
3948 | * (called by wavelan_event()) | ||
3949 | */ | ||
3950 | static inline int | ||
3951 | wv_pcmcia_config(dev_link_t * link) | ||
3952 | { | ||
3953 | client_handle_t handle = link->handle; | ||
3954 | tuple_t tuple; | ||
3955 | cisparse_t parse; | ||
3956 | struct net_device * dev = (struct net_device *) link->priv; | ||
3957 | int i; | ||
3958 | u_char buf[64]; | ||
3959 | win_req_t req; | ||
3960 | memreq_t mem; | ||
3961 | net_local * lp = netdev_priv(dev); | ||
3962 | |||
3963 | |||
3964 | #ifdef DEBUG_CONFIG_TRACE | ||
3965 | printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); | ||
3966 | #endif | ||
3967 | |||
3968 | /* | ||
3969 | * This reads the card's CONFIG tuple to find its configuration | ||
3970 | * registers. | ||
3971 | */ | ||
3972 | do | ||
3973 | { | ||
3974 | tuple.Attributes = 0; | ||
3975 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
3976 | i = pcmcia_get_first_tuple(handle, &tuple); | ||
3977 | if(i != CS_SUCCESS) | ||
3978 | break; | ||
3979 | tuple.TupleData = (cisdata_t *)buf; | ||
3980 | tuple.TupleDataMax = 64; | ||
3981 | tuple.TupleOffset = 0; | ||
3982 | i = pcmcia_get_tuple_data(handle, &tuple); | ||
3983 | if(i != CS_SUCCESS) | ||
3984 | break; | ||
3985 | i = pcmcia_parse_tuple(handle, &tuple, &parse); | ||
3986 | if(i != CS_SUCCESS) | ||
3987 | break; | ||
3988 | link->conf.ConfigBase = parse.config.base; | ||
3989 | link->conf.Present = parse.config.rmask[0]; | ||
3990 | } | ||
3991 | while(0); | ||
3992 | if(i != CS_SUCCESS) | ||
3993 | { | ||
3994 | cs_error(link->handle, ParseTuple, i); | ||
3995 | link->state &= ~DEV_CONFIG_PENDING; | ||
3996 | return FALSE; | ||
3997 | } | ||
3998 | |||
3999 | /* Configure card */ | ||
4000 | link->state |= DEV_CONFIG; | ||
4001 | do | ||
4002 | { | ||
4003 | i = pcmcia_request_io(link->handle, &link->io); | ||
4004 | if(i != CS_SUCCESS) | ||
4005 | { | ||
4006 | cs_error(link->handle, RequestIO, i); | ||
4007 | break; | ||
4008 | } | ||
4009 | |||
4010 | /* | ||
4011 | * Now allocate an interrupt line. Note that this does not | ||
4012 | * actually assign a handler to the interrupt. | ||
4013 | */ | ||
4014 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
4015 | if(i != CS_SUCCESS) | ||
4016 | { | ||
4017 | cs_error(link->handle, RequestIRQ, i); | ||
4018 | break; | ||
4019 | } | ||
4020 | |||
4021 | /* | ||
4022 | * This actually configures the PCMCIA socket -- setting up | ||
4023 | * the I/O windows and the interrupt mapping. | ||
4024 | */ | ||
4025 | link->conf.ConfigIndex = 1; | ||
4026 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
4027 | if(i != CS_SUCCESS) | ||
4028 | { | ||
4029 | cs_error(link->handle, RequestConfiguration, i); | ||
4030 | break; | ||
4031 | } | ||
4032 | |||
4033 | /* | ||
4034 | * Allocate a small memory window. Note that the dev_link_t | ||
4035 | * structure provides space for one window handle -- if your | ||
4036 | * device needs several windows, you'll need to keep track of | ||
4037 | * the handles in your private data structure, link->priv. | ||
4038 | */ | ||
4039 | req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; | ||
4040 | req.Base = req.Size = 0; | ||
4041 | req.AccessSpeed = mem_speed; | ||
4042 | i = pcmcia_request_window(&link->handle, &req, &link->win); | ||
4043 | if(i != CS_SUCCESS) | ||
4044 | { | ||
4045 | cs_error(link->handle, RequestWindow, i); | ||
4046 | break; | ||
4047 | } | ||
4048 | |||
4049 | lp->mem = ioremap(req.Base, req.Size); | ||
4050 | dev->mem_start = (u_long)lp->mem; | ||
4051 | dev->mem_end = dev->mem_start + req.Size; | ||
4052 | |||
4053 | mem.CardOffset = 0; mem.Page = 0; | ||
4054 | i = pcmcia_map_mem_page(link->win, &mem); | ||
4055 | if(i != CS_SUCCESS) | ||
4056 | { | ||
4057 | cs_error(link->handle, MapMemPage, i); | ||
4058 | break; | ||
4059 | } | ||
4060 | |||
4061 | /* Feed device with this info... */ | ||
4062 | dev->irq = link->irq.AssignedIRQ; | ||
4063 | dev->base_addr = link->io.BasePort1; | ||
4064 | netif_start_queue(dev); | ||
4065 | |||
4066 | #ifdef DEBUG_CONFIG_INFO | ||
4067 | printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART %p IRQ %d IOPORT 0x%x\n", | ||
4068 | lp->mem, dev->irq, (u_int) dev->base_addr); | ||
4069 | #endif | ||
4070 | |||
4071 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
4072 | i = register_netdev(dev); | ||
4073 | if(i != 0) | ||
4074 | { | ||
4075 | #ifdef DEBUG_CONFIG_ERRORS | ||
4076 | printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); | ||
4077 | #endif | ||
4078 | break; | ||
4079 | } | ||
4080 | } | ||
4081 | while(0); /* Humm... Disguised goto !!! */ | ||
4082 | |||
4083 | link->state &= ~DEV_CONFIG_PENDING; | ||
4084 | /* If any step failed, release any partially configured state */ | ||
4085 | if(i != 0) | ||
4086 | { | ||
4087 | wv_pcmcia_release(link); | ||
4088 | return FALSE; | ||
4089 | } | ||
4090 | |||
4091 | strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name); | ||
4092 | link->dev = &((net_local *) netdev_priv(dev))->node; | ||
4093 | |||
4094 | #ifdef DEBUG_CONFIG_TRACE | ||
4095 | printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); | ||
4096 | #endif | ||
4097 | return TRUE; | ||
4098 | } | ||
4099 | |||
4100 | /*------------------------------------------------------------------*/ | ||
4101 | /* | ||
4102 | * After a card is removed, wv_pcmcia_release() will unregister the net | ||
4103 | * device, and release the PCMCIA configuration. If the device is | ||
4104 | * still open, this will be postponed until it is closed. | ||
4105 | */ | ||
4106 | static void | ||
4107 | wv_pcmcia_release(dev_link_t *link) | ||
4108 | { | ||
4109 | struct net_device * dev = (struct net_device *) link->priv; | ||
4110 | net_local * lp = netdev_priv(dev); | ||
4111 | |||
4112 | #ifdef DEBUG_CONFIG_TRACE | ||
4113 | printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); | ||
4114 | #endif | ||
4115 | |||
4116 | /* Don't bother checking to see if these succeed or not */ | ||
4117 | iounmap(lp->mem); | ||
4118 | pcmcia_release_window(link->win); | ||
4119 | pcmcia_release_configuration(link->handle); | ||
4120 | pcmcia_release_io(link->handle, &link->io); | ||
4121 | pcmcia_release_irq(link->handle, &link->irq); | ||
4122 | |||
4123 | link->state &= ~DEV_CONFIG; | ||
4124 | |||
4125 | #ifdef DEBUG_CONFIG_TRACE | ||
4126 | printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); | ||
4127 | #endif | ||
4128 | } | ||
4129 | |||
4130 | /************************ INTERRUPT HANDLING ************************/ | ||
4131 | |||
4132 | /* | ||
4133 | * This function is the interrupt handler for the WaveLAN card. This | ||
4134 | * routine will be called whenever: | ||
4135 | * 1. A packet is received. | ||
4136 | * 2. A packet has successfully been transferred and the unit is | ||
4137 | * ready to transmit another packet. | ||
4138 | * 3. A command has completed execution. | ||
4139 | */ | ||
4140 | static irqreturn_t | ||
4141 | wavelan_interrupt(int irq, | ||
4142 | void * dev_id, | ||
4143 | struct pt_regs * regs) | ||
4144 | { | ||
4145 | struct net_device * dev; | ||
4146 | net_local * lp; | ||
4147 | kio_addr_t base; | ||
4148 | int status0; | ||
4149 | u_int tx_status; | ||
4150 | |||
4151 | if ((dev = dev_id) == NULL) | ||
4152 | { | ||
4153 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4154 | printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", | ||
4155 | irq); | ||
4156 | #endif | ||
4157 | return IRQ_NONE; | ||
4158 | } | ||
4159 | |||
4160 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4161 | printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); | ||
4162 | #endif | ||
4163 | |||
4164 | lp = netdev_priv(dev); | ||
4165 | base = dev->base_addr; | ||
4166 | |||
4167 | #ifdef DEBUG_INTERRUPT_INFO | ||
4168 | /* Check state of our spinlock (it should be cleared) */ | ||
4169 | if(spin_is_locked(&lp->spinlock)) | ||
4170 | printk(KERN_DEBUG | ||
4171 | "%s: wavelan_interrupt(): spinlock is already locked !!!\n", | ||
4172 | dev->name); | ||
4173 | #endif | ||
4174 | |||
4175 | /* Prevent reentrancy. We need to do that because we may have | ||
4176 | * multiple interrupt handler running concurently. | ||
4177 | * It is safe because interrupts are disabled before aquiring | ||
4178 | * the spinlock. */ | ||
4179 | spin_lock(&lp->spinlock); | ||
4180 | |||
4181 | /* Treat all pending interrupts */ | ||
4182 | while(1) | ||
4183 | { | ||
4184 | /* ---------------- INTERRUPT CHECKING ---------------- */ | ||
4185 | /* | ||
4186 | * Look for the interrupt and verify the validity | ||
4187 | */ | ||
4188 | outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); | ||
4189 | status0 = inb(LCSR(base)); | ||
4190 | |||
4191 | #ifdef DEBUG_INTERRUPT_INFO | ||
4192 | printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, | ||
4193 | (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); | ||
4194 | if(status0&SR0_INTERRUPT) | ||
4195 | { | ||
4196 | printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : | ||
4197 | ((status0 & SR0_EXECUTION) ? "cmd" : | ||
4198 | ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), | ||
4199 | (status0 & SR0_EVENT_MASK)); | ||
4200 | } | ||
4201 | else | ||
4202 | printk("\n"); | ||
4203 | #endif | ||
4204 | |||
4205 | /* Return if no actual interrupt from i82593 (normal exit) */ | ||
4206 | if(!(status0 & SR0_INTERRUPT)) | ||
4207 | break; | ||
4208 | |||
4209 | /* If interrupt is both Rx and Tx or none... | ||
4210 | * This code in fact is there to catch the spurious interrupt | ||
4211 | * when you remove the wavelan pcmcia card from the socket */ | ||
4212 | if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || | ||
4213 | ((status0 & SR0_BOTH_RX_TX) == 0x0)) | ||
4214 | { | ||
4215 | #ifdef DEBUG_INTERRUPT_INFO | ||
4216 | printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", | ||
4217 | dev->name, status0); | ||
4218 | #endif | ||
4219 | /* Acknowledge the interrupt */ | ||
4220 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); | ||
4221 | break; | ||
4222 | } | ||
4223 | |||
4224 | /* ----------------- RECEIVING PACKET ----------------- */ | ||
4225 | /* | ||
4226 | * When the wavelan signal the reception of a new packet, | ||
4227 | * we call wv_packet_rcv() to copy if from the buffer and | ||
4228 | * send it to NET3 | ||
4229 | */ | ||
4230 | if(status0 & SR0_RECEPTION) | ||
4231 | { | ||
4232 | #ifdef DEBUG_INTERRUPT_INFO | ||
4233 | printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); | ||
4234 | #endif | ||
4235 | |||
4236 | if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) | ||
4237 | { | ||
4238 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4239 | printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", | ||
4240 | dev->name); | ||
4241 | #endif | ||
4242 | lp->stats.rx_over_errors++; | ||
4243 | lp->overrunning = 1; | ||
4244 | } | ||
4245 | |||
4246 | /* Get the packet */ | ||
4247 | wv_packet_rcv(dev); | ||
4248 | lp->overrunning = 0; | ||
4249 | |||
4250 | /* Acknowledge the interrupt */ | ||
4251 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); | ||
4252 | continue; | ||
4253 | } | ||
4254 | |||
4255 | /* ---------------- COMMAND COMPLETION ---------------- */ | ||
4256 | /* | ||
4257 | * Interrupts issued when the i82593 has completed a command. | ||
4258 | * Most likely : transmission done | ||
4259 | */ | ||
4260 | |||
4261 | /* If a transmission has been done */ | ||
4262 | if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || | ||
4263 | (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || | ||
4264 | (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) | ||
4265 | { | ||
4266 | #ifdef DEBUG_TX_ERROR | ||
4267 | if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) | ||
4268 | printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", | ||
4269 | dev->name); | ||
4270 | #endif | ||
4271 | |||
4272 | /* Get transmission status */ | ||
4273 | tx_status = inb(LCSR(base)); | ||
4274 | tx_status |= (inb(LCSR(base)) << 8); | ||
4275 | #ifdef DEBUG_INTERRUPT_INFO | ||
4276 | printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", | ||
4277 | dev->name); | ||
4278 | { | ||
4279 | u_int rcv_bytes; | ||
4280 | u_char status3; | ||
4281 | rcv_bytes = inb(LCSR(base)); | ||
4282 | rcv_bytes |= (inb(LCSR(base)) << 8); | ||
4283 | status3 = inb(LCSR(base)); | ||
4284 | printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", | ||
4285 | tx_status, rcv_bytes, (u_int) status3); | ||
4286 | } | ||
4287 | #endif | ||
4288 | /* Check for possible errors */ | ||
4289 | if((tx_status & TX_OK) != TX_OK) | ||
4290 | { | ||
4291 | lp->stats.tx_errors++; | ||
4292 | |||
4293 | if(tx_status & TX_FRTL) | ||
4294 | { | ||
4295 | #ifdef DEBUG_TX_ERROR | ||
4296 | printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", | ||
4297 | dev->name); | ||
4298 | #endif | ||
4299 | } | ||
4300 | if(tx_status & TX_UND_RUN) | ||
4301 | { | ||
4302 | #ifdef DEBUG_TX_FAIL | ||
4303 | printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", | ||
4304 | dev->name); | ||
4305 | #endif | ||
4306 | lp->stats.tx_aborted_errors++; | ||
4307 | } | ||
4308 | if(tx_status & TX_LOST_CTS) | ||
4309 | { | ||
4310 | #ifdef DEBUG_TX_FAIL | ||
4311 | printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); | ||
4312 | #endif | ||
4313 | lp->stats.tx_carrier_errors++; | ||
4314 | } | ||
4315 | if(tx_status & TX_LOST_CRS) | ||
4316 | { | ||
4317 | #ifdef DEBUG_TX_FAIL | ||
4318 | printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", | ||
4319 | dev->name); | ||
4320 | #endif | ||
4321 | lp->stats.tx_carrier_errors++; | ||
4322 | } | ||
4323 | if(tx_status & TX_HRT_BEAT) | ||
4324 | { | ||
4325 | #ifdef DEBUG_TX_FAIL | ||
4326 | printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); | ||
4327 | #endif | ||
4328 | lp->stats.tx_heartbeat_errors++; | ||
4329 | } | ||
4330 | if(tx_status & TX_DEFER) | ||
4331 | { | ||
4332 | #ifdef DEBUG_TX_FAIL | ||
4333 | printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", | ||
4334 | dev->name); | ||
4335 | #endif | ||
4336 | } | ||
4337 | /* Ignore late collisions since they're more likely to happen | ||
4338 | * here (the WaveLAN design prevents the LAN controller from | ||
4339 | * receiving while it is transmitting). We take action only when | ||
4340 | * the maximum retransmit attempts is exceeded. | ||
4341 | */ | ||
4342 | if(tx_status & TX_COLL) | ||
4343 | { | ||
4344 | if(tx_status & TX_MAX_COL) | ||
4345 | { | ||
4346 | #ifdef DEBUG_TX_FAIL | ||
4347 | printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", | ||
4348 | dev->name); | ||
4349 | #endif | ||
4350 | if(!(tx_status & TX_NCOL_MASK)) | ||
4351 | { | ||
4352 | lp->stats.collisions += 0x10; | ||
4353 | } | ||
4354 | } | ||
4355 | } | ||
4356 | } /* if(!(tx_status & TX_OK)) */ | ||
4357 | |||
4358 | lp->stats.collisions += (tx_status & TX_NCOL_MASK); | ||
4359 | lp->stats.tx_packets++; | ||
4360 | |||
4361 | netif_wake_queue(dev); | ||
4362 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ | ||
4363 | } | ||
4364 | else /* if interrupt = transmit done or retransmit done */ | ||
4365 | { | ||
4366 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4367 | printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", | ||
4368 | status0); | ||
4369 | #endif | ||
4370 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ | ||
4371 | } | ||
4372 | } /* while(1) */ | ||
4373 | |||
4374 | spin_unlock(&lp->spinlock); | ||
4375 | |||
4376 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4377 | printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); | ||
4378 | #endif | ||
4379 | |||
4380 | /* We always return IRQ_HANDLED, because we will receive empty | ||
4381 | * interrupts under normal operations. Anyway, it doesn't matter | ||
4382 | * as we are dealing with an ISA interrupt that can't be shared. | ||
4383 | * | ||
4384 | * Explanation : under heavy receive, the following happens : | ||
4385 | * ->wavelan_interrupt() | ||
4386 | * (status0 & SR0_INTERRUPT) != 0 | ||
4387 | * ->wv_packet_rcv() | ||
4388 | * (status0 & SR0_INTERRUPT) != 0 | ||
4389 | * ->wv_packet_rcv() | ||
4390 | * (status0 & SR0_INTERRUPT) == 0 // i.e. no more event | ||
4391 | * <-wavelan_interrupt() | ||
4392 | * ->wavelan_interrupt() | ||
4393 | * (status0 & SR0_INTERRUPT) == 0 // i.e. empty interrupt | ||
4394 | * <-wavelan_interrupt() | ||
4395 | * Jean II */ | ||
4396 | return IRQ_HANDLED; | ||
4397 | } /* wv_interrupt */ | ||
4398 | |||
4399 | /*------------------------------------------------------------------*/ | ||
4400 | /* | ||
4401 | * Watchdog: when we start a transmission, a timer is set for us in the | ||
4402 | * kernel. If the transmission completes, this timer is disabled. If | ||
4403 | * the timer expires, we are called and we try to unlock the hardware. | ||
4404 | * | ||
4405 | * Note : This watchdog is move clever than the one in the ISA driver, | ||
4406 | * because it try to abort the current command before reseting | ||
4407 | * everything... | ||
4408 | * On the other hand, it's a bit simpler, because we don't have to | ||
4409 | * deal with the multiple Tx buffers... | ||
4410 | */ | ||
4411 | static void | ||
4412 | wavelan_watchdog(struct net_device * dev) | ||
4413 | { | ||
4414 | net_local * lp = netdev_priv(dev); | ||
4415 | kio_addr_t base = dev->base_addr; | ||
4416 | unsigned long flags; | ||
4417 | int aborted = FALSE; | ||
4418 | |||
4419 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4420 | printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); | ||
4421 | #endif | ||
4422 | |||
4423 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4424 | printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", | ||
4425 | dev->name); | ||
4426 | #endif | ||
4427 | |||
4428 | spin_lock_irqsave(&lp->spinlock, flags); | ||
4429 | |||
4430 | /* Ask to abort the current command */ | ||
4431 | outb(OP0_ABORT, LCCR(base)); | ||
4432 | |||
4433 | /* Wait for the end of the command (a bit hackish) */ | ||
4434 | if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", | ||
4435 | OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) | ||
4436 | aborted = TRUE; | ||
4437 | |||
4438 | /* Release spinlock here so that wv_hw_reset() can grab it */ | ||
4439 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
4440 | |||
4441 | /* Check if we were successful in aborting it */ | ||
4442 | if(!aborted) | ||
4443 | { | ||
4444 | /* It seem that it wasn't enough */ | ||
4445 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4446 | printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", | ||
4447 | dev->name); | ||
4448 | #endif | ||
4449 | wv_hw_reset(dev); | ||
4450 | } | ||
4451 | |||
4452 | #ifdef DEBUG_PSA_SHOW | ||
4453 | { | ||
4454 | psa_t psa; | ||
4455 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
4456 | wv_psa_show(&psa); | ||
4457 | } | ||
4458 | #endif | ||
4459 | #ifdef DEBUG_MMC_SHOW | ||
4460 | wv_mmc_show(dev); | ||
4461 | #endif | ||
4462 | #ifdef DEBUG_I82593_SHOW | ||
4463 | wv_ru_show(dev); | ||
4464 | #endif | ||
4465 | |||
4466 | /* We are no more waiting for something... */ | ||
4467 | netif_wake_queue(dev); | ||
4468 | |||
4469 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4470 | printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); | ||
4471 | #endif | ||
4472 | } | ||
4473 | |||
4474 | /********************* CONFIGURATION CALLBACKS *********************/ | ||
4475 | /* | ||
4476 | * Here are the functions called by the pcmcia package (cardmgr) and | ||
4477 | * linux networking (NET3) for initialization, configuration and | ||
4478 | * deinstallations of the Wavelan Pcmcia Hardware. | ||
4479 | */ | ||
4480 | |||
4481 | /*------------------------------------------------------------------*/ | ||
4482 | /* | ||
4483 | * Configure and start up the WaveLAN PCMCIA adaptor. | ||
4484 | * Called by NET3 when it "open" the device. | ||
4485 | */ | ||
4486 | static int | ||
4487 | wavelan_open(struct net_device * dev) | ||
4488 | { | ||
4489 | net_local * lp = netdev_priv(dev); | ||
4490 | dev_link_t * link = lp->link; | ||
4491 | kio_addr_t base = dev->base_addr; | ||
4492 | |||
4493 | #ifdef DEBUG_CALLBACK_TRACE | ||
4494 | printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, | ||
4495 | (unsigned int) dev); | ||
4496 | #endif | ||
4497 | |||
4498 | /* Check if the modem is powered up (wavelan_close() power it down */ | ||
4499 | if(hasr_read(base) & HASR_NO_CLK) | ||
4500 | { | ||
4501 | /* Power up (power up time is 250us) */ | ||
4502 | hacr_write(base, HACR_DEFAULT); | ||
4503 | |||
4504 | /* Check if the module has been powered up... */ | ||
4505 | if(hasr_read(base) & HASR_NO_CLK) | ||
4506 | { | ||
4507 | #ifdef DEBUG_CONFIG_ERRORS | ||
4508 | printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", | ||
4509 | dev->name); | ||
4510 | #endif | ||
4511 | return FALSE; | ||
4512 | } | ||
4513 | } | ||
4514 | |||
4515 | /* Start reception and declare the driver ready */ | ||
4516 | if(!lp->configured) | ||
4517 | return FALSE; | ||
4518 | if(!wv_ru_start(dev)) | ||
4519 | wv_hw_reset(dev); /* If problem : reset */ | ||
4520 | netif_start_queue(dev); | ||
4521 | |||
4522 | /* Mark the device as used */ | ||
4523 | link->open++; | ||
4524 | |||
4525 | #ifdef WAVELAN_ROAMING | ||
4526 | if(do_roaming) | ||
4527 | wv_roam_init(dev); | ||
4528 | #endif /* WAVELAN_ROAMING */ | ||
4529 | |||
4530 | #ifdef DEBUG_CALLBACK_TRACE | ||
4531 | printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); | ||
4532 | #endif | ||
4533 | return 0; | ||
4534 | } | ||
4535 | |||
4536 | /*------------------------------------------------------------------*/ | ||
4537 | /* | ||
4538 | * Shutdown the WaveLAN PCMCIA adaptor. | ||
4539 | * Called by NET3 when it "close" the device. | ||
4540 | */ | ||
4541 | static int | ||
4542 | wavelan_close(struct net_device * dev) | ||
4543 | { | ||
4544 | dev_link_t * link = ((net_local *)netdev_priv(dev))->link; | ||
4545 | kio_addr_t base = dev->base_addr; | ||
4546 | |||
4547 | #ifdef DEBUG_CALLBACK_TRACE | ||
4548 | printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, | ||
4549 | (unsigned int) dev); | ||
4550 | #endif | ||
4551 | |||
4552 | /* If the device isn't open, then nothing to do */ | ||
4553 | if(!link->open) | ||
4554 | { | ||
4555 | #ifdef DEBUG_CONFIG_INFO | ||
4556 | printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); | ||
4557 | #endif | ||
4558 | return 0; | ||
4559 | } | ||
4560 | |||
4561 | #ifdef WAVELAN_ROAMING | ||
4562 | /* Cleanup of roaming stuff... */ | ||
4563 | if(do_roaming) | ||
4564 | wv_roam_cleanup(dev); | ||
4565 | #endif /* WAVELAN_ROAMING */ | ||
4566 | |||
4567 | link->open--; | ||
4568 | |||
4569 | /* If the card is still present */ | ||
4570 | if(netif_running(dev)) | ||
4571 | { | ||
4572 | netif_stop_queue(dev); | ||
4573 | |||
4574 | /* Stop receiving new messages and wait end of transmission */ | ||
4575 | wv_ru_stop(dev); | ||
4576 | |||
4577 | /* Power down the module */ | ||
4578 | hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); | ||
4579 | } | ||
4580 | |||
4581 | #ifdef DEBUG_CALLBACK_TRACE | ||
4582 | printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); | ||
4583 | #endif | ||
4584 | return 0; | ||
4585 | } | ||
4586 | |||
4587 | /*------------------------------------------------------------------*/ | ||
4588 | /* | ||
4589 | * wavelan_attach() creates an "instance" of the driver, allocating | ||
4590 | * local data structures for one device (one interface). The device | ||
4591 | * is registered with Card Services. | ||
4592 | * | ||
4593 | * The dev_link structure is initialized, but we don't actually | ||
4594 | * configure the card at this point -- we wait until we receive a | ||
4595 | * card insertion event. | ||
4596 | */ | ||
4597 | static dev_link_t * | ||
4598 | wavelan_attach(void) | ||
4599 | { | ||
4600 | client_reg_t client_reg; /* Register with cardmgr */ | ||
4601 | dev_link_t * link; /* Info for cardmgr */ | ||
4602 | struct net_device * dev; /* Interface generic data */ | ||
4603 | net_local * lp; /* Interface specific data */ | ||
4604 | int ret; | ||
4605 | |||
4606 | #ifdef DEBUG_CALLBACK_TRACE | ||
4607 | printk(KERN_DEBUG "-> wavelan_attach()\n"); | ||
4608 | #endif | ||
4609 | |||
4610 | /* Initialize the dev_link_t structure */ | ||
4611 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
4612 | if (!link) return NULL; | ||
4613 | memset(link, 0, sizeof(struct dev_link_t)); | ||
4614 | |||
4615 | /* The io structure describes IO port mapping */ | ||
4616 | link->io.NumPorts1 = 8; | ||
4617 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
4618 | link->io.IOAddrLines = 3; | ||
4619 | |||
4620 | /* Interrupt setup */ | ||
4621 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
4622 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
4623 | link->irq.Handler = wavelan_interrupt; | ||
4624 | |||
4625 | /* General socket configuration */ | ||
4626 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
4627 | link->conf.Vcc = 50; | ||
4628 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
4629 | |||
4630 | /* Chain drivers */ | ||
4631 | link->next = dev_list; | ||
4632 | dev_list = link; | ||
4633 | |||
4634 | /* Allocate the generic data structure */ | ||
4635 | dev = alloc_etherdev(sizeof(net_local)); | ||
4636 | if (!dev) { | ||
4637 | kfree(link); | ||
4638 | return NULL; | ||
4639 | } | ||
4640 | link->priv = link->irq.Instance = dev; | ||
4641 | |||
4642 | lp = netdev_priv(dev); | ||
4643 | |||
4644 | /* Init specific data */ | ||
4645 | lp->configured = 0; | ||
4646 | lp->reconfig_82593 = FALSE; | ||
4647 | lp->nresets = 0; | ||
4648 | /* Multicast stuff */ | ||
4649 | lp->promiscuous = 0; | ||
4650 | lp->allmulticast = 0; | ||
4651 | lp->mc_count = 0; | ||
4652 | |||
4653 | /* Init spinlock */ | ||
4654 | spin_lock_init(&lp->spinlock); | ||
4655 | |||
4656 | /* back links */ | ||
4657 | lp->link = link; | ||
4658 | lp->dev = dev; | ||
4659 | |||
4660 | /* wavelan NET3 callbacks */ | ||
4661 | SET_MODULE_OWNER(dev); | ||
4662 | dev->open = &wavelan_open; | ||
4663 | dev->stop = &wavelan_close; | ||
4664 | dev->hard_start_xmit = &wavelan_packet_xmit; | ||
4665 | dev->get_stats = &wavelan_get_stats; | ||
4666 | dev->set_multicast_list = &wavelan_set_multicast_list; | ||
4667 | #ifdef SET_MAC_ADDRESS | ||
4668 | dev->set_mac_address = &wavelan_set_mac_address; | ||
4669 | #endif /* SET_MAC_ADDRESS */ | ||
4670 | |||
4671 | /* Set the watchdog timer */ | ||
4672 | dev->tx_timeout = &wavelan_watchdog; | ||
4673 | dev->watchdog_timeo = WATCHDOG_JIFFIES; | ||
4674 | SET_ETHTOOL_OPS(dev, &ops); | ||
4675 | |||
4676 | #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ | ||
4677 | dev->wireless_handlers = &wavelan_handler_def; | ||
4678 | lp->wireless_data.spy_data = &lp->spy_data; | ||
4679 | dev->wireless_data = &lp->wireless_data; | ||
4680 | #endif | ||
4681 | |||
4682 | /* Other specific data */ | ||
4683 | dev->mtu = WAVELAN_MTU; | ||
4684 | |||
4685 | /* Register with Card Services */ | ||
4686 | client_reg.dev_info = &dev_info; | ||
4687 | client_reg.EventMask = | ||
4688 | CS_EVENT_REGISTRATION_COMPLETE | | ||
4689 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
4690 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
4691 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
4692 | client_reg.event_handler = &wavelan_event; | ||
4693 | client_reg.Version = 0x0210; | ||
4694 | client_reg.event_callback_args.client_data = link; | ||
4695 | |||
4696 | #ifdef DEBUG_CONFIG_INFO | ||
4697 | printk(KERN_DEBUG "wavelan_attach(): almost done, calling pcmcia_register_client\n"); | ||
4698 | #endif | ||
4699 | |||
4700 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
4701 | if(ret != 0) | ||
4702 | { | ||
4703 | cs_error(link->handle, RegisterClient, ret); | ||
4704 | wavelan_detach(link); | ||
4705 | return NULL; | ||
4706 | } | ||
4707 | |||
4708 | #ifdef DEBUG_CALLBACK_TRACE | ||
4709 | printk(KERN_DEBUG "<- wavelan_attach()\n"); | ||
4710 | #endif | ||
4711 | |||
4712 | return link; | ||
4713 | } | ||
4714 | |||
4715 | /*------------------------------------------------------------------*/ | ||
4716 | /* | ||
4717 | * This deletes a driver "instance". The device is de-registered with | ||
4718 | * Card Services. If it has been released, all local data structures | ||
4719 | * are freed. Otherwise, the structures will be freed when the device | ||
4720 | * is released. | ||
4721 | */ | ||
4722 | static void | ||
4723 | wavelan_detach(dev_link_t * link) | ||
4724 | { | ||
4725 | #ifdef DEBUG_CALLBACK_TRACE | ||
4726 | printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); | ||
4727 | #endif | ||
4728 | |||
4729 | /* | ||
4730 | * If the device is currently configured and active, we won't | ||
4731 | * actually delete it yet. Instead, it is marked so that when the | ||
4732 | * release() function is called, that will trigger a proper | ||
4733 | * detach(). | ||
4734 | */ | ||
4735 | if(link->state & DEV_CONFIG) | ||
4736 | { | ||
4737 | /* Some others haven't done their job : give them another chance */ | ||
4738 | wv_pcmcia_release(link); | ||
4739 | } | ||
4740 | |||
4741 | /* Break the link with Card Services */ | ||
4742 | if(link->handle) | ||
4743 | pcmcia_deregister_client(link->handle); | ||
4744 | |||
4745 | /* Remove the interface data from the linked list */ | ||
4746 | if(dev_list == link) | ||
4747 | dev_list = link->next; | ||
4748 | else | ||
4749 | { | ||
4750 | dev_link_t * prev = dev_list; | ||
4751 | |||
4752 | while((prev != (dev_link_t *) NULL) && (prev->next != link)) | ||
4753 | prev = prev->next; | ||
4754 | |||
4755 | if(prev == (dev_link_t *) NULL) | ||
4756 | { | ||
4757 | #ifdef DEBUG_CONFIG_ERRORS | ||
4758 | printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n"); | ||
4759 | #endif | ||
4760 | return; | ||
4761 | } | ||
4762 | |||
4763 | prev->next = link->next; | ||
4764 | } | ||
4765 | |||
4766 | /* Free pieces */ | ||
4767 | if(link->priv) | ||
4768 | { | ||
4769 | struct net_device * dev = (struct net_device *) link->priv; | ||
4770 | |||
4771 | /* Remove ourselves from the kernel list of ethernet devices */ | ||
4772 | /* Warning : can't be called from interrupt, timer or wavelan_close() */ | ||
4773 | if (link->dev) | ||
4774 | unregister_netdev(dev); | ||
4775 | link->dev = NULL; | ||
4776 | ((net_local *)netdev_priv(dev))->link = NULL; | ||
4777 | ((net_local *)netdev_priv(dev))->dev = NULL; | ||
4778 | free_netdev(dev); | ||
4779 | } | ||
4780 | kfree(link); | ||
4781 | |||
4782 | #ifdef DEBUG_CALLBACK_TRACE | ||
4783 | printk(KERN_DEBUG "<- wavelan_detach()\n"); | ||
4784 | #endif | ||
4785 | } | ||
4786 | |||
4787 | /*------------------------------------------------------------------*/ | ||
4788 | /* | ||
4789 | * The card status event handler. Mostly, this schedules other stuff | ||
4790 | * to run after an event is received. A CARD_REMOVAL event also sets | ||
4791 | * some flags to discourage the net drivers from trying to talk to the | ||
4792 | * card any more. | ||
4793 | */ | ||
4794 | static int | ||
4795 | wavelan_event(event_t event, /* The event received */ | ||
4796 | int priority, | ||
4797 | event_callback_args_t * args) | ||
4798 | { | ||
4799 | dev_link_t * link = (dev_link_t *) args->client_data; | ||
4800 | struct net_device * dev = (struct net_device *) link->priv; | ||
4801 | |||
4802 | #ifdef DEBUG_CALLBACK_TRACE | ||
4803 | printk(KERN_DEBUG "->wavelan_event(): %s\n", | ||
4804 | ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" : | ||
4805 | ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" : | ||
4806 | ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" : | ||
4807 | ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" : | ||
4808 | ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" : | ||
4809 | ((event == CS_EVENT_PM_RESUME) ? "pm resume" : | ||
4810 | ((event == CS_EVENT_CARD_RESET) ? "card reset" : | ||
4811 | "unknown")))))))); | ||
4812 | #endif | ||
4813 | |||
4814 | switch(event) | ||
4815 | { | ||
4816 | case CS_EVENT_REGISTRATION_COMPLETE: | ||
4817 | #ifdef DEBUG_CONFIG_INFO | ||
4818 | printk(KERN_DEBUG "wavelan_cs: registration complete\n"); | ||
4819 | #endif | ||
4820 | break; | ||
4821 | |||
4822 | case CS_EVENT_CARD_REMOVAL: | ||
4823 | /* Oups ! The card is no more there */ | ||
4824 | link->state &= ~DEV_PRESENT; | ||
4825 | if(link->state & DEV_CONFIG) | ||
4826 | { | ||
4827 | /* Accept no more transmissions */ | ||
4828 | netif_device_detach(dev); | ||
4829 | |||
4830 | /* Release the card */ | ||
4831 | wv_pcmcia_release(link); | ||
4832 | } | ||
4833 | break; | ||
4834 | |||
4835 | case CS_EVENT_CARD_INSERTION: | ||
4836 | /* Reset and configure the card */ | ||
4837 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
4838 | if(wv_pcmcia_config(link) && | ||
4839 | wv_hw_config(dev)) | ||
4840 | wv_init_info(dev); | ||
4841 | else | ||
4842 | dev->irq = 0; | ||
4843 | break; | ||
4844 | |||
4845 | case CS_EVENT_PM_SUSPEND: | ||
4846 | /* NB: wavelan_close will be called, but too late, so we are | ||
4847 | * obliged to close nicely the wavelan here. David, could you | ||
4848 | * close the device before suspending them ? And, by the way, | ||
4849 | * could you, on resume, add a "route add -net ..." after the | ||
4850 | * ifconfig up ? Thanks... */ | ||
4851 | |||
4852 | /* Stop receiving new messages and wait end of transmission */ | ||
4853 | wv_ru_stop(dev); | ||
4854 | |||
4855 | /* Power down the module */ | ||
4856 | hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); | ||
4857 | |||
4858 | /* The card is now suspended */ | ||
4859 | link->state |= DEV_SUSPEND; | ||
4860 | /* Fall through... */ | ||
4861 | case CS_EVENT_RESET_PHYSICAL: | ||
4862 | if(link->state & DEV_CONFIG) | ||
4863 | { | ||
4864 | if(link->open) | ||
4865 | netif_device_detach(dev); | ||
4866 | pcmcia_release_configuration(link->handle); | ||
4867 | } | ||
4868 | break; | ||
4869 | |||
4870 | case CS_EVENT_PM_RESUME: | ||
4871 | link->state &= ~DEV_SUSPEND; | ||
4872 | /* Fall through... */ | ||
4873 | case CS_EVENT_CARD_RESET: | ||
4874 | if(link->state & DEV_CONFIG) | ||
4875 | { | ||
4876 | pcmcia_request_configuration(link->handle, &link->conf); | ||
4877 | if(link->open) /* If RESET -> True, If RESUME -> False ? */ | ||
4878 | { | ||
4879 | wv_hw_reset(dev); | ||
4880 | netif_device_attach(dev); | ||
4881 | } | ||
4882 | } | ||
4883 | break; | ||
4884 | } | ||
4885 | |||
4886 | #ifdef DEBUG_CALLBACK_TRACE | ||
4887 | printk(KERN_DEBUG "<-wavelan_event()\n"); | ||
4888 | #endif | ||
4889 | return 0; | ||
4890 | } | ||
4891 | |||
4892 | static struct pcmcia_driver wavelan_driver = { | ||
4893 | .owner = THIS_MODULE, | ||
4894 | .drv = { | ||
4895 | .name = "wavelan_cs", | ||
4896 | }, | ||
4897 | .attach = wavelan_attach, | ||
4898 | .detach = wavelan_detach, | ||
4899 | }; | ||
4900 | |||
4901 | static int __init | ||
4902 | init_wavelan_cs(void) | ||
4903 | { | ||
4904 | return pcmcia_register_driver(&wavelan_driver); | ||
4905 | } | ||
4906 | |||
4907 | static void __exit | ||
4908 | exit_wavelan_cs(void) | ||
4909 | { | ||
4910 | pcmcia_unregister_driver(&wavelan_driver); | ||
4911 | } | ||
4912 | |||
4913 | module_init(init_wavelan_cs); | ||
4914 | module_exit(exit_wavelan_cs); | ||
diff --git a/drivers/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h new file mode 100644 index 000000000000..29cff6daf860 --- /dev/null +++ b/drivers/net/wireless/wavelan_cs.h | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | * Wavelan Pcmcia driver | ||
3 | * | ||
4 | * Jean II - HPLB '96 | ||
5 | * | ||
6 | * Reorganization and extension of the driver. | ||
7 | * Original copyright follow. See wavelan_cs.h for details. | ||
8 | * | ||
9 | * This file contain the declarations of the Wavelan hardware. Note that | ||
10 | * the Pcmcia Wavelan include a i82593 controller (see definitions in | ||
11 | * file i82593.h). | ||
12 | * | ||
13 | * The main difference between the pcmcia hardware and the ISA one is | ||
14 | * the Ethernet Controller (i82593 instead of i82586). The i82593 allow | ||
15 | * only one send buffer. The PSA (Parameter Storage Area : EEprom for | ||
16 | * permanent storage of various info) is memory mapped, but not the | ||
17 | * MMI (Modem Management Interface). | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: | ||
22 | * An Ethernet-like radio transceiver controlled by an Intel 82593 | ||
23 | * coprocessor. | ||
24 | * | ||
25 | * | ||
26 | **************************************************************************** | ||
27 | * Copyright 1995 | ||
28 | * Anthony D. Joseph | ||
29 | * Massachusetts Institute of Technology | ||
30 | * | ||
31 | * Permission to use, copy, modify, and distribute this program | ||
32 | * for any purpose and without fee is hereby granted, provided | ||
33 | * that this copyright and permission notice appear on all copies | ||
34 | * and supporting documentation, the name of M.I.T. not be used | ||
35 | * in advertising or publicity pertaining to distribution of the | ||
36 | * program without specific prior permission, and notice be given | ||
37 | * in supporting documentation that copying and distribution is | ||
38 | * by permission of M.I.T. M.I.T. makes no representations about | ||
39 | * the suitability of this software for any purpose. It is pro- | ||
40 | * vided "as is" without express or implied warranty. | ||
41 | **************************************************************************** | ||
42 | * | ||
43 | * | ||
44 | * Credits: | ||
45 | * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for | ||
46 | * providing extremely useful information about WaveLAN PCMCIA hardware | ||
47 | * | ||
48 | * This driver is based upon several other drivers, in particular: | ||
49 | * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter | ||
50 | * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter | ||
51 | * Anders Klemets' PCMCIA WaveLAN adapter driver | ||
52 | * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter | ||
53 | */ | ||
54 | |||
55 | #ifndef _WAVELAN_CS_H | ||
56 | #define _WAVELAN_CS_H | ||
57 | |||
58 | /************************** MAGIC NUMBERS ***************************/ | ||
59 | |||
60 | /* The detection of the wavelan card is made by reading the MAC address | ||
61 | * from the card and checking it. If you have a non AT&T product (OEM, | ||
62 | * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this | ||
63 | * part to accommodate your hardware... | ||
64 | */ | ||
65 | const unsigned char MAC_ADDRESSES[][3] = | ||
66 | { | ||
67 | { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ | ||
68 | { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ | ||
69 | { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ | ||
70 | { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ | ||
71 | /* Add your card here and send me the patch ! */ | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * Constants used to convert channels to frequencies | ||
76 | */ | ||
77 | |||
78 | /* Frequency available in the 2.0 modem, in units of 250 kHz | ||
79 | * (as read in the offset register of the dac area). | ||
80 | * Used to map channel numbers used by `wfreqsel' to frequencies | ||
81 | */ | ||
82 | const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, | ||
83 | 0xD0, 0xF0, 0xF8, 0x150 }; | ||
84 | |||
85 | /* Frequencies of the 1.0 modem (fixed frequencies). | ||
86 | * Use to map the PSA `subband' to a frequency | ||
87 | * Note : all frequencies apart from the first one need to be multiplied by 10 | ||
88 | */ | ||
89 | const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; | ||
90 | |||
91 | |||
92 | /*************************** PC INTERFACE ****************************/ | ||
93 | |||
94 | /* WaveLAN host interface definitions */ | ||
95 | |||
96 | #define LCCR(base) (base) /* LAN Controller Command Register */ | ||
97 | #define LCSR(base) (base) /* LAN Controller Status Register */ | ||
98 | #define HACR(base) (base+0x1) /* Host Adapter Command Register */ | ||
99 | #define HASR(base) (base+0x1) /* Host Adapter Status Register */ | ||
100 | #define PIORL(base) (base+0x2) /* Program I/O Register Low */ | ||
101 | #define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ | ||
102 | #define PIORH(base) (base+0x3) /* Program I/O Register High */ | ||
103 | #define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ | ||
104 | #define PIOP(base) (base+0x4) /* Program I/O Port */ | ||
105 | #define MMR(base) (base+0x6) /* MMI Address Register */ | ||
106 | #define MMD(base) (base+0x7) /* MMI Data Register */ | ||
107 | |||
108 | /* Host Adaptor Command Register bit definitions */ | ||
109 | |||
110 | #define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ | ||
111 | #define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ | ||
112 | #define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ | ||
113 | #define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ | ||
114 | #define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ | ||
115 | |||
116 | #define HACR_RESET (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET) | ||
117 | #define HACR_DEFAULT (HACR_PWR_STAT) | ||
118 | |||
119 | /* Host Adapter Status Register bit definitions */ | ||
120 | |||
121 | #define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ | ||
122 | #define HASR_LOF (1 << 3) /* Lock out flag status */ | ||
123 | #define HASR_NO_CLK (1 << 4) /* active when modem not connected */ | ||
124 | |||
125 | /* Miscellaneous bit definitions */ | ||
126 | |||
127 | #define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ | ||
128 | #define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ | ||
129 | #define PIORH_MASK 0x1f /* only low 5 bits are significant */ | ||
130 | #define RPLH_MASK 0x1f /* only low 5 bits are significant */ | ||
131 | #define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ | ||
132 | |||
133 | /* Attribute Memory map */ | ||
134 | |||
135 | #define CIS_ADDR 0x0000 /* Card Information Status Register */ | ||
136 | #define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ | ||
137 | #define EEPROM_ADDR 0x1000 /* EEPROM address (unused ?) */ | ||
138 | #define COR_ADDR 0x4000 /* Configuration Option Register */ | ||
139 | |||
140 | /* Configuration Option Register bit definitions */ | ||
141 | |||
142 | #define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ | ||
143 | #define COR_SW_RESET (1 << 7) /* Software Reset on true */ | ||
144 | #define COR_LEVEL_IRQ (1 << 6) /* Level IRQ */ | ||
145 | |||
146 | /* Local Memory map */ | ||
147 | |||
148 | #define RX_BASE 0x0000 /* Receive memory, 8 kB */ | ||
149 | #define TX_BASE 0x2000 /* Transmit memory, 2 kB */ | ||
150 | #define UNUSED_BASE 0x2800 /* Unused, 22 kB */ | ||
151 | #define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ | ||
152 | #define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ | ||
153 | |||
154 | #define TRUE 1 | ||
155 | #define FALSE 0 | ||
156 | |||
157 | #define MOD_ENAL 1 | ||
158 | #define MOD_PROM 2 | ||
159 | |||
160 | /* Size of a MAC address */ | ||
161 | #define WAVELAN_ADDR_SIZE 6 | ||
162 | |||
163 | /* Maximum size of Wavelan packet */ | ||
164 | #define WAVELAN_MTU 1500 | ||
165 | |||
166 | #define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) | ||
167 | |||
168 | /********************** PARAMETER STORAGE AREA **********************/ | ||
169 | |||
170 | /* | ||
171 | * Parameter Storage Area (PSA). | ||
172 | */ | ||
173 | typedef struct psa_t psa_t; | ||
174 | struct psa_t | ||
175 | { | ||
176 | /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */ | ||
177 | unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ | ||
178 | unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ | ||
179 | unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ | ||
180 | unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ | ||
181 | unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ | ||
182 | unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ | ||
183 | unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ | ||
184 | unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ | ||
185 | unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ | ||
186 | unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ | ||
187 | |||
188 | unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ | ||
189 | unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ | ||
190 | unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ | ||
191 | #define PSA_UNIVERSAL 0 /* Universal (factory) */ | ||
192 | #define PSA_LOCAL 1 /* Local */ | ||
193 | unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ | ||
194 | #define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ | ||
195 | #define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ | ||
196 | #define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ | ||
197 | #define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ | ||
198 | #define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ | ||
199 | unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ | ||
200 | unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ | ||
201 | #define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ | ||
202 | unsigned char psa_subband; /* [0x20] Subband */ | ||
203 | #define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ | ||
204 | #define PSA_SUBBAND_2425 1 /* 2425 MHz */ | ||
205 | #define PSA_SUBBAND_2460 2 /* 2460 MHz */ | ||
206 | #define PSA_SUBBAND_2484 3 /* 2484 MHz */ | ||
207 | #define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ | ||
208 | unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ | ||
209 | unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ | ||
210 | unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ | ||
211 | unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ | ||
212 | unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ | ||
213 | unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ | ||
214 | unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ | ||
215 | unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ | ||
216 | unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ | ||
217 | unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ | ||
218 | unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ | ||
219 | unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ | ||
220 | unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ | ||
221 | }; | ||
222 | |||
223 | /* Size for structure checking (if padding is correct) */ | ||
224 | #define PSA_SIZE 64 | ||
225 | |||
226 | /* Calculate offset of a field in the above structure | ||
227 | * Warning : only even addresses are used */ | ||
228 | #define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) | ||
229 | |||
230 | /******************** MODEM MANAGEMENT INTERFACE ********************/ | ||
231 | |||
232 | /* | ||
233 | * Modem Management Controller (MMC) write structure. | ||
234 | */ | ||
235 | typedef struct mmw_t mmw_t; | ||
236 | struct mmw_t | ||
237 | { | ||
238 | unsigned char mmw_encr_key[8]; /* encryption key */ | ||
239 | unsigned char mmw_encr_enable; /* enable/disable encryption */ | ||
240 | #define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ | ||
241 | #define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ | ||
242 | unsigned char mmw_unused0[1]; /* unused */ | ||
243 | unsigned char mmw_des_io_invert; /* Encryption option */ | ||
244 | #define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ | ||
245 | #define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ | ||
246 | unsigned char mmw_unused1[5]; /* unused */ | ||
247 | unsigned char mmw_loopt_sel; /* looptest selection */ | ||
248 | #define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ | ||
249 | #define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ | ||
250 | #define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ | ||
251 | #define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ | ||
252 | #define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ | ||
253 | #define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ | ||
254 | #define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ | ||
255 | unsigned char mmw_jabber_enable; /* jabber timer enable */ | ||
256 | /* Abort transmissions > 200 ms */ | ||
257 | unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ | ||
258 | /* 0 : signal level & qual updated for every new message, 1 : frozen */ | ||
259 | unsigned char mmw_anten_sel; /* antenna selection */ | ||
260 | #define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ | ||
261 | #define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ | ||
262 | unsigned char mmw_ifs; /* inter frame spacing */ | ||
263 | /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ | ||
264 | unsigned char mmw_mod_delay; /* modem delay (synchro) */ | ||
265 | unsigned char mmw_jam_time; /* jamming time (after collision) */ | ||
266 | unsigned char mmw_unused2[1]; /* unused */ | ||
267 | unsigned char mmw_thr_pre_set; /* level threshold preset */ | ||
268 | /* Discard all packet with signal < this value (4) */ | ||
269 | unsigned char mmw_decay_prm; /* decay parameters */ | ||
270 | unsigned char mmw_decay_updat_prm; /* decay update parameterz */ | ||
271 | unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ | ||
272 | /* Discard all packet with quality < this value (3) */ | ||
273 | unsigned char mmw_netw_id_l; /* NWID low order byte */ | ||
274 | unsigned char mmw_netw_id_h; /* NWID high order byte */ | ||
275 | /* Network ID or Domain : create virtual net on the air */ | ||
276 | |||
277 | /* 2.0 Hardware extension - frequency selection support */ | ||
278 | unsigned char mmw_mode_select; /* for analog tests (set to 0) */ | ||
279 | unsigned char mmw_unused3[1]; /* unused */ | ||
280 | unsigned char mmw_fee_ctrl; /* frequency eeprom control */ | ||
281 | #define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ | ||
282 | #define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ | ||
283 | #define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ | ||
284 | #define MMW_FEE_CTRL_READ 0x06 /* Read */ | ||
285 | #define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ | ||
286 | #define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ | ||
287 | #define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ | ||
288 | #define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ | ||
289 | #define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ | ||
290 | #define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ | ||
291 | #define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ | ||
292 | #define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ | ||
293 | #define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ | ||
294 | /* Never issue this command (PRDS) : it's irreversible !!! */ | ||
295 | |||
296 | unsigned char mmw_fee_addr; /* EEprom address */ | ||
297 | #define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ | ||
298 | #define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ | ||
299 | #define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ | ||
300 | #define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ | ||
301 | #define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ | ||
302 | #define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ | ||
303 | |||
304 | unsigned char mmw_fee_data_l; /* Write data to EEprom */ | ||
305 | unsigned char mmw_fee_data_h; /* high octet */ | ||
306 | unsigned char mmw_ext_ant; /* Setting for external antenna */ | ||
307 | #define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ | ||
308 | #define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ | ||
309 | #define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ | ||
310 | #define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ | ||
311 | #define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ | ||
312 | }; | ||
313 | |||
314 | /* Size for structure checking (if padding is correct) */ | ||
315 | #define MMW_SIZE 37 | ||
316 | |||
317 | /* Calculate offset of a field in the above structure */ | ||
318 | #define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) | ||
319 | |||
320 | |||
321 | /* | ||
322 | * Modem Management Controller (MMC) read structure. | ||
323 | */ | ||
324 | typedef struct mmr_t mmr_t; | ||
325 | struct mmr_t | ||
326 | { | ||
327 | unsigned char mmr_unused0[8]; /* unused */ | ||
328 | unsigned char mmr_des_status; /* encryption status */ | ||
329 | unsigned char mmr_des_avail; /* encryption available (0x55 read) */ | ||
330 | #define MMR_DES_AVAIL_DES 0x55 /* DES available */ | ||
331 | #define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ | ||
332 | unsigned char mmr_des_io_invert; /* des I/O invert register */ | ||
333 | unsigned char mmr_unused1[5]; /* unused */ | ||
334 | unsigned char mmr_dce_status; /* DCE status */ | ||
335 | #define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ | ||
336 | #define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ | ||
337 | #define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ | ||
338 | #define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ | ||
339 | #define MMR_DCE_STATUS 0x0F /* mask to get the bits */ | ||
340 | unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ | ||
341 | unsigned char mmr_unused2[2]; /* unused */ | ||
342 | unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ | ||
343 | unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ | ||
344 | /* Warning : Read high order octet first !!! */ | ||
345 | unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ | ||
346 | unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ | ||
347 | unsigned char mmr_thr_pre_set; /* level threshold preset */ | ||
348 | #define MMR_THR_PRE_SET 0x3F /* level threshold preset */ | ||
349 | #define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ | ||
350 | unsigned char mmr_signal_lvl; /* signal level */ | ||
351 | #define MMR_SIGNAL_LVL 0x3F /* signal level */ | ||
352 | #define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ | ||
353 | unsigned char mmr_silence_lvl; /* silence level (noise) */ | ||
354 | #define MMR_SILENCE_LVL 0x3F /* silence level */ | ||
355 | #define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ | ||
356 | unsigned char mmr_sgnl_qual; /* signal quality */ | ||
357 | #define MMR_SGNL_QUAL 0x0F /* signal quality */ | ||
358 | #define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ | ||
359 | unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ | ||
360 | unsigned char mmr_unused3[3]; /* unused */ | ||
361 | |||
362 | /* 2.0 Hardware extension - frequency selection support */ | ||
363 | unsigned char mmr_fee_status; /* Status of frequency eeprom */ | ||
364 | #define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ | ||
365 | #define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ | ||
366 | #define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ | ||
367 | unsigned char mmr_unused4[1]; /* unused */ | ||
368 | unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ | ||
369 | unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ | ||
370 | }; | ||
371 | |||
372 | /* Size for structure checking (if padding is correct) */ | ||
373 | #define MMR_SIZE 36 | ||
374 | |||
375 | /* Calculate offset of a field in the above structure */ | ||
376 | #define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) | ||
377 | |||
378 | |||
379 | /* Make the two above structures one */ | ||
380 | typedef union mm_t | ||
381 | { | ||
382 | struct mmw_t w; /* Write to the mmc */ | ||
383 | struct mmr_t r; /* Read from the mmc */ | ||
384 | } mm_t; | ||
385 | |||
386 | #endif /* _WAVELAN_CS_H */ | ||
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h new file mode 100644 index 000000000000..ea2ef8dddb92 --- /dev/null +++ b/drivers/net/wireless/wavelan_cs.p.h | |||
@@ -0,0 +1,813 @@ | |||
1 | /* | ||
2 | * Wavelan Pcmcia driver | ||
3 | * | ||
4 | * Jean II - HPLB '96 | ||
5 | * | ||
6 | * Reorganisation and extension of the driver. | ||
7 | * | ||
8 | * This file contain all definition and declarations necessary for the | ||
9 | * wavelan pcmcia driver. This file is a private header, so it should | ||
10 | * be included only on wavelan_cs.c !!! | ||
11 | */ | ||
12 | |||
13 | #ifndef WAVELAN_CS_P_H | ||
14 | #define WAVELAN_CS_P_H | ||
15 | |||
16 | /************************** DOCUMENTATION **************************/ | ||
17 | /* | ||
18 | * This driver provide a Linux interface to the Wavelan Pcmcia hardware | ||
19 | * The Wavelan is a product of Lucent (http://www.wavelan.com/). | ||
20 | * This division was formerly part of NCR and then AT&T. | ||
21 | * Wavelan are also distributed by DEC (RoamAbout DS)... | ||
22 | * | ||
23 | * To know how to use this driver, read the PCMCIA HOWTO. | ||
24 | * If you want to exploit the many other fonctionalities, look comments | ||
25 | * in the code... | ||
26 | * | ||
27 | * This driver is the result of the effort of many peoples (see below). | ||
28 | */ | ||
29 | |||
30 | /* ------------------------ SPECIFIC NOTES ------------------------ */ | ||
31 | /* | ||
32 | * Web page | ||
33 | * -------- | ||
34 | * I try to maintain a web page with the Wireless LAN Howto at : | ||
35 | * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html | ||
36 | * | ||
37 | * SMP | ||
38 | * --- | ||
39 | * We now are SMP compliant (I eventually fixed the remaining bugs). | ||
40 | * The driver has been tested on a dual P6-150 and survived my usual | ||
41 | * set of torture tests. | ||
42 | * Anyway, I spent enough time chasing interrupt re-entrancy during | ||
43 | * errors or reconfigure, and I designed the locked/unlocked sections | ||
44 | * of the driver with great care, and with the recent addition of | ||
45 | * the spinlock (thanks to the new API), we should be quite close to | ||
46 | * the truth. | ||
47 | * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), | ||
48 | * but better safe than sorry (especially at 2 Mb/s ;-). | ||
49 | * | ||
50 | * I have also looked into disabling only our interrupt on the card | ||
51 | * (via HACR) instead of all interrupts in the processor (via cli), | ||
52 | * so that other driver are not impacted, and it look like it's | ||
53 | * possible, but it's very tricky to do right (full of races). As | ||
54 | * the gain would be mostly for SMP systems, it can wait... | ||
55 | * | ||
56 | * Debugging and options | ||
57 | * --------------------- | ||
58 | * You will find below a set of '#define" allowing a very fine control | ||
59 | * on the driver behaviour and the debug messages printed. | ||
60 | * The main options are : | ||
61 | * o WAVELAN_ROAMING, for the experimental roaming support. | ||
62 | * o SET_PSA_CRC, to have your card correctly recognised by | ||
63 | * an access point and the Point-to-Point diagnostic tool. | ||
64 | * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) | ||
65 | * (otherwise we always start afresh with some defaults) | ||
66 | * | ||
67 | * wavelan_cs.o is darn too big | ||
68 | * ------------------------- | ||
69 | * That's true ! There is a very simple way to reduce the driver | ||
70 | * object by 33% (yes !). Comment out the following line : | ||
71 | * #include <linux/wireless.h> | ||
72 | * Other compile options can also reduce the size of it... | ||
73 | * | ||
74 | * MAC address and hardware detection : | ||
75 | * ---------------------------------- | ||
76 | * The detection code of the wavelan chech that the first 3 | ||
77 | * octets of the MAC address fit the company code. This type of | ||
78 | * detection work well for AT&T cards (because the AT&T code is | ||
79 | * hardcoded in wavelan_cs.h), but of course will fail for other | ||
80 | * manufacturer. | ||
81 | * | ||
82 | * If you are sure that your card is derived from the wavelan, | ||
83 | * here is the way to configure it : | ||
84 | * 1) Get your MAC address | ||
85 | * a) With your card utilities (wfreqsel, instconf, ...) | ||
86 | * b) With the driver : | ||
87 | * o compile the kernel with DEBUG_CONFIG_INFO enabled | ||
88 | * o Boot and look the card messages | ||
89 | * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan_cs.h) | ||
90 | * 3) Compile & verify | ||
91 | * 4) Send me the MAC code - I will include it in the next version... | ||
92 | * | ||
93 | */ | ||
94 | |||
95 | /* --------------------- WIRELESS EXTENSIONS --------------------- */ | ||
96 | /* | ||
97 | * This driver is the first one to support "wireless extensions". | ||
98 | * This set of extensions provide you some way to control the wireless | ||
99 | * caracteristics of the hardware in a standard way and support for | ||
100 | * applications for taking advantage of it (like Mobile IP). | ||
101 | * | ||
102 | * You will need to enable the CONFIG_NET_RADIO define in the kernel | ||
103 | * configuration to enable the wireless extensions (this is the one | ||
104 | * giving access to the radio network device choice). | ||
105 | * | ||
106 | * It might also be a good idea as well to fetch the wireless tools to | ||
107 | * configure the device and play a bit. | ||
108 | */ | ||
109 | |||
110 | /* ---------------------------- FILES ---------------------------- */ | ||
111 | /* | ||
112 | * wavelan_cs.c : The actual code for the driver - C functions | ||
113 | * | ||
114 | * wavelan_cs.p.h : Private header : local types / vars for the driver | ||
115 | * | ||
116 | * wavelan_cs.h : Description of the hardware interface & structs | ||
117 | * | ||
118 | * i82593.h : Description if the Ethernet controller | ||
119 | */ | ||
120 | |||
121 | /* --------------------------- HISTORY --------------------------- */ | ||
122 | /* | ||
123 | * The history of the Wavelan drivers is as complicated as history of | ||
124 | * the Wavelan itself (NCR -> AT&T -> Lucent). | ||
125 | * | ||
126 | * All started with Anders Klemets <klemets@paul.rutgers.edu>, | ||
127 | * writting a Wavelan ISA driver for the MACH microkernel. Girish | ||
128 | * Welling <welling@paul.rutgers.edu> had also worked on it. | ||
129 | * Keith Moore modify this for the Pcmcia hardware. | ||
130 | * | ||
131 | * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI | ||
132 | * and add specific Pcmcia support (there is currently no equivalent | ||
133 | * of the PCMCIA package under BSD...). | ||
134 | * | ||
135 | * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to FreeBSD. | ||
136 | * | ||
137 | * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux. | ||
138 | * | ||
139 | * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver | ||
140 | * (with help of the BSDI PCMCIA driver) for PCMCIA. | ||
141 | * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work. | ||
142 | * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start | ||
143 | * correctly 2.00 cards (2.4 GHz with frequency selection). | ||
144 | * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his | ||
145 | * Pcmcia package (+ bug corrections). | ||
146 | * | ||
147 | * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some | ||
148 | * patchs to the Pcmcia driver. After, I added code in the ISA driver | ||
149 | * for Wireless Extensions and full support of frequency selection | ||
150 | * cards. Now, I'm doing the same to the Pcmcia driver + some | ||
151 | * reorganisation. | ||
152 | * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me | ||
153 | * much needed informations on the Wavelan hardware. | ||
154 | */ | ||
155 | |||
156 | /* By the way : for the copyright & legal stuff : | ||
157 | * Almost everybody wrote code under GNU or BSD license (or alike), | ||
158 | * and want that their original copyright remain somewhere in the | ||
159 | * code (for myself, I go with the GPL). | ||
160 | * Nobody want to take responsibility for anything, except the fame... | ||
161 | */ | ||
162 | |||
163 | /* --------------------------- CREDITS --------------------------- */ | ||
164 | /* | ||
165 | * Credits: | ||
166 | * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and | ||
167 | * Loeke Brederveld of Lucent for providing extremely useful | ||
168 | * information about WaveLAN PCMCIA hardware | ||
169 | * | ||
170 | * This driver is based upon several other drivers, in particular: | ||
171 | * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter | ||
172 | * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter | ||
173 | * Anders Klemets' PCMCIA WaveLAN adapter driver | ||
174 | * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter | ||
175 | * | ||
176 | * Additional Credits: | ||
177 | * | ||
178 | * This software was originally developed under Linux 1.2.3 | ||
179 | * (Slackware 2.0 distribution). | ||
180 | * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) | ||
181 | * with an HP OmniBook 4000 and then a 5500. | ||
182 | * | ||
183 | * It is based on other device drivers and information either written | ||
184 | * or supplied by: | ||
185 | * James Ashton (jaa101@syseng.anu.edu.au), | ||
186 | * Ajay Bakre (bakre@paul.rutgers.edu), | ||
187 | * Donald Becker (becker@super.org), | ||
188 | * Jim Binkley <jrb@cs.pdx.edu>, | ||
189 | * Loeke Brederveld <lbrederv@wavelan.com>, | ||
190 | * Allan Creighton (allanc@cs.su.oz.au), | ||
191 | * Brent Elphick <belphick@uwaterloo.ca>, | ||
192 | * Joe Finney <joe@comp.lancs.ac.uk>, | ||
193 | * Matthew Geier (matthew@cs.su.oz.au), | ||
194 | * Remo di Giovanni (remo@cs.su.oz.au), | ||
195 | * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), | ||
196 | * David Hinds <dahinds@users.sourceforge.net>, | ||
197 | * Jan Hoogendoorn (c/o marteijn@lucent.com), | ||
198 | * Bruce Janson <bruce@cs.usyd.edu.au>, | ||
199 | * Anthony D. Joseph <adj@lcs.mit.edu>, | ||
200 | * Anders Klemets (klemets@paul.rutgers.edu), | ||
201 | * Yunzhou Li <yunzhou@strat.iol.unh.edu>, | ||
202 | * Marc Meertens (mmeertens@lucent.com), | ||
203 | * Keith Moore, | ||
204 | * Robert Morris (rtm@das.harvard.edu), | ||
205 | * Ian Parkin (ian@cs.su.oz.au), | ||
206 | * John Rosenberg (johnr@cs.su.oz.au), | ||
207 | * George Rossi (george@phm.gov.au), | ||
208 | * Arthur Scott (arthur@cs.su.oz.au), | ||
209 | * Stanislav Sinyagin <stas@isf.ru> | ||
210 | * Peter Storey, | ||
211 | * Jean Tourrilhes <jt@hpl.hp.com>, | ||
212 | * Girish Welling (welling@paul.rutgers.edu) | ||
213 | * Clark Woodworth <clark@hiway1.exit109.com> | ||
214 | * Yongguang Zhang <ygz@isl.hrl.hac.com>... | ||
215 | */ | ||
216 | |||
217 | /* ------------------------- IMPROVEMENTS ------------------------- */ | ||
218 | /* | ||
219 | * I proudly present : | ||
220 | * | ||
221 | * Changes made in 2.8.22 : | ||
222 | * ---------------------- | ||
223 | * - improved wv_set_multicast_list | ||
224 | * - catch spurious interrupt | ||
225 | * - correct release of the device | ||
226 | * | ||
227 | * Changes mades in release : | ||
228 | * ------------------------ | ||
229 | * - Reorganisation of the code, function name change | ||
230 | * - Creation of private header (wavelan_cs.h) | ||
231 | * - Reorganised debug messages | ||
232 | * - More comments, history, ... | ||
233 | * - Configure earlier (in "insert" instead of "open") | ||
234 | * and do things only once | ||
235 | * - mmc_init : configure the PSA if not done | ||
236 | * - mmc_init : 2.00 detection better code for 2.00 init | ||
237 | * - better info at startup | ||
238 | * - Correct a HUGE bug (volatile & uncalibrated busy loop) | ||
239 | * in wv_82593_cmd => config speedup | ||
240 | * - Stop receiving & power down on close (and power up on open) | ||
241 | * use "ifconfig down" & "ifconfig up ; route add -net ..." | ||
242 | * - Send packets : add watchdog instead of pooling | ||
243 | * - Receive : check frame wrap around & try to recover some frames | ||
244 | * - wavelan_set_multicast_list : avoid reset | ||
245 | * - add wireless extensions (ioctl & get_wireless_stats) | ||
246 | * get/set nwid/frequency on fly, info for /proc/net/wireless | ||
247 | * - Suppress useless stuff from lp (net_local), but add link | ||
248 | * - More inlines | ||
249 | * - Lot of others minor details & cleanups | ||
250 | * | ||
251 | * Changes made in second release : | ||
252 | * ------------------------------ | ||
253 | * - Optimise wv_85893_reconfig stuff, fix potential problems | ||
254 | * - Change error values for ioctl | ||
255 | * - Non blocking wv_ru_stop() + call wv_reset() in case of problems | ||
256 | * - Remove development printk from wavelan_watchdog() | ||
257 | * - Remove of the watchdog to wavelan_close instead of wavelan_release | ||
258 | * fix potential problems... | ||
259 | * - Start debugging suspend stuff (but it's still a bit weird) | ||
260 | * - Debug & optimize dump header/packet in Rx & Tx (debug) | ||
261 | * - Use "readb" and "writeb" to be kernel 2.1 compliant | ||
262 | * - Better handling of bogus interrupts | ||
263 | * - Wireless extension : SETSPY and GETSPY | ||
264 | * - Remove old stuff (stats - for those needing it, just ask me...) | ||
265 | * - Make wireless extensions optional | ||
266 | * | ||
267 | * Changes made in third release : | ||
268 | * ----------------------------- | ||
269 | * - cleanups & typos | ||
270 | * - modif wireless ext (spy -> only one pointer) | ||
271 | * - new private ioctl to set/get quality & level threshold | ||
272 | * - Init : correct default value of level threshold for pcmcia | ||
273 | * - kill watchdog in hw_reset | ||
274 | * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) | ||
275 | * - Add message level (debug stuff in /var/adm/debug & errors not | ||
276 | * displayed at console and still in /var/adm/messages) | ||
277 | * | ||
278 | * Changes made in fourth release : | ||
279 | * ------------------------------ | ||
280 | * - multicast support (yes !) thanks to Yongguang Zhang. | ||
281 | * | ||
282 | * Changes made in fifth release (2.9.0) : | ||
283 | * ------------------------------------- | ||
284 | * - Revisited multicast code (it was mostly wrong). | ||
285 | * - protect code in wv_82593_reconfig with dev->tbusy (oups !) | ||
286 | * | ||
287 | * Changes made in sixth release (2.9.1a) : | ||
288 | * -------------------------------------- | ||
289 | * - Change the detection code for multi manufacturer code support | ||
290 | * - Correct bug (hang kernel) in init when we were "rejecting" a card | ||
291 | * | ||
292 | * Changes made in seventh release (2.9.1b) : | ||
293 | * ---------------------------------------- | ||
294 | * - Update to wireless extensions changes | ||
295 | * - Silly bug in card initial configuration (psa_conf_status) | ||
296 | * | ||
297 | * Changes made in eigth release : | ||
298 | * ----------------------------- | ||
299 | * - Small bug in debug code (probably not the last one...) | ||
300 | * - 1.2.13 support (thanks to Clark Woodworth) | ||
301 | * | ||
302 | * Changes made for release in 2.9.2b : | ||
303 | * ---------------------------------- | ||
304 | * - Level threshold is now a standard wireless extension (version 4 !) | ||
305 | * - modules parameters types for kernel > 2.1.17 | ||
306 | * - updated man page | ||
307 | * - Others cleanup from David Hinds | ||
308 | * | ||
309 | * Changes made for release in 2.9.5 : | ||
310 | * --------------------------------- | ||
311 | * - byte count stats (courtesy of David Hinds) | ||
312 | * - Remove dev_tint stuff (courtesy of David Hinds) | ||
313 | * - Others cleanup from David Hinds | ||
314 | * - Encryption setting from Brent Elphick (thanks a lot !) | ||
315 | * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) | ||
316 | * | ||
317 | * Changes made for release in 2.9.6 : | ||
318 | * --------------------------------- | ||
319 | * - fix bug : no longuer disable watchdog in case of bogus interrupt | ||
320 | * - increase timeout in config code for picky hardware | ||
321 | * - mask unused bits in status (Wireless Extensions) | ||
322 | * | ||
323 | * Changes integrated by Justin Seger <jseger@MIT.EDU> & David Hinds : | ||
324 | * ----------------------------------------------------------------- | ||
325 | * - Roaming "hack" from Joe Finney <joe@comp.lancs.ac.uk> | ||
326 | * - PSA CRC code from Bob Gray <rgray@bald.cs.dartmouth.edu> | ||
327 | * - Better initialisation of the i82593 controller | ||
328 | * from Joseph K. O'Sullivan <josullvn+@cs.cmu.edu> | ||
329 | * | ||
330 | * Changes made for release in 3.0.10 : | ||
331 | * ---------------------------------- | ||
332 | * - Fix eject "hang" of the driver under 2.2.X : | ||
333 | * o create wv_flush_stale_links() | ||
334 | * o Rename wavelan_release to wv_pcmcia_release & move up | ||
335 | * o move unregister_netdev to wavelan_detach() | ||
336 | * o wavelan_release() no longer call wavelan_detach() | ||
337 | * o Suppress "release" timer | ||
338 | * o Other cleanups & fixes | ||
339 | * - New MAC address in the probe | ||
340 | * - Reorg PSA_CRC code (endian neutral & cleaner) | ||
341 | * - Correct initialisation of the i82593 from Lucent manual | ||
342 | * - Put back the watchdog, with larger timeout | ||
343 | * - TRANSMIT_NO_CRC is a "normal" error, so recover from it | ||
344 | * from Derrick J Brashear <shadow@dementia.org> | ||
345 | * - Better handling of TX and RX normal failure conditions | ||
346 | * - #ifdef out all the roaming code | ||
347 | * - Add ESSID & "AP current address" ioctl stubs | ||
348 | * - General cleanup of the code | ||
349 | * | ||
350 | * Changes made for release in 3.0.13 : | ||
351 | * ---------------------------------- | ||
352 | * - Re-enable compilation of roaming code by default, but with | ||
353 | * do_roaming = 0 | ||
354 | * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather | ||
355 | * at the demand of John Carol Langford <jcl@gs176.sp.cs.cmu.edu> | ||
356 | * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. | ||
357 | * | ||
358 | * Changes made for release in 3.0.15 : | ||
359 | * ---------------------------------- | ||
360 | * - Change e-mail and web page addresses | ||
361 | * - Watchdog timer is now correctly expressed in HZ, not in jiffies | ||
362 | * - Add channel number to the list of frequencies in range | ||
363 | * - Add the (short) list of bit-rates in range | ||
364 | * - Developp a new sensitivity... (sens.value & sens.fixed) | ||
365 | * | ||
366 | * Changes made for release in 3.1.2 : | ||
367 | * --------------------------------- | ||
368 | * - Fix check for root permission (break instead of exit) | ||
369 | * - New nwid & encoding setting (Wireless Extension 9) | ||
370 | * | ||
371 | * Changes made for release in 3.1.12 : | ||
372 | * ---------------------------------- | ||
373 | * - reworked wv_82593_cmd to avoid using the IRQ handler and doing | ||
374 | * ugly things with interrupts. | ||
375 | * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog | ||
376 | * - Update to new network API (softnet - 2.3.43) : | ||
377 | * o replace dev->tbusy (David + me) | ||
378 | * o replace dev->tstart (David + me) | ||
379 | * o remove dev->interrupt (David) | ||
380 | * o add SMP locking via spinlock in splxx (me) | ||
381 | * o add spinlock in interrupt handler (me) | ||
382 | * o use kernel watchdog instead of ours (me) | ||
383 | * o verify that all the changes make sense and work (me) | ||
384 | * - Re-sync kernel/pcmcia versions (not much actually) | ||
385 | * - A few other cleanups (David & me)... | ||
386 | * | ||
387 | * Changes made for release in 3.1.22 : | ||
388 | * ---------------------------------- | ||
389 | * - Check that SMP works, remove annoying log message | ||
390 | * | ||
391 | * Changes made for release in 3.1.24 : | ||
392 | * ---------------------------------- | ||
393 | * - Fix unfrequent card lockup when watchdog was reseting the hardware : | ||
394 | * o control first busy loop in wv_82593_cmd() | ||
395 | * o Extend spinlock protection in wv_hw_config() | ||
396 | * | ||
397 | * Changes made for release in 3.1.33 : | ||
398 | * ---------------------------------- | ||
399 | * - Optional use new driver API for Wireless Extensions : | ||
400 | * o got rid of wavelan_ioctl() | ||
401 | * o use a bunch of iw_handler instead | ||
402 | * | ||
403 | * Changes made for release in 3.2.1 : | ||
404 | * --------------------------------- | ||
405 | * - Set dev->trans_start to avoid filling the logs | ||
406 | * (and generating useless abort commands) | ||
407 | * - Avoid deadlocks in mmc_out()/mmc_in() | ||
408 | * | ||
409 | * Wishes & dreams: | ||
410 | * ---------------- | ||
411 | * - Cleanup and integrate the roaming code | ||
412 | * (std debug, set DomainID, decay avg and co...) | ||
413 | */ | ||
414 | |||
415 | /***************************** INCLUDES *****************************/ | ||
416 | |||
417 | /* Linux headers that we need */ | ||
418 | #include <linux/config.h> | ||
419 | #include <linux/module.h> | ||
420 | #include <linux/kernel.h> | ||
421 | #include <linux/init.h> | ||
422 | #include <linux/sched.h> | ||
423 | #include <linux/ptrace.h> | ||
424 | #include <linux/slab.h> | ||
425 | #include <linux/string.h> | ||
426 | #include <linux/timer.h> | ||
427 | #include <linux/interrupt.h> | ||
428 | #include <linux/spinlock.h> | ||
429 | #include <linux/in.h> | ||
430 | #include <linux/delay.h> | ||
431 | #include <linux/bitops.h> | ||
432 | #include <asm/uaccess.h> | ||
433 | #include <asm/io.h> | ||
434 | #include <asm/system.h> | ||
435 | |||
436 | #include <linux/netdevice.h> | ||
437 | #include <linux/etherdevice.h> | ||
438 | #include <linux/skbuff.h> | ||
439 | #include <linux/if_arp.h> | ||
440 | #include <linux/ioport.h> | ||
441 | #include <linux/fcntl.h> | ||
442 | #include <linux/ethtool.h> | ||
443 | |||
444 | #ifdef CONFIG_NET_RADIO | ||
445 | #include <linux/wireless.h> /* Wireless extensions */ | ||
446 | #include <net/iw_handler.h> /* New driver API */ | ||
447 | #endif | ||
448 | |||
449 | /* Pcmcia headers that we need */ | ||
450 | #include <pcmcia/cs_types.h> | ||
451 | #include <pcmcia/cs.h> | ||
452 | #include <pcmcia/cistpl.h> | ||
453 | #include <pcmcia/cisreg.h> | ||
454 | #include <pcmcia/ds.h> | ||
455 | #include <pcmcia/version.h> | ||
456 | |||
457 | /* Wavelan declarations */ | ||
458 | #include "i82593.h" /* Definitions for the Intel chip */ | ||
459 | |||
460 | #include "wavelan_cs.h" /* Others bits of the hardware */ | ||
461 | |||
462 | /************************** DRIVER OPTIONS **************************/ | ||
463 | /* | ||
464 | * `#define' or `#undef' the following constant to change the behaviour | ||
465 | * of the driver... | ||
466 | */ | ||
467 | #define WAVELAN_ROAMING /* Include experimental roaming code */ | ||
468 | #undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ | ||
469 | #undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ | ||
470 | #define USE_PSA_CONFIG /* Use info from the PSA */ | ||
471 | #undef STRUCT_CHECK /* Verify padding of structures */ | ||
472 | #undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ | ||
473 | #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ | ||
474 | #undef SET_MAC_ADDRESS /* Experimental */ | ||
475 | |||
476 | #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ | ||
477 | /* Warning : these stuff will slow down the driver... */ | ||
478 | #define WIRELESS_SPY /* Enable spying addresses */ | ||
479 | #undef HISTOGRAM /* Enable histogram of sig level... */ | ||
480 | #endif | ||
481 | |||
482 | /****************************** DEBUG ******************************/ | ||
483 | |||
484 | #undef DEBUG_MODULE_TRACE /* Module insertion/removal */ | ||
485 | #undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ | ||
486 | #undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ | ||
487 | #undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ | ||
488 | #define DEBUG_INTERRUPT_ERROR /* problems */ | ||
489 | #undef DEBUG_CONFIG_TRACE /* Trace the config functions */ | ||
490 | #undef DEBUG_CONFIG_INFO /* What's going on... */ | ||
491 | #define DEBUG_CONFIG_ERRORS /* Errors on configuration */ | ||
492 | #undef DEBUG_TX_TRACE /* Transmission calls */ | ||
493 | #undef DEBUG_TX_INFO /* Header of the transmitted packet */ | ||
494 | #undef DEBUG_TX_FAIL /* Normal failure conditions */ | ||
495 | #define DEBUG_TX_ERROR /* Unexpected conditions */ | ||
496 | #undef DEBUG_RX_TRACE /* Transmission calls */ | ||
497 | #undef DEBUG_RX_INFO /* Header of the transmitted packet */ | ||
498 | #undef DEBUG_RX_FAIL /* Normal failure conditions */ | ||
499 | #define DEBUG_RX_ERROR /* Unexpected conditions */ | ||
500 | #undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ | ||
501 | #undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ | ||
502 | #undef DEBUG_IOCTL_INFO /* Various debug info */ | ||
503 | #define DEBUG_IOCTL_ERROR /* What's going wrong */ | ||
504 | #define DEBUG_BASIC_SHOW /* Show basic startup info */ | ||
505 | #undef DEBUG_VERSION_SHOW /* Print version info */ | ||
506 | #undef DEBUG_PSA_SHOW /* Dump psa to screen */ | ||
507 | #undef DEBUG_MMC_SHOW /* Dump mmc to screen */ | ||
508 | #undef DEBUG_SHOW_UNUSED /* Show also unused fields */ | ||
509 | #undef DEBUG_I82593_SHOW /* Show i82593 status */ | ||
510 | #undef DEBUG_DEVICE_SHOW /* Show device parameters */ | ||
511 | |||
512 | /************************ CONSTANTS & MACROS ************************/ | ||
513 | |||
514 | #ifdef DEBUG_VERSION_SHOW | ||
515 | static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n"; | ||
516 | #endif | ||
517 | |||
518 | /* Watchdog temporisation */ | ||
519 | #define WATCHDOG_JIFFIES (256*HZ/100) | ||
520 | |||
521 | /* Fix a bug in some old wireless extension definitions */ | ||
522 | #ifndef IW_ESSID_MAX_SIZE | ||
523 | #define IW_ESSID_MAX_SIZE 32 | ||
524 | #endif | ||
525 | |||
526 | /* ------------------------ PRIVATE IOCTL ------------------------ */ | ||
527 | |||
528 | #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ | ||
529 | #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ | ||
530 | #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ | ||
531 | #define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ | ||
532 | |||
533 | #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */ | ||
534 | #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */ | ||
535 | |||
536 | /*************************** WaveLAN Roaming **************************/ | ||
537 | #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ | ||
538 | |||
539 | #define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ | ||
540 | /* 2 = Info on each beacon rcvd... */ | ||
541 | #define MAX_WAVEPOINTS 7 /* Max visible at one time */ | ||
542 | #define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ | ||
543 | #define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ | ||
544 | #define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ | ||
545 | #define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ | ||
546 | #define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ | ||
547 | #define CELL_TIMEOUT 2*HZ /* in jiffies */ | ||
548 | |||
549 | #define FAST_CELL_SEARCH 1 /* Boolean values... */ | ||
550 | #define NWID_PROMISC 1 /* for code clarity. */ | ||
551 | |||
552 | typedef struct wavepoint_beacon | ||
553 | { | ||
554 | unsigned char dsap, /* Unused */ | ||
555 | ssap, /* Unused */ | ||
556 | ctrl, /* Unused */ | ||
557 | O,U,I, /* Unused */ | ||
558 | spec_id1, /* Unused */ | ||
559 | spec_id2, /* Unused */ | ||
560 | pdu_type, /* Unused */ | ||
561 | seq; /* WavePoint beacon sequence number */ | ||
562 | unsigned short domain_id, /* WavePoint Domain ID */ | ||
563 | nwid; /* WavePoint NWID */ | ||
564 | } wavepoint_beacon; | ||
565 | |||
566 | typedef struct wavepoint_history | ||
567 | { | ||
568 | unsigned short nwid; /* WavePoint's NWID */ | ||
569 | int average_slow; /* SNR running average */ | ||
570 | int average_fast; /* SNR running average */ | ||
571 | unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ | ||
572 | unsigned char qualptr; /* Index into ringbuffer */ | ||
573 | unsigned char last_seq; /* Last seq. no seen for WavePoint */ | ||
574 | struct wavepoint_history *next; /* Next WavePoint in table */ | ||
575 | struct wavepoint_history *prev; /* Previous WavePoint in table */ | ||
576 | unsigned long last_seen; /* Time of last beacon recvd, jiffies */ | ||
577 | } wavepoint_history; | ||
578 | |||
579 | struct wavepoint_table | ||
580 | { | ||
581 | wavepoint_history *head; /* Start of ringbuffer */ | ||
582 | int num_wavepoints; /* No. of WavePoints visible */ | ||
583 | unsigned char locked; /* Table lock */ | ||
584 | }; | ||
585 | |||
586 | #endif /* WAVELAN_ROAMING */ | ||
587 | |||
588 | /****************************** TYPES ******************************/ | ||
589 | |||
590 | /* Shortcuts */ | ||
591 | typedef struct net_device_stats en_stats; | ||
592 | typedef struct iw_statistics iw_stats; | ||
593 | typedef struct iw_quality iw_qual; | ||
594 | typedef struct iw_freq iw_freq; | ||
595 | typedef struct net_local net_local; | ||
596 | typedef struct timer_list timer_list; | ||
597 | |||
598 | /* Basic types */ | ||
599 | typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ | ||
600 | |||
601 | /* | ||
602 | * Static specific data for the interface. | ||
603 | * | ||
604 | * For each network interface, Linux keep data in two structure. "device" | ||
605 | * keep the generic data (same format for everybody) and "net_local" keep | ||
606 | * the additional specific data. | ||
607 | * Note that some of this specific data is in fact generic (en_stats, for | ||
608 | * example). | ||
609 | */ | ||
610 | struct net_local | ||
611 | { | ||
612 | dev_node_t node; /* ???? What is this stuff ???? */ | ||
613 | struct net_device * dev; /* Reverse link... */ | ||
614 | spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ | ||
615 | dev_link_t * link; /* pcmcia structure */ | ||
616 | en_stats stats; /* Ethernet interface statistics */ | ||
617 | int nresets; /* Number of hw resets */ | ||
618 | u_char configured; /* If it is configured */ | ||
619 | u_char reconfig_82593; /* Need to reconfigure the controller */ | ||
620 | u_char promiscuous; /* Promiscuous mode */ | ||
621 | u_char allmulticast; /* All Multicast mode */ | ||
622 | int mc_count; /* Number of multicast addresses */ | ||
623 | |||
624 | int stop; /* Current i82593 Stop Hit Register */ | ||
625 | int rfp; /* Last DMA machine receive pointer */ | ||
626 | int overrunning; /* Receiver overrun flag */ | ||
627 | |||
628 | #ifdef WIRELESS_EXT | ||
629 | iw_stats wstats; /* Wireless specific stats */ | ||
630 | |||
631 | struct iw_spy_data spy_data; | ||
632 | struct iw_public_data wireless_data; | ||
633 | #endif | ||
634 | |||
635 | #ifdef HISTOGRAM | ||
636 | int his_number; /* Number of intervals */ | ||
637 | u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ | ||
638 | u_long his_sum[16]; /* Sum in interval */ | ||
639 | #endif /* HISTOGRAM */ | ||
640 | #ifdef WAVELAN_ROAMING | ||
641 | u_long domain_id; /* Domain ID we lock on for roaming */ | ||
642 | int filter_domains; /* Check Domain ID of beacon found */ | ||
643 | struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ | ||
644 | wavepoint_history * curr_point; /* Current wavepoint */ | ||
645 | int cell_search; /* Searching for new cell? */ | ||
646 | struct timer_list cell_timer; /* Garbage collection */ | ||
647 | #endif /* WAVELAN_ROAMING */ | ||
648 | void __iomem *mem; | ||
649 | }; | ||
650 | |||
651 | /**************************** PROTOTYPES ****************************/ | ||
652 | |||
653 | #ifdef WAVELAN_ROAMING | ||
654 | /* ---------------------- ROAMING SUBROUTINES -----------------------*/ | ||
655 | |||
656 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); | ||
657 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); | ||
658 | void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); | ||
659 | void wl_cell_expiry(unsigned long data); | ||
660 | wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); | ||
661 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); | ||
662 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); | ||
663 | void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
664 | void wv_roam_init(struct net_device *dev); | ||
665 | void wv_roam_cleanup(struct net_device *dev); | ||
666 | #endif /* WAVELAN_ROAMING */ | ||
667 | |||
668 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | ||
669 | static inline u_char /* data */ | ||
670 | hasr_read(u_long); /* Read the host interface : base address */ | ||
671 | static inline void | ||
672 | hacr_write(u_long, /* Write to host interface : base address */ | ||
673 | u_char), /* data */ | ||
674 | hacr_write_slow(u_long, | ||
675 | u_char); | ||
676 | static void | ||
677 | psa_read(struct net_device *, /* Read the Parameter Storage Area */ | ||
678 | int, /* offset in PSA */ | ||
679 | u_char *, /* buffer to fill */ | ||
680 | int), /* size to read */ | ||
681 | psa_write(struct net_device *, /* Write to the PSA */ | ||
682 | int, /* Offset in psa */ | ||
683 | u_char *, /* Buffer in memory */ | ||
684 | int); /* Length of buffer */ | ||
685 | static inline void | ||
686 | mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ | ||
687 | u_short, | ||
688 | u_char), | ||
689 | mmc_write(u_long, /* Write n bytes to the MMC */ | ||
690 | u_char, | ||
691 | u_char *, | ||
692 | int); | ||
693 | static inline u_char /* Read 1 byte from the MMC */ | ||
694 | mmc_in(u_long, | ||
695 | u_short); | ||
696 | static inline void | ||
697 | mmc_read(u_long, /* Read n bytes from the MMC */ | ||
698 | u_char, | ||
699 | u_char *, | ||
700 | int), | ||
701 | fee_wait(u_long, /* Wait for frequency EEprom : base address */ | ||
702 | int, /* Base delay to wait for */ | ||
703 | int); /* Number of time to wait */ | ||
704 | static void | ||
705 | fee_read(u_long, /* Read the frequency EEprom : base address */ | ||
706 | u_short, /* destination offset */ | ||
707 | u_short *, /* data buffer */ | ||
708 | int); /* number of registers */ | ||
709 | /* ---------------------- I82593 SUBROUTINES ----------------------- */ | ||
710 | static int | ||
711 | wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ | ||
712 | char *, | ||
713 | int, | ||
714 | int); | ||
715 | static inline int | ||
716 | wv_diag(struct net_device *); /* Diagnostique the i82593 */ | ||
717 | static int | ||
718 | read_ringbuf(struct net_device *, /* Read a receive buffer */ | ||
719 | int, | ||
720 | char *, | ||
721 | int); | ||
722 | static inline void | ||
723 | wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ | ||
724 | /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ | ||
725 | static inline void | ||
726 | wv_init_info(struct net_device *); /* display startup info */ | ||
727 | /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ | ||
728 | static en_stats * | ||
729 | wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ | ||
730 | static iw_stats * | ||
731 | wavelan_get_wireless_stats(struct net_device *); | ||
732 | /* ----------------------- PACKET RECEPTION ----------------------- */ | ||
733 | static inline int | ||
734 | wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ | ||
735 | int, /* end of frame */ | ||
736 | int); /* start of buffer */ | ||
737 | static inline void | ||
738 | wv_packet_read(struct net_device *, /* Read a packet from a frame */ | ||
739 | int, | ||
740 | int), | ||
741 | wv_packet_rcv(struct net_device *); /* Read all packets waiting */ | ||
742 | /* --------------------- PACKET TRANSMISSION --------------------- */ | ||
743 | static inline void | ||
744 | wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ | ||
745 | void *, | ||
746 | short); | ||
747 | static int | ||
748 | wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ | ||
749 | struct net_device *); | ||
750 | /* -------------------- HARDWARE CONFIGURATION -------------------- */ | ||
751 | static inline int | ||
752 | wv_mmc_init(struct net_device *); /* Initialize the modem */ | ||
753 | static int | ||
754 | wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ | ||
755 | wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ | ||
756 | static int | ||
757 | wv_82593_config(struct net_device *); /* Configure the i82593 */ | ||
758 | static inline int | ||
759 | wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ | ||
760 | static int | ||
761 | wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ | ||
762 | static inline void | ||
763 | wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ | ||
764 | static inline int | ||
765 | wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ | ||
766 | static void | ||
767 | wv_pcmcia_release(dev_link_t *);/* Remove a device */ | ||
768 | /* ---------------------- INTERRUPT HANDLING ---------------------- */ | ||
769 | static irqreturn_t | ||
770 | wavelan_interrupt(int, /* Interrupt handler */ | ||
771 | void *, | ||
772 | struct pt_regs *); | ||
773 | static void | ||
774 | wavelan_watchdog(struct net_device *); /* Transmission watchdog */ | ||
775 | /* ------------------- CONFIGURATION CALLBACKS ------------------- */ | ||
776 | static int | ||
777 | wavelan_open(struct net_device *), /* Open the device */ | ||
778 | wavelan_close(struct net_device *); /* Close the device */ | ||
779 | static dev_link_t * | ||
780 | wavelan_attach(void); /* Create a new device */ | ||
781 | static void | ||
782 | wavelan_detach(dev_link_t *); /* Destroy a removed device */ | ||
783 | static int | ||
784 | wavelan_event(event_t, /* Manage pcmcia events */ | ||
785 | int, | ||
786 | event_callback_args_t *); | ||
787 | |||
788 | /**************************** VARIABLES ****************************/ | ||
789 | |||
790 | static dev_info_t dev_info = "wavelan_cs"; | ||
791 | static dev_link_t *dev_list = NULL; /* Linked list of devices */ | ||
792 | |||
793 | /* | ||
794 | * Parameters that can be set with 'insmod' | ||
795 | * The exact syntax is 'insmod wavelan_cs.o <var>=<value>' | ||
796 | */ | ||
797 | |||
798 | /* Shared memory speed, in ns */ | ||
799 | static int mem_speed = 0; | ||
800 | |||
801 | /* New module interface */ | ||
802 | module_param(mem_speed, int, 0); | ||
803 | |||
804 | #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ | ||
805 | /* Enable roaming mode ? No ! Please keep this to 0 */ | ||
806 | static int do_roaming = 0; | ||
807 | module_param(do_roaming, bool, 0); | ||
808 | #endif /* WAVELAN_ROAMING */ | ||
809 | |||
810 | MODULE_LICENSE("GPL"); | ||
811 | |||
812 | #endif /* WAVELAN_CS_P_H */ | ||
813 | |||
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h new file mode 100644 index 000000000000..8636d9306785 --- /dev/null +++ b/drivers/net/wireless/wl3501.h | |||
@@ -0,0 +1,614 @@ | |||
1 | #ifndef __WL3501_H__ | ||
2 | #define __WL3501_H__ | ||
3 | |||
4 | #include <linux/spinlock.h> | ||
5 | #include "ieee802_11.h" | ||
6 | |||
7 | /* define for WLA 2.0 */ | ||
8 | #define WL3501_BLKSZ 256 | ||
9 | /* | ||
10 | * ID for input Signals of DRIVER block | ||
11 | * bit[7-5] is block ID: 000 | ||
12 | * bit[4-0] is signal ID | ||
13 | */ | ||
14 | enum wl3501_signals { | ||
15 | WL3501_SIG_ALARM, | ||
16 | WL3501_SIG_MD_CONFIRM, | ||
17 | WL3501_SIG_MD_IND, | ||
18 | WL3501_SIG_ASSOC_CONFIRM, | ||
19 | WL3501_SIG_ASSOC_IND, | ||
20 | WL3501_SIG_AUTH_CONFIRM, | ||
21 | WL3501_SIG_AUTH_IND, | ||
22 | WL3501_SIG_DEAUTH_CONFIRM, | ||
23 | WL3501_SIG_DEAUTH_IND, | ||
24 | WL3501_SIG_DISASSOC_CONFIRM, | ||
25 | WL3501_SIG_DISASSOC_IND, | ||
26 | WL3501_SIG_GET_CONFIRM, | ||
27 | WL3501_SIG_JOIN_CONFIRM, | ||
28 | WL3501_SIG_PWR_MGMT_CONFIRM, | ||
29 | WL3501_SIG_REASSOC_CONFIRM, | ||
30 | WL3501_SIG_REASSOC_IND, | ||
31 | WL3501_SIG_SCAN_CONFIRM, | ||
32 | WL3501_SIG_SET_CONFIRM, | ||
33 | WL3501_SIG_START_CONFIRM, | ||
34 | WL3501_SIG_RESYNC_CONFIRM, | ||
35 | WL3501_SIG_SITE_CONFIRM, | ||
36 | WL3501_SIG_SAVE_CONFIRM, | ||
37 | WL3501_SIG_RFTEST_CONFIRM, | ||
38 | /* | ||
39 | * ID for input Signals of MLME block | ||
40 | * bit[7-5] is block ID: 010 | ||
41 | * bit[4-0] is signal ID | ||
42 | */ | ||
43 | WL3501_SIG_ASSOC_REQ = 0x20, | ||
44 | WL3501_SIG_AUTH_REQ, | ||
45 | WL3501_SIG_DEAUTH_REQ, | ||
46 | WL3501_SIG_DISASSOC_REQ, | ||
47 | WL3501_SIG_GET_REQ, | ||
48 | WL3501_SIG_JOIN_REQ, | ||
49 | WL3501_SIG_PWR_MGMT_REQ, | ||
50 | WL3501_SIG_REASSOC_REQ, | ||
51 | WL3501_SIG_SCAN_REQ, | ||
52 | WL3501_SIG_SET_REQ, | ||
53 | WL3501_SIG_START_REQ, | ||
54 | WL3501_SIG_MD_REQ, | ||
55 | WL3501_SIG_RESYNC_REQ, | ||
56 | WL3501_SIG_SITE_REQ, | ||
57 | WL3501_SIG_SAVE_REQ, | ||
58 | WL3501_SIG_RF_TEST_REQ, | ||
59 | WL3501_SIG_MM_CONFIRM = 0x60, | ||
60 | WL3501_SIG_MM_IND, | ||
61 | }; | ||
62 | |||
63 | enum wl3501_mib_attribs { | ||
64 | WL3501_MIB_ATTR_STATION_ID, | ||
65 | WL3501_MIB_ATTR_AUTH_ALGORITHMS, | ||
66 | WL3501_MIB_ATTR_AUTH_TYPE, | ||
67 | WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT, | ||
68 | WL3501_MIB_ATTR_CF_POLLABLE, | ||
69 | WL3501_MIB_ATTR_CFP_PERIOD, | ||
70 | WL3501_MIB_ATTR_CFPMAX_DURATION, | ||
71 | WL3501_MIB_ATTR_AUTH_RESP_TMOUT, | ||
72 | WL3501_MIB_ATTR_RX_DTIMS, | ||
73 | WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, | ||
74 | WL3501_MIB_ATTR_PRIV_INVOKED, | ||
75 | WL3501_MIB_ATTR_WEP_DEFAULT_KEYS, | ||
76 | WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID, | ||
77 | WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, | ||
78 | WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, | ||
79 | WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, | ||
80 | WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, | ||
81 | WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, | ||
82 | WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, | ||
83 | WL3501_MIB_ATTR_MAC_ADDR, | ||
84 | WL3501_MIB_ATTR_GROUP_ADDRS, | ||
85 | WL3501_MIB_ATTR_RTS_THRESHOLD, | ||
86 | WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, | ||
87 | WL3501_MIB_ATTR_LONG_RETRY_LIMIT, | ||
88 | WL3501_MIB_ATTR_FRAG_THRESHOLD, | ||
89 | WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME, | ||
90 | WL3501_MIB_ATTR_MAX_RX_LIFETIME, | ||
91 | WL3501_MIB_ATTR_MANUFACTURER_ID, | ||
92 | WL3501_MIB_ATTR_PRODUCT_ID, | ||
93 | WL3501_MIB_ATTR_TX_FRAG_COUNT, | ||
94 | WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT, | ||
95 | WL3501_MIB_ATTR_FAILED_COUNT, | ||
96 | WL3501_MIB_ATTR_RX_FRAG_COUNT, | ||
97 | WL3501_MIB_ATTR_MULTICAST_RX_COUNT, | ||
98 | WL3501_MIB_ATTR_FCS_ERROR_COUNT, | ||
99 | WL3501_MIB_ATTR_RETRY_COUNT, | ||
100 | WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT, | ||
101 | WL3501_MIB_ATTR_RTS_SUCCESS_COUNT, | ||
102 | WL3501_MIB_ATTR_RTS_FAILURE_COUNT, | ||
103 | WL3501_MIB_ATTR_ACK_FAILURE_COUNT, | ||
104 | WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, | ||
105 | WL3501_MIB_ATTR_PHY_TYPE, | ||
106 | WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT, | ||
107 | WL3501_MIB_ATTR_CURRENT_REG_DOMAIN, | ||
108 | WL3501_MIB_ATTR_SLOT_TIME, | ||
109 | WL3501_MIB_ATTR_CCA_TIME, | ||
110 | WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME, | ||
111 | WL3501_MIB_ATTR_TX_PLCP_DELAY, | ||
112 | WL3501_MIB_ATTR_RX_TX_SWITCH_TIME, | ||
113 | WL3501_MIB_ATTR_TX_RAMP_ON_TIME, | ||
114 | WL3501_MIB_ATTR_TX_RF_DELAY, | ||
115 | WL3501_MIB_ATTR_SIFS_TIME, | ||
116 | WL3501_MIB_ATTR_RX_RF_DELAY, | ||
117 | WL3501_MIB_ATTR_RX_PLCP_DELAY, | ||
118 | WL3501_MIB_ATTR_MAC_PROCESSING_DELAY, | ||
119 | WL3501_MIB_ATTR_TX_RAMP_OFF_TIME, | ||
120 | WL3501_MIB_ATTR_PREAMBLE_LEN, | ||
121 | WL3501_MIB_ATTR_PLCP_HEADER_LEN, | ||
122 | WL3501_MIB_ATTR_MPDU_DURATION_FACTOR, | ||
123 | WL3501_MIB_ATTR_AIR_PROPAGATION_TIME, | ||
124 | WL3501_MIB_ATTR_TEMP_TYPE, | ||
125 | WL3501_MIB_ATTR_CW_MIN, | ||
126 | WL3501_MIB_ATTR_CW_MAX, | ||
127 | WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX, | ||
128 | WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX, | ||
129 | WL3501_MIB_ATTR_MPDU_MAX_LEN, | ||
130 | WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS, | ||
131 | WL3501_MIB_ATTR_CURRENT_TX_ANTENNA, | ||
132 | WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS, | ||
133 | WL3501_MIB_ATTR_DIVERSITY_SUPPORT, | ||
134 | WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS, | ||
135 | WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS, | ||
136 | WL3501_MIB_ATTR_TX_PWR_LEVEL1, | ||
137 | WL3501_MIB_ATTR_TX_PWR_LEVEL2, | ||
138 | WL3501_MIB_ATTR_TX_PWR_LEVEL3, | ||
139 | WL3501_MIB_ATTR_TX_PWR_LEVEL4, | ||
140 | WL3501_MIB_ATTR_TX_PWR_LEVEL5, | ||
141 | WL3501_MIB_ATTR_TX_PWR_LEVEL6, | ||
142 | WL3501_MIB_ATTR_TX_PWR_LEVEL7, | ||
143 | WL3501_MIB_ATTR_TX_PWR_LEVEL8, | ||
144 | WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, | ||
145 | WL3501_MIB_ATTR_CURRENT_CHAN, | ||
146 | WL3501_MIB_ATTR_CCA_MODE_SUPPORTED, | ||
147 | WL3501_MIB_ATTR_CURRENT_CCA_MODE, | ||
148 | WL3501_MIB_ATTR_ED_THRESHOLD, | ||
149 | WL3501_MIB_ATTR_SINTHESIZER_LOCKED, | ||
150 | WL3501_MIB_ATTR_CURRENT_PWR_STATE, | ||
151 | WL3501_MIB_ATTR_DOZE_TURNON_TIME, | ||
152 | WL3501_MIB_ATTR_RCR33, | ||
153 | WL3501_MIB_ATTR_DEFAULT_CHAN, | ||
154 | WL3501_MIB_ATTR_SSID, | ||
155 | WL3501_MIB_ATTR_PWR_MGMT_ENABLE, | ||
156 | WL3501_MIB_ATTR_NET_CAPABILITY, | ||
157 | WL3501_MIB_ATTR_ROUTING, | ||
158 | }; | ||
159 | |||
160 | enum wl3501_net_type { | ||
161 | WL3501_NET_TYPE_INFRA, | ||
162 | WL3501_NET_TYPE_ADHOC, | ||
163 | WL3501_NET_TYPE_ANY_BSS, | ||
164 | }; | ||
165 | |||
166 | enum wl3501_scan_type { | ||
167 | WL3501_SCAN_TYPE_ACTIVE, | ||
168 | WL3501_SCAN_TYPE_PASSIVE, | ||
169 | }; | ||
170 | |||
171 | enum wl3501_tx_result { | ||
172 | WL3501_TX_RESULT_SUCCESS, | ||
173 | WL3501_TX_RESULT_NO_BSS, | ||
174 | WL3501_TX_RESULT_RETRY_LIMIT, | ||
175 | }; | ||
176 | |||
177 | enum wl3501_sys_type { | ||
178 | WL3501_SYS_TYPE_OPEN, | ||
179 | WL3501_SYS_TYPE_SHARE_KEY, | ||
180 | }; | ||
181 | |||
182 | enum wl3501_status { | ||
183 | WL3501_STATUS_SUCCESS, | ||
184 | WL3501_STATUS_INVALID, | ||
185 | WL3501_STATUS_TIMEOUT, | ||
186 | WL3501_STATUS_REFUSED, | ||
187 | WL3501_STATUS_MANY_REQ, | ||
188 | WL3501_STATUS_ALREADY_BSS, | ||
189 | }; | ||
190 | |||
191 | #define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */ | ||
192 | #define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */ | ||
193 | #define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */ | ||
194 | #define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */ | ||
195 | #define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */ | ||
196 | |||
197 | #define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */ | ||
198 | #define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */ | ||
199 | #define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */ | ||
200 | #define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */ | ||
201 | #define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */ | ||
202 | #define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ | ||
203 | #define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */ | ||
204 | #define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */ | ||
205 | |||
206 | #define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */ | ||
207 | |||
208 | enum iw_mgmt_rate_labels { | ||
209 | IW_MGMT_RATE_LABEL_1MBIT = 2, | ||
210 | IW_MGMT_RATE_LABEL_2MBIT = 4, | ||
211 | IW_MGMT_RATE_LABEL_5_5MBIT = 11, | ||
212 | IW_MGMT_RATE_LABEL_11MBIT = 22, | ||
213 | }; | ||
214 | |||
215 | enum iw_mgmt_info_element_ids { | ||
216 | IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */ | ||
217 | IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, | ||
218 | IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET, | ||
219 | IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, | ||
220 | IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET, | ||
221 | IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */ | ||
222 | IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, | ||
223 | /* 7-15: Reserved, unused */ | ||
224 | IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16, | ||
225 | /* 17-31 Reserved for challenge text extension */ | ||
226 | /* 32-255 Reserved, unused */ | ||
227 | }; | ||
228 | |||
229 | struct iw_mgmt_info_element { | ||
230 | u8 id; /* one of enum iw_mgmt_info_element_ids, | ||
231 | but sizeof(enum) > sizeof(u8) :-( */ | ||
232 | u8 len; | ||
233 | u8 data[0]; | ||
234 | } __attribute__ ((packed)); | ||
235 | |||
236 | struct iw_mgmt_essid_pset { | ||
237 | struct iw_mgmt_info_element el; | ||
238 | u8 essid[IW_ESSID_MAX_SIZE]; | ||
239 | } __attribute__ ((packed)); | ||
240 | |||
241 | /* | ||
242 | * According to 802.11 Wireless Netowors, the definitive guide - O'Reilly | ||
243 | * Pg 75 | ||
244 | */ | ||
245 | #define IW_DATA_RATE_MAX_LABELS 8 | ||
246 | |||
247 | struct iw_mgmt_data_rset { | ||
248 | struct iw_mgmt_info_element el; | ||
249 | u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS]; | ||
250 | } __attribute__ ((packed)); | ||
251 | |||
252 | struct iw_mgmt_ds_pset { | ||
253 | struct iw_mgmt_info_element el; | ||
254 | u8 chan; | ||
255 | } __attribute__ ((packed)); | ||
256 | |||
257 | struct iw_mgmt_cf_pset { | ||
258 | struct iw_mgmt_info_element el; | ||
259 | u8 cfp_count; | ||
260 | u8 cfp_period; | ||
261 | u16 cfp_max_duration; | ||
262 | u16 cfp_dur_remaining; | ||
263 | } __attribute__ ((packed)); | ||
264 | |||
265 | struct iw_mgmt_ibss_pset { | ||
266 | struct iw_mgmt_info_element el; | ||
267 | u16 atim_window; | ||
268 | } __attribute__ ((packed)); | ||
269 | |||
270 | struct wl3501_tx_hdr { | ||
271 | u16 tx_cnt; | ||
272 | u8 sync[16]; | ||
273 | u16 sfd; | ||
274 | u8 signal; | ||
275 | u8 service; | ||
276 | u16 len; | ||
277 | u16 crc16; | ||
278 | u16 frame_ctrl; | ||
279 | u16 duration_id; | ||
280 | u8 addr1[ETH_ALEN]; | ||
281 | u8 addr2[ETH_ALEN]; | ||
282 | u8 addr3[ETH_ALEN]; | ||
283 | u16 seq_ctrl; | ||
284 | u8 addr4[ETH_ALEN]; | ||
285 | }; | ||
286 | |||
287 | struct wl3501_rx_hdr { | ||
288 | u16 rx_next_blk; | ||
289 | u16 rc_next_frame_blk; | ||
290 | u8 rx_blk_ctrl; | ||
291 | u8 rx_next_frame; | ||
292 | u8 rx_next_frame1; | ||
293 | u8 rssi; | ||
294 | char time[8]; | ||
295 | u8 signal; | ||
296 | u8 service; | ||
297 | u16 len; | ||
298 | u16 crc16; | ||
299 | u16 frame_ctrl; | ||
300 | u16 duration; | ||
301 | u8 addr1[ETH_ALEN]; | ||
302 | u8 addr2[ETH_ALEN]; | ||
303 | u8 addr3[ETH_ALEN]; | ||
304 | u16 seq; | ||
305 | u8 addr4[ETH_ALEN]; | ||
306 | }; | ||
307 | |||
308 | struct wl3501_start_req { | ||
309 | u16 next_blk; | ||
310 | u8 sig_id; | ||
311 | u8 bss_type; | ||
312 | u16 beacon_period; | ||
313 | u16 dtim_period; | ||
314 | u16 probe_delay; | ||
315 | u16 cap_info; | ||
316 | struct iw_mgmt_essid_pset ssid; | ||
317 | struct iw_mgmt_data_rset bss_basic_rset; | ||
318 | struct iw_mgmt_data_rset operational_rset; | ||
319 | struct iw_mgmt_cf_pset cf_pset; | ||
320 | struct iw_mgmt_ds_pset ds_pset; | ||
321 | struct iw_mgmt_ibss_pset ibss_pset; | ||
322 | }; | ||
323 | |||
324 | struct wl3501_assoc_req { | ||
325 | u16 next_blk; | ||
326 | u8 sig_id; | ||
327 | u8 reserved; | ||
328 | u16 timeout; | ||
329 | u16 cap_info; | ||
330 | u16 listen_interval; | ||
331 | u8 mac_addr[ETH_ALEN]; | ||
332 | }; | ||
333 | |||
334 | struct wl3501_assoc_confirm { | ||
335 | u16 next_blk; | ||
336 | u8 sig_id; | ||
337 | u8 reserved; | ||
338 | u16 status; | ||
339 | }; | ||
340 | |||
341 | struct wl3501_assoc_ind { | ||
342 | u16 next_blk; | ||
343 | u8 sig_id; | ||
344 | u8 mac_addr[ETH_ALEN]; | ||
345 | }; | ||
346 | |||
347 | struct wl3501_auth_req { | ||
348 | u16 next_blk; | ||
349 | u8 sig_id; | ||
350 | u8 reserved; | ||
351 | u16 type; | ||
352 | u16 timeout; | ||
353 | u8 mac_addr[ETH_ALEN]; | ||
354 | }; | ||
355 | |||
356 | struct wl3501_auth_confirm { | ||
357 | u16 next_blk; | ||
358 | u8 sig_id; | ||
359 | u8 reserved; | ||
360 | u16 type; | ||
361 | u16 status; | ||
362 | u8 mac_addr[ETH_ALEN]; | ||
363 | }; | ||
364 | |||
365 | struct wl3501_get_req { | ||
366 | u16 next_blk; | ||
367 | u8 sig_id; | ||
368 | u8 reserved; | ||
369 | u16 mib_attrib; | ||
370 | }; | ||
371 | |||
372 | struct wl3501_get_confirm { | ||
373 | u16 next_blk; | ||
374 | u8 sig_id; | ||
375 | u8 reserved; | ||
376 | u16 mib_status; | ||
377 | u16 mib_attrib; | ||
378 | u8 mib_value[100]; | ||
379 | }; | ||
380 | |||
381 | struct wl3501_join_req { | ||
382 | u16 next_blk; | ||
383 | u8 sig_id; | ||
384 | u8 reserved; | ||
385 | struct iw_mgmt_data_rset operational_rset; | ||
386 | u16 reserved2; | ||
387 | u16 timeout; | ||
388 | u16 probe_delay; | ||
389 | u8 timestamp[8]; | ||
390 | u8 local_time[8]; | ||
391 | u16 beacon_period; | ||
392 | u16 dtim_period; | ||
393 | u16 cap_info; | ||
394 | u8 bss_type; | ||
395 | u8 bssid[ETH_ALEN]; | ||
396 | struct iw_mgmt_essid_pset ssid; | ||
397 | struct iw_mgmt_ds_pset ds_pset; | ||
398 | struct iw_mgmt_cf_pset cf_pset; | ||
399 | struct iw_mgmt_ibss_pset ibss_pset; | ||
400 | struct iw_mgmt_data_rset bss_basic_rset; | ||
401 | }; | ||
402 | |||
403 | struct wl3501_join_confirm { | ||
404 | u16 next_blk; | ||
405 | u8 sig_id; | ||
406 | u8 reserved; | ||
407 | u16 status; | ||
408 | }; | ||
409 | |||
410 | struct wl3501_pwr_mgmt_req { | ||
411 | u16 next_blk; | ||
412 | u8 sig_id; | ||
413 | u8 pwr_save; | ||
414 | u8 wake_up; | ||
415 | u8 receive_dtims; | ||
416 | }; | ||
417 | |||
418 | struct wl3501_pwr_mgmt_confirm { | ||
419 | u16 next_blk; | ||
420 | u8 sig_id; | ||
421 | u8 reserved; | ||
422 | u16 status; | ||
423 | }; | ||
424 | |||
425 | struct wl3501_scan_req { | ||
426 | u16 next_blk; | ||
427 | u8 sig_id; | ||
428 | u8 bss_type; | ||
429 | u16 probe_delay; | ||
430 | u16 min_chan_time; | ||
431 | u16 max_chan_time; | ||
432 | u8 chan_list[14]; | ||
433 | u8 bssid[ETH_ALEN]; | ||
434 | struct iw_mgmt_essid_pset ssid; | ||
435 | enum wl3501_scan_type scan_type; | ||
436 | }; | ||
437 | |||
438 | struct wl3501_scan_confirm { | ||
439 | u16 next_blk; | ||
440 | u8 sig_id; | ||
441 | u8 reserved; | ||
442 | u16 status; | ||
443 | char timestamp[8]; | ||
444 | char localtime[8]; | ||
445 | u16 beacon_period; | ||
446 | u16 dtim_period; | ||
447 | u16 cap_info; | ||
448 | u8 bss_type; | ||
449 | u8 bssid[ETH_ALEN]; | ||
450 | struct iw_mgmt_essid_pset ssid; | ||
451 | struct iw_mgmt_ds_pset ds_pset; | ||
452 | struct iw_mgmt_cf_pset cf_pset; | ||
453 | struct iw_mgmt_ibss_pset ibss_pset; | ||
454 | struct iw_mgmt_data_rset bss_basic_rset; | ||
455 | u8 rssi; | ||
456 | }; | ||
457 | |||
458 | struct wl3501_start_confirm { | ||
459 | u16 next_blk; | ||
460 | u8 sig_id; | ||
461 | u8 reserved; | ||
462 | u16 status; | ||
463 | }; | ||
464 | |||
465 | struct wl3501_md_req { | ||
466 | u16 next_blk; | ||
467 | u8 sig_id; | ||
468 | u8 routing; | ||
469 | u16 data; | ||
470 | u16 size; | ||
471 | u8 pri; | ||
472 | u8 service_class; | ||
473 | u8 daddr[ETH_ALEN]; | ||
474 | u8 saddr[ETH_ALEN]; | ||
475 | }; | ||
476 | |||
477 | struct wl3501_md_ind { | ||
478 | u16 next_blk; | ||
479 | u8 sig_id; | ||
480 | u8 routing; | ||
481 | u16 data; | ||
482 | u16 size; | ||
483 | u8 reception; | ||
484 | u8 pri; | ||
485 | u8 service_class; | ||
486 | u8 daddr[ETH_ALEN]; | ||
487 | u8 saddr[ETH_ALEN]; | ||
488 | }; | ||
489 | |||
490 | struct wl3501_md_confirm { | ||
491 | u16 next_blk; | ||
492 | u8 sig_id; | ||
493 | u8 reserved; | ||
494 | u16 data; | ||
495 | u8 status; | ||
496 | u8 pri; | ||
497 | u8 service_class; | ||
498 | }; | ||
499 | |||
500 | struct wl3501_resync_req { | ||
501 | u16 next_blk; | ||
502 | u8 sig_id; | ||
503 | }; | ||
504 | |||
505 | /* Definitions for supporting clone adapters. */ | ||
506 | /* System Interface Registers (SIR space) */ | ||
507 | #define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */ | ||
508 | #define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */ | ||
509 | #define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */ | ||
510 | #define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */ | ||
511 | #define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */ | ||
512 | #define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */ | ||
513 | #define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */ | ||
514 | #define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */ | ||
515 | |||
516 | /* Bits in GCR */ | ||
517 | #define WL3501_GCR_SWRESET ((u8)0x80) | ||
518 | #define WL3501_GCR_CORESET ((u8)0x40) | ||
519 | #define WL3501_GCR_DISPWDN ((u8)0x20) | ||
520 | #define WL3501_GCR_ECWAIT ((u8)0x10) | ||
521 | #define WL3501_GCR_ECINT ((u8)0x08) | ||
522 | #define WL3501_GCR_INT2EC ((u8)0x04) | ||
523 | #define WL3501_GCR_ENECINT ((u8)0x02) | ||
524 | #define WL3501_GCR_DAM ((u8)0x01) | ||
525 | |||
526 | /* Bits in BSS (Bank Switching Select Register) */ | ||
527 | #define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */ | ||
528 | #define WL3501_BSS_FPAGE1 ((u8)0x28) | ||
529 | #define WL3501_BSS_FPAGE2 ((u8)0x30) | ||
530 | #define WL3501_BSS_FPAGE3 ((u8)0x38) | ||
531 | #define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */ | ||
532 | #define WL3501_BSS_SPAGE1 ((u8)0x08) | ||
533 | #define WL3501_BSS_SPAGE2 ((u8)0x10) | ||
534 | #define WL3501_BSS_SPAGE3 ((u8)0x18) | ||
535 | |||
536 | /* Define Driver Interface */ | ||
537 | /* Refer IEEE 802.11 */ | ||
538 | /* Tx packet header, include PLCP and MPDU */ | ||
539 | /* Tx PLCP Header */ | ||
540 | struct wl3501_80211_tx_plcp_hdr { | ||
541 | u8 sync[16]; | ||
542 | u16 sfd; | ||
543 | u8 signal; | ||
544 | u8 service; | ||
545 | u16 len; | ||
546 | u16 crc16; | ||
547 | } __attribute__ ((packed)); | ||
548 | |||
549 | struct wl3501_80211_tx_hdr { | ||
550 | struct wl3501_80211_tx_plcp_hdr pclp_hdr; | ||
551 | struct ieee802_11_hdr mac_hdr; | ||
552 | } __attribute__ ((packed)); | ||
553 | |||
554 | /* | ||
555 | Reserve the beginning Tx space for descriptor use. | ||
556 | |||
557 | TxBlockOffset --> *----*----*----*----* \ | ||
558 | (TxFreeDesc) | 0 | 1 | 2 | 3 | \ | ||
559 | | 4 | 5 | 6 | 7 | | | ||
560 | | 8 | 9 | 10 | 11 | TX_DESC * 20 | ||
561 | | 12 | 13 | 14 | 15 | | | ||
562 | | 16 | 17 | 18 | 19 | / | ||
563 | TxBufferBegin --> *----*----*----*----* / | ||
564 | (TxBufferHead) | | | ||
565 | (TxBufferTail) | | | ||
566 | | Send Buffer | | ||
567 | | | | ||
568 | | | | ||
569 | *-------------------* | ||
570 | TxBufferEnd -------------------------/ | ||
571 | |||
572 | */ | ||
573 | |||
574 | struct wl3501_card { | ||
575 | int base_addr; | ||
576 | u8 mac_addr[ETH_ALEN]; | ||
577 | spinlock_t lock; | ||
578 | wait_queue_head_t wait; | ||
579 | struct wl3501_get_confirm sig_get_confirm; | ||
580 | struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm; | ||
581 | u16 tx_buffer_size; | ||
582 | u16 tx_buffer_head; | ||
583 | u16 tx_buffer_tail; | ||
584 | u16 tx_buffer_cnt; | ||
585 | u16 esbq_req_start; | ||
586 | u16 esbq_req_end; | ||
587 | u16 esbq_req_head; | ||
588 | u16 esbq_req_tail; | ||
589 | u16 esbq_confirm_start; | ||
590 | u16 esbq_confirm_end; | ||
591 | u16 esbq_confirm; | ||
592 | struct iw_mgmt_essid_pset essid; | ||
593 | struct iw_mgmt_essid_pset keep_essid; | ||
594 | u8 bssid[ETH_ALEN]; | ||
595 | int net_type; | ||
596 | char nick[32]; | ||
597 | char card_name[32]; | ||
598 | char firmware_date[32]; | ||
599 | u8 chan; | ||
600 | u8 cap_info; | ||
601 | u16 start_seg; | ||
602 | u16 bss_cnt; | ||
603 | u16 join_sta_bss; | ||
604 | u8 rssi; | ||
605 | u8 adhoc_times; | ||
606 | u8 reg_domain; | ||
607 | u8 version[2]; | ||
608 | struct wl3501_scan_confirm bss_set[20]; | ||
609 | struct net_device_stats stats; | ||
610 | struct iw_statistics wstats; | ||
611 | struct iw_spy_data spy_data; | ||
612 | struct dev_node_t node; | ||
613 | }; | ||
614 | #endif | ||
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c new file mode 100644 index 000000000000..1433e5aaf1b4 --- /dev/null +++ b/drivers/net/wireless/wl3501_cs.c | |||
@@ -0,0 +1,2270 @@ | |||
1 | /* | ||
2 | * WL3501 Wireless LAN PCMCIA Card Driver for Linux | ||
3 | * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw | ||
4 | * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
5 | * Wireless extensions in 2.4 by Gustavo Niemeyer <niemeyer@conectiva.com> | ||
6 | * | ||
7 | * References used by Fox Chen while writing the original driver for 2.0.30: | ||
8 | * | ||
9 | * 1. WL24xx packet drivers (tooasm.asm) | ||
10 | * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO | ||
11 | * 3. IEEE 802.11 | ||
12 | * 4. Linux network driver (/usr/src/linux/drivers/net) | ||
13 | * 5. ISA card driver - wl24.c | ||
14 | * 6. Linux PCMCIA skeleton driver - skeleton.c | ||
15 | * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c | ||
16 | * | ||
17 | * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12 | ||
18 | * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode. | ||
19 | * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null | ||
20 | * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct | ||
21 | * ETHER/IP/UDP/TCP header, and acknowledgement overhead) | ||
22 | * | ||
23 | * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode, | ||
24 | * 173 Kbytes/s in TCP. | ||
25 | * | ||
26 | * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode | ||
27 | * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) | ||
28 | */ | ||
29 | #undef REALLY_SLOW_IO /* most systems can safely undef this */ | ||
30 | |||
31 | #include <linux/config.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/in.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/fcntl.h> | ||
41 | #include <linux/if_arp.h> | ||
42 | #include <linux/ioport.h> | ||
43 | #include <linux/netdevice.h> | ||
44 | #include <linux/etherdevice.h> | ||
45 | #include <linux/skbuff.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/string.h> | ||
48 | #include <linux/wireless.h> | ||
49 | |||
50 | #include <net/iw_handler.h> | ||
51 | |||
52 | #include <pcmcia/version.h> | ||
53 | #include <pcmcia/cs_types.h> | ||
54 | #include <pcmcia/cs.h> | ||
55 | #include <pcmcia/cistpl.h> | ||
56 | #include <pcmcia/cisreg.h> | ||
57 | #include <pcmcia/ds.h> | ||
58 | |||
59 | #include <asm/io.h> | ||
60 | #include <asm/uaccess.h> | ||
61 | #include <asm/system.h> | ||
62 | |||
63 | #include "wl3501.h" | ||
64 | |||
65 | #ifndef __i386__ | ||
66 | #define slow_down_io() | ||
67 | #endif | ||
68 | |||
69 | /* For rough constant delay */ | ||
70 | #define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } | ||
71 | |||
72 | /* | ||
73 | * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not | ||
74 | * define PCMCIA_DEBUG at all, all the debug code will be left out. If you | ||
75 | * compile with PCMCIA_DEBUG=0, the debug code will be present but disabled -- | ||
76 | * but it can then be enabled for specific modules at load time with a | ||
77 | * 'pc_debug=#' option to insmod. | ||
78 | */ | ||
79 | #define PCMCIA_DEBUG 0 | ||
80 | #ifdef PCMCIA_DEBUG | ||
81 | static int pc_debug = PCMCIA_DEBUG; | ||
82 | module_param(pc_debug, int, 0); | ||
83 | #define dprintk(n, format, args...) \ | ||
84 | { if (pc_debug > (n)) \ | ||
85 | printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##args); } | ||
86 | #else | ||
87 | #define dprintk(n, format, args...) | ||
88 | #endif | ||
89 | |||
90 | #define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } | ||
91 | #define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } | ||
92 | #define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); } | ||
93 | |||
94 | #define WL3501_RELEASE_TIMEOUT (25 * HZ) | ||
95 | #define WL3501_MAX_ADHOC_TRIES 16 | ||
96 | |||
97 | #define WL3501_RESUME 0 | ||
98 | #define WL3501_SUSPEND 1 | ||
99 | |||
100 | /* | ||
101 | * The event() function is this driver's Card Services event handler. It will | ||
102 | * be called by Card Services when an appropriate card status event is | ||
103 | * received. The config() and release() entry points are used to configure or | ||
104 | * release a socket, in response to card insertion and ejection events. They | ||
105 | * are invoked from the wl24 event handler. | ||
106 | */ | ||
107 | static void wl3501_config(dev_link_t *link); | ||
108 | static void wl3501_release(dev_link_t *link); | ||
109 | static int wl3501_event(event_t event, int pri, event_callback_args_t *args); | ||
110 | |||
111 | /* | ||
112 | * The dev_info variable is the "key" that is used to match up this | ||
113 | * device driver with appropriate cards, through the card configuration | ||
114 | * database. | ||
115 | */ | ||
116 | static dev_info_t wl3501_dev_info = "wl3501_cs"; | ||
117 | |||
118 | static int wl3501_chan2freq[] = { | ||
119 | [0] = 2412, [1] = 2417, [2] = 2422, [3] = 2427, [4] = 2432, | ||
120 | [5] = 2437, [6] = 2442, [7] = 2447, [8] = 2452, [9] = 2457, | ||
121 | [10] = 2462, [11] = 2467, [12] = 2472, [13] = 2477, | ||
122 | }; | ||
123 | |||
124 | static const struct { | ||
125 | int reg_domain; | ||
126 | int min, max, deflt; | ||
127 | } iw_channel_table[] = { | ||
128 | { | ||
129 | .reg_domain = IW_REG_DOMAIN_FCC, | ||
130 | .min = 1, | ||
131 | .max = 11, | ||
132 | .deflt = 1, | ||
133 | }, | ||
134 | { | ||
135 | .reg_domain = IW_REG_DOMAIN_DOC, | ||
136 | .min = 1, | ||
137 | .max = 11, | ||
138 | .deflt = 1, | ||
139 | }, | ||
140 | { | ||
141 | .reg_domain = IW_REG_DOMAIN_ETSI, | ||
142 | .min = 1, | ||
143 | .max = 13, | ||
144 | .deflt = 1, | ||
145 | }, | ||
146 | { | ||
147 | .reg_domain = IW_REG_DOMAIN_SPAIN, | ||
148 | .min = 10, | ||
149 | .max = 11, | ||
150 | .deflt = 10, | ||
151 | }, | ||
152 | { | ||
153 | .reg_domain = IW_REG_DOMAIN_FRANCE, | ||
154 | .min = 10, | ||
155 | .max = 13, | ||
156 | .deflt = 10, | ||
157 | }, | ||
158 | { | ||
159 | .reg_domain = IW_REG_DOMAIN_MKK, | ||
160 | .min = 14, | ||
161 | .max = 14, | ||
162 | .deflt = 14, | ||
163 | }, | ||
164 | { | ||
165 | .reg_domain = IW_REG_DOMAIN_MKK1, | ||
166 | .min = 1, | ||
167 | .max = 14, | ||
168 | .deflt = 1, | ||
169 | }, | ||
170 | { | ||
171 | .reg_domain = IW_REG_DOMAIN_ISRAEL, | ||
172 | .min = 3, | ||
173 | .max = 9, | ||
174 | .deflt = 9, | ||
175 | }, | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * iw_valid_channel - validate channel in regulatory domain | ||
180 | * @reg_comain - regulatory domain | ||
181 | * @channel - channel to validate | ||
182 | * | ||
183 | * Returns 0 if invalid in the specified regulatory domain, non-zero if valid. | ||
184 | */ | ||
185 | static int iw_valid_channel(int reg_domain, int channel) | ||
186 | { | ||
187 | int i, rc = 0; | ||
188 | |||
189 | for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) | ||
190 | if (reg_domain == iw_channel_table[i].reg_domain) { | ||
191 | rc = channel >= iw_channel_table[i].min && | ||
192 | channel <= iw_channel_table[i].max; | ||
193 | break; | ||
194 | } | ||
195 | return rc; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * iw_default_channel - get default channel for a regulatory domain | ||
200 | * @reg_comain - regulatory domain | ||
201 | * | ||
202 | * Returns the default channel for a regulatory domain | ||
203 | */ | ||
204 | static int iw_default_channel(int reg_domain) | ||
205 | { | ||
206 | int i, rc = 1; | ||
207 | |||
208 | for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) | ||
209 | if (reg_domain == iw_channel_table[i].reg_domain) { | ||
210 | rc = iw_channel_table[i].deflt; | ||
211 | break; | ||
212 | } | ||
213 | return rc; | ||
214 | } | ||
215 | |||
216 | static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id, | ||
217 | struct iw_mgmt_info_element *el, | ||
218 | void *value, int len) | ||
219 | { | ||
220 | el->id = id; | ||
221 | el->len = len; | ||
222 | memcpy(el->data, value, len); | ||
223 | } | ||
224 | |||
225 | static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, | ||
226 | struct iw_mgmt_info_element *from) | ||
227 | { | ||
228 | iw_set_mgmt_info_element(from->id, to, from->data, from->len); | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * A linked list of "instances" of the wl24 device. Each actual PCMCIA card | ||
233 | * corresponds to one device instance, and is described by one dev_link_t | ||
234 | * structure (defined in ds.h). | ||
235 | * | ||
236 | * You may not want to use a linked list for this -- for example, the memory | ||
237 | * card driver uses an array of dev_link_t pointers, where minor device numbers | ||
238 | * are used to derive the corresponding array index. | ||
239 | */ | ||
240 | static dev_link_t *wl3501_dev_list; | ||
241 | |||
242 | static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) | ||
243 | { | ||
244 | wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * Get Ethernet MAC addresss. | ||
249 | * | ||
250 | * WARNING: We switch to FPAGE0 and switc back again. | ||
251 | * Making sure there is no other WL function beening called by ISR. | ||
252 | */ | ||
253 | static int wl3501_get_flash_mac_addr(struct wl3501_card *this) | ||
254 | { | ||
255 | int base_addr = this->base_addr; | ||
256 | |||
257 | /* get MAC addr */ | ||
258 | wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */ | ||
259 | wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */ | ||
260 | wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */ | ||
261 | |||
262 | /* wait for reading EEPROM */ | ||
263 | WL3501_NOPLOOP(100); | ||
264 | this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA); | ||
265 | WL3501_NOPLOOP(100); | ||
266 | this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA); | ||
267 | WL3501_NOPLOOP(100); | ||
268 | this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA); | ||
269 | WL3501_NOPLOOP(100); | ||
270 | this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA); | ||
271 | WL3501_NOPLOOP(100); | ||
272 | this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA); | ||
273 | WL3501_NOPLOOP(100); | ||
274 | this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA); | ||
275 | WL3501_NOPLOOP(100); | ||
276 | this->reg_domain = inb(base_addr + WL3501_NIC_IODPA); | ||
277 | WL3501_NOPLOOP(100); | ||
278 | wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS); | ||
279 | wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL); | ||
280 | wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); | ||
281 | WL3501_NOPLOOP(100); | ||
282 | this->version[0] = inb(base_addr + WL3501_NIC_IODPA); | ||
283 | WL3501_NOPLOOP(100); | ||
284 | this->version[1] = inb(base_addr + WL3501_NIC_IODPA); | ||
285 | /* switch to SRAM Page 0 (for safety) */ | ||
286 | wl3501_switch_page(this, WL3501_BSS_SPAGE0); | ||
287 | |||
288 | /* The MAC addr should be 00:60:... */ | ||
289 | return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60; | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * wl3501_set_to_wla - Move 'size' bytes from PC to card | ||
294 | * @dest: Card addressing space | ||
295 | * @src: PC addressing space | ||
296 | * @size: Bytes to move | ||
297 | * | ||
298 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) | ||
299 | */ | ||
300 | void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | ||
301 | { | ||
302 | /* switch to SRAM Page 0 */ | ||
303 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : | ||
304 | WL3501_BSS_SPAGE0); | ||
305 | /* set LMAL and LMAH */ | ||
306 | wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL); | ||
307 | wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH); | ||
308 | |||
309 | /* rep out to Port A */ | ||
310 | wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * wl3501_get_from_wla - Move 'size' bytes from card to PC | ||
315 | * @src: Card addressing space | ||
316 | * @dest: PC addressing space | ||
317 | * @size: Bytes to move | ||
318 | * | ||
319 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) | ||
320 | */ | ||
321 | void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, | ||
322 | int size) | ||
323 | { | ||
324 | /* switch to SRAM Page 0 */ | ||
325 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : | ||
326 | WL3501_BSS_SPAGE0); | ||
327 | /* set LMAL and LMAH */ | ||
328 | wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL); | ||
329 | wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH); | ||
330 | |||
331 | /* rep get from Port A */ | ||
332 | insb(this->base_addr + WL3501_NIC_IODPA, dest, size); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Get/Allocate a free Tx Data Buffer | ||
337 | * | ||
338 | * *--------------*-----------------*----------------------------------* | ||
339 | * | PLCP | MAC Header | DST SRC Data ... | | ||
340 | * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) | | ||
341 | * *--------------*-----------------*----------------------------------* | ||
342 | * \ \- IEEE 802.11 -/ \-------------- len --------------/ | ||
343 | * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ | ||
344 | * | ||
345 | * Return = Postion in Card | ||
346 | */ | ||
347 | static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) | ||
348 | { | ||
349 | u16 next, blk_cnt = 0, zero = 0; | ||
350 | u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len; | ||
351 | u16 ret = 0; | ||
352 | |||
353 | if (full_len > this->tx_buffer_cnt * 254) | ||
354 | goto out; | ||
355 | ret = this->tx_buffer_head; | ||
356 | while (full_len) { | ||
357 | if (full_len < 254) | ||
358 | full_len = 0; | ||
359 | else | ||
360 | full_len -= 254; | ||
361 | wl3501_get_from_wla(this, this->tx_buffer_head, &next, | ||
362 | sizeof(next)); | ||
363 | if (!full_len) | ||
364 | wl3501_set_to_wla(this, this->tx_buffer_head, &zero, | ||
365 | sizeof(zero)); | ||
366 | this->tx_buffer_head = next; | ||
367 | blk_cnt++; | ||
368 | /* if buffer is not enough */ | ||
369 | if (!next && full_len) { | ||
370 | this->tx_buffer_head = ret; | ||
371 | ret = 0; | ||
372 | goto out; | ||
373 | } | ||
374 | } | ||
375 | this->tx_buffer_cnt -= blk_cnt; | ||
376 | out: | ||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Free an allocated Tx Buffer. ptr must be correct position. | ||
382 | */ | ||
383 | static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) | ||
384 | { | ||
385 | /* check if all space is not free */ | ||
386 | if (!this->tx_buffer_head) | ||
387 | this->tx_buffer_head = ptr; | ||
388 | else | ||
389 | wl3501_set_to_wla(this, this->tx_buffer_tail, | ||
390 | &ptr, sizeof(ptr)); | ||
391 | while (ptr) { | ||
392 | u16 next; | ||
393 | |||
394 | this->tx_buffer_cnt++; | ||
395 | wl3501_get_from_wla(this, ptr, &next, sizeof(next)); | ||
396 | this->tx_buffer_tail = ptr; | ||
397 | ptr = next; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | static int wl3501_esbq_req_test(struct wl3501_card *this) | ||
402 | { | ||
403 | u8 tmp; | ||
404 | |||
405 | wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); | ||
406 | return tmp & 0x80; | ||
407 | } | ||
408 | |||
409 | static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr) | ||
410 | { | ||
411 | u16 tmp = 0; | ||
412 | |||
413 | wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2); | ||
414 | wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp)); | ||
415 | this->esbq_req_head += 4; | ||
416 | if (this->esbq_req_head >= this->esbq_req_end) | ||
417 | this->esbq_req_head = this->esbq_req_start; | ||
418 | } | ||
419 | |||
420 | static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) | ||
421 | { | ||
422 | int rc = -EIO; | ||
423 | |||
424 | if (wl3501_esbq_req_test(this)) { | ||
425 | u16 ptr = wl3501_get_tx_buffer(this, sig_size); | ||
426 | if (ptr) { | ||
427 | wl3501_set_to_wla(this, ptr, sig, sig_size); | ||
428 | wl3501_esbq_req(this, &ptr); | ||
429 | rc = 0; | ||
430 | } | ||
431 | } | ||
432 | return rc; | ||
433 | } | ||
434 | |||
435 | static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, | ||
436 | void *bf, int size) | ||
437 | { | ||
438 | struct wl3501_get_req sig = { | ||
439 | .sig_id = WL3501_SIG_GET_REQ, | ||
440 | .mib_attrib = index, | ||
441 | }; | ||
442 | unsigned long flags; | ||
443 | int rc = -EIO; | ||
444 | |||
445 | spin_lock_irqsave(&this->lock, flags); | ||
446 | if (wl3501_esbq_req_test(this)) { | ||
447 | u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); | ||
448 | if (ptr) { | ||
449 | wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); | ||
450 | wl3501_esbq_req(this, &ptr); | ||
451 | this->sig_get_confirm.mib_status = 255; | ||
452 | spin_unlock_irqrestore(&this->lock, flags); | ||
453 | rc = wait_event_interruptible(this->wait, | ||
454 | this->sig_get_confirm.mib_status != 255); | ||
455 | if (!rc) | ||
456 | memcpy(bf, this->sig_get_confirm.mib_value, | ||
457 | size); | ||
458 | goto out; | ||
459 | } | ||
460 | } | ||
461 | spin_unlock_irqrestore(&this->lock, flags); | ||
462 | out: | ||
463 | return rc; | ||
464 | } | ||
465 | |||
466 | static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) | ||
467 | { | ||
468 | struct wl3501_pwr_mgmt_req sig = { | ||
469 | .sig_id = WL3501_SIG_PWR_MGMT_REQ, | ||
470 | .pwr_save = suspend, | ||
471 | .wake_up = !suspend, | ||
472 | .receive_dtims = 10, | ||
473 | }; | ||
474 | unsigned long flags; | ||
475 | int rc = -EIO; | ||
476 | |||
477 | spin_lock_irqsave(&this->lock, flags); | ||
478 | if (wl3501_esbq_req_test(this)) { | ||
479 | u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); | ||
480 | if (ptr) { | ||
481 | wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); | ||
482 | wl3501_esbq_req(this, &ptr); | ||
483 | this->sig_pwr_mgmt_confirm.status = 255; | ||
484 | spin_unlock_irqrestore(&this->lock, flags); | ||
485 | rc = wait_event_interruptible(this->wait, | ||
486 | this->sig_pwr_mgmt_confirm.status != 255); | ||
487 | printk(KERN_INFO "%s: %s status=%d\n", __FUNCTION__, | ||
488 | suspend ? "suspend" : "resume", | ||
489 | this->sig_pwr_mgmt_confirm.status); | ||
490 | goto out; | ||
491 | } | ||
492 | } | ||
493 | spin_unlock_irqrestore(&this->lock, flags); | ||
494 | out: | ||
495 | return rc; | ||
496 | } | ||
497 | |||
498 | /** | ||
499 | * wl3501_send_pkt - Send a packet. | ||
500 | * @this - card | ||
501 | * | ||
502 | * Send a packet. | ||
503 | * | ||
504 | * data = Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, | ||
505 | * data[6] - data[11] is Src MAC Addr) | ||
506 | * Ref: IEEE 802.11 | ||
507 | */ | ||
508 | static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len) | ||
509 | { | ||
510 | u16 bf, sig_bf, next, tmplen, pktlen; | ||
511 | struct wl3501_md_req sig = { | ||
512 | .sig_id = WL3501_SIG_MD_REQ, | ||
513 | }; | ||
514 | u8 *pdata = (char *)data; | ||
515 | int rc = -EIO; | ||
516 | |||
517 | if (wl3501_esbq_req_test(this)) { | ||
518 | sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); | ||
519 | rc = -ENOMEM; | ||
520 | if (!sig_bf) /* No free buffer available */ | ||
521 | goto out; | ||
522 | bf = wl3501_get_tx_buffer(this, len + 26 + 24); | ||
523 | if (!bf) { | ||
524 | /* No free buffer available */ | ||
525 | wl3501_free_tx_buffer(this, sig_bf); | ||
526 | goto out; | ||
527 | } | ||
528 | rc = 0; | ||
529 | memcpy(&sig.daddr[0], pdata, 12); | ||
530 | pktlen = len - 12; | ||
531 | pdata += 12; | ||
532 | sig.data = bf; | ||
533 | if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { | ||
534 | u8 addr4[ETH_ALEN] = { | ||
535 | [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, | ||
536 | }; | ||
537 | |||
538 | wl3501_set_to_wla(this, bf + 2 + | ||
539 | offsetof(struct wl3501_tx_hdr, addr4), | ||
540 | addr4, sizeof(addr4)); | ||
541 | sig.size = pktlen + 24 + 4 + 6; | ||
542 | if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { | ||
543 | tmplen = 254 - sizeof(struct wl3501_tx_hdr); | ||
544 | pktlen -= tmplen; | ||
545 | } else { | ||
546 | tmplen = pktlen; | ||
547 | pktlen = 0; | ||
548 | } | ||
549 | wl3501_set_to_wla(this, | ||
550 | bf + 2 + sizeof(struct wl3501_tx_hdr), | ||
551 | pdata, tmplen); | ||
552 | pdata += tmplen; | ||
553 | wl3501_get_from_wla(this, bf, &next, sizeof(next)); | ||
554 | bf = next; | ||
555 | } else { | ||
556 | sig.size = pktlen + 24 + 4 - 2; | ||
557 | pdata += 2; | ||
558 | pktlen -= 2; | ||
559 | if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { | ||
560 | tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; | ||
561 | pktlen -= tmplen; | ||
562 | } else { | ||
563 | tmplen = pktlen; | ||
564 | pktlen = 0; | ||
565 | } | ||
566 | wl3501_set_to_wla(this, bf + 2 + | ||
567 | offsetof(struct wl3501_tx_hdr, addr4), | ||
568 | pdata, tmplen); | ||
569 | pdata += tmplen; | ||
570 | wl3501_get_from_wla(this, bf, &next, sizeof(next)); | ||
571 | bf = next; | ||
572 | } | ||
573 | while (pktlen > 0) { | ||
574 | if (pktlen > 254) { | ||
575 | tmplen = 254; | ||
576 | pktlen -= 254; | ||
577 | } else { | ||
578 | tmplen = pktlen; | ||
579 | pktlen = 0; | ||
580 | } | ||
581 | wl3501_set_to_wla(this, bf + 2, pdata, tmplen); | ||
582 | pdata += tmplen; | ||
583 | wl3501_get_from_wla(this, bf, &next, sizeof(next)); | ||
584 | bf = next; | ||
585 | } | ||
586 | wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); | ||
587 | wl3501_esbq_req(this, &sig_bf); | ||
588 | } | ||
589 | out: | ||
590 | return rc; | ||
591 | } | ||
592 | |||
593 | static int wl3501_mgmt_resync(struct wl3501_card *this) | ||
594 | { | ||
595 | struct wl3501_resync_req sig = { | ||
596 | .sig_id = WL3501_SIG_RESYNC_REQ, | ||
597 | }; | ||
598 | |||
599 | return wl3501_esbq_exec(this, &sig, sizeof(sig)); | ||
600 | } | ||
601 | |||
602 | static inline int wl3501_fw_bss_type(struct wl3501_card *this) | ||
603 | { | ||
604 | return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : | ||
605 | WL3501_NET_TYPE_ADHOC; | ||
606 | } | ||
607 | |||
608 | static inline int wl3501_fw_cap_info(struct wl3501_card *this) | ||
609 | { | ||
610 | return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : | ||
611 | WL3501_MGMT_CAPABILITY_IBSS; | ||
612 | } | ||
613 | |||
614 | static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time) | ||
615 | { | ||
616 | struct wl3501_scan_req sig = { | ||
617 | .sig_id = WL3501_SIG_SCAN_REQ, | ||
618 | .scan_type = WL3501_SCAN_TYPE_ACTIVE, | ||
619 | .probe_delay = 0x10, | ||
620 | .min_chan_time = chan_time, | ||
621 | .max_chan_time = chan_time, | ||
622 | .bss_type = wl3501_fw_bss_type(this), | ||
623 | }; | ||
624 | |||
625 | this->bss_cnt = this->join_sta_bss = 0; | ||
626 | return wl3501_esbq_exec(this, &sig, sizeof(sig)); | ||
627 | } | ||
628 | |||
629 | static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) | ||
630 | { | ||
631 | struct wl3501_join_req sig = { | ||
632 | .sig_id = WL3501_SIG_JOIN_REQ, | ||
633 | .timeout = 10, | ||
634 | .ds_pset = { | ||
635 | .el = { | ||
636 | .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, | ||
637 | .len = 1, | ||
638 | }, | ||
639 | .chan = this->chan, | ||
640 | }, | ||
641 | }; | ||
642 | |||
643 | memcpy(&sig.beacon_period, &this->bss_set[stas].beacon_period, 72); | ||
644 | return wl3501_esbq_exec(this, &sig, sizeof(sig)); | ||
645 | } | ||
646 | |||
647 | static int wl3501_mgmt_start(struct wl3501_card *this) | ||
648 | { | ||
649 | struct wl3501_start_req sig = { | ||
650 | .sig_id = WL3501_SIG_START_REQ, | ||
651 | .beacon_period = 400, | ||
652 | .dtim_period = 1, | ||
653 | .ds_pset = { | ||
654 | .el = { | ||
655 | .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, | ||
656 | .len = 1, | ||
657 | }, | ||
658 | .chan = this->chan, | ||
659 | }, | ||
660 | .bss_basic_rset = { | ||
661 | .el = { | ||
662 | .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, | ||
663 | .len = 2, | ||
664 | }, | ||
665 | .data_rate_labels = { | ||
666 | [0] = IW_MGMT_RATE_LABEL_MANDATORY | | ||
667 | IW_MGMT_RATE_LABEL_1MBIT, | ||
668 | [1] = IW_MGMT_RATE_LABEL_MANDATORY | | ||
669 | IW_MGMT_RATE_LABEL_2MBIT, | ||
670 | }, | ||
671 | }, | ||
672 | .operational_rset = { | ||
673 | .el = { | ||
674 | .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, | ||
675 | .len = 2, | ||
676 | }, | ||
677 | .data_rate_labels = { | ||
678 | [0] = IW_MGMT_RATE_LABEL_MANDATORY | | ||
679 | IW_MGMT_RATE_LABEL_1MBIT, | ||
680 | [1] = IW_MGMT_RATE_LABEL_MANDATORY | | ||
681 | IW_MGMT_RATE_LABEL_2MBIT, | ||
682 | }, | ||
683 | }, | ||
684 | .ibss_pset = { | ||
685 | .el = { | ||
686 | .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, | ||
687 | .len = 2, | ||
688 | }, | ||
689 | .atim_window = 10, | ||
690 | }, | ||
691 | .bss_type = wl3501_fw_bss_type(this), | ||
692 | .cap_info = wl3501_fw_cap_info(this), | ||
693 | }; | ||
694 | |||
695 | iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); | ||
696 | iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); | ||
697 | return wl3501_esbq_exec(this, &sig, sizeof(sig)); | ||
698 | } | ||
699 | |||
700 | static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) | ||
701 | { | ||
702 | u16 i = 0; | ||
703 | int matchflag = 0; | ||
704 | struct wl3501_scan_confirm sig; | ||
705 | |||
706 | dprintk(3, "entry"); | ||
707 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
708 | if (sig.status == WL3501_STATUS_SUCCESS) { | ||
709 | dprintk(3, "success"); | ||
710 | if ((this->net_type == IW_MODE_INFRA && | ||
711 | (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || | ||
712 | (this->net_type == IW_MODE_ADHOC && | ||
713 | (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || | ||
714 | this->net_type == IW_MODE_AUTO) { | ||
715 | if (!this->essid.el.len) | ||
716 | matchflag = 1; | ||
717 | else if (this->essid.el.len == 3 && | ||
718 | !memcmp(this->essid.essid, "ANY", 3)) | ||
719 | matchflag = 1; | ||
720 | else if (this->essid.el.len != sig.ssid.el.len) | ||
721 | matchflag = 0; | ||
722 | else if (memcmp(this->essid.essid, sig.ssid.essid, | ||
723 | this->essid.el.len)) | ||
724 | matchflag = 0; | ||
725 | else | ||
726 | matchflag = 1; | ||
727 | if (matchflag) { | ||
728 | for (i = 0; i < this->bss_cnt; i++) { | ||
729 | if (!memcmp(this->bss_set[i].bssid, | ||
730 | sig.bssid, ETH_ALEN)) { | ||
731 | matchflag = 0; | ||
732 | break; | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | if (matchflag && (i < 20)) { | ||
737 | memcpy(&this->bss_set[i].beacon_period, | ||
738 | &sig.beacon_period, 73); | ||
739 | this->bss_cnt++; | ||
740 | this->rssi = sig.rssi; | ||
741 | } | ||
742 | } | ||
743 | } else if (sig.status == WL3501_STATUS_TIMEOUT) { | ||
744 | dprintk(3, "timeout"); | ||
745 | this->join_sta_bss = 0; | ||
746 | for (i = this->join_sta_bss; i < this->bss_cnt; i++) | ||
747 | if (!wl3501_mgmt_join(this, i)) | ||
748 | break; | ||
749 | this->join_sta_bss = i; | ||
750 | if (this->join_sta_bss == this->bss_cnt) { | ||
751 | if (this->net_type == IW_MODE_INFRA) | ||
752 | wl3501_mgmt_scan(this, 100); | ||
753 | else { | ||
754 | this->adhoc_times++; | ||
755 | if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) | ||
756 | wl3501_mgmt_start(this); | ||
757 | else | ||
758 | wl3501_mgmt_scan(this, 100); | ||
759 | } | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * wl3501_block_interrupt - Mask interrupt from SUTRO | ||
766 | * @this - card | ||
767 | * | ||
768 | * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) | ||
769 | * Return: 1 if interrupt is originally enabled | ||
770 | */ | ||
771 | static int wl3501_block_interrupt(struct wl3501_card *this) | ||
772 | { | ||
773 | u8 old = inb(this->base_addr + WL3501_NIC_GCR); | ||
774 | u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | | ||
775 | WL3501_GCR_ENECINT)); | ||
776 | |||
777 | wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); | ||
778 | return old & WL3501_GCR_ENECINT; | ||
779 | } | ||
780 | |||
781 | /** | ||
782 | * wl3501_unblock_interrupt - Enable interrupt from SUTRO | ||
783 | * @this - card | ||
784 | * | ||
785 | * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) | ||
786 | * Return: 1 if interrupt is originally enabled | ||
787 | */ | ||
788 | static int wl3501_unblock_interrupt(struct wl3501_card *this) | ||
789 | { | ||
790 | u8 old = inb(this->base_addr + WL3501_NIC_GCR); | ||
791 | u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | | ||
792 | WL3501_GCR_ENECINT; | ||
793 | |||
794 | wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); | ||
795 | return old & WL3501_GCR_ENECINT; | ||
796 | } | ||
797 | |||
798 | /** | ||
799 | * wl3501_receive - Receive data from Receive Queue. | ||
800 | * | ||
801 | * Receive data from Receive Queue. | ||
802 | * | ||
803 | * @this: card | ||
804 | * @bf: address of host | ||
805 | * @size: size of buffer. | ||
806 | */ | ||
807 | static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size) | ||
808 | { | ||
809 | u16 next_addr, next_addr1; | ||
810 | u8 *data = bf + 12; | ||
811 | |||
812 | size -= 12; | ||
813 | wl3501_get_from_wla(this, this->start_seg + 2, | ||
814 | &next_addr, sizeof(next_addr)); | ||
815 | if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { | ||
816 | wl3501_get_from_wla(this, | ||
817 | this->start_seg + | ||
818 | sizeof(struct wl3501_rx_hdr), data, | ||
819 | WL3501_BLKSZ - | ||
820 | sizeof(struct wl3501_rx_hdr)); | ||
821 | size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); | ||
822 | data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); | ||
823 | } else { | ||
824 | wl3501_get_from_wla(this, | ||
825 | this->start_seg + | ||
826 | sizeof(struct wl3501_rx_hdr), | ||
827 | data, size); | ||
828 | size = 0; | ||
829 | } | ||
830 | while (size > 0) { | ||
831 | if (size > WL3501_BLKSZ - 5) { | ||
832 | wl3501_get_from_wla(this, next_addr + 5, data, | ||
833 | WL3501_BLKSZ - 5); | ||
834 | size -= WL3501_BLKSZ - 5; | ||
835 | data += WL3501_BLKSZ - 5; | ||
836 | wl3501_get_from_wla(this, next_addr + 2, &next_addr1, | ||
837 | sizeof(next_addr1)); | ||
838 | next_addr = next_addr1; | ||
839 | } else { | ||
840 | wl3501_get_from_wla(this, next_addr + 5, data, size); | ||
841 | size = 0; | ||
842 | } | ||
843 | } | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static void wl3501_esbq_req_free(struct wl3501_card *this) | ||
848 | { | ||
849 | u8 tmp; | ||
850 | u16 addr; | ||
851 | |||
852 | if (this->esbq_req_head == this->esbq_req_tail) | ||
853 | goto out; | ||
854 | wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); | ||
855 | if (!(tmp & 0x80)) | ||
856 | goto out; | ||
857 | wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); | ||
858 | wl3501_free_tx_buffer(this, addr); | ||
859 | this->esbq_req_tail += 4; | ||
860 | if (this->esbq_req_tail >= this->esbq_req_end) | ||
861 | this->esbq_req_tail = this->esbq_req_start; | ||
862 | out: | ||
863 | return; | ||
864 | } | ||
865 | |||
866 | static int wl3501_esbq_confirm(struct wl3501_card *this) | ||
867 | { | ||
868 | u8 tmp; | ||
869 | |||
870 | wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); | ||
871 | return tmp & 0x80; | ||
872 | } | ||
873 | |||
874 | static void wl3501_online(struct net_device *dev) | ||
875 | { | ||
876 | struct wl3501_card *this = dev->priv; | ||
877 | |||
878 | printk(KERN_INFO "%s: Wireless LAN online. BSSID: " | ||
879 | "%02X %02X %02X %02X %02X %02X\n", dev->name, | ||
880 | this->bssid[0], this->bssid[1], this->bssid[2], | ||
881 | this->bssid[3], this->bssid[4], this->bssid[5]); | ||
882 | netif_wake_queue(dev); | ||
883 | } | ||
884 | |||
885 | static void wl3501_esbq_confirm_done(struct wl3501_card *this) | ||
886 | { | ||
887 | u8 tmp = 0; | ||
888 | |||
889 | wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); | ||
890 | this->esbq_confirm += 4; | ||
891 | if (this->esbq_confirm >= this->esbq_confirm_end) | ||
892 | this->esbq_confirm = this->esbq_confirm_start; | ||
893 | } | ||
894 | |||
895 | static int wl3501_mgmt_auth(struct wl3501_card *this) | ||
896 | { | ||
897 | struct wl3501_auth_req sig = { | ||
898 | .sig_id = WL3501_SIG_AUTH_REQ, | ||
899 | .type = WL3501_SYS_TYPE_OPEN, | ||
900 | .timeout = 1000, | ||
901 | }; | ||
902 | |||
903 | dprintk(3, "entry"); | ||
904 | memcpy(sig.mac_addr, this->bssid, ETH_ALEN); | ||
905 | return wl3501_esbq_exec(this, &sig, sizeof(sig)); | ||
906 | } | ||
907 | |||
908 | static int wl3501_mgmt_association(struct wl3501_card *this) | ||
909 | { | ||
910 | struct wl3501_assoc_req sig = { | ||
911 | .sig_id = WL3501_SIG_ASSOC_REQ, | ||
912 | .timeout = 1000, | ||
913 | .listen_interval = 5, | ||
914 | .cap_info = this->cap_info, | ||
915 | }; | ||
916 | |||
917 | dprintk(3, "entry"); | ||
918 | memcpy(sig.mac_addr, this->bssid, ETH_ALEN); | ||
919 | return wl3501_esbq_exec(this, &sig, sizeof(sig)); | ||
920 | } | ||
921 | |||
922 | static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) | ||
923 | { | ||
924 | struct wl3501_card *this = dev->priv; | ||
925 | struct wl3501_join_confirm sig; | ||
926 | |||
927 | dprintk(3, "entry"); | ||
928 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
929 | if (sig.status == WL3501_STATUS_SUCCESS) { | ||
930 | if (this->net_type == IW_MODE_INFRA) { | ||
931 | if (this->join_sta_bss < this->bss_cnt) { | ||
932 | const int i = this->join_sta_bss; | ||
933 | memcpy(this->bssid, | ||
934 | this->bss_set[i].bssid, ETH_ALEN); | ||
935 | this->chan = this->bss_set[i].ds_pset.chan; | ||
936 | iw_copy_mgmt_info_element(&this->keep_essid.el, | ||
937 | &this->bss_set[i].ssid.el); | ||
938 | wl3501_mgmt_auth(this); | ||
939 | } | ||
940 | } else { | ||
941 | const int i = this->join_sta_bss; | ||
942 | |||
943 | memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN); | ||
944 | this->chan = this->bss_set[i].ds_pset.chan; | ||
945 | iw_copy_mgmt_info_element(&this->keep_essid.el, | ||
946 | &this->bss_set[i].ssid.el); | ||
947 | wl3501_online(dev); | ||
948 | } | ||
949 | } else { | ||
950 | int i; | ||
951 | this->join_sta_bss++; | ||
952 | for (i = this->join_sta_bss; i < this->bss_cnt; i++) | ||
953 | if (!wl3501_mgmt_join(this, i)) | ||
954 | break; | ||
955 | this->join_sta_bss = i; | ||
956 | if (this->join_sta_bss == this->bss_cnt) { | ||
957 | if (this->net_type == IW_MODE_INFRA) | ||
958 | wl3501_mgmt_scan(this, 100); | ||
959 | else { | ||
960 | this->adhoc_times++; | ||
961 | if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) | ||
962 | wl3501_mgmt_start(this); | ||
963 | else | ||
964 | wl3501_mgmt_scan(this, 100); | ||
965 | } | ||
966 | } | ||
967 | } | ||
968 | } | ||
969 | |||
970 | static inline void wl3501_alarm_interrupt(struct net_device *dev, | ||
971 | struct wl3501_card *this) | ||
972 | { | ||
973 | if (this->net_type == IW_MODE_INFRA) { | ||
974 | printk(KERN_INFO "Wireless LAN offline\n"); | ||
975 | netif_stop_queue(dev); | ||
976 | wl3501_mgmt_resync(this); | ||
977 | } | ||
978 | } | ||
979 | |||
980 | static inline void wl3501_md_confirm_interrupt(struct net_device *dev, | ||
981 | struct wl3501_card *this, | ||
982 | u16 addr) | ||
983 | { | ||
984 | struct wl3501_md_confirm sig; | ||
985 | |||
986 | dprintk(3, "entry"); | ||
987 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
988 | wl3501_free_tx_buffer(this, sig.data); | ||
989 | if (netif_queue_stopped(dev)) | ||
990 | netif_wake_queue(dev); | ||
991 | } | ||
992 | |||
993 | static inline void wl3501_md_ind_interrupt(struct net_device *dev, | ||
994 | struct wl3501_card *this, u16 addr) | ||
995 | { | ||
996 | struct wl3501_md_ind sig; | ||
997 | struct sk_buff *skb; | ||
998 | u8 rssi, addr4[ETH_ALEN]; | ||
999 | u16 pkt_len; | ||
1000 | |||
1001 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
1002 | this->start_seg = sig.data; | ||
1003 | wl3501_get_from_wla(this, | ||
1004 | sig.data + offsetof(struct wl3501_rx_hdr, rssi), | ||
1005 | &rssi, sizeof(rssi)); | ||
1006 | this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; | ||
1007 | |||
1008 | wl3501_get_from_wla(this, | ||
1009 | sig.data + | ||
1010 | offsetof(struct wl3501_rx_hdr, addr4), | ||
1011 | &addr4, sizeof(addr4)); | ||
1012 | if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && | ||
1013 | addr4[2] == 0x03 && addr4[4] == 0x00)) { | ||
1014 | printk(KERN_INFO "Insupported packet type!\n"); | ||
1015 | return; | ||
1016 | } | ||
1017 | pkt_len = sig.size + 12 - 24 - 4 - 6; | ||
1018 | |||
1019 | skb = dev_alloc_skb(pkt_len + 5); | ||
1020 | |||
1021 | if (!skb) { | ||
1022 | printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", | ||
1023 | dev->name, pkt_len); | ||
1024 | this->stats.rx_dropped++; | ||
1025 | } else { | ||
1026 | skb->dev = dev; | ||
1027 | skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ | ||
1028 | eth_copy_and_sum(skb, (unsigned char *)&sig.daddr, 12, 0); | ||
1029 | wl3501_receive(this, skb->data, pkt_len); | ||
1030 | skb_put(skb, pkt_len); | ||
1031 | skb->protocol = eth_type_trans(skb, dev); | ||
1032 | dev->last_rx = jiffies; | ||
1033 | this->stats.rx_packets++; | ||
1034 | this->stats.rx_bytes += skb->len; | ||
1035 | netif_rx(skb); | ||
1036 | } | ||
1037 | } | ||
1038 | |||
1039 | static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, | ||
1040 | u16 addr, void *sig, int size) | ||
1041 | { | ||
1042 | dprintk(3, "entry"); | ||
1043 | wl3501_get_from_wla(this, addr, &this->sig_get_confirm, | ||
1044 | sizeof(this->sig_get_confirm)); | ||
1045 | wake_up(&this->wait); | ||
1046 | } | ||
1047 | |||
1048 | static inline void wl3501_start_confirm_interrupt(struct net_device *dev, | ||
1049 | struct wl3501_card *this, | ||
1050 | u16 addr) | ||
1051 | { | ||
1052 | struct wl3501_start_confirm sig; | ||
1053 | |||
1054 | dprintk(3, "entry"); | ||
1055 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
1056 | if (sig.status == WL3501_STATUS_SUCCESS) | ||
1057 | netif_wake_queue(dev); | ||
1058 | } | ||
1059 | |||
1060 | static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, | ||
1061 | u16 addr) | ||
1062 | { | ||
1063 | struct wl3501_card *this = dev->priv; | ||
1064 | struct wl3501_assoc_confirm sig; | ||
1065 | |||
1066 | dprintk(3, "entry"); | ||
1067 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
1068 | |||
1069 | if (sig.status == WL3501_STATUS_SUCCESS) | ||
1070 | wl3501_online(dev); | ||
1071 | } | ||
1072 | |||
1073 | static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, | ||
1074 | u16 addr) | ||
1075 | { | ||
1076 | struct wl3501_auth_confirm sig; | ||
1077 | |||
1078 | dprintk(3, "entry"); | ||
1079 | wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); | ||
1080 | |||
1081 | if (sig.status == WL3501_STATUS_SUCCESS) | ||
1082 | wl3501_mgmt_association(this); | ||
1083 | else | ||
1084 | wl3501_mgmt_resync(this); | ||
1085 | } | ||
1086 | |||
1087 | static inline void wl3501_rx_interrupt(struct net_device *dev) | ||
1088 | { | ||
1089 | int morepkts; | ||
1090 | u16 addr; | ||
1091 | u8 sig_id; | ||
1092 | struct wl3501_card *this = dev->priv; | ||
1093 | |||
1094 | dprintk(3, "entry"); | ||
1095 | loop: | ||
1096 | morepkts = 0; | ||
1097 | if (!wl3501_esbq_confirm(this)) | ||
1098 | goto free; | ||
1099 | wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); | ||
1100 | wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); | ||
1101 | |||
1102 | switch (sig_id) { | ||
1103 | case WL3501_SIG_DEAUTH_IND: | ||
1104 | case WL3501_SIG_DISASSOC_IND: | ||
1105 | case WL3501_SIG_ALARM: | ||
1106 | wl3501_alarm_interrupt(dev, this); | ||
1107 | break; | ||
1108 | case WL3501_SIG_MD_CONFIRM: | ||
1109 | wl3501_md_confirm_interrupt(dev, this, addr); | ||
1110 | break; | ||
1111 | case WL3501_SIG_MD_IND: | ||
1112 | wl3501_md_ind_interrupt(dev, this, addr); | ||
1113 | break; | ||
1114 | case WL3501_SIG_GET_CONFIRM: | ||
1115 | wl3501_get_confirm_interrupt(this, addr, | ||
1116 | &this->sig_get_confirm, | ||
1117 | sizeof(this->sig_get_confirm)); | ||
1118 | break; | ||
1119 | case WL3501_SIG_PWR_MGMT_CONFIRM: | ||
1120 | wl3501_get_confirm_interrupt(this, addr, | ||
1121 | &this->sig_pwr_mgmt_confirm, | ||
1122 | sizeof(this->sig_pwr_mgmt_confirm)); | ||
1123 | break; | ||
1124 | case WL3501_SIG_START_CONFIRM: | ||
1125 | wl3501_start_confirm_interrupt(dev, this, addr); | ||
1126 | break; | ||
1127 | case WL3501_SIG_SCAN_CONFIRM: | ||
1128 | wl3501_mgmt_scan_confirm(this, addr); | ||
1129 | break; | ||
1130 | case WL3501_SIG_JOIN_CONFIRM: | ||
1131 | wl3501_mgmt_join_confirm(dev, addr); | ||
1132 | break; | ||
1133 | case WL3501_SIG_ASSOC_CONFIRM: | ||
1134 | wl3501_assoc_confirm_interrupt(dev, addr); | ||
1135 | break; | ||
1136 | case WL3501_SIG_AUTH_CONFIRM: | ||
1137 | wl3501_auth_confirm_interrupt(this, addr); | ||
1138 | break; | ||
1139 | case WL3501_SIG_RESYNC_CONFIRM: | ||
1140 | wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ | ||
1141 | break; | ||
1142 | } | ||
1143 | wl3501_esbq_confirm_done(this); | ||
1144 | morepkts = 1; | ||
1145 | /* free request if necessary */ | ||
1146 | free: | ||
1147 | wl3501_esbq_req_free(this); | ||
1148 | if (morepkts) | ||
1149 | goto loop; | ||
1150 | } | ||
1151 | |||
1152 | static inline void wl3501_ack_interrupt(struct wl3501_card *this) | ||
1153 | { | ||
1154 | wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR); | ||
1155 | } | ||
1156 | |||
1157 | /** | ||
1158 | * wl3501_interrupt - Hardware interrupt from card. | ||
1159 | * @irq - Interrupt number | ||
1160 | * @dev_id - net_device | ||
1161 | * @regs - registers | ||
1162 | * | ||
1163 | * We must acknowledge the interrupt as soon as possible, and block the | ||
1164 | * interrupt from the same card immediately to prevent re-entry. | ||
1165 | * | ||
1166 | * Before accessing the Control_Status_Block, we must lock SUTRO first. | ||
1167 | * On the other hand, to prevent SUTRO from malfunctioning, we must | ||
1168 | * unlock the SUTRO as soon as possible. | ||
1169 | */ | ||
1170 | static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1171 | { | ||
1172 | struct net_device *dev = (struct net_device *)dev_id; | ||
1173 | struct wl3501_card *this; | ||
1174 | int handled = 1; | ||
1175 | |||
1176 | if (!dev) | ||
1177 | goto unknown; | ||
1178 | this = dev->priv; | ||
1179 | spin_lock(&this->lock); | ||
1180 | wl3501_ack_interrupt(this); | ||
1181 | wl3501_block_interrupt(this); | ||
1182 | wl3501_rx_interrupt(dev); | ||
1183 | wl3501_unblock_interrupt(this); | ||
1184 | spin_unlock(&this->lock); | ||
1185 | out: | ||
1186 | return IRQ_RETVAL(handled); | ||
1187 | unknown: | ||
1188 | handled = 0; | ||
1189 | printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq); | ||
1190 | goto out; | ||
1191 | } | ||
1192 | |||
1193 | static int wl3501_reset_board(struct wl3501_card *this) | ||
1194 | { | ||
1195 | u8 tmp = 0; | ||
1196 | int i, rc = 0; | ||
1197 | |||
1198 | /* Coreset */ | ||
1199 | wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); | ||
1200 | wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); | ||
1201 | wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); | ||
1202 | |||
1203 | /* Reset SRAM 0x480 to zero */ | ||
1204 | wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); | ||
1205 | |||
1206 | /* Start up */ | ||
1207 | wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); | ||
1208 | |||
1209 | WL3501_NOPLOOP(1024 * 50); | ||
1210 | |||
1211 | wl3501_unblock_interrupt(this); /* acme: was commented */ | ||
1212 | |||
1213 | /* Polling Self_Test_Status */ | ||
1214 | for (i = 0; i < 10000; i++) { | ||
1215 | wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); | ||
1216 | |||
1217 | if (tmp == 'W') { | ||
1218 | /* firmware complete all test successfully */ | ||
1219 | tmp = 'A'; | ||
1220 | wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); | ||
1221 | goto out; | ||
1222 | } | ||
1223 | WL3501_NOPLOOP(10); | ||
1224 | } | ||
1225 | printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__); | ||
1226 | rc = -ENODEV; | ||
1227 | out: | ||
1228 | return rc; | ||
1229 | } | ||
1230 | |||
1231 | static int wl3501_init_firmware(struct wl3501_card *this) | ||
1232 | { | ||
1233 | u16 ptr, next; | ||
1234 | int rc = wl3501_reset_board(this); | ||
1235 | |||
1236 | if (rc) | ||
1237 | goto fail; | ||
1238 | this->card_name[0] = '\0'; | ||
1239 | wl3501_get_from_wla(this, 0x1a00, | ||
1240 | this->card_name, sizeof(this->card_name)); | ||
1241 | this->card_name[sizeof(this->card_name) - 1] = '\0'; | ||
1242 | this->firmware_date[0] = '\0'; | ||
1243 | wl3501_get_from_wla(this, 0x1a40, | ||
1244 | this->firmware_date, sizeof(this->firmware_date)); | ||
1245 | this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; | ||
1246 | /* Switch to SRAM Page 0 */ | ||
1247 | wl3501_switch_page(this, WL3501_BSS_SPAGE0); | ||
1248 | /* Read parameter from card */ | ||
1249 | wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); | ||
1250 | wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); | ||
1251 | wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); | ||
1252 | wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); | ||
1253 | wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); | ||
1254 | wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); | ||
1255 | this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; | ||
1256 | this->esbq_req_end += this->esbq_req_start; | ||
1257 | this->esbq_confirm = this->esbq_confirm_start; | ||
1258 | this->esbq_confirm_end += this->esbq_confirm_start; | ||
1259 | /* Initial Tx Buffer */ | ||
1260 | this->tx_buffer_cnt = 1; | ||
1261 | ptr = this->tx_buffer_head; | ||
1262 | next = ptr + WL3501_BLKSZ; | ||
1263 | while ((next - this->tx_buffer_head) < this->tx_buffer_size) { | ||
1264 | this->tx_buffer_cnt++; | ||
1265 | wl3501_set_to_wla(this, ptr, &next, sizeof(next)); | ||
1266 | ptr = next; | ||
1267 | next = ptr + WL3501_BLKSZ; | ||
1268 | } | ||
1269 | rc = 0; | ||
1270 | next = 0; | ||
1271 | wl3501_set_to_wla(this, ptr, &next, sizeof(next)); | ||
1272 | this->tx_buffer_tail = ptr; | ||
1273 | out: | ||
1274 | return rc; | ||
1275 | fail: | ||
1276 | printk(KERN_WARNING "%s: failed!\n", __FUNCTION__); | ||
1277 | goto out; | ||
1278 | } | ||
1279 | |||
1280 | static int wl3501_close(struct net_device *dev) | ||
1281 | { | ||
1282 | struct wl3501_card *this = dev->priv; | ||
1283 | int rc = -ENODEV; | ||
1284 | unsigned long flags; | ||
1285 | dev_link_t *link; | ||
1286 | |||
1287 | spin_lock_irqsave(&this->lock, flags); | ||
1288 | /* Check if the device is in wl3501_dev_list */ | ||
1289 | for (link = wl3501_dev_list; link; link = link->next) | ||
1290 | if (link->priv == dev) | ||
1291 | break; | ||
1292 | if (!link) | ||
1293 | goto out; | ||
1294 | link->open--; | ||
1295 | |||
1296 | /* Stop wl3501_hard_start_xmit() from now on */ | ||
1297 | netif_stop_queue(dev); | ||
1298 | wl3501_ack_interrupt(this); | ||
1299 | |||
1300 | /* Mask interrupts from the SUTRO */ | ||
1301 | wl3501_block_interrupt(this); | ||
1302 | |||
1303 | rc = 0; | ||
1304 | printk(KERN_INFO "%s: WL3501 closed\n", dev->name); | ||
1305 | out: | ||
1306 | spin_unlock_irqrestore(&this->lock, flags); | ||
1307 | return rc; | ||
1308 | } | ||
1309 | |||
1310 | /** | ||
1311 | * wl3501_reset - Reset the SUTRO. | ||
1312 | * @dev - network device | ||
1313 | * | ||
1314 | * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() | ||
1315 | * and wl3501_open() again, but I wouldn't like to free_irq() when the driver | ||
1316 | * is running. It seems to be dangerous. | ||
1317 | */ | ||
1318 | static int wl3501_reset(struct net_device *dev) | ||
1319 | { | ||
1320 | struct wl3501_card *this = dev->priv; | ||
1321 | int rc = -ENODEV; | ||
1322 | |||
1323 | wl3501_block_interrupt(this); | ||
1324 | |||
1325 | if (wl3501_init_firmware(this)) { | ||
1326 | printk(KERN_WARNING "%s: Can't initialize Firmware!\n", | ||
1327 | dev->name); | ||
1328 | /* Free IRQ, and mark IRQ as unused */ | ||
1329 | free_irq(dev->irq, dev); | ||
1330 | goto out; | ||
1331 | } | ||
1332 | |||
1333 | /* | ||
1334 | * Queue has to be started only when the Card is Started | ||
1335 | */ | ||
1336 | netif_stop_queue(dev); | ||
1337 | this->adhoc_times = 0; | ||
1338 | wl3501_ack_interrupt(this); | ||
1339 | wl3501_unblock_interrupt(this); | ||
1340 | wl3501_mgmt_scan(this, 100); | ||
1341 | dprintk(1, "%s: device reset", dev->name); | ||
1342 | rc = 0; | ||
1343 | out: | ||
1344 | return rc; | ||
1345 | } | ||
1346 | |||
1347 | static void wl3501_tx_timeout(struct net_device *dev) | ||
1348 | { | ||
1349 | struct wl3501_card *this = dev->priv; | ||
1350 | struct net_device_stats *stats = &this->stats; | ||
1351 | unsigned long flags; | ||
1352 | int rc; | ||
1353 | |||
1354 | stats->tx_errors++; | ||
1355 | spin_lock_irqsave(&this->lock, flags); | ||
1356 | rc = wl3501_reset(dev); | ||
1357 | spin_unlock_irqrestore(&this->lock, flags); | ||
1358 | if (rc) | ||
1359 | printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", | ||
1360 | dev->name, rc); | ||
1361 | else { | ||
1362 | dev->trans_start = jiffies; | ||
1363 | netif_wake_queue(dev); | ||
1364 | } | ||
1365 | } | ||
1366 | |||
1367 | /* | ||
1368 | * Return : 0 - OK | ||
1369 | * 1 - Could not transmit (dev_queue_xmit will queue it) | ||
1370 | * and try to sent it later | ||
1371 | */ | ||
1372 | static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
1373 | { | ||
1374 | int enabled, rc; | ||
1375 | struct wl3501_card *this = dev->priv; | ||
1376 | unsigned long flags; | ||
1377 | |||
1378 | spin_lock_irqsave(&this->lock, flags); | ||
1379 | enabled = wl3501_block_interrupt(this); | ||
1380 | dev->trans_start = jiffies; | ||
1381 | rc = wl3501_send_pkt(this, skb->data, skb->len); | ||
1382 | if (enabled) | ||
1383 | wl3501_unblock_interrupt(this); | ||
1384 | if (rc) { | ||
1385 | ++this->stats.tx_dropped; | ||
1386 | netif_stop_queue(dev); | ||
1387 | } else { | ||
1388 | ++this->stats.tx_packets; | ||
1389 | this->stats.tx_bytes += skb->len; | ||
1390 | kfree_skb(skb); | ||
1391 | |||
1392 | if (this->tx_buffer_cnt < 2) | ||
1393 | netif_stop_queue(dev); | ||
1394 | } | ||
1395 | spin_unlock_irqrestore(&this->lock, flags); | ||
1396 | return rc; | ||
1397 | } | ||
1398 | |||
1399 | static int wl3501_open(struct net_device *dev) | ||
1400 | { | ||
1401 | int rc = -ENODEV; | ||
1402 | struct wl3501_card *this = dev->priv; | ||
1403 | unsigned long flags; | ||
1404 | dev_link_t *link; | ||
1405 | |||
1406 | spin_lock_irqsave(&this->lock, flags); | ||
1407 | /* Check if the device is in wl3501_dev_list */ | ||
1408 | for (link = wl3501_dev_list; link; link = link->next) | ||
1409 | if (link->priv == dev) | ||
1410 | break; | ||
1411 | if (!DEV_OK(link)) | ||
1412 | goto out; | ||
1413 | netif_device_attach(dev); | ||
1414 | link->open++; | ||
1415 | |||
1416 | /* Initial WL3501 firmware */ | ||
1417 | dprintk(1, "%s: Initialize WL3501 firmware...", dev->name); | ||
1418 | if (wl3501_init_firmware(this)) | ||
1419 | goto fail; | ||
1420 | /* Initial device variables */ | ||
1421 | this->adhoc_times = 0; | ||
1422 | /* Acknowledge Interrupt, for cleaning last state */ | ||
1423 | wl3501_ack_interrupt(this); | ||
1424 | |||
1425 | /* Enable interrupt from card after all */ | ||
1426 | wl3501_unblock_interrupt(this); | ||
1427 | wl3501_mgmt_scan(this, 100); | ||
1428 | rc = 0; | ||
1429 | dprintk(1, "%s: WL3501 opened", dev->name); | ||
1430 | printk(KERN_INFO "%s: Card Name: %s\n" | ||
1431 | "%s: Firmware Date: %s\n", | ||
1432 | dev->name, this->card_name, | ||
1433 | dev->name, this->firmware_date); | ||
1434 | out: | ||
1435 | spin_unlock_irqrestore(&this->lock, flags); | ||
1436 | return rc; | ||
1437 | fail: | ||
1438 | printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); | ||
1439 | goto out; | ||
1440 | } | ||
1441 | |||
1442 | struct net_device_stats *wl3501_get_stats(struct net_device *dev) | ||
1443 | { | ||
1444 | struct wl3501_card *this = dev->priv; | ||
1445 | |||
1446 | return &this->stats; | ||
1447 | } | ||
1448 | |||
1449 | struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) | ||
1450 | { | ||
1451 | struct wl3501_card *this = dev->priv; | ||
1452 | struct iw_statistics *wstats = &this->wstats; | ||
1453 | u32 value; /* size checked: it is u32 */ | ||
1454 | |||
1455 | memset(wstats, 0, sizeof(*wstats)); | ||
1456 | wstats->status = netif_running(dev); | ||
1457 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, | ||
1458 | &value, sizeof(value))) | ||
1459 | wstats->discard.code += value; | ||
1460 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, | ||
1461 | &value, sizeof(value))) | ||
1462 | wstats->discard.code += value; | ||
1463 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, | ||
1464 | &value, sizeof(value))) | ||
1465 | wstats->discard.code += value; | ||
1466 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, | ||
1467 | &value, sizeof(value))) | ||
1468 | wstats->discard.retries = value; | ||
1469 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, | ||
1470 | &value, sizeof(value))) | ||
1471 | wstats->discard.misc += value; | ||
1472 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, | ||
1473 | &value, sizeof(value))) | ||
1474 | wstats->discard.misc += value; | ||
1475 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, | ||
1476 | &value, sizeof(value))) | ||
1477 | wstats->discard.misc += value; | ||
1478 | if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, | ||
1479 | &value, sizeof(value))) | ||
1480 | wstats->discard.misc += value; | ||
1481 | return wstats; | ||
1482 | } | ||
1483 | |||
1484 | static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
1485 | { | ||
1486 | strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver)); | ||
1487 | } | ||
1488 | |||
1489 | static struct ethtool_ops ops = { | ||
1490 | .get_drvinfo = wl3501_get_drvinfo | ||
1491 | }; | ||
1492 | |||
1493 | /** | ||
1494 | * wl3501_detach - deletes a driver "instance" | ||
1495 | * @link - FILL_IN | ||
1496 | * | ||
1497 | * This deletes a driver "instance". The device is de-registered with Card | ||
1498 | * Services. If it has been released, all local data structures are freed. | ||
1499 | * Otherwise, the structures will be freed when the device is released. | ||
1500 | */ | ||
1501 | static void wl3501_detach(dev_link_t *link) | ||
1502 | { | ||
1503 | dev_link_t **linkp; | ||
1504 | |||
1505 | /* Locate device structure */ | ||
1506 | for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next) | ||
1507 | if (*linkp == link) | ||
1508 | break; | ||
1509 | if (!*linkp) | ||
1510 | goto out; | ||
1511 | |||
1512 | /* If the device is currently configured and active, we won't actually | ||
1513 | * delete it yet. Instead, it is marked so that when the release() | ||
1514 | * function is called, that will trigger a proper detach(). */ | ||
1515 | |||
1516 | if (link->state & DEV_CONFIG) { | ||
1517 | #ifdef PCMCIA_DEBUG | ||
1518 | printk(KERN_DEBUG "wl3501_cs: detach postponed, '%s' " | ||
1519 | "still locked\n", link->dev->dev_name); | ||
1520 | #endif | ||
1521 | goto out; | ||
1522 | } | ||
1523 | |||
1524 | /* Break the link with Card Services */ | ||
1525 | if (link->handle) | ||
1526 | pcmcia_deregister_client(link->handle); | ||
1527 | |||
1528 | /* Unlink device structure, free pieces */ | ||
1529 | *linkp = link->next; | ||
1530 | |||
1531 | if (link->priv) | ||
1532 | free_netdev(link->priv); | ||
1533 | kfree(link); | ||
1534 | out: | ||
1535 | return; | ||
1536 | } | ||
1537 | |||
1538 | static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, | ||
1539 | union iwreq_data *wrqu, char *extra) | ||
1540 | { | ||
1541 | strlcpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); | ||
1542 | return 0; | ||
1543 | } | ||
1544 | |||
1545 | static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, | ||
1546 | union iwreq_data *wrqu, char *extra) | ||
1547 | { | ||
1548 | struct wl3501_card *this = dev->priv; | ||
1549 | int channel = wrqu->freq.m; | ||
1550 | int rc = -EINVAL; | ||
1551 | |||
1552 | if (iw_valid_channel(this->reg_domain, channel)) { | ||
1553 | this->chan = channel; | ||
1554 | rc = wl3501_reset(dev); | ||
1555 | } | ||
1556 | return rc; | ||
1557 | } | ||
1558 | |||
1559 | static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, | ||
1560 | union iwreq_data *wrqu, char *extra) | ||
1561 | { | ||
1562 | struct wl3501_card *this = dev->priv; | ||
1563 | |||
1564 | wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000; | ||
1565 | wrqu->freq.e = 1; | ||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, | ||
1570 | union iwreq_data *wrqu, char *extra) | ||
1571 | { | ||
1572 | int rc = -EINVAL; | ||
1573 | |||
1574 | if (wrqu->mode == IW_MODE_INFRA || | ||
1575 | wrqu->mode == IW_MODE_ADHOC || | ||
1576 | wrqu->mode == IW_MODE_AUTO) { | ||
1577 | struct wl3501_card *this = dev->priv; | ||
1578 | |||
1579 | this->net_type = wrqu->mode; | ||
1580 | rc = wl3501_reset(dev); | ||
1581 | } | ||
1582 | return rc; | ||
1583 | } | ||
1584 | |||
1585 | static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, | ||
1586 | union iwreq_data *wrqu, char *extra) | ||
1587 | { | ||
1588 | struct wl3501_card *this = dev->priv; | ||
1589 | |||
1590 | wrqu->mode = this->net_type; | ||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, | ||
1595 | union iwreq_data *wrqu, char *extra) | ||
1596 | { | ||
1597 | struct wl3501_card *this = dev->priv; | ||
1598 | |||
1599 | wrqu->sens.value = this->rssi; | ||
1600 | wrqu->sens.disabled = !wrqu->sens.value; | ||
1601 | wrqu->sens.fixed = 1; | ||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1605 | static int wl3501_get_range(struct net_device *dev, | ||
1606 | struct iw_request_info *info, | ||
1607 | union iwreq_data *wrqu, char *extra) | ||
1608 | { | ||
1609 | struct iw_range *range = (struct iw_range *)extra; | ||
1610 | |||
1611 | /* Set the length (very important for backward compatibility) */ | ||
1612 | wrqu->data.length = sizeof(*range); | ||
1613 | |||
1614 | /* Set all the info we don't care or don't know about to zero */ | ||
1615 | memset(range, 0, sizeof(*range)); | ||
1616 | |||
1617 | /* Set the Wireless Extension versions */ | ||
1618 | range->we_version_compiled = WIRELESS_EXT; | ||
1619 | range->we_version_source = 1; | ||
1620 | range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ | ||
1621 | /* FIXME: study the code to fill in more fields... */ | ||
1622 | return 0; | ||
1623 | } | ||
1624 | |||
1625 | static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, | ||
1626 | union iwreq_data *wrqu, char *extra) | ||
1627 | { | ||
1628 | struct wl3501_card *this = dev->priv; | ||
1629 | static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; | ||
1630 | int rc = -EINVAL; | ||
1631 | |||
1632 | /* FIXME: we support other ARPHRDs...*/ | ||
1633 | if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) | ||
1634 | goto out; | ||
1635 | if (!memcmp(bcast, wrqu->ap_addr.sa_data, ETH_ALEN)) { | ||
1636 | /* FIXME: rescan? */ | ||
1637 | } else | ||
1638 | memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); | ||
1639 | /* FIXME: rescan? deassoc & scan? */ | ||
1640 | rc = 0; | ||
1641 | out: | ||
1642 | return rc; | ||
1643 | } | ||
1644 | |||
1645 | static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, | ||
1646 | union iwreq_data *wrqu, char *extra) | ||
1647 | { | ||
1648 | struct wl3501_card *this = dev->priv; | ||
1649 | |||
1650 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | ||
1651 | memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); | ||
1652 | return 0; | ||
1653 | } | ||
1654 | |||
1655 | static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, | ||
1656 | union iwreq_data *wrqu, char *extra) | ||
1657 | { | ||
1658 | /* | ||
1659 | * FIXME: trigger scanning with a reset, yes, I'm lazy | ||
1660 | */ | ||
1661 | return wl3501_reset(dev); | ||
1662 | } | ||
1663 | |||
1664 | static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
1665 | union iwreq_data *wrqu, char *extra) | ||
1666 | { | ||
1667 | struct wl3501_card *this = dev->priv; | ||
1668 | int i; | ||
1669 | char *current_ev = extra; | ||
1670 | struct iw_event iwe; | ||
1671 | |||
1672 | for (i = 0; i < this->bss_cnt; ++i) { | ||
1673 | iwe.cmd = SIOCGIWAP; | ||
1674 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1675 | memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN); | ||
1676 | current_ev = iwe_stream_add_event(current_ev, | ||
1677 | extra + IW_SCAN_MAX_DATA, | ||
1678 | &iwe, IW_EV_ADDR_LEN); | ||
1679 | iwe.cmd = SIOCGIWESSID; | ||
1680 | iwe.u.data.flags = 1; | ||
1681 | iwe.u.data.length = this->bss_set[i].ssid.el.len; | ||
1682 | current_ev = iwe_stream_add_point(current_ev, | ||
1683 | extra + IW_SCAN_MAX_DATA, | ||
1684 | &iwe, | ||
1685 | this->bss_set[i].ssid.essid); | ||
1686 | iwe.cmd = SIOCGIWMODE; | ||
1687 | iwe.u.mode = this->bss_set[i].bss_type; | ||
1688 | current_ev = iwe_stream_add_event(current_ev, | ||
1689 | extra + IW_SCAN_MAX_DATA, | ||
1690 | &iwe, IW_EV_UINT_LEN); | ||
1691 | iwe.cmd = SIOCGIWFREQ; | ||
1692 | iwe.u.freq.m = this->bss_set[i].ds_pset.chan; | ||
1693 | iwe.u.freq.e = 0; | ||
1694 | current_ev = iwe_stream_add_event(current_ev, | ||
1695 | extra + IW_SCAN_MAX_DATA, | ||
1696 | &iwe, IW_EV_FREQ_LEN); | ||
1697 | iwe.cmd = SIOCGIWENCODE; | ||
1698 | if (this->bss_set[i].cap_info & WL3501_MGMT_CAPABILITY_PRIVACY) | ||
1699 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1700 | else | ||
1701 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1702 | iwe.u.data.length = 0; | ||
1703 | current_ev = iwe_stream_add_point(current_ev, | ||
1704 | extra + IW_SCAN_MAX_DATA, | ||
1705 | &iwe, NULL); | ||
1706 | } | ||
1707 | /* Length of data */ | ||
1708 | wrqu->data.length = (current_ev - extra); | ||
1709 | wrqu->data.flags = 0; /* FIXME: set properly these flags */ | ||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1713 | static int wl3501_set_essid(struct net_device *dev, | ||
1714 | struct iw_request_info *info, | ||
1715 | union iwreq_data *wrqu, char *extra) | ||
1716 | { | ||
1717 | struct wl3501_card *this = dev->priv; | ||
1718 | |||
1719 | if (wrqu->data.flags) { | ||
1720 | iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, | ||
1721 | &this->essid.el, | ||
1722 | extra, wrqu->data.length); | ||
1723 | } else { /* We accept any ESSID */ | ||
1724 | iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, | ||
1725 | &this->essid.el, "ANY", 3); | ||
1726 | } | ||
1727 | return wl3501_reset(dev); | ||
1728 | } | ||
1729 | |||
1730 | static int wl3501_get_essid(struct net_device *dev, | ||
1731 | struct iw_request_info *info, | ||
1732 | union iwreq_data *wrqu, char *extra) | ||
1733 | { | ||
1734 | struct wl3501_card *this = dev->priv; | ||
1735 | unsigned long flags; | ||
1736 | |||
1737 | spin_lock_irqsave(&this->lock, flags); | ||
1738 | wrqu->essid.flags = 1; | ||
1739 | wrqu->essid.length = this->essid.el.len; | ||
1740 | memcpy(extra, this->essid.essid, this->essid.el.len); | ||
1741 | spin_unlock_irqrestore(&this->lock, flags); | ||
1742 | return 0; | ||
1743 | } | ||
1744 | |||
1745 | static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, | ||
1746 | union iwreq_data *wrqu, char *extra) | ||
1747 | { | ||
1748 | struct wl3501_card *this = dev->priv; | ||
1749 | |||
1750 | if (wrqu->data.length > sizeof(this->nick)) | ||
1751 | return -E2BIG; | ||
1752 | strlcpy(this->nick, extra, wrqu->data.length); | ||
1753 | return 0; | ||
1754 | } | ||
1755 | |||
1756 | static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, | ||
1757 | union iwreq_data *wrqu, char *extra) | ||
1758 | { | ||
1759 | struct wl3501_card *this = dev->priv; | ||
1760 | |||
1761 | strlcpy(extra, this->nick, 32); | ||
1762 | wrqu->data.length = strlen(extra); | ||
1763 | return 0; | ||
1764 | } | ||
1765 | |||
1766 | static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, | ||
1767 | union iwreq_data *wrqu, char *extra) | ||
1768 | { | ||
1769 | /* | ||
1770 | * FIXME: have to see from where to get this info, perhaps this card | ||
1771 | * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most | ||
1772 | * common with the Planet Access Points. -acme | ||
1773 | */ | ||
1774 | wrqu->bitrate.value = 2000000; | ||
1775 | wrqu->bitrate.fixed = 1; | ||
1776 | return 0; | ||
1777 | } | ||
1778 | |||
1779 | static int wl3501_get_rts_threshold(struct net_device *dev, | ||
1780 | struct iw_request_info *info, | ||
1781 | union iwreq_data *wrqu, char *extra) | ||
1782 | { | ||
1783 | u16 threshold; /* size checked: it is u16 */ | ||
1784 | struct wl3501_card *this = dev->priv; | ||
1785 | int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, | ||
1786 | &threshold, sizeof(threshold)); | ||
1787 | if (!rc) { | ||
1788 | wrqu->rts.value = threshold; | ||
1789 | wrqu->rts.disabled = threshold >= 2347; | ||
1790 | wrqu->rts.fixed = 1; | ||
1791 | } | ||
1792 | return rc; | ||
1793 | } | ||
1794 | |||
1795 | static int wl3501_get_frag_threshold(struct net_device *dev, | ||
1796 | struct iw_request_info *info, | ||
1797 | union iwreq_data *wrqu, char *extra) | ||
1798 | { | ||
1799 | u16 threshold; /* size checked: it is u16 */ | ||
1800 | struct wl3501_card *this = dev->priv; | ||
1801 | int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, | ||
1802 | &threshold, sizeof(threshold)); | ||
1803 | if (!rc) { | ||
1804 | wrqu->frag.value = threshold; | ||
1805 | wrqu->frag.disabled = threshold >= 2346; | ||
1806 | wrqu->frag.fixed = 1; | ||
1807 | } | ||
1808 | return rc; | ||
1809 | } | ||
1810 | |||
1811 | static int wl3501_get_txpow(struct net_device *dev, | ||
1812 | struct iw_request_info *info, | ||
1813 | union iwreq_data *wrqu, char *extra) | ||
1814 | { | ||
1815 | u16 txpow; | ||
1816 | struct wl3501_card *this = dev->priv; | ||
1817 | int rc = wl3501_get_mib_value(this, | ||
1818 | WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, | ||
1819 | &txpow, sizeof(txpow)); | ||
1820 | if (!rc) { | ||
1821 | wrqu->txpower.value = txpow; | ||
1822 | wrqu->txpower.disabled = 0; | ||
1823 | /* | ||
1824 | * From the MIB values I think this can be configurable, | ||
1825 | * as it lists several tx power levels -acme | ||
1826 | */ | ||
1827 | wrqu->txpower.fixed = 0; | ||
1828 | wrqu->txpower.flags = IW_TXPOW_MWATT; | ||
1829 | } | ||
1830 | return rc; | ||
1831 | } | ||
1832 | |||
1833 | static int wl3501_get_retry(struct net_device *dev, | ||
1834 | struct iw_request_info *info, | ||
1835 | union iwreq_data *wrqu, char *extra) | ||
1836 | { | ||
1837 | u8 retry; /* size checked: it is u8 */ | ||
1838 | struct wl3501_card *this = dev->priv; | ||
1839 | int rc = wl3501_get_mib_value(this, | ||
1840 | WL3501_MIB_ATTR_LONG_RETRY_LIMIT, | ||
1841 | &retry, sizeof(retry)); | ||
1842 | if (rc) | ||
1843 | goto out; | ||
1844 | if (wrqu->retry.flags & IW_RETRY_MAX) { | ||
1845 | wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
1846 | goto set_value; | ||
1847 | } | ||
1848 | rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, | ||
1849 | &retry, sizeof(retry)); | ||
1850 | if (rc) | ||
1851 | goto out; | ||
1852 | wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; | ||
1853 | set_value: | ||
1854 | wrqu->retry.value = retry; | ||
1855 | wrqu->retry.disabled = 0; | ||
1856 | out: | ||
1857 | return rc; | ||
1858 | } | ||
1859 | |||
1860 | static int wl3501_get_encode(struct net_device *dev, | ||
1861 | struct iw_request_info *info, | ||
1862 | union iwreq_data *wrqu, char *extra) | ||
1863 | { | ||
1864 | u8 implemented, restricted, keys[100], len_keys, tocopy; | ||
1865 | struct wl3501_card *this = dev->priv; | ||
1866 | int rc = wl3501_get_mib_value(this, | ||
1867 | WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, | ||
1868 | &implemented, sizeof(implemented)); | ||
1869 | if (rc) | ||
1870 | goto out; | ||
1871 | if (!implemented) { | ||
1872 | wrqu->encoding.flags = IW_ENCODE_DISABLED; | ||
1873 | goto out; | ||
1874 | } | ||
1875 | rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, | ||
1876 | &restricted, sizeof(restricted)); | ||
1877 | if (rc) | ||
1878 | goto out; | ||
1879 | wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : | ||
1880 | IW_ENCODE_OPEN; | ||
1881 | rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, | ||
1882 | &len_keys, sizeof(len_keys)); | ||
1883 | if (rc) | ||
1884 | goto out; | ||
1885 | rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, | ||
1886 | keys, len_keys); | ||
1887 | if (rc) | ||
1888 | goto out; | ||
1889 | tocopy = min_t(u8, len_keys, wrqu->encoding.length); | ||
1890 | tocopy = min_t(u8, tocopy, 100); | ||
1891 | wrqu->encoding.length = tocopy; | ||
1892 | memset(extra, 0, tocopy); | ||
1893 | memcpy(extra, keys, tocopy); | ||
1894 | out: | ||
1895 | return rc; | ||
1896 | } | ||
1897 | |||
1898 | static int wl3501_get_power(struct net_device *dev, | ||
1899 | struct iw_request_info *info, | ||
1900 | union iwreq_data *wrqu, char *extra) | ||
1901 | { | ||
1902 | u8 pwr_state; | ||
1903 | struct wl3501_card *this = dev->priv; | ||
1904 | int rc = wl3501_get_mib_value(this, | ||
1905 | WL3501_MIB_ATTR_CURRENT_PWR_STATE, | ||
1906 | &pwr_state, sizeof(pwr_state)); | ||
1907 | if (rc) | ||
1908 | goto out; | ||
1909 | wrqu->power.disabled = !pwr_state; | ||
1910 | wrqu->power.flags = IW_POWER_ON; | ||
1911 | out: | ||
1912 | return rc; | ||
1913 | } | ||
1914 | |||
1915 | static const iw_handler wl3501_handler[] = { | ||
1916 | [SIOCGIWNAME - SIOCIWFIRST] = wl3501_get_name, | ||
1917 | [SIOCSIWFREQ - SIOCIWFIRST] = wl3501_set_freq, | ||
1918 | [SIOCGIWFREQ - SIOCIWFIRST] = wl3501_get_freq, | ||
1919 | [SIOCSIWMODE - SIOCIWFIRST] = wl3501_set_mode, | ||
1920 | [SIOCGIWMODE - SIOCIWFIRST] = wl3501_get_mode, | ||
1921 | [SIOCGIWSENS - SIOCIWFIRST] = wl3501_get_sens, | ||
1922 | [SIOCGIWRANGE - SIOCIWFIRST] = wl3501_get_range, | ||
1923 | [SIOCSIWSPY - SIOCIWFIRST] = iw_handler_set_spy, | ||
1924 | [SIOCGIWSPY - SIOCIWFIRST] = iw_handler_get_spy, | ||
1925 | [SIOCSIWTHRSPY - SIOCIWFIRST] = iw_handler_set_thrspy, | ||
1926 | [SIOCGIWTHRSPY - SIOCIWFIRST] = iw_handler_get_thrspy, | ||
1927 | [SIOCSIWAP - SIOCIWFIRST] = wl3501_set_wap, | ||
1928 | [SIOCGIWAP - SIOCIWFIRST] = wl3501_get_wap, | ||
1929 | [SIOCSIWSCAN - SIOCIWFIRST] = wl3501_set_scan, | ||
1930 | [SIOCGIWSCAN - SIOCIWFIRST] = wl3501_get_scan, | ||
1931 | [SIOCSIWESSID - SIOCIWFIRST] = wl3501_set_essid, | ||
1932 | [SIOCGIWESSID - SIOCIWFIRST] = wl3501_get_essid, | ||
1933 | [SIOCSIWNICKN - SIOCIWFIRST] = wl3501_set_nick, | ||
1934 | [SIOCGIWNICKN - SIOCIWFIRST] = wl3501_get_nick, | ||
1935 | [SIOCGIWRATE - SIOCIWFIRST] = wl3501_get_rate, | ||
1936 | [SIOCGIWRTS - SIOCIWFIRST] = wl3501_get_rts_threshold, | ||
1937 | [SIOCGIWFRAG - SIOCIWFIRST] = wl3501_get_frag_threshold, | ||
1938 | [SIOCGIWTXPOW - SIOCIWFIRST] = wl3501_get_txpow, | ||
1939 | [SIOCGIWRETRY - SIOCIWFIRST] = wl3501_get_retry, | ||
1940 | [SIOCGIWENCODE - SIOCIWFIRST] = wl3501_get_encode, | ||
1941 | [SIOCGIWPOWER - SIOCIWFIRST] = wl3501_get_power, | ||
1942 | }; | ||
1943 | |||
1944 | static const struct iw_handler_def wl3501_handler_def = { | ||
1945 | .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler), | ||
1946 | .standard = (iw_handler *)wl3501_handler, | ||
1947 | .spy_offset = offsetof(struct wl3501_card, spy_data), | ||
1948 | }; | ||
1949 | |||
1950 | /** | ||
1951 | * wl3501_attach - creates an "instance" of the driver | ||
1952 | * | ||
1953 | * Creates an "instance" of the driver, allocating local data structures for | ||
1954 | * one device. The device is registered with Card Services. | ||
1955 | * | ||
1956 | * The dev_link structure is initialized, but we don't actually configure the | ||
1957 | * card at this point -- we wait until we receive a card insertion event. | ||
1958 | */ | ||
1959 | static dev_link_t *wl3501_attach(void) | ||
1960 | { | ||
1961 | client_reg_t client_reg; | ||
1962 | dev_link_t *link; | ||
1963 | struct net_device *dev; | ||
1964 | int ret; | ||
1965 | |||
1966 | /* Initialize the dev_link_t structure */ | ||
1967 | link = kmalloc(sizeof(*link), GFP_KERNEL); | ||
1968 | if (!link) | ||
1969 | goto out; | ||
1970 | memset(link, 0, sizeof(struct dev_link_t)); | ||
1971 | |||
1972 | /* The io structure describes IO port mapping */ | ||
1973 | link->io.NumPorts1 = 16; | ||
1974 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
1975 | link->io.IOAddrLines = 5; | ||
1976 | |||
1977 | /* Interrupt setup */ | ||
1978 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
1979 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
1980 | link->irq.Handler = wl3501_interrupt; | ||
1981 | |||
1982 | /* General socket configuration */ | ||
1983 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
1984 | link->conf.Vcc = 50; | ||
1985 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
1986 | link->conf.ConfigIndex = 1; | ||
1987 | link->conf.Present = PRESENT_OPTION; | ||
1988 | |||
1989 | dev = alloc_etherdev(sizeof(struct wl3501_card)); | ||
1990 | if (!dev) | ||
1991 | goto out_link; | ||
1992 | dev->open = wl3501_open; | ||
1993 | dev->stop = wl3501_close; | ||
1994 | dev->hard_start_xmit = wl3501_hard_start_xmit; | ||
1995 | dev->tx_timeout = wl3501_tx_timeout; | ||
1996 | dev->watchdog_timeo = 5 * HZ; | ||
1997 | dev->get_stats = wl3501_get_stats; | ||
1998 | dev->get_wireless_stats = wl3501_get_wireless_stats; | ||
1999 | dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def; | ||
2000 | SET_ETHTOOL_OPS(dev, &ops); | ||
2001 | netif_stop_queue(dev); | ||
2002 | link->priv = link->irq.Instance = dev; | ||
2003 | |||
2004 | /* Register with Card Services */ | ||
2005 | link->next = wl3501_dev_list; | ||
2006 | wl3501_dev_list = link; | ||
2007 | client_reg.dev_info = &wl3501_dev_info; | ||
2008 | client_reg.EventMask = CS_EVENT_CARD_INSERTION | | ||
2009 | CS_EVENT_RESET_PHYSICAL | | ||
2010 | CS_EVENT_CARD_RESET | | ||
2011 | CS_EVENT_CARD_REMOVAL | | ||
2012 | CS_EVENT_PM_SUSPEND | | ||
2013 | CS_EVENT_PM_RESUME; | ||
2014 | client_reg.event_handler = wl3501_event; | ||
2015 | client_reg.Version = 0x0210; | ||
2016 | client_reg.event_callback_args.client_data = link; | ||
2017 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
2018 | if (ret) { | ||
2019 | cs_error(link->handle, RegisterClient, ret); | ||
2020 | wl3501_detach(link); | ||
2021 | link = NULL; | ||
2022 | } | ||
2023 | out: | ||
2024 | return link; | ||
2025 | out_link: | ||
2026 | kfree(link); | ||
2027 | link = NULL; | ||
2028 | goto out; | ||
2029 | } | ||
2030 | |||
2031 | #define CS_CHECK(fn, ret) \ | ||
2032 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
2033 | |||
2034 | /** | ||
2035 | * wl3501_config - configure the PCMCIA socket and make eth device available | ||
2036 | * @link - FILL_IN | ||
2037 | * | ||
2038 | * wl3501_config() is scheduled to run after a CARD_INSERTION event is | ||
2039 | * received, to configure the PCMCIA socket, and to make the ethernet device | ||
2040 | * available to the system. | ||
2041 | */ | ||
2042 | static void wl3501_config(dev_link_t *link) | ||
2043 | { | ||
2044 | tuple_t tuple; | ||
2045 | cisparse_t parse; | ||
2046 | client_handle_t handle = link->handle; | ||
2047 | struct net_device *dev = link->priv; | ||
2048 | int i = 0, j, last_fn, last_ret; | ||
2049 | unsigned char bf[64]; | ||
2050 | struct wl3501_card *this; | ||
2051 | |||
2052 | /* This reads the card's CONFIG tuple to find its config registers. */ | ||
2053 | tuple.Attributes = 0; | ||
2054 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
2055 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
2056 | tuple.TupleData = bf; | ||
2057 | tuple.TupleDataMax = sizeof(bf); | ||
2058 | tuple.TupleOffset = 0; | ||
2059 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
2060 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
2061 | link->conf.ConfigBase = parse.config.base; | ||
2062 | link->conf.Present = parse.config.rmask[0]; | ||
2063 | |||
2064 | /* Configure card */ | ||
2065 | link->state |= DEV_CONFIG; | ||
2066 | |||
2067 | /* Try allocating IO ports. This tries a few fixed addresses. If you | ||
2068 | * want, you can also read the card's config table to pick addresses -- | ||
2069 | * see the serial driver for an example. */ | ||
2070 | |||
2071 | for (j = 0x280; j < 0x400; j += 0x20) { | ||
2072 | /* The '^0x300' is so that we probe 0x300-0x3ff first, then | ||
2073 | * 0x200-0x2ff, and so on, because this seems safer */ | ||
2074 | link->io.BasePort1 = j; | ||
2075 | link->io.BasePort2 = link->io.BasePort1 + 0x10; | ||
2076 | i = pcmcia_request_io(link->handle, &link->io); | ||
2077 | if (i == CS_SUCCESS) | ||
2078 | break; | ||
2079 | } | ||
2080 | if (i != CS_SUCCESS) { | ||
2081 | cs_error(link->handle, RequestIO, i); | ||
2082 | goto failed; | ||
2083 | } | ||
2084 | |||
2085 | /* Now allocate an interrupt line. Note that this does not actually | ||
2086 | * assign a handler to the interrupt. */ | ||
2087 | |||
2088 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
2089 | |||
2090 | /* This actually configures the PCMCIA socket -- setting up the I/O | ||
2091 | * windows and the interrupt mapping. */ | ||
2092 | |||
2093 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
2094 | |||
2095 | dev->irq = link->irq.AssignedIRQ; | ||
2096 | dev->base_addr = link->io.BasePort1; | ||
2097 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
2098 | if (register_netdev(dev)) { | ||
2099 | printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); | ||
2100 | goto failed; | ||
2101 | } | ||
2102 | |||
2103 | SET_MODULE_OWNER(dev); | ||
2104 | |||
2105 | this = dev->priv; | ||
2106 | /* | ||
2107 | * At this point, the dev_node_t structure(s) should be initialized and | ||
2108 | * arranged in a linked list at link->dev. | ||
2109 | */ | ||
2110 | link->dev = &this->node; | ||
2111 | link->state &= ~DEV_CONFIG_PENDING; | ||
2112 | |||
2113 | this->base_addr = dev->base_addr; | ||
2114 | |||
2115 | if (!wl3501_get_flash_mac_addr(this)) { | ||
2116 | printk(KERN_WARNING "%s: Cant read MAC addr in flash ROM?\n", | ||
2117 | dev->name); | ||
2118 | goto failed; | ||
2119 | } | ||
2120 | strcpy(this->node.dev_name, dev->name); | ||
2121 | |||
2122 | /* print probe information */ | ||
2123 | printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:", | ||
2124 | dev->name, this->base_addr, (int)dev->irq); | ||
2125 | for (i = 0; i < 6; i++) { | ||
2126 | dev->dev_addr[i] = ((char *)&this->mac_addr)[i]; | ||
2127 | printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); | ||
2128 | } | ||
2129 | printk("\n"); | ||
2130 | /* | ||
2131 | * Initialize card parameters - added by jss | ||
2132 | */ | ||
2133 | this->net_type = IW_MODE_INFRA; | ||
2134 | this->bss_cnt = 0; | ||
2135 | this->join_sta_bss = 0; | ||
2136 | this->adhoc_times = 0; | ||
2137 | iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, | ||
2138 | "ANY", 3); | ||
2139 | this->card_name[0] = '\0'; | ||
2140 | this->firmware_date[0] = '\0'; | ||
2141 | this->rssi = 255; | ||
2142 | this->chan = iw_default_channel(this->reg_domain); | ||
2143 | strlcpy(this->nick, "Planet WL3501", sizeof(this->nick)); | ||
2144 | spin_lock_init(&this->lock); | ||
2145 | init_waitqueue_head(&this->wait); | ||
2146 | netif_start_queue(dev); | ||
2147 | goto out; | ||
2148 | cs_failed: | ||
2149 | cs_error(link->handle, last_fn, last_ret); | ||
2150 | failed: | ||
2151 | wl3501_release(link); | ||
2152 | out: | ||
2153 | return; | ||
2154 | } | ||
2155 | |||
2156 | /** | ||
2157 | * wl3501_release - unregister the net, release PCMCIA configuration | ||
2158 | * @arg - link | ||
2159 | * | ||
2160 | * After a card is removed, wl3501_release() will unregister the net device, | ||
2161 | * and release the PCMCIA configuration. If the device is still open, this | ||
2162 | * will be postponed until it is closed. | ||
2163 | */ | ||
2164 | static void wl3501_release(dev_link_t *link) | ||
2165 | { | ||
2166 | struct net_device *dev = link->priv; | ||
2167 | |||
2168 | /* Unlink the device chain */ | ||
2169 | if (link->dev) { | ||
2170 | unregister_netdev(dev); | ||
2171 | link->dev = NULL; | ||
2172 | } | ||
2173 | |||
2174 | /* Don't bother checking to see if these succeed or not */ | ||
2175 | pcmcia_release_configuration(link->handle); | ||
2176 | pcmcia_release_io(link->handle, &link->io); | ||
2177 | pcmcia_release_irq(link->handle, &link->irq); | ||
2178 | link->state &= ~DEV_CONFIG; | ||
2179 | } | ||
2180 | |||
2181 | /** | ||
2182 | * wl3501_event - The card status event handler | ||
2183 | * @event - event | ||
2184 | * @pri - priority | ||
2185 | * @args - arguments for this event | ||
2186 | * | ||
2187 | * The card status event handler. Mostly, this schedules other stuff to run | ||
2188 | * after an event is received. A CARD_REMOVAL event also sets some flags to | ||
2189 | * discourage the net drivers from trying to talk to the card any more. | ||
2190 | * | ||
2191 | * When a CARD_REMOVAL event is received, we immediately set a flag to block | ||
2192 | * future accesses to this device. All the functions that actually access the | ||
2193 | * device should check this flag to make sure the card is still present. | ||
2194 | */ | ||
2195 | static int wl3501_event(event_t event, int pri, event_callback_args_t *args) | ||
2196 | { | ||
2197 | dev_link_t *link = args->client_data; | ||
2198 | struct net_device *dev = link->priv; | ||
2199 | |||
2200 | switch (event) { | ||
2201 | case CS_EVENT_CARD_REMOVAL: | ||
2202 | link->state &= ~DEV_PRESENT; | ||
2203 | if (link->state & DEV_CONFIG) { | ||
2204 | while (link->open > 0) | ||
2205 | wl3501_close(dev); | ||
2206 | netif_device_detach(dev); | ||
2207 | wl3501_release(link); | ||
2208 | } | ||
2209 | break; | ||
2210 | case CS_EVENT_CARD_INSERTION: | ||
2211 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
2212 | wl3501_config(link); | ||
2213 | break; | ||
2214 | case CS_EVENT_PM_SUSPEND: | ||
2215 | link->state |= DEV_SUSPEND; | ||
2216 | wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); | ||
2217 | /* Fall through... */ | ||
2218 | case CS_EVENT_RESET_PHYSICAL: | ||
2219 | if (link->state & DEV_CONFIG) { | ||
2220 | if (link->open) | ||
2221 | netif_device_detach(dev); | ||
2222 | pcmcia_release_configuration(link->handle); | ||
2223 | } | ||
2224 | break; | ||
2225 | case CS_EVENT_PM_RESUME: | ||
2226 | link->state &= ~DEV_SUSPEND; | ||
2227 | wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); | ||
2228 | /* Fall through... */ | ||
2229 | case CS_EVENT_CARD_RESET: | ||
2230 | if (link->state & DEV_CONFIG) { | ||
2231 | pcmcia_request_configuration(link->handle, &link->conf); | ||
2232 | if (link->open) { | ||
2233 | wl3501_reset(dev); | ||
2234 | netif_device_attach(dev); | ||
2235 | } | ||
2236 | } | ||
2237 | break; | ||
2238 | } | ||
2239 | return 0; | ||
2240 | } | ||
2241 | |||
2242 | static struct pcmcia_driver wl3501_driver = { | ||
2243 | .owner = THIS_MODULE, | ||
2244 | .drv = { | ||
2245 | .name = "wl3501_cs", | ||
2246 | }, | ||
2247 | .attach = wl3501_attach, | ||
2248 | .detach = wl3501_detach, | ||
2249 | }; | ||
2250 | |||
2251 | static int __init wl3501_init_module(void) | ||
2252 | { | ||
2253 | return pcmcia_register_driver(&wl3501_driver); | ||
2254 | } | ||
2255 | |||
2256 | static void __exit wl3501_exit_module(void) | ||
2257 | { | ||
2258 | dprintk(0, ": unloading"); | ||
2259 | pcmcia_unregister_driver(&wl3501_driver); | ||
2260 | BUG_ON(wl3501_dev_list != NULL); | ||
2261 | } | ||
2262 | |||
2263 | module_init(wl3501_init_module); | ||
2264 | module_exit(wl3501_exit_module); | ||
2265 | |||
2266 | MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, " | ||
2267 | "Arnaldo Carvalho de Melo <acme@conectiva.com.br>," | ||
2268 | "Gustavo Niemeyer <niemeyer@conectiva.com>"); | ||
2269 | MODULE_DESCRIPTION("Planet wl3501 wireless driver"); | ||
2270 | MODULE_LICENSE("GPL"); | ||