diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/Kconfig | 39 | ||||
-rw-r--r-- | drivers/net/wireless/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/i82586.h | 413 | ||||
-rw-r--r-- | drivers/net/wireless/i82593.h | 229 | ||||
-rw-r--r-- | drivers/net/wireless/wavelan.c | 4383 | ||||
-rw-r--r-- | drivers/net/wireless/wavelan.h | 370 | ||||
-rw-r--r-- | drivers/net/wireless/wavelan.p.h | 696 | ||||
-rw-r--r-- | drivers/net/wireless/wavelan_cs.c | 4635 | ||||
-rw-r--r-- | drivers/net/wireless/wavelan_cs.h | 386 | ||||
-rw-r--r-- | drivers/net/wireless/wavelan_cs.p.h | 766 |
10 files changed, 0 insertions, 11919 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index d50b3bee9a9b..f94188f05a02 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -25,45 +25,6 @@ menuconfig WLAN_PRE80211 | |||
25 | This option does not affect the kernel build, it only | 25 | This option does not affect the kernel build, it only |
26 | lets you choose drivers. | 26 | lets you choose drivers. |
27 | 27 | ||
28 | config WAVELAN | ||
29 | tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" | ||
30 | depends on ISA && WLAN_PRE80211 | ||
31 | select WIRELESS_EXT | ||
32 | select WEXT_SPY | ||
33 | select WEXT_PRIV | ||
34 | ---help--- | ||
35 | The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is | ||
36 | a Radio LAN (wireless Ethernet-like Local Area Network) using the | ||
37 | radio frequencies 900 MHz and 2.4 GHz. | ||
38 | |||
39 | If you want to use an ISA WaveLAN card under Linux, say Y and read | ||
40 | the Ethernet-HOWTO, available from | ||
41 | <http://www.tldp.org/docs.html#howto>. Some more specific | ||
42 | information is contained in | ||
43 | <file:Documentation/networking/wavelan.txt> and in the source code | ||
44 | <file:drivers/net/wireless/wavelan.p.h>. | ||
45 | |||
46 | You will also need the wireless tools package available from | ||
47 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. | ||
48 | Please read the man pages contained therein. | ||
49 | |||
50 | To compile this driver as a module, choose M here: the module will be | ||
51 | called wavelan. | ||
52 | |||
53 | config PCMCIA_WAVELAN | ||
54 | tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" | ||
55 | depends on PCMCIA && WLAN_PRE80211 | ||
56 | select WIRELESS_EXT | ||
57 | select WEXT_SPY | ||
58 | select WEXT_PRIV | ||
59 | help | ||
60 | Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA | ||
61 | (PC-card) wireless Ethernet networking card to your computer. This | ||
62 | driver is for the non-IEEE-802.11 Wavelan cards. | ||
63 | |||
64 | To compile this driver as a module, choose M here: the module will be | ||
65 | called wavelan_cs. If unsure, say N. | ||
66 | |||
67 | config PCMCIA_NETWAVE | 28 | config PCMCIA_NETWAVE |
68 | tristate "Xircom Netwave AirSurfer Pcmcia wireless support" | 29 | tristate "Xircom Netwave AirSurfer Pcmcia wireless support" |
69 | depends on PCMCIA && WLAN_PRE80211 | 30 | depends on PCMCIA && WLAN_PRE80211 |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index b56c70f4ca75..f4a7c8ae27ea 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -6,9 +6,7 @@ obj-$(CONFIG_IPW2100) += ipw2x00/ | |||
6 | obj-$(CONFIG_IPW2200) += ipw2x00/ | 6 | obj-$(CONFIG_IPW2200) += ipw2x00/ |
7 | 7 | ||
8 | # Obsolete cards | 8 | # Obsolete cards |
9 | obj-$(CONFIG_WAVELAN) += wavelan.o | ||
10 | obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o | 9 | obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o |
11 | obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o | ||
12 | 10 | ||
13 | obj-$(CONFIG_HERMES) += orinoco/ | 11 | obj-$(CONFIG_HERMES) += orinoco/ |
14 | 12 | ||
diff --git a/drivers/net/wireless/i82586.h b/drivers/net/wireless/i82586.h deleted file mode 100644 index 5f65b250646f..000000000000 --- a/drivers/net/wireless/i82586.h +++ /dev/null | |||
@@ -1,413 +0,0 @@ | |||
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 deleted file mode 100644 index afac5c7a323d..000000000000 --- a/drivers/net/wireless/i82593.h +++ /dev/null | |||
@@ -1,229 +0,0 @@ | |||
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 | * HISTORY | ||
11 | * i82593.h,v | ||
12 | * Revision 1.4 2005/11/4 09:15:00 baroniunas | ||
13 | * Modified copyright with permission of author as follows: | ||
14 | * | ||
15 | * "If I82539.H is the only file with my copyright statement | ||
16 | * that is included in the Source Forge project, then you have | ||
17 | * my approval to change the copyright statement to be a GPL | ||
18 | * license, in the way you proposed on October 10." | ||
19 | * | ||
20 | * Revision 1.1 1996/07/17 15:23:12 root | ||
21 | * Initial revision | ||
22 | * | ||
23 | * Revision 1.3 1995/04/05 15:13:58 adj | ||
24 | * Initial alpha release | ||
25 | * | ||
26 | * Revision 1.2 1994/06/16 23:57:31 klemets | ||
27 | * Mirrored all the fields in the configuration block. | ||
28 | * | ||
29 | * Revision 1.1 1994/06/02 20:25:34 klemets | ||
30 | * Initial revision | ||
31 | * | ||
32 | * | ||
33 | */ | ||
34 | #ifndef _I82593_H | ||
35 | #define _I82593_H | ||
36 | |||
37 | /* Intel 82593 CSMA/CD Core LAN Controller */ | ||
38 | |||
39 | /* Port 0 Command Register definitions */ | ||
40 | |||
41 | /* Execution operations */ | ||
42 | #define OP0_NOP 0 /* CHNL = 0 */ | ||
43 | #define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ | ||
44 | #define OP0_IA_SETUP 1 | ||
45 | #define OP0_CONFIGURE 2 | ||
46 | #define OP0_MC_SETUP 3 | ||
47 | #define OP0_TRANSMIT 4 | ||
48 | #define OP0_TDR 5 | ||
49 | #define OP0_DUMP 6 | ||
50 | #define OP0_DIAGNOSE 7 | ||
51 | #define OP0_TRANSMIT_NO_CRC 9 | ||
52 | #define OP0_RETRANSMIT 12 | ||
53 | #define OP0_ABORT 13 | ||
54 | /* Reception operations */ | ||
55 | #define OP0_RCV_ENABLE 8 | ||
56 | #define OP0_RCV_DISABLE 10 | ||
57 | #define OP0_STOP_RCV 11 | ||
58 | /* Status pointer control operations */ | ||
59 | #define OP0_FIX_PTR 15 /* CHNL = 1 */ | ||
60 | #define OP0_RLS_PTR 15 /* CHNL = 0 */ | ||
61 | #define OP0_RESET 14 | ||
62 | |||
63 | #define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ | ||
64 | #define CR0_STATUS_0 0x00 | ||
65 | #define CR0_STATUS_1 0x20 | ||
66 | #define CR0_STATUS_2 0x40 | ||
67 | #define CR0_STATUS_3 0x60 | ||
68 | #define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ | ||
69 | |||
70 | /* Port 0 Status Register definitions */ | ||
71 | |||
72 | #define SR0_NO_RESULT 0 /* dummy */ | ||
73 | #define SR0_EVENT_MASK 0x0f | ||
74 | #define SR0_IA_SETUP_DONE 1 | ||
75 | #define SR0_CONFIGURE_DONE 2 | ||
76 | #define SR0_MC_SETUP_DONE 3 | ||
77 | #define SR0_TRANSMIT_DONE 4 | ||
78 | #define SR0_TDR_DONE 5 | ||
79 | #define SR0_DUMP_DONE 6 | ||
80 | #define SR0_DIAGNOSE_PASSED 7 | ||
81 | #define SR0_TRANSMIT_NO_CRC_DONE 9 | ||
82 | #define SR0_RETRANSMIT_DONE 12 | ||
83 | #define SR0_EXECUTION_ABORTED 13 | ||
84 | #define SR0_END_OF_FRAME 8 | ||
85 | #define SR0_RECEPTION_ABORTED 10 | ||
86 | #define SR0_DIAGNOSE_FAILED 15 | ||
87 | #define SR0_STOP_REG_HIT 11 | ||
88 | |||
89 | #define SR0_CHNL (1 << 4) | ||
90 | #define SR0_EXECUTION (1 << 5) | ||
91 | #define SR0_RECEPTION (1 << 6) | ||
92 | #define SR0_INTERRUPT (1 << 7) | ||
93 | #define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) | ||
94 | |||
95 | #define SR3_EXEC_STATE_MASK 0x03 | ||
96 | #define SR3_EXEC_IDLE 0 | ||
97 | #define SR3_TX_ABORT_IN_PROGRESS 1 | ||
98 | #define SR3_EXEC_ACTIVE 2 | ||
99 | #define SR3_ABORT_IN_PROGRESS 3 | ||
100 | #define SR3_EXEC_CHNL (1 << 2) | ||
101 | #define SR3_STP_ON_NO_RSRC (1 << 3) | ||
102 | #define SR3_RCVING_NO_RSRC (1 << 4) | ||
103 | #define SR3_RCV_STATE_MASK 0x60 | ||
104 | #define SR3_RCV_IDLE 0x00 | ||
105 | #define SR3_RCV_READY 0x20 | ||
106 | #define SR3_RCV_ACTIVE 0x40 | ||
107 | #define SR3_RCV_STOP_IN_PROG 0x60 | ||
108 | #define SR3_RCV_CHNL (1 << 7) | ||
109 | |||
110 | /* Port 1 Command Register definitions */ | ||
111 | |||
112 | #define OP1_NOP 0 | ||
113 | #define OP1_SWIT_TO_PORT_0 1 | ||
114 | #define OP1_INT_DISABLE 2 | ||
115 | #define OP1_INT_ENABLE 3 | ||
116 | #define OP1_SET_TS 5 | ||
117 | #define OP1_RST_TS 7 | ||
118 | #define OP1_POWER_DOWN 8 | ||
119 | #define OP1_RESET_RING_MNGMT 11 | ||
120 | #define OP1_RESET 14 | ||
121 | #define OP1_SEL_RST 15 | ||
122 | |||
123 | #define CR1_STATUS_4 0x00 | ||
124 | #define CR1_STATUS_5 0x20 | ||
125 | #define CR1_STATUS_6 0x40 | ||
126 | #define CR1_STOP_REG_UPDATE (1 << 7) | ||
127 | |||
128 | /* Receive frame status bits */ | ||
129 | |||
130 | #define RX_RCLD (1 << 0) | ||
131 | #define RX_IA_MATCH (1 << 1) | ||
132 | #define RX_NO_AD_MATCH (1 << 2) | ||
133 | #define RX_NO_SFD (1 << 3) | ||
134 | #define RX_SRT_FRM (1 << 7) | ||
135 | #define RX_OVRRUN (1 << 8) | ||
136 | #define RX_ALG_ERR (1 << 10) | ||
137 | #define RX_CRC_ERR (1 << 11) | ||
138 | #define RX_LEN_ERR (1 << 12) | ||
139 | #define RX_RCV_OK (1 << 13) | ||
140 | #define RX_TYP_LEN (1 << 15) | ||
141 | |||
142 | /* Transmit status bits */ | ||
143 | |||
144 | #define TX_NCOL_MASK 0x0f | ||
145 | #define TX_FRTL (1 << 4) | ||
146 | #define TX_MAX_COL (1 << 5) | ||
147 | #define TX_HRT_BEAT (1 << 6) | ||
148 | #define TX_DEFER (1 << 7) | ||
149 | #define TX_UND_RUN (1 << 8) | ||
150 | #define TX_LOST_CTS (1 << 9) | ||
151 | #define TX_LOST_CRS (1 << 10) | ||
152 | #define TX_LTCOL (1 << 11) | ||
153 | #define TX_OK (1 << 13) | ||
154 | #define TX_COLL (1 << 15) | ||
155 | |||
156 | struct i82593_conf_block { | ||
157 | u_char fifo_limit : 4, | ||
158 | forgnesi : 1, | ||
159 | fifo_32 : 1, | ||
160 | d6mod : 1, | ||
161 | throttle_enb : 1; | ||
162 | u_char throttle : 6, | ||
163 | cntrxint : 1, | ||
164 | contin : 1; | ||
165 | u_char addr_len : 3, | ||
166 | acloc : 1, | ||
167 | preamb_len : 2, | ||
168 | loopback : 2; | ||
169 | u_char lin_prio : 3, | ||
170 | tbofstop : 1, | ||
171 | exp_prio : 3, | ||
172 | bof_met : 1; | ||
173 | u_char : 4, | ||
174 | ifrm_spc : 4; | ||
175 | u_char : 5, | ||
176 | slottim_low : 3; | ||
177 | u_char slottim_hi : 3, | ||
178 | : 1, | ||
179 | max_retr : 4; | ||
180 | u_char prmisc : 1, | ||
181 | bc_dis : 1, | ||
182 | : 1, | ||
183 | crs_1 : 1, | ||
184 | nocrc_ins : 1, | ||
185 | crc_1632 : 1, | ||
186 | : 1, | ||
187 | crs_cdt : 1; | ||
188 | u_char cs_filter : 3, | ||
189 | crs_src : 1, | ||
190 | cd_filter : 3, | ||
191 | : 1; | ||
192 | u_char : 2, | ||
193 | min_fr_len : 6; | ||
194 | u_char lng_typ : 1, | ||
195 | lng_fld : 1, | ||
196 | rxcrc_xf : 1, | ||
197 | artx : 1, | ||
198 | sarec : 1, | ||
199 | tx_jabber : 1, /* why is this called max_len in the manual? */ | ||
200 | hash_1 : 1, | ||
201 | lbpkpol : 1; | ||
202 | u_char : 6, | ||
203 | fdx : 1, | ||
204 | : 1; | ||
205 | u_char dummy_6 : 6, /* supposed to be ones */ | ||
206 | mult_ia : 1, | ||
207 | dis_bof : 1; | ||
208 | u_char dummy_1 : 1, /* supposed to be one */ | ||
209 | tx_ifs_retrig : 2, | ||
210 | mc_all : 1, | ||
211 | rcv_mon : 2, | ||
212 | frag_acpt : 1, | ||
213 | tstrttrs : 1; | ||
214 | u_char fretx : 1, | ||
215 | runt_eop : 1, | ||
216 | hw_sw_pin : 1, | ||
217 | big_endn : 1, | ||
218 | syncrqs : 1, | ||
219 | sttlen : 1, | ||
220 | tx_eop : 1, | ||
221 | rx_eop : 1; | ||
222 | u_char rbuf_size : 5, | ||
223 | rcvstop : 1, | ||
224 | : 2; | ||
225 | }; | ||
226 | |||
227 | #define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ | ||
228 | |||
229 | #endif /* _I82593_H */ | ||
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c deleted file mode 100644 index d634b2da3b84..000000000000 --- a/drivers/net/wireless/wavelan.c +++ /dev/null | |||
@@ -1,4383 +0,0 @@ | |||
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 >= ARRAY_SIZE(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 i; | ||
44 | |||
45 | for (i = 0; i < ARRAY_SIZE(irqvals); i++) | ||
46 | if (irqvals[i] == irqval) | ||
47 | return i; | ||
48 | |||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | /********************* HOST ADAPTER SUBROUTINES *********************/ | ||
53 | /* | ||
54 | * Useful subroutines to manage the WaveLAN ISA interface | ||
55 | * | ||
56 | * One major difference with the PCMCIA hardware (except the port mapping) | ||
57 | * is that we have to keep the state of the Host Control Register | ||
58 | * because of the interrupt enable & bus size flags. | ||
59 | */ | ||
60 | |||
61 | /*------------------------------------------------------------------*/ | ||
62 | /* | ||
63 | * Read from card's Host Adaptor Status Register. | ||
64 | */ | ||
65 | static inline u16 hasr_read(unsigned long ioaddr) | ||
66 | { | ||
67 | return (inw(HASR(ioaddr))); | ||
68 | } /* hasr_read */ | ||
69 | |||
70 | /*------------------------------------------------------------------*/ | ||
71 | /* | ||
72 | * Write to card's Host Adapter Command Register. | ||
73 | */ | ||
74 | static inline void hacr_write(unsigned long ioaddr, u16 hacr) | ||
75 | { | ||
76 | outw(hacr, HACR(ioaddr)); | ||
77 | } /* hacr_write */ | ||
78 | |||
79 | /*------------------------------------------------------------------*/ | ||
80 | /* | ||
81 | * Write to card's Host Adapter Command Register. Include a delay for | ||
82 | * those times when it is needed. | ||
83 | */ | ||
84 | static void hacr_write_slow(unsigned long ioaddr, u16 hacr) | ||
85 | { | ||
86 | hacr_write(ioaddr, hacr); | ||
87 | /* delay might only be needed sometimes */ | ||
88 | mdelay(1); | ||
89 | } /* hacr_write_slow */ | ||
90 | |||
91 | /*------------------------------------------------------------------*/ | ||
92 | /* | ||
93 | * Set the channel attention bit. | ||
94 | */ | ||
95 | static inline void set_chan_attn(unsigned long ioaddr, u16 hacr) | ||
96 | { | ||
97 | hacr_write(ioaddr, hacr | HACR_CA); | ||
98 | } /* set_chan_attn */ | ||
99 | |||
100 | /*------------------------------------------------------------------*/ | ||
101 | /* | ||
102 | * Reset, and then set host adaptor into default mode. | ||
103 | */ | ||
104 | static inline void wv_hacr_reset(unsigned long ioaddr) | ||
105 | { | ||
106 | hacr_write_slow(ioaddr, HACR_RESET); | ||
107 | hacr_write(ioaddr, HACR_DEFAULT); | ||
108 | } /* wv_hacr_reset */ | ||
109 | |||
110 | /*------------------------------------------------------------------*/ | ||
111 | /* | ||
112 | * Set the I/O transfer over the ISA bus to 8-bit mode | ||
113 | */ | ||
114 | static inline void wv_16_off(unsigned long ioaddr, u16 hacr) | ||
115 | { | ||
116 | hacr &= ~HACR_16BITS; | ||
117 | hacr_write(ioaddr, hacr); | ||
118 | } /* wv_16_off */ | ||
119 | |||
120 | /*------------------------------------------------------------------*/ | ||
121 | /* | ||
122 | * Set the I/O transfer over the ISA bus to 8-bit mode | ||
123 | */ | ||
124 | static inline void wv_16_on(unsigned long ioaddr, u16 hacr) | ||
125 | { | ||
126 | hacr |= HACR_16BITS; | ||
127 | hacr_write(ioaddr, hacr); | ||
128 | } /* wv_16_on */ | ||
129 | |||
130 | /*------------------------------------------------------------------*/ | ||
131 | /* | ||
132 | * Disable interrupts on the WaveLAN hardware. | ||
133 | * (called by wv_82586_stop()) | ||
134 | */ | ||
135 | static inline void wv_ints_off(struct net_device * dev) | ||
136 | { | ||
137 | net_local *lp = netdev_priv(dev); | ||
138 | unsigned long ioaddr = dev->base_addr; | ||
139 | |||
140 | lp->hacr &= ~HACR_INTRON; | ||
141 | hacr_write(ioaddr, lp->hacr); | ||
142 | } /* wv_ints_off */ | ||
143 | |||
144 | /*------------------------------------------------------------------*/ | ||
145 | /* | ||
146 | * Enable interrupts on the WaveLAN hardware. | ||
147 | * (called by wv_hw_reset()) | ||
148 | */ | ||
149 | static inline void wv_ints_on(struct net_device * dev) | ||
150 | { | ||
151 | net_local *lp = netdev_priv(dev); | ||
152 | unsigned long ioaddr = dev->base_addr; | ||
153 | |||
154 | lp->hacr |= HACR_INTRON; | ||
155 | hacr_write(ioaddr, lp->hacr); | ||
156 | } /* wv_ints_on */ | ||
157 | |||
158 | /******************* MODEM MANAGEMENT SUBROUTINES *******************/ | ||
159 | /* | ||
160 | * Useful subroutines to manage the modem of the WaveLAN | ||
161 | */ | ||
162 | |||
163 | /*------------------------------------------------------------------*/ | ||
164 | /* | ||
165 | * Read the Parameter Storage Area from the WaveLAN card's memory | ||
166 | */ | ||
167 | /* | ||
168 | * Read bytes from the PSA. | ||
169 | */ | ||
170 | static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ | ||
171 | u8 * b, /* buffer to fill */ | ||
172 | int n) | ||
173 | { /* size to read */ | ||
174 | wv_16_off(ioaddr, hacr); | ||
175 | |||
176 | while (n-- > 0) { | ||
177 | outw(o, PIOR2(ioaddr)); | ||
178 | o++; | ||
179 | *b++ = inb(PIOP2(ioaddr)); | ||
180 | } | ||
181 | |||
182 | wv_16_on(ioaddr, hacr); | ||
183 | } /* psa_read */ | ||
184 | |||
185 | /*------------------------------------------------------------------*/ | ||
186 | /* | ||
187 | * Write the Parameter Storage Area to the WaveLAN card's memory. | ||
188 | */ | ||
189 | static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ | ||
190 | u8 * b, /* Buffer in memory */ | ||
191 | int n) | ||
192 | { /* Length of buffer */ | ||
193 | int count = 0; | ||
194 | |||
195 | wv_16_off(ioaddr, hacr); | ||
196 | |||
197 | while (n-- > 0) { | ||
198 | outw(o, PIOR2(ioaddr)); | ||
199 | o++; | ||
200 | |||
201 | outb(*b, PIOP2(ioaddr)); | ||
202 | b++; | ||
203 | |||
204 | /* Wait for the memory to finish its write cycle */ | ||
205 | count = 0; | ||
206 | while ((count++ < 100) && | ||
207 | (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); | ||
208 | } | ||
209 | |||
210 | wv_16_on(ioaddr, hacr); | ||
211 | } /* psa_write */ | ||
212 | |||
213 | #ifdef SET_PSA_CRC | ||
214 | /*------------------------------------------------------------------*/ | ||
215 | /* | ||
216 | * Calculate the PSA CRC | ||
217 | * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code | ||
218 | * NOTE: By specifying a length including the CRC position the | ||
219 | * returned value should be zero. (i.e. a correct checksum in the PSA) | ||
220 | * | ||
221 | * The Windows drivers don't use the CRC, but the AP and the PtP tool | ||
222 | * depend on it. | ||
223 | */ | ||
224 | static u16 psa_crc(u8 * psa, /* The PSA */ | ||
225 | int size) | ||
226 | { /* Number of short for CRC */ | ||
227 | int byte_cnt; /* Loop on the PSA */ | ||
228 | u16 crc_bytes = 0; /* Data in the PSA */ | ||
229 | int bit_cnt; /* Loop on the bits of the short */ | ||
230 | |||
231 | for (byte_cnt = 0; byte_cnt < size; byte_cnt++) { | ||
232 | crc_bytes ^= psa[byte_cnt]; /* Its an xor */ | ||
233 | |||
234 | for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) { | ||
235 | if (crc_bytes & 0x0001) | ||
236 | crc_bytes = (crc_bytes >> 1) ^ 0xA001; | ||
237 | else | ||
238 | crc_bytes >>= 1; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | return crc_bytes; | ||
243 | } /* psa_crc */ | ||
244 | #endif /* SET_PSA_CRC */ | ||
245 | |||
246 | /*------------------------------------------------------------------*/ | ||
247 | /* | ||
248 | * update the checksum field in the Wavelan's PSA | ||
249 | */ | ||
250 | static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) | ||
251 | { | ||
252 | #ifdef SET_PSA_CRC | ||
253 | psa_t psa; | ||
254 | u16 crc; | ||
255 | |||
256 | /* read the parameter storage area */ | ||
257 | psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); | ||
258 | |||
259 | /* update the checksum */ | ||
260 | crc = psa_crc((unsigned char *) &psa, | ||
261 | sizeof(psa) - sizeof(psa.psa_crc[0]) - | ||
262 | sizeof(psa.psa_crc[1]) | ||
263 | - sizeof(psa.psa_crc_status)); | ||
264 | |||
265 | psa.psa_crc[0] = crc & 0xFF; | ||
266 | psa.psa_crc[1] = (crc & 0xFF00) >> 8; | ||
267 | |||
268 | /* Write it ! */ | ||
269 | psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa, | ||
270 | (unsigned char *) &psa.psa_crc, 2); | ||
271 | |||
272 | #ifdef DEBUG_IOCTL_INFO | ||
273 | printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", | ||
274 | dev->name, psa.psa_crc[0], psa.psa_crc[1]); | ||
275 | |||
276 | /* Check again (luxury !) */ | ||
277 | crc = psa_crc((unsigned char *) &psa, | ||
278 | sizeof(psa) - sizeof(psa.psa_crc_status)); | ||
279 | |||
280 | if (crc != 0) | ||
281 | printk(KERN_WARNING | ||
282 | "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", | ||
283 | dev->name); | ||
284 | #endif /* DEBUG_IOCTL_INFO */ | ||
285 | #endif /* SET_PSA_CRC */ | ||
286 | } /* update_psa_checksum */ | ||
287 | |||
288 | /*------------------------------------------------------------------*/ | ||
289 | /* | ||
290 | * Write 1 byte to the MMC. | ||
291 | */ | ||
292 | static void mmc_out(unsigned long ioaddr, u16 o, u8 d) | ||
293 | { | ||
294 | int count = 0; | ||
295 | |||
296 | /* Wait for MMC to go idle */ | ||
297 | while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) | ||
298 | udelay(10); | ||
299 | |||
300 | outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); | ||
301 | } | ||
302 | |||
303 | /*------------------------------------------------------------------*/ | ||
304 | /* | ||
305 | * Routine to write bytes to the Modem Management Controller. | ||
306 | * We start at the end because it is the way it should be! | ||
307 | */ | ||
308 | static void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n) | ||
309 | { | ||
310 | o += n; | ||
311 | b += n; | ||
312 | |||
313 | while (n-- > 0) | ||
314 | mmc_out(ioaddr, --o, *(--b)); | ||
315 | } /* mmc_write */ | ||
316 | |||
317 | /*------------------------------------------------------------------*/ | ||
318 | /* | ||
319 | * Read a byte from the MMC. | ||
320 | * Optimised version for 1 byte, avoid using memory. | ||
321 | */ | ||
322 | static u8 mmc_in(unsigned long ioaddr, u16 o) | ||
323 | { | ||
324 | int count = 0; | ||
325 | |||
326 | while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) | ||
327 | udelay(10); | ||
328 | outw(o << 1, MMCR(ioaddr)); | ||
329 | |||
330 | while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) | ||
331 | udelay(10); | ||
332 | return (u8) (inw(MMCR(ioaddr)) >> 8); | ||
333 | } | ||
334 | |||
335 | /*------------------------------------------------------------------*/ | ||
336 | /* | ||
337 | * Routine to read bytes from the Modem Management Controller. | ||
338 | * The implementation is complicated by a lack of address lines, | ||
339 | * which prevents decoding of the low-order bit. | ||
340 | * (code has just been moved in the above function) | ||
341 | * We start at the end because it is the way it should be! | ||
342 | */ | ||
343 | static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n) | ||
344 | { | ||
345 | o += n; | ||
346 | b += n; | ||
347 | |||
348 | while (n-- > 0) | ||
349 | *(--b) = mmc_in(ioaddr, --o); | ||
350 | } /* mmc_read */ | ||
351 | |||
352 | /*------------------------------------------------------------------*/ | ||
353 | /* | ||
354 | * Get the type of encryption available. | ||
355 | */ | ||
356 | static inline int mmc_encr(unsigned long ioaddr) | ||
357 | { /* I/O port of the card */ | ||
358 | int temp; | ||
359 | |||
360 | temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); | ||
361 | if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) | ||
362 | return 0; | ||
363 | else | ||
364 | return temp; | ||
365 | } | ||
366 | |||
367 | /*------------------------------------------------------------------*/ | ||
368 | /* | ||
369 | * Wait for the frequency EEPROM to complete a command. | ||
370 | * I hope this one will be optimally inlined. | ||
371 | */ | ||
372 | static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */ | ||
373 | int delay, /* Base delay to wait for */ | ||
374 | int number) | ||
375 | { /* Number of time to wait */ | ||
376 | int count = 0; /* Wait only a limited time */ | ||
377 | |||
378 | while ((count++ < number) && | ||
379 | (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
380 | MMR_FEE_STATUS_BUSY)) udelay(delay); | ||
381 | } | ||
382 | |||
383 | /*------------------------------------------------------------------*/ | ||
384 | /* | ||
385 | * Read bytes from the Frequency EEPROM (frequency select cards). | ||
386 | */ | ||
387 | static void fee_read(unsigned long ioaddr, /* I/O port of the card */ | ||
388 | u16 o, /* destination offset */ | ||
389 | u16 * b, /* data buffer */ | ||
390 | int n) | ||
391 | { /* number of registers */ | ||
392 | b += n; /* Position at the end of the area */ | ||
393 | |||
394 | /* Write the address */ | ||
395 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
396 | |||
397 | /* Loop on all buffer */ | ||
398 | while (n-- > 0) { | ||
399 | /* Write the read command */ | ||
400 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
401 | MMW_FEE_CTRL_READ); | ||
402 | |||
403 | /* Wait until EEPROM is ready (should be quick). */ | ||
404 | fee_wait(ioaddr, 10, 100); | ||
405 | |||
406 | /* Read the value. */ | ||
407 | *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | | ||
408 | mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | |||
413 | /*------------------------------------------------------------------*/ | ||
414 | /* | ||
415 | * Write bytes from the Frequency EEPROM (frequency select cards). | ||
416 | * This is a bit complicated, because the frequency EEPROM has to | ||
417 | * be unprotected and the write enabled. | ||
418 | * Jean II | ||
419 | */ | ||
420 | static void fee_write(unsigned long ioaddr, /* I/O port of the card */ | ||
421 | u16 o, /* destination offset */ | ||
422 | u16 * b, /* data buffer */ | ||
423 | int n) | ||
424 | { /* number of registers */ | ||
425 | b += n; /* Position at the end of the area. */ | ||
426 | |||
427 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
428 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
429 | /* Ask to read the protected register */ | ||
430 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); | ||
431 | |||
432 | fee_wait(ioaddr, 10, 100); | ||
433 | |||
434 | /* Read the protected register. */ | ||
435 | printk("Protected 2: %02X-%02X\n", | ||
436 | mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), | ||
437 | mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); | ||
438 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
439 | |||
440 | /* Enable protected register. */ | ||
441 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
442 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); | ||
443 | |||
444 | fee_wait(ioaddr, 10, 100); | ||
445 | |||
446 | /* Unprotect area. */ | ||
447 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); | ||
448 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
449 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
450 | /* or use: */ | ||
451 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); | ||
452 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
453 | |||
454 | fee_wait(ioaddr, 10, 100); | ||
455 | #endif /* EEPROM_IS_PROTECTED */ | ||
456 | |||
457 | /* Write enable. */ | ||
458 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
459 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); | ||
460 | |||
461 | fee_wait(ioaddr, 10, 100); | ||
462 | |||
463 | /* Write the EEPROM address. */ | ||
464 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
465 | |||
466 | /* Loop on all buffer */ | ||
467 | while (n-- > 0) { | ||
468 | /* Write the value. */ | ||
469 | mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); | ||
470 | mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); | ||
471 | |||
472 | /* Write the write command. */ | ||
473 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
474 | MMW_FEE_CTRL_WRITE); | ||
475 | |||
476 | /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ | ||
477 | mdelay(10); | ||
478 | fee_wait(ioaddr, 10, 100); | ||
479 | } | ||
480 | |||
481 | /* Write disable. */ | ||
482 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); | ||
483 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); | ||
484 | |||
485 | fee_wait(ioaddr, 10, 100); | ||
486 | |||
487 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
488 | /* Reprotect EEPROM. */ | ||
489 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); | ||
490 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
491 | |||
492 | fee_wait(ioaddr, 10, 100); | ||
493 | #endif /* EEPROM_IS_PROTECTED */ | ||
494 | } | ||
495 | |||
496 | /************************ I82586 SUBROUTINES *************************/ | ||
497 | /* | ||
498 | * Useful subroutines to manage the Ethernet controller | ||
499 | */ | ||
500 | |||
501 | /*------------------------------------------------------------------*/ | ||
502 | /* | ||
503 | * Read bytes from the on-board RAM. | ||
504 | * Why does inlining this function make it fail? | ||
505 | */ | ||
506 | static /*inline */ void obram_read(unsigned long ioaddr, | ||
507 | u16 o, u8 * b, int n) | ||
508 | { | ||
509 | outw(o, PIOR1(ioaddr)); | ||
510 | insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); | ||
511 | } | ||
512 | |||
513 | /*------------------------------------------------------------------*/ | ||
514 | /* | ||
515 | * Write bytes to the on-board RAM. | ||
516 | */ | ||
517 | static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) | ||
518 | { | ||
519 | outw(o, PIOR1(ioaddr)); | ||
520 | outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); | ||
521 | } | ||
522 | |||
523 | /*------------------------------------------------------------------*/ | ||
524 | /* | ||
525 | * Acknowledge the reading of the status issued by the i82586. | ||
526 | */ | ||
527 | static void wv_ack(struct net_device * dev) | ||
528 | { | ||
529 | net_local *lp = netdev_priv(dev); | ||
530 | unsigned long ioaddr = dev->base_addr; | ||
531 | u16 scb_cs; | ||
532 | int i; | ||
533 | |||
534 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), | ||
535 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
536 | scb_cs &= SCB_ST_INT; | ||
537 | |||
538 | if (scb_cs == 0) | ||
539 | return; | ||
540 | |||
541 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
542 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
543 | |||
544 | set_chan_attn(ioaddr, lp->hacr); | ||
545 | |||
546 | for (i = 1000; i > 0; i--) { | ||
547 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
548 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
549 | if (scb_cs == 0) | ||
550 | break; | ||
551 | |||
552 | udelay(10); | ||
553 | } | ||
554 | udelay(100); | ||
555 | |||
556 | #ifdef DEBUG_CONFIG_ERROR | ||
557 | if (i <= 0) | ||
558 | printk(KERN_INFO | ||
559 | "%s: wv_ack(): board not accepting command.\n", | ||
560 | dev->name); | ||
561 | #endif | ||
562 | } | ||
563 | |||
564 | /*------------------------------------------------------------------*/ | ||
565 | /* | ||
566 | * Set channel attention bit and busy wait until command has | ||
567 | * completed, then acknowledge completion of the command. | ||
568 | */ | ||
569 | static int wv_synchronous_cmd(struct net_device * dev, const char *str) | ||
570 | { | ||
571 | net_local *lp = netdev_priv(dev); | ||
572 | unsigned long ioaddr = dev->base_addr; | ||
573 | u16 scb_cmd; | ||
574 | ach_t cb; | ||
575 | int i; | ||
576 | |||
577 | scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; | ||
578 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
579 | (unsigned char *) &scb_cmd, sizeof(scb_cmd)); | ||
580 | |||
581 | set_chan_attn(ioaddr, lp->hacr); | ||
582 | |||
583 | for (i = 1000; i > 0; i--) { | ||
584 | obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, | ||
585 | sizeof(cb)); | ||
586 | if (cb.ac_status & AC_SFLD_C) | ||
587 | break; | ||
588 | |||
589 | udelay(10); | ||
590 | } | ||
591 | udelay(100); | ||
592 | |||
593 | if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) { | ||
594 | #ifdef DEBUG_CONFIG_ERROR | ||
595 | printk(KERN_INFO "%s: %s failed; status = 0x%x\n", | ||
596 | dev->name, str, cb.ac_status); | ||
597 | #endif | ||
598 | #ifdef DEBUG_I82586_SHOW | ||
599 | wv_scb_show(ioaddr); | ||
600 | #endif | ||
601 | return -1; | ||
602 | } | ||
603 | |||
604 | /* Ack the status */ | ||
605 | wv_ack(dev); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | /*------------------------------------------------------------------*/ | ||
611 | /* | ||
612 | * Configuration commands completion interrupt. | ||
613 | * Check if done, and if OK. | ||
614 | */ | ||
615 | static int | ||
616 | wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) | ||
617 | { | ||
618 | unsigned short mcs_addr; | ||
619 | unsigned short status; | ||
620 | int ret; | ||
621 | |||
622 | #ifdef DEBUG_INTERRUPT_TRACE | ||
623 | printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); | ||
624 | #endif | ||
625 | |||
626 | mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) | ||
627 | + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); | ||
628 | |||
629 | /* Read the status of the last command (set mc list). */ | ||
630 | obram_read(ioaddr, acoff(mcs_addr, ac_status), | ||
631 | (unsigned char *) &status, sizeof(status)); | ||
632 | |||
633 | /* If not completed -> exit */ | ||
634 | if ((status & AC_SFLD_C) == 0) | ||
635 | ret = 0; /* Not ready to be scrapped */ | ||
636 | else { | ||
637 | #ifdef DEBUG_CONFIG_ERROR | ||
638 | unsigned short cfg_addr; | ||
639 | unsigned short ias_addr; | ||
640 | |||
641 | /* Check mc_config command */ | ||
642 | if ((status & AC_SFLD_OK) != AC_SFLD_OK) | ||
643 | printk(KERN_INFO | ||
644 | "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", | ||
645 | dev->name, status); | ||
646 | |||
647 | /* check ia-config command */ | ||
648 | ias_addr = mcs_addr - sizeof(ac_ias_t); | ||
649 | obram_read(ioaddr, acoff(ias_addr, ac_status), | ||
650 | (unsigned char *) &status, sizeof(status)); | ||
651 | if ((status & AC_SFLD_OK) != AC_SFLD_OK) | ||
652 | printk(KERN_INFO | ||
653 | "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", | ||
654 | dev->name, status); | ||
655 | |||
656 | /* Check config command. */ | ||
657 | cfg_addr = ias_addr - sizeof(ac_cfg_t); | ||
658 | obram_read(ioaddr, acoff(cfg_addr, ac_status), | ||
659 | (unsigned char *) &status, sizeof(status)); | ||
660 | if ((status & AC_SFLD_OK) != AC_SFLD_OK) | ||
661 | printk(KERN_INFO | ||
662 | "%s: wv_config_complete(): configure failed; status = 0x%x\n", | ||
663 | dev->name, status); | ||
664 | #endif /* DEBUG_CONFIG_ERROR */ | ||
665 | |||
666 | ret = 1; /* Ready to be scrapped */ | ||
667 | } | ||
668 | |||
669 | #ifdef DEBUG_INTERRUPT_TRACE | ||
670 | printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, | ||
671 | ret); | ||
672 | #endif | ||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | /*------------------------------------------------------------------*/ | ||
677 | /* | ||
678 | * Command completion interrupt. | ||
679 | * Reclaim as many freed tx buffers as we can. | ||
680 | * (called in wavelan_interrupt()). | ||
681 | * Note : the spinlock is already grabbed for us. | ||
682 | */ | ||
683 | static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) | ||
684 | { | ||
685 | int nreaped = 0; | ||
686 | |||
687 | #ifdef DEBUG_INTERRUPT_TRACE | ||
688 | printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); | ||
689 | #endif | ||
690 | |||
691 | /* Loop on all the transmit buffers */ | ||
692 | while (lp->tx_first_in_use != I82586NULL) { | ||
693 | unsigned short tx_status; | ||
694 | |||
695 | /* Read the first transmit buffer */ | ||
696 | obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), | ||
697 | (unsigned char *) &tx_status, | ||
698 | sizeof(tx_status)); | ||
699 | |||
700 | /* If not completed -> exit */ | ||
701 | if ((tx_status & AC_SFLD_C) == 0) | ||
702 | break; | ||
703 | |||
704 | /* Hack for reconfiguration */ | ||
705 | if (tx_status == 0xFFFF) | ||
706 | if (!wv_config_complete(dev, ioaddr, lp)) | ||
707 | break; /* Not completed */ | ||
708 | |||
709 | /* We now remove this buffer */ | ||
710 | nreaped++; | ||
711 | --lp->tx_n_in_use; | ||
712 | |||
713 | /* | ||
714 | if (lp->tx_n_in_use > 0) | ||
715 | printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); | ||
716 | */ | ||
717 | |||
718 | /* Was it the last one? */ | ||
719 | if (lp->tx_n_in_use <= 0) | ||
720 | lp->tx_first_in_use = I82586NULL; | ||
721 | else { | ||
722 | /* Next one in the chain */ | ||
723 | lp->tx_first_in_use += TXBLOCKZ; | ||
724 | if (lp->tx_first_in_use >= | ||
725 | OFFSET_CU + | ||
726 | NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= | ||
727 | NTXBLOCKS * TXBLOCKZ; | ||
728 | } | ||
729 | |||
730 | /* Hack for reconfiguration */ | ||
731 | if (tx_status == 0xFFFF) | ||
732 | continue; | ||
733 | |||
734 | /* Now, check status of the finished command */ | ||
735 | if (tx_status & AC_SFLD_OK) { | ||
736 | int ncollisions; | ||
737 | |||
738 | dev->stats.tx_packets++; | ||
739 | ncollisions = tx_status & AC_SFLD_MAXCOL; | ||
740 | dev->stats.collisions += ncollisions; | ||
741 | #ifdef DEBUG_TX_INFO | ||
742 | if (ncollisions > 0) | ||
743 | printk(KERN_DEBUG | ||
744 | "%s: wv_complete(): tx completed after %d collisions.\n", | ||
745 | dev->name, ncollisions); | ||
746 | #endif | ||
747 | } else { | ||
748 | dev->stats.tx_errors++; | ||
749 | if (tx_status & AC_SFLD_S10) { | ||
750 | dev->stats.tx_carrier_errors++; | ||
751 | #ifdef DEBUG_TX_FAIL | ||
752 | printk(KERN_DEBUG | ||
753 | "%s: wv_complete(): tx error: no CS.\n", | ||
754 | dev->name); | ||
755 | #endif | ||
756 | } | ||
757 | if (tx_status & AC_SFLD_S9) { | ||
758 | dev->stats.tx_carrier_errors++; | ||
759 | #ifdef DEBUG_TX_FAIL | ||
760 | printk(KERN_DEBUG | ||
761 | "%s: wv_complete(): tx error: lost CTS.\n", | ||
762 | dev->name); | ||
763 | #endif | ||
764 | } | ||
765 | if (tx_status & AC_SFLD_S8) { | ||
766 | dev->stats.tx_fifo_errors++; | ||
767 | #ifdef DEBUG_TX_FAIL | ||
768 | printk(KERN_DEBUG | ||
769 | "%s: wv_complete(): tx error: slow DMA.\n", | ||
770 | dev->name); | ||
771 | #endif | ||
772 | } | ||
773 | if (tx_status & AC_SFLD_S6) { | ||
774 | dev->stats.tx_heartbeat_errors++; | ||
775 | #ifdef DEBUG_TX_FAIL | ||
776 | printk(KERN_DEBUG | ||
777 | "%s: wv_complete(): tx error: heart beat.\n", | ||
778 | dev->name); | ||
779 | #endif | ||
780 | } | ||
781 | if (tx_status & AC_SFLD_S5) { | ||
782 | dev->stats.tx_aborted_errors++; | ||
783 | #ifdef DEBUG_TX_FAIL | ||
784 | printk(KERN_DEBUG | ||
785 | "%s: wv_complete(): tx error: too many collisions.\n", | ||
786 | dev->name); | ||
787 | #endif | ||
788 | } | ||
789 | } | ||
790 | |||
791 | #ifdef DEBUG_TX_INFO | ||
792 | printk(KERN_DEBUG | ||
793 | "%s: wv_complete(): tx completed, tx_status 0x%04x\n", | ||
794 | dev->name, tx_status); | ||
795 | #endif | ||
796 | } | ||
797 | |||
798 | #ifdef DEBUG_INTERRUPT_INFO | ||
799 | if (nreaped > 1) | ||
800 | printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", | ||
801 | dev->name, nreaped); | ||
802 | #endif | ||
803 | |||
804 | /* | ||
805 | * Inform upper layers. | ||
806 | */ | ||
807 | if (lp->tx_n_in_use < NTXBLOCKS - 1) { | ||
808 | netif_wake_queue(dev); | ||
809 | } | ||
810 | #ifdef DEBUG_INTERRUPT_TRACE | ||
811 | printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); | ||
812 | #endif | ||
813 | return nreaped; | ||
814 | } | ||
815 | |||
816 | /*------------------------------------------------------------------*/ | ||
817 | /* | ||
818 | * Reconfigure the i82586, or at least ask for it. | ||
819 | * Because wv_82586_config uses a transmission buffer, we must do it | ||
820 | * when we are sure that there is one left, so we do it now | ||
821 | * or in wavelan_packet_xmit() (I can't find any better place, | ||
822 | * wavelan_interrupt is not an option), so you may experience | ||
823 | * delays sometimes. | ||
824 | */ | ||
825 | static void wv_82586_reconfig(struct net_device * dev) | ||
826 | { | ||
827 | net_local *lp = netdev_priv(dev); | ||
828 | unsigned long flags; | ||
829 | |||
830 | /* Arm the flag, will be cleard in wv_82586_config() */ | ||
831 | lp->reconfig_82586 = 1; | ||
832 | |||
833 | /* Check if we can do it now ! */ | ||
834 | if((netif_running(dev)) && !(netif_queue_stopped(dev))) { | ||
835 | spin_lock_irqsave(&lp->spinlock, flags); | ||
836 | /* May fail */ | ||
837 | wv_82586_config(dev); | ||
838 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
839 | } | ||
840 | else { | ||
841 | #ifdef DEBUG_CONFIG_INFO | ||
842 | printk(KERN_DEBUG | ||
843 | "%s: wv_82586_reconfig(): delayed (state = %lX)\n", | ||
844 | dev->name, dev->state); | ||
845 | #endif | ||
846 | } | ||
847 | } | ||
848 | |||
849 | /********************* DEBUG & INFO SUBROUTINES *********************/ | ||
850 | /* | ||
851 | * This routine is used in the code to show information for debugging. | ||
852 | * Most of the time, it dumps the contents of hardware structures. | ||
853 | */ | ||
854 | |||
855 | #ifdef DEBUG_PSA_SHOW | ||
856 | /*------------------------------------------------------------------*/ | ||
857 | /* | ||
858 | * Print the formatted contents of the Parameter Storage Area. | ||
859 | */ | ||
860 | static void wv_psa_show(psa_t * p) | ||
861 | { | ||
862 | printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); | ||
863 | printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", | ||
864 | p->psa_io_base_addr_1, | ||
865 | p->psa_io_base_addr_2, | ||
866 | p->psa_io_base_addr_3, p->psa_io_base_addr_4); | ||
867 | printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", | ||
868 | p->psa_rem_boot_addr_1, | ||
869 | p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); | ||
870 | printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); | ||
871 | printk("psa_int_req_no: %d\n", p->psa_int_req_no); | ||
872 | #ifdef DEBUG_SHOW_UNUSED | ||
873 | printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); | ||
874 | #endif /* DEBUG_SHOW_UNUSED */ | ||
875 | printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); | ||
876 | printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); | ||
877 | printk(KERN_DEBUG "psa_univ_local_sel: %d, ", | ||
878 | p->psa_univ_local_sel); | ||
879 | printk("psa_comp_number: %d, ", p->psa_comp_number); | ||
880 | printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); | ||
881 | printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", | ||
882 | p->psa_feature_select); | ||
883 | printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); | ||
884 | printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); | ||
885 | printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); | ||
886 | printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], | ||
887 | p->psa_nwid[1]); | ||
888 | printk("psa_nwid_select: %d\n", p->psa_nwid_select); | ||
889 | printk(KERN_DEBUG "psa_encryption_select: %d, ", | ||
890 | p->psa_encryption_select); | ||
891 | printk | ||
892 | ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
893 | p->psa_encryption_key[0], p->psa_encryption_key[1], | ||
894 | p->psa_encryption_key[2], p->psa_encryption_key[3], | ||
895 | p->psa_encryption_key[4], p->psa_encryption_key[5], | ||
896 | p->psa_encryption_key[6], p->psa_encryption_key[7]); | ||
897 | printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); | ||
898 | printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", | ||
899 | p->psa_call_code[0]); | ||
900 | printk | ||
901 | ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
902 | p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2], | ||
903 | p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5], | ||
904 | p->psa_call_code[6], p->psa_call_code[7]); | ||
905 | #ifdef DEBUG_SHOW_UNUSED | ||
906 | printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n", | ||
907 | p->psa_reserved[0], | ||
908 | p->psa_reserved[1]); | ||
909 | #endif /* DEBUG_SHOW_UNUSED */ | ||
910 | printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); | ||
911 | printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); | ||
912 | printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); | ||
913 | } /* wv_psa_show */ | ||
914 | #endif /* DEBUG_PSA_SHOW */ | ||
915 | |||
916 | #ifdef DEBUG_MMC_SHOW | ||
917 | /*------------------------------------------------------------------*/ | ||
918 | /* | ||
919 | * Print the formatted status of the Modem Management Controller. | ||
920 | * This function needs to be completed. | ||
921 | */ | ||
922 | static void wv_mmc_show(struct net_device * dev) | ||
923 | { | ||
924 | unsigned long ioaddr = dev->base_addr; | ||
925 | net_local *lp = netdev_priv(dev); | ||
926 | mmr_t m; | ||
927 | |||
928 | /* Basic check */ | ||
929 | if (hasr_read(ioaddr) & HASR_NO_CLK) { | ||
930 | printk(KERN_WARNING | ||
931 | "%s: wv_mmc_show: modem not connected\n", | ||
932 | dev->name); | ||
933 | return; | ||
934 | } | ||
935 | |||
936 | /* Read the mmc */ | ||
937 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); | ||
938 | mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); | ||
939 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); | ||
940 | |||
941 | /* Don't forget to update statistics */ | ||
942 | lp->wstats.discard.nwid += | ||
943 | (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
944 | |||
945 | printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); | ||
946 | #ifdef DEBUG_SHOW_UNUSED | ||
947 | printk(KERN_DEBUG | ||
948 | "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
949 | m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2], | ||
950 | m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5], | ||
951 | m.mmr_unused0[6], m.mmr_unused0[7]); | ||
952 | #endif /* DEBUG_SHOW_UNUSED */ | ||
953 | printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", | ||
954 | m.mmr_des_avail, m.mmr_des_status); | ||
955 | #ifdef DEBUG_SHOW_UNUSED | ||
956 | printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", | ||
957 | m.mmr_unused1[0], | ||
958 | m.mmr_unused1[1], | ||
959 | m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]); | ||
960 | #endif /* DEBUG_SHOW_UNUSED */ | ||
961 | printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", | ||
962 | m.mmr_dce_status, | ||
963 | (m. | ||
964 | mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? | ||
965 | "energy detected," : "", | ||
966 | (m. | ||
967 | mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? | ||
968 | "loop test indicated," : "", | ||
969 | (m. | ||
970 | mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? | ||
971 | "transmitter on," : "", | ||
972 | (m. | ||
973 | mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? | ||
974 | "jabber timer expired," : ""); | ||
975 | printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id); | ||
976 | #ifdef DEBUG_SHOW_UNUSED | ||
977 | printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", | ||
978 | m.mmr_unused2[0], m.mmr_unused2[1]); | ||
979 | #endif /* DEBUG_SHOW_UNUSED */ | ||
980 | printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", | ||
981 | (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, | ||
982 | (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); | ||
983 | printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", | ||
984 | m.mmr_thr_pre_set & MMR_THR_PRE_SET, | ||
985 | (m. | ||
986 | mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : | ||
987 | "below"); | ||
988 | printk(KERN_DEBUG "signal_lvl: %d [%s], ", | ||
989 | m.mmr_signal_lvl & MMR_SIGNAL_LVL, | ||
990 | (m. | ||
991 | mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : | ||
992 | "no new msg"); | ||
993 | printk("silence_lvl: %d [%s], ", | ||
994 | m.mmr_silence_lvl & MMR_SILENCE_LVL, | ||
995 | (m. | ||
996 | mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : | ||
997 | "no new update"); | ||
998 | printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, | ||
999 | (m. | ||
1000 | mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : | ||
1001 | "Antenna 0"); | ||
1002 | #ifdef DEBUG_SHOW_UNUSED | ||
1003 | printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); | ||
1004 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1005 | } /* wv_mmc_show */ | ||
1006 | #endif /* DEBUG_MMC_SHOW */ | ||
1007 | |||
1008 | #ifdef DEBUG_I82586_SHOW | ||
1009 | /*------------------------------------------------------------------*/ | ||
1010 | /* | ||
1011 | * Print the last block of the i82586 memory. | ||
1012 | */ | ||
1013 | static void wv_scb_show(unsigned long ioaddr) | ||
1014 | { | ||
1015 | scb_t scb; | ||
1016 | |||
1017 | obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, | ||
1018 | sizeof(scb)); | ||
1019 | |||
1020 | printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); | ||
1021 | |||
1022 | printk(KERN_DEBUG "status: "); | ||
1023 | printk("stat 0x%x[%s%s%s%s] ", | ||
1024 | (scb. | ||
1025 | scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | | ||
1026 | SCB_ST_RNR)) >> 12, | ||
1027 | (scb. | ||
1028 | scb_status & SCB_ST_CX) ? "command completion interrupt," : | ||
1029 | "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", | ||
1030 | (scb. | ||
1031 | scb_status & SCB_ST_CNA) ? "command unit not active," : "", | ||
1032 | (scb. | ||
1033 | scb_status & SCB_ST_RNR) ? "receiving unit not ready," : | ||
1034 | ""); | ||
1035 | printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, | ||
1036 | ((scb.scb_status & SCB_ST_CUS) == | ||
1037 | SCB_ST_CUS_IDLE) ? "idle" : "", | ||
1038 | ((scb.scb_status & SCB_ST_CUS) == | ||
1039 | SCB_ST_CUS_SUSP) ? "suspended" : "", | ||
1040 | ((scb.scb_status & SCB_ST_CUS) == | ||
1041 | SCB_ST_CUS_ACTV) ? "active" : ""); | ||
1042 | printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4, | ||
1043 | ((scb.scb_status & SCB_ST_RUS) == | ||
1044 | SCB_ST_RUS_IDLE) ? "idle" : "", | ||
1045 | ((scb.scb_status & SCB_ST_RUS) == | ||
1046 | SCB_ST_RUS_SUSP) ? "suspended" : "", | ||
1047 | ((scb.scb_status & SCB_ST_RUS) == | ||
1048 | SCB_ST_RUS_NRES) ? "no resources" : "", | ||
1049 | ((scb.scb_status & SCB_ST_RUS) == | ||
1050 | SCB_ST_RUS_RDY) ? "ready" : ""); | ||
1051 | |||
1052 | printk(KERN_DEBUG "command: "); | ||
1053 | printk("ack 0x%x[%s%s%s%s] ", | ||
1054 | (scb. | ||
1055 | scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | | ||
1056 | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, | ||
1057 | (scb. | ||
1058 | scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", | ||
1059 | (scb. | ||
1060 | scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", | ||
1061 | (scb. | ||
1062 | scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", | ||
1063 | (scb. | ||
1064 | scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); | ||
1065 | printk("cuc 0x%x[%s%s%s%s%s] ", | ||
1066 | (scb.scb_command & SCB_CMD_CUC) >> 8, | ||
1067 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1068 | SCB_CMD_CUC_NOP) ? "nop" : "", | ||
1069 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1070 | SCB_CMD_CUC_GO) ? "start cbl_offset" : "", | ||
1071 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1072 | SCB_CMD_CUC_RES) ? "resume execution" : "", | ||
1073 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1074 | SCB_CMD_CUC_SUS) ? "suspend execution" : "", | ||
1075 | ((scb.scb_command & SCB_CMD_CUC) == | ||
1076 | SCB_CMD_CUC_ABT) ? "abort execution" : ""); | ||
1077 | printk("ruc 0x%x[%s%s%s%s%s]\n", | ||
1078 | (scb.scb_command & SCB_CMD_RUC) >> 4, | ||
1079 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1080 | SCB_CMD_RUC_NOP) ? "nop" : "", | ||
1081 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1082 | SCB_CMD_RUC_GO) ? "start rfa_offset" : "", | ||
1083 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1084 | SCB_CMD_RUC_RES) ? "resume reception" : "", | ||
1085 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1086 | SCB_CMD_RUC_SUS) ? "suspend reception" : "", | ||
1087 | ((scb.scb_command & SCB_CMD_RUC) == | ||
1088 | SCB_CMD_RUC_ABT) ? "abort reception" : ""); | ||
1089 | |||
1090 | printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); | ||
1091 | printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); | ||
1092 | |||
1093 | printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); | ||
1094 | printk("alnerrs %d ", scb.scb_alnerrs); | ||
1095 | printk("rscerrs %d ", scb.scb_rscerrs); | ||
1096 | printk("ovrnerrs %d\n", scb.scb_ovrnerrs); | ||
1097 | } | ||
1098 | |||
1099 | /*------------------------------------------------------------------*/ | ||
1100 | /* | ||
1101 | * Print the formatted status of the i82586's receive unit. | ||
1102 | */ | ||
1103 | static void wv_ru_show(struct net_device * dev) | ||
1104 | { | ||
1105 | printk(KERN_DEBUG | ||
1106 | "##### WaveLAN i82586 receiver unit status: #####\n"); | ||
1107 | printk(KERN_DEBUG "ru:"); | ||
1108 | /* | ||
1109 | * Not implemented yet | ||
1110 | */ | ||
1111 | printk("\n"); | ||
1112 | } /* wv_ru_show */ | ||
1113 | |||
1114 | /*------------------------------------------------------------------*/ | ||
1115 | /* | ||
1116 | * Display info about one control block of the i82586 memory. | ||
1117 | */ | ||
1118 | static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) | ||
1119 | { | ||
1120 | unsigned long ioaddr; | ||
1121 | ac_tx_t actx; | ||
1122 | |||
1123 | ioaddr = dev->base_addr; | ||
1124 | |||
1125 | printk("%d: 0x%x:", i, p); | ||
1126 | |||
1127 | obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx)); | ||
1128 | printk(" status=0x%x,", actx.tx_h.ac_status); | ||
1129 | printk(" command=0x%x,", actx.tx_h.ac_command); | ||
1130 | |||
1131 | /* | ||
1132 | { | ||
1133 | tbd_t tbd; | ||
1134 | |||
1135 | obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); | ||
1136 | printk(" tbd_status=0x%x,", tbd.tbd_status); | ||
1137 | } | ||
1138 | */ | ||
1139 | |||
1140 | printk("|"); | ||
1141 | } | ||
1142 | |||
1143 | /*------------------------------------------------------------------*/ | ||
1144 | /* | ||
1145 | * Print status of the command unit of the i82586. | ||
1146 | */ | ||
1147 | static void wv_cu_show(struct net_device * dev) | ||
1148 | { | ||
1149 | net_local *lp = netdev_priv(dev); | ||
1150 | unsigned int i; | ||
1151 | u16 p; | ||
1152 | |||
1153 | printk(KERN_DEBUG | ||
1154 | "##### WaveLAN i82586 command unit status: #####\n"); | ||
1155 | |||
1156 | printk(KERN_DEBUG); | ||
1157 | for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) { | ||
1158 | wv_cu_show_one(dev, lp, i, p); | ||
1159 | |||
1160 | p += TXBLOCKZ; | ||
1161 | if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) | ||
1162 | p -= NTXBLOCKS * TXBLOCKZ; | ||
1163 | } | ||
1164 | printk("\n"); | ||
1165 | } | ||
1166 | #endif /* DEBUG_I82586_SHOW */ | ||
1167 | |||
1168 | #ifdef DEBUG_DEVICE_SHOW | ||
1169 | /*------------------------------------------------------------------*/ | ||
1170 | /* | ||
1171 | * Print the formatted status of the WaveLAN PCMCIA device driver. | ||
1172 | */ | ||
1173 | static void wv_dev_show(struct net_device * dev) | ||
1174 | { | ||
1175 | printk(KERN_DEBUG "dev:"); | ||
1176 | printk(" state=%lX,", dev->state); | ||
1177 | printk(" trans_start=%ld,", dev->trans_start); | ||
1178 | printk(" flags=0x%x,", dev->flags); | ||
1179 | printk("\n"); | ||
1180 | } /* wv_dev_show */ | ||
1181 | |||
1182 | /*------------------------------------------------------------------*/ | ||
1183 | /* | ||
1184 | * Print the formatted status of the WaveLAN PCMCIA device driver's | ||
1185 | * private information. | ||
1186 | */ | ||
1187 | static void wv_local_show(struct net_device * dev) | ||
1188 | { | ||
1189 | net_local *lp; | ||
1190 | |||
1191 | lp = netdev_priv(dev); | ||
1192 | |||
1193 | printk(KERN_DEBUG "local:"); | ||
1194 | printk(" tx_n_in_use=%d,", lp->tx_n_in_use); | ||
1195 | printk(" hacr=0x%x,", lp->hacr); | ||
1196 | printk(" rx_head=0x%x,", lp->rx_head); | ||
1197 | printk(" rx_last=0x%x,", lp->rx_last); | ||
1198 | printk(" tx_first_free=0x%x,", lp->tx_first_free); | ||
1199 | printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); | ||
1200 | printk("\n"); | ||
1201 | } /* wv_local_show */ | ||
1202 | #endif /* DEBUG_DEVICE_SHOW */ | ||
1203 | |||
1204 | #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) | ||
1205 | /*------------------------------------------------------------------*/ | ||
1206 | /* | ||
1207 | * Dump packet header (and content if necessary) on the screen | ||
1208 | */ | ||
1209 | static inline void wv_packet_info(u8 * p, /* Packet to dump */ | ||
1210 | int length, /* Length of the packet */ | ||
1211 | char *msg1, /* Name of the device */ | ||
1212 | char *msg2) | ||
1213 | { /* Name of the function */ | ||
1214 | int i; | ||
1215 | int maxi; | ||
1216 | |||
1217 | printk(KERN_DEBUG | ||
1218 | "%s: %s(): dest %pM, length %d\n", | ||
1219 | msg1, msg2, p, length); | ||
1220 | printk(KERN_DEBUG | ||
1221 | "%s: %s(): src %pM, type 0x%02X%02X\n", | ||
1222 | msg1, msg2, &p[6], p[12], p[13]); | ||
1223 | |||
1224 | #ifdef DEBUG_PACKET_DUMP | ||
1225 | |||
1226 | printk(KERN_DEBUG "data=\""); | ||
1227 | |||
1228 | if ((maxi = length) > DEBUG_PACKET_DUMP) | ||
1229 | maxi = DEBUG_PACKET_DUMP; | ||
1230 | for (i = 14; i < maxi; i++) | ||
1231 | if (p[i] >= ' ' && p[i] <= '~') | ||
1232 | printk(" %c", p[i]); | ||
1233 | else | ||
1234 | printk("%02X", p[i]); | ||
1235 | if (maxi < length) | ||
1236 | printk(".."); | ||
1237 | printk("\"\n"); | ||
1238 | printk(KERN_DEBUG "\n"); | ||
1239 | #endif /* DEBUG_PACKET_DUMP */ | ||
1240 | } | ||
1241 | #endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ | ||
1242 | |||
1243 | /*------------------------------------------------------------------*/ | ||
1244 | /* | ||
1245 | * This is the information which is displayed by the driver at startup. | ||
1246 | * There are lots of flags for configuring it to your liking. | ||
1247 | */ | ||
1248 | static void wv_init_info(struct net_device * dev) | ||
1249 | { | ||
1250 | short ioaddr = dev->base_addr; | ||
1251 | net_local *lp = netdev_priv(dev); | ||
1252 | psa_t psa; | ||
1253 | |||
1254 | /* Read the parameter storage area */ | ||
1255 | psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); | ||
1256 | |||
1257 | #ifdef DEBUG_PSA_SHOW | ||
1258 | wv_psa_show(&psa); | ||
1259 | #endif | ||
1260 | #ifdef DEBUG_MMC_SHOW | ||
1261 | wv_mmc_show(dev); | ||
1262 | #endif | ||
1263 | #ifdef DEBUG_I82586_SHOW | ||
1264 | wv_cu_show(dev); | ||
1265 | #endif | ||
1266 | |||
1267 | #ifdef DEBUG_BASIC_SHOW | ||
1268 | /* Now, let's go for the basic stuff. */ | ||
1269 | printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d", | ||
1270 | dev->name, ioaddr, dev->dev_addr, dev->irq); | ||
1271 | |||
1272 | /* Print current network ID. */ | ||
1273 | if (psa.psa_nwid_select) | ||
1274 | printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], | ||
1275 | psa.psa_nwid[1]); | ||
1276 | else | ||
1277 | printk(", nwid off"); | ||
1278 | |||
1279 | /* If 2.00 card */ | ||
1280 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
1281 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
1282 | unsigned short freq; | ||
1283 | |||
1284 | /* Ask the EEPROM to read the frequency from the first area. */ | ||
1285 | fee_read(ioaddr, 0x00, &freq, 1); | ||
1286 | |||
1287 | /* Print frequency */ | ||
1288 | printk(", 2.00, %ld", (freq >> 6) + 2400L); | ||
1289 | |||
1290 | /* Hack! */ | ||
1291 | if (freq & 0x20) | ||
1292 | printk(".5"); | ||
1293 | } else { | ||
1294 | printk(", PC"); | ||
1295 | switch (psa.psa_comp_number) { | ||
1296 | case PSA_COMP_PC_AT_915: | ||
1297 | case PSA_COMP_PC_AT_2400: | ||
1298 | printk("-AT"); | ||
1299 | break; | ||
1300 | case PSA_COMP_PC_MC_915: | ||
1301 | case PSA_COMP_PC_MC_2400: | ||
1302 | printk("-MC"); | ||
1303 | break; | ||
1304 | case PSA_COMP_PCMCIA_915: | ||
1305 | printk("MCIA"); | ||
1306 | break; | ||
1307 | default: | ||
1308 | printk("?"); | ||
1309 | } | ||
1310 | printk(", "); | ||
1311 | switch (psa.psa_subband) { | ||
1312 | case PSA_SUBBAND_915: | ||
1313 | printk("915"); | ||
1314 | break; | ||
1315 | case PSA_SUBBAND_2425: | ||
1316 | printk("2425"); | ||
1317 | break; | ||
1318 | case PSA_SUBBAND_2460: | ||
1319 | printk("2460"); | ||
1320 | break; | ||
1321 | case PSA_SUBBAND_2484: | ||
1322 | printk("2484"); | ||
1323 | break; | ||
1324 | case PSA_SUBBAND_2430_5: | ||
1325 | printk("2430.5"); | ||
1326 | break; | ||
1327 | default: | ||
1328 | printk("?"); | ||
1329 | } | ||
1330 | } | ||
1331 | |||
1332 | printk(" MHz\n"); | ||
1333 | #endif /* DEBUG_BASIC_SHOW */ | ||
1334 | |||
1335 | #ifdef DEBUG_VERSION_SHOW | ||
1336 | /* Print version information */ | ||
1337 | printk(KERN_NOTICE "%s", version); | ||
1338 | #endif | ||
1339 | } /* wv_init_info */ | ||
1340 | |||
1341 | /********************* IOCTL, STATS & RECONFIG *********************/ | ||
1342 | /* | ||
1343 | * We found here routines that are called by Linux on different | ||
1344 | * occasions after the configuration and not for transmitting data | ||
1345 | * These may be called when the user use ifconfig, /proc/net/dev | ||
1346 | * or wireless extensions | ||
1347 | */ | ||
1348 | |||
1349 | |||
1350 | /*------------------------------------------------------------------*/ | ||
1351 | /* | ||
1352 | * Set or clear the multicast filter for this adaptor. | ||
1353 | * num_addrs == -1 Promiscuous mode, receive all packets | ||
1354 | * num_addrs == 0 Normal mode, clear multicast list | ||
1355 | * num_addrs > 0 Multicast mode, receive normal and MC packets, | ||
1356 | * and do best-effort filtering. | ||
1357 | */ | ||
1358 | static void wavelan_set_multicast_list(struct net_device * dev) | ||
1359 | { | ||
1360 | net_local *lp = netdev_priv(dev); | ||
1361 | |||
1362 | #ifdef DEBUG_IOCTL_TRACE | ||
1363 | printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", | ||
1364 | dev->name); | ||
1365 | #endif | ||
1366 | |||
1367 | #ifdef DEBUG_IOCTL_INFO | ||
1368 | printk(KERN_DEBUG | ||
1369 | "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", | ||
1370 | dev->name, dev->flags, dev->mc_count); | ||
1371 | #endif | ||
1372 | |||
1373 | /* Are we asking for promiscuous mode, | ||
1374 | * or all multicast addresses (we don't have that!) | ||
1375 | * or too many multicast addresses for the hardware filter? */ | ||
1376 | if ((dev->flags & IFF_PROMISC) || | ||
1377 | (dev->flags & IFF_ALLMULTI) || | ||
1378 | (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { | ||
1379 | /* | ||
1380 | * Enable promiscuous mode: receive all packets. | ||
1381 | */ | ||
1382 | if (!lp->promiscuous) { | ||
1383 | lp->promiscuous = 1; | ||
1384 | lp->mc_count = 0; | ||
1385 | |||
1386 | wv_82586_reconfig(dev); | ||
1387 | } | ||
1388 | } else | ||
1389 | /* Are there multicast addresses to send? */ | ||
1390 | if (dev->mc_list != (struct dev_mc_list *) NULL) { | ||
1391 | /* | ||
1392 | * Disable promiscuous mode, but receive all packets | ||
1393 | * in multicast list | ||
1394 | */ | ||
1395 | #ifdef MULTICAST_AVOID | ||
1396 | if (lp->promiscuous || (dev->mc_count != lp->mc_count)) | ||
1397 | #endif | ||
1398 | { | ||
1399 | lp->promiscuous = 0; | ||
1400 | lp->mc_count = dev->mc_count; | ||
1401 | |||
1402 | wv_82586_reconfig(dev); | ||
1403 | } | ||
1404 | } else { | ||
1405 | /* | ||
1406 | * Switch to normal mode: disable promiscuous mode and | ||
1407 | * clear the multicast list. | ||
1408 | */ | ||
1409 | if (lp->promiscuous || lp->mc_count == 0) { | ||
1410 | lp->promiscuous = 0; | ||
1411 | lp->mc_count = 0; | ||
1412 | |||
1413 | wv_82586_reconfig(dev); | ||
1414 | } | ||
1415 | } | ||
1416 | #ifdef DEBUG_IOCTL_TRACE | ||
1417 | printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", | ||
1418 | dev->name); | ||
1419 | #endif | ||
1420 | } | ||
1421 | |||
1422 | /*------------------------------------------------------------------*/ | ||
1423 | /* | ||
1424 | * This function doesn't exist. | ||
1425 | * (Note : it was a nice way to test the reconfigure stuff...) | ||
1426 | */ | ||
1427 | #ifdef SET_MAC_ADDRESS | ||
1428 | static int wavelan_set_mac_address(struct net_device * dev, void *addr) | ||
1429 | { | ||
1430 | struct sockaddr *mac = addr; | ||
1431 | |||
1432 | /* Copy the address. */ | ||
1433 | memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); | ||
1434 | |||
1435 | /* Reconfigure the beast. */ | ||
1436 | wv_82586_reconfig(dev); | ||
1437 | |||
1438 | return 0; | ||
1439 | } | ||
1440 | #endif /* SET_MAC_ADDRESS */ | ||
1441 | |||
1442 | |||
1443 | /*------------------------------------------------------------------*/ | ||
1444 | /* | ||
1445 | * Frequency setting (for hardware capable of it) | ||
1446 | * It's a bit complicated and you don't really want to look into it. | ||
1447 | * (called in wavelan_ioctl) | ||
1448 | */ | ||
1449 | static int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ | ||
1450 | iw_freq * frequency) | ||
1451 | { | ||
1452 | const int BAND_NUM = 10; /* Number of bands */ | ||
1453 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ | ||
1454 | #ifdef DEBUG_IOCTL_INFO | ||
1455 | int i; | ||
1456 | #endif | ||
1457 | |||
1458 | /* Setting by frequency */ | ||
1459 | /* Theoretically, you may set any frequency between | ||
1460 | * the two limits with a 0.5 MHz precision. In practice, | ||
1461 | * I don't want you to have trouble with local regulations. | ||
1462 | */ | ||
1463 | if ((frequency->e == 1) && | ||
1464 | (frequency->m >= (int) 2.412e8) | ||
1465 | && (frequency->m <= (int) 2.487e8)) { | ||
1466 | freq = ((frequency->m / 10000) - 24000L) / 5; | ||
1467 | } | ||
1468 | |||
1469 | /* Setting by channel (same as wfreqsel) */ | ||
1470 | /* Warning: each channel is 22 MHz wide, so some of the channels | ||
1471 | * will interfere. */ | ||
1472 | if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { | ||
1473 | /* Get frequency offset. */ | ||
1474 | freq = channel_bands[frequency->m] >> 1; | ||
1475 | } | ||
1476 | |||
1477 | /* Verify that the frequency is allowed. */ | ||
1478 | if (freq != 0L) { | ||
1479 | u16 table[10]; /* Authorized frequency table */ | ||
1480 | |||
1481 | /* Read the frequency table. */ | ||
1482 | fee_read(ioaddr, 0x71, table, 10); | ||
1483 | |||
1484 | #ifdef DEBUG_IOCTL_INFO | ||
1485 | printk(KERN_DEBUG "Frequency table: "); | ||
1486 | for (i = 0; i < 10; i++) { | ||
1487 | printk(" %04X", table[i]); | ||
1488 | } | ||
1489 | printk("\n"); | ||
1490 | #endif | ||
1491 | |||
1492 | /* Look in the table to see whether the frequency is allowed. */ | ||
1493 | if (!(table[9 - ((freq - 24) / 16)] & | ||
1494 | (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ | ||
1495 | } else | ||
1496 | return -EINVAL; | ||
1497 | |||
1498 | /* if we get a usable frequency */ | ||
1499 | if (freq != 0L) { | ||
1500 | unsigned short area[16]; | ||
1501 | unsigned short dac[2]; | ||
1502 | unsigned short area_verify[16]; | ||
1503 | unsigned short dac_verify[2]; | ||
1504 | /* Corresponding gain (in the power adjust value table) | ||
1505 | * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 | ||
1506 | * and WCIN062D.DOC, page 6.2.9. */ | ||
1507 | unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; | ||
1508 | int power_band = 0; /* Selected band */ | ||
1509 | unsigned short power_adjust; /* Correct value */ | ||
1510 | |||
1511 | /* Search for the gain. */ | ||
1512 | power_band = 0; | ||
1513 | while ((freq > power_limit[power_band]) && | ||
1514 | (power_limit[++power_band] != 0)); | ||
1515 | |||
1516 | /* Read the first area. */ | ||
1517 | fee_read(ioaddr, 0x00, area, 16); | ||
1518 | |||
1519 | /* Read the DAC. */ | ||
1520 | fee_read(ioaddr, 0x60, dac, 2); | ||
1521 | |||
1522 | /* Read the new power adjust value. */ | ||
1523 | fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, | ||
1524 | 1); | ||
1525 | if (power_band & 0x1) | ||
1526 | power_adjust >>= 8; | ||
1527 | else | ||
1528 | power_adjust &= 0xFF; | ||
1529 | |||
1530 | #ifdef DEBUG_IOCTL_INFO | ||
1531 | printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); | ||
1532 | for (i = 0; i < 16; i++) { | ||
1533 | printk(" %04X", area[i]); | ||
1534 | } | ||
1535 | printk("\n"); | ||
1536 | |||
1537 | printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", | ||
1538 | dac[0], dac[1]); | ||
1539 | #endif | ||
1540 | |||
1541 | /* Frequency offset (for info only) */ | ||
1542 | area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); | ||
1543 | |||
1544 | /* Receiver Principle main divider coefficient */ | ||
1545 | area[3] = (freq >> 1) + 2400L - 352L; | ||
1546 | area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1547 | |||
1548 | /* Transmitter Main divider coefficient */ | ||
1549 | area[13] = (freq >> 1) + 2400L; | ||
1550 | area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1551 | |||
1552 | /* Other parts of the area are flags, bit streams or unused. */ | ||
1553 | |||
1554 | /* Set the value in the DAC. */ | ||
1555 | dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); | ||
1556 | dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); | ||
1557 | |||
1558 | /* Write the first area. */ | ||
1559 | fee_write(ioaddr, 0x00, area, 16); | ||
1560 | |||
1561 | /* Write the DAC. */ | ||
1562 | fee_write(ioaddr, 0x60, dac, 2); | ||
1563 | |||
1564 | /* We now should verify here that the writing of the EEPROM went OK. */ | ||
1565 | |||
1566 | /* Reread the first area. */ | ||
1567 | fee_read(ioaddr, 0x00, area_verify, 16); | ||
1568 | |||
1569 | /* Reread the DAC. */ | ||
1570 | fee_read(ioaddr, 0x60, dac_verify, 2); | ||
1571 | |||
1572 | /* Compare. */ | ||
1573 | if (memcmp(area, area_verify, 16 * 2) || | ||
1574 | memcmp(dac, dac_verify, 2 * 2)) { | ||
1575 | #ifdef DEBUG_IOCTL_ERROR | ||
1576 | printk(KERN_INFO | ||
1577 | "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); | ||
1578 | #endif | ||
1579 | return -EOPNOTSUPP; | ||
1580 | } | ||
1581 | |||
1582 | /* We must download the frequency parameters to the | ||
1583 | * synthesizers (from the EEPROM - area 1) | ||
1584 | * Note: as the EEPROM is automatically decremented, we set the end | ||
1585 | * if the area... */ | ||
1586 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); | ||
1587 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
1588 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1589 | |||
1590 | /* Wait until the download is finished. */ | ||
1591 | fee_wait(ioaddr, 100, 100); | ||
1592 | |||
1593 | /* We must now download the power adjust value (gain) to | ||
1594 | * the synthesizers (from the EEPROM - area 7 - DAC). */ | ||
1595 | mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); | ||
1596 | mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), | ||
1597 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1598 | |||
1599 | /* Wait for the download to finish. */ | ||
1600 | fee_wait(ioaddr, 100, 100); | ||
1601 | |||
1602 | #ifdef DEBUG_IOCTL_INFO | ||
1603 | /* Verification of what we have done */ | ||
1604 | |||
1605 | printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); | ||
1606 | for (i = 0; i < 16; i++) { | ||
1607 | printk(" %04X", area_verify[i]); | ||
1608 | } | ||
1609 | printk("\n"); | ||
1610 | |||
1611 | printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", | ||
1612 | dac_verify[0], dac_verify[1]); | ||
1613 | #endif | ||
1614 | |||
1615 | return 0; | ||
1616 | } else | ||
1617 | return -EINVAL; /* Bah, never get there... */ | ||
1618 | } | ||
1619 | |||
1620 | /*------------------------------------------------------------------*/ | ||
1621 | /* | ||
1622 | * Give the list of available frequencies. | ||
1623 | */ | ||
1624 | static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ | ||
1625 | iw_freq * list, /* List of frequencies to fill */ | ||
1626 | int max) | ||
1627 | { /* Maximum number of frequencies */ | ||
1628 | u16 table[10]; /* Authorized frequency table */ | ||
1629 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ | ||
1630 | int i; /* index in the table */ | ||
1631 | int c = 0; /* Channel number */ | ||
1632 | |||
1633 | /* Read the frequency table. */ | ||
1634 | fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); | ||
1635 | |||
1636 | /* Check all frequencies. */ | ||
1637 | i = 0; | ||
1638 | for (freq = 0; freq < 150; freq++) | ||
1639 | /* Look in the table if the frequency is allowed */ | ||
1640 | if (table[9 - (freq / 16)] & (1 << (freq % 16))) { | ||
1641 | /* Compute approximate channel number */ | ||
1642 | while ((c < ARRAY_SIZE(channel_bands)) && | ||
1643 | (((channel_bands[c] >> 1) - 24) < freq)) | ||
1644 | c++; | ||
1645 | list[i].i = c; /* Set the list index */ | ||
1646 | |||
1647 | /* put in the list */ | ||
1648 | list[i].m = (((freq + 24) * 5) + 24000L) * 10000; | ||
1649 | list[i++].e = 1; | ||
1650 | |||
1651 | /* Check number. */ | ||
1652 | if (i >= max) | ||
1653 | return (i); | ||
1654 | } | ||
1655 | |||
1656 | return (i); | ||
1657 | } | ||
1658 | |||
1659 | #ifdef IW_WIRELESS_SPY | ||
1660 | /*------------------------------------------------------------------*/ | ||
1661 | /* | ||
1662 | * Gather wireless spy statistics: for each packet, compare the source | ||
1663 | * address with our list, and if they match, get the statistics. | ||
1664 | * Sorry, but this function really needs the wireless extensions. | ||
1665 | */ | ||
1666 | static inline void wl_spy_gather(struct net_device * dev, | ||
1667 | u8 * mac, /* MAC address */ | ||
1668 | u8 * stats) /* Statistics to gather */ | ||
1669 | { | ||
1670 | struct iw_quality wstats; | ||
1671 | |||
1672 | wstats.qual = stats[2] & MMR_SGNL_QUAL; | ||
1673 | wstats.level = stats[0] & MMR_SIGNAL_LVL; | ||
1674 | wstats.noise = stats[1] & MMR_SILENCE_LVL; | ||
1675 | wstats.updated = 0x7; | ||
1676 | |||
1677 | /* Update spy records */ | ||
1678 | wireless_spy_update(dev, mac, &wstats); | ||
1679 | } | ||
1680 | #endif /* IW_WIRELESS_SPY */ | ||
1681 | |||
1682 | #ifdef HISTOGRAM | ||
1683 | /*------------------------------------------------------------------*/ | ||
1684 | /* | ||
1685 | * This function calculates a histogram of the signal level. | ||
1686 | * As the noise is quite constant, it's like doing it on the SNR. | ||
1687 | * We have defined a set of interval (lp->his_range), and each time | ||
1688 | * the level goes in that interval, we increment the count (lp->his_sum). | ||
1689 | * With this histogram you may detect if one WaveLAN is really weak, | ||
1690 | * or you may also calculate the mean and standard deviation of the level. | ||
1691 | */ | ||
1692 | static inline void wl_his_gather(struct net_device * dev, u8 * stats) | ||
1693 | { /* Statistics to gather */ | ||
1694 | net_local *lp = netdev_priv(dev); | ||
1695 | u8 level = stats[0] & MMR_SIGNAL_LVL; | ||
1696 | int i; | ||
1697 | |||
1698 | /* Find the correct interval. */ | ||
1699 | i = 0; | ||
1700 | while ((i < (lp->his_number - 1)) | ||
1701 | && (level >= lp->his_range[i++])); | ||
1702 | |||
1703 | /* Increment interval counter. */ | ||
1704 | (lp->his_sum[i])++; | ||
1705 | } | ||
1706 | #endif /* HISTOGRAM */ | ||
1707 | |||
1708 | /*------------------------------------------------------------------*/ | ||
1709 | /* | ||
1710 | * Wireless Handler : get protocol name | ||
1711 | */ | ||
1712 | static int wavelan_get_name(struct net_device *dev, | ||
1713 | struct iw_request_info *info, | ||
1714 | union iwreq_data *wrqu, | ||
1715 | char *extra) | ||
1716 | { | ||
1717 | strcpy(wrqu->name, "WaveLAN"); | ||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1721 | /*------------------------------------------------------------------*/ | ||
1722 | /* | ||
1723 | * Wireless Handler : set NWID | ||
1724 | */ | ||
1725 | static int wavelan_set_nwid(struct net_device *dev, | ||
1726 | struct iw_request_info *info, | ||
1727 | union iwreq_data *wrqu, | ||
1728 | char *extra) | ||
1729 | { | ||
1730 | unsigned long ioaddr = dev->base_addr; | ||
1731 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1732 | psa_t psa; | ||
1733 | mm_t m; | ||
1734 | unsigned long flags; | ||
1735 | int ret = 0; | ||
1736 | |||
1737 | /* Disable interrupts and save flags. */ | ||
1738 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1739 | |||
1740 | /* Set NWID in WaveLAN. */ | ||
1741 | if (!wrqu->nwid.disabled) { | ||
1742 | /* Set NWID in psa */ | ||
1743 | psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; | ||
1744 | psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; | ||
1745 | psa.psa_nwid_select = 0x01; | ||
1746 | psa_write(ioaddr, lp->hacr, | ||
1747 | (char *) psa.psa_nwid - (char *) &psa, | ||
1748 | (unsigned char *) psa.psa_nwid, 3); | ||
1749 | |||
1750 | /* Set NWID in mmc. */ | ||
1751 | m.w.mmw_netw_id_l = psa.psa_nwid[1]; | ||
1752 | m.w.mmw_netw_id_h = psa.psa_nwid[0]; | ||
1753 | mmc_write(ioaddr, | ||
1754 | (char *) &m.w.mmw_netw_id_l - | ||
1755 | (char *) &m, | ||
1756 | (unsigned char *) &m.w.mmw_netw_id_l, 2); | ||
1757 | mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); | ||
1758 | } else { | ||
1759 | /* Disable NWID in the psa. */ | ||
1760 | psa.psa_nwid_select = 0x00; | ||
1761 | psa_write(ioaddr, lp->hacr, | ||
1762 | (char *) &psa.psa_nwid_select - | ||
1763 | (char *) &psa, | ||
1764 | (unsigned char *) &psa.psa_nwid_select, | ||
1765 | 1); | ||
1766 | |||
1767 | /* Disable NWID in the mmc (no filtering). */ | ||
1768 | mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), | ||
1769 | MMW_LOOPT_SEL_DIS_NWID); | ||
1770 | } | ||
1771 | /* update the Wavelan checksum */ | ||
1772 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
1773 | |||
1774 | /* Enable interrupts and restore flags. */ | ||
1775 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1776 | |||
1777 | return ret; | ||
1778 | } | ||
1779 | |||
1780 | /*------------------------------------------------------------------*/ | ||
1781 | /* | ||
1782 | * Wireless Handler : get NWID | ||
1783 | */ | ||
1784 | static int wavelan_get_nwid(struct net_device *dev, | ||
1785 | struct iw_request_info *info, | ||
1786 | union iwreq_data *wrqu, | ||
1787 | char *extra) | ||
1788 | { | ||
1789 | unsigned long ioaddr = dev->base_addr; | ||
1790 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1791 | psa_t psa; | ||
1792 | unsigned long flags; | ||
1793 | int ret = 0; | ||
1794 | |||
1795 | /* Disable interrupts and save flags. */ | ||
1796 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1797 | |||
1798 | /* Read the NWID. */ | ||
1799 | psa_read(ioaddr, lp->hacr, | ||
1800 | (char *) psa.psa_nwid - (char *) &psa, | ||
1801 | (unsigned char *) psa.psa_nwid, 3); | ||
1802 | wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; | ||
1803 | wrqu->nwid.disabled = !(psa.psa_nwid_select); | ||
1804 | wrqu->nwid.fixed = 1; /* Superfluous */ | ||
1805 | |||
1806 | /* Enable interrupts and restore flags. */ | ||
1807 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1808 | |||
1809 | return ret; | ||
1810 | } | ||
1811 | |||
1812 | /*------------------------------------------------------------------*/ | ||
1813 | /* | ||
1814 | * Wireless Handler : set frequency | ||
1815 | */ | ||
1816 | static int wavelan_set_freq(struct net_device *dev, | ||
1817 | struct iw_request_info *info, | ||
1818 | union iwreq_data *wrqu, | ||
1819 | char *extra) | ||
1820 | { | ||
1821 | unsigned long ioaddr = dev->base_addr; | ||
1822 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1823 | unsigned long flags; | ||
1824 | int ret; | ||
1825 | |||
1826 | /* Disable interrupts and save flags. */ | ||
1827 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1828 | |||
1829 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
1830 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
1831 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
1832 | ret = wv_set_frequency(ioaddr, &(wrqu->freq)); | ||
1833 | else | ||
1834 | ret = -EOPNOTSUPP; | ||
1835 | |||
1836 | /* Enable interrupts and restore flags. */ | ||
1837 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1838 | |||
1839 | return ret; | ||
1840 | } | ||
1841 | |||
1842 | /*------------------------------------------------------------------*/ | ||
1843 | /* | ||
1844 | * Wireless Handler : get frequency | ||
1845 | */ | ||
1846 | static int wavelan_get_freq(struct net_device *dev, | ||
1847 | struct iw_request_info *info, | ||
1848 | union iwreq_data *wrqu, | ||
1849 | char *extra) | ||
1850 | { | ||
1851 | unsigned long ioaddr = dev->base_addr; | ||
1852 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1853 | psa_t psa; | ||
1854 | unsigned long flags; | ||
1855 | int ret = 0; | ||
1856 | |||
1857 | /* Disable interrupts and save flags. */ | ||
1858 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1859 | |||
1860 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). | ||
1861 | * Does it work for everybody, especially old cards? */ | ||
1862 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
1863 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
1864 | unsigned short freq; | ||
1865 | |||
1866 | /* Ask the EEPROM to read the frequency from the first area. */ | ||
1867 | fee_read(ioaddr, 0x00, &freq, 1); | ||
1868 | wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; | ||
1869 | wrqu->freq.e = 1; | ||
1870 | } else { | ||
1871 | psa_read(ioaddr, lp->hacr, | ||
1872 | (char *) &psa.psa_subband - (char *) &psa, | ||
1873 | (unsigned char *) &psa.psa_subband, 1); | ||
1874 | |||
1875 | if (psa.psa_subband <= 4) { | ||
1876 | wrqu->freq.m = fixed_bands[psa.psa_subband]; | ||
1877 | wrqu->freq.e = (psa.psa_subband != 0); | ||
1878 | } else | ||
1879 | ret = -EOPNOTSUPP; | ||
1880 | } | ||
1881 | |||
1882 | /* Enable interrupts and restore flags. */ | ||
1883 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1884 | |||
1885 | return ret; | ||
1886 | } | ||
1887 | |||
1888 | /*------------------------------------------------------------------*/ | ||
1889 | /* | ||
1890 | * Wireless Handler : set level threshold | ||
1891 | */ | ||
1892 | static int wavelan_set_sens(struct net_device *dev, | ||
1893 | struct iw_request_info *info, | ||
1894 | union iwreq_data *wrqu, | ||
1895 | char *extra) | ||
1896 | { | ||
1897 | unsigned long ioaddr = dev->base_addr; | ||
1898 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1899 | psa_t psa; | ||
1900 | unsigned long flags; | ||
1901 | int ret = 0; | ||
1902 | |||
1903 | /* Disable interrupts and save flags. */ | ||
1904 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1905 | |||
1906 | /* Set the level threshold. */ | ||
1907 | /* We should complain loudly if wrqu->sens.fixed = 0, because we | ||
1908 | * can't set auto mode... */ | ||
1909 | psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; | ||
1910 | psa_write(ioaddr, lp->hacr, | ||
1911 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
1912 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
1913 | /* update the Wavelan checksum */ | ||
1914 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
1915 | mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), | ||
1916 | psa.psa_thr_pre_set); | ||
1917 | |||
1918 | /* Enable interrupts and restore flags. */ | ||
1919 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1920 | |||
1921 | return ret; | ||
1922 | } | ||
1923 | |||
1924 | /*------------------------------------------------------------------*/ | ||
1925 | /* | ||
1926 | * Wireless Handler : get level threshold | ||
1927 | */ | ||
1928 | static int wavelan_get_sens(struct net_device *dev, | ||
1929 | struct iw_request_info *info, | ||
1930 | union iwreq_data *wrqu, | ||
1931 | char *extra) | ||
1932 | { | ||
1933 | unsigned long ioaddr = dev->base_addr; | ||
1934 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1935 | psa_t psa; | ||
1936 | unsigned long flags; | ||
1937 | int ret = 0; | ||
1938 | |||
1939 | /* Disable interrupts and save flags. */ | ||
1940 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1941 | |||
1942 | /* Read the level threshold. */ | ||
1943 | psa_read(ioaddr, lp->hacr, | ||
1944 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
1945 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
1946 | wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; | ||
1947 | wrqu->sens.fixed = 1; | ||
1948 | |||
1949 | /* Enable interrupts and restore flags. */ | ||
1950 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1951 | |||
1952 | return ret; | ||
1953 | } | ||
1954 | |||
1955 | /*------------------------------------------------------------------*/ | ||
1956 | /* | ||
1957 | * Wireless Handler : set encryption key | ||
1958 | */ | ||
1959 | static int wavelan_set_encode(struct net_device *dev, | ||
1960 | struct iw_request_info *info, | ||
1961 | union iwreq_data *wrqu, | ||
1962 | char *extra) | ||
1963 | { | ||
1964 | unsigned long ioaddr = dev->base_addr; | ||
1965 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
1966 | unsigned long flags; | ||
1967 | psa_t psa; | ||
1968 | int ret = 0; | ||
1969 | |||
1970 | /* Disable interrupts and save flags. */ | ||
1971 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1972 | |||
1973 | /* Check if capable of encryption */ | ||
1974 | if (!mmc_encr(ioaddr)) { | ||
1975 | ret = -EOPNOTSUPP; | ||
1976 | } | ||
1977 | |||
1978 | /* Check the size of the key */ | ||
1979 | if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { | ||
1980 | ret = -EINVAL; | ||
1981 | } | ||
1982 | |||
1983 | if(!ret) { | ||
1984 | /* Basic checking... */ | ||
1985 | if (wrqu->encoding.length == 8) { | ||
1986 | /* Copy the key in the driver */ | ||
1987 | memcpy(psa.psa_encryption_key, extra, | ||
1988 | wrqu->encoding.length); | ||
1989 | psa.psa_encryption_select = 1; | ||
1990 | |||
1991 | psa_write(ioaddr, lp->hacr, | ||
1992 | (char *) &psa.psa_encryption_select - | ||
1993 | (char *) &psa, | ||
1994 | (unsigned char *) &psa. | ||
1995 | psa_encryption_select, 8 + 1); | ||
1996 | |||
1997 | mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), | ||
1998 | MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); | ||
1999 | mmc_write(ioaddr, mmwoff(0, mmw_encr_key), | ||
2000 | (unsigned char *) &psa. | ||
2001 | psa_encryption_key, 8); | ||
2002 | } | ||
2003 | |||
2004 | /* disable encryption */ | ||
2005 | if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { | ||
2006 | psa.psa_encryption_select = 0; | ||
2007 | psa_write(ioaddr, lp->hacr, | ||
2008 | (char *) &psa.psa_encryption_select - | ||
2009 | (char *) &psa, | ||
2010 | (unsigned char *) &psa. | ||
2011 | psa_encryption_select, 1); | ||
2012 | |||
2013 | mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); | ||
2014 | } | ||
2015 | /* update the Wavelan checksum */ | ||
2016 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
2017 | } | ||
2018 | |||
2019 | /* Enable interrupts and restore flags. */ | ||
2020 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2021 | |||
2022 | return ret; | ||
2023 | } | ||
2024 | |||
2025 | /*------------------------------------------------------------------*/ | ||
2026 | /* | ||
2027 | * Wireless Handler : get encryption key | ||
2028 | */ | ||
2029 | static int wavelan_get_encode(struct net_device *dev, | ||
2030 | struct iw_request_info *info, | ||
2031 | union iwreq_data *wrqu, | ||
2032 | char *extra) | ||
2033 | { | ||
2034 | unsigned long ioaddr = dev->base_addr; | ||
2035 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
2036 | psa_t psa; | ||
2037 | unsigned long flags; | ||
2038 | int ret = 0; | ||
2039 | |||
2040 | /* Disable interrupts and save flags. */ | ||
2041 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2042 | |||
2043 | /* Check if encryption is available */ | ||
2044 | if (!mmc_encr(ioaddr)) { | ||
2045 | ret = -EOPNOTSUPP; | ||
2046 | } else { | ||
2047 | /* Read the encryption key */ | ||
2048 | psa_read(ioaddr, lp->hacr, | ||
2049 | (char *) &psa.psa_encryption_select - | ||
2050 | (char *) &psa, | ||
2051 | (unsigned char *) &psa. | ||
2052 | psa_encryption_select, 1 + 8); | ||
2053 | |||
2054 | /* encryption is enabled ? */ | ||
2055 | if (psa.psa_encryption_select) | ||
2056 | wrqu->encoding.flags = IW_ENCODE_ENABLED; | ||
2057 | else | ||
2058 | wrqu->encoding.flags = IW_ENCODE_DISABLED; | ||
2059 | wrqu->encoding.flags |= mmc_encr(ioaddr); | ||
2060 | |||
2061 | /* Copy the key to the user buffer */ | ||
2062 | wrqu->encoding.length = 8; | ||
2063 | memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); | ||
2064 | } | ||
2065 | |||
2066 | /* Enable interrupts and restore flags. */ | ||
2067 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2068 | |||
2069 | return ret; | ||
2070 | } | ||
2071 | |||
2072 | /*------------------------------------------------------------------*/ | ||
2073 | /* | ||
2074 | * Wireless Handler : get range info | ||
2075 | */ | ||
2076 | static int wavelan_get_range(struct net_device *dev, | ||
2077 | struct iw_request_info *info, | ||
2078 | union iwreq_data *wrqu, | ||
2079 | char *extra) | ||
2080 | { | ||
2081 | unsigned long ioaddr = dev->base_addr; | ||
2082 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
2083 | struct iw_range *range = (struct iw_range *) extra; | ||
2084 | unsigned long flags; | ||
2085 | int ret = 0; | ||
2086 | |||
2087 | /* Set the length (very important for backward compatibility) */ | ||
2088 | wrqu->data.length = sizeof(struct iw_range); | ||
2089 | |||
2090 | /* Set all the info we don't care or don't know about to zero */ | ||
2091 | memset(range, 0, sizeof(struct iw_range)); | ||
2092 | |||
2093 | /* Set the Wireless Extension versions */ | ||
2094 | range->we_version_compiled = WIRELESS_EXT; | ||
2095 | range->we_version_source = 9; | ||
2096 | |||
2097 | /* Set information in the range struct. */ | ||
2098 | range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ | ||
2099 | range->min_nwid = 0x0000; | ||
2100 | range->max_nwid = 0xFFFF; | ||
2101 | |||
2102 | range->sensitivity = 0x3F; | ||
2103 | range->max_qual.qual = MMR_SGNL_QUAL; | ||
2104 | range->max_qual.level = MMR_SIGNAL_LVL; | ||
2105 | range->max_qual.noise = MMR_SILENCE_LVL; | ||
2106 | range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ | ||
2107 | /* Need to get better values for those two */ | ||
2108 | range->avg_qual.level = 30; | ||
2109 | range->avg_qual.noise = 8; | ||
2110 | |||
2111 | range->num_bitrates = 1; | ||
2112 | range->bitrate[0] = 2000000; /* 2 Mb/s */ | ||
2113 | |||
2114 | /* Event capability (kernel + driver) */ | ||
2115 | range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | | ||
2116 | IW_EVENT_CAPA_MASK(0x8B04)); | ||
2117 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
2118 | |||
2119 | /* Disable interrupts and save flags. */ | ||
2120 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2121 | |||
2122 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
2123 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
2124 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
2125 | range->num_channels = 10; | ||
2126 | range->num_frequency = wv_frequency_list(ioaddr, range->freq, | ||
2127 | IW_MAX_FREQUENCIES); | ||
2128 | } else | ||
2129 | range->num_channels = range->num_frequency = 0; | ||
2130 | |||
2131 | /* Encryption supported ? */ | ||
2132 | if (mmc_encr(ioaddr)) { | ||
2133 | range->encoding_size[0] = 8; /* DES = 64 bits key */ | ||
2134 | range->num_encoding_sizes = 1; | ||
2135 | range->max_encoding_tokens = 1; /* Only one key possible */ | ||
2136 | } else { | ||
2137 | range->num_encoding_sizes = 0; | ||
2138 | range->max_encoding_tokens = 0; | ||
2139 | } | ||
2140 | |||
2141 | /* Enable interrupts and restore flags. */ | ||
2142 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2143 | |||
2144 | return ret; | ||
2145 | } | ||
2146 | |||
2147 | /*------------------------------------------------------------------*/ | ||
2148 | /* | ||
2149 | * Wireless Private Handler : set quality threshold | ||
2150 | */ | ||
2151 | static int wavelan_set_qthr(struct net_device *dev, | ||
2152 | struct iw_request_info *info, | ||
2153 | union iwreq_data *wrqu, | ||
2154 | char *extra) | ||
2155 | { | ||
2156 | unsigned long ioaddr = dev->base_addr; | ||
2157 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
2158 | psa_t psa; | ||
2159 | unsigned long flags; | ||
2160 | |||
2161 | /* Disable interrupts and save flags. */ | ||
2162 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2163 | |||
2164 | psa.psa_quality_thr = *(extra) & 0x0F; | ||
2165 | psa_write(ioaddr, lp->hacr, | ||
2166 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2167 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2168 | /* update the Wavelan checksum */ | ||
2169 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
2170 | mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), | ||
2171 | psa.psa_quality_thr); | ||
2172 | |||
2173 | /* Enable interrupts and restore flags. */ | ||
2174 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2175 | |||
2176 | return 0; | ||
2177 | } | ||
2178 | |||
2179 | /*------------------------------------------------------------------*/ | ||
2180 | /* | ||
2181 | * Wireless Private Handler : get quality threshold | ||
2182 | */ | ||
2183 | static int wavelan_get_qthr(struct net_device *dev, | ||
2184 | struct iw_request_info *info, | ||
2185 | union iwreq_data *wrqu, | ||
2186 | char *extra) | ||
2187 | { | ||
2188 | unsigned long ioaddr = dev->base_addr; | ||
2189 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
2190 | psa_t psa; | ||
2191 | unsigned long flags; | ||
2192 | |||
2193 | /* Disable interrupts and save flags. */ | ||
2194 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2195 | |||
2196 | psa_read(ioaddr, lp->hacr, | ||
2197 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2198 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2199 | *(extra) = psa.psa_quality_thr & 0x0F; | ||
2200 | |||
2201 | /* Enable interrupts and restore flags. */ | ||
2202 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2203 | |||
2204 | return 0; | ||
2205 | } | ||
2206 | |||
2207 | #ifdef HISTOGRAM | ||
2208 | /*------------------------------------------------------------------*/ | ||
2209 | /* | ||
2210 | * Wireless Private Handler : set histogram | ||
2211 | */ | ||
2212 | static int wavelan_set_histo(struct net_device *dev, | ||
2213 | struct iw_request_info *info, | ||
2214 | union iwreq_data *wrqu, | ||
2215 | char *extra) | ||
2216 | { | ||
2217 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
2218 | |||
2219 | /* Check the number of intervals. */ | ||
2220 | if (wrqu->data.length > 16) { | ||
2221 | return(-E2BIG); | ||
2222 | } | ||
2223 | |||
2224 | /* Disable histo while we copy the addresses. | ||
2225 | * As we don't disable interrupts, we need to do this */ | ||
2226 | lp->his_number = 0; | ||
2227 | |||
2228 | /* Are there ranges to copy? */ | ||
2229 | if (wrqu->data.length > 0) { | ||
2230 | /* Copy interval ranges to the driver */ | ||
2231 | memcpy(lp->his_range, extra, wrqu->data.length); | ||
2232 | |||
2233 | { | ||
2234 | int i; | ||
2235 | printk(KERN_DEBUG "Histo :"); | ||
2236 | for(i = 0; i < wrqu->data.length; i++) | ||
2237 | printk(" %d", lp->his_range[i]); | ||
2238 | printk("\n"); | ||
2239 | } | ||
2240 | |||
2241 | /* Reset result structure. */ | ||
2242 | memset(lp->his_sum, 0x00, sizeof(long) * 16); | ||
2243 | } | ||
2244 | |||
2245 | /* Now we can set the number of ranges */ | ||
2246 | lp->his_number = wrqu->data.length; | ||
2247 | |||
2248 | return(0); | ||
2249 | } | ||
2250 | |||
2251 | /*------------------------------------------------------------------*/ | ||
2252 | /* | ||
2253 | * Wireless Private Handler : get histogram | ||
2254 | */ | ||
2255 | static int wavelan_get_histo(struct net_device *dev, | ||
2256 | struct iw_request_info *info, | ||
2257 | union iwreq_data *wrqu, | ||
2258 | char *extra) | ||
2259 | { | ||
2260 | net_local *lp = netdev_priv(dev); /* lp is not unused */ | ||
2261 | |||
2262 | /* Set the number of intervals. */ | ||
2263 | wrqu->data.length = lp->his_number; | ||
2264 | |||
2265 | /* Give back the distribution statistics */ | ||
2266 | if(lp->his_number > 0) | ||
2267 | memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); | ||
2268 | |||
2269 | return(0); | ||
2270 | } | ||
2271 | #endif /* HISTOGRAM */ | ||
2272 | |||
2273 | /*------------------------------------------------------------------*/ | ||
2274 | /* | ||
2275 | * Structures to export the Wireless Handlers | ||
2276 | */ | ||
2277 | |||
2278 | static const iw_handler wavelan_handler[] = | ||
2279 | { | ||
2280 | NULL, /* SIOCSIWNAME */ | ||
2281 | wavelan_get_name, /* SIOCGIWNAME */ | ||
2282 | wavelan_set_nwid, /* SIOCSIWNWID */ | ||
2283 | wavelan_get_nwid, /* SIOCGIWNWID */ | ||
2284 | wavelan_set_freq, /* SIOCSIWFREQ */ | ||
2285 | wavelan_get_freq, /* SIOCGIWFREQ */ | ||
2286 | NULL, /* SIOCSIWMODE */ | ||
2287 | NULL, /* SIOCGIWMODE */ | ||
2288 | wavelan_set_sens, /* SIOCSIWSENS */ | ||
2289 | wavelan_get_sens, /* SIOCGIWSENS */ | ||
2290 | NULL, /* SIOCSIWRANGE */ | ||
2291 | wavelan_get_range, /* SIOCGIWRANGE */ | ||
2292 | NULL, /* SIOCSIWPRIV */ | ||
2293 | NULL, /* SIOCGIWPRIV */ | ||
2294 | NULL, /* SIOCSIWSTATS */ | ||
2295 | NULL, /* SIOCGIWSTATS */ | ||
2296 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2297 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2298 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2299 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2300 | NULL, /* SIOCSIWAP */ | ||
2301 | NULL, /* SIOCGIWAP */ | ||
2302 | NULL, /* -- hole -- */ | ||
2303 | NULL, /* SIOCGIWAPLIST */ | ||
2304 | NULL, /* -- hole -- */ | ||
2305 | NULL, /* -- hole -- */ | ||
2306 | NULL, /* SIOCSIWESSID */ | ||
2307 | NULL, /* SIOCGIWESSID */ | ||
2308 | NULL, /* SIOCSIWNICKN */ | ||
2309 | NULL, /* SIOCGIWNICKN */ | ||
2310 | NULL, /* -- hole -- */ | ||
2311 | NULL, /* -- hole -- */ | ||
2312 | NULL, /* SIOCSIWRATE */ | ||
2313 | NULL, /* SIOCGIWRATE */ | ||
2314 | NULL, /* SIOCSIWRTS */ | ||
2315 | NULL, /* SIOCGIWRTS */ | ||
2316 | NULL, /* SIOCSIWFRAG */ | ||
2317 | NULL, /* SIOCGIWFRAG */ | ||
2318 | NULL, /* SIOCSIWTXPOW */ | ||
2319 | NULL, /* SIOCGIWTXPOW */ | ||
2320 | NULL, /* SIOCSIWRETRY */ | ||
2321 | NULL, /* SIOCGIWRETRY */ | ||
2322 | /* Bummer ! Why those are only at the end ??? */ | ||
2323 | wavelan_set_encode, /* SIOCSIWENCODE */ | ||
2324 | wavelan_get_encode, /* SIOCGIWENCODE */ | ||
2325 | }; | ||
2326 | |||
2327 | static const iw_handler wavelan_private_handler[] = | ||
2328 | { | ||
2329 | wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ | ||
2330 | wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ | ||
2331 | #ifdef HISTOGRAM | ||
2332 | wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ | ||
2333 | wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ | ||
2334 | #endif /* HISTOGRAM */ | ||
2335 | }; | ||
2336 | |||
2337 | static const struct iw_priv_args wavelan_private_args[] = { | ||
2338 | /*{ cmd, set_args, get_args, name } */ | ||
2339 | { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, | ||
2340 | { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, | ||
2341 | { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, | ||
2342 | { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, | ||
2343 | }; | ||
2344 | |||
2345 | static const struct iw_handler_def wavelan_handler_def = | ||
2346 | { | ||
2347 | .num_standard = ARRAY_SIZE(wavelan_handler), | ||
2348 | .num_private = ARRAY_SIZE(wavelan_private_handler), | ||
2349 | .num_private_args = ARRAY_SIZE(wavelan_private_args), | ||
2350 | .standard = wavelan_handler, | ||
2351 | .private = wavelan_private_handler, | ||
2352 | .private_args = wavelan_private_args, | ||
2353 | .get_wireless_stats = wavelan_get_wireless_stats, | ||
2354 | }; | ||
2355 | |||
2356 | /*------------------------------------------------------------------*/ | ||
2357 | /* | ||
2358 | * Get wireless statistics. | ||
2359 | * Called by /proc/net/wireless | ||
2360 | */ | ||
2361 | static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) | ||
2362 | { | ||
2363 | unsigned long ioaddr = dev->base_addr; | ||
2364 | net_local *lp = netdev_priv(dev); | ||
2365 | mmr_t m; | ||
2366 | iw_stats *wstats; | ||
2367 | unsigned long flags; | ||
2368 | |||
2369 | #ifdef DEBUG_IOCTL_TRACE | ||
2370 | printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", | ||
2371 | dev->name); | ||
2372 | #endif | ||
2373 | |||
2374 | /* Check */ | ||
2375 | if (lp == (net_local *) NULL) | ||
2376 | return (iw_stats *) NULL; | ||
2377 | |||
2378 | /* Disable interrupts and save flags. */ | ||
2379 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2380 | |||
2381 | wstats = &lp->wstats; | ||
2382 | |||
2383 | /* Get data from the mmc. */ | ||
2384 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); | ||
2385 | |||
2386 | mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); | ||
2387 | mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, | ||
2388 | 2); | ||
2389 | mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, | ||
2390 | 4); | ||
2391 | |||
2392 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); | ||
2393 | |||
2394 | /* Copy data to wireless stuff. */ | ||
2395 | wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; | ||
2396 | wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; | ||
2397 | wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; | ||
2398 | wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; | ||
2399 | wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | ||
2400 | | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | ||
2401 | | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); | ||
2402 | wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
2403 | wstats->discard.code = 0L; | ||
2404 | wstats->discard.misc = 0L; | ||
2405 | |||
2406 | /* Enable interrupts and restore flags. */ | ||
2407 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2408 | |||
2409 | #ifdef DEBUG_IOCTL_TRACE | ||
2410 | printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", | ||
2411 | dev->name); | ||
2412 | #endif | ||
2413 | return &lp->wstats; | ||
2414 | } | ||
2415 | |||
2416 | /************************* PACKET RECEPTION *************************/ | ||
2417 | /* | ||
2418 | * This part deals with receiving the packets. | ||
2419 | * The interrupt handler gets an interrupt when a packet has been | ||
2420 | * successfully received and calls this part. | ||
2421 | */ | ||
2422 | |||
2423 | /*------------------------------------------------------------------*/ | ||
2424 | /* | ||
2425 | * This routine does the actual copying of data (including the Ethernet | ||
2426 | * header structure) from the WaveLAN card to an sk_buff chain that | ||
2427 | * will be passed up to the network interface layer. NOTE: we | ||
2428 | * currently don't handle trailer protocols (neither does the rest of | ||
2429 | * the network interface), so if that is needed, it will (at least in | ||
2430 | * part) be added here. The contents of the receive ring buffer are | ||
2431 | * copied to a message chain that is then passed to the kernel. | ||
2432 | * | ||
2433 | * Note: if any errors occur, the packet is "dropped on the floor". | ||
2434 | * (called by wv_packet_rcv()) | ||
2435 | */ | ||
2436 | static void | ||
2437 | wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) | ||
2438 | { | ||
2439 | net_local *lp = netdev_priv(dev); | ||
2440 | unsigned long ioaddr = dev->base_addr; | ||
2441 | struct sk_buff *skb; | ||
2442 | |||
2443 | #ifdef DEBUG_RX_TRACE | ||
2444 | printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", | ||
2445 | dev->name, buf_off, sksize); | ||
2446 | #endif | ||
2447 | |||
2448 | /* Allocate buffer for the data */ | ||
2449 | if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) { | ||
2450 | #ifdef DEBUG_RX_ERROR | ||
2451 | printk(KERN_INFO | ||
2452 | "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", | ||
2453 | dev->name, sksize); | ||
2454 | #endif | ||
2455 | dev->stats.rx_dropped++; | ||
2456 | return; | ||
2457 | } | ||
2458 | |||
2459 | /* Copy the packet to the buffer. */ | ||
2460 | obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); | ||
2461 | skb->protocol = eth_type_trans(skb, dev); | ||
2462 | |||
2463 | #ifdef DEBUG_RX_INFO | ||
2464 | wv_packet_info(skb_mac_header(skb), sksize, dev->name, | ||
2465 | "wv_packet_read"); | ||
2466 | #endif /* DEBUG_RX_INFO */ | ||
2467 | |||
2468 | /* Statistics-gathering and associated stuff. | ||
2469 | * It seem a bit messy with all the define, but it's really | ||
2470 | * simple... */ | ||
2471 | if ( | ||
2472 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
2473 | (lp->spy_data.spy_number > 0) || | ||
2474 | #endif /* IW_WIRELESS_SPY */ | ||
2475 | #ifdef HISTOGRAM | ||
2476 | (lp->his_number > 0) || | ||
2477 | #endif /* HISTOGRAM */ | ||
2478 | 0) { | ||
2479 | u8 stats[3]; /* signal level, noise level, signal quality */ | ||
2480 | |||
2481 | /* Read signal level, silence level and signal quality bytes */ | ||
2482 | /* Note: in the PCMCIA hardware, these are part of the frame. | ||
2483 | * It seems that for the ISA hardware, it's nowhere to be | ||
2484 | * found in the frame, so I'm obliged to do this (it has a | ||
2485 | * side effect on /proc/net/wireless). | ||
2486 | * Any ideas? | ||
2487 | */ | ||
2488 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); | ||
2489 | mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); | ||
2490 | mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); | ||
2491 | |||
2492 | #ifdef DEBUG_RX_INFO | ||
2493 | printk(KERN_DEBUG | ||
2494 | "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", | ||
2495 | dev->name, stats[0] & 0x3F, stats[1] & 0x3F, | ||
2496 | stats[2] & 0x0F); | ||
2497 | #endif | ||
2498 | |||
2499 | /* Spying stuff */ | ||
2500 | #ifdef IW_WIRELESS_SPY | ||
2501 | wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, | ||
2502 | stats); | ||
2503 | #endif /* IW_WIRELESS_SPY */ | ||
2504 | #ifdef HISTOGRAM | ||
2505 | wl_his_gather(dev, stats); | ||
2506 | #endif /* HISTOGRAM */ | ||
2507 | } | ||
2508 | |||
2509 | /* | ||
2510 | * Hand the packet to the network module. | ||
2511 | */ | ||
2512 | netif_rx(skb); | ||
2513 | |||
2514 | /* Keep statistics up to date */ | ||
2515 | dev->stats.rx_packets++; | ||
2516 | dev->stats.rx_bytes += sksize; | ||
2517 | |||
2518 | #ifdef DEBUG_RX_TRACE | ||
2519 | printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); | ||
2520 | #endif | ||
2521 | } | ||
2522 | |||
2523 | /*------------------------------------------------------------------*/ | ||
2524 | /* | ||
2525 | * Transfer as many packets as we can | ||
2526 | * from the device RAM. | ||
2527 | * (called in wavelan_interrupt()). | ||
2528 | * Note : the spinlock is already grabbed for us. | ||
2529 | */ | ||
2530 | static void wv_receive(struct net_device * dev) | ||
2531 | { | ||
2532 | unsigned long ioaddr = dev->base_addr; | ||
2533 | net_local *lp = netdev_priv(dev); | ||
2534 | fd_t fd; | ||
2535 | rbd_t rbd; | ||
2536 | int nreaped = 0; | ||
2537 | |||
2538 | #ifdef DEBUG_RX_TRACE | ||
2539 | printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); | ||
2540 | #endif | ||
2541 | |||
2542 | /* Loop on each received packet. */ | ||
2543 | for (;;) { | ||
2544 | obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, | ||
2545 | sizeof(fd)); | ||
2546 | |||
2547 | /* Note about the status : | ||
2548 | * It start up to be 0 (the value we set). Then, when the RU | ||
2549 | * grab the buffer to prepare for reception, it sets the | ||
2550 | * FD_STATUS_B flag. When the RU has finished receiving the | ||
2551 | * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate | ||
2552 | * completion and set the other flags to indicate the eventual | ||
2553 | * errors. FD_STATUS_OK indicates that the reception was OK. | ||
2554 | */ | ||
2555 | |||
2556 | /* If the current frame is not complete, we have reached the end. */ | ||
2557 | if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) | ||
2558 | break; /* This is how we exit the loop. */ | ||
2559 | |||
2560 | nreaped++; | ||
2561 | |||
2562 | /* Check whether frame was correctly received. */ | ||
2563 | if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { | ||
2564 | /* Does the frame contain a pointer to the data? Let's check. */ | ||
2565 | if (fd.fd_rbd_offset != I82586NULL) { | ||
2566 | /* Read the receive buffer descriptor */ | ||
2567 | obram_read(ioaddr, fd.fd_rbd_offset, | ||
2568 | (unsigned char *) &rbd, | ||
2569 | sizeof(rbd)); | ||
2570 | |||
2571 | #ifdef DEBUG_RX_ERROR | ||
2572 | if ((rbd.rbd_status & RBD_STATUS_EOF) != | ||
2573 | RBD_STATUS_EOF) printk(KERN_INFO | ||
2574 | "%s: wv_receive(): missing EOF flag.\n", | ||
2575 | dev->name); | ||
2576 | |||
2577 | if ((rbd.rbd_status & RBD_STATUS_F) != | ||
2578 | RBD_STATUS_F) printk(KERN_INFO | ||
2579 | "%s: wv_receive(): missing F flag.\n", | ||
2580 | dev->name); | ||
2581 | #endif /* DEBUG_RX_ERROR */ | ||
2582 | |||
2583 | /* Read the packet and transmit to Linux */ | ||
2584 | wv_packet_read(dev, rbd.rbd_bufl, | ||
2585 | rbd. | ||
2586 | rbd_status & | ||
2587 | RBD_STATUS_ACNT); | ||
2588 | } | ||
2589 | #ifdef DEBUG_RX_ERROR | ||
2590 | else /* if frame has no data */ | ||
2591 | printk(KERN_INFO | ||
2592 | "%s: wv_receive(): frame has no data.\n", | ||
2593 | dev->name); | ||
2594 | #endif | ||
2595 | } else { /* If reception was no successful */ | ||
2596 | |||
2597 | dev->stats.rx_errors++; | ||
2598 | |||
2599 | #ifdef DEBUG_RX_INFO | ||
2600 | printk(KERN_DEBUG | ||
2601 | "%s: wv_receive(): frame not received successfully (%X).\n", | ||
2602 | dev->name, fd.fd_status); | ||
2603 | #endif | ||
2604 | |||
2605 | #ifdef DEBUG_RX_ERROR | ||
2606 | if ((fd.fd_status & FD_STATUS_S6) != 0) | ||
2607 | printk(KERN_INFO | ||
2608 | "%s: wv_receive(): no EOF flag.\n", | ||
2609 | dev->name); | ||
2610 | #endif | ||
2611 | |||
2612 | if ((fd.fd_status & FD_STATUS_S7) != 0) { | ||
2613 | dev->stats.rx_length_errors++; | ||
2614 | #ifdef DEBUG_RX_FAIL | ||
2615 | printk(KERN_DEBUG | ||
2616 | "%s: wv_receive(): frame too short.\n", | ||
2617 | dev->name); | ||
2618 | #endif | ||
2619 | } | ||
2620 | |||
2621 | if ((fd.fd_status & FD_STATUS_S8) != 0) { | ||
2622 | dev->stats.rx_over_errors++; | ||
2623 | #ifdef DEBUG_RX_FAIL | ||
2624 | printk(KERN_DEBUG | ||
2625 | "%s: wv_receive(): rx DMA overrun.\n", | ||
2626 | dev->name); | ||
2627 | #endif | ||
2628 | } | ||
2629 | |||
2630 | if ((fd.fd_status & FD_STATUS_S9) != 0) { | ||
2631 | dev->stats.rx_fifo_errors++; | ||
2632 | #ifdef DEBUG_RX_FAIL | ||
2633 | printk(KERN_DEBUG | ||
2634 | "%s: wv_receive(): ran out of resources.\n", | ||
2635 | dev->name); | ||
2636 | #endif | ||
2637 | } | ||
2638 | |||
2639 | if ((fd.fd_status & FD_STATUS_S10) != 0) { | ||
2640 | dev->stats.rx_frame_errors++; | ||
2641 | #ifdef DEBUG_RX_FAIL | ||
2642 | printk(KERN_DEBUG | ||
2643 | "%s: wv_receive(): alignment error.\n", | ||
2644 | dev->name); | ||
2645 | #endif | ||
2646 | } | ||
2647 | |||
2648 | if ((fd.fd_status & FD_STATUS_S11) != 0) { | ||
2649 | dev->stats.rx_crc_errors++; | ||
2650 | #ifdef DEBUG_RX_FAIL | ||
2651 | printk(KERN_DEBUG | ||
2652 | "%s: wv_receive(): CRC error.\n", | ||
2653 | dev->name); | ||
2654 | #endif | ||
2655 | } | ||
2656 | } | ||
2657 | |||
2658 | fd.fd_status = 0; | ||
2659 | obram_write(ioaddr, fdoff(lp->rx_head, fd_status), | ||
2660 | (unsigned char *) &fd.fd_status, | ||
2661 | sizeof(fd.fd_status)); | ||
2662 | |||
2663 | fd.fd_command = FD_COMMAND_EL; | ||
2664 | obram_write(ioaddr, fdoff(lp->rx_head, fd_command), | ||
2665 | (unsigned char *) &fd.fd_command, | ||
2666 | sizeof(fd.fd_command)); | ||
2667 | |||
2668 | fd.fd_command = 0; | ||
2669 | obram_write(ioaddr, fdoff(lp->rx_last, fd_command), | ||
2670 | (unsigned char *) &fd.fd_command, | ||
2671 | sizeof(fd.fd_command)); | ||
2672 | |||
2673 | lp->rx_last = lp->rx_head; | ||
2674 | lp->rx_head = fd.fd_link_offset; | ||
2675 | } /* for(;;) -> loop on all frames */ | ||
2676 | |||
2677 | #ifdef DEBUG_RX_INFO | ||
2678 | if (nreaped > 1) | ||
2679 | printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", | ||
2680 | dev->name, nreaped); | ||
2681 | #endif | ||
2682 | #ifdef DEBUG_RX_TRACE | ||
2683 | printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); | ||
2684 | #endif | ||
2685 | } | ||
2686 | |||
2687 | /*********************** PACKET TRANSMISSION ***********************/ | ||
2688 | /* | ||
2689 | * This part deals with sending packets through the WaveLAN. | ||
2690 | * | ||
2691 | */ | ||
2692 | |||
2693 | /*------------------------------------------------------------------*/ | ||
2694 | /* | ||
2695 | * This routine fills in the appropriate registers and memory | ||
2696 | * locations on the WaveLAN card and starts the card off on | ||
2697 | * the transmit. | ||
2698 | * | ||
2699 | * The principle: | ||
2700 | * Each block contains a transmit command, a NOP command, | ||
2701 | * a transmit block descriptor and a buffer. | ||
2702 | * The CU read the transmit block which point to the tbd, | ||
2703 | * read the tbd and the content of the buffer. | ||
2704 | * When it has finish with it, it goes to the next command | ||
2705 | * which in our case is the NOP. The NOP points on itself, | ||
2706 | * so the CU stop here. | ||
2707 | * When we add the next block, we modify the previous nop | ||
2708 | * to make it point on the new tx command. | ||
2709 | * Simple, isn't it ? | ||
2710 | * | ||
2711 | * (called in wavelan_packet_xmit()) | ||
2712 | */ | ||
2713 | static int wv_packet_write(struct net_device * dev, void *buf, short length) | ||
2714 | { | ||
2715 | net_local *lp = netdev_priv(dev); | ||
2716 | unsigned long ioaddr = dev->base_addr; | ||
2717 | unsigned short txblock; | ||
2718 | unsigned short txpred; | ||
2719 | unsigned short tx_addr; | ||
2720 | unsigned short nop_addr; | ||
2721 | unsigned short tbd_addr; | ||
2722 | unsigned short buf_addr; | ||
2723 | ac_tx_t tx; | ||
2724 | ac_nop_t nop; | ||
2725 | tbd_t tbd; | ||
2726 | int clen = length; | ||
2727 | unsigned long flags; | ||
2728 | |||
2729 | #ifdef DEBUG_TX_TRACE | ||
2730 | printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, | ||
2731 | length); | ||
2732 | #endif | ||
2733 | |||
2734 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2735 | |||
2736 | /* Check nothing bad has happened */ | ||
2737 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { | ||
2738 | #ifdef DEBUG_TX_ERROR | ||
2739 | printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", | ||
2740 | dev->name); | ||
2741 | #endif | ||
2742 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2743 | return 1; | ||
2744 | } | ||
2745 | |||
2746 | /* Calculate addresses of next block and previous block. */ | ||
2747 | txblock = lp->tx_first_free; | ||
2748 | txpred = txblock - TXBLOCKZ; | ||
2749 | if (txpred < OFFSET_CU) | ||
2750 | txpred += NTXBLOCKS * TXBLOCKZ; | ||
2751 | lp->tx_first_free += TXBLOCKZ; | ||
2752 | if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) | ||
2753 | lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; | ||
2754 | |||
2755 | lp->tx_n_in_use++; | ||
2756 | |||
2757 | /* Calculate addresses of the different parts of the block. */ | ||
2758 | tx_addr = txblock; | ||
2759 | nop_addr = tx_addr + sizeof(tx); | ||
2760 | tbd_addr = nop_addr + sizeof(nop); | ||
2761 | buf_addr = tbd_addr + sizeof(tbd); | ||
2762 | |||
2763 | /* | ||
2764 | * Transmit command | ||
2765 | */ | ||
2766 | tx.tx_h.ac_status = 0; | ||
2767 | obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), | ||
2768 | (unsigned char *) &tx.tx_h.ac_status, | ||
2769 | sizeof(tx.tx_h.ac_status)); | ||
2770 | |||
2771 | /* | ||
2772 | * NOP command | ||
2773 | */ | ||
2774 | nop.nop_h.ac_status = 0; | ||
2775 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
2776 | (unsigned char *) &nop.nop_h.ac_status, | ||
2777 | sizeof(nop.nop_h.ac_status)); | ||
2778 | nop.nop_h.ac_link = nop_addr; | ||
2779 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
2780 | (unsigned char *) &nop.nop_h.ac_link, | ||
2781 | sizeof(nop.nop_h.ac_link)); | ||
2782 | |||
2783 | /* | ||
2784 | * Transmit buffer descriptor | ||
2785 | */ | ||
2786 | tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); | ||
2787 | tbd.tbd_next_bd_offset = I82586NULL; | ||
2788 | tbd.tbd_bufl = buf_addr; | ||
2789 | tbd.tbd_bufh = 0; | ||
2790 | obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); | ||
2791 | |||
2792 | /* | ||
2793 | * Data | ||
2794 | */ | ||
2795 | obram_write(ioaddr, buf_addr, buf, length); | ||
2796 | |||
2797 | /* | ||
2798 | * Overwrite the predecessor NOP link | ||
2799 | * so that it points to this txblock. | ||
2800 | */ | ||
2801 | nop_addr = txpred + sizeof(tx); | ||
2802 | nop.nop_h.ac_status = 0; | ||
2803 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
2804 | (unsigned char *) &nop.nop_h.ac_status, | ||
2805 | sizeof(nop.nop_h.ac_status)); | ||
2806 | nop.nop_h.ac_link = txblock; | ||
2807 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
2808 | (unsigned char *) &nop.nop_h.ac_link, | ||
2809 | sizeof(nop.nop_h.ac_link)); | ||
2810 | |||
2811 | /* Make sure the watchdog will keep quiet for a while */ | ||
2812 | dev->trans_start = jiffies; | ||
2813 | |||
2814 | /* Keep stats up to date. */ | ||
2815 | dev->stats.tx_bytes += length; | ||
2816 | |||
2817 | if (lp->tx_first_in_use == I82586NULL) | ||
2818 | lp->tx_first_in_use = txblock; | ||
2819 | |||
2820 | if (lp->tx_n_in_use < NTXBLOCKS - 1) | ||
2821 | netif_wake_queue(dev); | ||
2822 | |||
2823 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2824 | |||
2825 | #ifdef DEBUG_TX_INFO | ||
2826 | wv_packet_info((u8 *) buf, length, dev->name, | ||
2827 | "wv_packet_write"); | ||
2828 | #endif /* DEBUG_TX_INFO */ | ||
2829 | |||
2830 | #ifdef DEBUG_TX_TRACE | ||
2831 | printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); | ||
2832 | #endif | ||
2833 | |||
2834 | return 0; | ||
2835 | } | ||
2836 | |||
2837 | /*------------------------------------------------------------------*/ | ||
2838 | /* | ||
2839 | * This routine is called when we want to send a packet (NET3 callback) | ||
2840 | * In this routine, we check if the harware is ready to accept | ||
2841 | * the packet. We also prevent reentrance. Then we call the function | ||
2842 | * to send the packet. | ||
2843 | */ | ||
2844 | static netdev_tx_t wavelan_packet_xmit(struct sk_buff *skb, | ||
2845 | struct net_device * dev) | ||
2846 | { | ||
2847 | net_local *lp = netdev_priv(dev); | ||
2848 | unsigned long flags; | ||
2849 | char data[ETH_ZLEN]; | ||
2850 | |||
2851 | #ifdef DEBUG_TX_TRACE | ||
2852 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, | ||
2853 | (unsigned) skb); | ||
2854 | #endif | ||
2855 | |||
2856 | /* | ||
2857 | * Block a timer-based transmit from overlapping. | ||
2858 | * In other words, prevent reentering this routine. | ||
2859 | */ | ||
2860 | netif_stop_queue(dev); | ||
2861 | |||
2862 | /* If somebody has asked to reconfigure the controller, | ||
2863 | * we can do it now. | ||
2864 | */ | ||
2865 | if (lp->reconfig_82586) { | ||
2866 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2867 | wv_82586_config(dev); | ||
2868 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2869 | /* Check that we can continue */ | ||
2870 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) | ||
2871 | return NETDEV_TX_BUSY; | ||
2872 | } | ||
2873 | |||
2874 | /* Do we need some padding? */ | ||
2875 | /* Note : on wireless the propagation time is in the order of 1us, | ||
2876 | * and we don't have the Ethernet specific requirement of beeing | ||
2877 | * able to detect collisions, therefore in theory we don't really | ||
2878 | * need to pad. Jean II */ | ||
2879 | if (skb->len < ETH_ZLEN) { | ||
2880 | memset(data, 0, ETH_ZLEN); | ||
2881 | skb_copy_from_linear_data(skb, data, skb->len); | ||
2882 | /* Write packet on the card */ | ||
2883 | if(wv_packet_write(dev, data, ETH_ZLEN)) | ||
2884 | return NETDEV_TX_BUSY; /* We failed */ | ||
2885 | } | ||
2886 | else if(wv_packet_write(dev, skb->data, skb->len)) | ||
2887 | return NETDEV_TX_BUSY; /* We failed */ | ||
2888 | |||
2889 | |||
2890 | dev_kfree_skb(skb); | ||
2891 | |||
2892 | #ifdef DEBUG_TX_TRACE | ||
2893 | printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); | ||
2894 | #endif | ||
2895 | return NETDEV_TX_OK; | ||
2896 | } | ||
2897 | |||
2898 | /*********************** HARDWARE CONFIGURATION ***********************/ | ||
2899 | /* | ||
2900 | * This part does the real job of starting and configuring the hardware. | ||
2901 | */ | ||
2902 | |||
2903 | /*--------------------------------------------------------------------*/ | ||
2904 | /* | ||
2905 | * Routine to initialize the Modem Management Controller. | ||
2906 | * (called by wv_hw_reset()) | ||
2907 | */ | ||
2908 | static int wv_mmc_init(struct net_device * dev) | ||
2909 | { | ||
2910 | unsigned long ioaddr = dev->base_addr; | ||
2911 | net_local *lp = netdev_priv(dev); | ||
2912 | psa_t psa; | ||
2913 | mmw_t m; | ||
2914 | int configured; | ||
2915 | |||
2916 | #ifdef DEBUG_CONFIG_TRACE | ||
2917 | printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); | ||
2918 | #endif | ||
2919 | |||
2920 | /* Read the parameter storage area. */ | ||
2921 | psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); | ||
2922 | |||
2923 | #ifdef USE_PSA_CONFIG | ||
2924 | configured = psa.psa_conf_status & 1; | ||
2925 | #else | ||
2926 | configured = 0; | ||
2927 | #endif | ||
2928 | |||
2929 | /* Is the PSA is not configured */ | ||
2930 | if (!configured) { | ||
2931 | /* User will be able to configure NWID later (with iwconfig). */ | ||
2932 | psa.psa_nwid[0] = 0; | ||
2933 | psa.psa_nwid[1] = 0; | ||
2934 | |||
2935 | /* no NWID checking since NWID is not set */ | ||
2936 | psa.psa_nwid_select = 0; | ||
2937 | |||
2938 | /* Disable encryption */ | ||
2939 | psa.psa_encryption_select = 0; | ||
2940 | |||
2941 | /* Set to standard values: | ||
2942 | * 0x04 for AT, | ||
2943 | * 0x01 for MCA, | ||
2944 | * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) | ||
2945 | */ | ||
2946 | if (psa.psa_comp_number & 1) | ||
2947 | psa.psa_thr_pre_set = 0x01; | ||
2948 | else | ||
2949 | psa.psa_thr_pre_set = 0x04; | ||
2950 | psa.psa_quality_thr = 0x03; | ||
2951 | |||
2952 | /* It is configured */ | ||
2953 | psa.psa_conf_status |= 1; | ||
2954 | |||
2955 | #ifdef USE_PSA_CONFIG | ||
2956 | /* Write the psa. */ | ||
2957 | psa_write(ioaddr, lp->hacr, | ||
2958 | (char *) psa.psa_nwid - (char *) &psa, | ||
2959 | (unsigned char *) psa.psa_nwid, 4); | ||
2960 | psa_write(ioaddr, lp->hacr, | ||
2961 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
2962 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
2963 | psa_write(ioaddr, lp->hacr, | ||
2964 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2965 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2966 | psa_write(ioaddr, lp->hacr, | ||
2967 | (char *) &psa.psa_conf_status - (char *) &psa, | ||
2968 | (unsigned char *) &psa.psa_conf_status, 1); | ||
2969 | /* update the Wavelan checksum */ | ||
2970 | update_psa_checksum(dev, ioaddr, lp->hacr); | ||
2971 | #endif | ||
2972 | } | ||
2973 | |||
2974 | /* Zero the mmc structure. */ | ||
2975 | memset(&m, 0x00, sizeof(m)); | ||
2976 | |||
2977 | /* Copy PSA info to the mmc. */ | ||
2978 | m.mmw_netw_id_l = psa.psa_nwid[1]; | ||
2979 | m.mmw_netw_id_h = psa.psa_nwid[0]; | ||
2980 | |||
2981 | if (psa.psa_nwid_select & 1) | ||
2982 | m.mmw_loopt_sel = 0x00; | ||
2983 | else | ||
2984 | m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; | ||
2985 | |||
2986 | memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, | ||
2987 | sizeof(m.mmw_encr_key)); | ||
2988 | |||
2989 | if (psa.psa_encryption_select) | ||
2990 | m.mmw_encr_enable = | ||
2991 | MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; | ||
2992 | else | ||
2993 | m.mmw_encr_enable = 0; | ||
2994 | |||
2995 | m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; | ||
2996 | m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; | ||
2997 | |||
2998 | /* | ||
2999 | * Set default modem control parameters. | ||
3000 | * See NCR document 407-0024326 Rev. A. | ||
3001 | */ | ||
3002 | m.mmw_jabber_enable = 0x01; | ||
3003 | m.mmw_freeze = 0; | ||
3004 | m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; | ||
3005 | m.mmw_ifs = 0x20; | ||
3006 | m.mmw_mod_delay = 0x04; | ||
3007 | m.mmw_jam_time = 0x38; | ||
3008 | |||
3009 | m.mmw_des_io_invert = 0; | ||
3010 | m.mmw_decay_prm = 0; | ||
3011 | m.mmw_decay_updat_prm = 0; | ||
3012 | |||
3013 | /* Write all info to MMC. */ | ||
3014 | mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m)); | ||
3015 | |||
3016 | /* The following code starts the modem of the 2.00 frequency | ||
3017 | * selectable cards at power on. It's not strictly needed for the | ||
3018 | * following boots. | ||
3019 | * The original patch was by Joe Finney for the PCMCIA driver, but | ||
3020 | * I've cleaned it up a bit and added documentation. | ||
3021 | * Thanks to Loeke Brederveld from Lucent for the info. | ||
3022 | */ | ||
3023 | |||
3024 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) | ||
3025 | * Does it work for everybody, especially old cards? */ | ||
3026 | /* Note: WFREQSEL verifies that it is able to read a sensible | ||
3027 | * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID | ||
3028 | * is 0xA (Xilinx version) or 0xB (Ariadne version). | ||
3029 | * My test is more crude but does work. */ | ||
3030 | if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & | ||
3031 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
3032 | /* We must download the frequency parameters to the | ||
3033 | * synthesizers (from the EEPROM - area 1) | ||
3034 | * Note: as the EEPROM is automatically decremented, we set the end | ||
3035 | * if the area... */ | ||
3036 | m.mmw_fee_addr = 0x0F; | ||
3037 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3038 | mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, | ||
3039 | (unsigned char *) &m.mmw_fee_ctrl, 2); | ||
3040 | |||
3041 | /* Wait until the download is finished. */ | ||
3042 | fee_wait(ioaddr, 100, 100); | ||
3043 | |||
3044 | #ifdef DEBUG_CONFIG_INFO | ||
3045 | /* The frequency was in the last word downloaded. */ | ||
3046 | mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m, | ||
3047 | (unsigned char *) &m.mmw_fee_data_l, 2); | ||
3048 | |||
3049 | /* Print some info for the user. */ | ||
3050 | printk(KERN_DEBUG | ||
3051 | "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", | ||
3052 | dev->name, | ||
3053 | ((m. | ||
3054 | mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) * | ||
3055 | 5 / 2 + 24000L); | ||
3056 | #endif | ||
3057 | |||
3058 | /* We must now download the power adjust value (gain) to | ||
3059 | * the synthesizers (from the EEPROM - area 7 - DAC). */ | ||
3060 | m.mmw_fee_addr = 0x61; | ||
3061 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3062 | mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, | ||
3063 | (unsigned char *) &m.mmw_fee_ctrl, 2); | ||
3064 | |||
3065 | /* Wait until the download is finished. */ | ||
3066 | } | ||
3067 | /* if 2.00 card */ | ||
3068 | #ifdef DEBUG_CONFIG_TRACE | ||
3069 | printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); | ||
3070 | #endif | ||
3071 | return 0; | ||
3072 | } | ||
3073 | |||
3074 | /*------------------------------------------------------------------*/ | ||
3075 | /* | ||
3076 | * Construct the fd and rbd structures. | ||
3077 | * Start the receive unit. | ||
3078 | * (called by wv_hw_reset()) | ||
3079 | */ | ||
3080 | static int wv_ru_start(struct net_device * dev) | ||
3081 | { | ||
3082 | net_local *lp = netdev_priv(dev); | ||
3083 | unsigned long ioaddr = dev->base_addr; | ||
3084 | u16 scb_cs; | ||
3085 | fd_t fd; | ||
3086 | rbd_t rbd; | ||
3087 | u16 rx; | ||
3088 | u16 rx_next; | ||
3089 | int i; | ||
3090 | |||
3091 | #ifdef DEBUG_CONFIG_TRACE | ||
3092 | printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); | ||
3093 | #endif | ||
3094 | |||
3095 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), | ||
3096 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3097 | if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) | ||
3098 | return 0; | ||
3099 | |||
3100 | lp->rx_head = OFFSET_RU; | ||
3101 | |||
3102 | for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) { | ||
3103 | rx_next = | ||
3104 | (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; | ||
3105 | |||
3106 | fd.fd_status = 0; | ||
3107 | fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; | ||
3108 | fd.fd_link_offset = rx_next; | ||
3109 | fd.fd_rbd_offset = rx + sizeof(fd); | ||
3110 | obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd)); | ||
3111 | |||
3112 | rbd.rbd_status = 0; | ||
3113 | rbd.rbd_next_rbd_offset = I82586NULL; | ||
3114 | rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); | ||
3115 | rbd.rbd_bufh = 0; | ||
3116 | rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); | ||
3117 | obram_write(ioaddr, rx + sizeof(fd), | ||
3118 | (unsigned char *) &rbd, sizeof(rbd)); | ||
3119 | |||
3120 | lp->rx_last = rx; | ||
3121 | } | ||
3122 | |||
3123 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), | ||
3124 | (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); | ||
3125 | |||
3126 | scb_cs = SCB_CMD_RUC_GO; | ||
3127 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3128 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3129 | |||
3130 | set_chan_attn(ioaddr, lp->hacr); | ||
3131 | |||
3132 | for (i = 1000; i > 0; i--) { | ||
3133 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3134 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3135 | if (scb_cs == 0) | ||
3136 | break; | ||
3137 | |||
3138 | udelay(10); | ||
3139 | } | ||
3140 | |||
3141 | if (i <= 0) { | ||
3142 | #ifdef DEBUG_CONFIG_ERROR | ||
3143 | printk(KERN_INFO | ||
3144 | "%s: wavelan_ru_start(): board not accepting command.\n", | ||
3145 | dev->name); | ||
3146 | #endif | ||
3147 | return -1; | ||
3148 | } | ||
3149 | #ifdef DEBUG_CONFIG_TRACE | ||
3150 | printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); | ||
3151 | #endif | ||
3152 | return 0; | ||
3153 | } | ||
3154 | |||
3155 | /*------------------------------------------------------------------*/ | ||
3156 | /* | ||
3157 | * Initialise the transmit blocks. | ||
3158 | * Start the command unit executing the NOP | ||
3159 | * self-loop of the first transmit block. | ||
3160 | * | ||
3161 | * Here we create the list of send buffers used to transmit packets | ||
3162 | * between the PC and the command unit. For each buffer, we create a | ||
3163 | * buffer descriptor (pointing on the buffer), a transmit command | ||
3164 | * (pointing to the buffer descriptor) and a NOP command. | ||
3165 | * The transmit command is linked to the NOP, and the NOP to itself. | ||
3166 | * When we will have finished executing the transmit command, we will | ||
3167 | * then loop on the NOP. By releasing the NOP link to a new command, | ||
3168 | * we may send another buffer. | ||
3169 | * | ||
3170 | * (called by wv_hw_reset()) | ||
3171 | */ | ||
3172 | static int wv_cu_start(struct net_device * dev) | ||
3173 | { | ||
3174 | net_local *lp = netdev_priv(dev); | ||
3175 | unsigned long ioaddr = dev->base_addr; | ||
3176 | int i; | ||
3177 | u16 txblock; | ||
3178 | u16 first_nop; | ||
3179 | u16 scb_cs; | ||
3180 | |||
3181 | #ifdef DEBUG_CONFIG_TRACE | ||
3182 | printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); | ||
3183 | #endif | ||
3184 | |||
3185 | lp->tx_first_free = OFFSET_CU; | ||
3186 | lp->tx_first_in_use = I82586NULL; | ||
3187 | |||
3188 | for (i = 0, txblock = OFFSET_CU; | ||
3189 | i < NTXBLOCKS; i++, txblock += TXBLOCKZ) { | ||
3190 | ac_tx_t tx; | ||
3191 | ac_nop_t nop; | ||
3192 | tbd_t tbd; | ||
3193 | unsigned short tx_addr; | ||
3194 | unsigned short nop_addr; | ||
3195 | unsigned short tbd_addr; | ||
3196 | unsigned short buf_addr; | ||
3197 | |||
3198 | tx_addr = txblock; | ||
3199 | nop_addr = tx_addr + sizeof(tx); | ||
3200 | tbd_addr = nop_addr + sizeof(nop); | ||
3201 | buf_addr = tbd_addr + sizeof(tbd); | ||
3202 | |||
3203 | tx.tx_h.ac_status = 0; | ||
3204 | tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; | ||
3205 | tx.tx_h.ac_link = nop_addr; | ||
3206 | tx.tx_tbd_offset = tbd_addr; | ||
3207 | obram_write(ioaddr, tx_addr, (unsigned char *) &tx, | ||
3208 | sizeof(tx)); | ||
3209 | |||
3210 | nop.nop_h.ac_status = 0; | ||
3211 | nop.nop_h.ac_command = acmd_nop; | ||
3212 | nop.nop_h.ac_link = nop_addr; | ||
3213 | obram_write(ioaddr, nop_addr, (unsigned char *) &nop, | ||
3214 | sizeof(nop)); | ||
3215 | |||
3216 | tbd.tbd_status = TBD_STATUS_EOF; | ||
3217 | tbd.tbd_next_bd_offset = I82586NULL; | ||
3218 | tbd.tbd_bufl = buf_addr; | ||
3219 | tbd.tbd_bufh = 0; | ||
3220 | obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, | ||
3221 | sizeof(tbd)); | ||
3222 | } | ||
3223 | |||
3224 | first_nop = | ||
3225 | OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); | ||
3226 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), | ||
3227 | (unsigned char *) &first_nop, sizeof(first_nop)); | ||
3228 | |||
3229 | scb_cs = SCB_CMD_CUC_GO; | ||
3230 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3231 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3232 | |||
3233 | set_chan_attn(ioaddr, lp->hacr); | ||
3234 | |||
3235 | for (i = 1000; i > 0; i--) { | ||
3236 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3237 | (unsigned char *) &scb_cs, sizeof(scb_cs)); | ||
3238 | if (scb_cs == 0) | ||
3239 | break; | ||
3240 | |||
3241 | udelay(10); | ||
3242 | } | ||
3243 | |||
3244 | if (i <= 0) { | ||
3245 | #ifdef DEBUG_CONFIG_ERROR | ||
3246 | printk(KERN_INFO | ||
3247 | "%s: wavelan_cu_start(): board not accepting command.\n", | ||
3248 | dev->name); | ||
3249 | #endif | ||
3250 | return -1; | ||
3251 | } | ||
3252 | |||
3253 | lp->tx_n_in_use = 0; | ||
3254 | netif_start_queue(dev); | ||
3255 | #ifdef DEBUG_CONFIG_TRACE | ||
3256 | printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); | ||
3257 | #endif | ||
3258 | return 0; | ||
3259 | } | ||
3260 | |||
3261 | /*------------------------------------------------------------------*/ | ||
3262 | /* | ||
3263 | * This routine does a standard configuration of the WaveLAN | ||
3264 | * controller (i82586). | ||
3265 | * | ||
3266 | * It initialises the scp, iscp and scb structure | ||
3267 | * The first two are just pointers to the next. | ||
3268 | * The last one is used for basic configuration and for basic | ||
3269 | * communication (interrupt status). | ||
3270 | * | ||
3271 | * (called by wv_hw_reset()) | ||
3272 | */ | ||
3273 | static int wv_82586_start(struct net_device * dev) | ||
3274 | { | ||
3275 | net_local *lp = netdev_priv(dev); | ||
3276 | unsigned long ioaddr = dev->base_addr; | ||
3277 | scp_t scp; /* system configuration pointer */ | ||
3278 | iscp_t iscp; /* intermediate scp */ | ||
3279 | scb_t scb; /* system control block */ | ||
3280 | ach_t cb; /* Action command header */ | ||
3281 | u8 zeroes[512]; | ||
3282 | int i; | ||
3283 | |||
3284 | #ifdef DEBUG_CONFIG_TRACE | ||
3285 | printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); | ||
3286 | #endif | ||
3287 | |||
3288 | /* | ||
3289 | * Clear the onboard RAM. | ||
3290 | */ | ||
3291 | memset(&zeroes[0], 0x00, sizeof(zeroes)); | ||
3292 | for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) | ||
3293 | obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); | ||
3294 | |||
3295 | /* | ||
3296 | * Construct the command unit structures: | ||
3297 | * scp, iscp, scb, cb. | ||
3298 | */ | ||
3299 | memset(&scp, 0x00, sizeof(scp)); | ||
3300 | scp.scp_sysbus = SCP_SY_16BBUS; | ||
3301 | scp.scp_iscpl = OFFSET_ISCP; | ||
3302 | obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp, | ||
3303 | sizeof(scp)); | ||
3304 | |||
3305 | memset(&iscp, 0x00, sizeof(iscp)); | ||
3306 | iscp.iscp_busy = 1; | ||
3307 | iscp.iscp_offset = OFFSET_SCB; | ||
3308 | obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, | ||
3309 | sizeof(iscp)); | ||
3310 | |||
3311 | /* Our first command is to reset the i82586. */ | ||
3312 | memset(&scb, 0x00, sizeof(scb)); | ||
3313 | scb.scb_command = SCB_CMD_RESET; | ||
3314 | scb.scb_cbl_offset = OFFSET_CU; | ||
3315 | scb.scb_rfa_offset = OFFSET_RU; | ||
3316 | obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb, | ||
3317 | sizeof(scb)); | ||
3318 | |||
3319 | set_chan_attn(ioaddr, lp->hacr); | ||
3320 | |||
3321 | /* Wait for command to finish. */ | ||
3322 | for (i = 1000; i > 0; i--) { | ||
3323 | obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, | ||
3324 | sizeof(iscp)); | ||
3325 | |||
3326 | if (iscp.iscp_busy == (unsigned short) 0) | ||
3327 | break; | ||
3328 | |||
3329 | udelay(10); | ||
3330 | } | ||
3331 | |||
3332 | if (i <= 0) { | ||
3333 | #ifdef DEBUG_CONFIG_ERROR | ||
3334 | printk(KERN_INFO | ||
3335 | "%s: wv_82586_start(): iscp_busy timeout.\n", | ||
3336 | dev->name); | ||
3337 | #endif | ||
3338 | return -1; | ||
3339 | } | ||
3340 | |||
3341 | /* Check command completion. */ | ||
3342 | for (i = 15; i > 0; i--) { | ||
3343 | obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, | ||
3344 | sizeof(scb)); | ||
3345 | |||
3346 | if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) | ||
3347 | break; | ||
3348 | |||
3349 | udelay(10); | ||
3350 | } | ||
3351 | |||
3352 | if (i <= 0) { | ||
3353 | #ifdef DEBUG_CONFIG_ERROR | ||
3354 | printk(KERN_INFO | ||
3355 | "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", | ||
3356 | dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); | ||
3357 | #endif | ||
3358 | return -1; | ||
3359 | } | ||
3360 | |||
3361 | wv_ack(dev); | ||
3362 | |||
3363 | /* Set the action command header. */ | ||
3364 | memset(&cb, 0x00, sizeof(cb)); | ||
3365 | cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); | ||
3366 | cb.ac_link = OFFSET_CU; | ||
3367 | obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); | ||
3368 | |||
3369 | if (wv_synchronous_cmd(dev, "diag()") == -1) | ||
3370 | return -1; | ||
3371 | |||
3372 | obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); | ||
3373 | if (cb.ac_status & AC_SFLD_FAIL) { | ||
3374 | #ifdef DEBUG_CONFIG_ERROR | ||
3375 | printk(KERN_INFO | ||
3376 | "%s: wv_82586_start(): i82586 Self Test failed.\n", | ||
3377 | dev->name); | ||
3378 | #endif | ||
3379 | return -1; | ||
3380 | } | ||
3381 | #ifdef DEBUG_I82586_SHOW | ||
3382 | wv_scb_show(ioaddr); | ||
3383 | #endif | ||
3384 | |||
3385 | #ifdef DEBUG_CONFIG_TRACE | ||
3386 | printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); | ||
3387 | #endif | ||
3388 | return 0; | ||
3389 | } | ||
3390 | |||
3391 | /*------------------------------------------------------------------*/ | ||
3392 | /* | ||
3393 | * This routine does a standard configuration of the WaveLAN | ||
3394 | * controller (i82586). | ||
3395 | * | ||
3396 | * This routine is a violent hack. We use the first free transmit block | ||
3397 | * to make our configuration. In the buffer area, we create the three | ||
3398 | * configuration commands (linked). We make the previous NOP point to | ||
3399 | * the beginning of the buffer instead of the tx command. After, we go | ||
3400 | * as usual to the NOP command. | ||
3401 | * Note that only the last command (mc_set) will generate an interrupt. | ||
3402 | * | ||
3403 | * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) | ||
3404 | */ | ||
3405 | static void wv_82586_config(struct net_device * dev) | ||
3406 | { | ||
3407 | net_local *lp = netdev_priv(dev); | ||
3408 | unsigned long ioaddr = dev->base_addr; | ||
3409 | unsigned short txblock; | ||
3410 | unsigned short txpred; | ||
3411 | unsigned short tx_addr; | ||
3412 | unsigned short nop_addr; | ||
3413 | unsigned short tbd_addr; | ||
3414 | unsigned short cfg_addr; | ||
3415 | unsigned short ias_addr; | ||
3416 | unsigned short mcs_addr; | ||
3417 | ac_tx_t tx; | ||
3418 | ac_nop_t nop; | ||
3419 | ac_cfg_t cfg; /* Configure action */ | ||
3420 | ac_ias_t ias; /* IA-setup action */ | ||
3421 | ac_mcs_t mcs; /* Multicast setup */ | ||
3422 | struct dev_mc_list *dmi; | ||
3423 | |||
3424 | #ifdef DEBUG_CONFIG_TRACE | ||
3425 | printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); | ||
3426 | #endif | ||
3427 | |||
3428 | /* Check nothing bad has happened */ | ||
3429 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { | ||
3430 | #ifdef DEBUG_CONFIG_ERROR | ||
3431 | printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", | ||
3432 | dev->name); | ||
3433 | #endif | ||
3434 | return; | ||
3435 | } | ||
3436 | |||
3437 | /* Calculate addresses of next block and previous block. */ | ||
3438 | txblock = lp->tx_first_free; | ||
3439 | txpred = txblock - TXBLOCKZ; | ||
3440 | if (txpred < OFFSET_CU) | ||
3441 | txpred += NTXBLOCKS * TXBLOCKZ; | ||
3442 | lp->tx_first_free += TXBLOCKZ; | ||
3443 | if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) | ||
3444 | lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; | ||
3445 | |||
3446 | lp->tx_n_in_use++; | ||
3447 | |||
3448 | /* Calculate addresses of the different parts of the block. */ | ||
3449 | tx_addr = txblock; | ||
3450 | nop_addr = tx_addr + sizeof(tx); | ||
3451 | tbd_addr = nop_addr + sizeof(nop); | ||
3452 | cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ | ||
3453 | ias_addr = cfg_addr + sizeof(cfg); | ||
3454 | mcs_addr = ias_addr + sizeof(ias); | ||
3455 | |||
3456 | /* | ||
3457 | * Transmit command | ||
3458 | */ | ||
3459 | tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ | ||
3460 | obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), | ||
3461 | (unsigned char *) &tx.tx_h.ac_status, | ||
3462 | sizeof(tx.tx_h.ac_status)); | ||
3463 | |||
3464 | /* | ||
3465 | * NOP command | ||
3466 | */ | ||
3467 | nop.nop_h.ac_status = 0; | ||
3468 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
3469 | (unsigned char *) &nop.nop_h.ac_status, | ||
3470 | sizeof(nop.nop_h.ac_status)); | ||
3471 | nop.nop_h.ac_link = nop_addr; | ||
3472 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
3473 | (unsigned char *) &nop.nop_h.ac_link, | ||
3474 | sizeof(nop.nop_h.ac_link)); | ||
3475 | |||
3476 | /* Create a configure action. */ | ||
3477 | memset(&cfg, 0x00, sizeof(cfg)); | ||
3478 | |||
3479 | /* | ||
3480 | * For Linux we invert AC_CFG_ALOC() so as to conform | ||
3481 | * to the way that net packets reach us from above. | ||
3482 | * (See also ac_tx_t.) | ||
3483 | * | ||
3484 | * Updated from Wavelan Manual WCIN085B | ||
3485 | */ | ||
3486 | cfg.cfg_byte_cnt = | ||
3487 | AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); | ||
3488 | cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); | ||
3489 | cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); | ||
3490 | cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | | ||
3491 | AC_CFG_ILPBCK(0) | | ||
3492 | AC_CFG_PRELEN(AC_CFG_PLEN_2) | | ||
3493 | AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); | ||
3494 | cfg.cfg_byte10 = AC_CFG_BOFMET(1) | | ||
3495 | AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); | ||
3496 | cfg.cfg_ifs = 0x20; | ||
3497 | cfg.cfg_slotl = 0x0C; | ||
3498 | cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0); | ||
3499 | cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | | ||
3500 | AC_CFG_BTSTF(0) | | ||
3501 | AC_CFG_CRC16(0) | | ||
3502 | AC_CFG_NCRC(0) | | ||
3503 | AC_CFG_TNCRS(1) | | ||
3504 | AC_CFG_MANCH(0) | | ||
3505 | AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous); | ||
3506 | cfg.cfg_byte15 = AC_CFG_ICDS(0) | | ||
3507 | AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0); | ||
3508 | /* | ||
3509 | cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); | ||
3510 | */ | ||
3511 | cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); | ||
3512 | |||
3513 | cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); | ||
3514 | cfg.cfg_h.ac_link = ias_addr; | ||
3515 | obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg)); | ||
3516 | |||
3517 | /* Set up the MAC address */ | ||
3518 | memset(&ias, 0x00, sizeof(ias)); | ||
3519 | ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); | ||
3520 | ias.ias_h.ac_link = mcs_addr; | ||
3521 | memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0], | ||
3522 | sizeof(ias.ias_addr)); | ||
3523 | obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias)); | ||
3524 | |||
3525 | /* Initialize adapter's Ethernet multicast addresses */ | ||
3526 | memset(&mcs, 0x00, sizeof(mcs)); | ||
3527 | mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); | ||
3528 | mcs.mcs_h.ac_link = nop_addr; | ||
3529 | mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; | ||
3530 | obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs)); | ||
3531 | |||
3532 | /* Any address to set? */ | ||
3533 | if (lp->mc_count) { | ||
3534 | for (dmi = dev->mc_list; dmi; dmi = dmi->next) | ||
3535 | outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr, | ||
3536 | WAVELAN_ADDR_SIZE >> 1); | ||
3537 | |||
3538 | #ifdef DEBUG_CONFIG_INFO | ||
3539 | printk(KERN_DEBUG | ||
3540 | "%s: wv_82586_config(): set %d multicast addresses:\n", | ||
3541 | dev->name, lp->mc_count); | ||
3542 | for (dmi = dev->mc_list; dmi; dmi = dmi->next) | ||
3543 | printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); | ||
3544 | #endif | ||
3545 | } | ||
3546 | |||
3547 | /* | ||
3548 | * Overwrite the predecessor NOP link | ||
3549 | * so that it points to the configure action. | ||
3550 | */ | ||
3551 | nop_addr = txpred + sizeof(tx); | ||
3552 | nop.nop_h.ac_status = 0; | ||
3553 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), | ||
3554 | (unsigned char *) &nop.nop_h.ac_status, | ||
3555 | sizeof(nop.nop_h.ac_status)); | ||
3556 | nop.nop_h.ac_link = cfg_addr; | ||
3557 | obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), | ||
3558 | (unsigned char *) &nop.nop_h.ac_link, | ||
3559 | sizeof(nop.nop_h.ac_link)); | ||
3560 | |||
3561 | /* Job done, clear the flag */ | ||
3562 | lp->reconfig_82586 = 0; | ||
3563 | |||
3564 | if (lp->tx_first_in_use == I82586NULL) | ||
3565 | lp->tx_first_in_use = txblock; | ||
3566 | |||
3567 | if (lp->tx_n_in_use == (NTXBLOCKS - 1)) | ||
3568 | netif_stop_queue(dev); | ||
3569 | |||
3570 | #ifdef DEBUG_CONFIG_TRACE | ||
3571 | printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); | ||
3572 | #endif | ||
3573 | } | ||
3574 | |||
3575 | /*------------------------------------------------------------------*/ | ||
3576 | /* | ||
3577 | * This routine, called by wavelan_close(), gracefully stops the | ||
3578 | * WaveLAN controller (i82586). | ||
3579 | * (called by wavelan_close()) | ||
3580 | */ | ||
3581 | static void wv_82586_stop(struct net_device * dev) | ||
3582 | { | ||
3583 | net_local *lp = netdev_priv(dev); | ||
3584 | unsigned long ioaddr = dev->base_addr; | ||
3585 | u16 scb_cmd; | ||
3586 | |||
3587 | #ifdef DEBUG_CONFIG_TRACE | ||
3588 | printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); | ||
3589 | #endif | ||
3590 | |||
3591 | /* Suspend both command unit and receive unit. */ | ||
3592 | scb_cmd = | ||
3593 | (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & | ||
3594 | SCB_CMD_RUC_SUS); | ||
3595 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3596 | (unsigned char *) &scb_cmd, sizeof(scb_cmd)); | ||
3597 | set_chan_attn(ioaddr, lp->hacr); | ||
3598 | |||
3599 | /* No more interrupts */ | ||
3600 | wv_ints_off(dev); | ||
3601 | |||
3602 | #ifdef DEBUG_CONFIG_TRACE | ||
3603 | printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); | ||
3604 | #endif | ||
3605 | } | ||
3606 | |||
3607 | /*------------------------------------------------------------------*/ | ||
3608 | /* | ||
3609 | * Totally reset the WaveLAN and restart it. | ||
3610 | * Performs the following actions: | ||
3611 | * 1. A power reset (reset DMA) | ||
3612 | * 2. Initialize the radio modem (using wv_mmc_init) | ||
3613 | * 3. Reset & Configure LAN controller (using wv_82586_start) | ||
3614 | * 4. Start the LAN controller's command unit | ||
3615 | * 5. Start the LAN controller's receive unit | ||
3616 | * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) | ||
3617 | */ | ||
3618 | static int wv_hw_reset(struct net_device * dev) | ||
3619 | { | ||
3620 | net_local *lp = netdev_priv(dev); | ||
3621 | unsigned long ioaddr = dev->base_addr; | ||
3622 | |||
3623 | #ifdef DEBUG_CONFIG_TRACE | ||
3624 | printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, | ||
3625 | (unsigned int) dev); | ||
3626 | #endif | ||
3627 | |||
3628 | /* Increase the number of resets done. */ | ||
3629 | lp->nresets++; | ||
3630 | |||
3631 | wv_hacr_reset(ioaddr); | ||
3632 | lp->hacr = HACR_DEFAULT; | ||
3633 | |||
3634 | if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0)) | ||
3635 | return -1; | ||
3636 | |||
3637 | /* Enable the card to send interrupts. */ | ||
3638 | wv_ints_on(dev); | ||
3639 | |||
3640 | /* Start card functions */ | ||
3641 | if (wv_cu_start(dev) < 0) | ||
3642 | return -1; | ||
3643 | |||
3644 | /* Setup the controller and parameters */ | ||
3645 | wv_82586_config(dev); | ||
3646 | |||
3647 | /* Finish configuration with the receive unit */ | ||
3648 | if (wv_ru_start(dev) < 0) | ||
3649 | return -1; | ||
3650 | |||
3651 | #ifdef DEBUG_CONFIG_TRACE | ||
3652 | printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); | ||
3653 | #endif | ||
3654 | return 0; | ||
3655 | } | ||
3656 | |||
3657 | /*------------------------------------------------------------------*/ | ||
3658 | /* | ||
3659 | * Check if there is a WaveLAN at the specific base address. | ||
3660 | * As a side effect, this reads the MAC address. | ||
3661 | * (called in wavelan_probe() and init_module()) | ||
3662 | */ | ||
3663 | static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) | ||
3664 | { | ||
3665 | int i; /* Loop counter */ | ||
3666 | |||
3667 | /* Check if the base address if available. */ | ||
3668 | if (!request_region(ioaddr, sizeof(ha_t), "wavelan probe")) | ||
3669 | return -EBUSY; /* ioaddr already used */ | ||
3670 | |||
3671 | /* Reset host interface */ | ||
3672 | wv_hacr_reset(ioaddr); | ||
3673 | |||
3674 | /* Read the MAC address from the parameter storage area. */ | ||
3675 | psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), | ||
3676 | mac, 6); | ||
3677 | |||
3678 | release_region(ioaddr, sizeof(ha_t)); | ||
3679 | |||
3680 | /* | ||
3681 | * Check the first three octets of the address for the manufacturer's code. | ||
3682 | * Note: if this can't find your WaveLAN card, you've got a | ||
3683 | * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on | ||
3684 | * how to configure your card. | ||
3685 | */ | ||
3686 | for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) | ||
3687 | if ((mac[0] == MAC_ADDRESSES[i][0]) && | ||
3688 | (mac[1] == MAC_ADDRESSES[i][1]) && | ||
3689 | (mac[2] == MAC_ADDRESSES[i][2])) | ||
3690 | return 0; | ||
3691 | |||
3692 | #ifdef DEBUG_CONFIG_INFO | ||
3693 | printk(KERN_WARNING | ||
3694 | "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", | ||
3695 | ioaddr, mac[0], mac[1], mac[2]); | ||
3696 | #endif | ||
3697 | return -ENODEV; | ||
3698 | } | ||
3699 | |||
3700 | /************************ INTERRUPT HANDLING ************************/ | ||
3701 | |||
3702 | /* | ||
3703 | * This function is the interrupt handler for the WaveLAN card. This | ||
3704 | * routine will be called whenever: | ||
3705 | */ | ||
3706 | static irqreturn_t wavelan_interrupt(int irq, void *dev_id) | ||
3707 | { | ||
3708 | struct net_device *dev; | ||
3709 | unsigned long ioaddr; | ||
3710 | net_local *lp; | ||
3711 | u16 hasr; | ||
3712 | u16 status; | ||
3713 | u16 ack_cmd; | ||
3714 | |||
3715 | dev = dev_id; | ||
3716 | |||
3717 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3718 | printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); | ||
3719 | #endif | ||
3720 | |||
3721 | lp = netdev_priv(dev); | ||
3722 | ioaddr = dev->base_addr; | ||
3723 | |||
3724 | #ifdef DEBUG_INTERRUPT_INFO | ||
3725 | /* Check state of our spinlock */ | ||
3726 | if(spin_is_locked(&lp->spinlock)) | ||
3727 | printk(KERN_DEBUG | ||
3728 | "%s: wavelan_interrupt(): spinlock is already locked !!!\n", | ||
3729 | dev->name); | ||
3730 | #endif | ||
3731 | |||
3732 | /* Prevent reentrancy. We need to do that because we may have | ||
3733 | * multiple interrupt handler running concurrently. | ||
3734 | * It is safe because interrupts are disabled before acquiring | ||
3735 | * the spinlock. */ | ||
3736 | spin_lock(&lp->spinlock); | ||
3737 | |||
3738 | /* We always had spurious interrupts at startup, but lately I | ||
3739 | * saw them comming *between* the request_irq() and the | ||
3740 | * spin_lock_irqsave() in wavelan_open(), so the spinlock | ||
3741 | * protection is no enough. | ||
3742 | * So, we also check lp->hacr that will tell us is we enabled | ||
3743 | * irqs or not (see wv_ints_on()). | ||
3744 | * We can't use netif_running(dev) because we depend on the | ||
3745 | * proper processing of the irq generated during the config. */ | ||
3746 | |||
3747 | /* Which interrupt it is ? */ | ||
3748 | hasr = hasr_read(ioaddr); | ||
3749 | |||
3750 | #ifdef DEBUG_INTERRUPT_INFO | ||
3751 | printk(KERN_INFO | ||
3752 | "%s: wavelan_interrupt(): hasr 0x%04x; hacr 0x%04x.\n", | ||
3753 | dev->name, hasr, lp->hacr); | ||
3754 | #endif | ||
3755 | |||
3756 | /* Check modem interrupt */ | ||
3757 | if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { | ||
3758 | u8 dce_status; | ||
3759 | |||
3760 | /* | ||
3761 | * Interrupt from the modem management controller. | ||
3762 | * This will clear it -- ignored for now. | ||
3763 | */ | ||
3764 | mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, | ||
3765 | sizeof(dce_status)); | ||
3766 | |||
3767 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3768 | printk(KERN_INFO | ||
3769 | "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", | ||
3770 | dev->name, dce_status); | ||
3771 | #endif | ||
3772 | } | ||
3773 | |||
3774 | /* Check if not controller interrupt */ | ||
3775 | if (((hasr & HASR_82586_INTR) == 0) || | ||
3776 | ((lp->hacr & HACR_82586_INT_ENABLE) == 0)) { | ||
3777 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3778 | printk(KERN_INFO | ||
3779 | "%s: wavelan_interrupt(): interrupt not coming from i82586 - hasr 0x%04x.\n", | ||
3780 | dev->name, hasr); | ||
3781 | #endif | ||
3782 | spin_unlock (&lp->spinlock); | ||
3783 | return IRQ_NONE; | ||
3784 | } | ||
3785 | |||
3786 | /* Read interrupt data. */ | ||
3787 | obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), | ||
3788 | (unsigned char *) &status, sizeof(status)); | ||
3789 | |||
3790 | /* | ||
3791 | * Acknowledge the interrupt(s). | ||
3792 | */ | ||
3793 | ack_cmd = status & SCB_ST_INT; | ||
3794 | obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), | ||
3795 | (unsigned char *) &ack_cmd, sizeof(ack_cmd)); | ||
3796 | set_chan_attn(ioaddr, lp->hacr); | ||
3797 | |||
3798 | #ifdef DEBUG_INTERRUPT_INFO | ||
3799 | printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", | ||
3800 | dev->name, status); | ||
3801 | #endif | ||
3802 | |||
3803 | /* Command completed. */ | ||
3804 | if ((status & SCB_ST_CX) == SCB_ST_CX) { | ||
3805 | #ifdef DEBUG_INTERRUPT_INFO | ||
3806 | printk(KERN_DEBUG | ||
3807 | "%s: wavelan_interrupt(): command completed.\n", | ||
3808 | dev->name); | ||
3809 | #endif | ||
3810 | wv_complete(dev, ioaddr, lp); | ||
3811 | } | ||
3812 | |||
3813 | /* Frame received. */ | ||
3814 | if ((status & SCB_ST_FR) == SCB_ST_FR) { | ||
3815 | #ifdef DEBUG_INTERRUPT_INFO | ||
3816 | printk(KERN_DEBUG | ||
3817 | "%s: wavelan_interrupt(): received packet.\n", | ||
3818 | dev->name); | ||
3819 | #endif | ||
3820 | wv_receive(dev); | ||
3821 | } | ||
3822 | |||
3823 | /* Check the state of the command unit. */ | ||
3824 | if (((status & SCB_ST_CNA) == SCB_ST_CNA) || | ||
3825 | (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && | ||
3826 | (netif_running(dev)))) { | ||
3827 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3828 | printk(KERN_INFO | ||
3829 | "%s: wavelan_interrupt(): CU inactive -- restarting\n", | ||
3830 | dev->name); | ||
3831 | #endif | ||
3832 | wv_hw_reset(dev); | ||
3833 | } | ||
3834 | |||
3835 | /* Check the state of the command unit. */ | ||
3836 | if (((status & SCB_ST_RNR) == SCB_ST_RNR) || | ||
3837 | (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && | ||
3838 | (netif_running(dev)))) { | ||
3839 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3840 | printk(KERN_INFO | ||
3841 | "%s: wavelan_interrupt(): RU not ready -- restarting\n", | ||
3842 | dev->name); | ||
3843 | #endif | ||
3844 | wv_hw_reset(dev); | ||
3845 | } | ||
3846 | |||
3847 | /* Release spinlock */ | ||
3848 | spin_unlock (&lp->spinlock); | ||
3849 | |||
3850 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3851 | printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); | ||
3852 | #endif | ||
3853 | return IRQ_HANDLED; | ||
3854 | } | ||
3855 | |||
3856 | /*------------------------------------------------------------------*/ | ||
3857 | /* | ||
3858 | * Watchdog: when we start a transmission, a timer is set for us in the | ||
3859 | * kernel. If the transmission completes, this timer is disabled. If | ||
3860 | * the timer expires, we are called and we try to unlock the hardware. | ||
3861 | */ | ||
3862 | static void wavelan_watchdog(struct net_device * dev) | ||
3863 | { | ||
3864 | net_local *lp = netdev_priv(dev); | ||
3865 | u_long ioaddr = dev->base_addr; | ||
3866 | unsigned long flags; | ||
3867 | unsigned int nreaped; | ||
3868 | |||
3869 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3870 | printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); | ||
3871 | #endif | ||
3872 | |||
3873 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3874 | printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", | ||
3875 | dev->name); | ||
3876 | #endif | ||
3877 | |||
3878 | /* Check that we came here for something */ | ||
3879 | if (lp->tx_n_in_use <= 0) { | ||
3880 | return; | ||
3881 | } | ||
3882 | |||
3883 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3884 | |||
3885 | /* Try to see if some buffers are not free (in case we missed | ||
3886 | * an interrupt */ | ||
3887 | nreaped = wv_complete(dev, ioaddr, lp); | ||
3888 | |||
3889 | #ifdef DEBUG_INTERRUPT_INFO | ||
3890 | printk(KERN_DEBUG | ||
3891 | "%s: wavelan_watchdog(): %d reaped, %d remain.\n", | ||
3892 | dev->name, nreaped, lp->tx_n_in_use); | ||
3893 | #endif | ||
3894 | |||
3895 | #ifdef DEBUG_PSA_SHOW | ||
3896 | { | ||
3897 | psa_t psa; | ||
3898 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
3899 | wv_psa_show(&psa); | ||
3900 | } | ||
3901 | #endif | ||
3902 | #ifdef DEBUG_MMC_SHOW | ||
3903 | wv_mmc_show(dev); | ||
3904 | #endif | ||
3905 | #ifdef DEBUG_I82586_SHOW | ||
3906 | wv_cu_show(dev); | ||
3907 | #endif | ||
3908 | |||
3909 | /* If no buffer has been freed */ | ||
3910 | if (nreaped == 0) { | ||
3911 | #ifdef DEBUG_INTERRUPT_ERROR | ||
3912 | printk(KERN_INFO | ||
3913 | "%s: wavelan_watchdog(): cleanup failed, trying reset\n", | ||
3914 | dev->name); | ||
3915 | #endif | ||
3916 | wv_hw_reset(dev); | ||
3917 | } | ||
3918 | |||
3919 | /* At this point, we should have some free Tx buffer ;-) */ | ||
3920 | if (lp->tx_n_in_use < NTXBLOCKS - 1) | ||
3921 | netif_wake_queue(dev); | ||
3922 | |||
3923 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3924 | |||
3925 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3926 | printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); | ||
3927 | #endif | ||
3928 | } | ||
3929 | |||
3930 | /********************* CONFIGURATION CALLBACKS *********************/ | ||
3931 | /* | ||
3932 | * Here are the functions called by the Linux networking code (NET3) | ||
3933 | * for initialization, configuration and deinstallations of the | ||
3934 | * WaveLAN ISA hardware. | ||
3935 | */ | ||
3936 | |||
3937 | /*------------------------------------------------------------------*/ | ||
3938 | /* | ||
3939 | * Configure and start up the WaveLAN PCMCIA adaptor. | ||
3940 | * Called by NET3 when it "opens" the device. | ||
3941 | */ | ||
3942 | static int wavelan_open(struct net_device * dev) | ||
3943 | { | ||
3944 | net_local *lp = netdev_priv(dev); | ||
3945 | unsigned long flags; | ||
3946 | |||
3947 | #ifdef DEBUG_CALLBACK_TRACE | ||
3948 | printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, | ||
3949 | (unsigned int) dev); | ||
3950 | #endif | ||
3951 | |||
3952 | /* Check irq */ | ||
3953 | if (dev->irq == 0) { | ||
3954 | #ifdef DEBUG_CONFIG_ERROR | ||
3955 | printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", | ||
3956 | dev->name); | ||
3957 | #endif | ||
3958 | return -ENXIO; | ||
3959 | } | ||
3960 | |||
3961 | if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) | ||
3962 | { | ||
3963 | #ifdef DEBUG_CONFIG_ERROR | ||
3964 | printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", | ||
3965 | dev->name); | ||
3966 | #endif | ||
3967 | return -EAGAIN; | ||
3968 | } | ||
3969 | |||
3970 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3971 | |||
3972 | if (wv_hw_reset(dev) != -1) { | ||
3973 | netif_start_queue(dev); | ||
3974 | } else { | ||
3975 | free_irq(dev->irq, dev); | ||
3976 | #ifdef DEBUG_CONFIG_ERROR | ||
3977 | printk(KERN_INFO | ||
3978 | "%s: wavelan_open(): impossible to start the card\n", | ||
3979 | dev->name); | ||
3980 | #endif | ||
3981 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3982 | return -EAGAIN; | ||
3983 | } | ||
3984 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3985 | |||
3986 | #ifdef DEBUG_CALLBACK_TRACE | ||
3987 | printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); | ||
3988 | #endif | ||
3989 | return 0; | ||
3990 | } | ||
3991 | |||
3992 | /*------------------------------------------------------------------*/ | ||
3993 | /* | ||
3994 | * Shut down the WaveLAN ISA card. | ||
3995 | * Called by NET3 when it "closes" the device. | ||
3996 | */ | ||
3997 | static int wavelan_close(struct net_device * dev) | ||
3998 | { | ||
3999 | net_local *lp = netdev_priv(dev); | ||
4000 | unsigned long flags; | ||
4001 | |||
4002 | #ifdef DEBUG_CALLBACK_TRACE | ||
4003 | printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, | ||
4004 | (unsigned int) dev); | ||
4005 | #endif | ||
4006 | |||
4007 | netif_stop_queue(dev); | ||
4008 | |||
4009 | /* | ||
4010 | * Flush the Tx and disable Rx. | ||
4011 | */ | ||
4012 | spin_lock_irqsave(&lp->spinlock, flags); | ||
4013 | wv_82586_stop(dev); | ||
4014 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
4015 | |||
4016 | free_irq(dev->irq, dev); | ||
4017 | |||
4018 | #ifdef DEBUG_CALLBACK_TRACE | ||
4019 | printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); | ||
4020 | #endif | ||
4021 | return 0; | ||
4022 | } | ||
4023 | |||
4024 | static const struct net_device_ops wavelan_netdev_ops = { | ||
4025 | .ndo_open = wavelan_open, | ||
4026 | .ndo_stop = wavelan_close, | ||
4027 | .ndo_start_xmit = wavelan_packet_xmit, | ||
4028 | .ndo_set_multicast_list = wavelan_set_multicast_list, | ||
4029 | .ndo_tx_timeout = wavelan_watchdog, | ||
4030 | .ndo_change_mtu = eth_change_mtu, | ||
4031 | .ndo_validate_addr = eth_validate_addr, | ||
4032 | #ifdef SET_MAC_ADDRESS | ||
4033 | .ndo_set_mac_address = wavelan_set_mac_address | ||
4034 | #else | ||
4035 | .ndo_set_mac_address = eth_mac_addr, | ||
4036 | #endif | ||
4037 | }; | ||
4038 | |||
4039 | |||
4040 | /*------------------------------------------------------------------*/ | ||
4041 | /* | ||
4042 | * Probe an I/O address, and if the WaveLAN is there configure the | ||
4043 | * device structure | ||
4044 | * (called by wavelan_probe() and via init_module()). | ||
4045 | */ | ||
4046 | static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) | ||
4047 | { | ||
4048 | u8 irq_mask; | ||
4049 | int irq; | ||
4050 | net_local *lp; | ||
4051 | mac_addr mac; | ||
4052 | int err; | ||
4053 | |||
4054 | if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) | ||
4055 | return -EADDRINUSE; | ||
4056 | |||
4057 | err = wv_check_ioaddr(ioaddr, mac); | ||
4058 | if (err) | ||
4059 | goto out; | ||
4060 | |||
4061 | memcpy(dev->dev_addr, mac, 6); | ||
4062 | |||
4063 | dev->base_addr = ioaddr; | ||
4064 | |||
4065 | #ifdef DEBUG_CALLBACK_TRACE | ||
4066 | printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", | ||
4067 | dev->name, (unsigned int) dev, ioaddr); | ||
4068 | #endif | ||
4069 | |||
4070 | /* Check IRQ argument on command line. */ | ||
4071 | if (dev->irq != 0) { | ||
4072 | irq_mask = wv_irq_to_psa(dev->irq); | ||
4073 | |||
4074 | if (irq_mask == 0) { | ||
4075 | #ifdef DEBUG_CONFIG_ERROR | ||
4076 | printk(KERN_WARNING | ||
4077 | "%s: wavelan_config(): invalid IRQ %d ignored.\n", | ||
4078 | dev->name, dev->irq); | ||
4079 | #endif | ||
4080 | dev->irq = 0; | ||
4081 | } else { | ||
4082 | #ifdef DEBUG_CONFIG_INFO | ||
4083 | printk(KERN_DEBUG | ||
4084 | "%s: wavelan_config(): changing IRQ to %d\n", | ||
4085 | dev->name, dev->irq); | ||
4086 | #endif | ||
4087 | psa_write(ioaddr, HACR_DEFAULT, | ||
4088 | psaoff(0, psa_int_req_no), &irq_mask, 1); | ||
4089 | /* update the Wavelan checksum */ | ||
4090 | update_psa_checksum(dev, ioaddr, HACR_DEFAULT); | ||
4091 | wv_hacr_reset(ioaddr); | ||
4092 | } | ||
4093 | } | ||
4094 | |||
4095 | psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), | ||
4096 | &irq_mask, 1); | ||
4097 | if ((irq = wv_psa_to_irq(irq_mask)) == -1) { | ||
4098 | #ifdef DEBUG_CONFIG_ERROR | ||
4099 | printk(KERN_INFO | ||
4100 | "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", | ||
4101 | dev->name, irq_mask); | ||
4102 | #endif | ||
4103 | err = -EAGAIN; | ||
4104 | goto out; | ||
4105 | } | ||
4106 | |||
4107 | dev->irq = irq; | ||
4108 | |||
4109 | dev->mem_start = 0x0000; | ||
4110 | dev->mem_end = 0x0000; | ||
4111 | dev->if_port = 0; | ||
4112 | |||
4113 | /* Initialize device structures */ | ||
4114 | memset(netdev_priv(dev), 0, sizeof(net_local)); | ||
4115 | lp = netdev_priv(dev); | ||
4116 | |||
4117 | /* Back link to the device structure. */ | ||
4118 | lp->dev = dev; | ||
4119 | /* Add the device at the beginning of the linked list. */ | ||
4120 | lp->next = wavelan_list; | ||
4121 | wavelan_list = lp; | ||
4122 | |||
4123 | lp->hacr = HACR_DEFAULT; | ||
4124 | |||
4125 | /* Multicast stuff */ | ||
4126 | lp->promiscuous = 0; | ||
4127 | lp->mc_count = 0; | ||
4128 | |||
4129 | /* Init spinlock */ | ||
4130 | spin_lock_init(&lp->spinlock); | ||
4131 | |||
4132 | dev->netdev_ops = &wavelan_netdev_ops; | ||
4133 | dev->watchdog_timeo = WATCHDOG_JIFFIES; | ||
4134 | dev->wireless_handlers = &wavelan_handler_def; | ||
4135 | lp->wireless_data.spy_data = &lp->spy_data; | ||
4136 | dev->wireless_data = &lp->wireless_data; | ||
4137 | |||
4138 | dev->mtu = WAVELAN_MTU; | ||
4139 | |||
4140 | /* Display nice information. */ | ||
4141 | wv_init_info(dev); | ||
4142 | |||
4143 | #ifdef DEBUG_CALLBACK_TRACE | ||
4144 | printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); | ||
4145 | #endif | ||
4146 | return 0; | ||
4147 | out: | ||
4148 | release_region(ioaddr, sizeof(ha_t)); | ||
4149 | return err; | ||
4150 | } | ||
4151 | |||
4152 | /*------------------------------------------------------------------*/ | ||
4153 | /* | ||
4154 | * Check for a network adaptor of this type. Return '0' iff one | ||
4155 | * exists. There seem to be different interpretations of | ||
4156 | * the initial value of dev->base_addr. | ||
4157 | * We follow the example in drivers/net/ne.c. | ||
4158 | * (called in "Space.c") | ||
4159 | */ | ||
4160 | struct net_device * __init wavelan_probe(int unit) | ||
4161 | { | ||
4162 | struct net_device *dev; | ||
4163 | short base_addr; | ||
4164 | int def_irq; | ||
4165 | int i; | ||
4166 | int r = 0; | ||
4167 | |||
4168 | /* compile-time check the sizes of structures */ | ||
4169 | BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); | ||
4170 | BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); | ||
4171 | BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); | ||
4172 | BUILD_BUG_ON(sizeof(ha_t) != HA_SIZE); | ||
4173 | |||
4174 | dev = alloc_etherdev(sizeof(net_local)); | ||
4175 | if (!dev) | ||
4176 | return ERR_PTR(-ENOMEM); | ||
4177 | |||
4178 | sprintf(dev->name, "eth%d", unit); | ||
4179 | netdev_boot_setup_check(dev); | ||
4180 | base_addr = dev->base_addr; | ||
4181 | def_irq = dev->irq; | ||
4182 | |||
4183 | #ifdef DEBUG_CALLBACK_TRACE | ||
4184 | printk(KERN_DEBUG | ||
4185 | "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", | ||
4186 | dev->name, dev, (unsigned int) dev->base_addr); | ||
4187 | #endif | ||
4188 | |||
4189 | /* Don't probe at all. */ | ||
4190 | if (base_addr < 0) { | ||
4191 | #ifdef DEBUG_CONFIG_ERROR | ||
4192 | printk(KERN_WARNING | ||
4193 | "%s: wavelan_probe(): invalid base address\n", | ||
4194 | dev->name); | ||
4195 | #endif | ||
4196 | r = -ENXIO; | ||
4197 | } else if (base_addr > 0x100) { /* Check a single specified location. */ | ||
4198 | r = wavelan_config(dev, base_addr); | ||
4199 | #ifdef DEBUG_CONFIG_INFO | ||
4200 | if (r != 0) | ||
4201 | printk(KERN_DEBUG | ||
4202 | "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", | ||
4203 | dev->name, base_addr); | ||
4204 | #endif | ||
4205 | |||
4206 | #ifdef DEBUG_CALLBACK_TRACE | ||
4207 | printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); | ||
4208 | #endif | ||
4209 | } else { /* Scan all possible addresses of the WaveLAN hardware. */ | ||
4210 | for (i = 0; i < ARRAY_SIZE(iobase); i++) { | ||
4211 | dev->irq = def_irq; | ||
4212 | if (wavelan_config(dev, iobase[i]) == 0) { | ||
4213 | #ifdef DEBUG_CALLBACK_TRACE | ||
4214 | printk(KERN_DEBUG | ||
4215 | "%s: <-wavelan_probe()\n", | ||
4216 | dev->name); | ||
4217 | #endif | ||
4218 | break; | ||
4219 | } | ||
4220 | } | ||
4221 | if (i == ARRAY_SIZE(iobase)) | ||
4222 | r = -ENODEV; | ||
4223 | } | ||
4224 | if (r) | ||
4225 | goto out; | ||
4226 | r = register_netdev(dev); | ||
4227 | if (r) | ||
4228 | goto out1; | ||
4229 | return dev; | ||
4230 | out1: | ||
4231 | release_region(dev->base_addr, sizeof(ha_t)); | ||
4232 | wavelan_list = wavelan_list->next; | ||
4233 | out: | ||
4234 | free_netdev(dev); | ||
4235 | return ERR_PTR(r); | ||
4236 | } | ||
4237 | |||
4238 | /****************************** MODULE ******************************/ | ||
4239 | /* | ||
4240 | * Module entry point: insertion and removal | ||
4241 | */ | ||
4242 | |||
4243 | #ifdef MODULE | ||
4244 | /*------------------------------------------------------------------*/ | ||
4245 | /* | ||
4246 | * Insertion of the module | ||
4247 | * I'm now quite proud of the multi-device support. | ||
4248 | */ | ||
4249 | int __init init_module(void) | ||
4250 | { | ||
4251 | int ret = -EIO; /* Return error if no cards found */ | ||
4252 | int i; | ||
4253 | |||
4254 | #ifdef DEBUG_MODULE_TRACE | ||
4255 | printk(KERN_DEBUG "-> init_module()\n"); | ||
4256 | #endif | ||
4257 | |||
4258 | /* If probing is asked */ | ||
4259 | if (io[0] == 0) { | ||
4260 | #ifdef DEBUG_CONFIG_ERROR | ||
4261 | printk(KERN_WARNING | ||
4262 | "WaveLAN init_module(): doing device probing (bad !)\n"); | ||
4263 | printk(KERN_WARNING | ||
4264 | "Specify base addresses while loading module to correct the problem\n"); | ||
4265 | #endif | ||
4266 | |||
4267 | /* Copy the basic set of address to be probed. */ | ||
4268 | for (i = 0; i < ARRAY_SIZE(iobase); i++) | ||
4269 | io[i] = iobase[i]; | ||
4270 | } | ||
4271 | |||
4272 | |||
4273 | /* Loop on all possible base addresses. */ | ||
4274 | for (i = 0; i < ARRAY_SIZE(io) && io[i] != 0; i++) { | ||
4275 | struct net_device *dev = alloc_etherdev(sizeof(net_local)); | ||
4276 | if (!dev) | ||
4277 | break; | ||
4278 | if (name[i]) | ||
4279 | strcpy(dev->name, name[i]); /* Copy name */ | ||
4280 | dev->base_addr = io[i]; | ||
4281 | dev->irq = irq[i]; | ||
4282 | |||
4283 | /* Check if there is something at this base address. */ | ||
4284 | if (wavelan_config(dev, io[i]) == 0) { | ||
4285 | if (register_netdev(dev) != 0) { | ||
4286 | release_region(dev->base_addr, sizeof(ha_t)); | ||
4287 | wavelan_list = wavelan_list->next; | ||
4288 | } else { | ||
4289 | ret = 0; | ||
4290 | continue; | ||
4291 | } | ||
4292 | } | ||
4293 | free_netdev(dev); | ||
4294 | } | ||
4295 | |||
4296 | #ifdef DEBUG_CONFIG_ERROR | ||
4297 | if (!wavelan_list) | ||
4298 | printk(KERN_WARNING | ||
4299 | "WaveLAN init_module(): no device found\n"); | ||
4300 | #endif | ||
4301 | |||
4302 | #ifdef DEBUG_MODULE_TRACE | ||
4303 | printk(KERN_DEBUG "<- init_module()\n"); | ||
4304 | #endif | ||
4305 | return ret; | ||
4306 | } | ||
4307 | |||
4308 | /*------------------------------------------------------------------*/ | ||
4309 | /* | ||
4310 | * Removal of the module | ||
4311 | */ | ||
4312 | void cleanup_module(void) | ||
4313 | { | ||
4314 | #ifdef DEBUG_MODULE_TRACE | ||
4315 | printk(KERN_DEBUG "-> cleanup_module()\n"); | ||
4316 | #endif | ||
4317 | |||
4318 | /* Loop on all devices and release them. */ | ||
4319 | while (wavelan_list) { | ||
4320 | struct net_device *dev = wavelan_list->dev; | ||
4321 | |||
4322 | #ifdef DEBUG_CONFIG_INFO | ||
4323 | printk(KERN_DEBUG | ||
4324 | "%s: cleanup_module(): removing device at 0x%x\n", | ||
4325 | dev->name, (unsigned int) dev); | ||
4326 | #endif | ||
4327 | unregister_netdev(dev); | ||
4328 | |||
4329 | release_region(dev->base_addr, sizeof(ha_t)); | ||
4330 | wavelan_list = wavelan_list->next; | ||
4331 | |||
4332 | free_netdev(dev); | ||
4333 | } | ||
4334 | |||
4335 | #ifdef DEBUG_MODULE_TRACE | ||
4336 | printk(KERN_DEBUG "<- cleanup_module()\n"); | ||
4337 | #endif | ||
4338 | } | ||
4339 | #endif /* MODULE */ | ||
4340 | MODULE_LICENSE("GPL"); | ||
4341 | |||
4342 | /* | ||
4343 | * This software may only be used and distributed | ||
4344 | * according to the terms of the GNU General Public License. | ||
4345 | * | ||
4346 | * This software was developed as a component of the | ||
4347 | * Linux operating system. | ||
4348 | * It is based on other device drivers and information | ||
4349 | * either written or supplied by: | ||
4350 | * Ajay Bakre (bakre@paul.rutgers.edu), | ||
4351 | * Donald Becker (becker@scyld.com), | ||
4352 | * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), | ||
4353 | * Anders Klemets (klemets@it.kth.se), | ||
4354 | * Vladimir V. Kolpakov (w@stier.koenig.ru), | ||
4355 | * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), | ||
4356 | * Pauline Middelink (middelin@polyware.iaf.nl), | ||
4357 | * Robert Morris (rtm@das.harvard.edu), | ||
4358 | * Jean Tourrilhes (jt@hplb.hpl.hp.com), | ||
4359 | * Girish Welling (welling@paul.rutgers.edu), | ||
4360 | * | ||
4361 | * Thanks go also to: | ||
4362 | * James Ashton (jaa101@syseng.anu.edu.au), | ||
4363 | * Alan Cox (alan@lxorguk.ukuu.org.uk), | ||
4364 | * Allan Creighton (allanc@cs.usyd.edu.au), | ||
4365 | * Matthew Geier (matthew@cs.usyd.edu.au), | ||
4366 | * Remo di Giovanni (remo@cs.usyd.edu.au), | ||
4367 | * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), | ||
4368 | * Vipul Gupta (vgupta@cs.binghamton.edu), | ||
4369 | * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), | ||
4370 | * Tim Nicholson (tim@cs.usyd.edu.au), | ||
4371 | * Ian Parkin (ian@cs.usyd.edu.au), | ||
4372 | * John Rosenberg (johnr@cs.usyd.edu.au), | ||
4373 | * George Rossi (george@phm.gov.au), | ||
4374 | * Arthur Scott (arthur@cs.usyd.edu.au), | ||
4375 | * Peter Storey, | ||
4376 | * for their assistance and advice. | ||
4377 | * | ||
4378 | * Please send bug reports, updates, comments to: | ||
4379 | * | ||
4380 | * Bruce Janson Email: bruce@cs.usyd.edu.au | ||
4381 | * Basser Department of Computer Science Phone: +61-2-9351-3423 | ||
4382 | * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 | ||
4383 | */ | ||
diff --git a/drivers/net/wireless/wavelan.h b/drivers/net/wireless/wavelan.h deleted file mode 100644 index 9ab360558ffd..000000000000 --- a/drivers/net/wireless/wavelan.h +++ /dev/null | |||
@@ -1,370 +0,0 @@ | |||
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 | } __attribute__ ((packed)); | ||
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 | } __attribute__ ((packed)); | ||
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 | } __attribute__ ((packed)); | ||
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 deleted file mode 100644 index dbe8de6e5f52..000000000000 --- a/drivers/net/wireless/wavelan.p.h +++ /dev/null | |||
@@ -1,696 +0,0 @@ | |||
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 | * It might be a good idea as well to fetch the wireless tools to | ||
102 | * configure the device and play a bit. | ||
103 | */ | ||
104 | |||
105 | /* ---------------------------- FILES ---------------------------- */ | ||
106 | /* | ||
107 | * wavelan.c: actual code for the driver: C functions | ||
108 | * | ||
109 | * wavelan.p.h: private header: local types and variables for driver | ||
110 | * | ||
111 | * wavelan.h: description of the hardware interface and structs | ||
112 | * | ||
113 | * i82586.h: description of the Ethernet controller | ||
114 | */ | ||
115 | |||
116 | /* --------------------------- HISTORY --------------------------- */ | ||
117 | /* | ||
118 | * This is based on information in the drivers' headers. It may not be | ||
119 | * accurate, and I guarantee only my best effort. | ||
120 | * | ||
121 | * The history of the WaveLAN drivers is as complicated as the history of | ||
122 | * the WaveLAN itself (NCR -> AT&T -> Lucent). | ||
123 | * | ||
124 | * It all started with Anders Klemets <klemets@paul.rutgers.edu> | ||
125 | * writing a WaveLAN ISA driver for the Mach microkernel. Girish | ||
126 | * Welling <welling@paul.rutgers.edu> had also worked on it. | ||
127 | * Keith Moore modified this for the PCMCIA hardware. | ||
128 | * | ||
129 | * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI | ||
130 | * and added specific PCMCIA support (there is currently no equivalent | ||
131 | * of the PCMCIA package under BSD). | ||
132 | * | ||
133 | * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD. | ||
134 | * | ||
135 | * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux. | ||
136 | * | ||
137 | * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver | ||
138 | * (with help of the BSDI PCMCIA driver) for PCMCIA. | ||
139 | * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work. | ||
140 | * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start | ||
141 | * 2.00 cards correctly (2.4 GHz with frequency selection). | ||
142 | * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his | ||
143 | * PCMCIA package (and bug corrections). | ||
144 | * | ||
145 | * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some | ||
146 | * patches to the PCMCIA driver. Later, I added code in the ISA driver | ||
147 | * for Wireless Extensions and full support of frequency selection | ||
148 | * cards. Then, I did the same to the PCMCIA driver, and did some | ||
149 | * reorganisation. Finally, I came back to the ISA driver to | ||
150 | * upgrade it at the same level as the PCMCIA one and reorganise | ||
151 | * the code. | ||
152 | * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me | ||
153 | * much needed information on the WaveLAN hardware. | ||
154 | */ | ||
155 | |||
156 | /* The original copyrights and literature mention others' names and | ||
157 | * credits. I don't know what their part in this development was. | ||
158 | */ | ||
159 | |||
160 | /* By the way, for the copyright and legal stuff: | ||
161 | * almost everybody wrote code under the GNU or BSD license (or similar), | ||
162 | * and want their original copyright to remain somewhere in the | ||
163 | * code (for myself, I go with the GPL). | ||
164 | * Nobody wants to take responsibility for anything, except the fame. | ||
165 | */ | ||
166 | |||
167 | /* --------------------------- CREDITS --------------------------- */ | ||
168 | /* | ||
169 | * This software was developed as a component of the | ||
170 | * Linux operating system. | ||
171 | * It is based on other device drivers and information | ||
172 | * either written or supplied by: | ||
173 | * Ajay Bakre <bakre@paul.rutgers.edu>, | ||
174 | * Donald Becker <becker@cesdis.gsfc.nasa.gov>, | ||
175 | * Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>, | ||
176 | * Brent Elphick <belphick@uwaterloo.ca>, | ||
177 | * Anders Klemets <klemets@it.kth.se>, | ||
178 | * Vladimir V. Kolpakov <w@stier.koenig.ru>, | ||
179 | * Marc Meertens <Marc.Meertens@Utrecht.NCR.com>, | ||
180 | * Pauline Middelink <middelin@polyware.iaf.nl>, | ||
181 | * Robert Morris <rtm@das.harvard.edu>, | ||
182 | * Jean Tourrilhes <jt@hpl.hp.com>, | ||
183 | * Girish Welling <welling@paul.rutgers.edu>, | ||
184 | * Clark Woodworth <clark@hiway1.exit109.com> | ||
185 | * Yongguang Zhang <ygz@isl.hrl.hac.com> | ||
186 | * | ||
187 | * Thanks go also to: | ||
188 | * James Ashton <jaa101@syseng.anu.edu.au>, | ||
189 | * Alan Cox <alan@lxorguk.ukuu.org.uk>, | ||
190 | * Allan Creighton <allanc@cs.usyd.edu.au>, | ||
191 | * Matthew Geier <matthew@cs.usyd.edu.au>, | ||
192 | * Remo di Giovanni <remo@cs.usyd.edu.au>, | ||
193 | * Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>, | ||
194 | * Vipul Gupta <vgupta@cs.binghamton.edu>, | ||
195 | * Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>, | ||
196 | * Tim Nicholson <tim@cs.usyd.edu.au>, | ||
197 | * Ian Parkin <ian@cs.usyd.edu.au>, | ||
198 | * John Rosenberg <johnr@cs.usyd.edu.au>, | ||
199 | * George Rossi <george@phm.gov.au>, | ||
200 | * Arthur Scott <arthur@cs.usyd.edu.au>, | ||
201 | * Stanislav Sinyagin <stas@isf.ru> | ||
202 | * and Peter Storey for their assistance and advice. | ||
203 | * | ||
204 | * Additional Credits: | ||
205 | * | ||
206 | * My development has been done initially under Debian 1.1 (Linux 2.0.x) | ||
207 | * and now under Debian 2.2, initially with an HP Vectra XP/60, and now | ||
208 | * an HP Vectra XP/90. | ||
209 | * | ||
210 | */ | ||
211 | |||
212 | /* ------------------------- IMPROVEMENTS ------------------------- */ | ||
213 | /* | ||
214 | * I proudly present: | ||
215 | * | ||
216 | * Changes made in first pre-release: | ||
217 | * ---------------------------------- | ||
218 | * - reorganisation of the code, function name change | ||
219 | * - creation of private header (wavelan.p.h) | ||
220 | * - reorganised debug messages | ||
221 | * - more comments, history, etc. | ||
222 | * - mmc_init: configure the PSA if not done | ||
223 | * - mmc_init: correct default value of level threshold for PCMCIA | ||
224 | * - mmc_init: 2.00 detection better code for 2.00 initialization | ||
225 | * - better info at startup | ||
226 | * - IRQ setting (note: this setting is permanent) | ||
227 | * - watchdog: change strategy (and solve module removal problems) | ||
228 | * - add wireless extensions (ioctl and get_wireless_stats) | ||
229 | * get/set nwid/frequency on fly, info for /proc/net/wireless | ||
230 | * - more wireless extensions: SETSPY and GETSPY | ||
231 | * - make wireless extensions optional | ||
232 | * - private ioctl to set/get quality and level threshold, histogram | ||
233 | * - remove /proc/net/wavelan | ||
234 | * - suppress useless stuff from lp (net_local) | ||
235 | * - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) | ||
236 | * - add message level (debug stuff in /var/adm/debug and errors not | ||
237 | * displayed at console and still in /var/adm/messages) | ||
238 | * - multi device support | ||
239 | * - start fixing the probe (init code) | ||
240 | * - more inlines | ||
241 | * - man page | ||
242 | * - many other minor details and cleanups | ||
243 | * | ||
244 | * Changes made in second pre-release: | ||
245 | * ----------------------------------- | ||
246 | * - clean up init code (probe and module init) | ||
247 | * - better multiple device support (module) | ||
248 | * - name assignment (module) | ||
249 | * | ||
250 | * Changes made in third pre-release: | ||
251 | * ---------------------------------- | ||
252 | * - be more conservative on timers | ||
253 | * - preliminary support for multicast (I still lack some details) | ||
254 | * | ||
255 | * Changes made in fourth pre-release: | ||
256 | * ----------------------------------- | ||
257 | * - multicast (revisited and finished) | ||
258 | * - avoid reset in set_multicast_list (a really big hack) | ||
259 | * if somebody could apply this code for other i82586 based drivers | ||
260 | * - share onboard memory 75% RU and 25% CU (instead of 50/50) | ||
261 | * | ||
262 | * Changes made for release in 2.1.15: | ||
263 | * ----------------------------------- | ||
264 | * - change the detection code for multi manufacturer code support | ||
265 | * | ||
266 | * Changes made for release in 2.1.17: | ||
267 | * ----------------------------------- | ||
268 | * - update to wireless extensions changes | ||
269 | * - silly bug in card initial configuration (psa_conf_status) | ||
270 | * | ||
271 | * Changes made for release in 2.1.27 & 2.0.30: | ||
272 | * -------------------------------------------- | ||
273 | * - small bug in debug code (probably not the last one...) | ||
274 | * - remove extern keyword for wavelan_probe() | ||
275 | * - level threshold is now a standard wireless extension (version 4 !) | ||
276 | * - modules parameters types (new module interface) | ||
277 | * | ||
278 | * Changes made for release in 2.1.36: | ||
279 | * ----------------------------------- | ||
280 | * - byte count stats (courtesy of David Hinds) | ||
281 | * - remove dev_tint stuff (courtesy of David Hinds) | ||
282 | * - encryption setting from Brent Elphick (thanks a lot!) | ||
283 | * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) | ||
284 | * | ||
285 | * Other changes (not by me) : | ||
286 | * ------------------------- | ||
287 | * - Spelling and gramar "rectification". | ||
288 | * | ||
289 | * Changes made for release in 2.0.37 & 2.2.2 : | ||
290 | * ------------------------------------------ | ||
291 | * - Correct status in /proc/net/wireless | ||
292 | * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) | ||
293 | * - Module init code don't fail if we found at least one card in | ||
294 | * the address list (Karlis Peisenieks) | ||
295 | * - Missing parenthesis (Christopher Peterson) | ||
296 | * - Correct i82586 configuration parameters | ||
297 | * - Encryption initialisation bug (Robert McCormack) | ||
298 | * - New mac addresses detected in the probe | ||
299 | * - Increase watchdog for busy environments | ||
300 | * | ||
301 | * Changes made for release in 2.0.38 & 2.2.7 : | ||
302 | * ------------------------------------------ | ||
303 | * - Correct the reception logic to better report errors and avoid | ||
304 | * sending bogus packet up the stack | ||
305 | * - Delay RU config to avoid corrupting first received packet | ||
306 | * - Change config completion code (to actually check something) | ||
307 | * - Avoid reading out of bound in skbuf to transmit | ||
308 | * - Rectify a lot of (useless) debugging code | ||
309 | * - Change the way to `#ifdef SET_PSA_CRC' | ||
310 | * | ||
311 | * Changes made for release in 2.2.11 & 2.3.13 : | ||
312 | * ------------------------------------------- | ||
313 | * - Change e-mail and web page addresses | ||
314 | * - Watchdog timer is now correctly expressed in HZ, not in jiffies | ||
315 | * - Add channel number to the list of frequencies in range | ||
316 | * - Add the (short) list of bit-rates in range | ||
317 | * - Developp a new sensitivity... (sens.value & sens.fixed) | ||
318 | * | ||
319 | * Changes made for release in 2.2.14 & 2.3.23 : | ||
320 | * ------------------------------------------- | ||
321 | * - Fix check for root permission (break instead of exit) | ||
322 | * - New nwid & encoding setting (Wireless Extension 9) | ||
323 | * | ||
324 | * Changes made for release in 2.3.49 : | ||
325 | * ---------------------------------- | ||
326 | * - Indentation reformating (Alan) | ||
327 | * - Update to new network API (softnet - 2.3.43) : | ||
328 | * o replace dev->tbusy (Alan) | ||
329 | * o replace dev->tstart (Alan) | ||
330 | * o remove dev->interrupt (Alan) | ||
331 | * o add SMP locking via spinlock in splxx (me) | ||
332 | * o add spinlock in interrupt handler (me) | ||
333 | * o use kernel watchdog instead of ours (me) | ||
334 | * o increase watchdog timeout (kernel is more sensitive) (me) | ||
335 | * o verify that all the changes make sense and work (me) | ||
336 | * - Fixup a potential gotcha when reconfiguring and thighten a bit | ||
337 | * the interactions with Tx queue. | ||
338 | * | ||
339 | * Changes made for release in 2.4.0 : | ||
340 | * --------------------------------- | ||
341 | * - Fix spinlock stupid bugs that I left in. The driver is now SMP | ||
342 | * compliant and doesn't lockup at startup. | ||
343 | * | ||
344 | * Changes made for release in 2.5.2 : | ||
345 | * --------------------------------- | ||
346 | * - Use new driver API for Wireless Extensions : | ||
347 | * o got rid of wavelan_ioctl() | ||
348 | * o use a bunch of iw_handler instead | ||
349 | * | ||
350 | * Changes made for release in 2.5.35 : | ||
351 | * ---------------------------------- | ||
352 | * - Set dev->trans_start to avoid filling the logs | ||
353 | * - Handle better spurious/bogus interrupt | ||
354 | * - Avoid deadlocks in mmc_out()/mmc_in() | ||
355 | * | ||
356 | * Wishes & dreams: | ||
357 | * ---------------- | ||
358 | * - roaming (see Pcmcia driver) | ||
359 | */ | ||
360 | |||
361 | /***************************** INCLUDES *****************************/ | ||
362 | |||
363 | #include <linux/module.h> | ||
364 | |||
365 | #include <linux/kernel.h> | ||
366 | #include <linux/sched.h> | ||
367 | #include <linux/types.h> | ||
368 | #include <linux/fcntl.h> | ||
369 | #include <linux/interrupt.h> | ||
370 | #include <linux/stat.h> | ||
371 | #include <linux/ptrace.h> | ||
372 | #include <linux/ioport.h> | ||
373 | #include <linux/in.h> | ||
374 | #include <linux/string.h> | ||
375 | #include <linux/delay.h> | ||
376 | #include <linux/bitops.h> | ||
377 | #include <asm/system.h> | ||
378 | #include <asm/io.h> | ||
379 | #include <asm/dma.h> | ||
380 | #include <asm/uaccess.h> | ||
381 | #include <linux/errno.h> | ||
382 | #include <linux/netdevice.h> | ||
383 | #include <linux/etherdevice.h> | ||
384 | #include <linux/skbuff.h> | ||
385 | #include <linux/slab.h> | ||
386 | #include <linux/timer.h> | ||
387 | #include <linux/init.h> | ||
388 | |||
389 | #include <linux/wireless.h> /* Wireless extensions */ | ||
390 | #include <net/iw_handler.h> /* Wireless handlers */ | ||
391 | |||
392 | /* WaveLAN declarations */ | ||
393 | #include "i82586.h" | ||
394 | #include "wavelan.h" | ||
395 | |||
396 | /************************** DRIVER OPTIONS **************************/ | ||
397 | /* | ||
398 | * `#define' or `#undef' the following constant to change the behaviour | ||
399 | * of the driver... | ||
400 | */ | ||
401 | #undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ | ||
402 | #define USE_PSA_CONFIG /* Use info from the PSA. */ | ||
403 | #undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ | ||
404 | #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ | ||
405 | #undef SET_MAC_ADDRESS /* Experimental */ | ||
406 | |||
407 | /* Warning: this stuff will slow down the driver. */ | ||
408 | #define WIRELESS_SPY /* Enable spying addresses. */ | ||
409 | #undef HISTOGRAM /* Enable histogram of signal level. */ | ||
410 | |||
411 | /****************************** DEBUG ******************************/ | ||
412 | |||
413 | #undef DEBUG_MODULE_TRACE /* module insertion/removal */ | ||
414 | #undef DEBUG_CALLBACK_TRACE /* calls made by Linux */ | ||
415 | #undef DEBUG_INTERRUPT_TRACE /* calls to handler */ | ||
416 | #undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */ | ||
417 | #define DEBUG_INTERRUPT_ERROR /* problems */ | ||
418 | #undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ | ||
419 | #undef DEBUG_CONFIG_INFO /* what's going on */ | ||
420 | #define DEBUG_CONFIG_ERROR /* errors on configuration */ | ||
421 | #undef DEBUG_TX_TRACE /* transmission calls */ | ||
422 | #undef DEBUG_TX_INFO /* header of the transmitted packet */ | ||
423 | #undef DEBUG_TX_FAIL /* Normal failure conditions */ | ||
424 | #define DEBUG_TX_ERROR /* Unexpected conditions */ | ||
425 | #undef DEBUG_RX_TRACE /* transmission calls */ | ||
426 | #undef DEBUG_RX_INFO /* header of the received packet */ | ||
427 | #undef DEBUG_RX_FAIL /* Normal failure conditions */ | ||
428 | #define DEBUG_RX_ERROR /* Unexpected conditions */ | ||
429 | |||
430 | #undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ | ||
431 | #undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ | ||
432 | #undef DEBUG_IOCTL_INFO /* various debugging info */ | ||
433 | #define DEBUG_IOCTL_ERROR /* what's going wrong */ | ||
434 | #define DEBUG_BASIC_SHOW /* Show basic startup info. */ | ||
435 | #undef DEBUG_VERSION_SHOW /* Print version info. */ | ||
436 | #undef DEBUG_PSA_SHOW /* Dump PSA to screen. */ | ||
437 | #undef DEBUG_MMC_SHOW /* Dump mmc to screen. */ | ||
438 | #undef DEBUG_SHOW_UNUSED /* Show unused fields too. */ | ||
439 | #undef DEBUG_I82586_SHOW /* Show i82586 status. */ | ||
440 | #undef DEBUG_DEVICE_SHOW /* Show device parameters. */ | ||
441 | |||
442 | /************************ CONSTANTS & MACROS ************************/ | ||
443 | |||
444 | #ifdef DEBUG_VERSION_SHOW | ||
445 | static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; | ||
446 | #endif | ||
447 | |||
448 | /* Watchdog temporisation */ | ||
449 | #define WATCHDOG_JIFFIES (512*HZ/100) | ||
450 | |||
451 | /* ------------------------ PRIVATE IOCTL ------------------------ */ | ||
452 | |||
453 | #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ | ||
454 | #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ | ||
455 | |||
456 | #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ | ||
457 | #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ | ||
458 | |||
459 | /****************************** TYPES ******************************/ | ||
460 | |||
461 | /* Shortcuts */ | ||
462 | typedef struct iw_statistics iw_stats; | ||
463 | typedef struct iw_quality iw_qual; | ||
464 | typedef struct iw_freq iw_freq;typedef struct net_local net_local; | ||
465 | typedef struct timer_list timer_list; | ||
466 | |||
467 | /* Basic types */ | ||
468 | typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ | ||
469 | |||
470 | /* | ||
471 | * Static specific data for the interface. | ||
472 | * | ||
473 | * For each network interface, Linux keeps data in two structures: "device" | ||
474 | * keeps the generic data (same format for everybody) and "net_local" keeps | ||
475 | * additional specific data. | ||
476 | */ | ||
477 | struct net_local | ||
478 | { | ||
479 | net_local * next; /* linked list of the devices */ | ||
480 | struct net_device * dev; /* reverse link */ | ||
481 | spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ | ||
482 | int nresets; /* number of hardware resets */ | ||
483 | u_char reconfig_82586; /* We need to reconfigure the controller. */ | ||
484 | u_char promiscuous; /* promiscuous mode */ | ||
485 | int mc_count; /* number of multicast addresses */ | ||
486 | u_short hacr; /* current host interface state */ | ||
487 | |||
488 | int tx_n_in_use; | ||
489 | u_short rx_head; | ||
490 | u_short rx_last; | ||
491 | u_short tx_first_free; | ||
492 | u_short tx_first_in_use; | ||
493 | |||
494 | iw_stats wstats; /* Wireless-specific statistics */ | ||
495 | |||
496 | struct iw_spy_data spy_data; | ||
497 | struct iw_public_data wireless_data; | ||
498 | |||
499 | #ifdef HISTOGRAM | ||
500 | int his_number; /* number of intervals */ | ||
501 | u_char his_range[16]; /* boundaries of interval ]n-1; n] */ | ||
502 | u_long his_sum[16]; /* sum in interval */ | ||
503 | #endif /* HISTOGRAM */ | ||
504 | }; | ||
505 | |||
506 | /**************************** PROTOTYPES ****************************/ | ||
507 | |||
508 | /* ----------------------- MISC. SUBROUTINES ------------------------ */ | ||
509 | static u_char | ||
510 | wv_irq_to_psa(int); | ||
511 | static int | ||
512 | wv_psa_to_irq(u_char); | ||
513 | /* ------------------- HOST ADAPTER SUBROUTINES ------------------- */ | ||
514 | static inline u_short /* data */ | ||
515 | hasr_read(u_long); /* Read the host interface: base address */ | ||
516 | static inline void | ||
517 | hacr_write(u_long, /* Write to host interface: base address */ | ||
518 | u_short), /* data */ | ||
519 | hacr_write_slow(u_long, | ||
520 | u_short), | ||
521 | set_chan_attn(u_long, /* ioaddr */ | ||
522 | u_short), /* hacr */ | ||
523 | wv_hacr_reset(u_long), /* ioaddr */ | ||
524 | wv_16_off(u_long, /* ioaddr */ | ||
525 | u_short), /* hacr */ | ||
526 | wv_16_on(u_long, /* ioaddr */ | ||
527 | u_short), /* hacr */ | ||
528 | wv_ints_off(struct net_device *), | ||
529 | wv_ints_on(struct net_device *); | ||
530 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | ||
531 | static void | ||
532 | psa_read(u_long, /* Read the Parameter Storage Area. */ | ||
533 | u_short, /* hacr */ | ||
534 | int, /* offset in PSA */ | ||
535 | u_char *, /* buffer to fill */ | ||
536 | int), /* size to read */ | ||
537 | psa_write(u_long, /* Write to the PSA. */ | ||
538 | u_short, /* hacr */ | ||
539 | int, /* offset in PSA */ | ||
540 | u_char *, /* buffer in memory */ | ||
541 | int); /* length of buffer */ | ||
542 | static inline void | ||
543 | mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */ | ||
544 | u_short, | ||
545 | u_char), | ||
546 | mmc_write(u_long, /* Write n bytes to the MMC. */ | ||
547 | u_char, | ||
548 | u_char *, | ||
549 | int); | ||
550 | static inline u_char /* Read 1 byte from the MMC. */ | ||
551 | mmc_in(u_long, | ||
552 | u_short); | ||
553 | static inline void | ||
554 | mmc_read(u_long, /* Read n bytes from the MMC. */ | ||
555 | u_char, | ||
556 | u_char *, | ||
557 | int), | ||
558 | fee_wait(u_long, /* Wait for frequency EEPROM: base address */ | ||
559 | int, /* base delay to wait for */ | ||
560 | int); /* time to wait */ | ||
561 | static void | ||
562 | fee_read(u_long, /* Read the frequency EEPROM: base address */ | ||
563 | u_short, /* destination offset */ | ||
564 | u_short *, /* data buffer */ | ||
565 | int); /* number of registers */ | ||
566 | /* ---------------------- I82586 SUBROUTINES ----------------------- */ | ||
567 | static /*inline*/ void | ||
568 | obram_read(u_long, /* ioaddr */ | ||
569 | u_short, /* o */ | ||
570 | u_char *, /* b */ | ||
571 | int); /* n */ | ||
572 | static inline void | ||
573 | obram_write(u_long, /* ioaddr */ | ||
574 | u_short, /* o */ | ||
575 | u_char *, /* b */ | ||
576 | int); /* n */ | ||
577 | static void | ||
578 | wv_ack(struct net_device *); | ||
579 | static inline int | ||
580 | wv_synchronous_cmd(struct net_device *, | ||
581 | const char *), | ||
582 | wv_config_complete(struct net_device *, | ||
583 | u_long, | ||
584 | net_local *); | ||
585 | static int | ||
586 | wv_complete(struct net_device *, | ||
587 | u_long, | ||
588 | net_local *); | ||
589 | static inline void | ||
590 | wv_82586_reconfig(struct net_device *); | ||
591 | /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ | ||
592 | #ifdef DEBUG_I82586_SHOW | ||
593 | static void | ||
594 | wv_scb_show(unsigned short); | ||
595 | #endif | ||
596 | static inline void | ||
597 | wv_init_info(struct net_device *); /* display startup info */ | ||
598 | /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ | ||
599 | static iw_stats * | ||
600 | wavelan_get_wireless_stats(struct net_device *); | ||
601 | static void | ||
602 | wavelan_set_multicast_list(struct net_device *); | ||
603 | /* ----------------------- PACKET RECEPTION ----------------------- */ | ||
604 | static inline void | ||
605 | wv_packet_read(struct net_device *, /* Read a packet from a frame. */ | ||
606 | u_short, | ||
607 | int), | ||
608 | wv_receive(struct net_device *); /* Read all packets waiting. */ | ||
609 | /* --------------------- PACKET TRANSMISSION --------------------- */ | ||
610 | static inline int | ||
611 | wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ | ||
612 | void *, | ||
613 | short); | ||
614 | static netdev_tx_t | ||
615 | wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ | ||
616 | struct net_device *); | ||
617 | /* -------------------- HARDWARE CONFIGURATION -------------------- */ | ||
618 | static inline int | ||
619 | wv_mmc_init(struct net_device *), /* Initialize the modem. */ | ||
620 | wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ | ||
621 | wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ | ||
622 | wv_82586_start(struct net_device *); /* Start the i82586. */ | ||
623 | static void | ||
624 | wv_82586_config(struct net_device *); /* Configure the i82586. */ | ||
625 | static inline void | ||
626 | wv_82586_stop(struct net_device *); | ||
627 | static int | ||
628 | wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ | ||
629 | wv_check_ioaddr(u_long, /* ioaddr */ | ||
630 | u_char *); /* mac address (read) */ | ||
631 | /* ---------------------- INTERRUPT HANDLING ---------------------- */ | ||
632 | static irqreturn_t | ||
633 | wavelan_interrupt(int, /* interrupt handler */ | ||
634 | void *); | ||
635 | static void | ||
636 | wavelan_watchdog(struct net_device *); /* transmission watchdog */ | ||
637 | /* ------------------- CONFIGURATION CALLBACKS ------------------- */ | ||
638 | static int | ||
639 | wavelan_open(struct net_device *), /* Open the device. */ | ||
640 | wavelan_close(struct net_device *), /* Close the device. */ | ||
641 | wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ | ||
642 | extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ | ||
643 | |||
644 | /**************************** VARIABLES ****************************/ | ||
645 | |||
646 | /* | ||
647 | * This is the root of the linked list of WaveLAN drivers | ||
648 | * It is use to verify that we don't reuse the same base address | ||
649 | * for two different drivers and to clean up when removing the module. | ||
650 | */ | ||
651 | static net_local * wavelan_list = (net_local *) NULL; | ||
652 | |||
653 | /* | ||
654 | * This table is used to translate the PSA value to IRQ number | ||
655 | * and vice versa. | ||
656 | */ | ||
657 | static u_char irqvals[] = | ||
658 | { | ||
659 | 0, 0, 0, 0x01, | ||
660 | 0x02, 0x04, 0, 0x08, | ||
661 | 0, 0, 0x10, 0x20, | ||
662 | 0x40, 0, 0, 0x80, | ||
663 | }; | ||
664 | |||
665 | /* | ||
666 | * Table of the available I/O addresses (base addresses) for WaveLAN | ||
667 | */ | ||
668 | static unsigned short iobase[] = | ||
669 | { | ||
670 | #if 0 | ||
671 | /* Leave out 0x3C0 for now -- seems to clash with some video | ||
672 | * controllers. | ||
673 | * Leave out the others too -- we will always use 0x390 and leave | ||
674 | * 0x300 for the Ethernet device. | ||
675 | * Jean II: 0x3E0 is fine as well. | ||
676 | */ | ||
677 | 0x300, 0x390, 0x3E0, 0x3C0 | ||
678 | #endif /* 0 */ | ||
679 | 0x390, 0x3E0 | ||
680 | }; | ||
681 | |||
682 | #ifdef MODULE | ||
683 | /* Parameters set by insmod */ | ||
684 | static int io[4]; | ||
685 | static int irq[4]; | ||
686 | static char *name[4]; | ||
687 | module_param_array(io, int, NULL, 0); | ||
688 | module_param_array(irq, int, NULL, 0); | ||
689 | module_param_array(name, charp, NULL, 0); | ||
690 | |||
691 | MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required"); | ||
692 | MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)"); | ||
693 | MODULE_PARM_DESC(name, "WaveLAN interface neme(s)"); | ||
694 | #endif /* MODULE */ | ||
695 | |||
696 | #endif /* WAVELAN_P_H */ | ||
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c deleted file mode 100644 index 431a20ec6db6..000000000000 --- a/drivers/net/wireless/wavelan_cs.c +++ /dev/null | |||
@@ -1,4635 +0,0 @@ | |||
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 | #ifdef WAVELAN_ROAMING | ||
63 | static void wl_cell_expiry(unsigned long data); | ||
64 | static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp); | ||
65 | static void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
66 | #endif /* WAVELAN_ROAMING */ | ||
67 | |||
68 | /************************* MISC SUBROUTINES **************************/ | ||
69 | /* | ||
70 | * Subroutines which won't fit in one of the following category | ||
71 | * (wavelan modem or i82593) | ||
72 | */ | ||
73 | |||
74 | /******************* MODEM MANAGEMENT SUBROUTINES *******************/ | ||
75 | /* | ||
76 | * Useful subroutines to manage the modem of the wavelan | ||
77 | */ | ||
78 | |||
79 | /*------------------------------------------------------------------*/ | ||
80 | /* | ||
81 | * Read from card's Host Adaptor Status Register. | ||
82 | */ | ||
83 | static inline u_char | ||
84 | hasr_read(u_long base) | ||
85 | { | ||
86 | return(inb(HASR(base))); | ||
87 | } /* hasr_read */ | ||
88 | |||
89 | /*------------------------------------------------------------------*/ | ||
90 | /* | ||
91 | * Write to card's Host Adapter Command Register. | ||
92 | */ | ||
93 | static inline void | ||
94 | hacr_write(u_long base, | ||
95 | u_char hacr) | ||
96 | { | ||
97 | outb(hacr, HACR(base)); | ||
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 void | ||
106 | hacr_write_slow(u_long base, | ||
107 | u_char hacr) | ||
108 | { | ||
109 | hacr_write(base, hacr); | ||
110 | /* delay might only be needed sometimes */ | ||
111 | mdelay(1); | ||
112 | } /* hacr_write_slow */ | ||
113 | |||
114 | /*------------------------------------------------------------------*/ | ||
115 | /* | ||
116 | * Read the Parameter Storage Area from the WaveLAN card's memory | ||
117 | */ | ||
118 | static void | ||
119 | psa_read(struct net_device * dev, | ||
120 | int o, /* offset in PSA */ | ||
121 | u_char * b, /* buffer to fill */ | ||
122 | int n) /* size to read */ | ||
123 | { | ||
124 | net_local *lp = netdev_priv(dev); | ||
125 | u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); | ||
126 | |||
127 | while(n-- > 0) | ||
128 | { | ||
129 | *b++ = readb(ptr); | ||
130 | /* Due to a lack of address decode pins, the WaveLAN PCMCIA card | ||
131 | * only supports reading even memory addresses. That means the | ||
132 | * increment here MUST be two. | ||
133 | * Because of that, we can't use memcpy_fromio()... | ||
134 | */ | ||
135 | ptr += 2; | ||
136 | } | ||
137 | } /* psa_read */ | ||
138 | |||
139 | /*------------------------------------------------------------------*/ | ||
140 | /* | ||
141 | * Write the Parameter Storage Area to the WaveLAN card's memory | ||
142 | */ | ||
143 | static void | ||
144 | psa_write(struct net_device * dev, | ||
145 | int o, /* Offset in psa */ | ||
146 | u_char * b, /* Buffer in memory */ | ||
147 | int n) /* Length of buffer */ | ||
148 | { | ||
149 | net_local *lp = netdev_priv(dev); | ||
150 | u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); | ||
151 | int count = 0; | ||
152 | unsigned int base = dev->base_addr; | ||
153 | /* As there seem to have no flag PSA_BUSY as in the ISA model, we are | ||
154 | * oblige to verify this address to know when the PSA is ready... */ | ||
155 | volatile u_char __iomem *verify = lp->mem + PSA_ADDR + | ||
156 | (psaoff(0, psa_comp_number) << 1); | ||
157 | |||
158 | /* Authorize writing to PSA */ | ||
159 | hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); | ||
160 | |||
161 | while(n-- > 0) | ||
162 | { | ||
163 | /* write to PSA */ | ||
164 | writeb(*b++, ptr); | ||
165 | ptr += 2; | ||
166 | |||
167 | /* I don't have the spec, so I don't know what the correct | ||
168 | * sequence to write is. This hack seem to work for me... */ | ||
169 | count = 0; | ||
170 | while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) | ||
171 | mdelay(1); | ||
172 | } | ||
173 | |||
174 | /* Put the host interface back in standard state */ | ||
175 | hacr_write(base, HACR_DEFAULT); | ||
176 | } /* psa_write */ | ||
177 | |||
178 | #ifdef SET_PSA_CRC | ||
179 | /*------------------------------------------------------------------*/ | ||
180 | /* | ||
181 | * Calculate the PSA CRC | ||
182 | * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code | ||
183 | * NOTE: By specifying a length including the CRC position the | ||
184 | * returned value should be zero. (i.e. a correct checksum in the PSA) | ||
185 | * | ||
186 | * The Windows drivers don't use the CRC, but the AP and the PtP tool | ||
187 | * depend on it. | ||
188 | */ | ||
189 | static u_short | ||
190 | psa_crc(unsigned char * psa, /* The PSA */ | ||
191 | int size) /* Number of short for CRC */ | ||
192 | { | ||
193 | int byte_cnt; /* Loop on the PSA */ | ||
194 | u_short crc_bytes = 0; /* Data in the PSA */ | ||
195 | int bit_cnt; /* Loop on the bits of the short */ | ||
196 | |||
197 | for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) | ||
198 | { | ||
199 | crc_bytes ^= psa[byte_cnt]; /* Its an xor */ | ||
200 | |||
201 | for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) | ||
202 | { | ||
203 | if(crc_bytes & 0x0001) | ||
204 | crc_bytes = (crc_bytes >> 1) ^ 0xA001; | ||
205 | else | ||
206 | crc_bytes >>= 1 ; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | return crc_bytes; | ||
211 | } /* psa_crc */ | ||
212 | #endif /* SET_PSA_CRC */ | ||
213 | |||
214 | /*------------------------------------------------------------------*/ | ||
215 | /* | ||
216 | * update the checksum field in the Wavelan's PSA | ||
217 | */ | ||
218 | static void | ||
219 | update_psa_checksum(struct net_device * dev) | ||
220 | { | ||
221 | #ifdef SET_PSA_CRC | ||
222 | psa_t psa; | ||
223 | u_short crc; | ||
224 | |||
225 | /* read the parameter storage area */ | ||
226 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
227 | |||
228 | /* update the checksum */ | ||
229 | crc = psa_crc((unsigned char *) &psa, | ||
230 | sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) | ||
231 | - sizeof(psa.psa_crc_status)); | ||
232 | |||
233 | psa.psa_crc[0] = crc & 0xFF; | ||
234 | psa.psa_crc[1] = (crc & 0xFF00) >> 8; | ||
235 | |||
236 | /* Write it ! */ | ||
237 | psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, | ||
238 | (unsigned char *)&psa.psa_crc, 2); | ||
239 | |||
240 | #ifdef DEBUG_IOCTL_INFO | ||
241 | printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", | ||
242 | dev->name, psa.psa_crc[0], psa.psa_crc[1]); | ||
243 | |||
244 | /* Check again (luxury !) */ | ||
245 | crc = psa_crc((unsigned char *) &psa, | ||
246 | sizeof(psa) - sizeof(psa.psa_crc_status)); | ||
247 | |||
248 | if(crc != 0) | ||
249 | printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); | ||
250 | #endif /* DEBUG_IOCTL_INFO */ | ||
251 | #endif /* SET_PSA_CRC */ | ||
252 | } /* update_psa_checksum */ | ||
253 | |||
254 | /*------------------------------------------------------------------*/ | ||
255 | /* | ||
256 | * Write 1 byte to the MMC. | ||
257 | */ | ||
258 | static void | ||
259 | mmc_out(u_long base, | ||
260 | u_short o, | ||
261 | u_char d) | ||
262 | { | ||
263 | int count = 0; | ||
264 | |||
265 | /* Wait for MMC to go idle */ | ||
266 | while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) | ||
267 | udelay(10); | ||
268 | |||
269 | outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); | ||
270 | outb(d, MMD(base)); | ||
271 | } | ||
272 | |||
273 | /*------------------------------------------------------------------*/ | ||
274 | /* | ||
275 | * Routine to write bytes to the Modem Management Controller. | ||
276 | * We start by the end because it is the way it should be ! | ||
277 | */ | ||
278 | static void | ||
279 | mmc_write(u_long base, | ||
280 | u_char o, | ||
281 | u_char * b, | ||
282 | int n) | ||
283 | { | ||
284 | o += n; | ||
285 | b += n; | ||
286 | |||
287 | while(n-- > 0 ) | ||
288 | mmc_out(base, --o, *(--b)); | ||
289 | } /* mmc_write */ | ||
290 | |||
291 | /*------------------------------------------------------------------*/ | ||
292 | /* | ||
293 | * Read 1 byte from the MMC. | ||
294 | * Optimised version for 1 byte, avoid using memory... | ||
295 | */ | ||
296 | static u_char | ||
297 | mmc_in(u_long base, | ||
298 | u_short o) | ||
299 | { | ||
300 | int count = 0; | ||
301 | |||
302 | while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) | ||
303 | udelay(10); | ||
304 | outb(o << 1, MMR(base)); /* Set the read address */ | ||
305 | |||
306 | outb(0, MMD(base)); /* Required dummy write */ | ||
307 | |||
308 | while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) | ||
309 | udelay(10); | ||
310 | return (u_char) (inb(MMD(base))); /* Now do the actual read */ | ||
311 | } | ||
312 | |||
313 | /*------------------------------------------------------------------*/ | ||
314 | /* | ||
315 | * Routine to read bytes from the Modem Management Controller. | ||
316 | * The implementation is complicated by a lack of address lines, | ||
317 | * which prevents decoding of the low-order bit. | ||
318 | * (code has just been moved in the above function) | ||
319 | * We start by the end because it is the way it should be ! | ||
320 | */ | ||
321 | static void | ||
322 | mmc_read(u_long base, | ||
323 | u_char o, | ||
324 | u_char * b, | ||
325 | int n) | ||
326 | { | ||
327 | o += n; | ||
328 | b += n; | ||
329 | |||
330 | while(n-- > 0) | ||
331 | *(--b) = mmc_in(base, --o); | ||
332 | } /* mmc_read */ | ||
333 | |||
334 | /*------------------------------------------------------------------*/ | ||
335 | /* | ||
336 | * Get the type of encryption available... | ||
337 | */ | ||
338 | static inline int | ||
339 | mmc_encr(u_long base) /* i/o port of the card */ | ||
340 | { | ||
341 | int temp; | ||
342 | |||
343 | temp = mmc_in(base, mmroff(0, mmr_des_avail)); | ||
344 | if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) | ||
345 | return 0; | ||
346 | else | ||
347 | return temp; | ||
348 | } | ||
349 | |||
350 | /*------------------------------------------------------------------*/ | ||
351 | /* | ||
352 | * Wait for the frequency EEprom to complete a command... | ||
353 | */ | ||
354 | static void | ||
355 | fee_wait(u_long base, /* i/o port of the card */ | ||
356 | int delay, /* Base delay to wait for */ | ||
357 | int number) /* Number of time to wait */ | ||
358 | { | ||
359 | int count = 0; /* Wait only a limited time */ | ||
360 | |||
361 | while((count++ < number) && | ||
362 | (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) | ||
363 | udelay(delay); | ||
364 | } | ||
365 | |||
366 | /*------------------------------------------------------------------*/ | ||
367 | /* | ||
368 | * Read bytes from the Frequency EEprom (frequency select cards). | ||
369 | */ | ||
370 | static void | ||
371 | fee_read(u_long base, /* i/o port of the card */ | ||
372 | u_short o, /* destination offset */ | ||
373 | u_short * b, /* data buffer */ | ||
374 | int n) /* number of registers */ | ||
375 | { | ||
376 | b += n; /* Position at the end of the area */ | ||
377 | |||
378 | /* Write the address */ | ||
379 | mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
380 | |||
381 | /* Loop on all buffer */ | ||
382 | while(n-- > 0) | ||
383 | { | ||
384 | /* Write the read command */ | ||
385 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); | ||
386 | |||
387 | /* Wait until EEprom is ready (should be quick !) */ | ||
388 | fee_wait(base, 10, 100); | ||
389 | |||
390 | /* Read the value */ | ||
391 | *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | | ||
392 | mmc_in(base, mmroff(0, mmr_fee_data_l))); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | |||
397 | /*------------------------------------------------------------------*/ | ||
398 | /* | ||
399 | * Write bytes from the Frequency EEprom (frequency select cards). | ||
400 | * This is a bit complicated, because the frequency eeprom has to | ||
401 | * be unprotected and the write enabled. | ||
402 | * Jean II | ||
403 | */ | ||
404 | static void | ||
405 | fee_write(u_long base, /* i/o port of the card */ | ||
406 | u_short o, /* destination offset */ | ||
407 | u_short * b, /* data buffer */ | ||
408 | int n) /* number of registers */ | ||
409 | { | ||
410 | b += n; /* Position at the end of the area */ | ||
411 | |||
412 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
413 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
414 | /* Ask to read the protected register */ | ||
415 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); | ||
416 | |||
417 | fee_wait(base, 10, 100); | ||
418 | |||
419 | /* Read the protected register */ | ||
420 | printk("Protected 2 : %02X-%02X\n", | ||
421 | mmc_in(base, mmroff(0, mmr_fee_data_h)), | ||
422 | mmc_in(base, mmroff(0, mmr_fee_data_l))); | ||
423 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
424 | |||
425 | /* Enable protected register */ | ||
426 | mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); | ||
427 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); | ||
428 | |||
429 | fee_wait(base, 10, 100); | ||
430 | |||
431 | /* Unprotect area */ | ||
432 | mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); | ||
433 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
434 | #ifdef DOESNT_SEEM_TO_WORK /* disabled */ | ||
435 | /* Or use : */ | ||
436 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); | ||
437 | #endif /* DOESNT_SEEM_TO_WORK */ | ||
438 | |||
439 | fee_wait(base, 10, 100); | ||
440 | #endif /* EEPROM_IS_PROTECTED */ | ||
441 | |||
442 | /* Write enable */ | ||
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_WREN); | ||
445 | |||
446 | fee_wait(base, 10, 100); | ||
447 | |||
448 | /* Write the EEprom address */ | ||
449 | mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); | ||
450 | |||
451 | /* Loop on all buffer */ | ||
452 | while(n-- > 0) | ||
453 | { | ||
454 | /* Write the value */ | ||
455 | mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); | ||
456 | mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); | ||
457 | |||
458 | /* Write the write command */ | ||
459 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); | ||
460 | |||
461 | /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ | ||
462 | mdelay(10); | ||
463 | fee_wait(base, 10, 100); | ||
464 | } | ||
465 | |||
466 | /* Write disable */ | ||
467 | mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); | ||
468 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); | ||
469 | |||
470 | fee_wait(base, 10, 100); | ||
471 | |||
472 | #ifdef EEPROM_IS_PROTECTED /* disabled */ | ||
473 | /* Reprotect EEprom */ | ||
474 | mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); | ||
475 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); | ||
476 | |||
477 | fee_wait(base, 10, 100); | ||
478 | #endif /* EEPROM_IS_PROTECTED */ | ||
479 | } | ||
480 | |||
481 | /******************* WaveLAN Roaming routines... ********************/ | ||
482 | |||
483 | #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ | ||
484 | |||
485 | static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00}; | ||
486 | |||
487 | static void wv_roam_init(struct net_device *dev) | ||
488 | { | ||
489 | net_local *lp= netdev_priv(dev); | ||
490 | |||
491 | /* Do not remove this unless you have a good reason */ | ||
492 | printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" | ||
493 | " device %s !\n", dev->name, dev->name); | ||
494 | printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" | ||
495 | " of the Wavelan driver.\n"); | ||
496 | printk(KERN_NOTICE "It may work, but may also make the driver behave in" | ||
497 | " erratic ways or crash.\n"); | ||
498 | |||
499 | lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ | ||
500 | lp->wavepoint_table.num_wavepoints=0; | ||
501 | lp->wavepoint_table.locked=0; | ||
502 | lp->curr_point=NULL; /* No default WavePoint */ | ||
503 | lp->cell_search=0; | ||
504 | |||
505 | lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ | ||
506 | lp->cell_timer.function=wl_cell_expiry; | ||
507 | lp->cell_timer.expires=jiffies+CELL_TIMEOUT; | ||
508 | add_timer(&lp->cell_timer); | ||
509 | |||
510 | wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ | ||
511 | /* to build up a good WavePoint */ | ||
512 | /* table... */ | ||
513 | printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); | ||
514 | } | ||
515 | |||
516 | static void wv_roam_cleanup(struct net_device *dev) | ||
517 | { | ||
518 | wavepoint_history *ptr,*old_ptr; | ||
519 | net_local *lp= netdev_priv(dev); | ||
520 | |||
521 | printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); | ||
522 | |||
523 | /* Fixme : maybe we should check that the timer exist before deleting it */ | ||
524 | del_timer(&lp->cell_timer); /* Remove cell expiry timer */ | ||
525 | ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ | ||
526 | while(ptr!=NULL) | ||
527 | { | ||
528 | old_ptr=ptr; | ||
529 | ptr=ptr->next; | ||
530 | wl_del_wavepoint(old_ptr,lp); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | /* Enable/Disable NWID promiscuous mode on a given device */ | ||
535 | static void wv_nwid_filter(unsigned char mode, net_local *lp) | ||
536 | { | ||
537 | mm_t m; | ||
538 | unsigned long flags; | ||
539 | |||
540 | #ifdef WAVELAN_ROAMING_DEBUG | ||
541 | printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); | ||
542 | #endif | ||
543 | |||
544 | /* Disable interrupts & save flags */ | ||
545 | spin_lock_irqsave(&lp->spinlock, flags); | ||
546 | |||
547 | m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; | ||
548 | mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); | ||
549 | |||
550 | if(mode==NWID_PROMISC) | ||
551 | lp->cell_search=1; | ||
552 | else | ||
553 | lp->cell_search=0; | ||
554 | |||
555 | /* ReEnable interrupts & restore flags */ | ||
556 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
557 | } | ||
558 | |||
559 | /* Find a record in the WavePoint table matching a given NWID */ | ||
560 | static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) | ||
561 | { | ||
562 | wavepoint_history *ptr=lp->wavepoint_table.head; | ||
563 | |||
564 | while(ptr!=NULL){ | ||
565 | if(ptr->nwid==nwid) | ||
566 | return ptr; | ||
567 | ptr=ptr->next; | ||
568 | } | ||
569 | return NULL; | ||
570 | } | ||
571 | |||
572 | /* Create a new wavepoint table entry */ | ||
573 | static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) | ||
574 | { | ||
575 | wavepoint_history *new_wavepoint; | ||
576 | |||
577 | #ifdef WAVELAN_ROAMING_DEBUG | ||
578 | printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); | ||
579 | #endif | ||
580 | |||
581 | if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) | ||
582 | return NULL; | ||
583 | |||
584 | new_wavepoint = kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); | ||
585 | if(new_wavepoint==NULL) | ||
586 | return NULL; | ||
587 | |||
588 | new_wavepoint->nwid=nwid; /* New WavePoints NWID */ | ||
589 | new_wavepoint->average_fast=0; /* Running Averages..*/ | ||
590 | new_wavepoint->average_slow=0; | ||
591 | new_wavepoint->qualptr=0; /* Start of ringbuffer */ | ||
592 | new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ | ||
593 | memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ | ||
594 | |||
595 | new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ | ||
596 | new_wavepoint->prev=NULL; | ||
597 | |||
598 | if(lp->wavepoint_table.head!=NULL) | ||
599 | lp->wavepoint_table.head->prev=new_wavepoint; | ||
600 | |||
601 | lp->wavepoint_table.head=new_wavepoint; | ||
602 | |||
603 | lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ | ||
604 | |||
605 | return new_wavepoint; | ||
606 | } | ||
607 | |||
608 | /* Remove a wavepoint entry from WavePoint table */ | ||
609 | static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) | ||
610 | { | ||
611 | if(wavepoint==NULL) | ||
612 | return; | ||
613 | |||
614 | if(lp->curr_point==wavepoint) | ||
615 | lp->curr_point=NULL; | ||
616 | |||
617 | if(wavepoint->prev!=NULL) | ||
618 | wavepoint->prev->next=wavepoint->next; | ||
619 | |||
620 | if(wavepoint->next!=NULL) | ||
621 | wavepoint->next->prev=wavepoint->prev; | ||
622 | |||
623 | if(lp->wavepoint_table.head==wavepoint) | ||
624 | lp->wavepoint_table.head=wavepoint->next; | ||
625 | |||
626 | lp->wavepoint_table.num_wavepoints--; | ||
627 | kfree(wavepoint); | ||
628 | } | ||
629 | |||
630 | /* Timer callback function - checks WavePoint table for stale entries */ | ||
631 | static void wl_cell_expiry(unsigned long data) | ||
632 | { | ||
633 | net_local *lp=(net_local *)data; | ||
634 | wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; | ||
635 | |||
636 | #if WAVELAN_ROAMING_DEBUG > 1 | ||
637 | printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); | ||
638 | #endif | ||
639 | |||
640 | if(lp->wavepoint_table.locked) | ||
641 | { | ||
642 | #if WAVELAN_ROAMING_DEBUG > 1 | ||
643 | printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); | ||
644 | #endif | ||
645 | |||
646 | lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ | ||
647 | add_timer(&lp->cell_timer); | ||
648 | return; | ||
649 | } | ||
650 | |||
651 | while(wavepoint!=NULL) | ||
652 | { | ||
653 | if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT)) | ||
654 | { | ||
655 | #ifdef WAVELAN_ROAMING_DEBUG | ||
656 | printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); | ||
657 | #endif | ||
658 | |||
659 | old_point=wavepoint; | ||
660 | wavepoint=wavepoint->next; | ||
661 | wl_del_wavepoint(old_point,lp); | ||
662 | } | ||
663 | else | ||
664 | wavepoint=wavepoint->next; | ||
665 | } | ||
666 | lp->cell_timer.expires=jiffies+CELL_TIMEOUT; | ||
667 | add_timer(&lp->cell_timer); | ||
668 | } | ||
669 | |||
670 | /* Update SNR history of a wavepoint */ | ||
671 | static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) | ||
672 | { | ||
673 | int i=0,num_missed=0,ptr=0; | ||
674 | int average_fast=0,average_slow=0; | ||
675 | |||
676 | num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed | ||
677 | any beacons? */ | ||
678 | if(num_missed) | ||
679 | for(i=0;i<num_missed;i++) | ||
680 | { | ||
681 | wavepoint->sigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ | ||
682 | wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ | ||
683 | } | ||
684 | wavepoint->last_seen=jiffies; /* Add beacon to history */ | ||
685 | wavepoint->last_seq=seq; | ||
686 | wavepoint->sigqual[wavepoint->qualptr++]=sigqual; | ||
687 | wavepoint->qualptr %=WAVEPOINT_HISTORY; | ||
688 | ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; | ||
689 | |||
690 | for(i=0;i<WAVEPOINT_FAST_HISTORY;i++) /* Update running averages */ | ||
691 | { | ||
692 | average_fast+=wavepoint->sigqual[ptr++]; | ||
693 | ptr %=WAVEPOINT_HISTORY; | ||
694 | } | ||
695 | |||
696 | average_slow=average_fast; | ||
697 | for(i=WAVEPOINT_FAST_HISTORY;i<WAVEPOINT_HISTORY;i++) | ||
698 | { | ||
699 | average_slow+=wavepoint->sigqual[ptr++]; | ||
700 | ptr %=WAVEPOINT_HISTORY; | ||
701 | } | ||
702 | |||
703 | wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; | ||
704 | wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; | ||
705 | } | ||
706 | |||
707 | /* Perform a handover to a new WavePoint */ | ||
708 | static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) | ||
709 | { | ||
710 | unsigned int base = lp->dev->base_addr; | ||
711 | mm_t m; | ||
712 | unsigned long flags; | ||
713 | |||
714 | if(wavepoint==lp->curr_point) /* Sanity check... */ | ||
715 | { | ||
716 | wv_nwid_filter(!NWID_PROMISC,lp); | ||
717 | return; | ||
718 | } | ||
719 | |||
720 | #ifdef WAVELAN_ROAMING_DEBUG | ||
721 | printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); | ||
722 | #endif | ||
723 | |||
724 | /* Disable interrupts & save flags */ | ||
725 | spin_lock_irqsave(&lp->spinlock, flags); | ||
726 | |||
727 | m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; | ||
728 | m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; | ||
729 | |||
730 | mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); | ||
731 | |||
732 | /* ReEnable interrupts & restore flags */ | ||
733 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
734 | |||
735 | wv_nwid_filter(!NWID_PROMISC,lp); | ||
736 | lp->curr_point=wavepoint; | ||
737 | } | ||
738 | |||
739 | /* Called when a WavePoint beacon is received */ | ||
740 | static void wl_roam_gather(struct net_device * dev, | ||
741 | u_char * hdr, /* Beacon header */ | ||
742 | u_char * stats) /* SNR, Signal quality | ||
743 | of packet */ | ||
744 | { | ||
745 | wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ | ||
746 | unsigned short nwid=ntohs(beacon->nwid); | ||
747 | unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ | ||
748 | wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ | ||
749 | net_local *lp = netdev_priv(dev); /* Device info */ | ||
750 | |||
751 | #ifdef I_NEED_THIS_FEATURE | ||
752 | /* Some people don't need this, some other may need it */ | ||
753 | nwid=nwid^ntohs(beacon->domain_id); | ||
754 | #endif | ||
755 | |||
756 | #if WAVELAN_ROAMING_DEBUG > 1 | ||
757 | printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); | ||
758 | printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); | ||
759 | #endif | ||
760 | |||
761 | lp->wavepoint_table.locked=1; /* <Mutex> */ | ||
762 | |||
763 | wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ | ||
764 | if(wavepoint==NULL) /* If no entry, Create a new one... */ | ||
765 | { | ||
766 | wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); | ||
767 | if(wavepoint==NULL) | ||
768 | goto out; | ||
769 | } | ||
770 | if(lp->curr_point==NULL) /* If this is the only WavePoint, */ | ||
771 | wv_roam_handover(wavepoint, lp); /* Jump on it! */ | ||
772 | |||
773 | wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history | ||
774 | stats. */ | ||
775 | |||
776 | if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ | ||
777 | if(!lp->cell_search) /* WavePoint is getting faint, */ | ||
778 | wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ | ||
779 | |||
780 | if(wavepoint->average_slow > | ||
781 | lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) | ||
782 | wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ | ||
783 | |||
784 | if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ | ||
785 | if(lp->cell_search) /* getting better, drop out of cell search mode */ | ||
786 | wv_nwid_filter(!NWID_PROMISC,lp); | ||
787 | |||
788 | out: | ||
789 | lp->wavepoint_table.locked=0; /* </MUTEX> :-) */ | ||
790 | } | ||
791 | |||
792 | /* Test this MAC frame a WavePoint beacon */ | ||
793 | static inline int WAVELAN_BEACON(unsigned char *data) | ||
794 | { | ||
795 | wavepoint_beacon *beacon= (wavepoint_beacon *)data; | ||
796 | static const wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; | ||
797 | |||
798 | if(memcmp(beacon,&beacon_template,9)==0) | ||
799 | return 1; | ||
800 | else | ||
801 | return 0; | ||
802 | } | ||
803 | #endif /* WAVELAN_ROAMING */ | ||
804 | |||
805 | /************************ I82593 SUBROUTINES *************************/ | ||
806 | /* | ||
807 | * Useful subroutines to manage the Ethernet controller | ||
808 | */ | ||
809 | |||
810 | /*------------------------------------------------------------------*/ | ||
811 | /* | ||
812 | * Routine to synchronously send a command to the i82593 chip. | ||
813 | * Should be called with interrupts disabled. | ||
814 | * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), | ||
815 | * wv_82593_config() & wv_diag()) | ||
816 | */ | ||
817 | static int | ||
818 | wv_82593_cmd(struct net_device * dev, | ||
819 | char * str, | ||
820 | int cmd, | ||
821 | int result) | ||
822 | { | ||
823 | unsigned int base = dev->base_addr; | ||
824 | int status; | ||
825 | int wait_completed; | ||
826 | long spin; | ||
827 | |||
828 | /* Spin until the chip finishes executing its current command (if any) */ | ||
829 | spin = 1000; | ||
830 | do | ||
831 | { | ||
832 | /* Time calibration of the loop */ | ||
833 | udelay(10); | ||
834 | |||
835 | /* Read the interrupt register */ | ||
836 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
837 | status = inb(LCSR(base)); | ||
838 | } | ||
839 | while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); | ||
840 | |||
841 | /* If the interrupt hasn't been posted */ | ||
842 | if (spin < 0) { | ||
843 | #ifdef DEBUG_INTERRUPT_ERROR | ||
844 | printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", | ||
845 | str, status); | ||
846 | #endif | ||
847 | return(FALSE); | ||
848 | } | ||
849 | |||
850 | /* Issue the command to the controller */ | ||
851 | outb(cmd, LCCR(base)); | ||
852 | |||
853 | /* If we don't have to check the result of the command | ||
854 | * Note : this mean that the irq handler will deal with that */ | ||
855 | if(result == SR0_NO_RESULT) | ||
856 | return(TRUE); | ||
857 | |||
858 | /* We are waiting for command completion */ | ||
859 | wait_completed = TRUE; | ||
860 | |||
861 | /* Busy wait while the LAN controller executes the command. */ | ||
862 | spin = 1000; | ||
863 | do | ||
864 | { | ||
865 | /* Time calibration of the loop */ | ||
866 | udelay(10); | ||
867 | |||
868 | /* Read the interrupt register */ | ||
869 | outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); | ||
870 | status = inb(LCSR(base)); | ||
871 | |||
872 | /* Check if there was an interrupt posted */ | ||
873 | if((status & SR0_INTERRUPT)) | ||
874 | { | ||
875 | /* Acknowledge the interrupt */ | ||
876 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); | ||
877 | |||
878 | /* Check if interrupt is a command completion */ | ||
879 | if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && | ||
880 | ((status & SR0_BOTH_RX_TX) != 0x0) && | ||
881 | !(status & SR0_RECEPTION)) | ||
882 | { | ||
883 | /* Signal command completion */ | ||
884 | wait_completed = FALSE; | ||
885 | } | ||
886 | else | ||
887 | { | ||
888 | /* Note : Rx interrupts will be handled later, because we can | ||
889 | * handle multiple Rx packets at once */ | ||
890 | #ifdef DEBUG_INTERRUPT_INFO | ||
891 | printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); | ||
892 | #endif | ||
893 | } | ||
894 | } | ||
895 | } | ||
896 | while(wait_completed && (spin-- > 0)); | ||
897 | |||
898 | /* If the interrupt hasn't be posted */ | ||
899 | if(wait_completed) | ||
900 | { | ||
901 | #ifdef DEBUG_INTERRUPT_ERROR | ||
902 | printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", | ||
903 | str, status); | ||
904 | #endif | ||
905 | return(FALSE); | ||
906 | } | ||
907 | |||
908 | /* Check the return code returned by the card (see above) against | ||
909 | * the expected return code provided by the caller */ | ||
910 | if((status & SR0_EVENT_MASK) != result) | ||
911 | { | ||
912 | #ifdef DEBUG_INTERRUPT_ERROR | ||
913 | printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", | ||
914 | str, status); | ||
915 | #endif | ||
916 | return(FALSE); | ||
917 | } | ||
918 | |||
919 | return(TRUE); | ||
920 | } /* wv_82593_cmd */ | ||
921 | |||
922 | /*------------------------------------------------------------------*/ | ||
923 | /* | ||
924 | * This routine does a 593 op-code number 7, and obtains the diagnose | ||
925 | * status for the WaveLAN. | ||
926 | */ | ||
927 | static inline int | ||
928 | wv_diag(struct net_device * dev) | ||
929 | { | ||
930 | return(wv_82593_cmd(dev, "wv_diag(): diagnose", | ||
931 | OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)); | ||
932 | } /* wv_diag */ | ||
933 | |||
934 | /*------------------------------------------------------------------*/ | ||
935 | /* | ||
936 | * Routine to read len bytes from the i82593's ring buffer, starting at | ||
937 | * chip address addr. The results read from the chip are stored in buf. | ||
938 | * The return value is the address to use for next the call. | ||
939 | */ | ||
940 | static int | ||
941 | read_ringbuf(struct net_device * dev, | ||
942 | int addr, | ||
943 | char * buf, | ||
944 | int len) | ||
945 | { | ||
946 | unsigned int base = dev->base_addr; | ||
947 | int ring_ptr = addr; | ||
948 | int chunk_len; | ||
949 | char * buf_ptr = buf; | ||
950 | |||
951 | /* Get all the buffer */ | ||
952 | while(len > 0) | ||
953 | { | ||
954 | /* Position the Program I/O Register at the ring buffer pointer */ | ||
955 | outb(ring_ptr & 0xff, PIORL(base)); | ||
956 | outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); | ||
957 | |||
958 | /* First, determine how much we can read without wrapping around the | ||
959 | ring buffer */ | ||
960 | if((addr + len) < (RX_BASE + RX_SIZE)) | ||
961 | chunk_len = len; | ||
962 | else | ||
963 | chunk_len = RX_BASE + RX_SIZE - addr; | ||
964 | insb(PIOP(base), buf_ptr, chunk_len); | ||
965 | buf_ptr += chunk_len; | ||
966 | len -= chunk_len; | ||
967 | ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; | ||
968 | } | ||
969 | return(ring_ptr); | ||
970 | } /* read_ringbuf */ | ||
971 | |||
972 | /*------------------------------------------------------------------*/ | ||
973 | /* | ||
974 | * Reconfigure the i82593, or at least ask for it... | ||
975 | * Because wv_82593_config use the transmission buffer, we must do it | ||
976 | * when we are sure that there is no transmission, so we do it now | ||
977 | * or in wavelan_packet_xmit() (I can't find any better place, | ||
978 | * wavelan_interrupt is not an option...), so you may experience | ||
979 | * some delay sometime... | ||
980 | */ | ||
981 | static void | ||
982 | wv_82593_reconfig(struct net_device * dev) | ||
983 | { | ||
984 | net_local * lp = netdev_priv(dev); | ||
985 | struct pcmcia_device * link = lp->link; | ||
986 | unsigned long flags; | ||
987 | |||
988 | /* Arm the flag, will be cleard in wv_82593_config() */ | ||
989 | lp->reconfig_82593 = TRUE; | ||
990 | |||
991 | /* Check if we can do it now ! */ | ||
992 | if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) | ||
993 | { | ||
994 | spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ | ||
995 | wv_82593_config(dev); | ||
996 | spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ | ||
997 | } | ||
998 | else | ||
999 | { | ||
1000 | #ifdef DEBUG_IOCTL_INFO | ||
1001 | printk(KERN_DEBUG | ||
1002 | "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", | ||
1003 | dev->name, dev->state, link->open); | ||
1004 | #endif | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | /********************* DEBUG & INFO SUBROUTINES *********************/ | ||
1009 | /* | ||
1010 | * This routines are used in the code to show debug informations. | ||
1011 | * Most of the time, it dump the content of hardware structures... | ||
1012 | */ | ||
1013 | |||
1014 | #ifdef DEBUG_PSA_SHOW | ||
1015 | /*------------------------------------------------------------------*/ | ||
1016 | /* | ||
1017 | * Print the formatted contents of the Parameter Storage Area. | ||
1018 | */ | ||
1019 | static void | ||
1020 | wv_psa_show(psa_t * p) | ||
1021 | { | ||
1022 | printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); | ||
1023 | printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", | ||
1024 | p->psa_io_base_addr_1, | ||
1025 | p->psa_io_base_addr_2, | ||
1026 | p->psa_io_base_addr_3, | ||
1027 | p->psa_io_base_addr_4); | ||
1028 | printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", | ||
1029 | p->psa_rem_boot_addr_1, | ||
1030 | p->psa_rem_boot_addr_2, | ||
1031 | p->psa_rem_boot_addr_3); | ||
1032 | printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); | ||
1033 | printk("psa_int_req_no: %d\n", p->psa_int_req_no); | ||
1034 | #ifdef DEBUG_SHOW_UNUSED | ||
1035 | printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); | ||
1036 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1037 | printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); | ||
1038 | printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); | ||
1039 | printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); | ||
1040 | printk("psa_comp_number: %d, ", p->psa_comp_number); | ||
1041 | printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); | ||
1042 | printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", | ||
1043 | p->psa_feature_select); | ||
1044 | printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); | ||
1045 | printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); | ||
1046 | printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); | ||
1047 | printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); | ||
1048 | printk("psa_nwid_select: %d\n", p->psa_nwid_select); | ||
1049 | printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); | ||
1050 | printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1051 | p->psa_encryption_key[0], | ||
1052 | p->psa_encryption_key[1], | ||
1053 | p->psa_encryption_key[2], | ||
1054 | p->psa_encryption_key[3], | ||
1055 | p->psa_encryption_key[4], | ||
1056 | p->psa_encryption_key[5], | ||
1057 | p->psa_encryption_key[6], | ||
1058 | p->psa_encryption_key[7]); | ||
1059 | printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); | ||
1060 | printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", | ||
1061 | p->psa_call_code[0]); | ||
1062 | printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1063 | p->psa_call_code[0], | ||
1064 | p->psa_call_code[1], | ||
1065 | p->psa_call_code[2], | ||
1066 | p->psa_call_code[3], | ||
1067 | p->psa_call_code[4], | ||
1068 | p->psa_call_code[5], | ||
1069 | p->psa_call_code[6], | ||
1070 | p->psa_call_code[7]); | ||
1071 | #ifdef DEBUG_SHOW_UNUSED | ||
1072 | printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n", | ||
1073 | p->psa_reserved[0], | ||
1074 | p->psa_reserved[1]); | ||
1075 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1076 | printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); | ||
1077 | printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); | ||
1078 | printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); | ||
1079 | } /* wv_psa_show */ | ||
1080 | #endif /* DEBUG_PSA_SHOW */ | ||
1081 | |||
1082 | #ifdef DEBUG_MMC_SHOW | ||
1083 | /*------------------------------------------------------------------*/ | ||
1084 | /* | ||
1085 | * Print the formatted status of the Modem Management Controller. | ||
1086 | * This function need to be completed... | ||
1087 | */ | ||
1088 | static void | ||
1089 | wv_mmc_show(struct net_device * dev) | ||
1090 | { | ||
1091 | unsigned int base = dev->base_addr; | ||
1092 | net_local * lp = netdev_priv(dev); | ||
1093 | mmr_t m; | ||
1094 | |||
1095 | /* Basic check */ | ||
1096 | if(hasr_read(base) & HASR_NO_CLK) | ||
1097 | { | ||
1098 | printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", | ||
1099 | dev->name); | ||
1100 | return; | ||
1101 | } | ||
1102 | |||
1103 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1104 | |||
1105 | /* Read the mmc */ | ||
1106 | mmc_out(base, mmwoff(0, mmw_freeze), 1); | ||
1107 | mmc_read(base, 0, (u_char *)&m, sizeof(m)); | ||
1108 | mmc_out(base, mmwoff(0, mmw_freeze), 0); | ||
1109 | |||
1110 | /* Don't forget to update statistics */ | ||
1111 | lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
1112 | |||
1113 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1114 | |||
1115 | printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); | ||
1116 | #ifdef DEBUG_SHOW_UNUSED | ||
1117 | printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1118 | m.mmr_unused0[0], | ||
1119 | m.mmr_unused0[1], | ||
1120 | m.mmr_unused0[2], | ||
1121 | m.mmr_unused0[3], | ||
1122 | m.mmr_unused0[4], | ||
1123 | m.mmr_unused0[5], | ||
1124 | m.mmr_unused0[6], | ||
1125 | m.mmr_unused0[7]); | ||
1126 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1127 | printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", | ||
1128 | m.mmr_des_avail, m.mmr_des_status); | ||
1129 | #ifdef DEBUG_SHOW_UNUSED | ||
1130 | printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", | ||
1131 | m.mmr_unused1[0], | ||
1132 | m.mmr_unused1[1], | ||
1133 | m.mmr_unused1[2], | ||
1134 | m.mmr_unused1[3], | ||
1135 | m.mmr_unused1[4]); | ||
1136 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1137 | printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", | ||
1138 | m.mmr_dce_status, | ||
1139 | (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", | ||
1140 | (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? | ||
1141 | "loop test indicated," : "", | ||
1142 | (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", | ||
1143 | (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? | ||
1144 | "jabber timer expired," : ""); | ||
1145 | printk(KERN_DEBUG "Dsp ID: %02X\n", | ||
1146 | m.mmr_dsp_id); | ||
1147 | #ifdef DEBUG_SHOW_UNUSED | ||
1148 | printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", | ||
1149 | m.mmr_unused2[0], | ||
1150 | m.mmr_unused2[1]); | ||
1151 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1152 | printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", | ||
1153 | (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, | ||
1154 | (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); | ||
1155 | printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", | ||
1156 | m.mmr_thr_pre_set & MMR_THR_PRE_SET, | ||
1157 | (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); | ||
1158 | printk(KERN_DEBUG "signal_lvl: %d [%s], ", | ||
1159 | m.mmr_signal_lvl & MMR_SIGNAL_LVL, | ||
1160 | (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); | ||
1161 | printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, | ||
1162 | (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); | ||
1163 | printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, | ||
1164 | (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); | ||
1165 | #ifdef DEBUG_SHOW_UNUSED | ||
1166 | printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); | ||
1167 | #endif /* DEBUG_SHOW_UNUSED */ | ||
1168 | } /* wv_mmc_show */ | ||
1169 | #endif /* DEBUG_MMC_SHOW */ | ||
1170 | |||
1171 | #ifdef DEBUG_I82593_SHOW | ||
1172 | /*------------------------------------------------------------------*/ | ||
1173 | /* | ||
1174 | * Print the formatted status of the i82593's receive unit. | ||
1175 | */ | ||
1176 | static void | ||
1177 | wv_ru_show(struct net_device * dev) | ||
1178 | { | ||
1179 | net_local *lp = netdev_priv(dev); | ||
1180 | |||
1181 | printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); | ||
1182 | printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); | ||
1183 | /* | ||
1184 | * Not implemented yet... | ||
1185 | */ | ||
1186 | printk("\n"); | ||
1187 | } /* wv_ru_show */ | ||
1188 | #endif /* DEBUG_I82593_SHOW */ | ||
1189 | |||
1190 | #ifdef DEBUG_DEVICE_SHOW | ||
1191 | /*------------------------------------------------------------------*/ | ||
1192 | /* | ||
1193 | * Print the formatted status of the WaveLAN PCMCIA device driver. | ||
1194 | */ | ||
1195 | static void | ||
1196 | wv_dev_show(struct net_device * dev) | ||
1197 | { | ||
1198 | printk(KERN_DEBUG "dev:"); | ||
1199 | printk(" state=%lX,", dev->state); | ||
1200 | printk(" trans_start=%ld,", dev->trans_start); | ||
1201 | printk(" flags=0x%x,", dev->flags); | ||
1202 | printk("\n"); | ||
1203 | } /* wv_dev_show */ | ||
1204 | |||
1205 | /*------------------------------------------------------------------*/ | ||
1206 | /* | ||
1207 | * Print the formatted status of the WaveLAN PCMCIA device driver's | ||
1208 | * private information. | ||
1209 | */ | ||
1210 | static void | ||
1211 | wv_local_show(struct net_device * dev) | ||
1212 | { | ||
1213 | net_local *lp = netdev_priv(dev); | ||
1214 | |||
1215 | printk(KERN_DEBUG "local:"); | ||
1216 | /* | ||
1217 | * Not implemented yet... | ||
1218 | */ | ||
1219 | printk("\n"); | ||
1220 | } /* wv_local_show */ | ||
1221 | #endif /* DEBUG_DEVICE_SHOW */ | ||
1222 | |||
1223 | #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) | ||
1224 | /*------------------------------------------------------------------*/ | ||
1225 | /* | ||
1226 | * Dump packet header (and content if necessary) on the screen | ||
1227 | */ | ||
1228 | static void | ||
1229 | wv_packet_info(u_char * p, /* Packet to dump */ | ||
1230 | int length, /* Length of the packet */ | ||
1231 | char * msg1, /* Name of the device */ | ||
1232 | char * msg2) /* Name of the function */ | ||
1233 | { | ||
1234 | int i; | ||
1235 | int maxi; | ||
1236 | |||
1237 | printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n", | ||
1238 | msg1, msg2, p, length); | ||
1239 | printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n", | ||
1240 | msg1, msg2, &p[6], p[12], p[13]); | ||
1241 | |||
1242 | #ifdef DEBUG_PACKET_DUMP | ||
1243 | |||
1244 | printk(KERN_DEBUG "data=\""); | ||
1245 | |||
1246 | if((maxi = length) > DEBUG_PACKET_DUMP) | ||
1247 | maxi = DEBUG_PACKET_DUMP; | ||
1248 | for(i = 14; i < maxi; i++) | ||
1249 | if(p[i] >= ' ' && p[i] <= '~') | ||
1250 | printk(" %c", p[i]); | ||
1251 | else | ||
1252 | printk("%02X", p[i]); | ||
1253 | if(maxi < length) | ||
1254 | printk(".."); | ||
1255 | printk("\"\n"); | ||
1256 | printk(KERN_DEBUG "\n"); | ||
1257 | #endif /* DEBUG_PACKET_DUMP */ | ||
1258 | } | ||
1259 | #endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ | ||
1260 | |||
1261 | /*------------------------------------------------------------------*/ | ||
1262 | /* | ||
1263 | * This is the information which is displayed by the driver at startup | ||
1264 | * There is a lot of flag to configure it at your will... | ||
1265 | */ | ||
1266 | static void | ||
1267 | wv_init_info(struct net_device * dev) | ||
1268 | { | ||
1269 | unsigned int base = dev->base_addr; | ||
1270 | psa_t psa; | ||
1271 | |||
1272 | /* Read the parameter storage area */ | ||
1273 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
1274 | |||
1275 | #ifdef DEBUG_PSA_SHOW | ||
1276 | wv_psa_show(&psa); | ||
1277 | #endif | ||
1278 | #ifdef DEBUG_MMC_SHOW | ||
1279 | wv_mmc_show(dev); | ||
1280 | #endif | ||
1281 | #ifdef DEBUG_I82593_SHOW | ||
1282 | wv_ru_show(dev); | ||
1283 | #endif | ||
1284 | |||
1285 | #ifdef DEBUG_BASIC_SHOW | ||
1286 | /* Now, let's go for the basic stuff */ | ||
1287 | printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM", | ||
1288 | dev->name, base, dev->irq, dev->dev_addr); | ||
1289 | |||
1290 | /* Print current network id */ | ||
1291 | if(psa.psa_nwid_select) | ||
1292 | printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); | ||
1293 | else | ||
1294 | printk(", nwid off"); | ||
1295 | |||
1296 | /* If 2.00 card */ | ||
1297 | if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
1298 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
1299 | { | ||
1300 | unsigned short freq; | ||
1301 | |||
1302 | /* Ask the EEprom to read the frequency from the first area */ | ||
1303 | fee_read(base, 0x00 /* 1st area - frequency... */, | ||
1304 | &freq, 1); | ||
1305 | |||
1306 | /* Print frequency */ | ||
1307 | printk(", 2.00, %ld", (freq >> 6) + 2400L); | ||
1308 | |||
1309 | /* Hack !!! */ | ||
1310 | if(freq & 0x20) | ||
1311 | printk(".5"); | ||
1312 | } | ||
1313 | else | ||
1314 | { | ||
1315 | printk(", PCMCIA, "); | ||
1316 | switch (psa.psa_subband) | ||
1317 | { | ||
1318 | case PSA_SUBBAND_915: | ||
1319 | printk("915"); | ||
1320 | break; | ||
1321 | case PSA_SUBBAND_2425: | ||
1322 | printk("2425"); | ||
1323 | break; | ||
1324 | case PSA_SUBBAND_2460: | ||
1325 | printk("2460"); | ||
1326 | break; | ||
1327 | case PSA_SUBBAND_2484: | ||
1328 | printk("2484"); | ||
1329 | break; | ||
1330 | case PSA_SUBBAND_2430_5: | ||
1331 | printk("2430.5"); | ||
1332 | break; | ||
1333 | default: | ||
1334 | printk("unknown"); | ||
1335 | } | ||
1336 | } | ||
1337 | |||
1338 | printk(" MHz\n"); | ||
1339 | #endif /* DEBUG_BASIC_SHOW */ | ||
1340 | |||
1341 | #ifdef DEBUG_VERSION_SHOW | ||
1342 | /* Print version information */ | ||
1343 | printk(KERN_NOTICE "%s", version); | ||
1344 | #endif | ||
1345 | } /* wv_init_info */ | ||
1346 | |||
1347 | /********************* IOCTL, STATS & RECONFIG *********************/ | ||
1348 | /* | ||
1349 | * We found here routines that are called by Linux on differents | ||
1350 | * occasions after the configuration and not for transmitting data | ||
1351 | * These may be called when the user use ifconfig, /proc/net/dev | ||
1352 | * or wireless extensions | ||
1353 | */ | ||
1354 | |||
1355 | |||
1356 | /*------------------------------------------------------------------*/ | ||
1357 | /* | ||
1358 | * Set or clear the multicast filter for this adaptor. | ||
1359 | * num_addrs == -1 Promiscuous mode, receive all packets | ||
1360 | * num_addrs == 0 Normal mode, clear multicast list | ||
1361 | * num_addrs > 0 Multicast mode, receive normal and MC packets, | ||
1362 | * and do best-effort filtering. | ||
1363 | */ | ||
1364 | |||
1365 | static void | ||
1366 | wavelan_set_multicast_list(struct net_device * dev) | ||
1367 | { | ||
1368 | net_local * lp = netdev_priv(dev); | ||
1369 | |||
1370 | #ifdef DEBUG_IOCTL_TRACE | ||
1371 | printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); | ||
1372 | #endif | ||
1373 | |||
1374 | #ifdef DEBUG_IOCTL_INFO | ||
1375 | printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", | ||
1376 | dev->name, dev->flags, dev->mc_count); | ||
1377 | #endif | ||
1378 | |||
1379 | if(dev->flags & IFF_PROMISC) | ||
1380 | { | ||
1381 | /* | ||
1382 | * Enable promiscuous mode: receive all packets. | ||
1383 | */ | ||
1384 | if(!lp->promiscuous) | ||
1385 | { | ||
1386 | lp->promiscuous = 1; | ||
1387 | lp->allmulticast = 0; | ||
1388 | lp->mc_count = 0; | ||
1389 | |||
1390 | wv_82593_reconfig(dev); | ||
1391 | } | ||
1392 | } | ||
1393 | else | ||
1394 | /* If all multicast addresses | ||
1395 | * or too much multicast addresses for the hardware filter */ | ||
1396 | if((dev->flags & IFF_ALLMULTI) || | ||
1397 | (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) | ||
1398 | { | ||
1399 | /* | ||
1400 | * Disable promiscuous mode, but active the all multicast mode | ||
1401 | */ | ||
1402 | if(!lp->allmulticast) | ||
1403 | { | ||
1404 | lp->promiscuous = 0; | ||
1405 | lp->allmulticast = 1; | ||
1406 | lp->mc_count = 0; | ||
1407 | |||
1408 | wv_82593_reconfig(dev); | ||
1409 | } | ||
1410 | } | ||
1411 | else | ||
1412 | /* If there is some multicast addresses to send */ | ||
1413 | if(dev->mc_list != (struct dev_mc_list *) NULL) | ||
1414 | { | ||
1415 | /* | ||
1416 | * Disable promiscuous mode, but receive all packets | ||
1417 | * in multicast list | ||
1418 | */ | ||
1419 | #ifdef MULTICAST_AVOID | ||
1420 | if(lp->promiscuous || lp->allmulticast || | ||
1421 | (dev->mc_count != lp->mc_count)) | ||
1422 | #endif | ||
1423 | { | ||
1424 | lp->promiscuous = 0; | ||
1425 | lp->allmulticast = 0; | ||
1426 | lp->mc_count = dev->mc_count; | ||
1427 | |||
1428 | wv_82593_reconfig(dev); | ||
1429 | } | ||
1430 | } | ||
1431 | else | ||
1432 | { | ||
1433 | /* | ||
1434 | * Switch to normal mode: disable promiscuous mode and | ||
1435 | * clear the multicast list. | ||
1436 | */ | ||
1437 | if(lp->promiscuous || lp->mc_count == 0) | ||
1438 | { | ||
1439 | lp->promiscuous = 0; | ||
1440 | lp->allmulticast = 0; | ||
1441 | lp->mc_count = 0; | ||
1442 | |||
1443 | wv_82593_reconfig(dev); | ||
1444 | } | ||
1445 | } | ||
1446 | #ifdef DEBUG_IOCTL_TRACE | ||
1447 | printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); | ||
1448 | #endif | ||
1449 | } | ||
1450 | |||
1451 | /*------------------------------------------------------------------*/ | ||
1452 | /* | ||
1453 | * This function doesn't exist... | ||
1454 | * (Note : it was a nice way to test the reconfigure stuff...) | ||
1455 | */ | ||
1456 | #ifdef SET_MAC_ADDRESS | ||
1457 | static int | ||
1458 | wavelan_set_mac_address(struct net_device * dev, | ||
1459 | void * addr) | ||
1460 | { | ||
1461 | struct sockaddr * mac = addr; | ||
1462 | |||
1463 | /* Copy the address */ | ||
1464 | memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); | ||
1465 | |||
1466 | /* Reconfig the beast */ | ||
1467 | wv_82593_reconfig(dev); | ||
1468 | |||
1469 | return 0; | ||
1470 | } | ||
1471 | #endif /* SET_MAC_ADDRESS */ | ||
1472 | |||
1473 | |||
1474 | /*------------------------------------------------------------------*/ | ||
1475 | /* | ||
1476 | * Frequency setting (for hardware able of it) | ||
1477 | * It's a bit complicated and you don't really want to look into it... | ||
1478 | */ | ||
1479 | static int | ||
1480 | wv_set_frequency(u_long base, /* i/o port of the card */ | ||
1481 | iw_freq * frequency) | ||
1482 | { | ||
1483 | const int BAND_NUM = 10; /* Number of bands */ | ||
1484 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ | ||
1485 | #ifdef DEBUG_IOCTL_INFO | ||
1486 | int i; | ||
1487 | #endif | ||
1488 | |||
1489 | /* Setting by frequency */ | ||
1490 | /* Theoritically, you may set any frequency between | ||
1491 | * the two limits with a 0.5 MHz precision. In practice, | ||
1492 | * I don't want you to have trouble with local | ||
1493 | * regulations... */ | ||
1494 | if((frequency->e == 1) && | ||
1495 | (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) | ||
1496 | { | ||
1497 | freq = ((frequency->m / 10000) - 24000L) / 5; | ||
1498 | } | ||
1499 | |||
1500 | /* Setting by channel (same as wfreqsel) */ | ||
1501 | /* Warning : each channel is 22MHz wide, so some of the channels | ||
1502 | * will interfere... */ | ||
1503 | if((frequency->e == 0) && | ||
1504 | (frequency->m >= 0) && (frequency->m < BAND_NUM)) | ||
1505 | { | ||
1506 | /* Get frequency offset. */ | ||
1507 | freq = channel_bands[frequency->m] >> 1; | ||
1508 | } | ||
1509 | |||
1510 | /* Verify if the frequency is allowed */ | ||
1511 | if(freq != 0L) | ||
1512 | { | ||
1513 | u_short table[10]; /* Authorized frequency table */ | ||
1514 | |||
1515 | /* Read the frequency table */ | ||
1516 | fee_read(base, 0x71 /* frequency table */, | ||
1517 | table, 10); | ||
1518 | |||
1519 | #ifdef DEBUG_IOCTL_INFO | ||
1520 | printk(KERN_DEBUG "Frequency table :"); | ||
1521 | for(i = 0; i < 10; i++) | ||
1522 | { | ||
1523 | printk(" %04X", | ||
1524 | table[i]); | ||
1525 | } | ||
1526 | printk("\n"); | ||
1527 | #endif | ||
1528 | |||
1529 | /* Look in the table if the frequency is allowed */ | ||
1530 | if(!(table[9 - ((freq - 24) / 16)] & | ||
1531 | (1 << ((freq - 24) % 16)))) | ||
1532 | return -EINVAL; /* not allowed */ | ||
1533 | } | ||
1534 | else | ||
1535 | return -EINVAL; | ||
1536 | |||
1537 | /* If we get a usable frequency */ | ||
1538 | if(freq != 0L) | ||
1539 | { | ||
1540 | unsigned short area[16]; | ||
1541 | unsigned short dac[2]; | ||
1542 | unsigned short area_verify[16]; | ||
1543 | unsigned short dac_verify[2]; | ||
1544 | /* Corresponding gain (in the power adjust value table) | ||
1545 | * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 | ||
1546 | * & WCIN062D.DOC, page 6.2.9 */ | ||
1547 | unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; | ||
1548 | int power_band = 0; /* Selected band */ | ||
1549 | unsigned short power_adjust; /* Correct value */ | ||
1550 | |||
1551 | /* Search for the gain */ | ||
1552 | power_band = 0; | ||
1553 | while((freq > power_limit[power_band]) && | ||
1554 | (power_limit[++power_band] != 0)) | ||
1555 | ; | ||
1556 | |||
1557 | /* Read the first area */ | ||
1558 | fee_read(base, 0x00, | ||
1559 | area, 16); | ||
1560 | |||
1561 | /* Read the DAC */ | ||
1562 | fee_read(base, 0x60, | ||
1563 | dac, 2); | ||
1564 | |||
1565 | /* Read the new power adjust value */ | ||
1566 | fee_read(base, 0x6B - (power_band >> 1), | ||
1567 | &power_adjust, 1); | ||
1568 | if(power_band & 0x1) | ||
1569 | power_adjust >>= 8; | ||
1570 | else | ||
1571 | power_adjust &= 0xFF; | ||
1572 | |||
1573 | #ifdef DEBUG_IOCTL_INFO | ||
1574 | printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); | ||
1575 | for(i = 0; i < 16; i++) | ||
1576 | { | ||
1577 | printk(" %04X", | ||
1578 | area[i]); | ||
1579 | } | ||
1580 | printk("\n"); | ||
1581 | |||
1582 | printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", | ||
1583 | dac[0], dac[1]); | ||
1584 | #endif | ||
1585 | |||
1586 | /* Frequency offset (for info only...) */ | ||
1587 | area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); | ||
1588 | |||
1589 | /* Receiver Principle main divider coefficient */ | ||
1590 | area[3] = (freq >> 1) + 2400L - 352L; | ||
1591 | area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1592 | |||
1593 | /* Transmitter Main divider coefficient */ | ||
1594 | area[13] = (freq >> 1) + 2400L; | ||
1595 | area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); | ||
1596 | |||
1597 | /* Others part of the area are flags, bit streams or unused... */ | ||
1598 | |||
1599 | /* Set the value in the DAC */ | ||
1600 | dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); | ||
1601 | dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); | ||
1602 | |||
1603 | /* Write the first area */ | ||
1604 | fee_write(base, 0x00, | ||
1605 | area, 16); | ||
1606 | |||
1607 | /* Write the DAC */ | ||
1608 | fee_write(base, 0x60, | ||
1609 | dac, 2); | ||
1610 | |||
1611 | /* We now should verify here that the EEprom writing was ok */ | ||
1612 | |||
1613 | /* ReRead the first area */ | ||
1614 | fee_read(base, 0x00, | ||
1615 | area_verify, 16); | ||
1616 | |||
1617 | /* ReRead the DAC */ | ||
1618 | fee_read(base, 0x60, | ||
1619 | dac_verify, 2); | ||
1620 | |||
1621 | /* Compare */ | ||
1622 | if(memcmp(area, area_verify, 16 * 2) || | ||
1623 | memcmp(dac, dac_verify, 2 * 2)) | ||
1624 | { | ||
1625 | #ifdef DEBUG_IOCTL_ERROR | ||
1626 | printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); | ||
1627 | #endif | ||
1628 | return -EOPNOTSUPP; | ||
1629 | } | ||
1630 | |||
1631 | /* We must download the frequency parameters to the | ||
1632 | * synthetisers (from the EEprom - area 1) | ||
1633 | * Note : as the EEprom is auto decremented, we set the end | ||
1634 | * if the area... */ | ||
1635 | mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); | ||
1636 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), | ||
1637 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1638 | |||
1639 | /* Wait until the download is finished */ | ||
1640 | fee_wait(base, 100, 100); | ||
1641 | |||
1642 | /* We must now download the power adjust value (gain) to | ||
1643 | * the synthetisers (from the EEprom - area 7 - DAC) */ | ||
1644 | mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); | ||
1645 | mmc_out(base, mmwoff(0, mmw_fee_ctrl), | ||
1646 | MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); | ||
1647 | |||
1648 | /* Wait until the download is finished */ | ||
1649 | fee_wait(base, 100, 100); | ||
1650 | |||
1651 | #ifdef DEBUG_IOCTL_INFO | ||
1652 | /* Verification of what we have done... */ | ||
1653 | |||
1654 | printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); | ||
1655 | for(i = 0; i < 16; i++) | ||
1656 | { | ||
1657 | printk(" %04X", | ||
1658 | area_verify[i]); | ||
1659 | } | ||
1660 | printk("\n"); | ||
1661 | |||
1662 | printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", | ||
1663 | dac_verify[0], dac_verify[1]); | ||
1664 | #endif | ||
1665 | |||
1666 | return 0; | ||
1667 | } | ||
1668 | else | ||
1669 | return -EINVAL; /* Bah, never get there... */ | ||
1670 | } | ||
1671 | |||
1672 | /*------------------------------------------------------------------*/ | ||
1673 | /* | ||
1674 | * Give the list of available frequencies | ||
1675 | */ | ||
1676 | static int | ||
1677 | wv_frequency_list(u_long base, /* i/o port of the card */ | ||
1678 | iw_freq * list, /* List of frequency to fill */ | ||
1679 | int max) /* Maximum number of frequencies */ | ||
1680 | { | ||
1681 | u_short table[10]; /* Authorized frequency table */ | ||
1682 | long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ | ||
1683 | int i; /* index in the table */ | ||
1684 | const int BAND_NUM = 10; /* Number of bands */ | ||
1685 | int c = 0; /* Channel number */ | ||
1686 | |||
1687 | /* Read the frequency table */ | ||
1688 | fee_read(base, 0x71 /* frequency table */, | ||
1689 | table, 10); | ||
1690 | |||
1691 | /* Look all frequencies */ | ||
1692 | i = 0; | ||
1693 | for(freq = 0; freq < 150; freq++) | ||
1694 | /* Look in the table if the frequency is allowed */ | ||
1695 | if(table[9 - (freq / 16)] & (1 << (freq % 16))) | ||
1696 | { | ||
1697 | /* Compute approximate channel number */ | ||
1698 | while((((channel_bands[c] >> 1) - 24) < freq) && | ||
1699 | (c < BAND_NUM)) | ||
1700 | c++; | ||
1701 | list[i].i = c; /* Set the list index */ | ||
1702 | |||
1703 | /* put in the list */ | ||
1704 | list[i].m = (((freq + 24) * 5) + 24000L) * 10000; | ||
1705 | list[i++].e = 1; | ||
1706 | |||
1707 | /* Check number */ | ||
1708 | if(i >= max) | ||
1709 | return(i); | ||
1710 | } | ||
1711 | |||
1712 | return(i); | ||
1713 | } | ||
1714 | |||
1715 | #ifdef IW_WIRELESS_SPY | ||
1716 | /*------------------------------------------------------------------*/ | ||
1717 | /* | ||
1718 | * Gather wireless spy statistics : for each packet, compare the source | ||
1719 | * address with out list, and if match, get the stats... | ||
1720 | * Sorry, but this function really need wireless extensions... | ||
1721 | */ | ||
1722 | static inline void | ||
1723 | wl_spy_gather(struct net_device * dev, | ||
1724 | u_char * mac, /* MAC address */ | ||
1725 | u_char * stats) /* Statistics to gather */ | ||
1726 | { | ||
1727 | struct iw_quality wstats; | ||
1728 | |||
1729 | wstats.qual = stats[2] & MMR_SGNL_QUAL; | ||
1730 | wstats.level = stats[0] & MMR_SIGNAL_LVL; | ||
1731 | wstats.noise = stats[1] & MMR_SILENCE_LVL; | ||
1732 | wstats.updated = 0x7; | ||
1733 | |||
1734 | /* Update spy records */ | ||
1735 | wireless_spy_update(dev, mac, &wstats); | ||
1736 | } | ||
1737 | #endif /* IW_WIRELESS_SPY */ | ||
1738 | |||
1739 | #ifdef HISTOGRAM | ||
1740 | /*------------------------------------------------------------------*/ | ||
1741 | /* | ||
1742 | * This function calculate an histogram on the signal level. | ||
1743 | * As the noise is quite constant, it's like doing it on the SNR. | ||
1744 | * We have defined a set of interval (lp->his_range), and each time | ||
1745 | * the level goes in that interval, we increment the count (lp->his_sum). | ||
1746 | * With this histogram you may detect if one wavelan is really weak, | ||
1747 | * or you may also calculate the mean and standard deviation of the level... | ||
1748 | */ | ||
1749 | static inline void | ||
1750 | wl_his_gather(struct net_device * dev, | ||
1751 | u_char * stats) /* Statistics to gather */ | ||
1752 | { | ||
1753 | net_local * lp = netdev_priv(dev); | ||
1754 | u_char level = stats[0] & MMR_SIGNAL_LVL; | ||
1755 | int i; | ||
1756 | |||
1757 | /* Find the correct interval */ | ||
1758 | i = 0; | ||
1759 | while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) | ||
1760 | ; | ||
1761 | |||
1762 | /* Increment interval counter */ | ||
1763 | (lp->his_sum[i])++; | ||
1764 | } | ||
1765 | #endif /* HISTOGRAM */ | ||
1766 | |||
1767 | static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
1768 | { | ||
1769 | strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1); | ||
1770 | } | ||
1771 | |||
1772 | static const struct ethtool_ops ops = { | ||
1773 | .get_drvinfo = wl_get_drvinfo | ||
1774 | }; | ||
1775 | |||
1776 | /*------------------------------------------------------------------*/ | ||
1777 | /* | ||
1778 | * Wireless Handler : get protocol name | ||
1779 | */ | ||
1780 | static int wavelan_get_name(struct net_device *dev, | ||
1781 | struct iw_request_info *info, | ||
1782 | union iwreq_data *wrqu, | ||
1783 | char *extra) | ||
1784 | { | ||
1785 | strcpy(wrqu->name, "WaveLAN"); | ||
1786 | return 0; | ||
1787 | } | ||
1788 | |||
1789 | /*------------------------------------------------------------------*/ | ||
1790 | /* | ||
1791 | * Wireless Handler : set NWID | ||
1792 | */ | ||
1793 | static int wavelan_set_nwid(struct net_device *dev, | ||
1794 | struct iw_request_info *info, | ||
1795 | union iwreq_data *wrqu, | ||
1796 | char *extra) | ||
1797 | { | ||
1798 | unsigned int base = dev->base_addr; | ||
1799 | net_local *lp = netdev_priv(dev); | ||
1800 | psa_t psa; | ||
1801 | mm_t m; | ||
1802 | unsigned long flags; | ||
1803 | int ret = 0; | ||
1804 | |||
1805 | /* Disable interrupts and save flags. */ | ||
1806 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1807 | |||
1808 | /* Set NWID in WaveLAN. */ | ||
1809 | if (!wrqu->nwid.disabled) { | ||
1810 | /* Set NWID in psa */ | ||
1811 | psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; | ||
1812 | psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; | ||
1813 | psa.psa_nwid_select = 0x01; | ||
1814 | psa_write(dev, | ||
1815 | (char *) psa.psa_nwid - (char *) &psa, | ||
1816 | (unsigned char *) psa.psa_nwid, 3); | ||
1817 | |||
1818 | /* Set NWID in mmc. */ | ||
1819 | m.w.mmw_netw_id_l = psa.psa_nwid[1]; | ||
1820 | m.w.mmw_netw_id_h = psa.psa_nwid[0]; | ||
1821 | mmc_write(base, | ||
1822 | (char *) &m.w.mmw_netw_id_l - | ||
1823 | (char *) &m, | ||
1824 | (unsigned char *) &m.w.mmw_netw_id_l, 2); | ||
1825 | mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); | ||
1826 | } else { | ||
1827 | /* Disable NWID in the psa. */ | ||
1828 | psa.psa_nwid_select = 0x00; | ||
1829 | psa_write(dev, | ||
1830 | (char *) &psa.psa_nwid_select - | ||
1831 | (char *) &psa, | ||
1832 | (unsigned char *) &psa.psa_nwid_select, | ||
1833 | 1); | ||
1834 | |||
1835 | /* Disable NWID in the mmc (no filtering). */ | ||
1836 | mmc_out(base, mmwoff(0, mmw_loopt_sel), | ||
1837 | MMW_LOOPT_SEL_DIS_NWID); | ||
1838 | } | ||
1839 | /* update the Wavelan checksum */ | ||
1840 | update_psa_checksum(dev); | ||
1841 | |||
1842 | /* Enable interrupts and restore flags. */ | ||
1843 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1844 | |||
1845 | return ret; | ||
1846 | } | ||
1847 | |||
1848 | /*------------------------------------------------------------------*/ | ||
1849 | /* | ||
1850 | * Wireless Handler : get NWID | ||
1851 | */ | ||
1852 | static int wavelan_get_nwid(struct net_device *dev, | ||
1853 | struct iw_request_info *info, | ||
1854 | union iwreq_data *wrqu, | ||
1855 | char *extra) | ||
1856 | { | ||
1857 | net_local *lp = netdev_priv(dev); | ||
1858 | psa_t psa; | ||
1859 | unsigned long flags; | ||
1860 | int ret = 0; | ||
1861 | |||
1862 | /* Disable interrupts and save flags. */ | ||
1863 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1864 | |||
1865 | /* Read the NWID. */ | ||
1866 | psa_read(dev, | ||
1867 | (char *) psa.psa_nwid - (char *) &psa, | ||
1868 | (unsigned char *) psa.psa_nwid, 3); | ||
1869 | wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; | ||
1870 | wrqu->nwid.disabled = !(psa.psa_nwid_select); | ||
1871 | wrqu->nwid.fixed = 1; /* Superfluous */ | ||
1872 | |||
1873 | /* Enable interrupts and restore flags. */ | ||
1874 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1875 | |||
1876 | return ret; | ||
1877 | } | ||
1878 | |||
1879 | /*------------------------------------------------------------------*/ | ||
1880 | /* | ||
1881 | * Wireless Handler : set frequency | ||
1882 | */ | ||
1883 | static int wavelan_set_freq(struct net_device *dev, | ||
1884 | struct iw_request_info *info, | ||
1885 | union iwreq_data *wrqu, | ||
1886 | char *extra) | ||
1887 | { | ||
1888 | unsigned int base = dev->base_addr; | ||
1889 | net_local *lp = netdev_priv(dev); | ||
1890 | unsigned long flags; | ||
1891 | int ret; | ||
1892 | |||
1893 | /* Disable interrupts and save flags. */ | ||
1894 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1895 | |||
1896 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
1897 | if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
1898 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
1899 | ret = wv_set_frequency(base, &(wrqu->freq)); | ||
1900 | else | ||
1901 | ret = -EOPNOTSUPP; | ||
1902 | |||
1903 | /* Enable interrupts and restore flags. */ | ||
1904 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1905 | |||
1906 | return ret; | ||
1907 | } | ||
1908 | |||
1909 | /*------------------------------------------------------------------*/ | ||
1910 | /* | ||
1911 | * Wireless Handler : get frequency | ||
1912 | */ | ||
1913 | static int wavelan_get_freq(struct net_device *dev, | ||
1914 | struct iw_request_info *info, | ||
1915 | union iwreq_data *wrqu, | ||
1916 | char *extra) | ||
1917 | { | ||
1918 | unsigned int base = dev->base_addr; | ||
1919 | net_local *lp = netdev_priv(dev); | ||
1920 | psa_t psa; | ||
1921 | unsigned long flags; | ||
1922 | int ret = 0; | ||
1923 | |||
1924 | /* Disable interrupts and save flags. */ | ||
1925 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1926 | |||
1927 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). | ||
1928 | * Does it work for everybody, especially old cards? */ | ||
1929 | if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
1930 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
1931 | unsigned short freq; | ||
1932 | |||
1933 | /* Ask the EEPROM to read the frequency from the first area. */ | ||
1934 | fee_read(base, 0x00, &freq, 1); | ||
1935 | wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; | ||
1936 | wrqu->freq.e = 1; | ||
1937 | } else { | ||
1938 | psa_read(dev, | ||
1939 | (char *) &psa.psa_subband - (char *) &psa, | ||
1940 | (unsigned char *) &psa.psa_subband, 1); | ||
1941 | |||
1942 | if (psa.psa_subband <= 4) { | ||
1943 | wrqu->freq.m = fixed_bands[psa.psa_subband]; | ||
1944 | wrqu->freq.e = (psa.psa_subband != 0); | ||
1945 | } else | ||
1946 | ret = -EOPNOTSUPP; | ||
1947 | } | ||
1948 | |||
1949 | /* Enable interrupts and restore flags. */ | ||
1950 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1951 | |||
1952 | return ret; | ||
1953 | } | ||
1954 | |||
1955 | /*------------------------------------------------------------------*/ | ||
1956 | /* | ||
1957 | * Wireless Handler : set level threshold | ||
1958 | */ | ||
1959 | static int wavelan_set_sens(struct net_device *dev, | ||
1960 | struct iw_request_info *info, | ||
1961 | union iwreq_data *wrqu, | ||
1962 | char *extra) | ||
1963 | { | ||
1964 | unsigned int base = dev->base_addr; | ||
1965 | net_local *lp = netdev_priv(dev); | ||
1966 | psa_t psa; | ||
1967 | unsigned long flags; | ||
1968 | int ret = 0; | ||
1969 | |||
1970 | /* Disable interrupts and save flags. */ | ||
1971 | spin_lock_irqsave(&lp->spinlock, flags); | ||
1972 | |||
1973 | /* Set the level threshold. */ | ||
1974 | /* We should complain loudly if wrqu->sens.fixed = 0, because we | ||
1975 | * can't set auto mode... */ | ||
1976 | psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; | ||
1977 | psa_write(dev, | ||
1978 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
1979 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
1980 | /* update the Wavelan checksum */ | ||
1981 | update_psa_checksum(dev); | ||
1982 | mmc_out(base, mmwoff(0, mmw_thr_pre_set), | ||
1983 | psa.psa_thr_pre_set); | ||
1984 | |||
1985 | /* Enable interrupts and restore flags. */ | ||
1986 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
1987 | |||
1988 | return ret; | ||
1989 | } | ||
1990 | |||
1991 | /*------------------------------------------------------------------*/ | ||
1992 | /* | ||
1993 | * Wireless Handler : get level threshold | ||
1994 | */ | ||
1995 | static int wavelan_get_sens(struct net_device *dev, | ||
1996 | struct iw_request_info *info, | ||
1997 | union iwreq_data *wrqu, | ||
1998 | char *extra) | ||
1999 | { | ||
2000 | net_local *lp = netdev_priv(dev); | ||
2001 | psa_t psa; | ||
2002 | unsigned long flags; | ||
2003 | int ret = 0; | ||
2004 | |||
2005 | /* Disable interrupts and save flags. */ | ||
2006 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2007 | |||
2008 | /* Read the level threshold. */ | ||
2009 | psa_read(dev, | ||
2010 | (char *) &psa.psa_thr_pre_set - (char *) &psa, | ||
2011 | (unsigned char *) &psa.psa_thr_pre_set, 1); | ||
2012 | wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; | ||
2013 | wrqu->sens.fixed = 1; | ||
2014 | |||
2015 | /* Enable interrupts and restore flags. */ | ||
2016 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2017 | |||
2018 | return ret; | ||
2019 | } | ||
2020 | |||
2021 | /*------------------------------------------------------------------*/ | ||
2022 | /* | ||
2023 | * Wireless Handler : set encryption key | ||
2024 | */ | ||
2025 | static int wavelan_set_encode(struct net_device *dev, | ||
2026 | struct iw_request_info *info, | ||
2027 | union iwreq_data *wrqu, | ||
2028 | char *extra) | ||
2029 | { | ||
2030 | unsigned int base = dev->base_addr; | ||
2031 | net_local *lp = netdev_priv(dev); | ||
2032 | unsigned long flags; | ||
2033 | psa_t psa; | ||
2034 | int ret = 0; | ||
2035 | |||
2036 | /* Disable interrupts and save flags. */ | ||
2037 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2038 | |||
2039 | /* Check if capable of encryption */ | ||
2040 | if (!mmc_encr(base)) { | ||
2041 | ret = -EOPNOTSUPP; | ||
2042 | } | ||
2043 | |||
2044 | /* Check the size of the key */ | ||
2045 | if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { | ||
2046 | ret = -EINVAL; | ||
2047 | } | ||
2048 | |||
2049 | if(!ret) { | ||
2050 | /* Basic checking... */ | ||
2051 | if (wrqu->encoding.length == 8) { | ||
2052 | /* Copy the key in the driver */ | ||
2053 | memcpy(psa.psa_encryption_key, extra, | ||
2054 | wrqu->encoding.length); | ||
2055 | psa.psa_encryption_select = 1; | ||
2056 | |||
2057 | psa_write(dev, | ||
2058 | (char *) &psa.psa_encryption_select - | ||
2059 | (char *) &psa, | ||
2060 | (unsigned char *) &psa. | ||
2061 | psa_encryption_select, 8 + 1); | ||
2062 | |||
2063 | mmc_out(base, mmwoff(0, mmw_encr_enable), | ||
2064 | MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); | ||
2065 | mmc_write(base, mmwoff(0, mmw_encr_key), | ||
2066 | (unsigned char *) &psa. | ||
2067 | psa_encryption_key, 8); | ||
2068 | } | ||
2069 | |||
2070 | /* disable encryption */ | ||
2071 | if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { | ||
2072 | psa.psa_encryption_select = 0; | ||
2073 | psa_write(dev, | ||
2074 | (char *) &psa.psa_encryption_select - | ||
2075 | (char *) &psa, | ||
2076 | (unsigned char *) &psa. | ||
2077 | psa_encryption_select, 1); | ||
2078 | |||
2079 | mmc_out(base, mmwoff(0, mmw_encr_enable), 0); | ||
2080 | } | ||
2081 | /* update the Wavelan checksum */ | ||
2082 | update_psa_checksum(dev); | ||
2083 | } | ||
2084 | |||
2085 | /* Enable interrupts and restore flags. */ | ||
2086 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2087 | |||
2088 | return ret; | ||
2089 | } | ||
2090 | |||
2091 | /*------------------------------------------------------------------*/ | ||
2092 | /* | ||
2093 | * Wireless Handler : get encryption key | ||
2094 | */ | ||
2095 | static int wavelan_get_encode(struct net_device *dev, | ||
2096 | struct iw_request_info *info, | ||
2097 | union iwreq_data *wrqu, | ||
2098 | char *extra) | ||
2099 | { | ||
2100 | unsigned int base = dev->base_addr; | ||
2101 | net_local *lp = netdev_priv(dev); | ||
2102 | psa_t psa; | ||
2103 | unsigned long flags; | ||
2104 | int ret = 0; | ||
2105 | |||
2106 | /* Disable interrupts and save flags. */ | ||
2107 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2108 | |||
2109 | /* Check if encryption is available */ | ||
2110 | if (!mmc_encr(base)) { | ||
2111 | ret = -EOPNOTSUPP; | ||
2112 | } else { | ||
2113 | /* Read the encryption key */ | ||
2114 | psa_read(dev, | ||
2115 | (char *) &psa.psa_encryption_select - | ||
2116 | (char *) &psa, | ||
2117 | (unsigned char *) &psa. | ||
2118 | psa_encryption_select, 1 + 8); | ||
2119 | |||
2120 | /* encryption is enabled ? */ | ||
2121 | if (psa.psa_encryption_select) | ||
2122 | wrqu->encoding.flags = IW_ENCODE_ENABLED; | ||
2123 | else | ||
2124 | wrqu->encoding.flags = IW_ENCODE_DISABLED; | ||
2125 | wrqu->encoding.flags |= mmc_encr(base); | ||
2126 | |||
2127 | /* Copy the key to the user buffer */ | ||
2128 | wrqu->encoding.length = 8; | ||
2129 | memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); | ||
2130 | } | ||
2131 | |||
2132 | /* Enable interrupts and restore flags. */ | ||
2133 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2134 | |||
2135 | return ret; | ||
2136 | } | ||
2137 | |||
2138 | #ifdef WAVELAN_ROAMING_EXT | ||
2139 | /*------------------------------------------------------------------*/ | ||
2140 | /* | ||
2141 | * Wireless Handler : set ESSID (domain) | ||
2142 | */ | ||
2143 | static int wavelan_set_essid(struct net_device *dev, | ||
2144 | struct iw_request_info *info, | ||
2145 | union iwreq_data *wrqu, | ||
2146 | char *extra) | ||
2147 | { | ||
2148 | net_local *lp = netdev_priv(dev); | ||
2149 | unsigned long flags; | ||
2150 | int ret = 0; | ||
2151 | |||
2152 | /* Disable interrupts and save flags. */ | ||
2153 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2154 | |||
2155 | /* Check if disable */ | ||
2156 | if(wrqu->data.flags == 0) | ||
2157 | lp->filter_domains = 0; | ||
2158 | else { | ||
2159 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
2160 | char * endp; | ||
2161 | |||
2162 | /* Terminate the string */ | ||
2163 | memcpy(essid, extra, wrqu->data.length); | ||
2164 | essid[IW_ESSID_MAX_SIZE] = '\0'; | ||
2165 | |||
2166 | #ifdef DEBUG_IOCTL_INFO | ||
2167 | printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); | ||
2168 | #endif /* DEBUG_IOCTL_INFO */ | ||
2169 | |||
2170 | /* Convert to a number (note : Wavelan specific) */ | ||
2171 | lp->domain_id = simple_strtoul(essid, &endp, 16); | ||
2172 | /* Has it worked ? */ | ||
2173 | if(endp > essid) | ||
2174 | lp->filter_domains = 1; | ||
2175 | else { | ||
2176 | lp->filter_domains = 0; | ||
2177 | ret = -EINVAL; | ||
2178 | } | ||
2179 | } | ||
2180 | |||
2181 | /* Enable interrupts and restore flags. */ | ||
2182 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2183 | |||
2184 | return ret; | ||
2185 | } | ||
2186 | |||
2187 | /*------------------------------------------------------------------*/ | ||
2188 | /* | ||
2189 | * Wireless Handler : get ESSID (domain) | ||
2190 | */ | ||
2191 | static int wavelan_get_essid(struct net_device *dev, | ||
2192 | struct iw_request_info *info, | ||
2193 | union iwreq_data *wrqu, | ||
2194 | char *extra) | ||
2195 | { | ||
2196 | net_local *lp = netdev_priv(dev); | ||
2197 | |||
2198 | /* Is the domain ID active ? */ | ||
2199 | wrqu->data.flags = lp->filter_domains; | ||
2200 | |||
2201 | /* Copy Domain ID into a string (Wavelan specific) */ | ||
2202 | /* Sound crazy, be we can't have a snprintf in the kernel !!! */ | ||
2203 | sprintf(extra, "%lX", lp->domain_id); | ||
2204 | extra[IW_ESSID_MAX_SIZE] = '\0'; | ||
2205 | |||
2206 | /* Set the length */ | ||
2207 | wrqu->data.length = strlen(extra); | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
2212 | /*------------------------------------------------------------------*/ | ||
2213 | /* | ||
2214 | * Wireless Handler : set AP address | ||
2215 | */ | ||
2216 | static int wavelan_set_wap(struct net_device *dev, | ||
2217 | struct iw_request_info *info, | ||
2218 | union iwreq_data *wrqu, | ||
2219 | char *extra) | ||
2220 | { | ||
2221 | #ifdef DEBUG_IOCTL_INFO | ||
2222 | printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data); | ||
2223 | #endif /* DEBUG_IOCTL_INFO */ | ||
2224 | |||
2225 | return -EOPNOTSUPP; | ||
2226 | } | ||
2227 | |||
2228 | /*------------------------------------------------------------------*/ | ||
2229 | /* | ||
2230 | * Wireless Handler : get AP address | ||
2231 | */ | ||
2232 | static int wavelan_get_wap(struct net_device *dev, | ||
2233 | struct iw_request_info *info, | ||
2234 | union iwreq_data *wrqu, | ||
2235 | char *extra) | ||
2236 | { | ||
2237 | /* Should get the real McCoy instead of own Ethernet address */ | ||
2238 | memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); | ||
2239 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | ||
2240 | |||
2241 | return -EOPNOTSUPP; | ||
2242 | } | ||
2243 | #endif /* WAVELAN_ROAMING_EXT */ | ||
2244 | |||
2245 | #ifdef WAVELAN_ROAMING | ||
2246 | /*------------------------------------------------------------------*/ | ||
2247 | /* | ||
2248 | * Wireless Handler : set mode | ||
2249 | */ | ||
2250 | static int wavelan_set_mode(struct net_device *dev, | ||
2251 | struct iw_request_info *info, | ||
2252 | union iwreq_data *wrqu, | ||
2253 | char *extra) | ||
2254 | { | ||
2255 | net_local *lp = netdev_priv(dev); | ||
2256 | unsigned long flags; | ||
2257 | int ret = 0; | ||
2258 | |||
2259 | /* Disable interrupts and save flags. */ | ||
2260 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2261 | |||
2262 | /* Check mode */ | ||
2263 | switch(wrqu->mode) { | ||
2264 | case IW_MODE_ADHOC: | ||
2265 | if(do_roaming) { | ||
2266 | wv_roam_cleanup(dev); | ||
2267 | do_roaming = 0; | ||
2268 | } | ||
2269 | break; | ||
2270 | case IW_MODE_INFRA: | ||
2271 | if(!do_roaming) { | ||
2272 | wv_roam_init(dev); | ||
2273 | do_roaming = 1; | ||
2274 | } | ||
2275 | break; | ||
2276 | default: | ||
2277 | ret = -EINVAL; | ||
2278 | } | ||
2279 | |||
2280 | /* Enable interrupts and restore flags. */ | ||
2281 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2282 | |||
2283 | return ret; | ||
2284 | } | ||
2285 | |||
2286 | /*------------------------------------------------------------------*/ | ||
2287 | /* | ||
2288 | * Wireless Handler : get mode | ||
2289 | */ | ||
2290 | static int wavelan_get_mode(struct net_device *dev, | ||
2291 | struct iw_request_info *info, | ||
2292 | union iwreq_data *wrqu, | ||
2293 | char *extra) | ||
2294 | { | ||
2295 | if(do_roaming) | ||
2296 | wrqu->mode = IW_MODE_INFRA; | ||
2297 | else | ||
2298 | wrqu->mode = IW_MODE_ADHOC; | ||
2299 | |||
2300 | return 0; | ||
2301 | } | ||
2302 | #endif /* WAVELAN_ROAMING */ | ||
2303 | |||
2304 | /*------------------------------------------------------------------*/ | ||
2305 | /* | ||
2306 | * Wireless Handler : get range info | ||
2307 | */ | ||
2308 | static int wavelan_get_range(struct net_device *dev, | ||
2309 | struct iw_request_info *info, | ||
2310 | union iwreq_data *wrqu, | ||
2311 | char *extra) | ||
2312 | { | ||
2313 | unsigned int base = dev->base_addr; | ||
2314 | net_local *lp = netdev_priv(dev); | ||
2315 | struct iw_range *range = (struct iw_range *) extra; | ||
2316 | unsigned long flags; | ||
2317 | int ret = 0; | ||
2318 | |||
2319 | /* Set the length (very important for backward compatibility) */ | ||
2320 | wrqu->data.length = sizeof(struct iw_range); | ||
2321 | |||
2322 | /* Set all the info we don't care or don't know about to zero */ | ||
2323 | memset(range, 0, sizeof(struct iw_range)); | ||
2324 | |||
2325 | /* Set the Wireless Extension versions */ | ||
2326 | range->we_version_compiled = WIRELESS_EXT; | ||
2327 | range->we_version_source = 9; | ||
2328 | |||
2329 | /* Set information in the range struct. */ | ||
2330 | range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ | ||
2331 | range->min_nwid = 0x0000; | ||
2332 | range->max_nwid = 0xFFFF; | ||
2333 | |||
2334 | range->sensitivity = 0x3F; | ||
2335 | range->max_qual.qual = MMR_SGNL_QUAL; | ||
2336 | range->max_qual.level = MMR_SIGNAL_LVL; | ||
2337 | range->max_qual.noise = MMR_SILENCE_LVL; | ||
2338 | range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ | ||
2339 | /* Need to get better values for those two */ | ||
2340 | range->avg_qual.level = 30; | ||
2341 | range->avg_qual.noise = 8; | ||
2342 | |||
2343 | range->num_bitrates = 1; | ||
2344 | range->bitrate[0] = 2000000; /* 2 Mb/s */ | ||
2345 | |||
2346 | /* Event capability (kernel + driver) */ | ||
2347 | range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | | ||
2348 | IW_EVENT_CAPA_MASK(0x8B04) | | ||
2349 | IW_EVENT_CAPA_MASK(0x8B06)); | ||
2350 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
2351 | |||
2352 | /* Disable interrupts and save flags. */ | ||
2353 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2354 | |||
2355 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ | ||
2356 | if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
2357 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { | ||
2358 | range->num_channels = 10; | ||
2359 | range->num_frequency = wv_frequency_list(base, range->freq, | ||
2360 | IW_MAX_FREQUENCIES); | ||
2361 | } else | ||
2362 | range->num_channels = range->num_frequency = 0; | ||
2363 | |||
2364 | /* Encryption supported ? */ | ||
2365 | if (mmc_encr(base)) { | ||
2366 | range->encoding_size[0] = 8; /* DES = 64 bits key */ | ||
2367 | range->num_encoding_sizes = 1; | ||
2368 | range->max_encoding_tokens = 1; /* Only one key possible */ | ||
2369 | } else { | ||
2370 | range->num_encoding_sizes = 0; | ||
2371 | range->max_encoding_tokens = 0; | ||
2372 | } | ||
2373 | |||
2374 | /* Enable interrupts and restore flags. */ | ||
2375 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2376 | |||
2377 | return ret; | ||
2378 | } | ||
2379 | |||
2380 | /*------------------------------------------------------------------*/ | ||
2381 | /* | ||
2382 | * Wireless Private Handler : set quality threshold | ||
2383 | */ | ||
2384 | static int wavelan_set_qthr(struct net_device *dev, | ||
2385 | struct iw_request_info *info, | ||
2386 | union iwreq_data *wrqu, | ||
2387 | char *extra) | ||
2388 | { | ||
2389 | unsigned int base = dev->base_addr; | ||
2390 | net_local *lp = netdev_priv(dev); | ||
2391 | psa_t psa; | ||
2392 | unsigned long flags; | ||
2393 | |||
2394 | /* Disable interrupts and save flags. */ | ||
2395 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2396 | |||
2397 | psa.psa_quality_thr = *(extra) & 0x0F; | ||
2398 | psa_write(dev, | ||
2399 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2400 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2401 | /* update the Wavelan checksum */ | ||
2402 | update_psa_checksum(dev); | ||
2403 | mmc_out(base, mmwoff(0, mmw_quality_thr), | ||
2404 | psa.psa_quality_thr); | ||
2405 | |||
2406 | /* Enable interrupts and restore flags. */ | ||
2407 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2408 | |||
2409 | return 0; | ||
2410 | } | ||
2411 | |||
2412 | /*------------------------------------------------------------------*/ | ||
2413 | /* | ||
2414 | * Wireless Private Handler : get quality threshold | ||
2415 | */ | ||
2416 | static int wavelan_get_qthr(struct net_device *dev, | ||
2417 | struct iw_request_info *info, | ||
2418 | union iwreq_data *wrqu, | ||
2419 | char *extra) | ||
2420 | { | ||
2421 | net_local *lp = netdev_priv(dev); | ||
2422 | psa_t psa; | ||
2423 | unsigned long flags; | ||
2424 | |||
2425 | /* Disable interrupts and save flags. */ | ||
2426 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2427 | |||
2428 | psa_read(dev, | ||
2429 | (char *) &psa.psa_quality_thr - (char *) &psa, | ||
2430 | (unsigned char *) &psa.psa_quality_thr, 1); | ||
2431 | *(extra) = psa.psa_quality_thr & 0x0F; | ||
2432 | |||
2433 | /* Enable interrupts and restore flags. */ | ||
2434 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2435 | |||
2436 | return 0; | ||
2437 | } | ||
2438 | |||
2439 | #ifdef WAVELAN_ROAMING | ||
2440 | /*------------------------------------------------------------------*/ | ||
2441 | /* | ||
2442 | * Wireless Private Handler : set roaming | ||
2443 | */ | ||
2444 | static int wavelan_set_roam(struct net_device *dev, | ||
2445 | struct iw_request_info *info, | ||
2446 | union iwreq_data *wrqu, | ||
2447 | char *extra) | ||
2448 | { | ||
2449 | net_local *lp = netdev_priv(dev); | ||
2450 | unsigned long flags; | ||
2451 | |||
2452 | /* Disable interrupts and save flags. */ | ||
2453 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2454 | |||
2455 | /* Note : should check if user == root */ | ||
2456 | if(do_roaming && (*extra)==0) | ||
2457 | wv_roam_cleanup(dev); | ||
2458 | else if(do_roaming==0 && (*extra)!=0) | ||
2459 | wv_roam_init(dev); | ||
2460 | |||
2461 | do_roaming = (*extra); | ||
2462 | |||
2463 | /* Enable interrupts and restore flags. */ | ||
2464 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2465 | |||
2466 | return 0; | ||
2467 | } | ||
2468 | |||
2469 | /*------------------------------------------------------------------*/ | ||
2470 | /* | ||
2471 | * Wireless Private Handler : get quality threshold | ||
2472 | */ | ||
2473 | static int wavelan_get_roam(struct net_device *dev, | ||
2474 | struct iw_request_info *info, | ||
2475 | union iwreq_data *wrqu, | ||
2476 | char *extra) | ||
2477 | { | ||
2478 | *(extra) = do_roaming; | ||
2479 | |||
2480 | return 0; | ||
2481 | } | ||
2482 | #endif /* WAVELAN_ROAMING */ | ||
2483 | |||
2484 | #ifdef HISTOGRAM | ||
2485 | /*------------------------------------------------------------------*/ | ||
2486 | /* | ||
2487 | * Wireless Private Handler : set histogram | ||
2488 | */ | ||
2489 | static int wavelan_set_histo(struct net_device *dev, | ||
2490 | struct iw_request_info *info, | ||
2491 | union iwreq_data *wrqu, | ||
2492 | char *extra) | ||
2493 | { | ||
2494 | net_local *lp = netdev_priv(dev); | ||
2495 | |||
2496 | /* Check the number of intervals. */ | ||
2497 | if (wrqu->data.length > 16) { | ||
2498 | return(-E2BIG); | ||
2499 | } | ||
2500 | |||
2501 | /* Disable histo while we copy the addresses. | ||
2502 | * As we don't disable interrupts, we need to do this */ | ||
2503 | lp->his_number = 0; | ||
2504 | |||
2505 | /* Are there ranges to copy? */ | ||
2506 | if (wrqu->data.length > 0) { | ||
2507 | /* Copy interval ranges to the driver */ | ||
2508 | memcpy(lp->his_range, extra, wrqu->data.length); | ||
2509 | |||
2510 | { | ||
2511 | int i; | ||
2512 | printk(KERN_DEBUG "Histo :"); | ||
2513 | for(i = 0; i < wrqu->data.length; i++) | ||
2514 | printk(" %d", lp->his_range[i]); | ||
2515 | printk("\n"); | ||
2516 | } | ||
2517 | |||
2518 | /* Reset result structure. */ | ||
2519 | memset(lp->his_sum, 0x00, sizeof(long) * 16); | ||
2520 | } | ||
2521 | |||
2522 | /* Now we can set the number of ranges */ | ||
2523 | lp->his_number = wrqu->data.length; | ||
2524 | |||
2525 | return(0); | ||
2526 | } | ||
2527 | |||
2528 | /*------------------------------------------------------------------*/ | ||
2529 | /* | ||
2530 | * Wireless Private Handler : get histogram | ||
2531 | */ | ||
2532 | static int wavelan_get_histo(struct net_device *dev, | ||
2533 | struct iw_request_info *info, | ||
2534 | union iwreq_data *wrqu, | ||
2535 | char *extra) | ||
2536 | { | ||
2537 | net_local *lp = netdev_priv(dev); | ||
2538 | |||
2539 | /* Set the number of intervals. */ | ||
2540 | wrqu->data.length = lp->his_number; | ||
2541 | |||
2542 | /* Give back the distribution statistics */ | ||
2543 | if(lp->his_number > 0) | ||
2544 | memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); | ||
2545 | |||
2546 | return(0); | ||
2547 | } | ||
2548 | #endif /* HISTOGRAM */ | ||
2549 | |||
2550 | /*------------------------------------------------------------------*/ | ||
2551 | /* | ||
2552 | * Structures to export the Wireless Handlers | ||
2553 | */ | ||
2554 | |||
2555 | static const struct iw_priv_args wavelan_private_args[] = { | ||
2556 | /*{ cmd, set_args, get_args, name } */ | ||
2557 | { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, | ||
2558 | { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, | ||
2559 | { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" }, | ||
2560 | { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, | ||
2561 | { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, | ||
2562 | { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, | ||
2563 | }; | ||
2564 | |||
2565 | static const iw_handler wavelan_handler[] = | ||
2566 | { | ||
2567 | NULL, /* SIOCSIWNAME */ | ||
2568 | wavelan_get_name, /* SIOCGIWNAME */ | ||
2569 | wavelan_set_nwid, /* SIOCSIWNWID */ | ||
2570 | wavelan_get_nwid, /* SIOCGIWNWID */ | ||
2571 | wavelan_set_freq, /* SIOCSIWFREQ */ | ||
2572 | wavelan_get_freq, /* SIOCGIWFREQ */ | ||
2573 | #ifdef WAVELAN_ROAMING | ||
2574 | wavelan_set_mode, /* SIOCSIWMODE */ | ||
2575 | wavelan_get_mode, /* SIOCGIWMODE */ | ||
2576 | #else /* WAVELAN_ROAMING */ | ||
2577 | NULL, /* SIOCSIWMODE */ | ||
2578 | NULL, /* SIOCGIWMODE */ | ||
2579 | #endif /* WAVELAN_ROAMING */ | ||
2580 | wavelan_set_sens, /* SIOCSIWSENS */ | ||
2581 | wavelan_get_sens, /* SIOCGIWSENS */ | ||
2582 | NULL, /* SIOCSIWRANGE */ | ||
2583 | wavelan_get_range, /* SIOCGIWRANGE */ | ||
2584 | NULL, /* SIOCSIWPRIV */ | ||
2585 | NULL, /* SIOCGIWPRIV */ | ||
2586 | NULL, /* SIOCSIWSTATS */ | ||
2587 | NULL, /* SIOCGIWSTATS */ | ||
2588 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2589 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2590 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2591 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2592 | #ifdef WAVELAN_ROAMING_EXT | ||
2593 | wavelan_set_wap, /* SIOCSIWAP */ | ||
2594 | wavelan_get_wap, /* SIOCGIWAP */ | ||
2595 | NULL, /* -- hole -- */ | ||
2596 | NULL, /* SIOCGIWAPLIST */ | ||
2597 | NULL, /* -- hole -- */ | ||
2598 | NULL, /* -- hole -- */ | ||
2599 | wavelan_set_essid, /* SIOCSIWESSID */ | ||
2600 | wavelan_get_essid, /* SIOCGIWESSID */ | ||
2601 | #else /* WAVELAN_ROAMING_EXT */ | ||
2602 | NULL, /* SIOCSIWAP */ | ||
2603 | NULL, /* SIOCGIWAP */ | ||
2604 | NULL, /* -- hole -- */ | ||
2605 | NULL, /* SIOCGIWAPLIST */ | ||
2606 | NULL, /* -- hole -- */ | ||
2607 | NULL, /* -- hole -- */ | ||
2608 | NULL, /* SIOCSIWESSID */ | ||
2609 | NULL, /* SIOCGIWESSID */ | ||
2610 | #endif /* WAVELAN_ROAMING_EXT */ | ||
2611 | NULL, /* SIOCSIWNICKN */ | ||
2612 | NULL, /* SIOCGIWNICKN */ | ||
2613 | NULL, /* -- hole -- */ | ||
2614 | NULL, /* -- hole -- */ | ||
2615 | NULL, /* SIOCSIWRATE */ | ||
2616 | NULL, /* SIOCGIWRATE */ | ||
2617 | NULL, /* SIOCSIWRTS */ | ||
2618 | NULL, /* SIOCGIWRTS */ | ||
2619 | NULL, /* SIOCSIWFRAG */ | ||
2620 | NULL, /* SIOCGIWFRAG */ | ||
2621 | NULL, /* SIOCSIWTXPOW */ | ||
2622 | NULL, /* SIOCGIWTXPOW */ | ||
2623 | NULL, /* SIOCSIWRETRY */ | ||
2624 | NULL, /* SIOCGIWRETRY */ | ||
2625 | wavelan_set_encode, /* SIOCSIWENCODE */ | ||
2626 | wavelan_get_encode, /* SIOCGIWENCODE */ | ||
2627 | }; | ||
2628 | |||
2629 | static const iw_handler wavelan_private_handler[] = | ||
2630 | { | ||
2631 | wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ | ||
2632 | wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ | ||
2633 | #ifdef WAVELAN_ROAMING | ||
2634 | wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */ | ||
2635 | wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */ | ||
2636 | #else /* WAVELAN_ROAMING */ | ||
2637 | NULL, /* SIOCIWFIRSTPRIV + 2 */ | ||
2638 | NULL, /* SIOCIWFIRSTPRIV + 3 */ | ||
2639 | #endif /* WAVELAN_ROAMING */ | ||
2640 | #ifdef HISTOGRAM | ||
2641 | wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */ | ||
2642 | wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */ | ||
2643 | #endif /* HISTOGRAM */ | ||
2644 | }; | ||
2645 | |||
2646 | static const struct iw_handler_def wavelan_handler_def = | ||
2647 | { | ||
2648 | .num_standard = ARRAY_SIZE(wavelan_handler), | ||
2649 | .num_private = ARRAY_SIZE(wavelan_private_handler), | ||
2650 | .num_private_args = ARRAY_SIZE(wavelan_private_args), | ||
2651 | .standard = wavelan_handler, | ||
2652 | .private = wavelan_private_handler, | ||
2653 | .private_args = wavelan_private_args, | ||
2654 | .get_wireless_stats = wavelan_get_wireless_stats, | ||
2655 | }; | ||
2656 | |||
2657 | /*------------------------------------------------------------------*/ | ||
2658 | /* | ||
2659 | * Get wireless statistics | ||
2660 | * Called by /proc/net/wireless... | ||
2661 | */ | ||
2662 | static iw_stats * | ||
2663 | wavelan_get_wireless_stats(struct net_device * dev) | ||
2664 | { | ||
2665 | unsigned int base = dev->base_addr; | ||
2666 | net_local * lp = netdev_priv(dev); | ||
2667 | mmr_t m; | ||
2668 | iw_stats * wstats; | ||
2669 | unsigned long flags; | ||
2670 | |||
2671 | #ifdef DEBUG_IOCTL_TRACE | ||
2672 | printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); | ||
2673 | #endif | ||
2674 | |||
2675 | /* Disable interrupts & save flags */ | ||
2676 | spin_lock_irqsave(&lp->spinlock, flags); | ||
2677 | |||
2678 | wstats = &lp->wstats; | ||
2679 | |||
2680 | /* Get data from the mmc */ | ||
2681 | mmc_out(base, mmwoff(0, mmw_freeze), 1); | ||
2682 | |||
2683 | mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); | ||
2684 | mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); | ||
2685 | mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); | ||
2686 | |||
2687 | mmc_out(base, mmwoff(0, mmw_freeze), 0); | ||
2688 | |||
2689 | /* Copy data to wireless stuff */ | ||
2690 | wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; | ||
2691 | wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; | ||
2692 | wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; | ||
2693 | wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; | ||
2694 | wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | | ||
2695 | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | | ||
2696 | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); | ||
2697 | wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; | ||
2698 | wstats->discard.code = 0L; | ||
2699 | wstats->discard.misc = 0L; | ||
2700 | |||
2701 | /* ReEnable interrupts & restore flags */ | ||
2702 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
2703 | |||
2704 | #ifdef DEBUG_IOCTL_TRACE | ||
2705 | printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); | ||
2706 | #endif | ||
2707 | return &lp->wstats; | ||
2708 | } | ||
2709 | |||
2710 | /************************* PACKET RECEPTION *************************/ | ||
2711 | /* | ||
2712 | * This part deal with receiving the packets. | ||
2713 | * The interrupt handler get an interrupt when a packet has been | ||
2714 | * successfully received and called this part... | ||
2715 | */ | ||
2716 | |||
2717 | /*------------------------------------------------------------------*/ | ||
2718 | /* | ||
2719 | * Calculate the starting address of the frame pointed to by the receive | ||
2720 | * frame pointer and verify that the frame seem correct | ||
2721 | * (called by wv_packet_rcv()) | ||
2722 | */ | ||
2723 | static int | ||
2724 | wv_start_of_frame(struct net_device * dev, | ||
2725 | int rfp, /* end of frame */ | ||
2726 | int wrap) /* start of buffer */ | ||
2727 | { | ||
2728 | unsigned int base = dev->base_addr; | ||
2729 | int rp; | ||
2730 | int len; | ||
2731 | |||
2732 | rp = (rfp - 5 + RX_SIZE) % RX_SIZE; | ||
2733 | outb(rp & 0xff, PIORL(base)); | ||
2734 | outb(((rp >> 8) & PIORH_MASK), PIORH(base)); | ||
2735 | len = inb(PIOP(base)); | ||
2736 | len |= inb(PIOP(base)) << 8; | ||
2737 | |||
2738 | /* Sanity checks on size */ | ||
2739 | /* Frame too big */ | ||
2740 | if(len > MAXDATAZ + 100) | ||
2741 | { | ||
2742 | #ifdef DEBUG_RX_ERROR | ||
2743 | printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", | ||
2744 | dev->name, rfp, len); | ||
2745 | #endif | ||
2746 | return(-1); | ||
2747 | } | ||
2748 | |||
2749 | /* Frame too short */ | ||
2750 | if(len < 7) | ||
2751 | { | ||
2752 | #ifdef DEBUG_RX_ERROR | ||
2753 | printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", | ||
2754 | dev->name, rfp, len); | ||
2755 | #endif | ||
2756 | return(-1); | ||
2757 | } | ||
2758 | |||
2759 | /* Wrap around buffer */ | ||
2760 | if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ | ||
2761 | { | ||
2762 | #ifdef DEBUG_RX_ERROR | ||
2763 | printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", | ||
2764 | dev->name, wrap, rfp, len); | ||
2765 | #endif | ||
2766 | return(-1); | ||
2767 | } | ||
2768 | |||
2769 | return((rp - len + RX_SIZE) % RX_SIZE); | ||
2770 | } /* wv_start_of_frame */ | ||
2771 | |||
2772 | /*------------------------------------------------------------------*/ | ||
2773 | /* | ||
2774 | * This routine does the actual copy of data (including the ethernet | ||
2775 | * header structure) from the WaveLAN card to an sk_buff chain that | ||
2776 | * will be passed up to the network interface layer. NOTE: We | ||
2777 | * currently don't handle trailer protocols (neither does the rest of | ||
2778 | * the network interface), so if that is needed, it will (at least in | ||
2779 | * part) be added here. The contents of the receive ring buffer are | ||
2780 | * copied to a message chain that is then passed to the kernel. | ||
2781 | * | ||
2782 | * Note: if any errors occur, the packet is "dropped on the floor" | ||
2783 | * (called by wv_packet_rcv()) | ||
2784 | */ | ||
2785 | static void | ||
2786 | wv_packet_read(struct net_device * dev, | ||
2787 | int fd_p, | ||
2788 | int sksize) | ||
2789 | { | ||
2790 | net_local * lp = netdev_priv(dev); | ||
2791 | struct sk_buff * skb; | ||
2792 | |||
2793 | #ifdef DEBUG_RX_TRACE | ||
2794 | printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", | ||
2795 | dev->name, fd_p, sksize); | ||
2796 | #endif | ||
2797 | |||
2798 | /* Allocate some buffer for the new packet */ | ||
2799 | if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) | ||
2800 | { | ||
2801 | #ifdef DEBUG_RX_ERROR | ||
2802 | printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", | ||
2803 | dev->name, sksize); | ||
2804 | #endif | ||
2805 | dev->stats.rx_dropped++; | ||
2806 | /* | ||
2807 | * Not only do we want to return here, but we also need to drop the | ||
2808 | * packet on the floor to clear the interrupt. | ||
2809 | */ | ||
2810 | return; | ||
2811 | } | ||
2812 | |||
2813 | skb_reserve(skb, 2); | ||
2814 | fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); | ||
2815 | skb->protocol = eth_type_trans(skb, dev); | ||
2816 | |||
2817 | #ifdef DEBUG_RX_INFO | ||
2818 | wv_packet_info(skb_mac_header(skb), sksize, dev->name, "wv_packet_read"); | ||
2819 | #endif /* DEBUG_RX_INFO */ | ||
2820 | |||
2821 | /* Statistics gathering & stuff associated. | ||
2822 | * It seem a bit messy with all the define, but it's really simple... */ | ||
2823 | if( | ||
2824 | #ifdef IW_WIRELESS_SPY | ||
2825 | (lp->spy_data.spy_number > 0) || | ||
2826 | #endif /* IW_WIRELESS_SPY */ | ||
2827 | #ifdef HISTOGRAM | ||
2828 | (lp->his_number > 0) || | ||
2829 | #endif /* HISTOGRAM */ | ||
2830 | #ifdef WAVELAN_ROAMING | ||
2831 | (do_roaming) || | ||
2832 | #endif /* WAVELAN_ROAMING */ | ||
2833 | 0) | ||
2834 | { | ||
2835 | u_char stats[3]; /* Signal level, Noise level, Signal quality */ | ||
2836 | |||
2837 | /* read signal level, silence level and signal quality bytes */ | ||
2838 | fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, | ||
2839 | stats, 3); | ||
2840 | #ifdef DEBUG_RX_INFO | ||
2841 | printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", | ||
2842 | dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); | ||
2843 | #endif | ||
2844 | |||
2845 | #ifdef WAVELAN_ROAMING | ||
2846 | if(do_roaming) | ||
2847 | if(WAVELAN_BEACON(skb->data)) | ||
2848 | wl_roam_gather(dev, skb->data, stats); | ||
2849 | #endif /* WAVELAN_ROAMING */ | ||
2850 | |||
2851 | #ifdef WIRELESS_SPY | ||
2852 | wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, stats); | ||
2853 | #endif /* WIRELESS_SPY */ | ||
2854 | #ifdef HISTOGRAM | ||
2855 | wl_his_gather(dev, stats); | ||
2856 | #endif /* HISTOGRAM */ | ||
2857 | } | ||
2858 | |||
2859 | /* | ||
2860 | * Hand the packet to the Network Module | ||
2861 | */ | ||
2862 | netif_rx(skb); | ||
2863 | |||
2864 | /* Keep stats up to date */ | ||
2865 | dev->stats.rx_packets++; | ||
2866 | dev->stats.rx_bytes += sksize; | ||
2867 | |||
2868 | #ifdef DEBUG_RX_TRACE | ||
2869 | printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); | ||
2870 | #endif | ||
2871 | return; | ||
2872 | } | ||
2873 | |||
2874 | /*------------------------------------------------------------------*/ | ||
2875 | /* | ||
2876 | * This routine is called by the interrupt handler to initiate a | ||
2877 | * packet transfer from the card to the network interface layer above | ||
2878 | * this driver. This routine checks if a buffer has been successfully | ||
2879 | * received by the WaveLAN card. If so, the routine wv_packet_read is | ||
2880 | * called to do the actual transfer of the card's data including the | ||
2881 | * ethernet header into a packet consisting of an sk_buff chain. | ||
2882 | * (called by wavelan_interrupt()) | ||
2883 | * Note : the spinlock is already grabbed for us and irq are disabled. | ||
2884 | */ | ||
2885 | static void | ||
2886 | wv_packet_rcv(struct net_device * dev) | ||
2887 | { | ||
2888 | unsigned int base = dev->base_addr; | ||
2889 | net_local * lp = netdev_priv(dev); | ||
2890 | int newrfp; | ||
2891 | int rp; | ||
2892 | int len; | ||
2893 | int f_start; | ||
2894 | int status; | ||
2895 | int i593_rfp; | ||
2896 | int stat_ptr; | ||
2897 | u_char c[4]; | ||
2898 | |||
2899 | #ifdef DEBUG_RX_TRACE | ||
2900 | printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); | ||
2901 | #endif | ||
2902 | |||
2903 | /* Get the new receive frame pointer from the i82593 chip */ | ||
2904 | outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); | ||
2905 | i593_rfp = inb(LCSR(base)); | ||
2906 | i593_rfp |= inb(LCSR(base)) << 8; | ||
2907 | i593_rfp %= RX_SIZE; | ||
2908 | |||
2909 | /* Get the new receive frame pointer from the WaveLAN card. | ||
2910 | * It is 3 bytes more than the increment of the i82593 receive | ||
2911 | * frame pointer, for each packet. This is because it includes the | ||
2912 | * 3 roaming bytes added by the mmc. | ||
2913 | */ | ||
2914 | newrfp = inb(RPLL(base)); | ||
2915 | newrfp |= inb(RPLH(base)) << 8; | ||
2916 | newrfp %= RX_SIZE; | ||
2917 | |||
2918 | #ifdef DEBUG_RX_INFO | ||
2919 | printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", | ||
2920 | dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); | ||
2921 | #endif | ||
2922 | |||
2923 | #ifdef DEBUG_RX_ERROR | ||
2924 | /* If no new frame pointer... */ | ||
2925 | if(lp->overrunning || newrfp == lp->rfp) | ||
2926 | printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", | ||
2927 | dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); | ||
2928 | #endif | ||
2929 | |||
2930 | /* Read all frames (packets) received */ | ||
2931 | while(newrfp != lp->rfp) | ||
2932 | { | ||
2933 | /* A frame is composed of the packet, followed by a status word, | ||
2934 | * the length of the frame (word) and the mmc info (SNR & qual). | ||
2935 | * It's because the length is at the end that we can only scan | ||
2936 | * frames backward. */ | ||
2937 | |||
2938 | /* Find the first frame by skipping backwards over the frames */ | ||
2939 | rp = newrfp; /* End of last frame */ | ||
2940 | while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && | ||
2941 | (f_start != -1)) | ||
2942 | rp = f_start; | ||
2943 | |||
2944 | /* If we had a problem */ | ||
2945 | if(f_start == -1) | ||
2946 | { | ||
2947 | #ifdef DEBUG_RX_ERROR | ||
2948 | printk(KERN_INFO "wavelan_cs: cannot find start of frame "); | ||
2949 | printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", | ||
2950 | i593_rfp, lp->stop, newrfp, lp->rfp); | ||
2951 | #endif | ||
2952 | lp->rfp = rp; /* Get to the last usable frame */ | ||
2953 | continue; | ||
2954 | } | ||
2955 | |||
2956 | /* f_start point to the beggining of the first frame received | ||
2957 | * and rp to the beggining of the next one */ | ||
2958 | |||
2959 | /* Read status & length of the frame */ | ||
2960 | stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; | ||
2961 | stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); | ||
2962 | status = c[0] | (c[1] << 8); | ||
2963 | len = c[2] | (c[3] << 8); | ||
2964 | |||
2965 | /* Check status */ | ||
2966 | if((status & RX_RCV_OK) != RX_RCV_OK) | ||
2967 | { | ||
2968 | dev->stats.rx_errors++; | ||
2969 | if(status & RX_NO_SFD) | ||
2970 | dev->stats.rx_frame_errors++; | ||
2971 | if(status & RX_CRC_ERR) | ||
2972 | dev->stats.rx_crc_errors++; | ||
2973 | if(status & RX_OVRRUN) | ||
2974 | dev->stats.rx_over_errors++; | ||
2975 | |||
2976 | #ifdef DEBUG_RX_FAIL | ||
2977 | printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", | ||
2978 | dev->name, status); | ||
2979 | #endif | ||
2980 | } | ||
2981 | else | ||
2982 | /* Read the packet and transmit to Linux */ | ||
2983 | wv_packet_read(dev, f_start, len - 2); | ||
2984 | |||
2985 | /* One frame has been processed, skip it */ | ||
2986 | lp->rfp = rp; | ||
2987 | } | ||
2988 | |||
2989 | /* | ||
2990 | * Update the frame stop register, but set it to less than | ||
2991 | * the full 8K to allow space for 3 bytes of signal strength | ||
2992 | * per packet. | ||
2993 | */ | ||
2994 | lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; | ||
2995 | outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); | ||
2996 | outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); | ||
2997 | outb(OP1_SWIT_TO_PORT_0, LCCR(base)); | ||
2998 | |||
2999 | #ifdef DEBUG_RX_TRACE | ||
3000 | printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); | ||
3001 | #endif | ||
3002 | } | ||
3003 | |||
3004 | /*********************** PACKET TRANSMISSION ***********************/ | ||
3005 | /* | ||
3006 | * This part deal with sending packet through the wavelan | ||
3007 | * We copy the packet to the send buffer and then issue the send | ||
3008 | * command to the i82593. The result of this operation will be | ||
3009 | * checked in wavelan_interrupt() | ||
3010 | */ | ||
3011 | |||
3012 | /*------------------------------------------------------------------*/ | ||
3013 | /* | ||
3014 | * This routine fills in the appropriate registers and memory | ||
3015 | * locations on the WaveLAN card and starts the card off on | ||
3016 | * the transmit. | ||
3017 | * (called in wavelan_packet_xmit()) | ||
3018 | */ | ||
3019 | static void | ||
3020 | wv_packet_write(struct net_device * dev, | ||
3021 | void * buf, | ||
3022 | short length) | ||
3023 | { | ||
3024 | net_local * lp = netdev_priv(dev); | ||
3025 | unsigned int base = dev->base_addr; | ||
3026 | unsigned long flags; | ||
3027 | int clen = length; | ||
3028 | register u_short xmtdata_base = TX_BASE; | ||
3029 | |||
3030 | #ifdef DEBUG_TX_TRACE | ||
3031 | printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); | ||
3032 | #endif | ||
3033 | |||
3034 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3035 | |||
3036 | /* Write the length of data buffer followed by the buffer */ | ||
3037 | outb(xmtdata_base & 0xff, PIORL(base)); | ||
3038 | outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3039 | outb(clen & 0xff, PIOP(base)); /* lsb */ | ||
3040 | outb(clen >> 8, PIOP(base)); /* msb */ | ||
3041 | |||
3042 | /* Send the data */ | ||
3043 | outsb(PIOP(base), buf, clen); | ||
3044 | |||
3045 | /* Indicate end of transmit chain */ | ||
3046 | outb(OP0_NOP, PIOP(base)); | ||
3047 | /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ | ||
3048 | outb(OP0_NOP, PIOP(base)); | ||
3049 | |||
3050 | /* Reset the transmit DMA pointer */ | ||
3051 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3052 | hacr_write(base, HACR_DEFAULT); | ||
3053 | /* Send the transmit command */ | ||
3054 | wv_82593_cmd(dev, "wv_packet_write(): transmit", | ||
3055 | OP0_TRANSMIT, SR0_NO_RESULT); | ||
3056 | |||
3057 | /* Make sure the watchdog will keep quiet for a while */ | ||
3058 | dev->trans_start = jiffies; | ||
3059 | |||
3060 | /* Keep stats up to date */ | ||
3061 | dev->stats.tx_bytes += length; | ||
3062 | |||
3063 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3064 | |||
3065 | #ifdef DEBUG_TX_INFO | ||
3066 | wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); | ||
3067 | #endif /* DEBUG_TX_INFO */ | ||
3068 | |||
3069 | #ifdef DEBUG_TX_TRACE | ||
3070 | printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); | ||
3071 | #endif | ||
3072 | } | ||
3073 | |||
3074 | /*------------------------------------------------------------------*/ | ||
3075 | /* | ||
3076 | * This routine is called when we want to send a packet (NET3 callback) | ||
3077 | * In this routine, we check if the harware is ready to accept | ||
3078 | * the packet. We also prevent reentrance. Then, we call the function | ||
3079 | * to send the packet... | ||
3080 | */ | ||
3081 | static netdev_tx_t | ||
3082 | wavelan_packet_xmit(struct sk_buff * skb, | ||
3083 | struct net_device * dev) | ||
3084 | { | ||
3085 | net_local * lp = netdev_priv(dev); | ||
3086 | unsigned long flags; | ||
3087 | |||
3088 | #ifdef DEBUG_TX_TRACE | ||
3089 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, | ||
3090 | (unsigned) skb); | ||
3091 | #endif | ||
3092 | |||
3093 | /* | ||
3094 | * Block a timer-based transmit from overlapping a previous transmit. | ||
3095 | * In other words, prevent reentering this routine. | ||
3096 | */ | ||
3097 | netif_stop_queue(dev); | ||
3098 | |||
3099 | /* If somebody has asked to reconfigure the controller, | ||
3100 | * we can do it now */ | ||
3101 | if(lp->reconfig_82593) | ||
3102 | { | ||
3103 | spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ | ||
3104 | wv_82593_config(dev); | ||
3105 | spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ | ||
3106 | /* Note : the configure procedure was totally synchronous, | ||
3107 | * so the Tx buffer is now free */ | ||
3108 | } | ||
3109 | |||
3110 | /* Check if we need some padding */ | ||
3111 | /* Note : on wireless the propagation time is in the order of 1us, | ||
3112 | * and we don't have the Ethernet specific requirement of beeing | ||
3113 | * able to detect collisions, therefore in theory we don't really | ||
3114 | * need to pad. Jean II */ | ||
3115 | if (skb_padto(skb, ETH_ZLEN)) | ||
3116 | return NETDEV_TX_OK; | ||
3117 | |||
3118 | wv_packet_write(dev, skb->data, skb->len); | ||
3119 | |||
3120 | dev_kfree_skb(skb); | ||
3121 | |||
3122 | #ifdef DEBUG_TX_TRACE | ||
3123 | printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); | ||
3124 | #endif | ||
3125 | return NETDEV_TX_OK; | ||
3126 | } | ||
3127 | |||
3128 | /********************** HARDWARE CONFIGURATION **********************/ | ||
3129 | /* | ||
3130 | * This part do the real job of starting and configuring the hardware. | ||
3131 | */ | ||
3132 | |||
3133 | /*------------------------------------------------------------------*/ | ||
3134 | /* | ||
3135 | * Routine to initialize the Modem Management Controller. | ||
3136 | * (called by wv_hw_config()) | ||
3137 | */ | ||
3138 | static int | ||
3139 | wv_mmc_init(struct net_device * dev) | ||
3140 | { | ||
3141 | unsigned int base = dev->base_addr; | ||
3142 | psa_t psa; | ||
3143 | mmw_t m; | ||
3144 | int configured; | ||
3145 | int i; /* Loop counter */ | ||
3146 | |||
3147 | #ifdef DEBUG_CONFIG_TRACE | ||
3148 | printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); | ||
3149 | #endif | ||
3150 | |||
3151 | /* Read the parameter storage area */ | ||
3152 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
3153 | |||
3154 | /* | ||
3155 | * Check the first three octets of the MAC addr for the manufacturer's code. | ||
3156 | * Note: If you get the error message below, you've got a | ||
3157 | * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on | ||
3158 | * how to configure your card... | ||
3159 | */ | ||
3160 | for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) | ||
3161 | if ((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && | ||
3162 | (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && | ||
3163 | (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) | ||
3164 | break; | ||
3165 | |||
3166 | /* If we have not found it... */ | ||
3167 | if (i == ARRAY_SIZE(MAC_ADDRESSES)) | ||
3168 | { | ||
3169 | #ifdef DEBUG_CONFIG_ERRORS | ||
3170 | printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", | ||
3171 | dev->name, psa.psa_univ_mac_addr[0], | ||
3172 | psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); | ||
3173 | #endif | ||
3174 | return FALSE; | ||
3175 | } | ||
3176 | |||
3177 | /* Get the MAC address */ | ||
3178 | memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); | ||
3179 | |||
3180 | #ifdef USE_PSA_CONFIG | ||
3181 | configured = psa.psa_conf_status & 1; | ||
3182 | #else | ||
3183 | configured = 0; | ||
3184 | #endif | ||
3185 | |||
3186 | /* Is the PSA is not configured */ | ||
3187 | if(!configured) | ||
3188 | { | ||
3189 | /* User will be able to configure NWID after (with iwconfig) */ | ||
3190 | psa.psa_nwid[0] = 0; | ||
3191 | psa.psa_nwid[1] = 0; | ||
3192 | |||
3193 | /* As NWID is not set : no NWID checking */ | ||
3194 | psa.psa_nwid_select = 0; | ||
3195 | |||
3196 | /* Disable encryption */ | ||
3197 | psa.psa_encryption_select = 0; | ||
3198 | |||
3199 | /* Set to standard values | ||
3200 | * 0x04 for AT, | ||
3201 | * 0x01 for MCA, | ||
3202 | * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) | ||
3203 | */ | ||
3204 | if (psa.psa_comp_number & 1) | ||
3205 | psa.psa_thr_pre_set = 0x01; | ||
3206 | else | ||
3207 | psa.psa_thr_pre_set = 0x04; | ||
3208 | psa.psa_quality_thr = 0x03; | ||
3209 | |||
3210 | /* It is configured */ | ||
3211 | psa.psa_conf_status |= 1; | ||
3212 | |||
3213 | #ifdef USE_PSA_CONFIG | ||
3214 | /* Write the psa */ | ||
3215 | psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, | ||
3216 | (unsigned char *)psa.psa_nwid, 4); | ||
3217 | psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, | ||
3218 | (unsigned char *)&psa.psa_thr_pre_set, 1); | ||
3219 | psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, | ||
3220 | (unsigned char *)&psa.psa_quality_thr, 1); | ||
3221 | psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, | ||
3222 | (unsigned char *)&psa.psa_conf_status, 1); | ||
3223 | /* update the Wavelan checksum */ | ||
3224 | update_psa_checksum(dev); | ||
3225 | #endif /* USE_PSA_CONFIG */ | ||
3226 | } | ||
3227 | |||
3228 | /* Zero the mmc structure */ | ||
3229 | memset(&m, 0x00, sizeof(m)); | ||
3230 | |||
3231 | /* Copy PSA info to the mmc */ | ||
3232 | m.mmw_netw_id_l = psa.psa_nwid[1]; | ||
3233 | m.mmw_netw_id_h = psa.psa_nwid[0]; | ||
3234 | |||
3235 | if(psa.psa_nwid_select & 1) | ||
3236 | m.mmw_loopt_sel = 0x00; | ||
3237 | else | ||
3238 | m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; | ||
3239 | |||
3240 | memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, | ||
3241 | sizeof(m.mmw_encr_key)); | ||
3242 | |||
3243 | if(psa.psa_encryption_select) | ||
3244 | m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; | ||
3245 | else | ||
3246 | m.mmw_encr_enable = 0; | ||
3247 | |||
3248 | m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; | ||
3249 | m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; | ||
3250 | |||
3251 | /* | ||
3252 | * Set default modem control parameters. | ||
3253 | * See NCR document 407-0024326 Rev. A. | ||
3254 | */ | ||
3255 | m.mmw_jabber_enable = 0x01; | ||
3256 | m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; | ||
3257 | m.mmw_ifs = 0x20; | ||
3258 | m.mmw_mod_delay = 0x04; | ||
3259 | m.mmw_jam_time = 0x38; | ||
3260 | |||
3261 | m.mmw_des_io_invert = 0; | ||
3262 | m.mmw_freeze = 0; | ||
3263 | m.mmw_decay_prm = 0; | ||
3264 | m.mmw_decay_updat_prm = 0; | ||
3265 | |||
3266 | /* Write all info to mmc */ | ||
3267 | mmc_write(base, 0, (u_char *)&m, sizeof(m)); | ||
3268 | |||
3269 | /* The following code start the modem of the 2.00 frequency | ||
3270 | * selectable cards at power on. It's not strictly needed for the | ||
3271 | * following boots... | ||
3272 | * The original patch was by Joe Finney for the PCMCIA driver, but | ||
3273 | * I've cleaned it a bit and add documentation. | ||
3274 | * Thanks to Loeke Brederveld from Lucent for the info. | ||
3275 | */ | ||
3276 | |||
3277 | /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) | ||
3278 | * (does it work for everybody ? - especially old cards...) */ | ||
3279 | /* Note : WFREQSEL verify that it is able to read from EEprom | ||
3280 | * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID | ||
3281 | * is 0xA (Xilinx version) or 0xB (Ariadne version). | ||
3282 | * My test is more crude but do work... */ | ||
3283 | if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & | ||
3284 | (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) | ||
3285 | { | ||
3286 | /* We must download the frequency parameters to the | ||
3287 | * synthetisers (from the EEprom - area 1) | ||
3288 | * Note : as the EEprom is auto decremented, we set the end | ||
3289 | * if the area... */ | ||
3290 | m.mmw_fee_addr = 0x0F; | ||
3291 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3292 | mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, | ||
3293 | (unsigned char *)&m.mmw_fee_ctrl, 2); | ||
3294 | |||
3295 | /* Wait until the download is finished */ | ||
3296 | fee_wait(base, 100, 100); | ||
3297 | |||
3298 | #ifdef DEBUG_CONFIG_INFO | ||
3299 | /* The frequency was in the last word downloaded... */ | ||
3300 | mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, | ||
3301 | (unsigned char *)&m.mmw_fee_data_l, 2); | ||
3302 | |||
3303 | /* Print some info for the user */ | ||
3304 | printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", | ||
3305 | dev->name, | ||
3306 | ((m.mmw_fee_data_h << 4) | | ||
3307 | (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); | ||
3308 | #endif | ||
3309 | |||
3310 | /* We must now download the power adjust value (gain) to | ||
3311 | * the synthetisers (from the EEprom - area 7 - DAC) */ | ||
3312 | m.mmw_fee_addr = 0x61; | ||
3313 | m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; | ||
3314 | mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, | ||
3315 | (unsigned char *)&m.mmw_fee_ctrl, 2); | ||
3316 | |||
3317 | /* Wait until the download is finished */ | ||
3318 | } /* if 2.00 card */ | ||
3319 | |||
3320 | #ifdef DEBUG_CONFIG_TRACE | ||
3321 | printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); | ||
3322 | #endif | ||
3323 | return TRUE; | ||
3324 | } | ||
3325 | |||
3326 | /*------------------------------------------------------------------*/ | ||
3327 | /* | ||
3328 | * Routine to gracefully turn off reception, and wait for any commands | ||
3329 | * to complete. | ||
3330 | * (called in wv_ru_start() and wavelan_close() and wavelan_event()) | ||
3331 | */ | ||
3332 | static int | ||
3333 | wv_ru_stop(struct net_device * dev) | ||
3334 | { | ||
3335 | unsigned int base = dev->base_addr; | ||
3336 | net_local * lp = netdev_priv(dev); | ||
3337 | unsigned long flags; | ||
3338 | int status; | ||
3339 | int spin; | ||
3340 | |||
3341 | #ifdef DEBUG_CONFIG_TRACE | ||
3342 | printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); | ||
3343 | #endif | ||
3344 | |||
3345 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3346 | |||
3347 | /* First, send the LAN controller a stop receive command */ | ||
3348 | wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", | ||
3349 | OP0_STOP_RCV, SR0_NO_RESULT); | ||
3350 | |||
3351 | /* Then, spin until the receive unit goes idle */ | ||
3352 | spin = 300; | ||
3353 | do | ||
3354 | { | ||
3355 | udelay(10); | ||
3356 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
3357 | status = inb(LCSR(base)); | ||
3358 | } | ||
3359 | while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); | ||
3360 | |||
3361 | /* Now, spin until the chip finishes executing its current command */ | ||
3362 | do | ||
3363 | { | ||
3364 | udelay(10); | ||
3365 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
3366 | status = inb(LCSR(base)); | ||
3367 | } | ||
3368 | while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); | ||
3369 | |||
3370 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3371 | |||
3372 | /* If there was a problem */ | ||
3373 | if(spin <= 0) | ||
3374 | { | ||
3375 | #ifdef DEBUG_CONFIG_ERRORS | ||
3376 | printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", | ||
3377 | dev->name); | ||
3378 | #endif | ||
3379 | return FALSE; | ||
3380 | } | ||
3381 | |||
3382 | #ifdef DEBUG_CONFIG_TRACE | ||
3383 | printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); | ||
3384 | #endif | ||
3385 | return TRUE; | ||
3386 | } /* wv_ru_stop */ | ||
3387 | |||
3388 | /*------------------------------------------------------------------*/ | ||
3389 | /* | ||
3390 | * This routine starts the receive unit running. First, it checks if | ||
3391 | * the card is actually ready. Then the card is instructed to receive | ||
3392 | * packets again. | ||
3393 | * (called in wv_hw_reset() & wavelan_open()) | ||
3394 | */ | ||
3395 | static int | ||
3396 | wv_ru_start(struct net_device * dev) | ||
3397 | { | ||
3398 | unsigned int base = dev->base_addr; | ||
3399 | net_local * lp = netdev_priv(dev); | ||
3400 | unsigned long flags; | ||
3401 | |||
3402 | #ifdef DEBUG_CONFIG_TRACE | ||
3403 | printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); | ||
3404 | #endif | ||
3405 | |||
3406 | /* | ||
3407 | * We need to start from a quiescent state. To do so, we could check | ||
3408 | * if the card is already running, but instead we just try to shut | ||
3409 | * it down. First, we disable reception (in case it was already enabled). | ||
3410 | */ | ||
3411 | if(!wv_ru_stop(dev)) | ||
3412 | return FALSE; | ||
3413 | |||
3414 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3415 | |||
3416 | /* Now we know that no command is being executed. */ | ||
3417 | |||
3418 | /* Set the receive frame pointer and stop pointer */ | ||
3419 | lp->rfp = 0; | ||
3420 | outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); | ||
3421 | |||
3422 | /* Reset ring management. This sets the receive frame pointer to 1 */ | ||
3423 | outb(OP1_RESET_RING_MNGMT, LCCR(base)); | ||
3424 | |||
3425 | #if 0 | ||
3426 | /* XXX the i82593 manual page 6-4 seems to indicate that the stop register | ||
3427 | should be set as below */ | ||
3428 | /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ | ||
3429 | #elif 0 | ||
3430 | /* but I set it 0 instead */ | ||
3431 | lp->stop = 0; | ||
3432 | #else | ||
3433 | /* but I set it to 3 bytes per packet less than 8K */ | ||
3434 | lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; | ||
3435 | #endif | ||
3436 | outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); | ||
3437 | outb(OP1_INT_ENABLE, LCCR(base)); | ||
3438 | outb(OP1_SWIT_TO_PORT_0, LCCR(base)); | ||
3439 | |||
3440 | /* Reset receive DMA pointer */ | ||
3441 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3442 | hacr_write_slow(base, HACR_DEFAULT); | ||
3443 | |||
3444 | /* Receive DMA on channel 1 */ | ||
3445 | wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", | ||
3446 | CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); | ||
3447 | |||
3448 | #ifdef DEBUG_I82593_SHOW | ||
3449 | { | ||
3450 | int status; | ||
3451 | int opri; | ||
3452 | int spin = 10000; | ||
3453 | |||
3454 | /* spin until the chip starts receiving */ | ||
3455 | do | ||
3456 | { | ||
3457 | outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); | ||
3458 | status = inb(LCSR(base)); | ||
3459 | if(spin-- <= 0) | ||
3460 | break; | ||
3461 | } | ||
3462 | while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && | ||
3463 | ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); | ||
3464 | printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", | ||
3465 | (status & SR3_RCV_STATE_MASK), i); | ||
3466 | } | ||
3467 | #endif | ||
3468 | |||
3469 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3470 | |||
3471 | #ifdef DEBUG_CONFIG_TRACE | ||
3472 | printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); | ||
3473 | #endif | ||
3474 | return TRUE; | ||
3475 | } | ||
3476 | |||
3477 | /*------------------------------------------------------------------*/ | ||
3478 | /* | ||
3479 | * This routine does a standard config of the WaveLAN controller (i82593). | ||
3480 | * In the ISA driver, this is integrated in wavelan_hardware_reset() | ||
3481 | * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) | ||
3482 | */ | ||
3483 | static int | ||
3484 | wv_82593_config(struct net_device * dev) | ||
3485 | { | ||
3486 | unsigned int base = dev->base_addr; | ||
3487 | net_local * lp = netdev_priv(dev); | ||
3488 | struct i82593_conf_block cfblk; | ||
3489 | int ret = TRUE; | ||
3490 | |||
3491 | #ifdef DEBUG_CONFIG_TRACE | ||
3492 | printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); | ||
3493 | #endif | ||
3494 | |||
3495 | /* Create & fill i82593 config block | ||
3496 | * | ||
3497 | * Now conform to Wavelan document WCIN085B | ||
3498 | */ | ||
3499 | memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); | ||
3500 | cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ | ||
3501 | cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ | ||
3502 | cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ | ||
3503 | cfblk.fifo_32 = 1; | ||
3504 | cfblk.throttle_enb = FALSE; | ||
3505 | cfblk.contin = TRUE; /* enable continuous mode */ | ||
3506 | cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ | ||
3507 | cfblk.addr_len = WAVELAN_ADDR_SIZE; | ||
3508 | cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ | ||
3509 | cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ | ||
3510 | cfblk.loopback = FALSE; | ||
3511 | cfblk.lin_prio = 0; /* conform to 802.3 backoff algorithm */ | ||
3512 | cfblk.exp_prio = 5; /* conform to 802.3 backoff algorithm */ | ||
3513 | cfblk.bof_met = 1; /* conform to 802.3 backoff algorithm */ | ||
3514 | cfblk.ifrm_spc = 0x20 >> 4; /* 32 bit times interframe spacing */ | ||
3515 | cfblk.slottim_low = 0x20 >> 5; /* 32 bit times slot time */ | ||
3516 | cfblk.slottim_hi = 0x0; | ||
3517 | cfblk.max_retr = 15; | ||
3518 | cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ | ||
3519 | cfblk.bc_dis = FALSE; /* Enable broadcast reception */ | ||
3520 | cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ | ||
3521 | cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ | ||
3522 | cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ | ||
3523 | cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ | ||
3524 | cfblk.cs_filter = 0; /* CS is recognized immediately */ | ||
3525 | cfblk.crs_src = FALSE; /* External carrier sense */ | ||
3526 | cfblk.cd_filter = 0; /* CD is recognized immediately */ | ||
3527 | cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ | ||
3528 | cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ | ||
3529 | cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ | ||
3530 | cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ | ||
3531 | cfblk.artx = TRUE; /* Disable automatic retransmission */ | ||
3532 | cfblk.sarec = TRUE; /* Disable source addr trig of CD */ | ||
3533 | cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ | ||
3534 | cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ | ||
3535 | cfblk.lbpkpol = TRUE; /* Loopback pin active high */ | ||
3536 | cfblk.fdx = FALSE; /* Disable full duplex operation */ | ||
3537 | cfblk.dummy_6 = 0x3f; /* all ones */ | ||
3538 | cfblk.mult_ia = FALSE; /* No multiple individual addresses */ | ||
3539 | cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ | ||
3540 | cfblk.dummy_1 = TRUE; /* set to 1 */ | ||
3541 | cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ | ||
3542 | #ifdef MULTICAST_ALL | ||
3543 | cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ | ||
3544 | #else | ||
3545 | cfblk.mc_all = FALSE; /* No multicast all mode */ | ||
3546 | #endif | ||
3547 | cfblk.rcv_mon = 0; /* Monitor mode disabled */ | ||
3548 | cfblk.frag_acpt = TRUE; /* Do not accept fragments */ | ||
3549 | cfblk.tstrttrs = FALSE; /* No start transmission threshold */ | ||
3550 | cfblk.fretx = TRUE; /* FIFO automatic retransmission */ | ||
3551 | cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ | ||
3552 | cfblk.sttlen = TRUE; /* 6 byte status registers */ | ||
3553 | cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ | ||
3554 | cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ | ||
3555 | cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ | ||
3556 | cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ | ||
3557 | |||
3558 | #ifdef DEBUG_I82593_SHOW | ||
3559 | print_hex_dump(KERN_DEBUG, "wavelan_cs: config block: ", DUMP_PREFIX_NONE, | ||
3560 | 16, 1, &cfblk, sizeof(struct i82593_conf_block), false); | ||
3561 | #endif | ||
3562 | |||
3563 | /* Copy the config block to the i82593 */ | ||
3564 | outb(TX_BASE & 0xff, PIORL(base)); | ||
3565 | outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3566 | outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ | ||
3567 | outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ | ||
3568 | outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); | ||
3569 | |||
3570 | /* reset transmit DMA pointer */ | ||
3571 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3572 | hacr_write(base, HACR_DEFAULT); | ||
3573 | if(!wv_82593_cmd(dev, "wv_82593_config(): configure", | ||
3574 | OP0_CONFIGURE, SR0_CONFIGURE_DONE)) | ||
3575 | ret = FALSE; | ||
3576 | |||
3577 | /* Initialize adapter's ethernet MAC address */ | ||
3578 | outb(TX_BASE & 0xff, PIORL(base)); | ||
3579 | outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3580 | outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ | ||
3581 | outb(0, PIOP(base)); /* byte count msb */ | ||
3582 | outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); | ||
3583 | |||
3584 | /* reset transmit DMA pointer */ | ||
3585 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3586 | hacr_write(base, HACR_DEFAULT); | ||
3587 | if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", | ||
3588 | OP0_IA_SETUP, SR0_IA_SETUP_DONE)) | ||
3589 | ret = FALSE; | ||
3590 | |||
3591 | #ifdef WAVELAN_ROAMING | ||
3592 | /* If roaming is enabled, join the "Beacon Request" multicast group... */ | ||
3593 | /* But only if it's not in there already! */ | ||
3594 | if(do_roaming) | ||
3595 | dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); | ||
3596 | #endif /* WAVELAN_ROAMING */ | ||
3597 | |||
3598 | /* If any multicast address to set */ | ||
3599 | if(lp->mc_count) | ||
3600 | { | ||
3601 | struct dev_mc_list * dmi; | ||
3602 | int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; | ||
3603 | |||
3604 | #ifdef DEBUG_CONFIG_INFO | ||
3605 | printk(KERN_DEBUG "%s: wv_hw_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 " %pM\n", dmi->dmi_addr); | ||
3609 | #endif | ||
3610 | |||
3611 | /* Initialize adapter's ethernet multicast addresses */ | ||
3612 | outb(TX_BASE & 0xff, PIORL(base)); | ||
3613 | outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); | ||
3614 | outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ | ||
3615 | outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ | ||
3616 | for(dmi=dev->mc_list; dmi; dmi=dmi->next) | ||
3617 | outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); | ||
3618 | |||
3619 | /* reset transmit DMA pointer */ | ||
3620 | hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); | ||
3621 | hacr_write(base, HACR_DEFAULT); | ||
3622 | if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", | ||
3623 | OP0_MC_SETUP, SR0_MC_SETUP_DONE)) | ||
3624 | ret = FALSE; | ||
3625 | lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ | ||
3626 | } | ||
3627 | |||
3628 | /* Job done, clear the flag */ | ||
3629 | lp->reconfig_82593 = FALSE; | ||
3630 | |||
3631 | #ifdef DEBUG_CONFIG_TRACE | ||
3632 | printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); | ||
3633 | #endif | ||
3634 | return(ret); | ||
3635 | } | ||
3636 | |||
3637 | /*------------------------------------------------------------------*/ | ||
3638 | /* | ||
3639 | * Read the Access Configuration Register, perform a software reset, | ||
3640 | * and then re-enable the card's software. | ||
3641 | * | ||
3642 | * If I understand correctly : reset the pcmcia interface of the | ||
3643 | * wavelan. | ||
3644 | * (called by wv_config()) | ||
3645 | */ | ||
3646 | static int | ||
3647 | wv_pcmcia_reset(struct net_device * dev) | ||
3648 | { | ||
3649 | int i; | ||
3650 | conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; | ||
3651 | struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; | ||
3652 | |||
3653 | #ifdef DEBUG_CONFIG_TRACE | ||
3654 | printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); | ||
3655 | #endif | ||
3656 | |||
3657 | i = pcmcia_access_configuration_register(link, ®); | ||
3658 | if (i != 0) | ||
3659 | { | ||
3660 | cs_error(link, AccessConfigurationRegister, i); | ||
3661 | return FALSE; | ||
3662 | } | ||
3663 | |||
3664 | #ifdef DEBUG_CONFIG_INFO | ||
3665 | printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", | ||
3666 | dev->name, (u_int) reg.Value); | ||
3667 | #endif | ||
3668 | |||
3669 | reg.Action = CS_WRITE; | ||
3670 | reg.Value = reg.Value | COR_SW_RESET; | ||
3671 | i = pcmcia_access_configuration_register(link, ®); | ||
3672 | if (i != 0) | ||
3673 | { | ||
3674 | cs_error(link, AccessConfigurationRegister, i); | ||
3675 | return FALSE; | ||
3676 | } | ||
3677 | |||
3678 | reg.Action = CS_WRITE; | ||
3679 | reg.Value = COR_LEVEL_IRQ | COR_CONFIG; | ||
3680 | i = pcmcia_access_configuration_register(link, ®); | ||
3681 | if (i != 0) | ||
3682 | { | ||
3683 | cs_error(link, AccessConfigurationRegister, i); | ||
3684 | return FALSE; | ||
3685 | } | ||
3686 | |||
3687 | #ifdef DEBUG_CONFIG_TRACE | ||
3688 | printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); | ||
3689 | #endif | ||
3690 | return TRUE; | ||
3691 | } | ||
3692 | |||
3693 | /*------------------------------------------------------------------*/ | ||
3694 | /* | ||
3695 | * wavelan_hw_config() is called after a CARD_INSERTION event is | ||
3696 | * received, to configure the wavelan hardware. | ||
3697 | * Note that the reception will be enabled in wavelan->open(), so the | ||
3698 | * device is configured but idle... | ||
3699 | * Performs the following actions: | ||
3700 | * 1. A pcmcia software reset (using wv_pcmcia_reset()) | ||
3701 | * 2. A power reset (reset DMA) | ||
3702 | * 3. Reset the LAN controller | ||
3703 | * 4. Initialize the radio modem (using wv_mmc_init) | ||
3704 | * 5. Configure LAN controller (using wv_82593_config) | ||
3705 | * 6. Perform a diagnostic on the LAN controller | ||
3706 | * (called by wavelan_event() & wv_hw_reset()) | ||
3707 | */ | ||
3708 | static int | ||
3709 | wv_hw_config(struct net_device * dev) | ||
3710 | { | ||
3711 | net_local * lp = netdev_priv(dev); | ||
3712 | unsigned int base = dev->base_addr; | ||
3713 | unsigned long flags; | ||
3714 | int ret = FALSE; | ||
3715 | |||
3716 | #ifdef DEBUG_CONFIG_TRACE | ||
3717 | printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); | ||
3718 | #endif | ||
3719 | |||
3720 | /* compile-time check the sizes of structures */ | ||
3721 | BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); | ||
3722 | BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); | ||
3723 | BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); | ||
3724 | |||
3725 | /* Reset the pcmcia interface */ | ||
3726 | if(wv_pcmcia_reset(dev) == FALSE) | ||
3727 | return FALSE; | ||
3728 | |||
3729 | /* Disable interrupts */ | ||
3730 | spin_lock_irqsave(&lp->spinlock, flags); | ||
3731 | |||
3732 | /* Disguised goto ;-) */ | ||
3733 | do | ||
3734 | { | ||
3735 | /* Power UP the module + reset the modem + reset host adapter | ||
3736 | * (in fact, reset DMA channels) */ | ||
3737 | hacr_write_slow(base, HACR_RESET); | ||
3738 | hacr_write(base, HACR_DEFAULT); | ||
3739 | |||
3740 | /* Check if the module has been powered up... */ | ||
3741 | if(hasr_read(base) & HASR_NO_CLK) | ||
3742 | { | ||
3743 | #ifdef DEBUG_CONFIG_ERRORS | ||
3744 | printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", | ||
3745 | dev->name); | ||
3746 | #endif | ||
3747 | break; | ||
3748 | } | ||
3749 | |||
3750 | /* initialize the modem */ | ||
3751 | if(wv_mmc_init(dev) == FALSE) | ||
3752 | { | ||
3753 | #ifdef DEBUG_CONFIG_ERRORS | ||
3754 | printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", | ||
3755 | dev->name); | ||
3756 | #endif | ||
3757 | break; | ||
3758 | } | ||
3759 | |||
3760 | /* reset the LAN controller (i82593) */ | ||
3761 | outb(OP0_RESET, LCCR(base)); | ||
3762 | mdelay(1); /* A bit crude ! */ | ||
3763 | |||
3764 | /* Initialize the LAN controller */ | ||
3765 | if(wv_82593_config(dev) == FALSE) | ||
3766 | { | ||
3767 | #ifdef DEBUG_CONFIG_ERRORS | ||
3768 | printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", | ||
3769 | dev->name); | ||
3770 | #endif | ||
3771 | break; | ||
3772 | } | ||
3773 | |||
3774 | /* Diagnostic */ | ||
3775 | if(wv_diag(dev) == FALSE) | ||
3776 | { | ||
3777 | #ifdef DEBUG_CONFIG_ERRORS | ||
3778 | printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", | ||
3779 | dev->name); | ||
3780 | #endif | ||
3781 | break; | ||
3782 | } | ||
3783 | |||
3784 | /* | ||
3785 | * insert code for loopback test here | ||
3786 | */ | ||
3787 | |||
3788 | /* The device is now configured */ | ||
3789 | lp->configured = 1; | ||
3790 | ret = TRUE; | ||
3791 | } | ||
3792 | while(0); | ||
3793 | |||
3794 | /* Re-enable interrupts */ | ||
3795 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
3796 | |||
3797 | #ifdef DEBUG_CONFIG_TRACE | ||
3798 | printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); | ||
3799 | #endif | ||
3800 | return(ret); | ||
3801 | } | ||
3802 | |||
3803 | /*------------------------------------------------------------------*/ | ||
3804 | /* | ||
3805 | * Totally reset the wavelan and restart it. | ||
3806 | * Performs the following actions: | ||
3807 | * 1. Call wv_hw_config() | ||
3808 | * 2. Start the LAN controller's receive unit | ||
3809 | * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) | ||
3810 | */ | ||
3811 | static void | ||
3812 | wv_hw_reset(struct net_device * dev) | ||
3813 | { | ||
3814 | net_local * lp = netdev_priv(dev); | ||
3815 | |||
3816 | #ifdef DEBUG_CONFIG_TRACE | ||
3817 | printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); | ||
3818 | #endif | ||
3819 | |||
3820 | lp->nresets++; | ||
3821 | lp->configured = 0; | ||
3822 | |||
3823 | /* Call wv_hw_config() for most of the reset & init stuff */ | ||
3824 | if(wv_hw_config(dev) == FALSE) | ||
3825 | return; | ||
3826 | |||
3827 | /* start receive unit */ | ||
3828 | wv_ru_start(dev); | ||
3829 | |||
3830 | #ifdef DEBUG_CONFIG_TRACE | ||
3831 | printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); | ||
3832 | #endif | ||
3833 | } | ||
3834 | |||
3835 | /*------------------------------------------------------------------*/ | ||
3836 | /* | ||
3837 | * wv_pcmcia_config() is called after a CARD_INSERTION event is | ||
3838 | * received, to configure the PCMCIA socket, and to make the ethernet | ||
3839 | * device available to the system. | ||
3840 | * (called by wavelan_event()) | ||
3841 | */ | ||
3842 | static int | ||
3843 | wv_pcmcia_config(struct pcmcia_device * link) | ||
3844 | { | ||
3845 | struct net_device * dev = (struct net_device *) link->priv; | ||
3846 | int i; | ||
3847 | win_req_t req; | ||
3848 | memreq_t mem; | ||
3849 | net_local * lp = netdev_priv(dev); | ||
3850 | |||
3851 | |||
3852 | #ifdef DEBUG_CONFIG_TRACE | ||
3853 | printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); | ||
3854 | #endif | ||
3855 | |||
3856 | do | ||
3857 | { | ||
3858 | i = pcmcia_request_io(link, &link->io); | ||
3859 | if (i != 0) | ||
3860 | { | ||
3861 | cs_error(link, RequestIO, i); | ||
3862 | break; | ||
3863 | } | ||
3864 | |||
3865 | /* | ||
3866 | * Now allocate an interrupt line. Note that this does not | ||
3867 | * actually assign a handler to the interrupt. | ||
3868 | */ | ||
3869 | i = pcmcia_request_irq(link, &link->irq); | ||
3870 | if (i != 0) | ||
3871 | { | ||
3872 | cs_error(link, RequestIRQ, i); | ||
3873 | break; | ||
3874 | } | ||
3875 | |||
3876 | /* | ||
3877 | * This actually configures the PCMCIA socket -- setting up | ||
3878 | * the I/O windows and the interrupt mapping. | ||
3879 | */ | ||
3880 | link->conf.ConfigIndex = 1; | ||
3881 | i = pcmcia_request_configuration(link, &link->conf); | ||
3882 | if (i != 0) | ||
3883 | { | ||
3884 | cs_error(link, RequestConfiguration, i); | ||
3885 | break; | ||
3886 | } | ||
3887 | |||
3888 | /* | ||
3889 | * Allocate a small memory window. Note that the struct pcmcia_device | ||
3890 | * structure provides space for one window handle -- if your | ||
3891 | * device needs several windows, you'll need to keep track of | ||
3892 | * the handles in your private data structure, link->priv. | ||
3893 | */ | ||
3894 | req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; | ||
3895 | req.Base = req.Size = 0; | ||
3896 | req.AccessSpeed = mem_speed; | ||
3897 | i = pcmcia_request_window(&link, &req, &link->win); | ||
3898 | if (i != 0) | ||
3899 | { | ||
3900 | cs_error(link, RequestWindow, i); | ||
3901 | break; | ||
3902 | } | ||
3903 | |||
3904 | lp->mem = ioremap(req.Base, req.Size); | ||
3905 | dev->mem_start = (u_long)lp->mem; | ||
3906 | dev->mem_end = dev->mem_start + req.Size; | ||
3907 | |||
3908 | mem.CardOffset = 0; mem.Page = 0; | ||
3909 | i = pcmcia_map_mem_page(link->win, &mem); | ||
3910 | if (i != 0) | ||
3911 | { | ||
3912 | cs_error(link, MapMemPage, i); | ||
3913 | break; | ||
3914 | } | ||
3915 | |||
3916 | /* Feed device with this info... */ | ||
3917 | dev->irq = link->irq.AssignedIRQ; | ||
3918 | dev->base_addr = link->io.BasePort1; | ||
3919 | netif_start_queue(dev); | ||
3920 | |||
3921 | #ifdef DEBUG_CONFIG_INFO | ||
3922 | printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART %p IRQ %d IOPORT 0x%x\n", | ||
3923 | lp->mem, dev->irq, (u_int) dev->base_addr); | ||
3924 | #endif | ||
3925 | |||
3926 | SET_NETDEV_DEV(dev, &handle_to_dev(link)); | ||
3927 | i = register_netdev(dev); | ||
3928 | if(i != 0) | ||
3929 | { | ||
3930 | #ifdef DEBUG_CONFIG_ERRORS | ||
3931 | printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); | ||
3932 | #endif | ||
3933 | break; | ||
3934 | } | ||
3935 | } | ||
3936 | while(0); /* Humm... Disguised goto !!! */ | ||
3937 | |||
3938 | /* If any step failed, release any partially configured state */ | ||
3939 | if(i != 0) | ||
3940 | { | ||
3941 | wv_pcmcia_release(link); | ||
3942 | return FALSE; | ||
3943 | } | ||
3944 | |||
3945 | strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name); | ||
3946 | link->dev_node = &((net_local *) netdev_priv(dev))->node; | ||
3947 | |||
3948 | #ifdef DEBUG_CONFIG_TRACE | ||
3949 | printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); | ||
3950 | #endif | ||
3951 | return TRUE; | ||
3952 | } | ||
3953 | |||
3954 | /*------------------------------------------------------------------*/ | ||
3955 | /* | ||
3956 | * After a card is removed, wv_pcmcia_release() will unregister the net | ||
3957 | * device, and release the PCMCIA configuration. If the device is | ||
3958 | * still open, this will be postponed until it is closed. | ||
3959 | */ | ||
3960 | static void | ||
3961 | wv_pcmcia_release(struct pcmcia_device *link) | ||
3962 | { | ||
3963 | struct net_device * dev = (struct net_device *) link->priv; | ||
3964 | net_local * lp = netdev_priv(dev); | ||
3965 | |||
3966 | #ifdef DEBUG_CONFIG_TRACE | ||
3967 | printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); | ||
3968 | #endif | ||
3969 | |||
3970 | iounmap(lp->mem); | ||
3971 | pcmcia_disable_device(link); | ||
3972 | |||
3973 | #ifdef DEBUG_CONFIG_TRACE | ||
3974 | printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); | ||
3975 | #endif | ||
3976 | } | ||
3977 | |||
3978 | /************************ INTERRUPT HANDLING ************************/ | ||
3979 | |||
3980 | /* | ||
3981 | * This function is the interrupt handler for the WaveLAN card. This | ||
3982 | * routine will be called whenever: | ||
3983 | * 1. A packet is received. | ||
3984 | * 2. A packet has successfully been transferred and the unit is | ||
3985 | * ready to transmit another packet. | ||
3986 | * 3. A command has completed execution. | ||
3987 | */ | ||
3988 | static irqreturn_t | ||
3989 | wavelan_interrupt(int irq, | ||
3990 | void * dev_id) | ||
3991 | { | ||
3992 | struct net_device * dev = dev_id; | ||
3993 | net_local * lp; | ||
3994 | unsigned int base; | ||
3995 | int status0; | ||
3996 | u_int tx_status; | ||
3997 | |||
3998 | #ifdef DEBUG_INTERRUPT_TRACE | ||
3999 | printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); | ||
4000 | #endif | ||
4001 | |||
4002 | lp = netdev_priv(dev); | ||
4003 | base = dev->base_addr; | ||
4004 | |||
4005 | #ifdef DEBUG_INTERRUPT_INFO | ||
4006 | /* Check state of our spinlock (it should be cleared) */ | ||
4007 | if(spin_is_locked(&lp->spinlock)) | ||
4008 | printk(KERN_DEBUG | ||
4009 | "%s: wavelan_interrupt(): spinlock is already locked !!!\n", | ||
4010 | dev->name); | ||
4011 | #endif | ||
4012 | |||
4013 | /* Prevent reentrancy. We need to do that because we may have | ||
4014 | * multiple interrupt handler running concurently. | ||
4015 | * It is safe because interrupts are disabled before aquiring | ||
4016 | * the spinlock. */ | ||
4017 | spin_lock(&lp->spinlock); | ||
4018 | |||
4019 | /* Treat all pending interrupts */ | ||
4020 | while(1) | ||
4021 | { | ||
4022 | /* ---------------- INTERRUPT CHECKING ---------------- */ | ||
4023 | /* | ||
4024 | * Look for the interrupt and verify the validity | ||
4025 | */ | ||
4026 | outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); | ||
4027 | status0 = inb(LCSR(base)); | ||
4028 | |||
4029 | #ifdef DEBUG_INTERRUPT_INFO | ||
4030 | printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, | ||
4031 | (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); | ||
4032 | if(status0&SR0_INTERRUPT) | ||
4033 | { | ||
4034 | printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : | ||
4035 | ((status0 & SR0_EXECUTION) ? "cmd" : | ||
4036 | ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), | ||
4037 | (status0 & SR0_EVENT_MASK)); | ||
4038 | } | ||
4039 | else | ||
4040 | printk("\n"); | ||
4041 | #endif | ||
4042 | |||
4043 | /* Return if no actual interrupt from i82593 (normal exit) */ | ||
4044 | if(!(status0 & SR0_INTERRUPT)) | ||
4045 | break; | ||
4046 | |||
4047 | /* If interrupt is both Rx and Tx or none... | ||
4048 | * This code in fact is there to catch the spurious interrupt | ||
4049 | * when you remove the wavelan pcmcia card from the socket */ | ||
4050 | if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || | ||
4051 | ((status0 & SR0_BOTH_RX_TX) == 0x0)) | ||
4052 | { | ||
4053 | #ifdef DEBUG_INTERRUPT_INFO | ||
4054 | printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", | ||
4055 | dev->name, status0); | ||
4056 | #endif | ||
4057 | /* Acknowledge the interrupt */ | ||
4058 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); | ||
4059 | break; | ||
4060 | } | ||
4061 | |||
4062 | /* ----------------- RECEIVING PACKET ----------------- */ | ||
4063 | /* | ||
4064 | * When the wavelan signal the reception of a new packet, | ||
4065 | * we call wv_packet_rcv() to copy if from the buffer and | ||
4066 | * send it to NET3 | ||
4067 | */ | ||
4068 | if(status0 & SR0_RECEPTION) | ||
4069 | { | ||
4070 | #ifdef DEBUG_INTERRUPT_INFO | ||
4071 | printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); | ||
4072 | #endif | ||
4073 | |||
4074 | if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) | ||
4075 | { | ||
4076 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4077 | printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", | ||
4078 | dev->name); | ||
4079 | #endif | ||
4080 | dev->stats.rx_over_errors++; | ||
4081 | lp->overrunning = 1; | ||
4082 | } | ||
4083 | |||
4084 | /* Get the packet */ | ||
4085 | wv_packet_rcv(dev); | ||
4086 | lp->overrunning = 0; | ||
4087 | |||
4088 | /* Acknowledge the interrupt */ | ||
4089 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); | ||
4090 | continue; | ||
4091 | } | ||
4092 | |||
4093 | /* ---------------- COMMAND COMPLETION ---------------- */ | ||
4094 | /* | ||
4095 | * Interrupts issued when the i82593 has completed a command. | ||
4096 | * Most likely : transmission done | ||
4097 | */ | ||
4098 | |||
4099 | /* If a transmission has been done */ | ||
4100 | if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || | ||
4101 | (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || | ||
4102 | (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) | ||
4103 | { | ||
4104 | #ifdef DEBUG_TX_ERROR | ||
4105 | if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) | ||
4106 | printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", | ||
4107 | dev->name); | ||
4108 | #endif | ||
4109 | |||
4110 | /* Get transmission status */ | ||
4111 | tx_status = inb(LCSR(base)); | ||
4112 | tx_status |= (inb(LCSR(base)) << 8); | ||
4113 | #ifdef DEBUG_INTERRUPT_INFO | ||
4114 | printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", | ||
4115 | dev->name); | ||
4116 | { | ||
4117 | u_int rcv_bytes; | ||
4118 | u_char status3; | ||
4119 | rcv_bytes = inb(LCSR(base)); | ||
4120 | rcv_bytes |= (inb(LCSR(base)) << 8); | ||
4121 | status3 = inb(LCSR(base)); | ||
4122 | printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", | ||
4123 | tx_status, rcv_bytes, (u_int) status3); | ||
4124 | } | ||
4125 | #endif | ||
4126 | /* Check for possible errors */ | ||
4127 | if((tx_status & TX_OK) != TX_OK) | ||
4128 | { | ||
4129 | dev->stats.tx_errors++; | ||
4130 | |||
4131 | if(tx_status & TX_FRTL) | ||
4132 | { | ||
4133 | #ifdef DEBUG_TX_ERROR | ||
4134 | printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", | ||
4135 | dev->name); | ||
4136 | #endif | ||
4137 | } | ||
4138 | if(tx_status & TX_UND_RUN) | ||
4139 | { | ||
4140 | #ifdef DEBUG_TX_FAIL | ||
4141 | printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", | ||
4142 | dev->name); | ||
4143 | #endif | ||
4144 | dev->stats.tx_aborted_errors++; | ||
4145 | } | ||
4146 | if(tx_status & TX_LOST_CTS) | ||
4147 | { | ||
4148 | #ifdef DEBUG_TX_FAIL | ||
4149 | printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); | ||
4150 | #endif | ||
4151 | dev->stats.tx_carrier_errors++; | ||
4152 | } | ||
4153 | if(tx_status & TX_LOST_CRS) | ||
4154 | { | ||
4155 | #ifdef DEBUG_TX_FAIL | ||
4156 | printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", | ||
4157 | dev->name); | ||
4158 | #endif | ||
4159 | dev->stats.tx_carrier_errors++; | ||
4160 | } | ||
4161 | if(tx_status & TX_HRT_BEAT) | ||
4162 | { | ||
4163 | #ifdef DEBUG_TX_FAIL | ||
4164 | printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); | ||
4165 | #endif | ||
4166 | dev->stats.tx_heartbeat_errors++; | ||
4167 | } | ||
4168 | if(tx_status & TX_DEFER) | ||
4169 | { | ||
4170 | #ifdef DEBUG_TX_FAIL | ||
4171 | printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", | ||
4172 | dev->name); | ||
4173 | #endif | ||
4174 | } | ||
4175 | /* Ignore late collisions since they're more likely to happen | ||
4176 | * here (the WaveLAN design prevents the LAN controller from | ||
4177 | * receiving while it is transmitting). We take action only when | ||
4178 | * the maximum retransmit attempts is exceeded. | ||
4179 | */ | ||
4180 | if(tx_status & TX_COLL) | ||
4181 | { | ||
4182 | if(tx_status & TX_MAX_COL) | ||
4183 | { | ||
4184 | #ifdef DEBUG_TX_FAIL | ||
4185 | printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", | ||
4186 | dev->name); | ||
4187 | #endif | ||
4188 | if(!(tx_status & TX_NCOL_MASK)) | ||
4189 | { | ||
4190 | dev->stats.collisions += 0x10; | ||
4191 | } | ||
4192 | } | ||
4193 | } | ||
4194 | } /* if(!(tx_status & TX_OK)) */ | ||
4195 | |||
4196 | dev->stats.collisions += (tx_status & TX_NCOL_MASK); | ||
4197 | dev->stats.tx_packets++; | ||
4198 | |||
4199 | netif_wake_queue(dev); | ||
4200 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ | ||
4201 | } | ||
4202 | else /* if interrupt = transmit done or retransmit done */ | ||
4203 | { | ||
4204 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4205 | printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", | ||
4206 | status0); | ||
4207 | #endif | ||
4208 | outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ | ||
4209 | } | ||
4210 | } /* while(1) */ | ||
4211 | |||
4212 | spin_unlock(&lp->spinlock); | ||
4213 | |||
4214 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4215 | printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); | ||
4216 | #endif | ||
4217 | |||
4218 | /* We always return IRQ_HANDLED, because we will receive empty | ||
4219 | * interrupts under normal operations. Anyway, it doesn't matter | ||
4220 | * as we are dealing with an ISA interrupt that can't be shared. | ||
4221 | * | ||
4222 | * Explanation : under heavy receive, the following happens : | ||
4223 | * ->wavelan_interrupt() | ||
4224 | * (status0 & SR0_INTERRUPT) != 0 | ||
4225 | * ->wv_packet_rcv() | ||
4226 | * (status0 & SR0_INTERRUPT) != 0 | ||
4227 | * ->wv_packet_rcv() | ||
4228 | * (status0 & SR0_INTERRUPT) == 0 // i.e. no more event | ||
4229 | * <-wavelan_interrupt() | ||
4230 | * ->wavelan_interrupt() | ||
4231 | * (status0 & SR0_INTERRUPT) == 0 // i.e. empty interrupt | ||
4232 | * <-wavelan_interrupt() | ||
4233 | * Jean II */ | ||
4234 | return IRQ_HANDLED; | ||
4235 | } /* wv_interrupt */ | ||
4236 | |||
4237 | /*------------------------------------------------------------------*/ | ||
4238 | /* | ||
4239 | * Watchdog: when we start a transmission, a timer is set for us in the | ||
4240 | * kernel. If the transmission completes, this timer is disabled. If | ||
4241 | * the timer expires, we are called and we try to unlock the hardware. | ||
4242 | * | ||
4243 | * Note : This watchdog is move clever than the one in the ISA driver, | ||
4244 | * because it try to abort the current command before reseting | ||
4245 | * everything... | ||
4246 | * On the other hand, it's a bit simpler, because we don't have to | ||
4247 | * deal with the multiple Tx buffers... | ||
4248 | */ | ||
4249 | static void | ||
4250 | wavelan_watchdog(struct net_device * dev) | ||
4251 | { | ||
4252 | net_local * lp = netdev_priv(dev); | ||
4253 | unsigned int base = dev->base_addr; | ||
4254 | unsigned long flags; | ||
4255 | int aborted = FALSE; | ||
4256 | |||
4257 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4258 | printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); | ||
4259 | #endif | ||
4260 | |||
4261 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4262 | printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", | ||
4263 | dev->name); | ||
4264 | #endif | ||
4265 | |||
4266 | spin_lock_irqsave(&lp->spinlock, flags); | ||
4267 | |||
4268 | /* Ask to abort the current command */ | ||
4269 | outb(OP0_ABORT, LCCR(base)); | ||
4270 | |||
4271 | /* Wait for the end of the command (a bit hackish) */ | ||
4272 | if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", | ||
4273 | OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) | ||
4274 | aborted = TRUE; | ||
4275 | |||
4276 | /* Release spinlock here so that wv_hw_reset() can grab it */ | ||
4277 | spin_unlock_irqrestore(&lp->spinlock, flags); | ||
4278 | |||
4279 | /* Check if we were successful in aborting it */ | ||
4280 | if(!aborted) | ||
4281 | { | ||
4282 | /* It seem that it wasn't enough */ | ||
4283 | #ifdef DEBUG_INTERRUPT_ERROR | ||
4284 | printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", | ||
4285 | dev->name); | ||
4286 | #endif | ||
4287 | wv_hw_reset(dev); | ||
4288 | } | ||
4289 | |||
4290 | #ifdef DEBUG_PSA_SHOW | ||
4291 | { | ||
4292 | psa_t psa; | ||
4293 | psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); | ||
4294 | wv_psa_show(&psa); | ||
4295 | } | ||
4296 | #endif | ||
4297 | #ifdef DEBUG_MMC_SHOW | ||
4298 | wv_mmc_show(dev); | ||
4299 | #endif | ||
4300 | #ifdef DEBUG_I82593_SHOW | ||
4301 | wv_ru_show(dev); | ||
4302 | #endif | ||
4303 | |||
4304 | /* We are no more waiting for something... */ | ||
4305 | netif_wake_queue(dev); | ||
4306 | |||
4307 | #ifdef DEBUG_INTERRUPT_TRACE | ||
4308 | printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); | ||
4309 | #endif | ||
4310 | } | ||
4311 | |||
4312 | /********************* CONFIGURATION CALLBACKS *********************/ | ||
4313 | /* | ||
4314 | * Here are the functions called by the pcmcia package (cardmgr) and | ||
4315 | * linux networking (NET3) for initialization, configuration and | ||
4316 | * deinstallations of the Wavelan Pcmcia Hardware. | ||
4317 | */ | ||
4318 | |||
4319 | /*------------------------------------------------------------------*/ | ||
4320 | /* | ||
4321 | * Configure and start up the WaveLAN PCMCIA adaptor. | ||
4322 | * Called by NET3 when it "open" the device. | ||
4323 | */ | ||
4324 | static int | ||
4325 | wavelan_open(struct net_device * dev) | ||
4326 | { | ||
4327 | net_local * lp = netdev_priv(dev); | ||
4328 | struct pcmcia_device * link = lp->link; | ||
4329 | unsigned int base = dev->base_addr; | ||
4330 | |||
4331 | #ifdef DEBUG_CALLBACK_TRACE | ||
4332 | printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, | ||
4333 | (unsigned int) dev); | ||
4334 | #endif | ||
4335 | |||
4336 | /* Check if the modem is powered up (wavelan_close() power it down */ | ||
4337 | if(hasr_read(base) & HASR_NO_CLK) | ||
4338 | { | ||
4339 | /* Power up (power up time is 250us) */ | ||
4340 | hacr_write(base, HACR_DEFAULT); | ||
4341 | |||
4342 | /* Check if the module has been powered up... */ | ||
4343 | if(hasr_read(base) & HASR_NO_CLK) | ||
4344 | { | ||
4345 | #ifdef DEBUG_CONFIG_ERRORS | ||
4346 | printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", | ||
4347 | dev->name); | ||
4348 | #endif | ||
4349 | return FALSE; | ||
4350 | } | ||
4351 | } | ||
4352 | |||
4353 | /* Start reception and declare the driver ready */ | ||
4354 | if(!lp->configured) | ||
4355 | return FALSE; | ||
4356 | if(!wv_ru_start(dev)) | ||
4357 | wv_hw_reset(dev); /* If problem : reset */ | ||
4358 | netif_start_queue(dev); | ||
4359 | |||
4360 | /* Mark the device as used */ | ||
4361 | link->open++; | ||
4362 | |||
4363 | #ifdef WAVELAN_ROAMING | ||
4364 | if(do_roaming) | ||
4365 | wv_roam_init(dev); | ||
4366 | #endif /* WAVELAN_ROAMING */ | ||
4367 | |||
4368 | #ifdef DEBUG_CALLBACK_TRACE | ||
4369 | printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); | ||
4370 | #endif | ||
4371 | return 0; | ||
4372 | } | ||
4373 | |||
4374 | /*------------------------------------------------------------------*/ | ||
4375 | /* | ||
4376 | * Shutdown the WaveLAN PCMCIA adaptor. | ||
4377 | * Called by NET3 when it "close" the device. | ||
4378 | */ | ||
4379 | static int | ||
4380 | wavelan_close(struct net_device * dev) | ||
4381 | { | ||
4382 | struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; | ||
4383 | unsigned int base = dev->base_addr; | ||
4384 | |||
4385 | #ifdef DEBUG_CALLBACK_TRACE | ||
4386 | printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, | ||
4387 | (unsigned int) dev); | ||
4388 | #endif | ||
4389 | |||
4390 | /* If the device isn't open, then nothing to do */ | ||
4391 | if(!link->open) | ||
4392 | { | ||
4393 | #ifdef DEBUG_CONFIG_INFO | ||
4394 | printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); | ||
4395 | #endif | ||
4396 | return 0; | ||
4397 | } | ||
4398 | |||
4399 | #ifdef WAVELAN_ROAMING | ||
4400 | /* Cleanup of roaming stuff... */ | ||
4401 | if(do_roaming) | ||
4402 | wv_roam_cleanup(dev); | ||
4403 | #endif /* WAVELAN_ROAMING */ | ||
4404 | |||
4405 | link->open--; | ||
4406 | |||
4407 | /* If the card is still present */ | ||
4408 | if(netif_running(dev)) | ||
4409 | { | ||
4410 | netif_stop_queue(dev); | ||
4411 | |||
4412 | /* Stop receiving new messages and wait end of transmission */ | ||
4413 | wv_ru_stop(dev); | ||
4414 | |||
4415 | /* Power down the module */ | ||
4416 | hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); | ||
4417 | } | ||
4418 | |||
4419 | #ifdef DEBUG_CALLBACK_TRACE | ||
4420 | printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); | ||
4421 | #endif | ||
4422 | return 0; | ||
4423 | } | ||
4424 | |||
4425 | static const struct net_device_ops wavelan_netdev_ops = { | ||
4426 | .ndo_open = wavelan_open, | ||
4427 | .ndo_stop = wavelan_close, | ||
4428 | .ndo_start_xmit = wavelan_packet_xmit, | ||
4429 | .ndo_set_multicast_list = wavelan_set_multicast_list, | ||
4430 | #ifdef SET_MAC_ADDRESS | ||
4431 | .ndo_set_mac_address = wavelan_set_mac_address, | ||
4432 | #endif | ||
4433 | .ndo_tx_timeout = wavelan_watchdog, | ||
4434 | .ndo_change_mtu = eth_change_mtu, | ||
4435 | .ndo_validate_addr = eth_validate_addr, | ||
4436 | }; | ||
4437 | |||
4438 | /*------------------------------------------------------------------*/ | ||
4439 | /* | ||
4440 | * wavelan_attach() creates an "instance" of the driver, allocating | ||
4441 | * local data structures for one device (one interface). The device | ||
4442 | * is registered with Card Services. | ||
4443 | * | ||
4444 | * The dev_link structure is initialized, but we don't actually | ||
4445 | * configure the card at this point -- we wait until we receive a | ||
4446 | * card insertion event. | ||
4447 | */ | ||
4448 | static int | ||
4449 | wavelan_probe(struct pcmcia_device *p_dev) | ||
4450 | { | ||
4451 | struct net_device * dev; /* Interface generic data */ | ||
4452 | net_local * lp; /* Interface specific data */ | ||
4453 | int ret; | ||
4454 | |||
4455 | #ifdef DEBUG_CALLBACK_TRACE | ||
4456 | printk(KERN_DEBUG "-> wavelan_attach()\n"); | ||
4457 | #endif | ||
4458 | |||
4459 | /* The io structure describes IO port mapping */ | ||
4460 | p_dev->io.NumPorts1 = 8; | ||
4461 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
4462 | p_dev->io.IOAddrLines = 3; | ||
4463 | |||
4464 | /* Interrupt setup */ | ||
4465 | p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; | ||
4466 | p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
4467 | p_dev->irq.Handler = wavelan_interrupt; | ||
4468 | |||
4469 | /* General socket configuration */ | ||
4470 | p_dev->conf.Attributes = CONF_ENABLE_IRQ; | ||
4471 | p_dev->conf.IntType = INT_MEMORY_AND_IO; | ||
4472 | |||
4473 | /* Allocate the generic data structure */ | ||
4474 | dev = alloc_etherdev(sizeof(net_local)); | ||
4475 | if (!dev) | ||
4476 | return -ENOMEM; | ||
4477 | |||
4478 | p_dev->priv = p_dev->irq.Instance = dev; | ||
4479 | |||
4480 | lp = netdev_priv(dev); | ||
4481 | |||
4482 | /* Init specific data */ | ||
4483 | lp->configured = 0; | ||
4484 | lp->reconfig_82593 = FALSE; | ||
4485 | lp->nresets = 0; | ||
4486 | /* Multicast stuff */ | ||
4487 | lp->promiscuous = 0; | ||
4488 | lp->allmulticast = 0; | ||
4489 | lp->mc_count = 0; | ||
4490 | |||
4491 | /* Init spinlock */ | ||
4492 | spin_lock_init(&lp->spinlock); | ||
4493 | |||
4494 | /* back links */ | ||
4495 | lp->dev = dev; | ||
4496 | |||
4497 | /* wavelan NET3 callbacks */ | ||
4498 | dev->netdev_ops = &wavelan_netdev_ops; | ||
4499 | dev->watchdog_timeo = WATCHDOG_JIFFIES; | ||
4500 | SET_ETHTOOL_OPS(dev, &ops); | ||
4501 | |||
4502 | dev->wireless_handlers = &wavelan_handler_def; | ||
4503 | lp->wireless_data.spy_data = &lp->spy_data; | ||
4504 | dev->wireless_data = &lp->wireless_data; | ||
4505 | |||
4506 | /* Other specific data */ | ||
4507 | dev->mtu = WAVELAN_MTU; | ||
4508 | |||
4509 | ret = wv_pcmcia_config(p_dev); | ||
4510 | if (ret) | ||
4511 | return ret; | ||
4512 | |||
4513 | ret = wv_hw_config(dev); | ||
4514 | if (ret) { | ||
4515 | dev->irq = 0; | ||
4516 | pcmcia_disable_device(p_dev); | ||
4517 | return ret; | ||
4518 | } | ||
4519 | |||
4520 | wv_init_info(dev); | ||
4521 | |||
4522 | #ifdef DEBUG_CALLBACK_TRACE | ||
4523 | printk(KERN_DEBUG "<- wavelan_attach()\n"); | ||
4524 | #endif | ||
4525 | |||
4526 | return 0; | ||
4527 | } | ||
4528 | |||
4529 | /*------------------------------------------------------------------*/ | ||
4530 | /* | ||
4531 | * This deletes a driver "instance". The device is de-registered with | ||
4532 | * Card Services. If it has been released, all local data structures | ||
4533 | * are freed. Otherwise, the structures will be freed when the device | ||
4534 | * is released. | ||
4535 | */ | ||
4536 | static void | ||
4537 | wavelan_detach(struct pcmcia_device *link) | ||
4538 | { | ||
4539 | #ifdef DEBUG_CALLBACK_TRACE | ||
4540 | printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); | ||
4541 | #endif | ||
4542 | |||
4543 | /* Some others haven't done their job : give them another chance */ | ||
4544 | wv_pcmcia_release(link); | ||
4545 | |||
4546 | /* Free pieces */ | ||
4547 | if(link->priv) | ||
4548 | { | ||
4549 | struct net_device * dev = (struct net_device *) link->priv; | ||
4550 | |||
4551 | /* Remove ourselves from the kernel list of ethernet devices */ | ||
4552 | /* Warning : can't be called from interrupt, timer or wavelan_close() */ | ||
4553 | if (link->dev_node) | ||
4554 | unregister_netdev(dev); | ||
4555 | link->dev_node = NULL; | ||
4556 | ((net_local *)netdev_priv(dev))->link = NULL; | ||
4557 | ((net_local *)netdev_priv(dev))->dev = NULL; | ||
4558 | free_netdev(dev); | ||
4559 | } | ||
4560 | |||
4561 | #ifdef DEBUG_CALLBACK_TRACE | ||
4562 | printk(KERN_DEBUG "<- wavelan_detach()\n"); | ||
4563 | #endif | ||
4564 | } | ||
4565 | |||
4566 | static int wavelan_suspend(struct pcmcia_device *link) | ||
4567 | { | ||
4568 | struct net_device * dev = (struct net_device *) link->priv; | ||
4569 | |||
4570 | /* NB: wavelan_close will be called, but too late, so we are | ||
4571 | * obliged to close nicely the wavelan here. David, could you | ||
4572 | * close the device before suspending them ? And, by the way, | ||
4573 | * could you, on resume, add a "route add -net ..." after the | ||
4574 | * ifconfig up ? Thanks... */ | ||
4575 | |||
4576 | /* Stop receiving new messages and wait end of transmission */ | ||
4577 | wv_ru_stop(dev); | ||
4578 | |||
4579 | if (link->open) | ||
4580 | netif_device_detach(dev); | ||
4581 | |||
4582 | /* Power down the module */ | ||
4583 | hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); | ||
4584 | |||
4585 | return 0; | ||
4586 | } | ||
4587 | |||
4588 | static int wavelan_resume(struct pcmcia_device *link) | ||
4589 | { | ||
4590 | struct net_device * dev = (struct net_device *) link->priv; | ||
4591 | |||
4592 | if (link->open) { | ||
4593 | wv_hw_reset(dev); | ||
4594 | netif_device_attach(dev); | ||
4595 | } | ||
4596 | |||
4597 | return 0; | ||
4598 | } | ||
4599 | |||
4600 | |||
4601 | static struct pcmcia_device_id wavelan_ids[] = { | ||
4602 | PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975), | ||
4603 | PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06), | ||
4604 | PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/PCMCIA", 0x23eb9949, 0x1bc50975), | ||
4605 | PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/PCMCIA", 0x24358cd4, 0x1bc50975), | ||
4606 | PCMCIA_DEVICE_NULL, | ||
4607 | }; | ||
4608 | MODULE_DEVICE_TABLE(pcmcia, wavelan_ids); | ||
4609 | |||
4610 | static struct pcmcia_driver wavelan_driver = { | ||
4611 | .owner = THIS_MODULE, | ||
4612 | .drv = { | ||
4613 | .name = "wavelan_cs", | ||
4614 | }, | ||
4615 | .probe = wavelan_probe, | ||
4616 | .remove = wavelan_detach, | ||
4617 | .id_table = wavelan_ids, | ||
4618 | .suspend = wavelan_suspend, | ||
4619 | .resume = wavelan_resume, | ||
4620 | }; | ||
4621 | |||
4622 | static int __init | ||
4623 | init_wavelan_cs(void) | ||
4624 | { | ||
4625 | return pcmcia_register_driver(&wavelan_driver); | ||
4626 | } | ||
4627 | |||
4628 | static void __exit | ||
4629 | exit_wavelan_cs(void) | ||
4630 | { | ||
4631 | pcmcia_unregister_driver(&wavelan_driver); | ||
4632 | } | ||
4633 | |||
4634 | module_init(init_wavelan_cs); | ||
4635 | module_exit(exit_wavelan_cs); | ||
diff --git a/drivers/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h deleted file mode 100644 index 2e4bfe4147c6..000000000000 --- a/drivers/net/wireless/wavelan_cs.h +++ /dev/null | |||
@@ -1,386 +0,0 @@ | |||
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 | static 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 | static 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 | static 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 | } __attribute__((packed)); | ||
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 deleted file mode 100644 index 81d91531c4f9..000000000000 --- a/drivers/net/wireless/wavelan_cs.p.h +++ /dev/null | |||
@@ -1,766 +0,0 @@ | |||
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 | * It might be a good idea as well to fetch the wireless tools to | ||
103 | * configure the device and play a bit. | ||
104 | */ | ||
105 | |||
106 | /* ---------------------------- FILES ---------------------------- */ | ||
107 | /* | ||
108 | * wavelan_cs.c : The actual code for the driver - C functions | ||
109 | * | ||
110 | * wavelan_cs.p.h : Private header : local types / vars for the driver | ||
111 | * | ||
112 | * wavelan_cs.h : Description of the hardware interface & structs | ||
113 | * | ||
114 | * i82593.h : Description if the Ethernet controller | ||
115 | */ | ||
116 | |||
117 | /* --------------------------- HISTORY --------------------------- */ | ||
118 | /* | ||
119 | * The history of the Wavelan drivers is as complicated as history of | ||
120 | * the Wavelan itself (NCR -> AT&T -> Lucent). | ||
121 | * | ||
122 | * All started with Anders Klemets <klemets@paul.rutgers.edu>, | ||
123 | * writing a Wavelan ISA driver for the MACH microkernel. Girish | ||
124 | * Welling <welling@paul.rutgers.edu> had also worked on it. | ||
125 | * Keith Moore modify this for the Pcmcia hardware. | ||
126 | * | ||
127 | * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI | ||
128 | * and add specific Pcmcia support (there is currently no equivalent | ||
129 | * of the PCMCIA package under BSD...). | ||
130 | * | ||
131 | * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to FreeBSD. | ||
132 | * | ||
133 | * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux. | ||
134 | * | ||
135 | * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver | ||
136 | * (with help of the BSDI PCMCIA driver) for PCMCIA. | ||
137 | * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work. | ||
138 | * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start | ||
139 | * correctly 2.00 cards (2.4 GHz with frequency selection). | ||
140 | * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his | ||
141 | * Pcmcia package (+ bug corrections). | ||
142 | * | ||
143 | * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some | ||
144 | * patchs to the Pcmcia driver. After, I added code in the ISA driver | ||
145 | * for Wireless Extensions and full support of frequency selection | ||
146 | * cards. Now, I'm doing the same to the Pcmcia driver + some | ||
147 | * reorganisation. | ||
148 | * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me | ||
149 | * much needed informations on the Wavelan hardware. | ||
150 | */ | ||
151 | |||
152 | /* By the way : for the copyright & legal stuff : | ||
153 | * Almost everybody wrote code under GNU or BSD license (or alike), | ||
154 | * and want that their original copyright remain somewhere in the | ||
155 | * code (for myself, I go with the GPL). | ||
156 | * Nobody want to take responsibility for anything, except the fame... | ||
157 | */ | ||
158 | |||
159 | /* --------------------------- CREDITS --------------------------- */ | ||
160 | /* | ||
161 | * Credits: | ||
162 | * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and | ||
163 | * Loeke Brederveld of Lucent for providing extremely useful | ||
164 | * information about WaveLAN PCMCIA hardware | ||
165 | * | ||
166 | * This driver is based upon several other drivers, in particular: | ||
167 | * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter | ||
168 | * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter | ||
169 | * Anders Klemets' PCMCIA WaveLAN adapter driver | ||
170 | * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter | ||
171 | * | ||
172 | * Additional Credits: | ||
173 | * | ||
174 | * This software was originally developed under Linux 1.2.3 | ||
175 | * (Slackware 2.0 distribution). | ||
176 | * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) | ||
177 | * with an HP OmniBook 4000 and then a 5500. | ||
178 | * | ||
179 | * It is based on other device drivers and information either written | ||
180 | * or supplied by: | ||
181 | * James Ashton (jaa101@syseng.anu.edu.au), | ||
182 | * Ajay Bakre (bakre@paul.rutgers.edu), | ||
183 | * Donald Becker (becker@super.org), | ||
184 | * Jim Binkley <jrb@cs.pdx.edu>, | ||
185 | * Loeke Brederveld <lbrederv@wavelan.com>, | ||
186 | * Allan Creighton (allanc@cs.su.oz.au), | ||
187 | * Brent Elphick <belphick@uwaterloo.ca>, | ||
188 | * Joe Finney <joe@comp.lancs.ac.uk>, | ||
189 | * Matthew Geier (matthew@cs.su.oz.au), | ||
190 | * Remo di Giovanni (remo@cs.su.oz.au), | ||
191 | * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), | ||
192 | * David Hinds <dahinds@users.sourceforge.net>, | ||
193 | * Jan Hoogendoorn (c/o marteijn@lucent.com), | ||
194 | * Bruce Janson <bruce@cs.usyd.edu.au>, | ||
195 | * Anthony D. Joseph <adj@lcs.mit.edu>, | ||
196 | * Anders Klemets (klemets@paul.rutgers.edu), | ||
197 | * Yunzhou Li <yunzhou@strat.iol.unh.edu>, | ||
198 | * Marc Meertens (mmeertens@lucent.com), | ||
199 | * Keith Moore, | ||
200 | * Robert Morris (rtm@das.harvard.edu), | ||
201 | * Ian Parkin (ian@cs.su.oz.au), | ||
202 | * John Rosenberg (johnr@cs.su.oz.au), | ||
203 | * George Rossi (george@phm.gov.au), | ||
204 | * Arthur Scott (arthur@cs.su.oz.au), | ||
205 | * Stanislav Sinyagin <stas@isf.ru> | ||
206 | * Peter Storey, | ||
207 | * Jean Tourrilhes <jt@hpl.hp.com>, | ||
208 | * Girish Welling (welling@paul.rutgers.edu) | ||
209 | * Clark Woodworth <clark@hiway1.exit109.com> | ||
210 | * Yongguang Zhang <ygz@isl.hrl.hac.com>... | ||
211 | */ | ||
212 | |||
213 | /* ------------------------- IMPROVEMENTS ------------------------- */ | ||
214 | /* | ||
215 | * I proudly present : | ||
216 | * | ||
217 | * Changes made in 2.8.22 : | ||
218 | * ---------------------- | ||
219 | * - improved wv_set_multicast_list | ||
220 | * - catch spurious interrupt | ||
221 | * - correct release of the device | ||
222 | * | ||
223 | * Changes mades in release : | ||
224 | * ------------------------ | ||
225 | * - Reorganisation of the code, function name change | ||
226 | * - Creation of private header (wavelan_cs.h) | ||
227 | * - Reorganised debug messages | ||
228 | * - More comments, history, ... | ||
229 | * - Configure earlier (in "insert" instead of "open") | ||
230 | * and do things only once | ||
231 | * - mmc_init : configure the PSA if not done | ||
232 | * - mmc_init : 2.00 detection better code for 2.00 init | ||
233 | * - better info at startup | ||
234 | * - Correct a HUGE bug (volatile & uncalibrated busy loop) | ||
235 | * in wv_82593_cmd => config speedup | ||
236 | * - Stop receiving & power down on close (and power up on open) | ||
237 | * use "ifconfig down" & "ifconfig up ; route add -net ..." | ||
238 | * - Send packets : add watchdog instead of pooling | ||
239 | * - Receive : check frame wrap around & try to recover some frames | ||
240 | * - wavelan_set_multicast_list : avoid reset | ||
241 | * - add wireless extensions (ioctl & get_wireless_stats) | ||
242 | * get/set nwid/frequency on fly, info for /proc/net/wireless | ||
243 | * - Suppress useless stuff from lp (net_local), but add link | ||
244 | * - More inlines | ||
245 | * - Lot of others minor details & cleanups | ||
246 | * | ||
247 | * Changes made in second release : | ||
248 | * ------------------------------ | ||
249 | * - Optimise wv_85893_reconfig stuff, fix potential problems | ||
250 | * - Change error values for ioctl | ||
251 | * - Non blocking wv_ru_stop() + call wv_reset() in case of problems | ||
252 | * - Remove development printk from wavelan_watchdog() | ||
253 | * - Remove of the watchdog to wavelan_close instead of wavelan_release | ||
254 | * fix potential problems... | ||
255 | * - Start debugging suspend stuff (but it's still a bit weird) | ||
256 | * - Debug & optimize dump header/packet in Rx & Tx (debug) | ||
257 | * - Use "readb" and "writeb" to be kernel 2.1 compliant | ||
258 | * - Better handling of bogus interrupts | ||
259 | * - Wireless extension : SETSPY and GETSPY | ||
260 | * - Remove old stuff (stats - for those needing it, just ask me...) | ||
261 | * - Make wireless extensions optional | ||
262 | * | ||
263 | * Changes made in third release : | ||
264 | * ----------------------------- | ||
265 | * - cleanups & typos | ||
266 | * - modif wireless ext (spy -> only one pointer) | ||
267 | * - new private ioctl to set/get quality & level threshold | ||
268 | * - Init : correct default value of level threshold for pcmcia | ||
269 | * - kill watchdog in hw_reset | ||
270 | * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) | ||
271 | * - Add message level (debug stuff in /var/adm/debug & errors not | ||
272 | * displayed at console and still in /var/adm/messages) | ||
273 | * | ||
274 | * Changes made in fourth release : | ||
275 | * ------------------------------ | ||
276 | * - multicast support (yes !) thanks to Yongguang Zhang. | ||
277 | * | ||
278 | * Changes made in fifth release (2.9.0) : | ||
279 | * ------------------------------------- | ||
280 | * - Revisited multicast code (it was mostly wrong). | ||
281 | * - protect code in wv_82593_reconfig with dev->tbusy (oups !) | ||
282 | * | ||
283 | * Changes made in sixth release (2.9.1a) : | ||
284 | * -------------------------------------- | ||
285 | * - Change the detection code for multi manufacturer code support | ||
286 | * - Correct bug (hang kernel) in init when we were "rejecting" a card | ||
287 | * | ||
288 | * Changes made in seventh release (2.9.1b) : | ||
289 | * ---------------------------------------- | ||
290 | * - Update to wireless extensions changes | ||
291 | * - Silly bug in card initial configuration (psa_conf_status) | ||
292 | * | ||
293 | * Changes made in eigth release : | ||
294 | * ----------------------------- | ||
295 | * - Small bug in debug code (probably not the last one...) | ||
296 | * - 1.2.13 support (thanks to Clark Woodworth) | ||
297 | * | ||
298 | * Changes made for release in 2.9.2b : | ||
299 | * ---------------------------------- | ||
300 | * - Level threshold is now a standard wireless extension (version 4 !) | ||
301 | * - modules parameters types for kernel > 2.1.17 | ||
302 | * - updated man page | ||
303 | * - Others cleanup from David Hinds | ||
304 | * | ||
305 | * Changes made for release in 2.9.5 : | ||
306 | * --------------------------------- | ||
307 | * - byte count stats (courtesy of David Hinds) | ||
308 | * - Remove dev_tint stuff (courtesy of David Hinds) | ||
309 | * - Others cleanup from David Hinds | ||
310 | * - Encryption setting from Brent Elphick (thanks a lot !) | ||
311 | * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) | ||
312 | * | ||
313 | * Changes made for release in 2.9.6 : | ||
314 | * --------------------------------- | ||
315 | * - fix bug : no longuer disable watchdog in case of bogus interrupt | ||
316 | * - increase timeout in config code for picky hardware | ||
317 | * - mask unused bits in status (Wireless Extensions) | ||
318 | * | ||
319 | * Changes integrated by Justin Seger <jseger@MIT.EDU> & David Hinds : | ||
320 | * ----------------------------------------------------------------- | ||
321 | * - Roaming "hack" from Joe Finney <joe@comp.lancs.ac.uk> | ||
322 | * - PSA CRC code from Bob Gray <rgray@bald.cs.dartmouth.edu> | ||
323 | * - Better initialisation of the i82593 controller | ||
324 | * from Joseph K. O'Sullivan <josullvn+@cs.cmu.edu> | ||
325 | * | ||
326 | * Changes made for release in 3.0.10 : | ||
327 | * ---------------------------------- | ||
328 | * - Fix eject "hang" of the driver under 2.2.X : | ||
329 | * o create wv_flush_stale_links() | ||
330 | * o Rename wavelan_release to wv_pcmcia_release & move up | ||
331 | * o move unregister_netdev to wavelan_detach() | ||
332 | * o wavelan_release() no longer call wavelan_detach() | ||
333 | * o Suppress "release" timer | ||
334 | * o Other cleanups & fixes | ||
335 | * - New MAC address in the probe | ||
336 | * - Reorg PSA_CRC code (endian neutral & cleaner) | ||
337 | * - Correct initialisation of the i82593 from Lucent manual | ||
338 | * - Put back the watchdog, with larger timeout | ||
339 | * - TRANSMIT_NO_CRC is a "normal" error, so recover from it | ||
340 | * from Derrick J Brashear <shadow@dementia.org> | ||
341 | * - Better handling of TX and RX normal failure conditions | ||
342 | * - #ifdef out all the roaming code | ||
343 | * - Add ESSID & "AP current address" ioctl stubs | ||
344 | * - General cleanup of the code | ||
345 | * | ||
346 | * Changes made for release in 3.0.13 : | ||
347 | * ---------------------------------- | ||
348 | * - Re-enable compilation of roaming code by default, but with | ||
349 | * do_roaming = 0 | ||
350 | * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather | ||
351 | * at the demand of John Carol Langford <jcl@gs176.sp.cs.cmu.edu> | ||
352 | * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. | ||
353 | * | ||
354 | * Changes made for release in 3.0.15 : | ||
355 | * ---------------------------------- | ||
356 | * - Change e-mail and web page addresses | ||
357 | * - Watchdog timer is now correctly expressed in HZ, not in jiffies | ||
358 | * - Add channel number to the list of frequencies in range | ||
359 | * - Add the (short) list of bit-rates in range | ||
360 | * - Developp a new sensitivity... (sens.value & sens.fixed) | ||
361 | * | ||
362 | * Changes made for release in 3.1.2 : | ||
363 | * --------------------------------- | ||
364 | * - Fix check for root permission (break instead of exit) | ||
365 | * - New nwid & encoding setting (Wireless Extension 9) | ||
366 | * | ||
367 | * Changes made for release in 3.1.12 : | ||
368 | * ---------------------------------- | ||
369 | * - reworked wv_82593_cmd to avoid using the IRQ handler and doing | ||
370 | * ugly things with interrupts. | ||
371 | * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog | ||
372 | * - Update to new network API (softnet - 2.3.43) : | ||
373 | * o replace dev->tbusy (David + me) | ||
374 | * o replace dev->tstart (David + me) | ||
375 | * o remove dev->interrupt (David) | ||
376 | * o add SMP locking via spinlock in splxx (me) | ||
377 | * o add spinlock in interrupt handler (me) | ||
378 | * o use kernel watchdog instead of ours (me) | ||
379 | * o verify that all the changes make sense and work (me) | ||
380 | * - Re-sync kernel/pcmcia versions (not much actually) | ||
381 | * - A few other cleanups (David & me)... | ||
382 | * | ||
383 | * Changes made for release in 3.1.22 : | ||
384 | * ---------------------------------- | ||
385 | * - Check that SMP works, remove annoying log message | ||
386 | * | ||
387 | * Changes made for release in 3.1.24 : | ||
388 | * ---------------------------------- | ||
389 | * - Fix unfrequent card lockup when watchdog was reseting the hardware : | ||
390 | * o control first busy loop in wv_82593_cmd() | ||
391 | * o Extend spinlock protection in wv_hw_config() | ||
392 | * | ||
393 | * Changes made for release in 3.1.33 : | ||
394 | * ---------------------------------- | ||
395 | * - Optional use new driver API for Wireless Extensions : | ||
396 | * o got rid of wavelan_ioctl() | ||
397 | * o use a bunch of iw_handler instead | ||
398 | * | ||
399 | * Changes made for release in 3.2.1 : | ||
400 | * --------------------------------- | ||
401 | * - Set dev->trans_start to avoid filling the logs | ||
402 | * (and generating useless abort commands) | ||
403 | * - Avoid deadlocks in mmc_out()/mmc_in() | ||
404 | * | ||
405 | * Wishes & dreams: | ||
406 | * ---------------- | ||
407 | * - Cleanup and integrate the roaming code | ||
408 | * (std debug, set DomainID, decay avg and co...) | ||
409 | */ | ||
410 | |||
411 | /***************************** INCLUDES *****************************/ | ||
412 | |||
413 | /* Linux headers that we need */ | ||
414 | #include <linux/module.h> | ||
415 | #include <linux/kernel.h> | ||
416 | #include <linux/init.h> | ||
417 | #include <linux/sched.h> | ||
418 | #include <linux/ptrace.h> | ||
419 | #include <linux/slab.h> | ||
420 | #include <linux/string.h> | ||
421 | #include <linux/timer.h> | ||
422 | #include <linux/interrupt.h> | ||
423 | #include <linux/spinlock.h> | ||
424 | #include <linux/in.h> | ||
425 | #include <linux/delay.h> | ||
426 | #include <linux/bitops.h> | ||
427 | #include <asm/uaccess.h> | ||
428 | #include <asm/io.h> | ||
429 | #include <asm/system.h> | ||
430 | |||
431 | #include <linux/netdevice.h> | ||
432 | #include <linux/etherdevice.h> | ||
433 | #include <linux/skbuff.h> | ||
434 | #include <linux/if_arp.h> | ||
435 | #include <linux/ioport.h> | ||
436 | #include <linux/fcntl.h> | ||
437 | #include <linux/ethtool.h> | ||
438 | #include <linux/wireless.h> /* Wireless extensions */ | ||
439 | #include <net/iw_handler.h> /* New driver API */ | ||
440 | |||
441 | /* Pcmcia headers that we need */ | ||
442 | #include <pcmcia/cs_types.h> | ||
443 | #include <pcmcia/cs.h> | ||
444 | #include <pcmcia/cistpl.h> | ||
445 | #include <pcmcia/cisreg.h> | ||
446 | #include <pcmcia/ds.h> | ||
447 | |||
448 | /* Wavelan declarations */ | ||
449 | #include "i82593.h" /* Definitions for the Intel chip */ | ||
450 | |||
451 | #include "wavelan_cs.h" /* Others bits of the hardware */ | ||
452 | |||
453 | /************************** DRIVER OPTIONS **************************/ | ||
454 | /* | ||
455 | * `#define' or `#undef' the following constant to change the behaviour | ||
456 | * of the driver... | ||
457 | */ | ||
458 | #define WAVELAN_ROAMING /* Include experimental roaming code */ | ||
459 | #undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ | ||
460 | #undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ | ||
461 | #define USE_PSA_CONFIG /* Use info from the PSA */ | ||
462 | #undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ | ||
463 | #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ | ||
464 | #undef SET_MAC_ADDRESS /* Experimental */ | ||
465 | |||
466 | /* Warning : these stuff will slow down the driver... */ | ||
467 | #define WIRELESS_SPY /* Enable spying addresses */ | ||
468 | #undef HISTOGRAM /* Enable histogram of sig level... */ | ||
469 | |||
470 | /****************************** DEBUG ******************************/ | ||
471 | |||
472 | #undef DEBUG_MODULE_TRACE /* Module insertion/removal */ | ||
473 | #undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ | ||
474 | #undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ | ||
475 | #undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ | ||
476 | #define DEBUG_INTERRUPT_ERROR /* problems */ | ||
477 | #undef DEBUG_CONFIG_TRACE /* Trace the config functions */ | ||
478 | #undef DEBUG_CONFIG_INFO /* What's going on... */ | ||
479 | #define DEBUG_CONFIG_ERRORS /* Errors on configuration */ | ||
480 | #undef DEBUG_TX_TRACE /* Transmission calls */ | ||
481 | #undef DEBUG_TX_INFO /* Header of the transmitted packet */ | ||
482 | #undef DEBUG_TX_FAIL /* Normal failure conditions */ | ||
483 | #define DEBUG_TX_ERROR /* Unexpected conditions */ | ||
484 | #undef DEBUG_RX_TRACE /* Transmission calls */ | ||
485 | #undef DEBUG_RX_INFO /* Header of the transmitted packet */ | ||
486 | #undef DEBUG_RX_FAIL /* Normal failure conditions */ | ||
487 | #define DEBUG_RX_ERROR /* Unexpected conditions */ | ||
488 | #undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ | ||
489 | #undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ | ||
490 | #undef DEBUG_IOCTL_INFO /* Various debug info */ | ||
491 | #define DEBUG_IOCTL_ERROR /* What's going wrong */ | ||
492 | #define DEBUG_BASIC_SHOW /* Show basic startup info */ | ||
493 | #undef DEBUG_VERSION_SHOW /* Print version info */ | ||
494 | #undef DEBUG_PSA_SHOW /* Dump psa to screen */ | ||
495 | #undef DEBUG_MMC_SHOW /* Dump mmc to screen */ | ||
496 | #undef DEBUG_SHOW_UNUSED /* Show also unused fields */ | ||
497 | #undef DEBUG_I82593_SHOW /* Show i82593 status */ | ||
498 | #undef DEBUG_DEVICE_SHOW /* Show device parameters */ | ||
499 | |||
500 | /************************ CONSTANTS & MACROS ************************/ | ||
501 | |||
502 | #ifdef DEBUG_VERSION_SHOW | ||
503 | static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n"; | ||
504 | #endif | ||
505 | |||
506 | /* Watchdog temporisation */ | ||
507 | #define WATCHDOG_JIFFIES (256*HZ/100) | ||
508 | |||
509 | /* Fix a bug in some old wireless extension definitions */ | ||
510 | #ifndef IW_ESSID_MAX_SIZE | ||
511 | #define IW_ESSID_MAX_SIZE 32 | ||
512 | #endif | ||
513 | |||
514 | /* ------------------------ PRIVATE IOCTL ------------------------ */ | ||
515 | |||
516 | #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ | ||
517 | #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ | ||
518 | #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ | ||
519 | #define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ | ||
520 | |||
521 | #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */ | ||
522 | #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */ | ||
523 | |||
524 | /*************************** WaveLAN Roaming **************************/ | ||
525 | #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ | ||
526 | |||
527 | #define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ | ||
528 | /* 2 = Info on each beacon rcvd... */ | ||
529 | #define MAX_WAVEPOINTS 7 /* Max visible at one time */ | ||
530 | #define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ | ||
531 | #define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ | ||
532 | #define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ | ||
533 | #define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ | ||
534 | #define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ | ||
535 | #define CELL_TIMEOUT 2*HZ /* in jiffies */ | ||
536 | |||
537 | #define FAST_CELL_SEARCH 1 /* Boolean values... */ | ||
538 | #define NWID_PROMISC 1 /* for code clarity. */ | ||
539 | |||
540 | typedef struct wavepoint_beacon | ||
541 | { | ||
542 | unsigned char dsap, /* Unused */ | ||
543 | ssap, /* Unused */ | ||
544 | ctrl, /* Unused */ | ||
545 | O,U,I, /* Unused */ | ||
546 | spec_id1, /* Unused */ | ||
547 | spec_id2, /* Unused */ | ||
548 | pdu_type, /* Unused */ | ||
549 | seq; /* WavePoint beacon sequence number */ | ||
550 | __be16 domain_id, /* WavePoint Domain ID */ | ||
551 | nwid; /* WavePoint NWID */ | ||
552 | } wavepoint_beacon; | ||
553 | |||
554 | typedef struct wavepoint_history | ||
555 | { | ||
556 | unsigned short nwid; /* WavePoint's NWID */ | ||
557 | int average_slow; /* SNR running average */ | ||
558 | int average_fast; /* SNR running average */ | ||
559 | unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ | ||
560 | unsigned char qualptr; /* Index into ringbuffer */ | ||
561 | unsigned char last_seq; /* Last seq. no seen for WavePoint */ | ||
562 | struct wavepoint_history *next; /* Next WavePoint in table */ | ||
563 | struct wavepoint_history *prev; /* Previous WavePoint in table */ | ||
564 | unsigned long last_seen; /* Time of last beacon recvd, jiffies */ | ||
565 | } wavepoint_history; | ||
566 | |||
567 | struct wavepoint_table | ||
568 | { | ||
569 | wavepoint_history *head; /* Start of ringbuffer */ | ||
570 | int num_wavepoints; /* No. of WavePoints visible */ | ||
571 | unsigned char locked; /* Table lock */ | ||
572 | }; | ||
573 | |||
574 | #endif /* WAVELAN_ROAMING */ | ||
575 | |||
576 | /****************************** TYPES ******************************/ | ||
577 | |||
578 | /* Shortcuts */ | ||
579 | typedef struct iw_statistics iw_stats; | ||
580 | typedef struct iw_quality iw_qual; | ||
581 | typedef struct iw_freq iw_freq; | ||
582 | typedef struct net_local net_local; | ||
583 | typedef struct timer_list timer_list; | ||
584 | |||
585 | /* Basic types */ | ||
586 | typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ | ||
587 | |||
588 | /* | ||
589 | * Static specific data for the interface. | ||
590 | * | ||
591 | * For each network interface, Linux keep data in two structure. "device" | ||
592 | * keep the generic data (same format for everybody) and "net_local" keep | ||
593 | * the additional specific data. | ||
594 | */ | ||
595 | struct net_local | ||
596 | { | ||
597 | dev_node_t node; /* ???? What is this stuff ???? */ | ||
598 | struct net_device * dev; /* Reverse link... */ | ||
599 | spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ | ||
600 | struct pcmcia_device * link; /* pcmcia structure */ | ||
601 | int nresets; /* Number of hw resets */ | ||
602 | u_char configured; /* If it is configured */ | ||
603 | u_char reconfig_82593; /* Need to reconfigure the controller */ | ||
604 | u_char promiscuous; /* Promiscuous mode */ | ||
605 | u_char allmulticast; /* All Multicast mode */ | ||
606 | int mc_count; /* Number of multicast addresses */ | ||
607 | |||
608 | int stop; /* Current i82593 Stop Hit Register */ | ||
609 | int rfp; /* Last DMA machine receive pointer */ | ||
610 | int overrunning; /* Receiver overrun flag */ | ||
611 | |||
612 | iw_stats wstats; /* Wireless specific stats */ | ||
613 | |||
614 | struct iw_spy_data spy_data; | ||
615 | struct iw_public_data wireless_data; | ||
616 | |||
617 | #ifdef HISTOGRAM | ||
618 | int his_number; /* Number of intervals */ | ||
619 | u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ | ||
620 | u_long his_sum[16]; /* Sum in interval */ | ||
621 | #endif /* HISTOGRAM */ | ||
622 | #ifdef WAVELAN_ROAMING | ||
623 | u_long domain_id; /* Domain ID we lock on for roaming */ | ||
624 | int filter_domains; /* Check Domain ID of beacon found */ | ||
625 | struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ | ||
626 | wavepoint_history * curr_point; /* Current wavepoint */ | ||
627 | int cell_search; /* Searching for new cell? */ | ||
628 | struct timer_list cell_timer; /* Garbage collection */ | ||
629 | #endif /* WAVELAN_ROAMING */ | ||
630 | void __iomem *mem; | ||
631 | }; | ||
632 | |||
633 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | ||
634 | static inline u_char /* data */ | ||
635 | hasr_read(u_long); /* Read the host interface : base address */ | ||
636 | static void | ||
637 | hacr_write(u_long, /* Write to host interface : base address */ | ||
638 | u_char), /* data */ | ||
639 | hacr_write_slow(u_long, | ||
640 | u_char); | ||
641 | static void | ||
642 | psa_read(struct net_device *, /* Read the Parameter Storage Area */ | ||
643 | int, /* offset in PSA */ | ||
644 | u_char *, /* buffer to fill */ | ||
645 | int), /* size to read */ | ||
646 | psa_write(struct net_device *, /* Write to the PSA */ | ||
647 | int, /* Offset in psa */ | ||
648 | u_char *, /* Buffer in memory */ | ||
649 | int); /* Length of buffer */ | ||
650 | static void | ||
651 | mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ | ||
652 | u_short, | ||
653 | u_char), | ||
654 | mmc_write(u_long, /* Write n bytes to the MMC */ | ||
655 | u_char, | ||
656 | u_char *, | ||
657 | int); | ||
658 | static u_char /* Read 1 byte from the MMC */ | ||
659 | mmc_in(u_long, | ||
660 | u_short); | ||
661 | static void | ||
662 | mmc_read(u_long, /* Read n bytes from the MMC */ | ||
663 | u_char, | ||
664 | u_char *, | ||
665 | int), | ||
666 | fee_wait(u_long, /* Wait for frequency EEprom : base address */ | ||
667 | int, /* Base delay to wait for */ | ||
668 | int); /* Number of time to wait */ | ||
669 | static void | ||
670 | fee_read(u_long, /* Read the frequency EEprom : base address */ | ||
671 | u_short, /* destination offset */ | ||
672 | u_short *, /* data buffer */ | ||
673 | int); /* number of registers */ | ||
674 | /* ---------------------- I82593 SUBROUTINES ----------------------- */ | ||
675 | static int | ||
676 | wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ | ||
677 | char *, | ||
678 | int, | ||
679 | int); | ||
680 | static inline int | ||
681 | wv_diag(struct net_device *); /* Diagnostique the i82593 */ | ||
682 | static int | ||
683 | read_ringbuf(struct net_device *, /* Read a receive buffer */ | ||
684 | int, | ||
685 | char *, | ||
686 | int); | ||
687 | static void | ||
688 | wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ | ||
689 | /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ | ||
690 | static void | ||
691 | wv_init_info(struct net_device *); /* display startup info */ | ||
692 | /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ | ||
693 | static iw_stats * | ||
694 | wavelan_get_wireless_stats(struct net_device *); | ||
695 | /* ----------------------- PACKET RECEPTION ----------------------- */ | ||
696 | static int | ||
697 | wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ | ||
698 | int, /* end of frame */ | ||
699 | int); /* start of buffer */ | ||
700 | static void | ||
701 | wv_packet_read(struct net_device *, /* Read a packet from a frame */ | ||
702 | int, | ||
703 | int), | ||
704 | wv_packet_rcv(struct net_device *); /* Read all packets waiting */ | ||
705 | /* --------------------- PACKET TRANSMISSION --------------------- */ | ||
706 | static void | ||
707 | wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ | ||
708 | void *, | ||
709 | short); | ||
710 | static netdev_tx_t | ||
711 | wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ | ||
712 | struct net_device *); | ||
713 | /* -------------------- HARDWARE CONFIGURATION -------------------- */ | ||
714 | static int | ||
715 | wv_mmc_init(struct net_device *); /* Initialize the modem */ | ||
716 | static int | ||
717 | wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ | ||
718 | wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ | ||
719 | static int | ||
720 | wv_82593_config(struct net_device *); /* Configure the i82593 */ | ||
721 | static int | ||
722 | wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ | ||
723 | static int | ||
724 | wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ | ||
725 | static void | ||
726 | wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ | ||
727 | static int | ||
728 | wv_pcmcia_config(struct pcmcia_device *); /* Configure the pcmcia interface */ | ||
729 | static void | ||
730 | wv_pcmcia_release(struct pcmcia_device *);/* Remove a device */ | ||
731 | /* ---------------------- INTERRUPT HANDLING ---------------------- */ | ||
732 | static irqreturn_t | ||
733 | wavelan_interrupt(int, /* Interrupt handler */ | ||
734 | void *); | ||
735 | static void | ||
736 | wavelan_watchdog(struct net_device *); /* Transmission watchdog */ | ||
737 | /* ------------------- CONFIGURATION CALLBACKS ------------------- */ | ||
738 | static int | ||
739 | wavelan_open(struct net_device *), /* Open the device */ | ||
740 | wavelan_close(struct net_device *); /* Close the device */ | ||
741 | static void | ||
742 | wavelan_detach(struct pcmcia_device *p_dev); /* Destroy a removed device */ | ||
743 | |||
744 | /**************************** VARIABLES ****************************/ | ||
745 | |||
746 | /* | ||
747 | * Parameters that can be set with 'insmod' | ||
748 | * The exact syntax is 'insmod wavelan_cs.o <var>=<value>' | ||
749 | */ | ||
750 | |||
751 | /* Shared memory speed, in ns */ | ||
752 | static int mem_speed = 0; | ||
753 | |||
754 | /* New module interface */ | ||
755 | module_param(mem_speed, int, 0); | ||
756 | |||
757 | #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ | ||
758 | /* Enable roaming mode ? No ! Please keep this to 0 */ | ||
759 | static int do_roaming = 0; | ||
760 | module_param(do_roaming, bool, 0); | ||
761 | #endif /* WAVELAN_ROAMING */ | ||
762 | |||
763 | MODULE_LICENSE("GPL"); | ||
764 | |||
765 | #endif /* WAVELAN_CS_P_H */ | ||
766 | |||