1 |
62 |
marcus.erl |
/*** -*- linux-c -*- **********************************************************
|
2 |
|
|
|
3 |
|
|
Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
|
4 |
|
|
|
5 |
|
|
Copyright 2000-2001 ATMEL Corporation.
|
6 |
|
|
Copyright 2003-2004 Simon Kelley.
|
7 |
|
|
|
8 |
|
|
This code was developed from version 2.1.1 of the Atmel drivers,
|
9 |
|
|
released by Atmel corp. under the GPL in December 2002. It also
|
10 |
|
|
includes code from the Linux aironet drivers (C) Benjamin Reed,
|
11 |
|
|
and the Linux PCMCIA package, (C) David Hinds and the Linux wireless
|
12 |
|
|
extensions, (C) Jean Tourrilhes.
|
13 |
|
|
|
14 |
|
|
The firmware module for reading the MAC address of the card comes from
|
15 |
|
|
net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright
|
16 |
|
|
by him. net.russotto.AtmelMACFW is used under the GPL license version 2.
|
17 |
|
|
This file contains the module in binary form and, under the terms
|
18 |
|
|
of the GPL, in source form. The source is located at the end of the file.
|
19 |
|
|
|
20 |
|
|
This program is free software; you can redistribute it and/or modify
|
21 |
|
|
it under the terms of the GNU General Public License as published by
|
22 |
|
|
the Free Software Foundation; either version 2 of the License, or
|
23 |
|
|
(at your option) any later version.
|
24 |
|
|
|
25 |
|
|
This software is distributed in the hope that it will be useful,
|
26 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
27 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
28 |
|
|
GNU General Public License for more details.
|
29 |
|
|
|
30 |
|
|
You should have received a copy of the GNU General Public License
|
31 |
|
|
along with Atmel wireless lan drivers; if not, write to the Free Software
|
32 |
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
33 |
|
|
|
34 |
|
|
For all queries about this code, please contact the current author,
|
35 |
|
|
Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
|
36 |
|
|
|
37 |
|
|
Credit is due to HP UK and Cambridge Online Systems Ltd for supplying
|
38 |
|
|
hardware used during development of this driver.
|
39 |
|
|
|
40 |
|
|
******************************************************************************/
|
41 |
|
|
|
42 |
|
|
#include <linux/init.h>
|
43 |
|
|
|
44 |
|
|
#include <linux/kernel.h>
|
45 |
|
|
#include <linux/ptrace.h>
|
46 |
|
|
#include <linux/slab.h>
|
47 |
|
|
#include <linux/string.h>
|
48 |
|
|
#include <linux/ctype.h>
|
49 |
|
|
#include <linux/timer.h>
|
50 |
|
|
#include <asm/io.h>
|
51 |
|
|
#include <asm/system.h>
|
52 |
|
|
#include <asm/uaccess.h>
|
53 |
|
|
#include <linux/module.h>
|
54 |
|
|
#include <linux/netdevice.h>
|
55 |
|
|
#include <linux/etherdevice.h>
|
56 |
|
|
#include <linux/skbuff.h>
|
57 |
|
|
#include <linux/if_arp.h>
|
58 |
|
|
#include <linux/ioport.h>
|
59 |
|
|
#include <linux/fcntl.h>
|
60 |
|
|
#include <linux/delay.h>
|
61 |
|
|
#include <linux/wireless.h>
|
62 |
|
|
#include <net/iw_handler.h>
|
63 |
|
|
#include <linux/byteorder/generic.h>
|
64 |
|
|
#include <linux/crc32.h>
|
65 |
|
|
#include <linux/proc_fs.h>
|
66 |
|
|
#include <linux/device.h>
|
67 |
|
|
#include <linux/moduleparam.h>
|
68 |
|
|
#include <linux/firmware.h>
|
69 |
|
|
#include <net/ieee80211.h>
|
70 |
|
|
#include "atmel.h"
|
71 |
|
|
|
72 |
|
|
#define DRIVER_MAJOR 0
|
73 |
|
|
#define DRIVER_MINOR 98
|
74 |
|
|
|
75 |
|
|
MODULE_AUTHOR("Simon Kelley");
|
76 |
|
|
MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
|
77 |
|
|
MODULE_LICENSE("GPL");
|
78 |
|
|
MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards");
|
79 |
|
|
|
80 |
|
|
/* The name of the firmware file to be loaded
|
81 |
|
|
over-rides any automatic selection */
|
82 |
|
|
static char *firmware = NULL;
|
83 |
|
|
module_param(firmware, charp, 0);
|
84 |
|
|
|
85 |
|
|
/* table of firmware file names */
|
86 |
|
|
static struct {
|
87 |
|
|
AtmelFWType fw_type;
|
88 |
|
|
const char *fw_file;
|
89 |
|
|
const char *fw_file_ext;
|
90 |
|
|
} fw_table[] = {
|
91 |
|
|
{ ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" },
|
92 |
|
|
{ ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" },
|
93 |
|
|
{ ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" },
|
94 |
|
|
{ ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" },
|
95 |
|
|
{ ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" },
|
96 |
|
|
{ ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" },
|
97 |
|
|
{ ATMEL_FW_TYPE_504A_2958,"atmel_at76c504a_2958","bin" },
|
98 |
|
|
{ ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" },
|
99 |
|
|
{ ATMEL_FW_TYPE_NONE, NULL, NULL }
|
100 |
|
|
};
|
101 |
|
|
|
102 |
|
|
#define MAX_SSID_LENGTH 32
|
103 |
|
|
#define MGMT_JIFFIES (256 * HZ / 100)
|
104 |
|
|
|
105 |
|
|
#define MAX_BSS_ENTRIES 64
|
106 |
|
|
|
107 |
|
|
/* registers */
|
108 |
|
|
#define GCR 0x00 // (SIR0) General Configuration Register
|
109 |
|
|
#define BSR 0x02 // (SIR1) Bank Switching Select Register
|
110 |
|
|
#define AR 0x04
|
111 |
|
|
#define DR 0x08
|
112 |
|
|
#define MR1 0x12 // Mirror Register 1
|
113 |
|
|
#define MR2 0x14 // Mirror Register 2
|
114 |
|
|
#define MR3 0x16 // Mirror Register 3
|
115 |
|
|
#define MR4 0x18 // Mirror Register 4
|
116 |
|
|
|
117 |
|
|
#define GPR1 0x0c
|
118 |
|
|
#define GPR2 0x0e
|
119 |
|
|
#define GPR3 0x10
|
120 |
|
|
//
|
121 |
|
|
// Constants for the GCR register.
|
122 |
|
|
//
|
123 |
|
|
#define GCR_REMAP 0x0400 // Remap internal SRAM to 0
|
124 |
|
|
#define GCR_SWRES 0x0080 // BIU reset (ARM and PAI are NOT reset)
|
125 |
|
|
#define GCR_CORES 0x0060 // Core Reset (ARM and PAI are reset)
|
126 |
|
|
#define GCR_ENINT 0x0002 // Enable Interrupts
|
127 |
|
|
#define GCR_ACKINT 0x0008 // Acknowledge Interrupts
|
128 |
|
|
|
129 |
|
|
#define BSS_SRAM 0x0200 // AMBA module selection --> SRAM
|
130 |
|
|
#define BSS_IRAM 0x0100 // AMBA module selection --> IRAM
|
131 |
|
|
//
|
132 |
|
|
// Constants for the MR registers.
|
133 |
|
|
//
|
134 |
|
|
#define MAC_INIT_COMPLETE 0x0001 // MAC init has been completed
|
135 |
|
|
#define MAC_BOOT_COMPLETE 0x0010 // MAC boot has been completed
|
136 |
|
|
#define MAC_INIT_OK 0x0002 // MAC boot has been completed
|
137 |
|
|
|
138 |
|
|
#define MIB_MAX_DATA_BYTES 212
|
139 |
|
|
#define MIB_HEADER_SIZE 4 /* first four fields */
|
140 |
|
|
|
141 |
|
|
struct get_set_mib {
|
142 |
|
|
u8 type;
|
143 |
|
|
u8 size;
|
144 |
|
|
u8 index;
|
145 |
|
|
u8 reserved;
|
146 |
|
|
u8 data[MIB_MAX_DATA_BYTES];
|
147 |
|
|
};
|
148 |
|
|
|
149 |
|
|
struct rx_desc {
|
150 |
|
|
u32 Next;
|
151 |
|
|
u16 MsduPos;
|
152 |
|
|
u16 MsduSize;
|
153 |
|
|
|
154 |
|
|
u8 State;
|
155 |
|
|
u8 Status;
|
156 |
|
|
u8 Rate;
|
157 |
|
|
u8 Rssi;
|
158 |
|
|
u8 LinkQuality;
|
159 |
|
|
u8 PreambleType;
|
160 |
|
|
u16 Duration;
|
161 |
|
|
u32 RxTime;
|
162 |
|
|
};
|
163 |
|
|
|
164 |
|
|
#define RX_DESC_FLAG_VALID 0x80
|
165 |
|
|
#define RX_DESC_FLAG_CONSUMED 0x40
|
166 |
|
|
#define RX_DESC_FLAG_IDLE 0x00
|
167 |
|
|
|
168 |
|
|
#define RX_STATUS_SUCCESS 0x00
|
169 |
|
|
|
170 |
|
|
#define RX_DESC_MSDU_POS_OFFSET 4
|
171 |
|
|
#define RX_DESC_MSDU_SIZE_OFFSET 6
|
172 |
|
|
#define RX_DESC_FLAGS_OFFSET 8
|
173 |
|
|
#define RX_DESC_STATUS_OFFSET 9
|
174 |
|
|
#define RX_DESC_RSSI_OFFSET 11
|
175 |
|
|
#define RX_DESC_LINK_QUALITY_OFFSET 12
|
176 |
|
|
#define RX_DESC_PREAMBLE_TYPE_OFFSET 13
|
177 |
|
|
#define RX_DESC_DURATION_OFFSET 14
|
178 |
|
|
#define RX_DESC_RX_TIME_OFFSET 16
|
179 |
|
|
|
180 |
|
|
struct tx_desc {
|
181 |
|
|
u32 NextDescriptor;
|
182 |
|
|
u16 TxStartOfFrame;
|
183 |
|
|
u16 TxLength;
|
184 |
|
|
|
185 |
|
|
u8 TxState;
|
186 |
|
|
u8 TxStatus;
|
187 |
|
|
u8 RetryCount;
|
188 |
|
|
|
189 |
|
|
u8 TxRate;
|
190 |
|
|
|
191 |
|
|
u8 KeyIndex;
|
192 |
|
|
u8 ChiperType;
|
193 |
|
|
u8 ChipreLength;
|
194 |
|
|
u8 Reserved1;
|
195 |
|
|
|
196 |
|
|
u8 Reserved;
|
197 |
|
|
u8 PacketType;
|
198 |
|
|
u16 HostTxLength;
|
199 |
|
|
};
|
200 |
|
|
|
201 |
|
|
#define TX_DESC_NEXT_OFFSET 0
|
202 |
|
|
#define TX_DESC_POS_OFFSET 4
|
203 |
|
|
#define TX_DESC_SIZE_OFFSET 6
|
204 |
|
|
#define TX_DESC_FLAGS_OFFSET 8
|
205 |
|
|
#define TX_DESC_STATUS_OFFSET 9
|
206 |
|
|
#define TX_DESC_RETRY_OFFSET 10
|
207 |
|
|
#define TX_DESC_RATE_OFFSET 11
|
208 |
|
|
#define TX_DESC_KEY_INDEX_OFFSET 12
|
209 |
|
|
#define TX_DESC_CIPHER_TYPE_OFFSET 13
|
210 |
|
|
#define TX_DESC_CIPHER_LENGTH_OFFSET 14
|
211 |
|
|
#define TX_DESC_PACKET_TYPE_OFFSET 17
|
212 |
|
|
#define TX_DESC_HOST_LENGTH_OFFSET 18
|
213 |
|
|
|
214 |
|
|
///////////////////////////////////////////////////////
|
215 |
|
|
// Host-MAC interface
|
216 |
|
|
///////////////////////////////////////////////////////
|
217 |
|
|
|
218 |
|
|
#define TX_STATUS_SUCCESS 0x00
|
219 |
|
|
|
220 |
|
|
#define TX_FIRM_OWN 0x80
|
221 |
|
|
#define TX_DONE 0x40
|
222 |
|
|
|
223 |
|
|
#define TX_ERROR 0x01
|
224 |
|
|
|
225 |
|
|
#define TX_PACKET_TYPE_DATA 0x01
|
226 |
|
|
#define TX_PACKET_TYPE_MGMT 0x02
|
227 |
|
|
|
228 |
|
|
#define ISR_EMPTY 0x00 // no bits set in ISR
|
229 |
|
|
#define ISR_TxCOMPLETE 0x01 // packet transmitted
|
230 |
|
|
#define ISR_RxCOMPLETE 0x02 // packet received
|
231 |
|
|
#define ISR_RxFRAMELOST 0x04 // Rx Frame lost
|
232 |
|
|
#define ISR_FATAL_ERROR 0x08 // Fatal error
|
233 |
|
|
#define ISR_COMMAND_COMPLETE 0x10 // command completed
|
234 |
|
|
#define ISR_OUT_OF_RANGE 0x20 // command completed
|
235 |
|
|
#define ISR_IBSS_MERGE 0x40 // (4.1.2.30): IBSS merge
|
236 |
|
|
#define ISR_GENERIC_IRQ 0x80
|
237 |
|
|
|
238 |
|
|
#define Local_Mib_Type 0x01
|
239 |
|
|
#define Mac_Address_Mib_Type 0x02
|
240 |
|
|
#define Mac_Mib_Type 0x03
|
241 |
|
|
#define Statistics_Mib_Type 0x04
|
242 |
|
|
#define Mac_Mgmt_Mib_Type 0x05
|
243 |
|
|
#define Mac_Wep_Mib_Type 0x06
|
244 |
|
|
#define Phy_Mib_Type 0x07
|
245 |
|
|
#define Multi_Domain_MIB 0x08
|
246 |
|
|
|
247 |
|
|
#define MAC_MGMT_MIB_CUR_BSSID_POS 14
|
248 |
|
|
#define MAC_MIB_FRAG_THRESHOLD_POS 8
|
249 |
|
|
#define MAC_MIB_RTS_THRESHOLD_POS 10
|
250 |
|
|
#define MAC_MIB_SHORT_RETRY_POS 16
|
251 |
|
|
#define MAC_MIB_LONG_RETRY_POS 17
|
252 |
|
|
#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16
|
253 |
|
|
#define MAC_MGMT_MIB_BEACON_PER_POS 0
|
254 |
|
|
#define MAC_MGMT_MIB_STATION_ID_POS 6
|
255 |
|
|
#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11
|
256 |
|
|
#define MAC_MGMT_MIB_CUR_BSSID_POS 14
|
257 |
|
|
#define MAC_MGMT_MIB_PS_MODE_POS 53
|
258 |
|
|
#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54
|
259 |
|
|
#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56
|
260 |
|
|
#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57
|
261 |
|
|
#define PHY_MIB_CHANNEL_POS 14
|
262 |
|
|
#define PHY_MIB_RATE_SET_POS 20
|
263 |
|
|
#define PHY_MIB_REG_DOMAIN_POS 26
|
264 |
|
|
#define LOCAL_MIB_AUTO_TX_RATE_POS 3
|
265 |
|
|
#define LOCAL_MIB_SSID_SIZE 5
|
266 |
|
|
#define LOCAL_MIB_TX_PROMISCUOUS_POS 6
|
267 |
|
|
#define LOCAL_MIB_TX_MGMT_RATE_POS 7
|
268 |
|
|
#define LOCAL_MIB_TX_CONTROL_RATE_POS 8
|
269 |
|
|
#define LOCAL_MIB_PREAMBLE_TYPE 9
|
270 |
|
|
#define MAC_ADDR_MIB_MAC_ADDR_POS 0
|
271 |
|
|
|
272 |
|
|
#define CMD_Set_MIB_Vars 0x01
|
273 |
|
|
#define CMD_Get_MIB_Vars 0x02
|
274 |
|
|
#define CMD_Scan 0x03
|
275 |
|
|
#define CMD_Join 0x04
|
276 |
|
|
#define CMD_Start 0x05
|
277 |
|
|
#define CMD_EnableRadio 0x06
|
278 |
|
|
#define CMD_DisableRadio 0x07
|
279 |
|
|
#define CMD_SiteSurvey 0x0B
|
280 |
|
|
|
281 |
|
|
#define CMD_STATUS_IDLE 0x00
|
282 |
|
|
#define CMD_STATUS_COMPLETE 0x01
|
283 |
|
|
#define CMD_STATUS_UNKNOWN 0x02
|
284 |
|
|
#define CMD_STATUS_INVALID_PARAMETER 0x03
|
285 |
|
|
#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04
|
286 |
|
|
#define CMD_STATUS_TIME_OUT 0x07
|
287 |
|
|
#define CMD_STATUS_IN_PROGRESS 0x08
|
288 |
|
|
#define CMD_STATUS_REJECTED_RADIO_OFF 0x09
|
289 |
|
|
#define CMD_STATUS_HOST_ERROR 0xFF
|
290 |
|
|
#define CMD_STATUS_BUSY 0xFE
|
291 |
|
|
|
292 |
|
|
#define CMD_BLOCK_COMMAND_OFFSET 0
|
293 |
|
|
#define CMD_BLOCK_STATUS_OFFSET 1
|
294 |
|
|
#define CMD_BLOCK_PARAMETERS_OFFSET 4
|
295 |
|
|
|
296 |
|
|
#define SCAN_OPTIONS_SITE_SURVEY 0x80
|
297 |
|
|
|
298 |
|
|
#define MGMT_FRAME_BODY_OFFSET 24
|
299 |
|
|
#define MAX_AUTHENTICATION_RETRIES 3
|
300 |
|
|
#define MAX_ASSOCIATION_RETRIES 3
|
301 |
|
|
|
302 |
|
|
#define AUTHENTICATION_RESPONSE_TIME_OUT 1000
|
303 |
|
|
|
304 |
|
|
#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */
|
305 |
|
|
#define LOOP_RETRY_LIMIT 500000
|
306 |
|
|
|
307 |
|
|
#define ACTIVE_MODE 1
|
308 |
|
|
#define PS_MODE 2
|
309 |
|
|
|
310 |
|
|
#define MAX_ENCRYPTION_KEYS 4
|
311 |
|
|
#define MAX_ENCRYPTION_KEY_SIZE 40
|
312 |
|
|
|
313 |
|
|
///////////////////////////////////////////////////////////////////////////
|
314 |
|
|
// 802.11 related definitions
|
315 |
|
|
///////////////////////////////////////////////////////////////////////////
|
316 |
|
|
|
317 |
|
|
//
|
318 |
|
|
// Regulatory Domains
|
319 |
|
|
//
|
320 |
|
|
|
321 |
|
|
#define REG_DOMAIN_FCC 0x10 //Channels 1-11 USA
|
322 |
|
|
#define REG_DOMAIN_DOC 0x20 //Channel 1-11 Canada
|
323 |
|
|
#define REG_DOMAIN_ETSI 0x30 //Channel 1-13 Europe (ex Spain/France)
|
324 |
|
|
#define REG_DOMAIN_SPAIN 0x31 //Channel 10-11 Spain
|
325 |
|
|
#define REG_DOMAIN_FRANCE 0x32 //Channel 10-13 France
|
326 |
|
|
#define REG_DOMAIN_MKK 0x40 //Channel 14 Japan
|
327 |
|
|
#define REG_DOMAIN_MKK1 0x41 //Channel 1-14 Japan(MKK1)
|
328 |
|
|
#define REG_DOMAIN_ISRAEL 0x50 //Channel 3-9 ISRAEL
|
329 |
|
|
|
330 |
|
|
#define BSS_TYPE_AD_HOC 1
|
331 |
|
|
#define BSS_TYPE_INFRASTRUCTURE 2
|
332 |
|
|
|
333 |
|
|
#define SCAN_TYPE_ACTIVE 0
|
334 |
|
|
#define SCAN_TYPE_PASSIVE 1
|
335 |
|
|
|
336 |
|
|
#define LONG_PREAMBLE 0
|
337 |
|
|
#define SHORT_PREAMBLE 1
|
338 |
|
|
#define AUTO_PREAMBLE 2
|
339 |
|
|
|
340 |
|
|
#define DATA_FRAME_WS_HEADER_SIZE 30
|
341 |
|
|
|
342 |
|
|
/* promiscuous mode control */
|
343 |
|
|
#define PROM_MODE_OFF 0x0
|
344 |
|
|
#define PROM_MODE_UNKNOWN 0x1
|
345 |
|
|
#define PROM_MODE_CRC_FAILED 0x2
|
346 |
|
|
#define PROM_MODE_DUPLICATED 0x4
|
347 |
|
|
#define PROM_MODE_MGMT 0x8
|
348 |
|
|
#define PROM_MODE_CTRL 0x10
|
349 |
|
|
#define PROM_MODE_BAD_PROTOCOL 0x20
|
350 |
|
|
|
351 |
|
|
#define IFACE_INT_STATUS_OFFSET 0
|
352 |
|
|
#define IFACE_INT_MASK_OFFSET 1
|
353 |
|
|
#define IFACE_LOCKOUT_HOST_OFFSET 2
|
354 |
|
|
#define IFACE_LOCKOUT_MAC_OFFSET 3
|
355 |
|
|
#define IFACE_FUNC_CTRL_OFFSET 28
|
356 |
|
|
#define IFACE_MAC_STAT_OFFSET 30
|
357 |
|
|
#define IFACE_GENERIC_INT_TYPE_OFFSET 32
|
358 |
|
|
|
359 |
|
|
#define CIPHER_SUITE_NONE 0
|
360 |
|
|
#define CIPHER_SUITE_WEP_64 1
|
361 |
|
|
#define CIPHER_SUITE_TKIP 2
|
362 |
|
|
#define CIPHER_SUITE_AES 3
|
363 |
|
|
#define CIPHER_SUITE_CCX 4
|
364 |
|
|
#define CIPHER_SUITE_WEP_128 5
|
365 |
|
|
|
366 |
|
|
//
|
367 |
|
|
// IFACE MACROS & definitions
|
368 |
|
|
//
|
369 |
|
|
//
|
370 |
|
|
|
371 |
|
|
// FuncCtrl field:
|
372 |
|
|
//
|
373 |
|
|
#define FUNC_CTRL_TxENABLE 0x10
|
374 |
|
|
#define FUNC_CTRL_RxENABLE 0x20
|
375 |
|
|
#define FUNC_CTRL_INIT_COMPLETE 0x01
|
376 |
|
|
|
377 |
|
|
/* A stub firmware image which reads the MAC address from NVRAM on the card.
|
378 |
|
|
For copyright information and source see the end of this file. */
|
379 |
|
|
static u8 mac_reader[] = {
|
380 |
|
|
0x06,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea,
|
381 |
|
|
0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,
|
382 |
|
|
0xd3,0x00,0xa0,0xe3,0x00,0xf0,0x21,0xe1,0x0e,0x04,0xa0,0xe3,0x00,0x10,0xa0,0xe3,
|
383 |
|
|
0x81,0x11,0xa0,0xe1,0x00,0x10,0x81,0xe3,0x00,0x10,0x80,0xe5,0x1c,0x10,0x90,0xe5,
|
384 |
|
|
0x10,0x10,0xc1,0xe3,0x1c,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5,
|
385 |
|
|
0x02,0x03,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xb0,0x10,0xc0,0xe1,0xb4,0x10,0xc0,0xe1,
|
386 |
|
|
0xb8,0x10,0xc0,0xe1,0xbc,0x10,0xc0,0xe1,0x56,0xdc,0xa0,0xe3,0x21,0x00,0x00,0xeb,
|
387 |
|
|
0x0a,0x00,0xa0,0xe3,0x1a,0x00,0x00,0xeb,0x10,0x00,0x00,0xeb,0x07,0x00,0x00,0xeb,
|
388 |
|
|
0x02,0x03,0xa0,0xe3,0x02,0x14,0xa0,0xe3,0xb4,0x10,0xc0,0xe1,0x4c,0x10,0x9f,0xe5,
|
389 |
|
|
0xbc,0x10,0xc0,0xe1,0x10,0x10,0xa0,0xe3,0xb8,0x10,0xc0,0xe1,0xfe,0xff,0xff,0xea,
|
390 |
|
|
0x00,0x40,0x2d,0xe9,0x00,0x20,0xa0,0xe3,0x02,0x3c,0xa0,0xe3,0x00,0x10,0xa0,0xe3,
|
391 |
|
|
0x28,0x00,0x9f,0xe5,0x37,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,
|
392 |
|
|
0x00,0x40,0x2d,0xe9,0x12,0x2e,0xa0,0xe3,0x06,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe3,
|
393 |
|
|
0x02,0x04,0xa0,0xe3,0x2f,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,
|
394 |
|
|
0x00,0x02,0x00,0x02,0x80,0x01,0x90,0xe0,0x01,0x00,0x00,0x0a,0x01,0x00,0x50,0xe2,
|
395 |
|
|
0xfc,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x80,0x10,0xa0,0xe3,0xf3,0x06,0xa0,0xe3,
|
396 |
|
|
0x00,0x10,0x80,0xe5,0x00,0x10,0xa0,0xe3,0x00,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,
|
397 |
|
|
0x04,0x10,0x80,0xe5,0x00,0x10,0x80,0xe5,0x0e,0x34,0xa0,0xe3,0x1c,0x10,0x93,0xe5,
|
398 |
|
|
0x02,0x1a,0x81,0xe3,0x1c,0x10,0x83,0xe5,0x58,0x11,0x9f,0xe5,0x30,0x10,0x80,0xe5,
|
399 |
|
|
0x54,0x11,0x9f,0xe5,0x34,0x10,0x80,0xe5,0x38,0x10,0x80,0xe5,0x3c,0x10,0x80,0xe5,
|
400 |
|
|
0x10,0x10,0x90,0xe5,0x08,0x00,0x90,0xe5,0x1e,0xff,0x2f,0xe1,0xf3,0x16,0xa0,0xe3,
|
401 |
|
|
0x08,0x00,0x91,0xe5,0x05,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,0x10,0x00,0x91,0xe5,
|
402 |
|
|
0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0xff,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,
|
403 |
|
|
0x10,0x00,0x91,0xe5,0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5,
|
404 |
|
|
0x10,0x00,0x91,0xe5,0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5,
|
405 |
|
|
0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x30,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1,
|
406 |
|
|
0x03,0x40,0xa0,0xe1,0xa2,0x02,0xa0,0xe1,0x08,0x00,0x00,0xe2,0x03,0x00,0x80,0xe2,
|
407 |
|
|
0xd8,0x10,0x9f,0xe5,0x00,0x00,0xc1,0xe5,0x01,0x20,0xc1,0xe5,0xe2,0xff,0xff,0xeb,
|
408 |
|
|
0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x1a,0x14,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xeb,
|
409 |
|
|
0x04,0x20,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x02,0x00,0xa0,0xe3,0x01,0x00,0x00,0xeb,
|
410 |
|
|
0x30,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0xf3,0x46,0xa0,0xe3,
|
411 |
|
|
0x00,0x30,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x9a,0x8c,0x50,0x9f,0xe5,
|
412 |
|
|
0x03,0x60,0xd5,0xe7,0x0c,0x60,0x84,0xe5,0x10,0x60,0x94,0xe5,0x02,0x00,0x16,0xe3,
|
413 |
|
|
0xfc,0xff,0xff,0x0a,0x01,0x30,0x83,0xe2,0x00,0x00,0x53,0xe1,0xf7,0xff,0xff,0x3a,
|
414 |
|
|
0xff,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x08,0x00,0x94,0xe5,0x10,0x00,0x94,0xe5,
|
415 |
|
|
0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x94,0xe5,0x00,0x00,0xa0,0xe3,
|
416 |
|
|
0x00,0x00,0x52,0xe3,0x0b,0x00,0x00,0x9a,0x10,0x50,0x94,0xe5,0x02,0x00,0x15,0xe3,
|
417 |
|
|
0xfc,0xff,0xff,0x0a,0x0c,0x30,0x84,0xe5,0x10,0x50,0x94,0xe5,0x01,0x00,0x15,0xe3,
|
418 |
|
|
0xfc,0xff,0xff,0x0a,0x08,0x50,0x94,0xe5,0x01,0x50,0xc1,0xe4,0x01,0x00,0x80,0xe2,
|
419 |
|
|
0x02,0x00,0x50,0xe1,0xf3,0xff,0xff,0x3a,0xc8,0x00,0xa0,0xe3,0x98,0xff,0xff,0xeb,
|
420 |
|
|
0x70,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x01,0x0c,0x00,0x02,0x01,0x02,0x00,0x02,
|
421 |
|
|
0x00,0x01,0x00,0x02
|
422 |
|
|
};
|
423 |
|
|
|
424 |
|
|
struct atmel_private {
|
425 |
|
|
void *card; /* Bus dependent stucture varies for PCcard */
|
426 |
|
|
int (*present_callback)(void *); /* And callback which uses it */
|
427 |
|
|
char firmware_id[32];
|
428 |
|
|
AtmelFWType firmware_type;
|
429 |
|
|
u8 *firmware;
|
430 |
|
|
int firmware_length;
|
431 |
|
|
struct timer_list management_timer;
|
432 |
|
|
struct net_device *dev;
|
433 |
|
|
struct device *sys_dev;
|
434 |
|
|
struct iw_statistics wstats;
|
435 |
|
|
struct net_device_stats stats; // device stats
|
436 |
|
|
spinlock_t irqlock, timerlock; // spinlocks
|
437 |
|
|
enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type;
|
438 |
|
|
enum {
|
439 |
|
|
CARD_TYPE_PARALLEL_FLASH,
|
440 |
|
|
CARD_TYPE_SPI_FLASH,
|
441 |
|
|
CARD_TYPE_EEPROM
|
442 |
|
|
} card_type;
|
443 |
|
|
int do_rx_crc; /* If we need to CRC incoming packets */
|
444 |
|
|
int probe_crc; /* set if we don't yet know */
|
445 |
|
|
int crc_ok_cnt, crc_ko_cnt; /* counters for probing */
|
446 |
|
|
u16 rx_desc_head;
|
447 |
|
|
u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous;
|
448 |
|
|
u16 tx_free_mem, tx_buff_head, tx_buff_tail;
|
449 |
|
|
|
450 |
|
|
u16 frag_seq, frag_len, frag_no;
|
451 |
|
|
u8 frag_source[6];
|
452 |
|
|
|
453 |
|
|
u8 wep_is_on, default_key, exclude_unencrypted, encryption_level;
|
454 |
|
|
u8 group_cipher_suite, pairwise_cipher_suite;
|
455 |
|
|
u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
|
456 |
|
|
int wep_key_len[MAX_ENCRYPTION_KEYS];
|
457 |
|
|
int use_wpa, radio_on_broken; /* firmware dependent stuff. */
|
458 |
|
|
|
459 |
|
|
u16 host_info_base;
|
460 |
|
|
struct host_info_struct {
|
461 |
|
|
/* NB this is matched to the hardware, don't change. */
|
462 |
|
|
u8 volatile int_status;
|
463 |
|
|
u8 volatile int_mask;
|
464 |
|
|
u8 volatile lockout_host;
|
465 |
|
|
u8 volatile lockout_mac;
|
466 |
|
|
|
467 |
|
|
u16 tx_buff_pos;
|
468 |
|
|
u16 tx_buff_size;
|
469 |
|
|
u16 tx_desc_pos;
|
470 |
|
|
u16 tx_desc_count;
|
471 |
|
|
|
472 |
|
|
u16 rx_buff_pos;
|
473 |
|
|
u16 rx_buff_size;
|
474 |
|
|
u16 rx_desc_pos;
|
475 |
|
|
u16 rx_desc_count;
|
476 |
|
|
|
477 |
|
|
u16 build_version;
|
478 |
|
|
u16 command_pos;
|
479 |
|
|
|
480 |
|
|
u16 major_version;
|
481 |
|
|
u16 minor_version;
|
482 |
|
|
|
483 |
|
|
u16 func_ctrl;
|
484 |
|
|
u16 mac_status;
|
485 |
|
|
u16 generic_IRQ_type;
|
486 |
|
|
u8 reserved[2];
|
487 |
|
|
} host_info;
|
488 |
|
|
|
489 |
|
|
enum {
|
490 |
|
|
STATION_STATE_SCANNING,
|
491 |
|
|
STATION_STATE_JOINNING,
|
492 |
|
|
STATION_STATE_AUTHENTICATING,
|
493 |
|
|
STATION_STATE_ASSOCIATING,
|
494 |
|
|
STATION_STATE_READY,
|
495 |
|
|
STATION_STATE_REASSOCIATING,
|
496 |
|
|
STATION_STATE_DOWN,
|
497 |
|
|
STATION_STATE_MGMT_ERROR
|
498 |
|
|
} station_state;
|
499 |
|
|
|
500 |
|
|
int operating_mode, power_mode;
|
501 |
|
|
time_t last_qual;
|
502 |
|
|
int beacons_this_sec;
|
503 |
|
|
int channel;
|
504 |
|
|
int reg_domain, config_reg_domain;
|
505 |
|
|
int tx_rate;
|
506 |
|
|
int auto_tx_rate;
|
507 |
|
|
int rts_threshold;
|
508 |
|
|
int frag_threshold;
|
509 |
|
|
int long_retry, short_retry;
|
510 |
|
|
int preamble;
|
511 |
|
|
int default_beacon_period, beacon_period, listen_interval;
|
512 |
|
|
int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum;
|
513 |
|
|
int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt;
|
514 |
|
|
enum {
|
515 |
|
|
SITE_SURVEY_IDLE,
|
516 |
|
|
SITE_SURVEY_IN_PROGRESS,
|
517 |
|
|
SITE_SURVEY_COMPLETED
|
518 |
|
|
} site_survey_state;
|
519 |
|
|
time_t last_survey;
|
520 |
|
|
|
521 |
|
|
int station_was_associated, station_is_associated;
|
522 |
|
|
int fast_scan;
|
523 |
|
|
|
524 |
|
|
struct bss_info {
|
525 |
|
|
int channel;
|
526 |
|
|
int SSIDsize;
|
527 |
|
|
int RSSI;
|
528 |
|
|
int UsingWEP;
|
529 |
|
|
int preamble;
|
530 |
|
|
int beacon_period;
|
531 |
|
|
int BSStype;
|
532 |
|
|
u8 BSSID[6];
|
533 |
|
|
u8 SSID[MAX_SSID_LENGTH];
|
534 |
|
|
} BSSinfo[MAX_BSS_ENTRIES];
|
535 |
|
|
int BSS_list_entries, current_BSS;
|
536 |
|
|
int connect_to_any_BSS;
|
537 |
|
|
int SSID_size, new_SSID_size;
|
538 |
|
|
u8 CurrentBSSID[6], BSSID[6];
|
539 |
|
|
u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH];
|
540 |
|
|
u64 last_beacon_timestamp;
|
541 |
|
|
u8 rx_buf[MAX_WIRELESS_BODY];
|
542 |
|
|
};
|
543 |
|
|
|
544 |
|
|
static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16};
|
545 |
|
|
|
546 |
|
|
static const struct {
|
547 |
|
|
int reg_domain;
|
548 |
|
|
int min, max;
|
549 |
|
|
char *name;
|
550 |
|
|
} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" },
|
551 |
|
|
{ REG_DOMAIN_DOC, 1, 11, "Canada" },
|
552 |
|
|
{ REG_DOMAIN_ETSI, 1, 13, "Europe" },
|
553 |
|
|
{ REG_DOMAIN_SPAIN, 10, 11, "Spain" },
|
554 |
|
|
{ REG_DOMAIN_FRANCE, 10, 13, "France" },
|
555 |
|
|
{ REG_DOMAIN_MKK, 14, 14, "MKK" },
|
556 |
|
|
{ REG_DOMAIN_MKK1, 1, 14, "MKK1" },
|
557 |
|
|
{ REG_DOMAIN_ISRAEL, 3, 9, "Israel"} };
|
558 |
|
|
|
559 |
|
|
static void build_wpa_mib(struct atmel_private *priv);
|
560 |
|
|
static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
561 |
|
|
static void atmel_copy_to_card(struct net_device *dev, u16 dest,
|
562 |
|
|
unsigned char *src, u16 len);
|
563 |
|
|
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest,
|
564 |
|
|
u16 src, u16 len);
|
565 |
|
|
static void atmel_set_gcr(struct net_device *dev, u16 mask);
|
566 |
|
|
static void atmel_clear_gcr(struct net_device *dev, u16 mask);
|
567 |
|
|
static int atmel_lock_mac(struct atmel_private *priv);
|
568 |
|
|
static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
|
569 |
|
|
static void atmel_command_irq(struct atmel_private *priv);
|
570 |
|
|
static int atmel_validate_channel(struct atmel_private *priv, int channel);
|
571 |
|
|
static void atmel_management_frame(struct atmel_private *priv,
|
572 |
|
|
struct ieee80211_hdr_4addr *header,
|
573 |
|
|
u16 frame_len, u8 rssi);
|
574 |
|
|
static void atmel_management_timer(u_long a);
|
575 |
|
|
static void atmel_send_command(struct atmel_private *priv, int command,
|
576 |
|
|
void *cmd, int cmd_size);
|
577 |
|
|
static int atmel_send_command_wait(struct atmel_private *priv, int command,
|
578 |
|
|
void *cmd, int cmd_size);
|
579 |
|
|
static void atmel_transmit_management_frame(struct atmel_private *priv,
|
580 |
|
|
struct ieee80211_hdr_4addr *header,
|
581 |
|
|
u8 *body, int body_len);
|
582 |
|
|
|
583 |
|
|
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
|
584 |
|
|
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index,
|
585 |
|
|
u8 data);
|
586 |
|
|
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
|
587 |
|
|
u16 data);
|
588 |
|
|
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
|
589 |
|
|
u8 *data, int data_len);
|
590 |
|
|
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
|
591 |
|
|
u8 *data, int data_len);
|
592 |
|
|
static void atmel_scan(struct atmel_private *priv, int specific_ssid);
|
593 |
|
|
static void atmel_join_bss(struct atmel_private *priv, int bss_index);
|
594 |
|
|
static void atmel_smooth_qual(struct atmel_private *priv);
|
595 |
|
|
static void atmel_writeAR(struct net_device *dev, u16 data);
|
596 |
|
|
static int probe_atmel_card(struct net_device *dev);
|
597 |
|
|
static int reset_atmel_card(struct net_device *dev);
|
598 |
|
|
static void atmel_enter_state(struct atmel_private *priv, int new_state);
|
599 |
|
|
int atmel_open (struct net_device *dev);
|
600 |
|
|
|
601 |
|
|
static inline u16 atmel_hi(struct atmel_private *priv, u16 offset)
|
602 |
|
|
{
|
603 |
|
|
return priv->host_info_base + offset;
|
604 |
|
|
}
|
605 |
|
|
|
606 |
|
|
static inline u16 atmel_co(struct atmel_private *priv, u16 offset)
|
607 |
|
|
{
|
608 |
|
|
return priv->host_info.command_pos + offset;
|
609 |
|
|
}
|
610 |
|
|
|
611 |
|
|
static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc)
|
612 |
|
|
{
|
613 |
|
|
return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset;
|
614 |
|
|
}
|
615 |
|
|
|
616 |
|
|
static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc)
|
617 |
|
|
{
|
618 |
|
|
return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset;
|
619 |
|
|
}
|
620 |
|
|
|
621 |
|
|
static inline u8 atmel_read8(struct net_device *dev, u16 offset)
|
622 |
|
|
{
|
623 |
|
|
return inb(dev->base_addr + offset);
|
624 |
|
|
}
|
625 |
|
|
|
626 |
|
|
static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data)
|
627 |
|
|
{
|
628 |
|
|
outb(data, dev->base_addr + offset);
|
629 |
|
|
}
|
630 |
|
|
|
631 |
|
|
static inline u16 atmel_read16(struct net_device *dev, u16 offset)
|
632 |
|
|
{
|
633 |
|
|
return inw(dev->base_addr + offset);
|
634 |
|
|
}
|
635 |
|
|
|
636 |
|
|
static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data)
|
637 |
|
|
{
|
638 |
|
|
outw(data, dev->base_addr + offset);
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos)
|
642 |
|
|
{
|
643 |
|
|
atmel_writeAR(priv->dev, pos);
|
644 |
|
|
return atmel_read8(priv->dev, DR);
|
645 |
|
|
}
|
646 |
|
|
|
647 |
|
|
static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data)
|
648 |
|
|
{
|
649 |
|
|
atmel_writeAR(priv->dev, pos);
|
650 |
|
|
atmel_write8(priv->dev, DR, data);
|
651 |
|
|
}
|
652 |
|
|
|
653 |
|
|
static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos)
|
654 |
|
|
{
|
655 |
|
|
atmel_writeAR(priv->dev, pos);
|
656 |
|
|
return atmel_read16(priv->dev, DR);
|
657 |
|
|
}
|
658 |
|
|
|
659 |
|
|
static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data)
|
660 |
|
|
{
|
661 |
|
|
atmel_writeAR(priv->dev, pos);
|
662 |
|
|
atmel_write16(priv->dev, DR, data);
|
663 |
|
|
}
|
664 |
|
|
|
665 |
|
|
static const struct iw_handler_def atmel_handler_def;
|
666 |
|
|
|
667 |
|
|
static void tx_done_irq(struct atmel_private *priv)
|
668 |
|
|
{
|
669 |
|
|
int i;
|
670 |
|
|
|
671 |
|
|
for (i = 0;
|
672 |
|
|
atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE &&
|
673 |
|
|
i < priv->host_info.tx_desc_count;
|
674 |
|
|
i++) {
|
675 |
|
|
u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head));
|
676 |
|
|
u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head));
|
677 |
|
|
u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head));
|
678 |
|
|
|
679 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0);
|
680 |
|
|
|
681 |
|
|
priv->tx_free_mem += msdu_size;
|
682 |
|
|
priv->tx_desc_free++;
|
683 |
|
|
|
684 |
|
|
if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size))
|
685 |
|
|
priv->tx_buff_head = 0;
|
686 |
|
|
else
|
687 |
|
|
priv->tx_buff_head += msdu_size;
|
688 |
|
|
|
689 |
|
|
if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1))
|
690 |
|
|
priv->tx_desc_head++ ;
|
691 |
|
|
else
|
692 |
|
|
priv->tx_desc_head = 0;
|
693 |
|
|
|
694 |
|
|
if (type == TX_PACKET_TYPE_DATA) {
|
695 |
|
|
if (status == TX_STATUS_SUCCESS)
|
696 |
|
|
priv->stats.tx_packets++;
|
697 |
|
|
else
|
698 |
|
|
priv->stats.tx_errors++;
|
699 |
|
|
netif_wake_queue(priv->dev);
|
700 |
|
|
}
|
701 |
|
|
}
|
702 |
|
|
}
|
703 |
|
|
|
704 |
|
|
static u16 find_tx_buff(struct atmel_private *priv, u16 len)
|
705 |
|
|
{
|
706 |
|
|
u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail;
|
707 |
|
|
|
708 |
|
|
if (priv->tx_desc_free == 3 || priv->tx_free_mem < len)
|
709 |
|
|
return 0;
|
710 |
|
|
|
711 |
|
|
if (bottom_free >= len)
|
712 |
|
|
return priv->host_info.tx_buff_pos + priv->tx_buff_tail;
|
713 |
|
|
|
714 |
|
|
if (priv->tx_free_mem - bottom_free >= len) {
|
715 |
|
|
priv->tx_buff_tail = 0;
|
716 |
|
|
return priv->host_info.tx_buff_pos;
|
717 |
|
|
}
|
718 |
|
|
|
719 |
|
|
return 0;
|
720 |
|
|
}
|
721 |
|
|
|
722 |
|
|
static void tx_update_descriptor(struct atmel_private *priv, int is_bcast,
|
723 |
|
|
u16 len, u16 buff, u8 type)
|
724 |
|
|
{
|
725 |
|
|
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff);
|
726 |
|
|
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len);
|
727 |
|
|
if (!priv->use_wpa)
|
728 |
|
|
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
|
729 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type);
|
730 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate);
|
731 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0);
|
732 |
|
|
if (priv->use_wpa) {
|
733 |
|
|
int cipher_type, cipher_length;
|
734 |
|
|
if (is_bcast) {
|
735 |
|
|
cipher_type = priv->group_cipher_suite;
|
736 |
|
|
if (cipher_type == CIPHER_SUITE_WEP_64 ||
|
737 |
|
|
cipher_type == CIPHER_SUITE_WEP_128)
|
738 |
|
|
cipher_length = 8;
|
739 |
|
|
else if (cipher_type == CIPHER_SUITE_TKIP)
|
740 |
|
|
cipher_length = 12;
|
741 |
|
|
else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 ||
|
742 |
|
|
priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) {
|
743 |
|
|
cipher_type = priv->pairwise_cipher_suite;
|
744 |
|
|
cipher_length = 8;
|
745 |
|
|
} else {
|
746 |
|
|
cipher_type = CIPHER_SUITE_NONE;
|
747 |
|
|
cipher_length = 0;
|
748 |
|
|
}
|
749 |
|
|
} else {
|
750 |
|
|
cipher_type = priv->pairwise_cipher_suite;
|
751 |
|
|
if (cipher_type == CIPHER_SUITE_WEP_64 ||
|
752 |
|
|
cipher_type == CIPHER_SUITE_WEP_128)
|
753 |
|
|
cipher_length = 8;
|
754 |
|
|
else if (cipher_type == CIPHER_SUITE_TKIP)
|
755 |
|
|
cipher_length = 12;
|
756 |
|
|
else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 ||
|
757 |
|
|
priv->group_cipher_suite == CIPHER_SUITE_WEP_128) {
|
758 |
|
|
cipher_type = priv->group_cipher_suite;
|
759 |
|
|
cipher_length = 8;
|
760 |
|
|
} else {
|
761 |
|
|
cipher_type = CIPHER_SUITE_NONE;
|
762 |
|
|
cipher_length = 0;
|
763 |
|
|
}
|
764 |
|
|
}
|
765 |
|
|
|
766 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail),
|
767 |
|
|
cipher_type);
|
768 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail),
|
769 |
|
|
cipher_length);
|
770 |
|
|
}
|
771 |
|
|
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L);
|
772 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN);
|
773 |
|
|
if (priv->tx_desc_previous != priv->tx_desc_tail)
|
774 |
|
|
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0);
|
775 |
|
|
priv->tx_desc_previous = priv->tx_desc_tail;
|
776 |
|
|
if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1))
|
777 |
|
|
priv->tx_desc_tail++;
|
778 |
|
|
else
|
779 |
|
|
priv->tx_desc_tail = 0;
|
780 |
|
|
priv->tx_desc_free--;
|
781 |
|
|
priv->tx_free_mem -= len;
|
782 |
|
|
}
|
783 |
|
|
|
784 |
|
|
static int start_tx(struct sk_buff *skb, struct net_device *dev)
|
785 |
|
|
{
|
786 |
|
|
static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
787 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
788 |
|
|
struct ieee80211_hdr_4addr header;
|
789 |
|
|
unsigned long flags;
|
790 |
|
|
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
|
791 |
|
|
|
792 |
|
|
if (priv->card && priv->present_callback &&
|
793 |
|
|
!(*priv->present_callback)(priv->card)) {
|
794 |
|
|
priv->stats.tx_errors++;
|
795 |
|
|
dev_kfree_skb(skb);
|
796 |
|
|
return 0;
|
797 |
|
|
}
|
798 |
|
|
|
799 |
|
|
if (priv->station_state != STATION_STATE_READY) {
|
800 |
|
|
priv->stats.tx_errors++;
|
801 |
|
|
dev_kfree_skb(skb);
|
802 |
|
|
return 0;
|
803 |
|
|
}
|
804 |
|
|
|
805 |
|
|
/* first ensure the timer func cannot run */
|
806 |
|
|
spin_lock_bh(&priv->timerlock);
|
807 |
|
|
/* then stop the hardware ISR */
|
808 |
|
|
spin_lock_irqsave(&priv->irqlock, flags);
|
809 |
|
|
/* nb doing the above in the opposite order will deadlock */
|
810 |
|
|
|
811 |
|
|
/* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the
|
812 |
|
|
12 first bytes (containing DA/SA) and put them in the appropriate
|
813 |
|
|
fields of the Wireless Header. Thus the packet length is then the
|
814 |
|
|
initial + 18 (+30-12) */
|
815 |
|
|
|
816 |
|
|
if (!(buff = find_tx_buff(priv, len + 18))) {
|
817 |
|
|
priv->stats.tx_dropped++;
|
818 |
|
|
spin_unlock_irqrestore(&priv->irqlock, flags);
|
819 |
|
|
spin_unlock_bh(&priv->timerlock);
|
820 |
|
|
netif_stop_queue(dev);
|
821 |
|
|
return 1;
|
822 |
|
|
}
|
823 |
|
|
|
824 |
|
|
frame_ctl = IEEE80211_FTYPE_DATA;
|
825 |
|
|
header.duration_id = 0;
|
826 |
|
|
header.seq_ctl = 0;
|
827 |
|
|
if (priv->wep_is_on)
|
828 |
|
|
frame_ctl |= IEEE80211_FCTL_PROTECTED;
|
829 |
|
|
if (priv->operating_mode == IW_MODE_ADHOC) {
|
830 |
|
|
skb_copy_from_linear_data(skb, &header.addr1, 6);
|
831 |
|
|
memcpy(&header.addr2, dev->dev_addr, 6);
|
832 |
|
|
memcpy(&header.addr3, priv->BSSID, 6);
|
833 |
|
|
} else {
|
834 |
|
|
frame_ctl |= IEEE80211_FCTL_TODS;
|
835 |
|
|
memcpy(&header.addr1, priv->CurrentBSSID, 6);
|
836 |
|
|
memcpy(&header.addr2, dev->dev_addr, 6);
|
837 |
|
|
skb_copy_from_linear_data(skb, &header.addr3, 6);
|
838 |
|
|
}
|
839 |
|
|
|
840 |
|
|
if (priv->use_wpa)
|
841 |
|
|
memcpy(&header.addr4, SNAP_RFC1024, 6);
|
842 |
|
|
|
843 |
|
|
header.frame_ctl = cpu_to_le16(frame_ctl);
|
844 |
|
|
/* Copy the wireless header into the card */
|
845 |
|
|
atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
|
846 |
|
|
/* Copy the packet sans its 802.3 header addresses which have been replaced */
|
847 |
|
|
atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12);
|
848 |
|
|
priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE;
|
849 |
|
|
|
850 |
|
|
/* low bit of first byte of destination tells us if broadcast */
|
851 |
|
|
tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
|
852 |
|
|
dev->trans_start = jiffies;
|
853 |
|
|
priv->stats.tx_bytes += len;
|
854 |
|
|
|
855 |
|
|
spin_unlock_irqrestore(&priv->irqlock, flags);
|
856 |
|
|
spin_unlock_bh(&priv->timerlock);
|
857 |
|
|
dev_kfree_skb(skb);
|
858 |
|
|
|
859 |
|
|
return 0;
|
860 |
|
|
}
|
861 |
|
|
|
862 |
|
|
static void atmel_transmit_management_frame(struct atmel_private *priv,
|
863 |
|
|
struct ieee80211_hdr_4addr *header,
|
864 |
|
|
u8 *body, int body_len)
|
865 |
|
|
{
|
866 |
|
|
u16 buff;
|
867 |
|
|
int len = MGMT_FRAME_BODY_OFFSET + body_len;
|
868 |
|
|
|
869 |
|
|
if (!(buff = find_tx_buff(priv, len)))
|
870 |
|
|
return;
|
871 |
|
|
|
872 |
|
|
atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET);
|
873 |
|
|
atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len);
|
874 |
|
|
priv->tx_buff_tail += len;
|
875 |
|
|
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
|
876 |
|
|
}
|
877 |
|
|
|
878 |
|
|
static void fast_rx_path(struct atmel_private *priv,
|
879 |
|
|
struct ieee80211_hdr_4addr *header,
|
880 |
|
|
u16 msdu_size, u16 rx_packet_loc, u32 crc)
|
881 |
|
|
{
|
882 |
|
|
/* fast path: unfragmented packet copy directly into skbuf */
|
883 |
|
|
u8 mac4[6];
|
884 |
|
|
struct sk_buff *skb;
|
885 |
|
|
unsigned char *skbp;
|
886 |
|
|
|
887 |
|
|
/* get the final, mac 4 header field, this tells us encapsulation */
|
888 |
|
|
atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6);
|
889 |
|
|
msdu_size -= 6;
|
890 |
|
|
|
891 |
|
|
if (priv->do_rx_crc) {
|
892 |
|
|
crc = crc32_le(crc, mac4, 6);
|
893 |
|
|
msdu_size -= 4;
|
894 |
|
|
}
|
895 |
|
|
|
896 |
|
|
if (!(skb = dev_alloc_skb(msdu_size + 14))) {
|
897 |
|
|
priv->stats.rx_dropped++;
|
898 |
|
|
return;
|
899 |
|
|
}
|
900 |
|
|
|
901 |
|
|
skb_reserve(skb, 2);
|
902 |
|
|
skbp = skb_put(skb, msdu_size + 12);
|
903 |
|
|
atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size);
|
904 |
|
|
|
905 |
|
|
if (priv->do_rx_crc) {
|
906 |
|
|
u32 netcrc;
|
907 |
|
|
crc = crc32_le(crc, skbp + 12, msdu_size);
|
908 |
|
|
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4);
|
909 |
|
|
if ((crc ^ 0xffffffff) != netcrc) {
|
910 |
|
|
priv->stats.rx_crc_errors++;
|
911 |
|
|
dev_kfree_skb(skb);
|
912 |
|
|
return;
|
913 |
|
|
}
|
914 |
|
|
}
|
915 |
|
|
|
916 |
|
|
memcpy(skbp, header->addr1, 6); /* destination address */
|
917 |
|
|
if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
|
918 |
|
|
memcpy(&skbp[6], header->addr3, 6);
|
919 |
|
|
else
|
920 |
|
|
memcpy(&skbp[6], header->addr2, 6); /* source address */
|
921 |
|
|
|
922 |
|
|
priv->dev->last_rx = jiffies;
|
923 |
|
|
skb->protocol = eth_type_trans(skb, priv->dev);
|
924 |
|
|
skb->ip_summed = CHECKSUM_NONE;
|
925 |
|
|
netif_rx(skb);
|
926 |
|
|
priv->stats.rx_bytes += 12 + msdu_size;
|
927 |
|
|
priv->stats.rx_packets++;
|
928 |
|
|
}
|
929 |
|
|
|
930 |
|
|
/* Test to see if the packet in card memory at packet_loc has a valid CRC
|
931 |
|
|
It doesn't matter that this is slow: it is only used to proble the first few
|
932 |
|
|
packets. */
|
933 |
|
|
static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
|
934 |
|
|
{
|
935 |
|
|
int i = msdu_size - 4;
|
936 |
|
|
u32 netcrc, crc = 0xffffffff;
|
937 |
|
|
|
938 |
|
|
if (msdu_size < 4)
|
939 |
|
|
return 0;
|
940 |
|
|
|
941 |
|
|
atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4);
|
942 |
|
|
|
943 |
|
|
atmel_writeAR(priv->dev, packet_loc);
|
944 |
|
|
while (i--) {
|
945 |
|
|
u8 octet = atmel_read8(priv->dev, DR);
|
946 |
|
|
crc = crc32_le(crc, &octet, 1);
|
947 |
|
|
}
|
948 |
|
|
|
949 |
|
|
return (crc ^ 0xffffffff) == netcrc;
|
950 |
|
|
}
|
951 |
|
|
|
952 |
|
|
static void frag_rx_path(struct atmel_private *priv,
|
953 |
|
|
struct ieee80211_hdr_4addr *header,
|
954 |
|
|
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
|
955 |
|
|
u8 frag_no, int more_frags)
|
956 |
|
|
{
|
957 |
|
|
u8 mac4[6];
|
958 |
|
|
u8 source[6];
|
959 |
|
|
struct sk_buff *skb;
|
960 |
|
|
|
961 |
|
|
if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
|
962 |
|
|
memcpy(source, header->addr3, 6);
|
963 |
|
|
else
|
964 |
|
|
memcpy(source, header->addr2, 6);
|
965 |
|
|
|
966 |
|
|
rx_packet_loc += 24; /* skip header */
|
967 |
|
|
|
968 |
|
|
if (priv->do_rx_crc)
|
969 |
|
|
msdu_size -= 4;
|
970 |
|
|
|
971 |
|
|
if (frag_no == 0) { /* first fragment */
|
972 |
|
|
atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6);
|
973 |
|
|
msdu_size -= 6;
|
974 |
|
|
rx_packet_loc += 6;
|
975 |
|
|
|
976 |
|
|
if (priv->do_rx_crc)
|
977 |
|
|
crc = crc32_le(crc, mac4, 6);
|
978 |
|
|
|
979 |
|
|
priv->frag_seq = seq_no;
|
980 |
|
|
priv->frag_no = 1;
|
981 |
|
|
priv->frag_len = msdu_size;
|
982 |
|
|
memcpy(priv->frag_source, source, 6);
|
983 |
|
|
memcpy(&priv->rx_buf[6], source, 6);
|
984 |
|
|
memcpy(priv->rx_buf, header->addr1, 6);
|
985 |
|
|
|
986 |
|
|
atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size);
|
987 |
|
|
|
988 |
|
|
if (priv->do_rx_crc) {
|
989 |
|
|
u32 netcrc;
|
990 |
|
|
crc = crc32_le(crc, &priv->rx_buf[12], msdu_size);
|
991 |
|
|
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
|
992 |
|
|
if ((crc ^ 0xffffffff) != netcrc) {
|
993 |
|
|
priv->stats.rx_crc_errors++;
|
994 |
|
|
memset(priv->frag_source, 0xff, 6);
|
995 |
|
|
}
|
996 |
|
|
}
|
997 |
|
|
|
998 |
|
|
} else if (priv->frag_no == frag_no &&
|
999 |
|
|
priv->frag_seq == seq_no &&
|
1000 |
|
|
memcmp(priv->frag_source, source, 6) == 0) {
|
1001 |
|
|
|
1002 |
|
|
atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len],
|
1003 |
|
|
rx_packet_loc, msdu_size);
|
1004 |
|
|
if (priv->do_rx_crc) {
|
1005 |
|
|
u32 netcrc;
|
1006 |
|
|
crc = crc32_le(crc,
|
1007 |
|
|
&priv->rx_buf[12 + priv->frag_len],
|
1008 |
|
|
msdu_size);
|
1009 |
|
|
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
|
1010 |
|
|
if ((crc ^ 0xffffffff) != netcrc) {
|
1011 |
|
|
priv->stats.rx_crc_errors++;
|
1012 |
|
|
memset(priv->frag_source, 0xff, 6);
|
1013 |
|
|
more_frags = 1; /* don't send broken assembly */
|
1014 |
|
|
}
|
1015 |
|
|
}
|
1016 |
|
|
|
1017 |
|
|
priv->frag_len += msdu_size;
|
1018 |
|
|
priv->frag_no++;
|
1019 |
|
|
|
1020 |
|
|
if (!more_frags) { /* last one */
|
1021 |
|
|
memset(priv->frag_source, 0xff, 6);
|
1022 |
|
|
if (!(skb = dev_alloc_skb(priv->frag_len + 14))) {
|
1023 |
|
|
priv->stats.rx_dropped++;
|
1024 |
|
|
} else {
|
1025 |
|
|
skb_reserve(skb, 2);
|
1026 |
|
|
memcpy(skb_put(skb, priv->frag_len + 12),
|
1027 |
|
|
priv->rx_buf,
|
1028 |
|
|
priv->frag_len + 12);
|
1029 |
|
|
priv->dev->last_rx = jiffies;
|
1030 |
|
|
skb->protocol = eth_type_trans(skb, priv->dev);
|
1031 |
|
|
skb->ip_summed = CHECKSUM_NONE;
|
1032 |
|
|
netif_rx(skb);
|
1033 |
|
|
priv->stats.rx_bytes += priv->frag_len + 12;
|
1034 |
|
|
priv->stats.rx_packets++;
|
1035 |
|
|
}
|
1036 |
|
|
}
|
1037 |
|
|
} else
|
1038 |
|
|
priv->wstats.discard.fragment++;
|
1039 |
|
|
}
|
1040 |
|
|
|
1041 |
|
|
static void rx_done_irq(struct atmel_private *priv)
|
1042 |
|
|
{
|
1043 |
|
|
int i;
|
1044 |
|
|
struct ieee80211_hdr_4addr header;
|
1045 |
|
|
|
1046 |
|
|
for (i = 0;
|
1047 |
|
|
atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
|
1048 |
|
|
i < priv->host_info.rx_desc_count;
|
1049 |
|
|
i++) {
|
1050 |
|
|
|
1051 |
|
|
u16 msdu_size, rx_packet_loc, frame_ctl, seq_control;
|
1052 |
|
|
u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head));
|
1053 |
|
|
u32 crc = 0xffffffff;
|
1054 |
|
|
|
1055 |
|
|
if (status != RX_STATUS_SUCCESS) {
|
1056 |
|
|
if (status == 0xc1) /* determined by experiment */
|
1057 |
|
|
priv->wstats.discard.nwid++;
|
1058 |
|
|
else
|
1059 |
|
|
priv->stats.rx_errors++;
|
1060 |
|
|
goto next;
|
1061 |
|
|
}
|
1062 |
|
|
|
1063 |
|
|
msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head));
|
1064 |
|
|
rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head));
|
1065 |
|
|
|
1066 |
|
|
if (msdu_size < 30) {
|
1067 |
|
|
priv->stats.rx_errors++;
|
1068 |
|
|
goto next;
|
1069 |
|
|
}
|
1070 |
|
|
|
1071 |
|
|
/* Get header as far as end of seq_ctl */
|
1072 |
|
|
atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24);
|
1073 |
|
|
frame_ctl = le16_to_cpu(header.frame_ctl);
|
1074 |
|
|
seq_control = le16_to_cpu(header.seq_ctl);
|
1075 |
|
|
|
1076 |
|
|
/* probe for CRC use here if needed once five packets have
|
1077 |
|
|
arrived with the same crc status, we assume we know what's
|
1078 |
|
|
happening and stop probing */
|
1079 |
|
|
if (priv->probe_crc) {
|
1080 |
|
|
if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) {
|
1081 |
|
|
priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
|
1082 |
|
|
} else {
|
1083 |
|
|
priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24);
|
1084 |
|
|
}
|
1085 |
|
|
if (priv->do_rx_crc) {
|
1086 |
|
|
if (priv->crc_ok_cnt++ > 5)
|
1087 |
|
|
priv->probe_crc = 0;
|
1088 |
|
|
} else {
|
1089 |
|
|
if (priv->crc_ko_cnt++ > 5)
|
1090 |
|
|
priv->probe_crc = 0;
|
1091 |
|
|
}
|
1092 |
|
|
}
|
1093 |
|
|
|
1094 |
|
|
/* don't CRC header when WEP in use */
|
1095 |
|
|
if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) {
|
1096 |
|
|
crc = crc32_le(0xffffffff, (unsigned char *)&header, 24);
|
1097 |
|
|
}
|
1098 |
|
|
msdu_size -= 24; /* header */
|
1099 |
|
|
|
1100 |
|
|
if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
|
1101 |
|
|
int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS;
|
1102 |
|
|
u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG;
|
1103 |
|
|
u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4;
|
1104 |
|
|
|
1105 |
|
|
if (!more_fragments && packet_fragment_no == 0) {
|
1106 |
|
|
fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc);
|
1107 |
|
|
} else {
|
1108 |
|
|
frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc,
|
1109 |
|
|
packet_sequence_no, packet_fragment_no, more_fragments);
|
1110 |
|
|
}
|
1111 |
|
|
}
|
1112 |
|
|
|
1113 |
|
|
if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
|
1114 |
|
|
/* copy rest of packet into buffer */
|
1115 |
|
|
atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size);
|
1116 |
|
|
|
1117 |
|
|
/* we use the same buffer for frag reassembly and control packets */
|
1118 |
|
|
memset(priv->frag_source, 0xff, 6);
|
1119 |
|
|
|
1120 |
|
|
if (priv->do_rx_crc) {
|
1121 |
|
|
/* last 4 octets is crc */
|
1122 |
|
|
msdu_size -= 4;
|
1123 |
|
|
crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size);
|
1124 |
|
|
if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) {
|
1125 |
|
|
priv->stats.rx_crc_errors++;
|
1126 |
|
|
goto next;
|
1127 |
|
|
}
|
1128 |
|
|
}
|
1129 |
|
|
|
1130 |
|
|
atmel_management_frame(priv, &header, msdu_size,
|
1131 |
|
|
atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head)));
|
1132 |
|
|
}
|
1133 |
|
|
|
1134 |
|
|
next:
|
1135 |
|
|
/* release descriptor */
|
1136 |
|
|
atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED);
|
1137 |
|
|
|
1138 |
|
|
if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1))
|
1139 |
|
|
priv->rx_desc_head++;
|
1140 |
|
|
else
|
1141 |
|
|
priv->rx_desc_head = 0;
|
1142 |
|
|
}
|
1143 |
|
|
}
|
1144 |
|
|
|
1145 |
|
|
static irqreturn_t service_interrupt(int irq, void *dev_id)
|
1146 |
|
|
{
|
1147 |
|
|
struct net_device *dev = (struct net_device *) dev_id;
|
1148 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1149 |
|
|
u8 isr;
|
1150 |
|
|
int i = -1;
|
1151 |
|
|
static u8 irq_order[] = {
|
1152 |
|
|
ISR_OUT_OF_RANGE,
|
1153 |
|
|
ISR_RxCOMPLETE,
|
1154 |
|
|
ISR_TxCOMPLETE,
|
1155 |
|
|
ISR_RxFRAMELOST,
|
1156 |
|
|
ISR_FATAL_ERROR,
|
1157 |
|
|
ISR_COMMAND_COMPLETE,
|
1158 |
|
|
ISR_IBSS_MERGE,
|
1159 |
|
|
ISR_GENERIC_IRQ
|
1160 |
|
|
};
|
1161 |
|
|
|
1162 |
|
|
if (priv->card && priv->present_callback &&
|
1163 |
|
|
!(*priv->present_callback)(priv->card))
|
1164 |
|
|
return IRQ_HANDLED;
|
1165 |
|
|
|
1166 |
|
|
/* In this state upper-level code assumes it can mess with
|
1167 |
|
|
the card unhampered by interrupts which may change register state.
|
1168 |
|
|
Note that even though the card shouldn't generate interrupts
|
1169 |
|
|
the inturrupt line may be shared. This allows card setup
|
1170 |
|
|
to go on without disabling interrupts for a long time. */
|
1171 |
|
|
if (priv->station_state == STATION_STATE_DOWN)
|
1172 |
|
|
return IRQ_NONE;
|
1173 |
|
|
|
1174 |
|
|
atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */
|
1175 |
|
|
|
1176 |
|
|
while (1) {
|
1177 |
|
|
if (!atmel_lock_mac(priv)) {
|
1178 |
|
|
/* failed to contact card */
|
1179 |
|
|
printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name);
|
1180 |
|
|
return IRQ_HANDLED;
|
1181 |
|
|
}
|
1182 |
|
|
|
1183 |
|
|
isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET));
|
1184 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
|
1185 |
|
|
|
1186 |
|
|
if (!isr) {
|
1187 |
|
|
atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */
|
1188 |
|
|
return i == -1 ? IRQ_NONE : IRQ_HANDLED;
|
1189 |
|
|
}
|
1190 |
|
|
|
1191 |
|
|
atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */
|
1192 |
|
|
|
1193 |
|
|
for (i = 0; i < ARRAY_SIZE(irq_order); i++)
|
1194 |
|
|
if (isr & irq_order[i])
|
1195 |
|
|
break;
|
1196 |
|
|
|
1197 |
|
|
if (!atmel_lock_mac(priv)) {
|
1198 |
|
|
/* failed to contact card */
|
1199 |
|
|
printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name);
|
1200 |
|
|
return IRQ_HANDLED;
|
1201 |
|
|
}
|
1202 |
|
|
|
1203 |
|
|
isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET));
|
1204 |
|
|
isr ^= irq_order[i];
|
1205 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr);
|
1206 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
|
1207 |
|
|
|
1208 |
|
|
switch (irq_order[i]) {
|
1209 |
|
|
|
1210 |
|
|
case ISR_OUT_OF_RANGE:
|
1211 |
|
|
if (priv->operating_mode == IW_MODE_INFRA &&
|
1212 |
|
|
priv->station_state == STATION_STATE_READY) {
|
1213 |
|
|
priv->station_is_associated = 0;
|
1214 |
|
|
atmel_scan(priv, 1);
|
1215 |
|
|
}
|
1216 |
|
|
break;
|
1217 |
|
|
|
1218 |
|
|
case ISR_RxFRAMELOST:
|
1219 |
|
|
priv->wstats.discard.misc++;
|
1220 |
|
|
/* fall through */
|
1221 |
|
|
case ISR_RxCOMPLETE:
|
1222 |
|
|
rx_done_irq(priv);
|
1223 |
|
|
break;
|
1224 |
|
|
|
1225 |
|
|
case ISR_TxCOMPLETE:
|
1226 |
|
|
tx_done_irq(priv);
|
1227 |
|
|
break;
|
1228 |
|
|
|
1229 |
|
|
case ISR_FATAL_ERROR:
|
1230 |
|
|
printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name);
|
1231 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
1232 |
|
|
break;
|
1233 |
|
|
|
1234 |
|
|
case ISR_COMMAND_COMPLETE:
|
1235 |
|
|
atmel_command_irq(priv);
|
1236 |
|
|
break;
|
1237 |
|
|
|
1238 |
|
|
case ISR_IBSS_MERGE:
|
1239 |
|
|
atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS,
|
1240 |
|
|
priv->CurrentBSSID, 6);
|
1241 |
|
|
/* The WPA stuff cares about the current AP address */
|
1242 |
|
|
if (priv->use_wpa)
|
1243 |
|
|
build_wpa_mib(priv);
|
1244 |
|
|
break;
|
1245 |
|
|
case ISR_GENERIC_IRQ:
|
1246 |
|
|
printk(KERN_INFO "%s: Generic_irq received.\n", dev->name);
|
1247 |
|
|
break;
|
1248 |
|
|
}
|
1249 |
|
|
}
|
1250 |
|
|
}
|
1251 |
|
|
|
1252 |
|
|
static struct net_device_stats *atmel_get_stats(struct net_device *dev)
|
1253 |
|
|
{
|
1254 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1255 |
|
|
return &priv->stats;
|
1256 |
|
|
}
|
1257 |
|
|
|
1258 |
|
|
static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
|
1259 |
|
|
{
|
1260 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1261 |
|
|
|
1262 |
|
|
/* update the link quality here in case we are seeing no beacons
|
1263 |
|
|
at all to drive the process */
|
1264 |
|
|
atmel_smooth_qual(priv);
|
1265 |
|
|
|
1266 |
|
|
priv->wstats.status = priv->station_state;
|
1267 |
|
|
|
1268 |
|
|
if (priv->operating_mode == IW_MODE_INFRA) {
|
1269 |
|
|
if (priv->station_state != STATION_STATE_READY) {
|
1270 |
|
|
priv->wstats.qual.qual = 0;
|
1271 |
|
|
priv->wstats.qual.level = 0;
|
1272 |
|
|
priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID
|
1273 |
|
|
| IW_QUAL_LEVEL_INVALID);
|
1274 |
|
|
}
|
1275 |
|
|
priv->wstats.qual.noise = 0;
|
1276 |
|
|
priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
|
1277 |
|
|
} else {
|
1278 |
|
|
/* Quality levels cannot be determined in ad-hoc mode,
|
1279 |
|
|
because we can 'hear' more that one remote station. */
|
1280 |
|
|
priv->wstats.qual.qual = 0;
|
1281 |
|
|
priv->wstats.qual.level = 0;
|
1282 |
|
|
priv->wstats.qual.noise = 0;
|
1283 |
|
|
priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID
|
1284 |
|
|
| IW_QUAL_LEVEL_INVALID
|
1285 |
|
|
| IW_QUAL_NOISE_INVALID;
|
1286 |
|
|
priv->wstats.miss.beacon = 0;
|
1287 |
|
|
}
|
1288 |
|
|
|
1289 |
|
|
return &priv->wstats;
|
1290 |
|
|
}
|
1291 |
|
|
|
1292 |
|
|
static int atmel_change_mtu(struct net_device *dev, int new_mtu)
|
1293 |
|
|
{
|
1294 |
|
|
if ((new_mtu < 68) || (new_mtu > 2312))
|
1295 |
|
|
return -EINVAL;
|
1296 |
|
|
dev->mtu = new_mtu;
|
1297 |
|
|
return 0;
|
1298 |
|
|
}
|
1299 |
|
|
|
1300 |
|
|
static int atmel_set_mac_address(struct net_device *dev, void *p)
|
1301 |
|
|
{
|
1302 |
|
|
struct sockaddr *addr = p;
|
1303 |
|
|
|
1304 |
|
|
memcpy (dev->dev_addr, addr->sa_data, dev->addr_len);
|
1305 |
|
|
return atmel_open(dev);
|
1306 |
|
|
}
|
1307 |
|
|
|
1308 |
|
|
EXPORT_SYMBOL(atmel_open);
|
1309 |
|
|
|
1310 |
|
|
int atmel_open(struct net_device *dev)
|
1311 |
|
|
{
|
1312 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1313 |
|
|
int i, channel;
|
1314 |
|
|
|
1315 |
|
|
/* any scheduled timer is no longer needed and might screw things up.. */
|
1316 |
|
|
del_timer_sync(&priv->management_timer);
|
1317 |
|
|
|
1318 |
|
|
/* Interrupts will not touch the card once in this state... */
|
1319 |
|
|
priv->station_state = STATION_STATE_DOWN;
|
1320 |
|
|
|
1321 |
|
|
if (priv->new_SSID_size) {
|
1322 |
|
|
memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size);
|
1323 |
|
|
priv->SSID_size = priv->new_SSID_size;
|
1324 |
|
|
priv->new_SSID_size = 0;
|
1325 |
|
|
}
|
1326 |
|
|
priv->BSS_list_entries = 0;
|
1327 |
|
|
|
1328 |
|
|
priv->AuthenticationRequestRetryCnt = 0;
|
1329 |
|
|
priv->AssociationRequestRetryCnt = 0;
|
1330 |
|
|
priv->ReAssociationRequestRetryCnt = 0;
|
1331 |
|
|
priv->CurrentAuthentTransactionSeqNum = 0x0001;
|
1332 |
|
|
priv->ExpectedAuthentTransactionSeqNum = 0x0002;
|
1333 |
|
|
|
1334 |
|
|
priv->site_survey_state = SITE_SURVEY_IDLE;
|
1335 |
|
|
priv->station_is_associated = 0;
|
1336 |
|
|
|
1337 |
|
|
if (!reset_atmel_card(dev))
|
1338 |
|
|
return -EAGAIN;
|
1339 |
|
|
|
1340 |
|
|
if (priv->config_reg_domain) {
|
1341 |
|
|
priv->reg_domain = priv->config_reg_domain;
|
1342 |
|
|
atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain);
|
1343 |
|
|
} else {
|
1344 |
|
|
priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS);
|
1345 |
|
|
for (i = 0; i < ARRAY_SIZE(channel_table); i++)
|
1346 |
|
|
if (priv->reg_domain == channel_table[i].reg_domain)
|
1347 |
|
|
break;
|
1348 |
|
|
if (i == ARRAY_SIZE(channel_table)) {
|
1349 |
|
|
priv->reg_domain = REG_DOMAIN_MKK1;
|
1350 |
|
|
printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name);
|
1351 |
|
|
}
|
1352 |
|
|
}
|
1353 |
|
|
|
1354 |
|
|
if ((channel = atmel_validate_channel(priv, priv->channel)))
|
1355 |
|
|
priv->channel = channel;
|
1356 |
|
|
|
1357 |
|
|
/* this moves station_state on.... */
|
1358 |
|
|
atmel_scan(priv, 1);
|
1359 |
|
|
|
1360 |
|
|
atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */
|
1361 |
|
|
return 0;
|
1362 |
|
|
}
|
1363 |
|
|
|
1364 |
|
|
static int atmel_close(struct net_device *dev)
|
1365 |
|
|
{
|
1366 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1367 |
|
|
|
1368 |
|
|
/* Send event to userspace that we are disassociating */
|
1369 |
|
|
if (priv->station_state == STATION_STATE_READY) {
|
1370 |
|
|
union iwreq_data wrqu;
|
1371 |
|
|
|
1372 |
|
|
wrqu.data.length = 0;
|
1373 |
|
|
wrqu.data.flags = 0;
|
1374 |
|
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
1375 |
|
|
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
|
1376 |
|
|
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
1377 |
|
|
}
|
1378 |
|
|
|
1379 |
|
|
atmel_enter_state(priv, STATION_STATE_DOWN);
|
1380 |
|
|
|
1381 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD)
|
1382 |
|
|
atmel_write16(dev, GCR, 0x0060);
|
1383 |
|
|
atmel_write16(dev, GCR, 0x0040);
|
1384 |
|
|
return 0;
|
1385 |
|
|
}
|
1386 |
|
|
|
1387 |
|
|
static int atmel_validate_channel(struct atmel_private *priv, int channel)
|
1388 |
|
|
{
|
1389 |
|
|
/* check that channel is OK, if so return zero,
|
1390 |
|
|
else return suitable default channel */
|
1391 |
|
|
int i;
|
1392 |
|
|
|
1393 |
|
|
for (i = 0; i < ARRAY_SIZE(channel_table); i++)
|
1394 |
|
|
if (priv->reg_domain == channel_table[i].reg_domain) {
|
1395 |
|
|
if (channel >= channel_table[i].min &&
|
1396 |
|
|
channel <= channel_table[i].max)
|
1397 |
|
|
return 0;
|
1398 |
|
|
else
|
1399 |
|
|
return channel_table[i].min;
|
1400 |
|
|
}
|
1401 |
|
|
return 0;
|
1402 |
|
|
}
|
1403 |
|
|
|
1404 |
|
|
static int atmel_proc_output (char *buf, struct atmel_private *priv)
|
1405 |
|
|
{
|
1406 |
|
|
int i;
|
1407 |
|
|
char *p = buf;
|
1408 |
|
|
char *s, *r, *c;
|
1409 |
|
|
|
1410 |
|
|
p += sprintf(p, "Driver version:\t\t%d.%d\n",
|
1411 |
|
|
DRIVER_MAJOR, DRIVER_MINOR);
|
1412 |
|
|
|
1413 |
|
|
if (priv->station_state != STATION_STATE_DOWN) {
|
1414 |
|
|
p += sprintf(p, "Firmware version:\t%d.%d build %d\n"
|
1415 |
|
|
"Firmware location:\t",
|
1416 |
|
|
priv->host_info.major_version,
|
1417 |
|
|
priv->host_info.minor_version,
|
1418 |
|
|
priv->host_info.build_version);
|
1419 |
|
|
|
1420 |
|
|
if (priv->card_type != CARD_TYPE_EEPROM)
|
1421 |
|
|
p += sprintf(p, "on card\n");
|
1422 |
|
|
else if (priv->firmware)
|
1423 |
|
|
p += sprintf(p, "%s loaded by host\n",
|
1424 |
|
|
priv->firmware_id);
|
1425 |
|
|
else
|
1426 |
|
|
p += sprintf(p, "%s loaded by hotplug\n",
|
1427 |
|
|
priv->firmware_id);
|
1428 |
|
|
|
1429 |
|
|
switch (priv->card_type) {
|
1430 |
|
|
case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break;
|
1431 |
|
|
case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break;
|
1432 |
|
|
case CARD_TYPE_EEPROM: c = "EEPROM"; break;
|
1433 |
|
|
default: c = "<unknown>";
|
1434 |
|
|
}
|
1435 |
|
|
|
1436 |
|
|
r = "<unknown>";
|
1437 |
|
|
for (i = 0; i < ARRAY_SIZE(channel_table); i++)
|
1438 |
|
|
if (priv->reg_domain == channel_table[i].reg_domain)
|
1439 |
|
|
r = channel_table[i].name;
|
1440 |
|
|
|
1441 |
|
|
p += sprintf(p, "MAC memory type:\t%s\n", c);
|
1442 |
|
|
p += sprintf(p, "Regulatory domain:\t%s\n", r);
|
1443 |
|
|
p += sprintf(p, "Host CRC checking:\t%s\n",
|
1444 |
|
|
priv->do_rx_crc ? "On" : "Off");
|
1445 |
|
|
p += sprintf(p, "WPA-capable firmware:\t%s\n",
|
1446 |
|
|
priv->use_wpa ? "Yes" : "No");
|
1447 |
|
|
}
|
1448 |
|
|
|
1449 |
|
|
switch(priv->station_state) {
|
1450 |
|
|
case STATION_STATE_SCANNING: s = "Scanning"; break;
|
1451 |
|
|
case STATION_STATE_JOINNING: s = "Joining"; break;
|
1452 |
|
|
case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break;
|
1453 |
|
|
case STATION_STATE_ASSOCIATING: s = "Associating"; break;
|
1454 |
|
|
case STATION_STATE_READY: s = "Ready"; break;
|
1455 |
|
|
case STATION_STATE_REASSOCIATING: s = "Reassociating"; break;
|
1456 |
|
|
case STATION_STATE_MGMT_ERROR: s = "Management error"; break;
|
1457 |
|
|
case STATION_STATE_DOWN: s = "Down"; break;
|
1458 |
|
|
default: s = "<unknown>";
|
1459 |
|
|
}
|
1460 |
|
|
|
1461 |
|
|
p += sprintf(p, "Current state:\t\t%s\n", s);
|
1462 |
|
|
return p - buf;
|
1463 |
|
|
}
|
1464 |
|
|
|
1465 |
|
|
static int atmel_read_proc(char *page, char **start, off_t off,
|
1466 |
|
|
int count, int *eof, void *data)
|
1467 |
|
|
{
|
1468 |
|
|
struct atmel_private *priv = data;
|
1469 |
|
|
int len = atmel_proc_output (page, priv);
|
1470 |
|
|
if (len <= off+count) *eof = 1;
|
1471 |
|
|
*start = page + off;
|
1472 |
|
|
len -= off;
|
1473 |
|
|
if (len>count) len = count;
|
1474 |
|
|
if (len<0) len = 0;
|
1475 |
|
|
return len;
|
1476 |
|
|
}
|
1477 |
|
|
|
1478 |
|
|
struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
|
1479 |
|
|
const AtmelFWType fw_type,
|
1480 |
|
|
struct device *sys_dev,
|
1481 |
|
|
int (*card_present)(void *), void *card)
|
1482 |
|
|
{
|
1483 |
|
|
struct proc_dir_entry *ent;
|
1484 |
|
|
struct net_device *dev;
|
1485 |
|
|
struct atmel_private *priv;
|
1486 |
|
|
int rc;
|
1487 |
|
|
DECLARE_MAC_BUF(mac);
|
1488 |
|
|
|
1489 |
|
|
/* Create the network device object. */
|
1490 |
|
|
dev = alloc_etherdev(sizeof(*priv));
|
1491 |
|
|
if (!dev) {
|
1492 |
|
|
printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n");
|
1493 |
|
|
return NULL;
|
1494 |
|
|
}
|
1495 |
|
|
if (dev_alloc_name(dev, dev->name) < 0) {
|
1496 |
|
|
printk(KERN_ERR "atmel: Couldn't get name!\n");
|
1497 |
|
|
goto err_out_free;
|
1498 |
|
|
}
|
1499 |
|
|
|
1500 |
|
|
priv = netdev_priv(dev);
|
1501 |
|
|
priv->dev = dev;
|
1502 |
|
|
priv->sys_dev = sys_dev;
|
1503 |
|
|
priv->present_callback = card_present;
|
1504 |
|
|
priv->card = card;
|
1505 |
|
|
priv->firmware = NULL;
|
1506 |
|
|
priv->firmware_id[0] = '\0';
|
1507 |
|
|
priv->firmware_type = fw_type;
|
1508 |
|
|
if (firmware) /* module parameter */
|
1509 |
|
|
strcpy(priv->firmware_id, firmware);
|
1510 |
|
|
priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI;
|
1511 |
|
|
priv->station_state = STATION_STATE_DOWN;
|
1512 |
|
|
priv->do_rx_crc = 0;
|
1513 |
|
|
/* For PCMCIA cards, some chips need CRC, some don't
|
1514 |
|
|
so we have to probe. */
|
1515 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD) {
|
1516 |
|
|
priv->probe_crc = 1;
|
1517 |
|
|
priv->crc_ok_cnt = priv->crc_ko_cnt = 0;
|
1518 |
|
|
} else
|
1519 |
|
|
priv->probe_crc = 0;
|
1520 |
|
|
memset(&priv->stats, 0, sizeof(priv->stats));
|
1521 |
|
|
memset(&priv->wstats, 0, sizeof(priv->wstats));
|
1522 |
|
|
priv->last_qual = jiffies;
|
1523 |
|
|
priv->last_beacon_timestamp = 0;
|
1524 |
|
|
memset(priv->frag_source, 0xff, sizeof(priv->frag_source));
|
1525 |
|
|
memset(priv->BSSID, 0, 6);
|
1526 |
|
|
priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */
|
1527 |
|
|
priv->station_was_associated = 0;
|
1528 |
|
|
|
1529 |
|
|
priv->last_survey = jiffies;
|
1530 |
|
|
priv->preamble = LONG_PREAMBLE;
|
1531 |
|
|
priv->operating_mode = IW_MODE_INFRA;
|
1532 |
|
|
priv->connect_to_any_BSS = 0;
|
1533 |
|
|
priv->config_reg_domain = 0;
|
1534 |
|
|
priv->reg_domain = 0;
|
1535 |
|
|
priv->tx_rate = 3;
|
1536 |
|
|
priv->auto_tx_rate = 1;
|
1537 |
|
|
priv->channel = 4;
|
1538 |
|
|
priv->power_mode = 0;
|
1539 |
|
|
priv->SSID[0] = '\0';
|
1540 |
|
|
priv->SSID_size = 0;
|
1541 |
|
|
priv->new_SSID_size = 0;
|
1542 |
|
|
priv->frag_threshold = 2346;
|
1543 |
|
|
priv->rts_threshold = 2347;
|
1544 |
|
|
priv->short_retry = 7;
|
1545 |
|
|
priv->long_retry = 4;
|
1546 |
|
|
|
1547 |
|
|
priv->wep_is_on = 0;
|
1548 |
|
|
priv->default_key = 0;
|
1549 |
|
|
priv->encryption_level = 0;
|
1550 |
|
|
priv->exclude_unencrypted = 0;
|
1551 |
|
|
priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
|
1552 |
|
|
priv->use_wpa = 0;
|
1553 |
|
|
memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
|
1554 |
|
|
memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
|
1555 |
|
|
|
1556 |
|
|
priv->default_beacon_period = priv->beacon_period = 100;
|
1557 |
|
|
priv->listen_interval = 1;
|
1558 |
|
|
|
1559 |
|
|
init_timer(&priv->management_timer);
|
1560 |
|
|
spin_lock_init(&priv->irqlock);
|
1561 |
|
|
spin_lock_init(&priv->timerlock);
|
1562 |
|
|
priv->management_timer.function = atmel_management_timer;
|
1563 |
|
|
priv->management_timer.data = (unsigned long) dev;
|
1564 |
|
|
|
1565 |
|
|
dev->open = atmel_open;
|
1566 |
|
|
dev->stop = atmel_close;
|
1567 |
|
|
dev->change_mtu = atmel_change_mtu;
|
1568 |
|
|
dev->set_mac_address = atmel_set_mac_address;
|
1569 |
|
|
dev->hard_start_xmit = start_tx;
|
1570 |
|
|
dev->get_stats = atmel_get_stats;
|
1571 |
|
|
dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
|
1572 |
|
|
dev->do_ioctl = atmel_ioctl;
|
1573 |
|
|
dev->irq = irq;
|
1574 |
|
|
dev->base_addr = port;
|
1575 |
|
|
|
1576 |
|
|
SET_NETDEV_DEV(dev, sys_dev);
|
1577 |
|
|
|
1578 |
|
|
if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) {
|
1579 |
|
|
printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc);
|
1580 |
|
|
goto err_out_free;
|
1581 |
|
|
}
|
1582 |
|
|
|
1583 |
|
|
if (!request_region(dev->base_addr, 32,
|
1584 |
|
|
priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) {
|
1585 |
|
|
goto err_out_irq;
|
1586 |
|
|
}
|
1587 |
|
|
|
1588 |
|
|
if (register_netdev(dev))
|
1589 |
|
|
goto err_out_res;
|
1590 |
|
|
|
1591 |
|
|
if (!probe_atmel_card(dev)){
|
1592 |
|
|
unregister_netdev(dev);
|
1593 |
|
|
goto err_out_res;
|
1594 |
|
|
}
|
1595 |
|
|
|
1596 |
|
|
netif_carrier_off(dev);
|
1597 |
|
|
|
1598 |
|
|
ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
|
1599 |
|
|
if (!ent)
|
1600 |
|
|
printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
|
1601 |
|
|
|
1602 |
|
|
printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n",
|
1603 |
|
|
dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr));
|
1604 |
|
|
|
1605 |
|
|
return dev;
|
1606 |
|
|
|
1607 |
|
|
err_out_res:
|
1608 |
|
|
release_region( dev->base_addr, 32);
|
1609 |
|
|
err_out_irq:
|
1610 |
|
|
free_irq(dev->irq, dev);
|
1611 |
|
|
err_out_free:
|
1612 |
|
|
free_netdev(dev);
|
1613 |
|
|
return NULL;
|
1614 |
|
|
}
|
1615 |
|
|
|
1616 |
|
|
EXPORT_SYMBOL(init_atmel_card);
|
1617 |
|
|
|
1618 |
|
|
void stop_atmel_card(struct net_device *dev)
|
1619 |
|
|
{
|
1620 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1621 |
|
|
|
1622 |
|
|
/* put a brick on it... */
|
1623 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD)
|
1624 |
|
|
atmel_write16(dev, GCR, 0x0060);
|
1625 |
|
|
atmel_write16(dev, GCR, 0x0040);
|
1626 |
|
|
|
1627 |
|
|
del_timer_sync(&priv->management_timer);
|
1628 |
|
|
unregister_netdev(dev);
|
1629 |
|
|
remove_proc_entry("driver/atmel", NULL);
|
1630 |
|
|
free_irq(dev->irq, dev);
|
1631 |
|
|
kfree(priv->firmware);
|
1632 |
|
|
release_region(dev->base_addr, 32);
|
1633 |
|
|
free_netdev(dev);
|
1634 |
|
|
}
|
1635 |
|
|
|
1636 |
|
|
EXPORT_SYMBOL(stop_atmel_card);
|
1637 |
|
|
|
1638 |
|
|
static int atmel_set_essid(struct net_device *dev,
|
1639 |
|
|
struct iw_request_info *info,
|
1640 |
|
|
struct iw_point *dwrq,
|
1641 |
|
|
char *extra)
|
1642 |
|
|
{
|
1643 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1644 |
|
|
|
1645 |
|
|
/* Check if we asked for `any' */
|
1646 |
|
|
if(dwrq->flags == 0) {
|
1647 |
|
|
priv->connect_to_any_BSS = 1;
|
1648 |
|
|
} else {
|
1649 |
|
|
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
1650 |
|
|
|
1651 |
|
|
priv->connect_to_any_BSS = 0;
|
1652 |
|
|
|
1653 |
|
|
/* Check the size of the string */
|
1654 |
|
|
if (dwrq->length > MAX_SSID_LENGTH)
|
1655 |
|
|
return -E2BIG;
|
1656 |
|
|
if (index != 0)
|
1657 |
|
|
return -EINVAL;
|
1658 |
|
|
|
1659 |
|
|
memcpy(priv->new_SSID, extra, dwrq->length);
|
1660 |
|
|
priv->new_SSID_size = dwrq->length;
|
1661 |
|
|
}
|
1662 |
|
|
|
1663 |
|
|
return -EINPROGRESS;
|
1664 |
|
|
}
|
1665 |
|
|
|
1666 |
|
|
static int atmel_get_essid(struct net_device *dev,
|
1667 |
|
|
struct iw_request_info *info,
|
1668 |
|
|
struct iw_point *dwrq,
|
1669 |
|
|
char *extra)
|
1670 |
|
|
{
|
1671 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1672 |
|
|
|
1673 |
|
|
/* Get the current SSID */
|
1674 |
|
|
if (priv->new_SSID_size != 0) {
|
1675 |
|
|
memcpy(extra, priv->new_SSID, priv->new_SSID_size);
|
1676 |
|
|
dwrq->length = priv->new_SSID_size;
|
1677 |
|
|
} else {
|
1678 |
|
|
memcpy(extra, priv->SSID, priv->SSID_size);
|
1679 |
|
|
dwrq->length = priv->SSID_size;
|
1680 |
|
|
}
|
1681 |
|
|
|
1682 |
|
|
dwrq->flags = !priv->connect_to_any_BSS; /* active */
|
1683 |
|
|
|
1684 |
|
|
return 0;
|
1685 |
|
|
}
|
1686 |
|
|
|
1687 |
|
|
static int atmel_get_wap(struct net_device *dev,
|
1688 |
|
|
struct iw_request_info *info,
|
1689 |
|
|
struct sockaddr *awrq,
|
1690 |
|
|
char *extra)
|
1691 |
|
|
{
|
1692 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1693 |
|
|
memcpy(awrq->sa_data, priv->CurrentBSSID, 6);
|
1694 |
|
|
awrq->sa_family = ARPHRD_ETHER;
|
1695 |
|
|
|
1696 |
|
|
return 0;
|
1697 |
|
|
}
|
1698 |
|
|
|
1699 |
|
|
static int atmel_set_encode(struct net_device *dev,
|
1700 |
|
|
struct iw_request_info *info,
|
1701 |
|
|
struct iw_point *dwrq,
|
1702 |
|
|
char *extra)
|
1703 |
|
|
{
|
1704 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1705 |
|
|
|
1706 |
|
|
/* Basic checking: do we have a key to set ?
|
1707 |
|
|
* Note : with the new API, it's impossible to get a NULL pointer.
|
1708 |
|
|
* Therefore, we need to check a key size == 0 instead.
|
1709 |
|
|
* New version of iwconfig properly set the IW_ENCODE_NOKEY flag
|
1710 |
|
|
* when no key is present (only change flags), but older versions
|
1711 |
|
|
* don't do it. - Jean II */
|
1712 |
|
|
if (dwrq->length > 0) {
|
1713 |
|
|
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
1714 |
|
|
int current_index = priv->default_key;
|
1715 |
|
|
/* Check the size of the key */
|
1716 |
|
|
if (dwrq->length > 13) {
|
1717 |
|
|
return -EINVAL;
|
1718 |
|
|
}
|
1719 |
|
|
/* Check the index (none -> use current) */
|
1720 |
|
|
if (index < 0 || index >= 4)
|
1721 |
|
|
index = current_index;
|
1722 |
|
|
else
|
1723 |
|
|
priv->default_key = index;
|
1724 |
|
|
/* Set the length */
|
1725 |
|
|
if (dwrq->length > 5)
|
1726 |
|
|
priv->wep_key_len[index] = 13;
|
1727 |
|
|
else
|
1728 |
|
|
if (dwrq->length > 0)
|
1729 |
|
|
priv->wep_key_len[index] = 5;
|
1730 |
|
|
else
|
1731 |
|
|
/* Disable the key */
|
1732 |
|
|
priv->wep_key_len[index] = 0;
|
1733 |
|
|
/* Check if the key is not marked as invalid */
|
1734 |
|
|
if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
|
1735 |
|
|
/* Cleanup */
|
1736 |
|
|
memset(priv->wep_keys[index], 0, 13);
|
1737 |
|
|
/* Copy the key in the driver */
|
1738 |
|
|
memcpy(priv->wep_keys[index], extra, dwrq->length);
|
1739 |
|
|
}
|
1740 |
|
|
/* WE specify that if a valid key is set, encryption
|
1741 |
|
|
* should be enabled (user may turn it off later)
|
1742 |
|
|
* This is also how "iwconfig ethX key on" works */
|
1743 |
|
|
if (index == current_index &&
|
1744 |
|
|
priv->wep_key_len[index] > 0) {
|
1745 |
|
|
priv->wep_is_on = 1;
|
1746 |
|
|
priv->exclude_unencrypted = 1;
|
1747 |
|
|
if (priv->wep_key_len[index] > 5) {
|
1748 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
|
1749 |
|
|
priv->encryption_level = 2;
|
1750 |
|
|
} else {
|
1751 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
|
1752 |
|
|
priv->encryption_level = 1;
|
1753 |
|
|
}
|
1754 |
|
|
}
|
1755 |
|
|
} else {
|
1756 |
|
|
/* Do we want to just set the transmit key index ? */
|
1757 |
|
|
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
1758 |
|
|
if (index >= 0 && index < 4) {
|
1759 |
|
|
priv->default_key = index;
|
1760 |
|
|
} else
|
1761 |
|
|
/* Don't complain if only change the mode */
|
1762 |
|
|
if (!dwrq->flags & IW_ENCODE_MODE) {
|
1763 |
|
|
return -EINVAL;
|
1764 |
|
|
}
|
1765 |
|
|
}
|
1766 |
|
|
/* Read the flags */
|
1767 |
|
|
if (dwrq->flags & IW_ENCODE_DISABLED) {
|
1768 |
|
|
priv->wep_is_on = 0;
|
1769 |
|
|
priv->encryption_level = 0;
|
1770 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
|
1771 |
|
|
} else {
|
1772 |
|
|
priv->wep_is_on = 1;
|
1773 |
|
|
if (priv->wep_key_len[priv->default_key] > 5) {
|
1774 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
|
1775 |
|
|
priv->encryption_level = 2;
|
1776 |
|
|
} else {
|
1777 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
|
1778 |
|
|
priv->encryption_level = 1;
|
1779 |
|
|
}
|
1780 |
|
|
}
|
1781 |
|
|
if (dwrq->flags & IW_ENCODE_RESTRICTED)
|
1782 |
|
|
priv->exclude_unencrypted = 1;
|
1783 |
|
|
if(dwrq->flags & IW_ENCODE_OPEN)
|
1784 |
|
|
priv->exclude_unencrypted = 0;
|
1785 |
|
|
|
1786 |
|
|
return -EINPROGRESS; /* Call commit handler */
|
1787 |
|
|
}
|
1788 |
|
|
|
1789 |
|
|
static int atmel_get_encode(struct net_device *dev,
|
1790 |
|
|
struct iw_request_info *info,
|
1791 |
|
|
struct iw_point *dwrq,
|
1792 |
|
|
char *extra)
|
1793 |
|
|
{
|
1794 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1795 |
|
|
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
1796 |
|
|
|
1797 |
|
|
if (!priv->wep_is_on)
|
1798 |
|
|
dwrq->flags = IW_ENCODE_DISABLED;
|
1799 |
|
|
else {
|
1800 |
|
|
if (priv->exclude_unencrypted)
|
1801 |
|
|
dwrq->flags = IW_ENCODE_RESTRICTED;
|
1802 |
|
|
else
|
1803 |
|
|
dwrq->flags = IW_ENCODE_OPEN;
|
1804 |
|
|
}
|
1805 |
|
|
/* Which key do we want ? -1 -> tx index */
|
1806 |
|
|
if (index < 0 || index >= 4)
|
1807 |
|
|
index = priv->default_key;
|
1808 |
|
|
dwrq->flags |= index + 1;
|
1809 |
|
|
/* Copy the key to the user buffer */
|
1810 |
|
|
dwrq->length = priv->wep_key_len[index];
|
1811 |
|
|
if (dwrq->length > 16) {
|
1812 |
|
|
dwrq->length=0;
|
1813 |
|
|
} else {
|
1814 |
|
|
memset(extra, 0, 16);
|
1815 |
|
|
memcpy(extra, priv->wep_keys[index], dwrq->length);
|
1816 |
|
|
}
|
1817 |
|
|
|
1818 |
|
|
return 0;
|
1819 |
|
|
}
|
1820 |
|
|
|
1821 |
|
|
static int atmel_set_encodeext(struct net_device *dev,
|
1822 |
|
|
struct iw_request_info *info,
|
1823 |
|
|
union iwreq_data *wrqu,
|
1824 |
|
|
char *extra)
|
1825 |
|
|
{
|
1826 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1827 |
|
|
struct iw_point *encoding = &wrqu->encoding;
|
1828 |
|
|
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
|
1829 |
|
|
int idx, key_len, alg = ext->alg, set_key = 1;
|
1830 |
|
|
|
1831 |
|
|
/* Determine and validate the key index */
|
1832 |
|
|
idx = encoding->flags & IW_ENCODE_INDEX;
|
1833 |
|
|
if (idx) {
|
1834 |
|
|
if (idx < 1 || idx > WEP_KEYS)
|
1835 |
|
|
return -EINVAL;
|
1836 |
|
|
idx--;
|
1837 |
|
|
} else
|
1838 |
|
|
idx = priv->default_key;
|
1839 |
|
|
|
1840 |
|
|
if (encoding->flags & IW_ENCODE_DISABLED)
|
1841 |
|
|
alg = IW_ENCODE_ALG_NONE;
|
1842 |
|
|
|
1843 |
|
|
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
|
1844 |
|
|
priv->default_key = idx;
|
1845 |
|
|
set_key = ext->key_len > 0 ? 1 : 0;
|
1846 |
|
|
}
|
1847 |
|
|
|
1848 |
|
|
if (set_key) {
|
1849 |
|
|
/* Set the requested key first */
|
1850 |
|
|
switch (alg) {
|
1851 |
|
|
case IW_ENCODE_ALG_NONE:
|
1852 |
|
|
priv->wep_is_on = 0;
|
1853 |
|
|
priv->encryption_level = 0;
|
1854 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
|
1855 |
|
|
break;
|
1856 |
|
|
case IW_ENCODE_ALG_WEP:
|
1857 |
|
|
if (ext->key_len > 5) {
|
1858 |
|
|
priv->wep_key_len[idx] = 13;
|
1859 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
|
1860 |
|
|
priv->encryption_level = 2;
|
1861 |
|
|
} else if (ext->key_len > 0) {
|
1862 |
|
|
priv->wep_key_len[idx] = 5;
|
1863 |
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
|
1864 |
|
|
priv->encryption_level = 1;
|
1865 |
|
|
} else {
|
1866 |
|
|
return -EINVAL;
|
1867 |
|
|
}
|
1868 |
|
|
priv->wep_is_on = 1;
|
1869 |
|
|
memset(priv->wep_keys[idx], 0, 13);
|
1870 |
|
|
key_len = min ((int)ext->key_len, priv->wep_key_len[idx]);
|
1871 |
|
|
memcpy(priv->wep_keys[idx], ext->key, key_len);
|
1872 |
|
|
break;
|
1873 |
|
|
default:
|
1874 |
|
|
return -EINVAL;
|
1875 |
|
|
}
|
1876 |
|
|
}
|
1877 |
|
|
|
1878 |
|
|
return -EINPROGRESS;
|
1879 |
|
|
}
|
1880 |
|
|
|
1881 |
|
|
static int atmel_get_encodeext(struct net_device *dev,
|
1882 |
|
|
struct iw_request_info *info,
|
1883 |
|
|
union iwreq_data *wrqu,
|
1884 |
|
|
char *extra)
|
1885 |
|
|
{
|
1886 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1887 |
|
|
struct iw_point *encoding = &wrqu->encoding;
|
1888 |
|
|
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
|
1889 |
|
|
int idx, max_key_len;
|
1890 |
|
|
|
1891 |
|
|
max_key_len = encoding->length - sizeof(*ext);
|
1892 |
|
|
if (max_key_len < 0)
|
1893 |
|
|
return -EINVAL;
|
1894 |
|
|
|
1895 |
|
|
idx = encoding->flags & IW_ENCODE_INDEX;
|
1896 |
|
|
if (idx) {
|
1897 |
|
|
if (idx < 1 || idx > WEP_KEYS)
|
1898 |
|
|
return -EINVAL;
|
1899 |
|
|
idx--;
|
1900 |
|
|
} else
|
1901 |
|
|
idx = priv->default_key;
|
1902 |
|
|
|
1903 |
|
|
encoding->flags = idx + 1;
|
1904 |
|
|
memset(ext, 0, sizeof(*ext));
|
1905 |
|
|
|
1906 |
|
|
if (!priv->wep_is_on) {
|
1907 |
|
|
ext->alg = IW_ENCODE_ALG_NONE;
|
1908 |
|
|
ext->key_len = 0;
|
1909 |
|
|
encoding->flags |= IW_ENCODE_DISABLED;
|
1910 |
|
|
} else {
|
1911 |
|
|
if (priv->encryption_level > 0)
|
1912 |
|
|
ext->alg = IW_ENCODE_ALG_WEP;
|
1913 |
|
|
else
|
1914 |
|
|
return -EINVAL;
|
1915 |
|
|
|
1916 |
|
|
ext->key_len = priv->wep_key_len[idx];
|
1917 |
|
|
memcpy(ext->key, priv->wep_keys[idx], ext->key_len);
|
1918 |
|
|
encoding->flags |= IW_ENCODE_ENABLED;
|
1919 |
|
|
}
|
1920 |
|
|
|
1921 |
|
|
return 0;
|
1922 |
|
|
}
|
1923 |
|
|
|
1924 |
|
|
static int atmel_set_auth(struct net_device *dev,
|
1925 |
|
|
struct iw_request_info *info,
|
1926 |
|
|
union iwreq_data *wrqu, char *extra)
|
1927 |
|
|
{
|
1928 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1929 |
|
|
struct iw_param *param = &wrqu->param;
|
1930 |
|
|
|
1931 |
|
|
switch (param->flags & IW_AUTH_INDEX) {
|
1932 |
|
|
case IW_AUTH_WPA_VERSION:
|
1933 |
|
|
case IW_AUTH_CIPHER_PAIRWISE:
|
1934 |
|
|
case IW_AUTH_CIPHER_GROUP:
|
1935 |
|
|
case IW_AUTH_KEY_MGMT:
|
1936 |
|
|
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
|
1937 |
|
|
case IW_AUTH_PRIVACY_INVOKED:
|
1938 |
|
|
/*
|
1939 |
|
|
* atmel does not use these parameters
|
1940 |
|
|
*/
|
1941 |
|
|
break;
|
1942 |
|
|
|
1943 |
|
|
case IW_AUTH_DROP_UNENCRYPTED:
|
1944 |
|
|
priv->exclude_unencrypted = param->value ? 1 : 0;
|
1945 |
|
|
break;
|
1946 |
|
|
|
1947 |
|
|
case IW_AUTH_80211_AUTH_ALG: {
|
1948 |
|
|
if (param->value & IW_AUTH_ALG_SHARED_KEY) {
|
1949 |
|
|
priv->exclude_unencrypted = 1;
|
1950 |
|
|
} else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
|
1951 |
|
|
priv->exclude_unencrypted = 0;
|
1952 |
|
|
} else
|
1953 |
|
|
return -EINVAL;
|
1954 |
|
|
break;
|
1955 |
|
|
}
|
1956 |
|
|
|
1957 |
|
|
case IW_AUTH_WPA_ENABLED:
|
1958 |
|
|
/* Silently accept disable of WPA */
|
1959 |
|
|
if (param->value > 0)
|
1960 |
|
|
return -EOPNOTSUPP;
|
1961 |
|
|
break;
|
1962 |
|
|
|
1963 |
|
|
default:
|
1964 |
|
|
return -EOPNOTSUPP;
|
1965 |
|
|
}
|
1966 |
|
|
return -EINPROGRESS;
|
1967 |
|
|
}
|
1968 |
|
|
|
1969 |
|
|
static int atmel_get_auth(struct net_device *dev,
|
1970 |
|
|
struct iw_request_info *info,
|
1971 |
|
|
union iwreq_data *wrqu, char *extra)
|
1972 |
|
|
{
|
1973 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
1974 |
|
|
struct iw_param *param = &wrqu->param;
|
1975 |
|
|
|
1976 |
|
|
switch (param->flags & IW_AUTH_INDEX) {
|
1977 |
|
|
case IW_AUTH_DROP_UNENCRYPTED:
|
1978 |
|
|
param->value = priv->exclude_unencrypted;
|
1979 |
|
|
break;
|
1980 |
|
|
|
1981 |
|
|
case IW_AUTH_80211_AUTH_ALG:
|
1982 |
|
|
if (priv->exclude_unencrypted == 1)
|
1983 |
|
|
param->value = IW_AUTH_ALG_SHARED_KEY;
|
1984 |
|
|
else
|
1985 |
|
|
param->value = IW_AUTH_ALG_OPEN_SYSTEM;
|
1986 |
|
|
break;
|
1987 |
|
|
|
1988 |
|
|
case IW_AUTH_WPA_ENABLED:
|
1989 |
|
|
param->value = 0;
|
1990 |
|
|
break;
|
1991 |
|
|
|
1992 |
|
|
default:
|
1993 |
|
|
return -EOPNOTSUPP;
|
1994 |
|
|
}
|
1995 |
|
|
return 0;
|
1996 |
|
|
}
|
1997 |
|
|
|
1998 |
|
|
|
1999 |
|
|
static int atmel_get_name(struct net_device *dev,
|
2000 |
|
|
struct iw_request_info *info,
|
2001 |
|
|
char *cwrq,
|
2002 |
|
|
char *extra)
|
2003 |
|
|
{
|
2004 |
|
|
strcpy(cwrq, "IEEE 802.11-DS");
|
2005 |
|
|
return 0;
|
2006 |
|
|
}
|
2007 |
|
|
|
2008 |
|
|
static int atmel_set_rate(struct net_device *dev,
|
2009 |
|
|
struct iw_request_info *info,
|
2010 |
|
|
struct iw_param *vwrq,
|
2011 |
|
|
char *extra)
|
2012 |
|
|
{
|
2013 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2014 |
|
|
|
2015 |
|
|
if (vwrq->fixed == 0) {
|
2016 |
|
|
priv->tx_rate = 3;
|
2017 |
|
|
priv->auto_tx_rate = 1;
|
2018 |
|
|
} else {
|
2019 |
|
|
priv->auto_tx_rate = 0;
|
2020 |
|
|
|
2021 |
|
|
/* Which type of value ? */
|
2022 |
|
|
if ((vwrq->value < 4) && (vwrq->value >= 0)) {
|
2023 |
|
|
/* Setting by rate index */
|
2024 |
|
|
priv->tx_rate = vwrq->value;
|
2025 |
|
|
} else {
|
2026 |
|
|
/* Setting by frequency value */
|
2027 |
|
|
switch (vwrq->value) {
|
2028 |
|
|
case 1000000: priv->tx_rate = 0; break;
|
2029 |
|
|
case 2000000: priv->tx_rate = 1; break;
|
2030 |
|
|
case 5500000: priv->tx_rate = 2; break;
|
2031 |
|
|
case 11000000: priv->tx_rate = 3; break;
|
2032 |
|
|
default: return -EINVAL;
|
2033 |
|
|
}
|
2034 |
|
|
}
|
2035 |
|
|
}
|
2036 |
|
|
|
2037 |
|
|
return -EINPROGRESS;
|
2038 |
|
|
}
|
2039 |
|
|
|
2040 |
|
|
static int atmel_set_mode(struct net_device *dev,
|
2041 |
|
|
struct iw_request_info *info,
|
2042 |
|
|
__u32 *uwrq,
|
2043 |
|
|
char *extra)
|
2044 |
|
|
{
|
2045 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2046 |
|
|
|
2047 |
|
|
if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA)
|
2048 |
|
|
return -EINVAL;
|
2049 |
|
|
|
2050 |
|
|
priv->operating_mode = *uwrq;
|
2051 |
|
|
return -EINPROGRESS;
|
2052 |
|
|
}
|
2053 |
|
|
|
2054 |
|
|
static int atmel_get_mode(struct net_device *dev,
|
2055 |
|
|
struct iw_request_info *info,
|
2056 |
|
|
__u32 *uwrq,
|
2057 |
|
|
char *extra)
|
2058 |
|
|
{
|
2059 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2060 |
|
|
|
2061 |
|
|
*uwrq = priv->operating_mode;
|
2062 |
|
|
return 0;
|
2063 |
|
|
}
|
2064 |
|
|
|
2065 |
|
|
static int atmel_get_rate(struct net_device *dev,
|
2066 |
|
|
struct iw_request_info *info,
|
2067 |
|
|
struct iw_param *vwrq,
|
2068 |
|
|
char *extra)
|
2069 |
|
|
{
|
2070 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2071 |
|
|
|
2072 |
|
|
if (priv->auto_tx_rate) {
|
2073 |
|
|
vwrq->fixed = 0;
|
2074 |
|
|
vwrq->value = 11000000;
|
2075 |
|
|
} else {
|
2076 |
|
|
vwrq->fixed = 1;
|
2077 |
|
|
switch(priv->tx_rate) {
|
2078 |
|
|
case 0: vwrq->value = 1000000; break;
|
2079 |
|
|
case 1: vwrq->value = 2000000; break;
|
2080 |
|
|
case 2: vwrq->value = 5500000; break;
|
2081 |
|
|
case 3: vwrq->value = 11000000; break;
|
2082 |
|
|
}
|
2083 |
|
|
}
|
2084 |
|
|
return 0;
|
2085 |
|
|
}
|
2086 |
|
|
|
2087 |
|
|
static int atmel_set_power(struct net_device *dev,
|
2088 |
|
|
struct iw_request_info *info,
|
2089 |
|
|
struct iw_param *vwrq,
|
2090 |
|
|
char *extra)
|
2091 |
|
|
{
|
2092 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2093 |
|
|
priv->power_mode = vwrq->disabled ? 0 : 1;
|
2094 |
|
|
return -EINPROGRESS;
|
2095 |
|
|
}
|
2096 |
|
|
|
2097 |
|
|
static int atmel_get_power(struct net_device *dev,
|
2098 |
|
|
struct iw_request_info *info,
|
2099 |
|
|
struct iw_param *vwrq,
|
2100 |
|
|
char *extra)
|
2101 |
|
|
{
|
2102 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2103 |
|
|
vwrq->disabled = priv->power_mode ? 0 : 1;
|
2104 |
|
|
vwrq->flags = IW_POWER_ON;
|
2105 |
|
|
return 0;
|
2106 |
|
|
}
|
2107 |
|
|
|
2108 |
|
|
static int atmel_set_retry(struct net_device *dev,
|
2109 |
|
|
struct iw_request_info *info,
|
2110 |
|
|
struct iw_param *vwrq,
|
2111 |
|
|
char *extra)
|
2112 |
|
|
{
|
2113 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2114 |
|
|
|
2115 |
|
|
if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
|
2116 |
|
|
if (vwrq->flags & IW_RETRY_LONG)
|
2117 |
|
|
priv->long_retry = vwrq->value;
|
2118 |
|
|
else if (vwrq->flags & IW_RETRY_SHORT)
|
2119 |
|
|
priv->short_retry = vwrq->value;
|
2120 |
|
|
else {
|
2121 |
|
|
/* No modifier : set both */
|
2122 |
|
|
priv->long_retry = vwrq->value;
|
2123 |
|
|
priv->short_retry = vwrq->value;
|
2124 |
|
|
}
|
2125 |
|
|
return -EINPROGRESS;
|
2126 |
|
|
}
|
2127 |
|
|
|
2128 |
|
|
return -EINVAL;
|
2129 |
|
|
}
|
2130 |
|
|
|
2131 |
|
|
static int atmel_get_retry(struct net_device *dev,
|
2132 |
|
|
struct iw_request_info *info,
|
2133 |
|
|
struct iw_param *vwrq,
|
2134 |
|
|
char *extra)
|
2135 |
|
|
{
|
2136 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2137 |
|
|
|
2138 |
|
|
vwrq->disabled = 0; /* Can't be disabled */
|
2139 |
|
|
|
2140 |
|
|
/* Note : by default, display the short retry number */
|
2141 |
|
|
if (vwrq->flags & IW_RETRY_LONG) {
|
2142 |
|
|
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
2143 |
|
|
vwrq->value = priv->long_retry;
|
2144 |
|
|
} else {
|
2145 |
|
|
vwrq->flags = IW_RETRY_LIMIT;
|
2146 |
|
|
vwrq->value = priv->short_retry;
|
2147 |
|
|
if (priv->long_retry != priv->short_retry)
|
2148 |
|
|
vwrq->flags |= IW_RETRY_SHORT;
|
2149 |
|
|
}
|
2150 |
|
|
|
2151 |
|
|
return 0;
|
2152 |
|
|
}
|
2153 |
|
|
|
2154 |
|
|
static int atmel_set_rts(struct net_device *dev,
|
2155 |
|
|
struct iw_request_info *info,
|
2156 |
|
|
struct iw_param *vwrq,
|
2157 |
|
|
char *extra)
|
2158 |
|
|
{
|
2159 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2160 |
|
|
int rthr = vwrq->value;
|
2161 |
|
|
|
2162 |
|
|
if (vwrq->disabled)
|
2163 |
|
|
rthr = 2347;
|
2164 |
|
|
if ((rthr < 0) || (rthr > 2347)) {
|
2165 |
|
|
return -EINVAL;
|
2166 |
|
|
}
|
2167 |
|
|
priv->rts_threshold = rthr;
|
2168 |
|
|
|
2169 |
|
|
return -EINPROGRESS; /* Call commit handler */
|
2170 |
|
|
}
|
2171 |
|
|
|
2172 |
|
|
static int atmel_get_rts(struct net_device *dev,
|
2173 |
|
|
struct iw_request_info *info,
|
2174 |
|
|
struct iw_param *vwrq,
|
2175 |
|
|
char *extra)
|
2176 |
|
|
{
|
2177 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2178 |
|
|
|
2179 |
|
|
vwrq->value = priv->rts_threshold;
|
2180 |
|
|
vwrq->disabled = (vwrq->value >= 2347);
|
2181 |
|
|
vwrq->fixed = 1;
|
2182 |
|
|
|
2183 |
|
|
return 0;
|
2184 |
|
|
}
|
2185 |
|
|
|
2186 |
|
|
static int atmel_set_frag(struct net_device *dev,
|
2187 |
|
|
struct iw_request_info *info,
|
2188 |
|
|
struct iw_param *vwrq,
|
2189 |
|
|
char *extra)
|
2190 |
|
|
{
|
2191 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2192 |
|
|
int fthr = vwrq->value;
|
2193 |
|
|
|
2194 |
|
|
if (vwrq->disabled)
|
2195 |
|
|
fthr = 2346;
|
2196 |
|
|
if ((fthr < 256) || (fthr > 2346)) {
|
2197 |
|
|
return -EINVAL;
|
2198 |
|
|
}
|
2199 |
|
|
fthr &= ~0x1; /* Get an even value - is it really needed ??? */
|
2200 |
|
|
priv->frag_threshold = fthr;
|
2201 |
|
|
|
2202 |
|
|
return -EINPROGRESS; /* Call commit handler */
|
2203 |
|
|
}
|
2204 |
|
|
|
2205 |
|
|
static int atmel_get_frag(struct net_device *dev,
|
2206 |
|
|
struct iw_request_info *info,
|
2207 |
|
|
struct iw_param *vwrq,
|
2208 |
|
|
char *extra)
|
2209 |
|
|
{
|
2210 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2211 |
|
|
|
2212 |
|
|
vwrq->value = priv->frag_threshold;
|
2213 |
|
|
vwrq->disabled = (vwrq->value >= 2346);
|
2214 |
|
|
vwrq->fixed = 1;
|
2215 |
|
|
|
2216 |
|
|
return 0;
|
2217 |
|
|
}
|
2218 |
|
|
|
2219 |
|
|
static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
|
2220 |
|
|
2447, 2452, 2457, 2462, 2467, 2472, 2484 };
|
2221 |
|
|
|
2222 |
|
|
static int atmel_set_freq(struct net_device *dev,
|
2223 |
|
|
struct iw_request_info *info,
|
2224 |
|
|
struct iw_freq *fwrq,
|
2225 |
|
|
char *extra)
|
2226 |
|
|
{
|
2227 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2228 |
|
|
int rc = -EINPROGRESS; /* Call commit handler */
|
2229 |
|
|
|
2230 |
|
|
/* If setting by frequency, convert to a channel */
|
2231 |
|
|
if ((fwrq->e == 1) &&
|
2232 |
|
|
(fwrq->m >= (int) 241200000) &&
|
2233 |
|
|
(fwrq->m <= (int) 248700000)) {
|
2234 |
|
|
int f = fwrq->m / 100000;
|
2235 |
|
|
int c = 0;
|
2236 |
|
|
while ((c < 14) && (f != frequency_list[c]))
|
2237 |
|
|
c++;
|
2238 |
|
|
/* Hack to fall through... */
|
2239 |
|
|
fwrq->e = 0;
|
2240 |
|
|
fwrq->m = c + 1;
|
2241 |
|
|
}
|
2242 |
|
|
/* Setting by channel number */
|
2243 |
|
|
if ((fwrq->m > 1000) || (fwrq->e > 0))
|
2244 |
|
|
rc = -EOPNOTSUPP;
|
2245 |
|
|
else {
|
2246 |
|
|
int channel = fwrq->m;
|
2247 |
|
|
if (atmel_validate_channel(priv, channel) == 0) {
|
2248 |
|
|
priv->channel = channel;
|
2249 |
|
|
} else {
|
2250 |
|
|
rc = -EINVAL;
|
2251 |
|
|
}
|
2252 |
|
|
}
|
2253 |
|
|
return rc;
|
2254 |
|
|
}
|
2255 |
|
|
|
2256 |
|
|
static int atmel_get_freq(struct net_device *dev,
|
2257 |
|
|
struct iw_request_info *info,
|
2258 |
|
|
struct iw_freq *fwrq,
|
2259 |
|
|
char *extra)
|
2260 |
|
|
{
|
2261 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2262 |
|
|
|
2263 |
|
|
fwrq->m = priv->channel;
|
2264 |
|
|
fwrq->e = 0;
|
2265 |
|
|
return 0;
|
2266 |
|
|
}
|
2267 |
|
|
|
2268 |
|
|
static int atmel_set_scan(struct net_device *dev,
|
2269 |
|
|
struct iw_request_info *info,
|
2270 |
|
|
struct iw_param *vwrq,
|
2271 |
|
|
char *extra)
|
2272 |
|
|
{
|
2273 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2274 |
|
|
unsigned long flags;
|
2275 |
|
|
|
2276 |
|
|
/* Note : you may have realised that, as this is a SET operation,
|
2277 |
|
|
* this is privileged and therefore a normal user can't
|
2278 |
|
|
* perform scanning.
|
2279 |
|
|
* This is not an error, while the device perform scanning,
|
2280 |
|
|
* traffic doesn't flow, so it's a perfect DoS...
|
2281 |
|
|
* Jean II */
|
2282 |
|
|
|
2283 |
|
|
if (priv->station_state == STATION_STATE_DOWN)
|
2284 |
|
|
return -EAGAIN;
|
2285 |
|
|
|
2286 |
|
|
/* Timeout old surveys. */
|
2287 |
|
|
if ((jiffies - priv->last_survey) > (20 * HZ))
|
2288 |
|
|
priv->site_survey_state = SITE_SURVEY_IDLE;
|
2289 |
|
|
priv->last_survey = jiffies;
|
2290 |
|
|
|
2291 |
|
|
/* Initiate a scan command */
|
2292 |
|
|
if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS)
|
2293 |
|
|
return -EBUSY;
|
2294 |
|
|
|
2295 |
|
|
del_timer_sync(&priv->management_timer);
|
2296 |
|
|
spin_lock_irqsave(&priv->irqlock, flags);
|
2297 |
|
|
|
2298 |
|
|
priv->site_survey_state = SITE_SURVEY_IN_PROGRESS;
|
2299 |
|
|
priv->fast_scan = 0;
|
2300 |
|
|
atmel_scan(priv, 0);
|
2301 |
|
|
spin_unlock_irqrestore(&priv->irqlock, flags);
|
2302 |
|
|
|
2303 |
|
|
return 0;
|
2304 |
|
|
}
|
2305 |
|
|
|
2306 |
|
|
static int atmel_get_scan(struct net_device *dev,
|
2307 |
|
|
struct iw_request_info *info,
|
2308 |
|
|
struct iw_point *dwrq,
|
2309 |
|
|
char *extra)
|
2310 |
|
|
{
|
2311 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2312 |
|
|
int i;
|
2313 |
|
|
char *current_ev = extra;
|
2314 |
|
|
struct iw_event iwe;
|
2315 |
|
|
|
2316 |
|
|
if (priv->site_survey_state != SITE_SURVEY_COMPLETED)
|
2317 |
|
|
return -EAGAIN;
|
2318 |
|
|
|
2319 |
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
2320 |
|
|
iwe.cmd = SIOCGIWAP;
|
2321 |
|
|
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
2322 |
|
|
memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6);
|
2323 |
|
|
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN);
|
2324 |
|
|
|
2325 |
|
|
iwe.u.data.length = priv->BSSinfo[i].SSIDsize;
|
2326 |
|
|
if (iwe.u.data.length > 32)
|
2327 |
|
|
iwe.u.data.length = 32;
|
2328 |
|
|
iwe.cmd = SIOCGIWESSID;
|
2329 |
|
|
iwe.u.data.flags = 1;
|
2330 |
|
|
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID);
|
2331 |
|
|
|
2332 |
|
|
iwe.cmd = SIOCGIWMODE;
|
2333 |
|
|
iwe.u.mode = priv->BSSinfo[i].BSStype;
|
2334 |
|
|
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN);
|
2335 |
|
|
|
2336 |
|
|
iwe.cmd = SIOCGIWFREQ;
|
2337 |
|
|
iwe.u.freq.m = priv->BSSinfo[i].channel;
|
2338 |
|
|
iwe.u.freq.e = 0;
|
2339 |
|
|
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN);
|
2340 |
|
|
|
2341 |
|
|
/* Add quality statistics */
|
2342 |
|
|
iwe.cmd = IWEVQUAL;
|
2343 |
|
|
iwe.u.qual.level = priv->BSSinfo[i].RSSI;
|
2344 |
|
|
iwe.u.qual.qual = iwe.u.qual.level;
|
2345 |
|
|
/* iwe.u.qual.noise = SOMETHING */
|
2346 |
|
|
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA , &iwe, IW_EV_QUAL_LEN);
|
2347 |
|
|
|
2348 |
|
|
|
2349 |
|
|
iwe.cmd = SIOCGIWENCODE;
|
2350 |
|
|
if (priv->BSSinfo[i].UsingWEP)
|
2351 |
|
|
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
|
2352 |
|
|
else
|
2353 |
|
|
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
2354 |
|
|
iwe.u.data.length = 0;
|
2355 |
|
|
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL);
|
2356 |
|
|
}
|
2357 |
|
|
|
2358 |
|
|
/* Length of data */
|
2359 |
|
|
dwrq->length = (current_ev - extra);
|
2360 |
|
|
dwrq->flags = 0;
|
2361 |
|
|
|
2362 |
|
|
return 0;
|
2363 |
|
|
}
|
2364 |
|
|
|
2365 |
|
|
static int atmel_get_range(struct net_device *dev,
|
2366 |
|
|
struct iw_request_info *info,
|
2367 |
|
|
struct iw_point *dwrq,
|
2368 |
|
|
char *extra)
|
2369 |
|
|
{
|
2370 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2371 |
|
|
struct iw_range *range = (struct iw_range *) extra;
|
2372 |
|
|
int k, i, j;
|
2373 |
|
|
|
2374 |
|
|
dwrq->length = sizeof(struct iw_range);
|
2375 |
|
|
memset(range, 0, sizeof(struct iw_range));
|
2376 |
|
|
range->min_nwid = 0x0000;
|
2377 |
|
|
range->max_nwid = 0x0000;
|
2378 |
|
|
range->num_channels = 0;
|
2379 |
|
|
for (j = 0; j < ARRAY_SIZE(channel_table); j++)
|
2380 |
|
|
if (priv->reg_domain == channel_table[j].reg_domain) {
|
2381 |
|
|
range->num_channels = channel_table[j].max - channel_table[j].min + 1;
|
2382 |
|
|
break;
|
2383 |
|
|
}
|
2384 |
|
|
if (range->num_channels != 0) {
|
2385 |
|
|
for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) {
|
2386 |
|
|
range->freq[k].i = i; /* List index */
|
2387 |
|
|
range->freq[k].m = frequency_list[i - 1] * 100000;
|
2388 |
|
|
range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
|
2389 |
|
|
}
|
2390 |
|
|
range->num_frequency = k;
|
2391 |
|
|
}
|
2392 |
|
|
|
2393 |
|
|
range->max_qual.qual = 100;
|
2394 |
|
|
range->max_qual.level = 100;
|
2395 |
|
|
range->max_qual.noise = 0;
|
2396 |
|
|
range->max_qual.updated = IW_QUAL_NOISE_INVALID;
|
2397 |
|
|
|
2398 |
|
|
range->avg_qual.qual = 50;
|
2399 |
|
|
range->avg_qual.level = 50;
|
2400 |
|
|
range->avg_qual.noise = 0;
|
2401 |
|
|
range->avg_qual.updated = IW_QUAL_NOISE_INVALID;
|
2402 |
|
|
|
2403 |
|
|
range->sensitivity = 0;
|
2404 |
|
|
|
2405 |
|
|
range->bitrate[0] = 1000000;
|
2406 |
|
|
range->bitrate[1] = 2000000;
|
2407 |
|
|
range->bitrate[2] = 5500000;
|
2408 |
|
|
range->bitrate[3] = 11000000;
|
2409 |
|
|
range->num_bitrates = 4;
|
2410 |
|
|
|
2411 |
|
|
range->min_rts = 0;
|
2412 |
|
|
range->max_rts = 2347;
|
2413 |
|
|
range->min_frag = 256;
|
2414 |
|
|
range->max_frag = 2346;
|
2415 |
|
|
|
2416 |
|
|
range->encoding_size[0] = 5;
|
2417 |
|
|
range->encoding_size[1] = 13;
|
2418 |
|
|
range->num_encoding_sizes = 2;
|
2419 |
|
|
range->max_encoding_tokens = 4;
|
2420 |
|
|
|
2421 |
|
|
range->pmp_flags = IW_POWER_ON;
|
2422 |
|
|
range->pmt_flags = IW_POWER_ON;
|
2423 |
|
|
range->pm_capa = 0;
|
2424 |
|
|
|
2425 |
|
|
range->we_version_source = WIRELESS_EXT;
|
2426 |
|
|
range->we_version_compiled = WIRELESS_EXT;
|
2427 |
|
|
range->retry_capa = IW_RETRY_LIMIT ;
|
2428 |
|
|
range->retry_flags = IW_RETRY_LIMIT;
|
2429 |
|
|
range->r_time_flags = 0;
|
2430 |
|
|
range->min_retry = 1;
|
2431 |
|
|
range->max_retry = 65535;
|
2432 |
|
|
|
2433 |
|
|
return 0;
|
2434 |
|
|
}
|
2435 |
|
|
|
2436 |
|
|
static int atmel_set_wap(struct net_device *dev,
|
2437 |
|
|
struct iw_request_info *info,
|
2438 |
|
|
struct sockaddr *awrq,
|
2439 |
|
|
char *extra)
|
2440 |
|
|
{
|
2441 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2442 |
|
|
int i;
|
2443 |
|
|
static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
2444 |
|
|
static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
2445 |
|
|
unsigned long flags;
|
2446 |
|
|
|
2447 |
|
|
if (awrq->sa_family != ARPHRD_ETHER)
|
2448 |
|
|
return -EINVAL;
|
2449 |
|
|
|
2450 |
|
|
if (!memcmp(any, awrq->sa_data, 6) ||
|
2451 |
|
|
!memcmp(off, awrq->sa_data, 6)) {
|
2452 |
|
|
del_timer_sync(&priv->management_timer);
|
2453 |
|
|
spin_lock_irqsave(&priv->irqlock, flags);
|
2454 |
|
|
atmel_scan(priv, 1);
|
2455 |
|
|
spin_unlock_irqrestore(&priv->irqlock, flags);
|
2456 |
|
|
return 0;
|
2457 |
|
|
}
|
2458 |
|
|
|
2459 |
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
2460 |
|
|
if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) {
|
2461 |
|
|
if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) {
|
2462 |
|
|
return -EINVAL;
|
2463 |
|
|
} else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) {
|
2464 |
|
|
return -EINVAL;
|
2465 |
|
|
} else {
|
2466 |
|
|
del_timer_sync(&priv->management_timer);
|
2467 |
|
|
spin_lock_irqsave(&priv->irqlock, flags);
|
2468 |
|
|
atmel_join_bss(priv, i);
|
2469 |
|
|
spin_unlock_irqrestore(&priv->irqlock, flags);
|
2470 |
|
|
return 0;
|
2471 |
|
|
}
|
2472 |
|
|
}
|
2473 |
|
|
}
|
2474 |
|
|
|
2475 |
|
|
return -EINVAL;
|
2476 |
|
|
}
|
2477 |
|
|
|
2478 |
|
|
static int atmel_config_commit(struct net_device *dev,
|
2479 |
|
|
struct iw_request_info *info, /* NULL */
|
2480 |
|
|
void *zwrq, /* NULL */
|
2481 |
|
|
char *extra) /* NULL */
|
2482 |
|
|
{
|
2483 |
|
|
return atmel_open(dev);
|
2484 |
|
|
}
|
2485 |
|
|
|
2486 |
|
|
static const iw_handler atmel_handler[] =
|
2487 |
|
|
{
|
2488 |
|
|
(iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */
|
2489 |
|
|
(iw_handler) atmel_get_name, /* SIOCGIWNAME */
|
2490 |
|
|
(iw_handler) NULL, /* SIOCSIWNWID */
|
2491 |
|
|
(iw_handler) NULL, /* SIOCGIWNWID */
|
2492 |
|
|
(iw_handler) atmel_set_freq, /* SIOCSIWFREQ */
|
2493 |
|
|
(iw_handler) atmel_get_freq, /* SIOCGIWFREQ */
|
2494 |
|
|
(iw_handler) atmel_set_mode, /* SIOCSIWMODE */
|
2495 |
|
|
(iw_handler) atmel_get_mode, /* SIOCGIWMODE */
|
2496 |
|
|
(iw_handler) NULL, /* SIOCSIWSENS */
|
2497 |
|
|
(iw_handler) NULL, /* SIOCGIWSENS */
|
2498 |
|
|
(iw_handler) NULL, /* SIOCSIWRANGE */
|
2499 |
|
|
(iw_handler) atmel_get_range, /* SIOCGIWRANGE */
|
2500 |
|
|
(iw_handler) NULL, /* SIOCSIWPRIV */
|
2501 |
|
|
(iw_handler) NULL, /* SIOCGIWPRIV */
|
2502 |
|
|
(iw_handler) NULL, /* SIOCSIWSTATS */
|
2503 |
|
|
(iw_handler) NULL, /* SIOCGIWSTATS */
|
2504 |
|
|
(iw_handler) NULL, /* SIOCSIWSPY */
|
2505 |
|
|
(iw_handler) NULL, /* SIOCGIWSPY */
|
2506 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2507 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2508 |
|
|
(iw_handler) atmel_set_wap, /* SIOCSIWAP */
|
2509 |
|
|
(iw_handler) atmel_get_wap, /* SIOCGIWAP */
|
2510 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2511 |
|
|
(iw_handler) NULL, /* SIOCGIWAPLIST */
|
2512 |
|
|
(iw_handler) atmel_set_scan, /* SIOCSIWSCAN */
|
2513 |
|
|
(iw_handler) atmel_get_scan, /* SIOCGIWSCAN */
|
2514 |
|
|
(iw_handler) atmel_set_essid, /* SIOCSIWESSID */
|
2515 |
|
|
(iw_handler) atmel_get_essid, /* SIOCGIWESSID */
|
2516 |
|
|
(iw_handler) NULL, /* SIOCSIWNICKN */
|
2517 |
|
|
(iw_handler) NULL, /* SIOCGIWNICKN */
|
2518 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2519 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2520 |
|
|
(iw_handler) atmel_set_rate, /* SIOCSIWRATE */
|
2521 |
|
|
(iw_handler) atmel_get_rate, /* SIOCGIWRATE */
|
2522 |
|
|
(iw_handler) atmel_set_rts, /* SIOCSIWRTS */
|
2523 |
|
|
(iw_handler) atmel_get_rts, /* SIOCGIWRTS */
|
2524 |
|
|
(iw_handler) atmel_set_frag, /* SIOCSIWFRAG */
|
2525 |
|
|
(iw_handler) atmel_get_frag, /* SIOCGIWFRAG */
|
2526 |
|
|
(iw_handler) NULL, /* SIOCSIWTXPOW */
|
2527 |
|
|
(iw_handler) NULL, /* SIOCGIWTXPOW */
|
2528 |
|
|
(iw_handler) atmel_set_retry, /* SIOCSIWRETRY */
|
2529 |
|
|
(iw_handler) atmel_get_retry, /* SIOCGIWRETRY */
|
2530 |
|
|
(iw_handler) atmel_set_encode, /* SIOCSIWENCODE */
|
2531 |
|
|
(iw_handler) atmel_get_encode, /* SIOCGIWENCODE */
|
2532 |
|
|
(iw_handler) atmel_set_power, /* SIOCSIWPOWER */
|
2533 |
|
|
(iw_handler) atmel_get_power, /* SIOCGIWPOWER */
|
2534 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2535 |
|
|
(iw_handler) NULL, /* -- hole -- */
|
2536 |
|
|
(iw_handler) NULL, /* SIOCSIWGENIE */
|
2537 |
|
|
(iw_handler) NULL, /* SIOCGIWGENIE */
|
2538 |
|
|
(iw_handler) atmel_set_auth, /* SIOCSIWAUTH */
|
2539 |
|
|
(iw_handler) atmel_get_auth, /* SIOCGIWAUTH */
|
2540 |
|
|
(iw_handler) atmel_set_encodeext, /* SIOCSIWENCODEEXT */
|
2541 |
|
|
(iw_handler) atmel_get_encodeext, /* SIOCGIWENCODEEXT */
|
2542 |
|
|
(iw_handler) NULL, /* SIOCSIWPMKSA */
|
2543 |
|
|
};
|
2544 |
|
|
|
2545 |
|
|
static const iw_handler atmel_private_handler[] =
|
2546 |
|
|
{
|
2547 |
|
|
NULL, /* SIOCIWFIRSTPRIV */
|
2548 |
|
|
};
|
2549 |
|
|
|
2550 |
|
|
typedef struct atmel_priv_ioctl {
|
2551 |
|
|
char id[32];
|
2552 |
|
|
unsigned char __user *data;
|
2553 |
|
|
unsigned short len;
|
2554 |
|
|
} atmel_priv_ioctl;
|
2555 |
|
|
|
2556 |
|
|
#define ATMELFWL SIOCIWFIRSTPRIV
|
2557 |
|
|
#define ATMELIDIFC ATMELFWL + 1
|
2558 |
|
|
#define ATMELRD ATMELFWL + 2
|
2559 |
|
|
#define ATMELMAGIC 0x51807
|
2560 |
|
|
#define REGDOMAINSZ 20
|
2561 |
|
|
|
2562 |
|
|
static const struct iw_priv_args atmel_private_args[] = {
|
2563 |
|
|
{
|
2564 |
|
|
.cmd = ATMELFWL,
|
2565 |
|
|
.set_args = IW_PRIV_TYPE_BYTE
|
2566 |
|
|
| IW_PRIV_SIZE_FIXED
|
2567 |
|
|
| sizeof (atmel_priv_ioctl),
|
2568 |
|
|
.get_args = IW_PRIV_TYPE_NONE,
|
2569 |
|
|
.name = "atmelfwl"
|
2570 |
|
|
}, {
|
2571 |
|
|
.cmd = ATMELIDIFC,
|
2572 |
|
|
.set_args = IW_PRIV_TYPE_NONE,
|
2573 |
|
|
.get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
|
2574 |
|
|
.name = "atmelidifc"
|
2575 |
|
|
}, {
|
2576 |
|
|
.cmd = ATMELRD,
|
2577 |
|
|
.set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ,
|
2578 |
|
|
.get_args = IW_PRIV_TYPE_NONE,
|
2579 |
|
|
.name = "regdomain"
|
2580 |
|
|
},
|
2581 |
|
|
};
|
2582 |
|
|
|
2583 |
|
|
static const struct iw_handler_def atmel_handler_def =
|
2584 |
|
|
{
|
2585 |
|
|
.num_standard = ARRAY_SIZE(atmel_handler),
|
2586 |
|
|
.num_private = ARRAY_SIZE(atmel_private_handler),
|
2587 |
|
|
.num_private_args = ARRAY_SIZE(atmel_private_args),
|
2588 |
|
|
.standard = (iw_handler *) atmel_handler,
|
2589 |
|
|
.private = (iw_handler *) atmel_private_handler,
|
2590 |
|
|
.private_args = (struct iw_priv_args *) atmel_private_args,
|
2591 |
|
|
.get_wireless_stats = atmel_get_wireless_stats
|
2592 |
|
|
};
|
2593 |
|
|
|
2594 |
|
|
static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
2595 |
|
|
{
|
2596 |
|
|
int i, rc = 0;
|
2597 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
2598 |
|
|
atmel_priv_ioctl com;
|
2599 |
|
|
struct iwreq *wrq = (struct iwreq *) rq;
|
2600 |
|
|
unsigned char *new_firmware;
|
2601 |
|
|
char domain[REGDOMAINSZ + 1];
|
2602 |
|
|
|
2603 |
|
|
switch (cmd) {
|
2604 |
|
|
case ATMELIDIFC:
|
2605 |
|
|
wrq->u.param.value = ATMELMAGIC;
|
2606 |
|
|
break;
|
2607 |
|
|
|
2608 |
|
|
case ATMELFWL:
|
2609 |
|
|
if (copy_from_user(&com, rq->ifr_data, sizeof(com))) {
|
2610 |
|
|
rc = -EFAULT;
|
2611 |
|
|
break;
|
2612 |
|
|
}
|
2613 |
|
|
|
2614 |
|
|
if (!capable(CAP_NET_ADMIN)) {
|
2615 |
|
|
rc = -EPERM;
|
2616 |
|
|
break;
|
2617 |
|
|
}
|
2618 |
|
|
|
2619 |
|
|
if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) {
|
2620 |
|
|
rc = -ENOMEM;
|
2621 |
|
|
break;
|
2622 |
|
|
}
|
2623 |
|
|
|
2624 |
|
|
if (copy_from_user(new_firmware, com.data, com.len)) {
|
2625 |
|
|
kfree(new_firmware);
|
2626 |
|
|
rc = -EFAULT;
|
2627 |
|
|
break;
|
2628 |
|
|
}
|
2629 |
|
|
|
2630 |
|
|
kfree(priv->firmware);
|
2631 |
|
|
|
2632 |
|
|
priv->firmware = new_firmware;
|
2633 |
|
|
priv->firmware_length = com.len;
|
2634 |
|
|
strncpy(priv->firmware_id, com.id, 31);
|
2635 |
|
|
priv->firmware_id[31] = '\0';
|
2636 |
|
|
break;
|
2637 |
|
|
|
2638 |
|
|
case ATMELRD:
|
2639 |
|
|
if (copy_from_user(domain, rq->ifr_data, REGDOMAINSZ)) {
|
2640 |
|
|
rc = -EFAULT;
|
2641 |
|
|
break;
|
2642 |
|
|
}
|
2643 |
|
|
|
2644 |
|
|
if (!capable(CAP_NET_ADMIN)) {
|
2645 |
|
|
rc = -EPERM;
|
2646 |
|
|
break;
|
2647 |
|
|
}
|
2648 |
|
|
|
2649 |
|
|
domain[REGDOMAINSZ] = 0;
|
2650 |
|
|
rc = -EINVAL;
|
2651 |
|
|
for (i = 0; i < ARRAY_SIZE(channel_table); i++) {
|
2652 |
|
|
/* strcasecmp doesn't exist in the library */
|
2653 |
|
|
char *a = channel_table[i].name;
|
2654 |
|
|
char *b = domain;
|
2655 |
|
|
while (*a) {
|
2656 |
|
|
char c1 = *a++;
|
2657 |
|
|
char c2 = *b++;
|
2658 |
|
|
if (tolower(c1) != tolower(c2))
|
2659 |
|
|
break;
|
2660 |
|
|
}
|
2661 |
|
|
if (!*a && !*b) {
|
2662 |
|
|
priv->config_reg_domain = channel_table[i].reg_domain;
|
2663 |
|
|
rc = 0;
|
2664 |
|
|
}
|
2665 |
|
|
}
|
2666 |
|
|
|
2667 |
|
|
if (rc == 0 && priv->station_state != STATION_STATE_DOWN)
|
2668 |
|
|
rc = atmel_open(dev);
|
2669 |
|
|
break;
|
2670 |
|
|
|
2671 |
|
|
default:
|
2672 |
|
|
rc = -EOPNOTSUPP;
|
2673 |
|
|
}
|
2674 |
|
|
|
2675 |
|
|
return rc;
|
2676 |
|
|
}
|
2677 |
|
|
|
2678 |
|
|
struct auth_body {
|
2679 |
|
|
u16 alg;
|
2680 |
|
|
u16 trans_seq;
|
2681 |
|
|
u16 status;
|
2682 |
|
|
u8 el_id;
|
2683 |
|
|
u8 chall_text_len;
|
2684 |
|
|
u8 chall_text[253];
|
2685 |
|
|
};
|
2686 |
|
|
|
2687 |
|
|
static void atmel_enter_state(struct atmel_private *priv, int new_state)
|
2688 |
|
|
{
|
2689 |
|
|
int old_state = priv->station_state;
|
2690 |
|
|
|
2691 |
|
|
if (new_state == old_state)
|
2692 |
|
|
return;
|
2693 |
|
|
|
2694 |
|
|
priv->station_state = new_state;
|
2695 |
|
|
|
2696 |
|
|
if (new_state == STATION_STATE_READY) {
|
2697 |
|
|
netif_start_queue(priv->dev);
|
2698 |
|
|
netif_carrier_on(priv->dev);
|
2699 |
|
|
}
|
2700 |
|
|
|
2701 |
|
|
if (old_state == STATION_STATE_READY) {
|
2702 |
|
|
netif_carrier_off(priv->dev);
|
2703 |
|
|
if (netif_running(priv->dev))
|
2704 |
|
|
netif_stop_queue(priv->dev);
|
2705 |
|
|
priv->last_beacon_timestamp = 0;
|
2706 |
|
|
}
|
2707 |
|
|
}
|
2708 |
|
|
|
2709 |
|
|
static void atmel_scan(struct atmel_private *priv, int specific_ssid)
|
2710 |
|
|
{
|
2711 |
|
|
struct {
|
2712 |
|
|
u8 BSSID[6];
|
2713 |
|
|
u8 SSID[MAX_SSID_LENGTH];
|
2714 |
|
|
u8 scan_type;
|
2715 |
|
|
u8 channel;
|
2716 |
|
|
u16 BSS_type;
|
2717 |
|
|
u16 min_channel_time;
|
2718 |
|
|
u16 max_channel_time;
|
2719 |
|
|
u8 options;
|
2720 |
|
|
u8 SSID_size;
|
2721 |
|
|
} cmd;
|
2722 |
|
|
|
2723 |
|
|
memset(cmd.BSSID, 0xff, 6);
|
2724 |
|
|
|
2725 |
|
|
if (priv->fast_scan) {
|
2726 |
|
|
cmd.SSID_size = priv->SSID_size;
|
2727 |
|
|
memcpy(cmd.SSID, priv->SSID, priv->SSID_size);
|
2728 |
|
|
cmd.min_channel_time = cpu_to_le16(10);
|
2729 |
|
|
cmd.max_channel_time = cpu_to_le16(50);
|
2730 |
|
|
} else {
|
2731 |
|
|
priv->BSS_list_entries = 0;
|
2732 |
|
|
cmd.SSID_size = 0;
|
2733 |
|
|
cmd.min_channel_time = cpu_to_le16(10);
|
2734 |
|
|
cmd.max_channel_time = cpu_to_le16(120);
|
2735 |
|
|
}
|
2736 |
|
|
|
2737 |
|
|
cmd.options = 0;
|
2738 |
|
|
|
2739 |
|
|
if (!specific_ssid)
|
2740 |
|
|
cmd.options |= SCAN_OPTIONS_SITE_SURVEY;
|
2741 |
|
|
|
2742 |
|
|
cmd.channel = (priv->channel & 0x7f);
|
2743 |
|
|
cmd.scan_type = SCAN_TYPE_ACTIVE;
|
2744 |
|
|
cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ?
|
2745 |
|
|
BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE);
|
2746 |
|
|
|
2747 |
|
|
atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd));
|
2748 |
|
|
|
2749 |
|
|
/* This must come after all hardware access to avoid being messed up
|
2750 |
|
|
by stuff happening in interrupt context after we leave STATE_DOWN */
|
2751 |
|
|
atmel_enter_state(priv, STATION_STATE_SCANNING);
|
2752 |
|
|
}
|
2753 |
|
|
|
2754 |
|
|
static void join(struct atmel_private *priv, int type)
|
2755 |
|
|
{
|
2756 |
|
|
struct {
|
2757 |
|
|
u8 BSSID[6];
|
2758 |
|
|
u8 SSID[MAX_SSID_LENGTH];
|
2759 |
|
|
u8 BSS_type; /* this is a short in a scan command - weird */
|
2760 |
|
|
u8 channel;
|
2761 |
|
|
u16 timeout;
|
2762 |
|
|
u8 SSID_size;
|
2763 |
|
|
u8 reserved;
|
2764 |
|
|
} cmd;
|
2765 |
|
|
|
2766 |
|
|
cmd.SSID_size = priv->SSID_size;
|
2767 |
|
|
memcpy(cmd.SSID, priv->SSID, priv->SSID_size);
|
2768 |
|
|
memcpy(cmd.BSSID, priv->CurrentBSSID, 6);
|
2769 |
|
|
cmd.channel = (priv->channel & 0x7f);
|
2770 |
|
|
cmd.BSS_type = type;
|
2771 |
|
|
cmd.timeout = cpu_to_le16(2000);
|
2772 |
|
|
|
2773 |
|
|
atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd));
|
2774 |
|
|
}
|
2775 |
|
|
|
2776 |
|
|
static void start(struct atmel_private *priv, int type)
|
2777 |
|
|
{
|
2778 |
|
|
struct {
|
2779 |
|
|
u8 BSSID[6];
|
2780 |
|
|
u8 SSID[MAX_SSID_LENGTH];
|
2781 |
|
|
u8 BSS_type;
|
2782 |
|
|
u8 channel;
|
2783 |
|
|
u8 SSID_size;
|
2784 |
|
|
u8 reserved[3];
|
2785 |
|
|
} cmd;
|
2786 |
|
|
|
2787 |
|
|
cmd.SSID_size = priv->SSID_size;
|
2788 |
|
|
memcpy(cmd.SSID, priv->SSID, priv->SSID_size);
|
2789 |
|
|
memcpy(cmd.BSSID, priv->BSSID, 6);
|
2790 |
|
|
cmd.BSS_type = type;
|
2791 |
|
|
cmd.channel = (priv->channel & 0x7f);
|
2792 |
|
|
|
2793 |
|
|
atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd));
|
2794 |
|
|
}
|
2795 |
|
|
|
2796 |
|
|
static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
|
2797 |
|
|
u8 channel)
|
2798 |
|
|
{
|
2799 |
|
|
int rejoin = 0;
|
2800 |
|
|
int new = capability & MFIE_TYPE_POWER_CONSTRAINT ?
|
2801 |
|
|
SHORT_PREAMBLE : LONG_PREAMBLE;
|
2802 |
|
|
|
2803 |
|
|
if (priv->preamble != new) {
|
2804 |
|
|
priv->preamble = new;
|
2805 |
|
|
rejoin = 1;
|
2806 |
|
|
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new);
|
2807 |
|
|
}
|
2808 |
|
|
|
2809 |
|
|
if (priv->channel != channel) {
|
2810 |
|
|
priv->channel = channel;
|
2811 |
|
|
rejoin = 1;
|
2812 |
|
|
atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel);
|
2813 |
|
|
}
|
2814 |
|
|
|
2815 |
|
|
if (rejoin) {
|
2816 |
|
|
priv->station_is_associated = 0;
|
2817 |
|
|
atmel_enter_state(priv, STATION_STATE_JOINNING);
|
2818 |
|
|
|
2819 |
|
|
if (priv->operating_mode == IW_MODE_INFRA)
|
2820 |
|
|
join(priv, BSS_TYPE_INFRASTRUCTURE);
|
2821 |
|
|
else
|
2822 |
|
|
join(priv, BSS_TYPE_AD_HOC);
|
2823 |
|
|
}
|
2824 |
|
|
}
|
2825 |
|
|
|
2826 |
|
|
static void send_authentication_request(struct atmel_private *priv, u16 system,
|
2827 |
|
|
u8 *challenge, int challenge_len)
|
2828 |
|
|
{
|
2829 |
|
|
struct ieee80211_hdr_4addr header;
|
2830 |
|
|
struct auth_body auth;
|
2831 |
|
|
|
2832 |
|
|
header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
|
2833 |
|
|
header.duration_id = cpu_to_le16(0x8000);
|
2834 |
|
|
header.seq_ctl = 0;
|
2835 |
|
|
memcpy(header.addr1, priv->CurrentBSSID, 6);
|
2836 |
|
|
memcpy(header.addr2, priv->dev->dev_addr, 6);
|
2837 |
|
|
memcpy(header.addr3, priv->CurrentBSSID, 6);
|
2838 |
|
|
|
2839 |
|
|
if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
|
2840 |
|
|
/* no WEP for authentication frames with TrSeqNo 1 */
|
2841 |
|
|
header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
2842 |
|
|
|
2843 |
|
|
auth.alg = cpu_to_le16(system);
|
2844 |
|
|
|
2845 |
|
|
auth.status = 0;
|
2846 |
|
|
auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum);
|
2847 |
|
|
priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1;
|
2848 |
|
|
priv->CurrentAuthentTransactionSeqNum += 2;
|
2849 |
|
|
|
2850 |
|
|
if (challenge_len != 0) {
|
2851 |
|
|
auth.el_id = 16; /* challenge_text */
|
2852 |
|
|
auth.chall_text_len = challenge_len;
|
2853 |
|
|
memcpy(auth.chall_text, challenge, challenge_len);
|
2854 |
|
|
atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len);
|
2855 |
|
|
} else {
|
2856 |
|
|
atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6);
|
2857 |
|
|
}
|
2858 |
|
|
}
|
2859 |
|
|
|
2860 |
|
|
static void send_association_request(struct atmel_private *priv, int is_reassoc)
|
2861 |
|
|
{
|
2862 |
|
|
u8 *ssid_el_p;
|
2863 |
|
|
int bodysize;
|
2864 |
|
|
struct ieee80211_hdr_4addr header;
|
2865 |
|
|
struct ass_req_format {
|
2866 |
|
|
u16 capability;
|
2867 |
|
|
u16 listen_interval;
|
2868 |
|
|
u8 ap[6]; /* nothing after here directly accessible */
|
2869 |
|
|
u8 ssid_el_id;
|
2870 |
|
|
u8 ssid_len;
|
2871 |
|
|
u8 ssid[MAX_SSID_LENGTH];
|
2872 |
|
|
u8 sup_rates_el_id;
|
2873 |
|
|
u8 sup_rates_len;
|
2874 |
|
|
u8 rates[4];
|
2875 |
|
|
} body;
|
2876 |
|
|
|
2877 |
|
|
header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
2878 |
|
|
(is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
|
2879 |
|
|
header.duration_id = cpu_to_le16(0x8000);
|
2880 |
|
|
header.seq_ctl = 0;
|
2881 |
|
|
|
2882 |
|
|
memcpy(header.addr1, priv->CurrentBSSID, 6);
|
2883 |
|
|
memcpy(header.addr2, priv->dev->dev_addr, 6);
|
2884 |
|
|
memcpy(header.addr3, priv->CurrentBSSID, 6);
|
2885 |
|
|
|
2886 |
|
|
body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
|
2887 |
|
|
if (priv->wep_is_on)
|
2888 |
|
|
body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
|
2889 |
|
|
if (priv->preamble == SHORT_PREAMBLE)
|
2890 |
|
|
body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT);
|
2891 |
|
|
|
2892 |
|
|
body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period);
|
2893 |
|
|
|
2894 |
|
|
/* current AP address - only in reassoc frame */
|
2895 |
|
|
if (is_reassoc) {
|
2896 |
|
|
memcpy(body.ap, priv->CurrentBSSID, 6);
|
2897 |
|
|
ssid_el_p = (u8 *)&body.ssid_el_id;
|
2898 |
|
|
bodysize = 18 + priv->SSID_size;
|
2899 |
|
|
} else {
|
2900 |
|
|
ssid_el_p = (u8 *)&body.ap[0];
|
2901 |
|
|
bodysize = 12 + priv->SSID_size;
|
2902 |
|
|
}
|
2903 |
|
|
|
2904 |
|
|
ssid_el_p[0] = MFIE_TYPE_SSID;
|
2905 |
|
|
ssid_el_p[1] = priv->SSID_size;
|
2906 |
|
|
memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
|
2907 |
|
|
ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES;
|
2908 |
|
|
ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */
|
2909 |
|
|
memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4);
|
2910 |
|
|
|
2911 |
|
|
atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
|
2912 |
|
|
}
|
2913 |
|
|
|
2914 |
|
|
static int is_frame_from_current_bss(struct atmel_private *priv,
|
2915 |
|
|
struct ieee80211_hdr_4addr *header)
|
2916 |
|
|
{
|
2917 |
|
|
if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
|
2918 |
|
|
return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
|
2919 |
|
|
else
|
2920 |
|
|
return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
|
2921 |
|
|
}
|
2922 |
|
|
|
2923 |
|
|
static int retrieve_bss(struct atmel_private *priv)
|
2924 |
|
|
{
|
2925 |
|
|
int i;
|
2926 |
|
|
int max_rssi = -128;
|
2927 |
|
|
int max_index = -1;
|
2928 |
|
|
|
2929 |
|
|
if (priv->BSS_list_entries == 0)
|
2930 |
|
|
return -1;
|
2931 |
|
|
|
2932 |
|
|
if (priv->connect_to_any_BSS) {
|
2933 |
|
|
/* Select a BSS with the max-RSSI but of the same type and of
|
2934 |
|
|
the same WEP mode and that it is not marked as 'bad' (i.e.
|
2935 |
|
|
we had previously failed to connect to this BSS with the
|
2936 |
|
|
settings that we currently use) */
|
2937 |
|
|
priv->current_BSS = 0;
|
2938 |
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
2939 |
|
|
if (priv->operating_mode == priv->BSSinfo[i].BSStype &&
|
2940 |
|
|
((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
|
2941 |
|
|
(priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
|
2942 |
|
|
!(priv->BSSinfo[i].channel & 0x80)) {
|
2943 |
|
|
max_rssi = priv->BSSinfo[i].RSSI;
|
2944 |
|
|
priv->current_BSS = max_index = i;
|
2945 |
|
|
}
|
2946 |
|
|
}
|
2947 |
|
|
return max_index;
|
2948 |
|
|
}
|
2949 |
|
|
|
2950 |
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
2951 |
|
|
if (priv->SSID_size == priv->BSSinfo[i].SSIDsize &&
|
2952 |
|
|
memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 &&
|
2953 |
|
|
priv->operating_mode == priv->BSSinfo[i].BSStype &&
|
2954 |
|
|
atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) {
|
2955 |
|
|
if (priv->BSSinfo[i].RSSI >= max_rssi) {
|
2956 |
|
|
max_rssi = priv->BSSinfo[i].RSSI;
|
2957 |
|
|
max_index = i;
|
2958 |
|
|
}
|
2959 |
|
|
}
|
2960 |
|
|
}
|
2961 |
|
|
return max_index;
|
2962 |
|
|
}
|
2963 |
|
|
|
2964 |
|
|
static void store_bss_info(struct atmel_private *priv,
|
2965 |
|
|
struct ieee80211_hdr_4addr *header, u16 capability,
|
2966 |
|
|
u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
|
2967 |
|
|
u8 *ssid, int is_beacon)
|
2968 |
|
|
{
|
2969 |
|
|
u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3;
|
2970 |
|
|
int i, index;
|
2971 |
|
|
|
2972 |
|
|
for (index = -1, i = 0; i < priv->BSS_list_entries; i++)
|
2973 |
|
|
if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0)
|
2974 |
|
|
index = i;
|
2975 |
|
|
|
2976 |
|
|
/* If we process a probe and an entry from this BSS exists
|
2977 |
|
|
we will update the BSS entry with the info from this BSS.
|
2978 |
|
|
If we process a beacon we will only update RSSI */
|
2979 |
|
|
|
2980 |
|
|
if (index == -1) {
|
2981 |
|
|
if (priv->BSS_list_entries == MAX_BSS_ENTRIES)
|
2982 |
|
|
return;
|
2983 |
|
|
index = priv->BSS_list_entries++;
|
2984 |
|
|
memcpy(priv->BSSinfo[index].BSSID, bss, 6);
|
2985 |
|
|
priv->BSSinfo[index].RSSI = rssi;
|
2986 |
|
|
} else {
|
2987 |
|
|
if (rssi > priv->BSSinfo[index].RSSI)
|
2988 |
|
|
priv->BSSinfo[index].RSSI = rssi;
|
2989 |
|
|
if (is_beacon)
|
2990 |
|
|
return;
|
2991 |
|
|
}
|
2992 |
|
|
|
2993 |
|
|
priv->BSSinfo[index].channel = channel;
|
2994 |
|
|
priv->BSSinfo[index].beacon_period = beacon_period;
|
2995 |
|
|
priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY;
|
2996 |
|
|
memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len);
|
2997 |
|
|
priv->BSSinfo[index].SSIDsize = ssid_len;
|
2998 |
|
|
|
2999 |
|
|
if (capability & WLAN_CAPABILITY_IBSS)
|
3000 |
|
|
priv->BSSinfo[index].BSStype = IW_MODE_ADHOC;
|
3001 |
|
|
else if (capability & WLAN_CAPABILITY_ESS)
|
3002 |
|
|
priv->BSSinfo[index].BSStype =IW_MODE_INFRA;
|
3003 |
|
|
|
3004 |
|
|
priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ?
|
3005 |
|
|
SHORT_PREAMBLE : LONG_PREAMBLE;
|
3006 |
|
|
}
|
3007 |
|
|
|
3008 |
|
|
static void authenticate(struct atmel_private *priv, u16 frame_len)
|
3009 |
|
|
{
|
3010 |
|
|
struct auth_body *auth = (struct auth_body *)priv->rx_buf;
|
3011 |
|
|
u16 status = le16_to_cpu(auth->status);
|
3012 |
|
|
u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
|
3013 |
|
|
u16 system = le16_to_cpu(auth->alg);
|
3014 |
|
|
|
3015 |
|
|
if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) {
|
3016 |
|
|
/* no WEP */
|
3017 |
|
|
if (priv->station_was_associated) {
|
3018 |
|
|
atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
|
3019 |
|
|
send_association_request(priv, 1);
|
3020 |
|
|
return;
|
3021 |
|
|
} else {
|
3022 |
|
|
atmel_enter_state(priv, STATION_STATE_ASSOCIATING);
|
3023 |
|
|
send_association_request(priv, 0);
|
3024 |
|
|
return;
|
3025 |
|
|
}
|
3026 |
|
|
}
|
3027 |
|
|
|
3028 |
|
|
if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) {
|
3029 |
|
|
int should_associate = 0;
|
3030 |
|
|
/* WEP */
|
3031 |
|
|
if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum)
|
3032 |
|
|
return;
|
3033 |
|
|
|
3034 |
|
|
if (system == WLAN_AUTH_OPEN) {
|
3035 |
|
|
if (trans_seq_no == 0x0002) {
|
3036 |
|
|
should_associate = 1;
|
3037 |
|
|
}
|
3038 |
|
|
} else if (system == WLAN_AUTH_SHARED_KEY) {
|
3039 |
|
|
if (trans_seq_no == 0x0002 &&
|
3040 |
|
|
auth->el_id == MFIE_TYPE_CHALLENGE) {
|
3041 |
|
|
send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
|
3042 |
|
|
return;
|
3043 |
|
|
} else if (trans_seq_no == 0x0004) {
|
3044 |
|
|
should_associate = 1;
|
3045 |
|
|
}
|
3046 |
|
|
}
|
3047 |
|
|
|
3048 |
|
|
if (should_associate) {
|
3049 |
|
|
if(priv->station_was_associated) {
|
3050 |
|
|
atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
|
3051 |
|
|
send_association_request(priv, 1);
|
3052 |
|
|
return;
|
3053 |
|
|
} else {
|
3054 |
|
|
atmel_enter_state(priv, STATION_STATE_ASSOCIATING);
|
3055 |
|
|
send_association_request(priv, 0);
|
3056 |
|
|
return;
|
3057 |
|
|
}
|
3058 |
|
|
}
|
3059 |
|
|
}
|
3060 |
|
|
|
3061 |
|
|
if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
|
3062 |
|
|
/* Do opensystem first, then try sharedkey */
|
3063 |
|
|
if (system == WLAN_AUTH_OPEN) {
|
3064 |
|
|
priv->CurrentAuthentTransactionSeqNum = 0x001;
|
3065 |
|
|
priv->exclude_unencrypted = 1;
|
3066 |
|
|
send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0);
|
3067 |
|
|
return;
|
3068 |
|
|
} else if (priv->connect_to_any_BSS) {
|
3069 |
|
|
int bss_index;
|
3070 |
|
|
|
3071 |
|
|
priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
|
3072 |
|
|
|
3073 |
|
|
if ((bss_index = retrieve_bss(priv)) != -1) {
|
3074 |
|
|
atmel_join_bss(priv, bss_index);
|
3075 |
|
|
return;
|
3076 |
|
|
}
|
3077 |
|
|
}
|
3078 |
|
|
}
|
3079 |
|
|
|
3080 |
|
|
priv->AuthenticationRequestRetryCnt = 0;
|
3081 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3082 |
|
|
priv->station_is_associated = 0;
|
3083 |
|
|
}
|
3084 |
|
|
|
3085 |
|
|
static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
|
3086 |
|
|
{
|
3087 |
|
|
struct ass_resp_format {
|
3088 |
|
|
u16 capability;
|
3089 |
|
|
u16 status;
|
3090 |
|
|
u16 ass_id;
|
3091 |
|
|
u8 el_id;
|
3092 |
|
|
u8 length;
|
3093 |
|
|
u8 rates[4];
|
3094 |
|
|
} *ass_resp = (struct ass_resp_format *)priv->rx_buf;
|
3095 |
|
|
|
3096 |
|
|
u16 status = le16_to_cpu(ass_resp->status);
|
3097 |
|
|
u16 ass_id = le16_to_cpu(ass_resp->ass_id);
|
3098 |
|
|
u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length;
|
3099 |
|
|
|
3100 |
|
|
union iwreq_data wrqu;
|
3101 |
|
|
|
3102 |
|
|
if (frame_len < 8 + rates_len)
|
3103 |
|
|
return;
|
3104 |
|
|
|
3105 |
|
|
if (status == WLAN_STATUS_SUCCESS) {
|
3106 |
|
|
if (subtype == IEEE80211_STYPE_ASSOC_RESP)
|
3107 |
|
|
priv->AssociationRequestRetryCnt = 0;
|
3108 |
|
|
else
|
3109 |
|
|
priv->ReAssociationRequestRetryCnt = 0;
|
3110 |
|
|
|
3111 |
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
3112 |
|
|
MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff);
|
3113 |
|
|
atmel_set_mib(priv, Phy_Mib_Type,
|
3114 |
|
|
PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len);
|
3115 |
|
|
if (priv->power_mode == 0) {
|
3116 |
|
|
priv->listen_interval = 1;
|
3117 |
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
|
3118 |
|
|
MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
3119 |
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
3120 |
|
|
MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
3121 |
|
|
} else {
|
3122 |
|
|
priv->listen_interval = 2;
|
3123 |
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
|
3124 |
|
|
MAC_MGMT_MIB_PS_MODE_POS, PS_MODE);
|
3125 |
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
3126 |
|
|
MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2);
|
3127 |
|
|
}
|
3128 |
|
|
|
3129 |
|
|
priv->station_is_associated = 1;
|
3130 |
|
|
priv->station_was_associated = 1;
|
3131 |
|
|
atmel_enter_state(priv, STATION_STATE_READY);
|
3132 |
|
|
|
3133 |
|
|
/* Send association event to userspace */
|
3134 |
|
|
wrqu.data.length = 0;
|
3135 |
|
|
wrqu.data.flags = 0;
|
3136 |
|
|
memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN);
|
3137 |
|
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
3138 |
|
|
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
3139 |
|
|
|
3140 |
|
|
return;
|
3141 |
|
|
}
|
3142 |
|
|
|
3143 |
|
|
if (subtype == IEEE80211_STYPE_ASSOC_RESP &&
|
3144 |
|
|
status != WLAN_STATUS_ASSOC_DENIED_RATES &&
|
3145 |
|
|
status != WLAN_STATUS_CAPS_UNSUPPORTED &&
|
3146 |
|
|
priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) {
|
3147 |
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
3148 |
|
|
priv->AssociationRequestRetryCnt++;
|
3149 |
|
|
send_association_request(priv, 0);
|
3150 |
|
|
return;
|
3151 |
|
|
}
|
3152 |
|
|
|
3153 |
|
|
if (subtype == IEEE80211_STYPE_REASSOC_RESP &&
|
3154 |
|
|
status != WLAN_STATUS_ASSOC_DENIED_RATES &&
|
3155 |
|
|
status != WLAN_STATUS_CAPS_UNSUPPORTED &&
|
3156 |
|
|
priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) {
|
3157 |
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
3158 |
|
|
priv->ReAssociationRequestRetryCnt++;
|
3159 |
|
|
send_association_request(priv, 1);
|
3160 |
|
|
return;
|
3161 |
|
|
}
|
3162 |
|
|
|
3163 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3164 |
|
|
priv->station_is_associated = 0;
|
3165 |
|
|
|
3166 |
|
|
if (priv->connect_to_any_BSS) {
|
3167 |
|
|
int bss_index;
|
3168 |
|
|
priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
|
3169 |
|
|
|
3170 |
|
|
if ((bss_index = retrieve_bss(priv)) != -1)
|
3171 |
|
|
atmel_join_bss(priv, bss_index);
|
3172 |
|
|
}
|
3173 |
|
|
}
|
3174 |
|
|
|
3175 |
|
|
void atmel_join_bss(struct atmel_private *priv, int bss_index)
|
3176 |
|
|
{
|
3177 |
|
|
struct bss_info *bss = &priv->BSSinfo[bss_index];
|
3178 |
|
|
|
3179 |
|
|
memcpy(priv->CurrentBSSID, bss->BSSID, 6);
|
3180 |
|
|
memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize);
|
3181 |
|
|
|
3182 |
|
|
/* The WPA stuff cares about the current AP address */
|
3183 |
|
|
if (priv->use_wpa)
|
3184 |
|
|
build_wpa_mib(priv);
|
3185 |
|
|
|
3186 |
|
|
/* When switching to AdHoc turn OFF Power Save if needed */
|
3187 |
|
|
|
3188 |
|
|
if (bss->BSStype == IW_MODE_ADHOC &&
|
3189 |
|
|
priv->operating_mode != IW_MODE_ADHOC &&
|
3190 |
|
|
priv->power_mode) {
|
3191 |
|
|
priv->power_mode = 0;
|
3192 |
|
|
priv->listen_interval = 1;
|
3193 |
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
|
3194 |
|
|
MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
3195 |
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
3196 |
|
|
MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
3197 |
|
|
}
|
3198 |
|
|
|
3199 |
|
|
priv->operating_mode = bss->BSStype;
|
3200 |
|
|
priv->channel = bss->channel & 0x7f;
|
3201 |
|
|
priv->beacon_period = bss->beacon_period;
|
3202 |
|
|
|
3203 |
|
|
if (priv->preamble != bss->preamble) {
|
3204 |
|
|
priv->preamble = bss->preamble;
|
3205 |
|
|
atmel_set_mib8(priv, Local_Mib_Type,
|
3206 |
|
|
LOCAL_MIB_PREAMBLE_TYPE, bss->preamble);
|
3207 |
|
|
}
|
3208 |
|
|
|
3209 |
|
|
if (!priv->wep_is_on && bss->UsingWEP) {
|
3210 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3211 |
|
|
priv->station_is_associated = 0;
|
3212 |
|
|
return;
|
3213 |
|
|
}
|
3214 |
|
|
|
3215 |
|
|
if (priv->wep_is_on && !bss->UsingWEP) {
|
3216 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3217 |
|
|
priv->station_is_associated = 0;
|
3218 |
|
|
return;
|
3219 |
|
|
}
|
3220 |
|
|
|
3221 |
|
|
atmel_enter_state(priv, STATION_STATE_JOINNING);
|
3222 |
|
|
|
3223 |
|
|
if (priv->operating_mode == IW_MODE_INFRA)
|
3224 |
|
|
join(priv, BSS_TYPE_INFRASTRUCTURE);
|
3225 |
|
|
else
|
3226 |
|
|
join(priv, BSS_TYPE_AD_HOC);
|
3227 |
|
|
}
|
3228 |
|
|
|
3229 |
|
|
static void restart_search(struct atmel_private *priv)
|
3230 |
|
|
{
|
3231 |
|
|
int bss_index;
|
3232 |
|
|
|
3233 |
|
|
if (!priv->connect_to_any_BSS) {
|
3234 |
|
|
atmel_scan(priv, 1);
|
3235 |
|
|
} else {
|
3236 |
|
|
priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
|
3237 |
|
|
|
3238 |
|
|
if ((bss_index = retrieve_bss(priv)) != -1)
|
3239 |
|
|
atmel_join_bss(priv, bss_index);
|
3240 |
|
|
else
|
3241 |
|
|
atmel_scan(priv, 0);
|
3242 |
|
|
}
|
3243 |
|
|
}
|
3244 |
|
|
|
3245 |
|
|
static void smooth_rssi(struct atmel_private *priv, u8 rssi)
|
3246 |
|
|
{
|
3247 |
|
|
u8 old = priv->wstats.qual.level;
|
3248 |
|
|
u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */
|
3249 |
|
|
|
3250 |
|
|
switch (priv->firmware_type) {
|
3251 |
|
|
case ATMEL_FW_TYPE_502E:
|
3252 |
|
|
max_rssi = 63; /* 502-rmfd-reve max by experiment */
|
3253 |
|
|
break;
|
3254 |
|
|
default:
|
3255 |
|
|
break;
|
3256 |
|
|
}
|
3257 |
|
|
|
3258 |
|
|
rssi = rssi * 100 / max_rssi;
|
3259 |
|
|
if ((rssi + old) % 2)
|
3260 |
|
|
priv->wstats.qual.level = (rssi + old) / 2 + 1;
|
3261 |
|
|
else
|
3262 |
|
|
priv->wstats.qual.level = (rssi + old) / 2;
|
3263 |
|
|
priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
|
3264 |
|
|
priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID;
|
3265 |
|
|
}
|
3266 |
|
|
|
3267 |
|
|
static void atmel_smooth_qual(struct atmel_private *priv)
|
3268 |
|
|
{
|
3269 |
|
|
unsigned long time_diff = (jiffies - priv->last_qual) / HZ;
|
3270 |
|
|
while (time_diff--) {
|
3271 |
|
|
priv->last_qual += HZ;
|
3272 |
|
|
priv->wstats.qual.qual = priv->wstats.qual.qual / 2;
|
3273 |
|
|
priv->wstats.qual.qual +=
|
3274 |
|
|
priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000;
|
3275 |
|
|
priv->beacons_this_sec = 0;
|
3276 |
|
|
}
|
3277 |
|
|
priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
|
3278 |
|
|
priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID;
|
3279 |
|
|
}
|
3280 |
|
|
|
3281 |
|
|
/* deals with incoming managment frames. */
|
3282 |
|
|
static void atmel_management_frame(struct atmel_private *priv,
|
3283 |
|
|
struct ieee80211_hdr_4addr *header,
|
3284 |
|
|
u16 frame_len, u8 rssi)
|
3285 |
|
|
{
|
3286 |
|
|
u16 subtype;
|
3287 |
|
|
|
3288 |
|
|
subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE;
|
3289 |
|
|
switch (subtype) {
|
3290 |
|
|
case IEEE80211_STYPE_BEACON:
|
3291 |
|
|
case IEEE80211_STYPE_PROBE_RESP:
|
3292 |
|
|
|
3293 |
|
|
/* beacon frame has multiple variable-length fields -
|
3294 |
|
|
never let an engineer loose with a data structure design. */
|
3295 |
|
|
{
|
3296 |
|
|
struct beacon_format {
|
3297 |
|
|
u64 timestamp;
|
3298 |
|
|
u16 interval;
|
3299 |
|
|
u16 capability;
|
3300 |
|
|
u8 ssid_el_id;
|
3301 |
|
|
u8 ssid_length;
|
3302 |
|
|
/* ssid here */
|
3303 |
|
|
u8 rates_el_id;
|
3304 |
|
|
u8 rates_length;
|
3305 |
|
|
/* rates here */
|
3306 |
|
|
u8 ds_el_id;
|
3307 |
|
|
u8 ds_length;
|
3308 |
|
|
/* ds here */
|
3309 |
|
|
} *beacon = (struct beacon_format *)priv->rx_buf;
|
3310 |
|
|
|
3311 |
|
|
u8 channel, rates_length, ssid_length;
|
3312 |
|
|
u64 timestamp = le64_to_cpu(beacon->timestamp);
|
3313 |
|
|
u16 beacon_interval = le16_to_cpu(beacon->interval);
|
3314 |
|
|
u16 capability = le16_to_cpu(beacon->capability);
|
3315 |
|
|
u8 *beaconp = priv->rx_buf;
|
3316 |
|
|
ssid_length = beacon->ssid_length;
|
3317 |
|
|
/* this blows chunks. */
|
3318 |
|
|
if (frame_len < 14 || frame_len < ssid_length + 15)
|
3319 |
|
|
return;
|
3320 |
|
|
rates_length = beaconp[beacon->ssid_length + 15];
|
3321 |
|
|
if (frame_len < ssid_length + rates_length + 18)
|
3322 |
|
|
return;
|
3323 |
|
|
if (ssid_length > MAX_SSID_LENGTH)
|
3324 |
|
|
return;
|
3325 |
|
|
channel = beaconp[ssid_length + rates_length + 18];
|
3326 |
|
|
|
3327 |
|
|
if (priv->station_state == STATION_STATE_READY) {
|
3328 |
|
|
smooth_rssi(priv, rssi);
|
3329 |
|
|
if (is_frame_from_current_bss(priv, header)) {
|
3330 |
|
|
priv->beacons_this_sec++;
|
3331 |
|
|
atmel_smooth_qual(priv);
|
3332 |
|
|
if (priv->last_beacon_timestamp) {
|
3333 |
|
|
/* Note truncate this to 32 bits - kernel can't divide a long long */
|
3334 |
|
|
u32 beacon_delay = timestamp - priv->last_beacon_timestamp;
|
3335 |
|
|
int beacons = beacon_delay / (beacon_interval * 1000);
|
3336 |
|
|
if (beacons > 1)
|
3337 |
|
|
priv->wstats.miss.beacon += beacons - 1;
|
3338 |
|
|
}
|
3339 |
|
|
priv->last_beacon_timestamp = timestamp;
|
3340 |
|
|
handle_beacon_probe(priv, capability, channel);
|
3341 |
|
|
}
|
3342 |
|
|
}
|
3343 |
|
|
|
3344 |
|
|
if (priv->station_state == STATION_STATE_SCANNING)
|
3345 |
|
|
store_bss_info(priv, header, capability,
|
3346 |
|
|
beacon_interval, channel, rssi,
|
3347 |
|
|
ssid_length,
|
3348 |
|
|
&beacon->rates_el_id,
|
3349 |
|
|
subtype == IEEE80211_STYPE_BEACON);
|
3350 |
|
|
}
|
3351 |
|
|
break;
|
3352 |
|
|
|
3353 |
|
|
case IEEE80211_STYPE_AUTH:
|
3354 |
|
|
|
3355 |
|
|
if (priv->station_state == STATION_STATE_AUTHENTICATING)
|
3356 |
|
|
authenticate(priv, frame_len);
|
3357 |
|
|
|
3358 |
|
|
break;
|
3359 |
|
|
|
3360 |
|
|
case IEEE80211_STYPE_ASSOC_RESP:
|
3361 |
|
|
case IEEE80211_STYPE_REASSOC_RESP:
|
3362 |
|
|
|
3363 |
|
|
if (priv->station_state == STATION_STATE_ASSOCIATING ||
|
3364 |
|
|
priv->station_state == STATION_STATE_REASSOCIATING)
|
3365 |
|
|
associate(priv, frame_len, subtype);
|
3366 |
|
|
|
3367 |
|
|
break;
|
3368 |
|
|
|
3369 |
|
|
case IEEE80211_STYPE_DISASSOC:
|
3370 |
|
|
if (priv->station_is_associated &&
|
3371 |
|
|
priv->operating_mode == IW_MODE_INFRA &&
|
3372 |
|
|
is_frame_from_current_bss(priv, header)) {
|
3373 |
|
|
priv->station_was_associated = 0;
|
3374 |
|
|
priv->station_is_associated = 0;
|
3375 |
|
|
|
3376 |
|
|
atmel_enter_state(priv, STATION_STATE_JOINNING);
|
3377 |
|
|
join(priv, BSS_TYPE_INFRASTRUCTURE);
|
3378 |
|
|
}
|
3379 |
|
|
|
3380 |
|
|
break;
|
3381 |
|
|
|
3382 |
|
|
case IEEE80211_STYPE_DEAUTH:
|
3383 |
|
|
if (priv->operating_mode == IW_MODE_INFRA &&
|
3384 |
|
|
is_frame_from_current_bss(priv, header)) {
|
3385 |
|
|
priv->station_was_associated = 0;
|
3386 |
|
|
|
3387 |
|
|
atmel_enter_state(priv, STATION_STATE_JOINNING);
|
3388 |
|
|
join(priv, BSS_TYPE_INFRASTRUCTURE);
|
3389 |
|
|
}
|
3390 |
|
|
|
3391 |
|
|
break;
|
3392 |
|
|
}
|
3393 |
|
|
}
|
3394 |
|
|
|
3395 |
|
|
/* run when timer expires */
|
3396 |
|
|
static void atmel_management_timer(u_long a)
|
3397 |
|
|
{
|
3398 |
|
|
struct net_device *dev = (struct net_device *) a;
|
3399 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
3400 |
|
|
unsigned long flags;
|
3401 |
|
|
|
3402 |
|
|
/* Check if the card has been yanked. */
|
3403 |
|
|
if (priv->card && priv->present_callback &&
|
3404 |
|
|
!(*priv->present_callback)(priv->card))
|
3405 |
|
|
return;
|
3406 |
|
|
|
3407 |
|
|
spin_lock_irqsave(&priv->irqlock, flags);
|
3408 |
|
|
|
3409 |
|
|
switch (priv->station_state) {
|
3410 |
|
|
|
3411 |
|
|
case STATION_STATE_AUTHENTICATING:
|
3412 |
|
|
if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) {
|
3413 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3414 |
|
|
priv->station_is_associated = 0;
|
3415 |
|
|
priv->AuthenticationRequestRetryCnt = 0;
|
3416 |
|
|
restart_search(priv);
|
3417 |
|
|
} else {
|
3418 |
|
|
int auth = WLAN_AUTH_OPEN;
|
3419 |
|
|
priv->AuthenticationRequestRetryCnt++;
|
3420 |
|
|
priv->CurrentAuthentTransactionSeqNum = 0x0001;
|
3421 |
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
3422 |
|
|
if (priv->wep_is_on && priv->exclude_unencrypted)
|
3423 |
|
|
auth = WLAN_AUTH_SHARED_KEY;
|
3424 |
|
|
send_authentication_request(priv, auth, NULL, 0);
|
3425 |
|
|
}
|
3426 |
|
|
break;
|
3427 |
|
|
|
3428 |
|
|
case STATION_STATE_ASSOCIATING:
|
3429 |
|
|
if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) {
|
3430 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3431 |
|
|
priv->station_is_associated = 0;
|
3432 |
|
|
priv->AssociationRequestRetryCnt = 0;
|
3433 |
|
|
restart_search(priv);
|
3434 |
|
|
} else {
|
3435 |
|
|
priv->AssociationRequestRetryCnt++;
|
3436 |
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
3437 |
|
|
send_association_request(priv, 0);
|
3438 |
|
|
}
|
3439 |
|
|
break;
|
3440 |
|
|
|
3441 |
|
|
case STATION_STATE_REASSOCIATING:
|
3442 |
|
|
if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) {
|
3443 |
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
3444 |
|
|
priv->station_is_associated = 0;
|
3445 |
|
|
priv->ReAssociationRequestRetryCnt = 0;
|
3446 |
|
|
restart_search(priv);
|
3447 |
|
|
} else {
|
3448 |
|
|
priv->ReAssociationRequestRetryCnt++;
|
3449 |
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
3450 |
|
|
send_association_request(priv, 1);
|
3451 |
|
|
}
|
3452 |
|
|
break;
|
3453 |
|
|
|
3454 |
|
|
default:
|
3455 |
|
|
break;
|
3456 |
|
|
}
|
3457 |
|
|
|
3458 |
|
|
spin_unlock_irqrestore(&priv->irqlock, flags);
|
3459 |
|
|
}
|
3460 |
|
|
|
3461 |
|
|
static void atmel_command_irq(struct atmel_private *priv)
|
3462 |
|
|
{
|
3463 |
|
|
u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET));
|
3464 |
|
|
u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET));
|
3465 |
|
|
int fast_scan;
|
3466 |
|
|
union iwreq_data wrqu;
|
3467 |
|
|
|
3468 |
|
|
if (status == CMD_STATUS_IDLE ||
|
3469 |
|
|
status == CMD_STATUS_IN_PROGRESS)
|
3470 |
|
|
return;
|
3471 |
|
|
|
3472 |
|
|
switch (command){
|
3473 |
|
|
|
3474 |
|
|
case CMD_Start:
|
3475 |
|
|
if (status == CMD_STATUS_COMPLETE) {
|
3476 |
|
|
priv->station_was_associated = priv->station_is_associated;
|
3477 |
|
|
atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS,
|
3478 |
|
|
(u8 *)priv->CurrentBSSID, 6);
|
3479 |
|
|
atmel_enter_state(priv, STATION_STATE_READY);
|
3480 |
|
|
}
|
3481 |
|
|
break;
|
3482 |
|
|
|
3483 |
|
|
case CMD_Scan:
|
3484 |
|
|
fast_scan = priv->fast_scan;
|
3485 |
|
|
priv->fast_scan = 0;
|
3486 |
|
|
|
3487 |
|
|
if (status != CMD_STATUS_COMPLETE) {
|
3488 |
|
|
atmel_scan(priv, 1);
|
3489 |
|
|
} else {
|
3490 |
|
|
int bss_index = retrieve_bss(priv);
|
3491 |
|
|
int notify_scan_complete = 1;
|
3492 |
|
|
if (bss_index != -1) {
|
3493 |
|
|
atmel_join_bss(priv, bss_index);
|
3494 |
|
|
} else if (priv->operating_mode == IW_MODE_ADHOC &&
|
3495 |
|
|
priv->SSID_size != 0) {
|
3496 |
|
|
start(priv, BSS_TYPE_AD_HOC);
|
3497 |
|
|
} else {
|
3498 |
|
|
priv->fast_scan = !fast_scan;
|
3499 |
|
|
atmel_scan(priv, 1);
|
3500 |
|
|
notify_scan_complete = 0;
|
3501 |
|
|
}
|
3502 |
|
|
priv->site_survey_state = SITE_SURVEY_COMPLETED;
|
3503 |
|
|
if (notify_scan_complete) {
|
3504 |
|
|
wrqu.data.length = 0;
|
3505 |
|
|
wrqu.data.flags = 0;
|
3506 |
|
|
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
|
3507 |
|
|
}
|
3508 |
|
|
}
|
3509 |
|
|
break;
|
3510 |
|
|
|
3511 |
|
|
case CMD_SiteSurvey:
|
3512 |
|
|
priv->fast_scan = 0;
|
3513 |
|
|
|
3514 |
|
|
if (status != CMD_STATUS_COMPLETE)
|
3515 |
|
|
return;
|
3516 |
|
|
|
3517 |
|
|
priv->site_survey_state = SITE_SURVEY_COMPLETED;
|
3518 |
|
|
if (priv->station_is_associated) {
|
3519 |
|
|
atmel_enter_state(priv, STATION_STATE_READY);
|
3520 |
|
|
wrqu.data.length = 0;
|
3521 |
|
|
wrqu.data.flags = 0;
|
3522 |
|
|
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
|
3523 |
|
|
} else {
|
3524 |
|
|
atmel_scan(priv, 1);
|
3525 |
|
|
}
|
3526 |
|
|
break;
|
3527 |
|
|
|
3528 |
|
|
case CMD_Join:
|
3529 |
|
|
if (status == CMD_STATUS_COMPLETE) {
|
3530 |
|
|
if (priv->operating_mode == IW_MODE_ADHOC) {
|
3531 |
|
|
priv->station_was_associated = priv->station_is_associated;
|
3532 |
|
|
atmel_enter_state(priv, STATION_STATE_READY);
|
3533 |
|
|
} else {
|
3534 |
|
|
int auth = WLAN_AUTH_OPEN;
|
3535 |
|
|
priv->AuthenticationRequestRetryCnt = 0;
|
3536 |
|
|
atmel_enter_state(priv, STATION_STATE_AUTHENTICATING);
|
3537 |
|
|
|
3538 |
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
3539 |
|
|
priv->CurrentAuthentTransactionSeqNum = 0x0001;
|
3540 |
|
|
if (priv->wep_is_on && priv->exclude_unencrypted)
|
3541 |
|
|
auth = WLAN_AUTH_SHARED_KEY;
|
3542 |
|
|
send_authentication_request(priv, auth, NULL, 0);
|
3543 |
|
|
}
|
3544 |
|
|
return;
|
3545 |
|
|
}
|
3546 |
|
|
|
3547 |
|
|
atmel_scan(priv, 1);
|
3548 |
|
|
}
|
3549 |
|
|
}
|
3550 |
|
|
|
3551 |
|
|
static int atmel_wakeup_firmware(struct atmel_private *priv)
|
3552 |
|
|
{
|
3553 |
|
|
struct host_info_struct *iface = &priv->host_info;
|
3554 |
|
|
u16 mr1, mr3;
|
3555 |
|
|
int i;
|
3556 |
|
|
|
3557 |
|
|
if (priv->card_type == CARD_TYPE_SPI_FLASH)
|
3558 |
|
|
atmel_set_gcr(priv->dev, GCR_REMAP);
|
3559 |
|
|
|
3560 |
|
|
/* wake up on-board processor */
|
3561 |
|
|
atmel_clear_gcr(priv->dev, 0x0040);
|
3562 |
|
|
atmel_write16(priv->dev, BSR, BSS_SRAM);
|
3563 |
|
|
|
3564 |
|
|
if (priv->card_type == CARD_TYPE_SPI_FLASH)
|
3565 |
|
|
mdelay(100);
|
3566 |
|
|
|
3567 |
|
|
/* and wait for it */
|
3568 |
|
|
for (i = LOOP_RETRY_LIMIT; i; i--) {
|
3569 |
|
|
mr1 = atmel_read16(priv->dev, MR1);
|
3570 |
|
|
mr3 = atmel_read16(priv->dev, MR3);
|
3571 |
|
|
|
3572 |
|
|
if (mr3 & MAC_BOOT_COMPLETE)
|
3573 |
|
|
break;
|
3574 |
|
|
if (mr1 & MAC_BOOT_COMPLETE &&
|
3575 |
|
|
priv->bus_type == BUS_TYPE_PCCARD)
|
3576 |
|
|
break;
|
3577 |
|
|
}
|
3578 |
|
|
|
3579 |
|
|
if (i == 0) {
|
3580 |
|
|
printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name);
|
3581 |
|
|
return 0;
|
3582 |
|
|
}
|
3583 |
|
|
|
3584 |
|
|
if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) {
|
3585 |
|
|
printk(KERN_ALERT "%s: card missing.\n", priv->dev->name);
|
3586 |
|
|
return 0;
|
3587 |
|
|
}
|
3588 |
|
|
|
3589 |
|
|
/* now check for completion of MAC initialization through
|
3590 |
|
|
the FunCtrl field of the IFACE, poll MR1 to detect completion of
|
3591 |
|
|
MAC initialization, check completion status, set interrupt mask,
|
3592 |
|
|
enables interrupts and calls Tx and Rx initialization functions */
|
3593 |
|
|
|
3594 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE);
|
3595 |
|
|
|
3596 |
|
|
for (i = LOOP_RETRY_LIMIT; i; i--) {
|
3597 |
|
|
mr1 = atmel_read16(priv->dev, MR1);
|
3598 |
|
|
mr3 = atmel_read16(priv->dev, MR3);
|
3599 |
|
|
|
3600 |
|
|
if (mr3 & MAC_INIT_COMPLETE)
|
3601 |
|
|
break;
|
3602 |
|
|
if (mr1 & MAC_INIT_COMPLETE &&
|
3603 |
|
|
priv->bus_type == BUS_TYPE_PCCARD)
|
3604 |
|
|
break;
|
3605 |
|
|
}
|
3606 |
|
|
|
3607 |
|
|
if (i == 0) {
|
3608 |
|
|
printk(KERN_ALERT "%s: MAC failed to initialise.\n",
|
3609 |
|
|
priv->dev->name);
|
3610 |
|
|
return 0;
|
3611 |
|
|
}
|
3612 |
|
|
|
3613 |
|
|
/* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */
|
3614 |
|
|
if ((mr3 & MAC_INIT_COMPLETE) &&
|
3615 |
|
|
!(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) {
|
3616 |
|
|
printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name);
|
3617 |
|
|
return 0;
|
3618 |
|
|
}
|
3619 |
|
|
if ((mr1 & MAC_INIT_COMPLETE) &&
|
3620 |
|
|
!(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) {
|
3621 |
|
|
printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name);
|
3622 |
|
|
return 0;
|
3623 |
|
|
}
|
3624 |
|
|
|
3625 |
|
|
atmel_copy_to_host(priv->dev, (unsigned char *)iface,
|
3626 |
|
|
priv->host_info_base, sizeof(*iface));
|
3627 |
|
|
|
3628 |
|
|
iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos);
|
3629 |
|
|
iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size);
|
3630 |
|
|
iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos);
|
3631 |
|
|
iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count);
|
3632 |
|
|
iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos);
|
3633 |
|
|
iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size);
|
3634 |
|
|
iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos);
|
3635 |
|
|
iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count);
|
3636 |
|
|
iface->build_version = le16_to_cpu(iface->build_version);
|
3637 |
|
|
iface->command_pos = le16_to_cpu(iface->command_pos);
|
3638 |
|
|
iface->major_version = le16_to_cpu(iface->major_version);
|
3639 |
|
|
iface->minor_version = le16_to_cpu(iface->minor_version);
|
3640 |
|
|
iface->func_ctrl = le16_to_cpu(iface->func_ctrl);
|
3641 |
|
|
iface->mac_status = le16_to_cpu(iface->mac_status);
|
3642 |
|
|
|
3643 |
|
|
return 1;
|
3644 |
|
|
}
|
3645 |
|
|
|
3646 |
|
|
/* determine type of memory and MAC address */
|
3647 |
|
|
static int probe_atmel_card(struct net_device *dev)
|
3648 |
|
|
{
|
3649 |
|
|
int rc = 0;
|
3650 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
3651 |
|
|
|
3652 |
|
|
/* reset pccard */
|
3653 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD)
|
3654 |
|
|
atmel_write16(dev, GCR, 0x0060);
|
3655 |
|
|
|
3656 |
|
|
atmel_write16(dev, GCR, 0x0040);
|
3657 |
|
|
mdelay(500);
|
3658 |
|
|
|
3659 |
|
|
if (atmel_read16(dev, MR2) == 0) {
|
3660 |
|
|
/* No stored firmware so load a small stub which just
|
3661 |
|
|
tells us the MAC address */
|
3662 |
|
|
int i;
|
3663 |
|
|
priv->card_type = CARD_TYPE_EEPROM;
|
3664 |
|
|
atmel_write16(dev, BSR, BSS_IRAM);
|
3665 |
|
|
atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader));
|
3666 |
|
|
atmel_set_gcr(dev, GCR_REMAP);
|
3667 |
|
|
atmel_clear_gcr(priv->dev, 0x0040);
|
3668 |
|
|
atmel_write16(dev, BSR, BSS_SRAM);
|
3669 |
|
|
for (i = LOOP_RETRY_LIMIT; i; i--)
|
3670 |
|
|
if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE)
|
3671 |
|
|
break;
|
3672 |
|
|
if (i == 0) {
|
3673 |
|
|
printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name);
|
3674 |
|
|
} else {
|
3675 |
|
|
atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6);
|
3676 |
|
|
/* got address, now squash it again until the network
|
3677 |
|
|
interface is opened */
|
3678 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD)
|
3679 |
|
|
atmel_write16(dev, GCR, 0x0060);
|
3680 |
|
|
atmel_write16(dev, GCR, 0x0040);
|
3681 |
|
|
rc = 1;
|
3682 |
|
|
}
|
3683 |
|
|
} else if (atmel_read16(dev, MR4) == 0) {
|
3684 |
|
|
/* Mac address easy in this case. */
|
3685 |
|
|
priv->card_type = CARD_TYPE_PARALLEL_FLASH;
|
3686 |
|
|
atmel_write16(dev, BSR, 1);
|
3687 |
|
|
atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6);
|
3688 |
|
|
atmel_write16(dev, BSR, 0x200);
|
3689 |
|
|
rc = 1;
|
3690 |
|
|
} else {
|
3691 |
|
|
/* Standard firmware in flash, boot it up and ask
|
3692 |
|
|
for the Mac Address */
|
3693 |
|
|
priv->card_type = CARD_TYPE_SPI_FLASH;
|
3694 |
|
|
if (atmel_wakeup_firmware(priv)) {
|
3695 |
|
|
atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6);
|
3696 |
|
|
|
3697 |
|
|
/* got address, now squash it again until the network
|
3698 |
|
|
interface is opened */
|
3699 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD)
|
3700 |
|
|
atmel_write16(dev, GCR, 0x0060);
|
3701 |
|
|
atmel_write16(dev, GCR, 0x0040);
|
3702 |
|
|
rc = 1;
|
3703 |
|
|
}
|
3704 |
|
|
}
|
3705 |
|
|
|
3706 |
|
|
if (rc) {
|
3707 |
|
|
if (dev->dev_addr[0] == 0xFF) {
|
3708 |
|
|
u8 default_mac[] = {0x00,0x04, 0x25, 0x00, 0x00, 0x00};
|
3709 |
|
|
printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
|
3710 |
|
|
memcpy(dev->dev_addr, default_mac, 6);
|
3711 |
|
|
}
|
3712 |
|
|
}
|
3713 |
|
|
|
3714 |
|
|
return rc;
|
3715 |
|
|
}
|
3716 |
|
|
|
3717 |
|
|
/* Move the encyption information on the MIB structure.
|
3718 |
|
|
This routine is for the pre-WPA firmware: later firmware has
|
3719 |
|
|
a different format MIB and a different routine. */
|
3720 |
|
|
static void build_wep_mib(struct atmel_private *priv)
|
3721 |
|
|
{
|
3722 |
|
|
struct { /* NB this is matched to the hardware, don't change. */
|
3723 |
|
|
u8 wep_is_on;
|
3724 |
|
|
u8 default_key; /* 0..3 */
|
3725 |
|
|
u8 reserved;
|
3726 |
|
|
u8 exclude_unencrypted;
|
3727 |
|
|
|
3728 |
|
|
u32 WEPICV_error_count;
|
3729 |
|
|
u32 WEP_excluded_count;
|
3730 |
|
|
|
3731 |
|
|
u8 wep_keys[MAX_ENCRYPTION_KEYS][13];
|
3732 |
|
|
u8 encryption_level; /* 0, 1, 2 */
|
3733 |
|
|
u8 reserved2[3];
|
3734 |
|
|
} mib;
|
3735 |
|
|
int i;
|
3736 |
|
|
|
3737 |
|
|
mib.wep_is_on = priv->wep_is_on;
|
3738 |
|
|
if (priv->wep_is_on) {
|
3739 |
|
|
if (priv->wep_key_len[priv->default_key] > 5)
|
3740 |
|
|
mib.encryption_level = 2;
|
3741 |
|
|
else
|
3742 |
|
|
mib.encryption_level = 1;
|
3743 |
|
|
} else {
|
3744 |
|
|
mib.encryption_level = 0;
|
3745 |
|
|
}
|
3746 |
|
|
|
3747 |
|
|
mib.default_key = priv->default_key;
|
3748 |
|
|
mib.exclude_unencrypted = priv->exclude_unencrypted;
|
3749 |
|
|
|
3750 |
|
|
for (i = 0; i < MAX_ENCRYPTION_KEYS; i++)
|
3751 |
|
|
memcpy(mib.wep_keys[i], priv->wep_keys[i], 13);
|
3752 |
|
|
|
3753 |
|
|
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
|
3754 |
|
|
}
|
3755 |
|
|
|
3756 |
|
|
static void build_wpa_mib(struct atmel_private *priv)
|
3757 |
|
|
{
|
3758 |
|
|
/* This is for the later (WPA enabled) firmware. */
|
3759 |
|
|
|
3760 |
|
|
struct { /* NB this is matched to the hardware, don't change. */
|
3761 |
|
|
u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
|
3762 |
|
|
u8 receiver_address[6];
|
3763 |
|
|
u8 wep_is_on;
|
3764 |
|
|
u8 default_key; /* 0..3 */
|
3765 |
|
|
u8 group_key;
|
3766 |
|
|
u8 exclude_unencrypted;
|
3767 |
|
|
u8 encryption_type;
|
3768 |
|
|
u8 reserved;
|
3769 |
|
|
|
3770 |
|
|
u32 WEPICV_error_count;
|
3771 |
|
|
u32 WEP_excluded_count;
|
3772 |
|
|
|
3773 |
|
|
u8 key_RSC[4][8];
|
3774 |
|
|
} mib;
|
3775 |
|
|
|
3776 |
|
|
int i;
|
3777 |
|
|
|
3778 |
|
|
mib.wep_is_on = priv->wep_is_on;
|
3779 |
|
|
mib.exclude_unencrypted = priv->exclude_unencrypted;
|
3780 |
|
|
memcpy(mib.receiver_address, priv->CurrentBSSID, 6);
|
3781 |
|
|
|
3782 |
|
|
/* zero all the keys before adding in valid ones. */
|
3783 |
|
|
memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value));
|
3784 |
|
|
|
3785 |
|
|
if (priv->wep_is_on) {
|
3786 |
|
|
/* There's a comment in the Atmel code to the effect that this
|
3787 |
|
|
is only valid when still using WEP, it may need to be set to
|
3788 |
|
|
something to use WPA */
|
3789 |
|
|
memset(mib.key_RSC, 0, sizeof(mib.key_RSC));
|
3790 |
|
|
|
3791 |
|
|
mib.default_key = mib.group_key = 255;
|
3792 |
|
|
for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) {
|
3793 |
|
|
if (priv->wep_key_len[i] > 0) {
|
3794 |
|
|
memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE);
|
3795 |
|
|
if (i == priv->default_key) {
|
3796 |
|
|
mib.default_key = i;
|
3797 |
|
|
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7;
|
3798 |
|
|
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite;
|
3799 |
|
|
} else {
|
3800 |
|
|
mib.group_key = i;
|
3801 |
|
|
priv->group_cipher_suite = priv->pairwise_cipher_suite;
|
3802 |
|
|
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1;
|
3803 |
|
|
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite;
|
3804 |
|
|
}
|
3805 |
|
|
}
|
3806 |
|
|
}
|
3807 |
|
|
if (mib.default_key == 255)
|
3808 |
|
|
mib.default_key = mib.group_key != 255 ? mib.group_key : 0;
|
3809 |
|
|
if (mib.group_key == 255)
|
3810 |
|
|
mib.group_key = mib.default_key;
|
3811 |
|
|
|
3812 |
|
|
}
|
3813 |
|
|
|
3814 |
|
|
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
|
3815 |
|
|
}
|
3816 |
|
|
|
3817 |
|
|
static int reset_atmel_card(struct net_device *dev)
|
3818 |
|
|
{
|
3819 |
|
|
/* do everything necessary to wake up the hardware, including
|
3820 |
|
|
waiting for the lightning strike and throwing the knife switch....
|
3821 |
|
|
|
3822 |
|
|
set all the Mib values which matter in the card to match
|
3823 |
|
|
their settings in the atmel_private structure. Some of these
|
3824 |
|
|
can be altered on the fly, but many (WEP, infrastucture or ad-hoc)
|
3825 |
|
|
can only be changed by tearing down the world and coming back through
|
3826 |
|
|
here.
|
3827 |
|
|
|
3828 |
|
|
This routine is also responsible for initialising some
|
3829 |
|
|
hardware-specific fields in the atmel_private structure,
|
3830 |
|
|
including a copy of the firmware's hostinfo stucture
|
3831 |
|
|
which is the route into the rest of the firmare datastructures. */
|
3832 |
|
|
|
3833 |
|
|
struct atmel_private *priv = netdev_priv(dev);
|
3834 |
|
|
u8 configuration;
|
3835 |
|
|
int old_state = priv->station_state;
|
3836 |
|
|
|
3837 |
|
|
/* data to add to the firmware names, in priority order
|
3838 |
|
|
this implemenents firmware versioning */
|
3839 |
|
|
|
3840 |
|
|
static char *firmware_modifier[] = {
|
3841 |
|
|
"-wpa",
|
3842 |
|
|
"",
|
3843 |
|
|
NULL
|
3844 |
|
|
};
|
3845 |
|
|
|
3846 |
|
|
/* reset pccard */
|
3847 |
|
|
if (priv->bus_type == BUS_TYPE_PCCARD)
|
3848 |
|
|
atmel_write16(priv->dev, GCR, 0x0060);
|
3849 |
|
|
|
3850 |
|
|
/* stop card , disable interrupts */
|
3851 |
|
|
atmel_write16(priv->dev, GCR, 0x0040);
|
3852 |
|
|
|
3853 |
|
|
if (priv->card_type == CARD_TYPE_EEPROM) {
|
3854 |
|
|
/* copy in firmware if needed */
|
3855 |
|
|
const struct firmware *fw_entry = NULL;
|
3856 |
|
|
unsigned char *fw;
|
3857 |
|
|
int len = priv->firmware_length;
|
3858 |
|
|
if (!(fw = priv->firmware)) {
|
3859 |
|
|
if (priv->firmware_type == ATMEL_FW_TYPE_NONE) {
|
3860 |
|
|
if (strlen(priv->firmware_id) == 0) {
|
3861 |
|
|
printk(KERN_INFO
|
3862 |
|
|
"%s: card type is unknown: assuming at76c502 firmware is OK.\n",
|
3863 |
|
|
dev->name);
|
3864 |
|
|
printk(KERN_INFO
|
3865 |
|
|
"%s: if not, use the firmware= module parameter.\n",
|
3866 |
|
|
dev->name);
|
3867 |
|
|
strcpy(priv->firmware_id, "atmel_at76c502.bin");
|
3868 |
|
|
}
|
3869 |
|
|
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) {
|
3870 |
|
|
printk(KERN_ALERT
|
3871 |
|
|
"%s: firmware %s is missing, cannot continue.\n",
|
3872 |
|
|
dev->name, priv->firmware_id);
|
3873 |
|
|
return 0;
|
3874 |
|
|
}
|
3875 |
|
|
} else {
|
3876 |
|
|
int fw_index = 0;
|
3877 |
|
|
int success = 0;
|
3878 |
|
|
|
3879 |
|
|
/* get firmware filename entry based on firmware type ID */
|
3880 |
|
|
while (fw_table[fw_index].fw_type != priv->firmware_type
|
3881 |
|
|
&& fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE)
|
3882 |
|
|
fw_index++;
|
3883 |
|
|
|
3884 |
|
|
/* construct the actual firmware file name */
|
3885 |
|
|
if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) {
|
3886 |
|
|
int i;
|
3887 |
|
|
for (i = 0; firmware_modifier[i]; i++) {
|
3888 |
|
|
snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file,
|
3889 |
|
|
firmware_modifier[i], fw_table[fw_index].fw_file_ext);
|
3890 |
|
|
priv->firmware_id[31] = '\0';
|
3891 |
|
|
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) {
|
3892 |
|
|
success = 1;
|
3893 |
|
|
break;
|
3894 |
|
|
}
|
3895 |
|
|
}
|
3896 |
|
|
}
|
3897 |
|
|
if (!success) {
|
3898 |
|
|
printk(KERN_ALERT
|
3899 |
|
|
"%s: firmware %s is missing, cannot start.\n",
|
3900 |
|
|
dev->name, priv->firmware_id);
|
3901 |
|
|
priv->firmware_id[0] = '\0';
|
3902 |
|
|
return 0;
|
3903 |
|
|
}
|
3904 |
|
|
}
|
3905 |
|
|
|
3906 |
|
|
fw = fw_entry->data;
|
3907 |
|
|
len = fw_entry->size;
|
3908 |
|
|
}
|
3909 |
|
|
|
3910 |
|
|
if (len <= 0x6000) {
|
3911 |
|
|
atmel_write16(priv->dev, BSR, BSS_IRAM);
|
3912 |
|
|
atmel_copy_to_card(priv->dev, 0, fw, len);
|
3913 |
|
|
atmel_set_gcr(priv->dev, GCR_REMAP);
|
3914 |
|
|
} else {
|
3915 |
|
|
/* Remap */
|
3916 |
|
|
atmel_set_gcr(priv->dev, GCR_REMAP);
|
3917 |
|
|
atmel_write16(priv->dev, BSR, BSS_IRAM);
|
3918 |
|
|
atmel_copy_to_card(priv->dev, 0, fw, 0x6000);
|
3919 |
|
|
atmel_write16(priv->dev, BSR, 0x2ff);
|
3920 |
|
|
atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000);
|
3921 |
|
|
}
|
3922 |
|
|
|
3923 |
|
|
if (fw_entry)
|
3924 |
|
|
release_firmware(fw_entry);
|
3925 |
|
|
}
|
3926 |
|
|
|
3927 |
|
|
if (!atmel_wakeup_firmware(priv))
|
3928 |
|
|
return 0;
|
3929 |
|
|
|
3930 |
|
|
/* Check the version and set the correct flag for wpa stuff,
|
3931 |
|
|
old and new firmware is incompatible.
|
3932 |
|
|
The pre-wpa 3com firmware reports major version 5,
|
3933 |
|
|
the wpa 3com firmware is major version 4 and doesn't need
|
3934 |
|
|
the 3com broken-ness filter. */
|
3935 |
|
|
priv->use_wpa = (priv->host_info.major_version == 4);
|
3936 |
|
|
priv->radio_on_broken = (priv->host_info.major_version == 5);
|
3937 |
|
|
|
3938 |
|
|
/* unmask all irq sources */
|
3939 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff);
|
3940 |
|
|
|
3941 |
|
|
/* int Tx system and enable Tx */
|
3942 |
|
|
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0);
|
3943 |
|
|
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L);
|
3944 |
|
|
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0);
|
3945 |
|
|
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0);
|
3946 |
|
|
|
3947 |
|
|
priv->tx_desc_free = priv->host_info.tx_desc_count;
|
3948 |
|
|
priv->tx_desc_head = 0;
|
3949 |
|
|
priv->tx_desc_tail = 0;
|
3950 |
|
|
priv->tx_desc_previous = 0;
|
3951 |
|
|
priv->tx_free_mem = priv->host_info.tx_buff_size;
|
3952 |
|
|
priv->tx_buff_head = 0;
|
3953 |
|
|
priv->tx_buff_tail = 0;
|
3954 |
|
|
|
3955 |
|
|
configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET));
|
3956 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET),
|
3957 |
|
|
configuration | FUNC_CTRL_TxENABLE);
|
3958 |
|
|
|
3959 |
|
|
/* init Rx system and enable */
|
3960 |
|
|
priv->rx_desc_head = 0;
|
3961 |
|
|
|
3962 |
|
|
configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET));
|
3963 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET),
|
3964 |
|
|
configuration | FUNC_CTRL_RxENABLE);
|
3965 |
|
|
|
3966 |
|
|
if (!priv->radio_on_broken) {
|
3967 |
|
|
if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) ==
|
3968 |
|
|
CMD_STATUS_REJECTED_RADIO_OFF) {
|
3969 |
|
|
printk(KERN_INFO
|
3970 |
|
|
"%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n",
|
3971 |
|
|
dev->name);
|
3972 |
|
|
return 0;
|
3973 |
|
|
}
|
3974 |
|
|
}
|
3975 |
|
|
|
3976 |
|
|
/* set up enough MIB values to run. */
|
3977 |
|
|
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate);
|
3978 |
|
|
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF);
|
3979 |
|
|
atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold);
|
3980 |
|
|
atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold);
|
3981 |
|
|
atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry);
|
3982 |
|
|
atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry);
|
3983 |
|
|
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble);
|
3984 |
|
|
atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS,
|
3985 |
|
|
priv->dev->dev_addr, 6);
|
3986 |
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
3987 |
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
3988 |
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period);
|
3989 |
|
|
atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4);
|
3990 |
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on);
|
3991 |
|
|
if (priv->use_wpa)
|
3992 |
|
|
build_wpa_mib(priv);
|
3993 |
|
|
else
|
3994 |
|
|
build_wep_mib(priv);
|
3995 |
|
|
|
3996 |
|
|
if (old_state == STATION_STATE_READY)
|
3997 |
|
|
{
|
3998 |
|
|
union iwreq_data wrqu;
|
3999 |
|
|
|
4000 |
|
|
wrqu.data.length = 0;
|
4001 |
|
|
wrqu.data.flags = 0;
|
4002 |
|
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
4003 |
|
|
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
|
4004 |
|
|
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
4005 |
|
|
}
|
4006 |
|
|
|
4007 |
|
|
return 1;
|
4008 |
|
|
}
|
4009 |
|
|
|
4010 |
|
|
static void atmel_send_command(struct atmel_private *priv, int command,
|
4011 |
|
|
void *cmd, int cmd_size)
|
4012 |
|
|
{
|
4013 |
|
|
if (cmd)
|
4014 |
|
|
atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET),
|
4015 |
|
|
cmd, cmd_size);
|
4016 |
|
|
|
4017 |
|
|
atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command);
|
4018 |
|
|
atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0);
|
4019 |
|
|
}
|
4020 |
|
|
|
4021 |
|
|
static int atmel_send_command_wait(struct atmel_private *priv, int command,
|
4022 |
|
|
void *cmd, int cmd_size)
|
4023 |
|
|
{
|
4024 |
|
|
int i, status;
|
4025 |
|
|
|
4026 |
|
|
atmel_send_command(priv, command, cmd, cmd_size);
|
4027 |
|
|
|
4028 |
|
|
for (i = 5000; i; i--) {
|
4029 |
|
|
status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET));
|
4030 |
|
|
if (status != CMD_STATUS_IDLE &&
|
4031 |
|
|
status != CMD_STATUS_IN_PROGRESS)
|
4032 |
|
|
break;
|
4033 |
|
|
udelay(20);
|
4034 |
|
|
}
|
4035 |
|
|
|
4036 |
|
|
if (i == 0) {
|
4037 |
|
|
printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name);
|
4038 |
|
|
status = CMD_STATUS_HOST_ERROR;
|
4039 |
|
|
} else {
|
4040 |
|
|
if (command != CMD_EnableRadio)
|
4041 |
|
|
status = CMD_STATUS_COMPLETE;
|
4042 |
|
|
}
|
4043 |
|
|
|
4044 |
|
|
return status;
|
4045 |
|
|
}
|
4046 |
|
|
|
4047 |
|
|
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index)
|
4048 |
|
|
{
|
4049 |
|
|
struct get_set_mib m;
|
4050 |
|
|
m.type = type;
|
4051 |
|
|
m.size = 1;
|
4052 |
|
|
m.index = index;
|
4053 |
|
|
|
4054 |
|
|
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
|
4055 |
|
|
return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE));
|
4056 |
|
|
}
|
4057 |
|
|
|
4058 |
|
|
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data)
|
4059 |
|
|
{
|
4060 |
|
|
struct get_set_mib m;
|
4061 |
|
|
m.type = type;
|
4062 |
|
|
m.size = 1;
|
4063 |
|
|
m.index = index;
|
4064 |
|
|
m.data[0] = data;
|
4065 |
|
|
|
4066 |
|
|
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
|
4067 |
|
|
}
|
4068 |
|
|
|
4069 |
|
|
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
|
4070 |
|
|
u16 data)
|
4071 |
|
|
{
|
4072 |
|
|
struct get_set_mib m;
|
4073 |
|
|
m.type = type;
|
4074 |
|
|
m.size = 2;
|
4075 |
|
|
m.index = index;
|
4076 |
|
|
m.data[0] = data;
|
4077 |
|
|
m.data[1] = data >> 8;
|
4078 |
|
|
|
4079 |
|
|
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2);
|
4080 |
|
|
}
|
4081 |
|
|
|
4082 |
|
|
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
|
4083 |
|
|
u8 *data, int data_len)
|
4084 |
|
|
{
|
4085 |
|
|
struct get_set_mib m;
|
4086 |
|
|
m.type = type;
|
4087 |
|
|
m.size = data_len;
|
4088 |
|
|
m.index = index;
|
4089 |
|
|
|
4090 |
|
|
if (data_len > MIB_MAX_DATA_BYTES)
|
4091 |
|
|
printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
|
4092 |
|
|
|
4093 |
|
|
memcpy(m.data, data, data_len);
|
4094 |
|
|
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
|
4095 |
|
|
}
|
4096 |
|
|
|
4097 |
|
|
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
|
4098 |
|
|
u8 *data, int data_len)
|
4099 |
|
|
{
|
4100 |
|
|
struct get_set_mib m;
|
4101 |
|
|
m.type = type;
|
4102 |
|
|
m.size = data_len;
|
4103 |
|
|
m.index = index;
|
4104 |
|
|
|
4105 |
|
|
if (data_len > MIB_MAX_DATA_BYTES)
|
4106 |
|
|
printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
|
4107 |
|
|
|
4108 |
|
|
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
|
4109 |
|
|
atmel_copy_to_host(priv->dev, data,
|
4110 |
|
|
atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len);
|
4111 |
|
|
}
|
4112 |
|
|
|
4113 |
|
|
static void atmel_writeAR(struct net_device *dev, u16 data)
|
4114 |
|
|
{
|
4115 |
|
|
int i;
|
4116 |
|
|
outw(data, dev->base_addr + AR);
|
4117 |
|
|
/* Address register appears to need some convincing..... */
|
4118 |
|
|
for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++)
|
4119 |
|
|
outw(data, dev->base_addr + AR);
|
4120 |
|
|
}
|
4121 |
|
|
|
4122 |
|
|
static void atmel_copy_to_card(struct net_device *dev, u16 dest,
|
4123 |
|
|
unsigned char *src, u16 len)
|
4124 |
|
|
{
|
4125 |
|
|
int i;
|
4126 |
|
|
atmel_writeAR(dev, dest);
|
4127 |
|
|
if (dest % 2) {
|
4128 |
|
|
atmel_write8(dev, DR, *src);
|
4129 |
|
|
src++; len--;
|
4130 |
|
|
}
|
4131 |
|
|
for (i = len; i > 1 ; i -= 2) {
|
4132 |
|
|
u8 lb = *src++;
|
4133 |
|
|
u8 hb = *src++;
|
4134 |
|
|
atmel_write16(dev, DR, lb | (hb << 8));
|
4135 |
|
|
}
|
4136 |
|
|
if (i)
|
4137 |
|
|
atmel_write8(dev, DR, *src);
|
4138 |
|
|
}
|
4139 |
|
|
|
4140 |
|
|
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest,
|
4141 |
|
|
u16 src, u16 len)
|
4142 |
|
|
{
|
4143 |
|
|
int i;
|
4144 |
|
|
atmel_writeAR(dev, src);
|
4145 |
|
|
if (src % 2) {
|
4146 |
|
|
*dest = atmel_read8(dev, DR);
|
4147 |
|
|
dest++; len--;
|
4148 |
|
|
}
|
4149 |
|
|
for (i = len; i > 1 ; i -= 2) {
|
4150 |
|
|
u16 hw = atmel_read16(dev, DR);
|
4151 |
|
|
*dest++ = hw;
|
4152 |
|
|
*dest++ = hw >> 8;
|
4153 |
|
|
}
|
4154 |
|
|
if (i)
|
4155 |
|
|
*dest = atmel_read8(dev, DR);
|
4156 |
|
|
}
|
4157 |
|
|
|
4158 |
|
|
static void atmel_set_gcr(struct net_device *dev, u16 mask)
|
4159 |
|
|
{
|
4160 |
|
|
outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR);
|
4161 |
|
|
}
|
4162 |
|
|
|
4163 |
|
|
static void atmel_clear_gcr(struct net_device *dev, u16 mask)
|
4164 |
|
|
{
|
4165 |
|
|
outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR);
|
4166 |
|
|
}
|
4167 |
|
|
|
4168 |
|
|
static int atmel_lock_mac(struct atmel_private *priv)
|
4169 |
|
|
{
|
4170 |
|
|
int i, j = 20;
|
4171 |
|
|
retry:
|
4172 |
|
|
for (i = 5000; i; i--) {
|
4173 |
|
|
if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET)))
|
4174 |
|
|
break;
|
4175 |
|
|
udelay(20);
|
4176 |
|
|
}
|
4177 |
|
|
|
4178 |
|
|
if (!i)
|
4179 |
|
|
return 0; /* timed out */
|
4180 |
|
|
|
4181 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1);
|
4182 |
|
|
if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) {
|
4183 |
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
|
4184 |
|
|
if (!j--)
|
4185 |
|
|
return 0; /* timed out */
|
4186 |
|
|
goto retry;
|
4187 |
|
|
}
|
4188 |
|
|
|
4189 |
|
|
return 1;
|
4190 |
|
|
}
|
4191 |
|
|
|
4192 |
|
|
static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data)
|
4193 |
|
|
{
|
4194 |
|
|
atmel_writeAR(priv->dev, pos);
|
4195 |
|
|
atmel_write16(priv->dev, DR, data); /* card is little-endian */
|
4196 |
|
|
atmel_write16(priv->dev, DR, data >> 16);
|
4197 |
|
|
}
|
4198 |
|
|
|
4199 |
|
|
/***************************************************************************/
|
4200 |
|
|
/* There follows the source form of the MAC address reading firmware */
|
4201 |
|
|
/***************************************************************************/
|
4202 |
|
|
#if 0
|
4203 |
|
|
|
4204 |
|
|
/* Copyright 2003 Matthew T. Russotto */
|
4205 |
|
|
/* But derived from the Atmel 76C502 firmware written by Atmel and */
|
4206 |
|
|
/* included in "atmel wireless lan drivers" package */
|
4207 |
|
|
/**
|
4208 |
|
|
This file is part of net.russotto.AtmelMACFW, hereto referred to
|
4209 |
|
|
as AtmelMACFW
|
4210 |
|
|
|
4211 |
|
|
AtmelMACFW is free software; you can redistribute it and/or modify
|
4212 |
|
|
it under the terms of the GNU General Public License version 2
|
4213 |
|
|
as published by the Free Software Foundation.
|
4214 |
|
|
|
4215 |
|
|
AtmelMACFW is distributed in the hope that it will be useful,
|
4216 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
4217 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
4218 |
|
|
GNU General Public License for more details.
|
4219 |
|
|
|
4220 |
|
|
You should have received a copy of the GNU General Public License
|
4221 |
|
|
along with AtmelMACFW; if not, write to the Free Software
|
4222 |
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
4223 |
|
|
|
4224 |
|
|
****************************************************************************/
|
4225 |
|
|
/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */
|
4226 |
|
|
/* It will probably work on the 76C504 and 76C502 RFMD_3COM */
|
4227 |
|
|
/* It only works on SPI EEPROM versions of the card. */
|
4228 |
|
|
|
4229 |
|
|
/* This firmware initializes the SPI controller and clock, reads the MAC */
|
4230 |
|
|
/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */
|
4231 |
|
|
/* address in MR2, and sets MR3 to 0x10 to indicate it is done */
|
4232 |
|
|
/* It also puts a complete copy of the EEPROM in SRAM with the offset in */
|
4233 |
|
|
/* MR4, for investigational purposes (maybe we can determine chip type */
|
4234 |
|
|
/* from that?) */
|
4235 |
|
|
|
4236 |
|
|
.org 0
|
4237 |
|
|
.set MRBASE, 0x8000000
|
4238 |
|
|
.set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */
|
4239 |
|
|
.set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */
|
4240 |
|
|
.set SRAM_BASE, 0x02000000
|
4241 |
|
|
.set SP_BASE, 0x0F300000
|
4242 |
|
|
.set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */
|
4243 |
|
|
.set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */
|
4244 |
|
|
.set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */
|
4245 |
|
|
.set STACK_BASE, 0x5600
|
4246 |
|
|
.set SP_SR, 0x10
|
4247 |
|
|
.set SP_TDRE, 2 /* status register bit -- TDR empty */
|
4248 |
|
|
.set SP_RDRF, 1 /* status register bit -- RDR full */
|
4249 |
|
|
.set SP_SWRST, 0x80
|
4250 |
|
|
.set SP_SPIEN, 0x1
|
4251 |
|
|
.set SP_CR, 0 /* control register */
|
4252 |
|
|
.set SP_MR, 4 /* mode register */
|
4253 |
|
|
.set SP_RDR, 0x08 /* Read Data Register */
|
4254 |
|
|
.set SP_TDR, 0x0C /* Transmit Data Register */
|
4255 |
|
|
.set SP_CSR0, 0x30 /* chip select registers */
|
4256 |
|
|
.set SP_CSR1, 0x34
|
4257 |
|
|
.set SP_CSR2, 0x38
|
4258 |
|
|
.set SP_CSR3, 0x3C
|
4259 |
|
|
.set NVRAM_CMD_RDSR, 5 /* read status register */
|
4260 |
|
|
.set NVRAM_CMD_READ, 3 /* read data */
|
4261 |
|
|
.set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */
|
4262 |
|
|
.set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the
|
4263 |
|
|
serial output, since SO is normally high. But it
|
4264 |
|
|
does cause 8 clock cycles and thus 8 bits to be
|
4265 |
|
|
clocked in to the chip. See Atmel's SPI
|
4266 |
|
|
controller (e.g. AT91M55800) timing and 4K
|
4267 |
|
|
SPI EEPROM manuals */
|
4268 |
|
|
|
4269 |
|
|
.set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */
|
4270 |
|
|
.set NVRAM_IMAGE, 0x02000200
|
4271 |
|
|
.set NVRAM_LENGTH, 0x0200
|
4272 |
|
|
.set MAC_ADDRESS_MIB, SRAM_BASE
|
4273 |
|
|
.set MAC_ADDRESS_LENGTH, 6
|
4274 |
|
|
.set MAC_BOOT_FLAG, 0x10
|
4275 |
|
|
.set MR1, 0
|
4276 |
|
|
.set MR2, 4
|
4277 |
|
|
.set MR3, 8
|
4278 |
|
|
.set MR4, 0xC
|
4279 |
|
|
RESET_VECTOR:
|
4280 |
|
|
b RESET_HANDLER
|
4281 |
|
|
UNDEF_VECTOR:
|
4282 |
|
|
b HALT1
|
4283 |
|
|
SWI_VECTOR:
|
4284 |
|
|
b HALT1
|
4285 |
|
|
IABORT_VECTOR:
|
4286 |
|
|
b HALT1
|
4287 |
|
|
DABORT_VECTOR:
|
4288 |
|
|
RESERVED_VECTOR:
|
4289 |
|
|
b HALT1
|
4290 |
|
|
IRQ_VECTOR:
|
4291 |
|
|
b HALT1
|
4292 |
|
|
FIQ_VECTOR:
|
4293 |
|
|
b HALT1
|
4294 |
|
|
HALT1: b HALT1
|
4295 |
|
|
RESET_HANDLER:
|
4296 |
|
|
mov r0, #CPSR_INITIAL
|
4297 |
|
|
msr CPSR_c, r0 /* This is probably unnecessary */
|
4298 |
|
|
|
4299 |
|
|
/* I'm guessing this is initializing clock generator electronics for SPI */
|
4300 |
|
|
ldr r0, =SPI_CGEN_BASE
|
4301 |
|
|
mov r1, #0
|
4302 |
|
|
mov r1, r1, lsl #3
|
4303 |
|
|
orr r1,r1, #0
|
4304 |
|
|
str r1, [r0]
|
4305 |
|
|
ldr r1, [r0, #28]
|
4306 |
|
|
bic r1, r1, #16
|
4307 |
|
|
str r1, [r0, #28]
|
4308 |
|
|
mov r1, #1
|
4309 |
|
|
str r1, [r0, #8]
|
4310 |
|
|
|
4311 |
|
|
ldr r0, =MRBASE
|
4312 |
|
|
mov r1, #0
|
4313 |
|
|
strh r1, [r0, #MR1]
|
4314 |
|
|
strh r1, [r0, #MR2]
|
4315 |
|
|
strh r1, [r0, #MR3]
|
4316 |
|
|
strh r1, [r0, #MR4]
|
4317 |
|
|
|
4318 |
|
|
mov sp, #STACK_BASE
|
4319 |
|
|
bl SP_INIT
|
4320 |
|
|
mov r0, #10
|
4321 |
|
|
bl DELAY9
|
4322 |
|
|
bl GET_MAC_ADDR
|
4323 |
|
|
bl GET_WHOLE_NVRAM
|
4324 |
|
|
ldr r0, =MRBASE
|
4325 |
|
|
ldr r1, =MAC_ADDRESS_MIB
|
4326 |
|
|
strh r1, [r0, #MR2]
|
4327 |
|
|
ldr r1, =NVRAM_IMAGE
|
4328 |
|
|
strh r1, [r0, #MR4]
|
4329 |
|
|
mov r1, #MAC_BOOT_FLAG
|
4330 |
|
|
strh r1, [r0, #MR3]
|
4331 |
|
|
HALT2: b HALT2
|
4332 |
|
|
.func Get_Whole_NVRAM, GET_WHOLE_NVRAM
|
4333 |
|
|
GET_WHOLE_NVRAM:
|
4334 |
|
|
stmdb sp!, {lr}
|
4335 |
|
|
mov r2, #0 /* 0th bytes of NVRAM */
|
4336 |
|
|
mov r3, #NVRAM_LENGTH
|
4337 |
|
|
mov r1, #0 /* not used in routine */
|
4338 |
|
|
ldr r0, =NVRAM_IMAGE
|
4339 |
|
|
bl NVRAM_XFER
|
4340 |
|
|
ldmia sp!, {lr}
|
4341 |
|
|
bx lr
|
4342 |
|
|
.endfunc
|
4343 |
|
|
|
4344 |
|
|
.func Get_MAC_Addr, GET_MAC_ADDR
|
4345 |
|
|
GET_MAC_ADDR:
|
4346 |
|
|
stmdb sp!, {lr}
|
4347 |
|
|
mov r2, #0x120 /* address of MAC Address within NVRAM */
|
4348 |
|
|
mov r3, #MAC_ADDRESS_LENGTH
|
4349 |
|
|
mov r1, #0 /* not used in routine */
|
4350 |
|
|
ldr r0, =MAC_ADDRESS_MIB
|
4351 |
|
|
bl NVRAM_XFER
|
4352 |
|
|
ldmia sp!, {lr}
|
4353 |
|
|
bx lr
|
4354 |
|
|
.endfunc
|
4355 |
|
|
.ltorg
|
4356 |
|
|
.func Delay9, DELAY9
|
4357 |
|
|
DELAY9:
|
4358 |
|
|
adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */
|
4359 |
|
|
DELAYLOOP:
|
4360 |
|
|
beq DELAY9_done
|
4361 |
|
|
subs r0, r0, #1
|
4362 |
|
|
b DELAYLOOP
|
4363 |
|
|
DELAY9_done:
|
4364 |
|
|
bx lr
|
4365 |
|
|
.endfunc
|
4366 |
|
|
|
4367 |
|
|
.func SP_Init, SP_INIT
|
4368 |
|
|
SP_INIT:
|
4369 |
|
|
mov r1, #SP_SWRST
|
4370 |
|
|
ldr r0, =SP_BASE
|
4371 |
|
|
str r1, [r0, #SP_CR] /* reset the SPI */
|
4372 |
|
|
mov r1, #0
|
4373 |
|
|
str r1, [r0, #SP_CR] /* release SPI from reset state */
|
4374 |
|
|
mov r1, #SP_SPIEN
|
4375 |
|
|
str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/
|
4376 |
|
|
str r1, [r0, #SP_CR] /* enable the SPI */
|
4377 |
|
|
|
4378 |
|
|
/* My guess would be this turns on the SPI clock */
|
4379 |
|
|
ldr r3, =SPI_CGEN_BASE
|
4380 |
|
|
ldr r1, [r3, #28]
|
4381 |
|
|
orr r1, r1, #0x2000
|
4382 |
|
|
str r1, [r3, #28]
|
4383 |
|
|
|
4384 |
|
|
ldr r1, =0x2000c01
|
4385 |
|
|
str r1, [r0, #SP_CSR0]
|
4386 |
|
|
ldr r1, =0x2000201
|
4387 |
|
|
str r1, [r0, #SP_CSR1]
|
4388 |
|
|
str r1, [r0, #SP_CSR2]
|
4389 |
|
|
str r1, [r0, #SP_CSR3]
|
4390 |
|
|
ldr r1, [r0, #SP_SR]
|
4391 |
|
|
ldr r0, [r0, #SP_RDR]
|
4392 |
|
|
bx lr
|
4393 |
|
|
.endfunc
|
4394 |
|
|
.func NVRAM_Init, NVRAM_INIT
|
4395 |
|
|
NVRAM_INIT:
|
4396 |
|
|
ldr r1, =SP_BASE
|
4397 |
|
|
ldr r0, [r1, #SP_RDR]
|
4398 |
|
|
mov r0, #NVRAM_CMD_RDSR
|
4399 |
|
|
str r0, [r1, #SP_TDR]
|
4400 |
|
|
SP_loop1:
|
4401 |
|
|
ldr r0, [r1, #SP_SR]
|
4402 |
|
|
tst r0, #SP_TDRE
|
4403 |
|
|
beq SP_loop1
|
4404 |
|
|
|
4405 |
|
|
mov r0, #SPI_8CLOCKS
|
4406 |
|
|
str r0, [r1, #SP_TDR]
|
4407 |
|
|
SP_loop2:
|
4408 |
|
|
ldr r0, [r1, #SP_SR]
|
4409 |
|
|
tst r0, #SP_TDRE
|
4410 |
|
|
beq SP_loop2
|
4411 |
|
|
|
4412 |
|
|
ldr r0, [r1, #SP_RDR]
|
4413 |
|
|
SP_loop3:
|
4414 |
|
|
ldr r0, [r1, #SP_SR]
|
4415 |
|
|
tst r0, #SP_RDRF
|
4416 |
|
|
beq SP_loop3
|
4417 |
|
|
|
4418 |
|
|
ldr r0, [r1, #SP_RDR]
|
4419 |
|
|
and r0, r0, #255
|
4420 |
|
|
bx lr
|
4421 |
|
|
.endfunc
|
4422 |
|
|
|
4423 |
|
|
.func NVRAM_Xfer, NVRAM_XFER
|
4424 |
|
|
/* r0 = dest address */
|
4425 |
|
|
/* r1 = not used */
|
4426 |
|
|
/* r2 = src address within NVRAM */
|
4427 |
|
|
/* r3 = length */
|
4428 |
|
|
NVRAM_XFER:
|
4429 |
|
|
stmdb sp!, {r4, r5, lr}
|
4430 |
|
|
mov r5, r0 /* save r0 (dest address) */
|
4431 |
|
|
mov r4, r3 /* save r3 (length) */
|
4432 |
|
|
mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */
|
4433 |
|
|
and r0, r0, #8
|
4434 |
|
|
add r0, r0, #NVRAM_CMD_READ
|
4435 |
|
|
ldr r1, =NVRAM_SCRATCH
|
4436 |
|
|
strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */
|
4437 |
|
|
strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */
|
4438 |
|
|
_local1:
|
4439 |
|
|
bl NVRAM_INIT
|
4440 |
|
|
tst r0, #NVRAM_SR_RDY
|
4441 |
|
|
bne _local1
|
4442 |
|
|
mov r0, #20
|
4443 |
|
|
bl DELAY9
|
4444 |
|
|
mov r2, r4 /* length */
|
4445 |
|
|
mov r1, r5 /* dest address */
|
4446 |
|
|
mov r0, #2 /* bytes to transfer in command */
|
4447 |
|
|
bl NVRAM_XFER2
|
4448 |
|
|
ldmia sp!, {r4, r5, lr}
|
4449 |
|
|
bx lr
|
4450 |
|
|
.endfunc
|
4451 |
|
|
|
4452 |
|
|
.func NVRAM_Xfer2, NVRAM_XFER2
|
4453 |
|
|
NVRAM_XFER2:
|
4454 |
|
|
stmdb sp!, {r4, r5, r6, lr}
|
4455 |
|
|
ldr r4, =SP_BASE
|
4456 |
|
|
mov r3, #0
|
4457 |
|
|
cmp r0, #0
|
4458 |
|
|
bls _local2
|
4459 |
|
|
ldr r5, =NVRAM_SCRATCH
|
4460 |
|
|
_local4:
|
4461 |
|
|
ldrb r6, [r5, r3]
|
4462 |
|
|
str r6, [r4, #SP_TDR]
|
4463 |
|
|
_local3:
|
4464 |
|
|
ldr r6, [r4, #SP_SR]
|
4465 |
|
|
tst r6, #SP_TDRE
|
4466 |
|
|
beq _local3
|
4467 |
|
|
add r3, r3, #1
|
4468 |
|
|
cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */
|
4469 |
|
|
blo _local4
|
4470 |
|
|
_local2:
|
4471 |
|
|
mov r3, #SPI_8CLOCKS
|
4472 |
|
|
str r3, [r4, #SP_TDR]
|
4473 |
|
|
ldr r0, [r4, #SP_RDR]
|
4474 |
|
|
_local5:
|
4475 |
|
|
ldr r0, [r4, #SP_SR]
|
4476 |
|
|
tst r0, #SP_RDRF
|
4477 |
|
|
beq _local5
|
4478 |
|
|
ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */
|
4479 |
|
|
mov r0, #0
|
4480 |
|
|
cmp r2, #0 /* r2 is # of bytes to copy in */
|
4481 |
|
|
bls _local6
|
4482 |
|
|
_local7:
|
4483 |
|
|
ldr r5, [r4, #SP_SR]
|
4484 |
|
|
tst r5, #SP_TDRE
|
4485 |
|
|
beq _local7
|
4486 |
|
|
str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */
|
4487 |
|
|
_local8:
|
4488 |
|
|
ldr r5, [r4, #SP_SR]
|
4489 |
|
|
tst r5, #SP_RDRF
|
4490 |
|
|
beq _local8
|
4491 |
|
|
ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */
|
4492 |
|
|
strb r5, [r1], #1 /* postindexed */
|
4493 |
|
|
add r0, r0, #1
|
4494 |
|
|
cmp r0, r2
|
4495 |
|
|
blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */
|
4496 |
|
|
_local6:
|
4497 |
|
|
mov r0, #200
|
4498 |
|
|
bl DELAY9
|
4499 |
|
|
ldmia sp!, {r4, r5, r6, lr}
|
4500 |
|
|
bx lr
|
4501 |
|
|
#endif
|