Newer
Older
/*** -*- linux-c -*- **********************************************************
Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
Copyright 2000-2001 ATMEL Corporation.
Copyright 2003-2004 Simon Kelley.
This code was developed from version 2.1.1 of the Atmel drivers,
released by Atmel corp. under the GPL in December 2002. It also
includes code from the Linux aironet drivers (C) Benjamin Reed,
and the Linux PCMCIA package, (C) David Hinds and the Linux wireless
extensions, (C) Jean Tourrilhes.
The firmware module for reading the MAC address of the card comes from
net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright
by him. net.russotto.AtmelMACFW is used under the GPL license version 2.
This file contains the module in binary form and, under the terms
of the GPL, in source form. The source is located at the end of the file.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Atmel wireless lan drivers; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For all queries about this code, please contact the current author,
Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
Credit is due to HP UK and Cambridge Online Systems Ltd for supplying
hardware used during development of this driver.
******************************************************************************/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/timer.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <linux/crc32.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
MODULE_AUTHOR("Simon Kelley");
MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards");
/* The name of the firmware file to be loaded
over-rides any automatic selection */
static char *firmware = NULL;
module_param(firmware, charp, 0);
/* table of firmware file names */
AtmelFWType fw_type;
const char *fw_file;
const char *fw_file_ext;
} fw_table[] = {
{ ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" },
{ ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" },
{ ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" },
{ ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" },
{ ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" },
{ ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" },
{ ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" },
{ ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" },
{ ATMEL_FW_TYPE_NONE, NULL, NULL }
MODULE_FIRMWARE("atmel_at76c502-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502.bin");
MODULE_FIRMWARE("atmel_at76c502d-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502d.bin");
MODULE_FIRMWARE("atmel_at76c502e-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502e.bin");
MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502_3com.bin");
MODULE_FIRMWARE("atmel_at76c504-wpa.bin");
MODULE_FIRMWARE("atmel_at76c504.bin");
MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin");
MODULE_FIRMWARE("atmel_at76c504_2958.bin");
MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin");
MODULE_FIRMWARE("atmel_at76c504a_2958.bin");
MODULE_FIRMWARE("atmel_at76c506-wpa.bin");
MODULE_FIRMWARE("atmel_at76c506.bin");
#define MAX_SSID_LENGTH 32
#define MGMT_JIFFIES (256 * HZ / 100)
#define GCR 0x00 /* (SIR0) General Configuration Register */
#define BSR 0x02 /* (SIR1) Bank Switching Select Register */
#define MR1 0x12 /* Mirror Register 1 */
#define MR2 0x14 /* Mirror Register 2 */
#define MR3 0x16 /* Mirror Register 3 */
#define MR4 0x18 /* Mirror Register 4 */
#define GPR1 0x0c
#define GPR2 0x0e
#define GPR3 0x10
/*
* Constants for the GCR register.
*/
#define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */
#define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */
#define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */
#define GCR_ENINT 0x0002 /* Enable Interrupts */
#define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */
#define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */
#define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */
/*
*Constants for the MR registers.
*/
#define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */
#define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */
#define MAC_INIT_OK 0x0002 /* MAC boot has been completed */
#define MIB_MAX_DATA_BYTES 212
#define MIB_HEADER_SIZE 4 /* first four fields */
struct get_set_mib {
u8 type;
u8 size;
u8 index;
u8 reserved;
u8 data[MIB_MAX_DATA_BYTES];
u32 Next;
u16 MsduPos;
u16 MsduSize;
u8 State;
u8 Status;
u8 Rate;
u8 Rssi;
u8 LinkQuality;
u8 PreambleType;
u16 Duration;
u32 RxTime;
};
#define RX_DESC_FLAG_VALID 0x80
#define RX_DESC_FLAG_CONSUMED 0x40
#define RX_DESC_FLAG_IDLE 0x00
#define RX_STATUS_SUCCESS 0x00
#define RX_DESC_MSDU_POS_OFFSET 4
#define RX_DESC_MSDU_SIZE_OFFSET 6
#define RX_DESC_FLAGS_OFFSET 8
#define RX_DESC_STATUS_OFFSET 9
#define RX_DESC_RSSI_OFFSET 11
#define RX_DESC_LINK_QUALITY_OFFSET 12
#define RX_DESC_PREAMBLE_TYPE_OFFSET 13
#define RX_DESC_DURATION_OFFSET 14
#define RX_DESC_RX_TIME_OFFSET 16
struct tx_desc {
u32 NextDescriptor;
u16 TxStartOfFrame;
u16 TxLength;
u8 TxRate;
u8 KeyIndex;
u8 ChiperType;
u8 ChipreLength;
u8 Reserved;
u8 PacketType;
u16 HostTxLength;
};
#define TX_DESC_NEXT_OFFSET 0
#define TX_DESC_POS_OFFSET 4
#define TX_DESC_SIZE_OFFSET 6
#define TX_DESC_FLAGS_OFFSET 8
#define TX_DESC_STATUS_OFFSET 9
#define TX_DESC_RETRY_OFFSET 10
#define TX_DESC_RATE_OFFSET 11
#define TX_DESC_KEY_INDEX_OFFSET 12
#define TX_DESC_CIPHER_TYPE_OFFSET 13
#define TX_DESC_CIPHER_LENGTH_OFFSET 14
#define TX_DESC_PACKET_TYPE_OFFSET 17
#define TX_DESC_HOST_LENGTH_OFFSET 18
#define TX_STATUS_SUCCESS 0x00
#define TX_FIRM_OWN 0x80
#define TX_DONE 0x40
#define TX_ERROR 0x01
#define TX_PACKET_TYPE_DATA 0x01
#define TX_PACKET_TYPE_MGMT 0x02
#define ISR_EMPTY 0x00 /* no bits set in ISR */
#define ISR_TxCOMPLETE 0x01 /* packet transmitted */
#define ISR_RxCOMPLETE 0x02 /* packet received */
#define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */
#define ISR_FATAL_ERROR 0x08 /* Fatal error */
#define ISR_COMMAND_COMPLETE 0x10 /* command completed */
#define ISR_OUT_OF_RANGE 0x20 /* command completed */
#define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#define Local_Mib_Type 0x01
#define Mac_Address_Mib_Type 0x02
#define Mac_Mib_Type 0x03
#define Statistics_Mib_Type 0x04
#define Mac_Mgmt_Mib_Type 0x05
#define Mac_Wep_Mib_Type 0x06
#define Phy_Mib_Type 0x07
#define Multi_Domain_MIB 0x08
#define MAC_MGMT_MIB_CUR_BSSID_POS 14
#define MAC_MIB_FRAG_THRESHOLD_POS 8
#define MAC_MIB_RTS_THRESHOLD_POS 10
#define MAC_MIB_SHORT_RETRY_POS 16
#define MAC_MIB_LONG_RETRY_POS 17
#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16
#define MAC_MGMT_MIB_BEACON_PER_POS 0
#define MAC_MGMT_MIB_STATION_ID_POS 6
#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11
#define MAC_MGMT_MIB_CUR_BSSID_POS 14
#define MAC_MGMT_MIB_PS_MODE_POS 53
#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54
#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56
#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57
#define PHY_MIB_CHANNEL_POS 14
#define PHY_MIB_RATE_SET_POS 20
#define PHY_MIB_REG_DOMAIN_POS 26
#define LOCAL_MIB_AUTO_TX_RATE_POS 3
#define LOCAL_MIB_SSID_SIZE 5
#define LOCAL_MIB_TX_PROMISCUOUS_POS 6
#define LOCAL_MIB_TX_MGMT_RATE_POS 7
#define LOCAL_MIB_TX_CONTROL_RATE_POS 8
#define LOCAL_MIB_PREAMBLE_TYPE 9
#define MAC_ADDR_MIB_MAC_ADDR_POS 0
#define CMD_Set_MIB_Vars 0x01
#define CMD_Get_MIB_Vars 0x02
#define CMD_Scan 0x03
#define CMD_Join 0x04
#define CMD_Start 0x05
#define CMD_EnableRadio 0x06
#define CMD_DisableRadio 0x07
#define CMD_SiteSurvey 0x0B
#define CMD_STATUS_IDLE 0x00
#define CMD_STATUS_COMPLETE 0x01
#define CMD_STATUS_UNKNOWN 0x02
#define CMD_STATUS_INVALID_PARAMETER 0x03
#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04
#define CMD_STATUS_TIME_OUT 0x07
#define CMD_STATUS_IN_PROGRESS 0x08
#define CMD_STATUS_REJECTED_RADIO_OFF 0x09
#define CMD_STATUS_HOST_ERROR 0xFF
#define CMD_STATUS_BUSY 0xFE
#define CMD_BLOCK_COMMAND_OFFSET 0
#define CMD_BLOCK_STATUS_OFFSET 1
#define CMD_BLOCK_PARAMETERS_OFFSET 4
#define SCAN_OPTIONS_SITE_SURVEY 0x80
#define MGMT_FRAME_BODY_OFFSET 24
#define MAX_AUTHENTICATION_RETRIES 3
#define AUTHENTICATION_RESPONSE_TIME_OUT 1000
#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */
#define LOOP_RETRY_LIMIT 500000
#define ACTIVE_MODE 1
#define PS_MODE 2
#define MAX_ENCRYPTION_KEYS 4
#define MAX_ENCRYPTION_KEY_SIZE 40
#define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */
#define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */
#define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */
#define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */
#define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */
#define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */
#define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */
#define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */
#define BSS_TYPE_INFRASTRUCTURE 2
#define SCAN_TYPE_ACTIVE 0
#define SCAN_TYPE_PASSIVE 1
#define LONG_PREAMBLE 0
#define SHORT_PREAMBLE 1
#define AUTO_PREAMBLE 2
#define DATA_FRAME_WS_HEADER_SIZE 30
#define PROM_MODE_OFF 0x0
#define PROM_MODE_UNKNOWN 0x1
#define PROM_MODE_CRC_FAILED 0x2
#define PROM_MODE_DUPLICATED 0x4
#define PROM_MODE_MGMT 0x8
#define PROM_MODE_CTRL 0x10
#define PROM_MODE_BAD_PROTOCOL 0x20
#define IFACE_INT_MASK_OFFSET 1
#define IFACE_LOCKOUT_HOST_OFFSET 2
#define IFACE_LOCKOUT_MAC_OFFSET 3
#define IFACE_FUNC_CTRL_OFFSET 28
#define IFACE_MAC_STAT_OFFSET 30
#define IFACE_GENERIC_INT_TYPE_OFFSET 32
#define CIPHER_SUITE_WEP_64 1
#define CIPHER_SUITE_TKIP 2
#define CIPHER_SUITE_AES 3
#define CIPHER_SUITE_CCX 4
#define CIPHER_SUITE_WEP_128 5
#define FUNC_CTRL_TxENABLE 0x10
#define FUNC_CTRL_RxENABLE 0x20
/* A stub firmware image which reads the MAC address from NVRAM on the card.
For copyright information and source see the end of this file. */
static u8 mac_reader[] = {
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5,
0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5,
0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1,
0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb,
0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb,
0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5,
0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea,
0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1,
0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1,
0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2,
0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5,
0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5,
0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5,
0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3,
0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5,
0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5,
0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5,
0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5,
0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1,
0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2,
0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb,
0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb,
0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb,
0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3,
0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5,
0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3,
0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a,
0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5,
0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3,
0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3,
0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2,
0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb,
0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02,
0x00, 0x01, 0x00, 0x02
};
struct atmel_private {
void *card; /* Bus dependent stucture varies for PCcard */
int (*present_callback)(void *); /* And callback which uses it */
char firmware_id[32];
AtmelFWType firmware_type;
u8 *firmware;
int firmware_length;
struct timer_list management_timer;
struct net_device *dev;
struct device *sys_dev;
struct iw_statistics wstats;
spinlock_t irqlock, timerlock; /* spinlocks */
} card_type;
int do_rx_crc; /* If we need to CRC incoming packets */
int probe_crc; /* set if we don't yet know */
int crc_ok_cnt, crc_ko_cnt; /* counters for probing */
u16 rx_desc_head;
u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous;
u16 tx_free_mem, tx_buff_head, tx_buff_tail;
u8 wep_is_on, default_key, exclude_unencrypted, encryption_level;
u8 group_cipher_suite, pairwise_cipher_suite;
u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
int wep_key_len[MAX_ENCRYPTION_KEYS];
int use_wpa, radio_on_broken; /* firmware dependent stuff. */
u16 host_info_base;
/* NB this is matched to the hardware, don't change. */
u8 volatile int_status;
u8 volatile int_mask;
u8 volatile lockout_host;
u8 volatile lockout_mac;
u16 tx_buff_pos;
u16 tx_buff_size;
u16 tx_desc_pos;
u16 tx_desc_count;
u16 rx_buff_pos;
u16 rx_buff_size;
u16 rx_desc_pos;
u16 rx_desc_count;
u16 func_ctrl;
u16 mac_status;
u16 generic_IRQ_type;
u8 reserved[2];
} host_info;
STATION_STATE_SCANNING,
STATION_STATE_JOINNING,
STATION_STATE_AUTHENTICATING,
STATION_STATE_ASSOCIATING,
STATION_STATE_READY,
STATION_STATE_REASSOCIATING,
STATION_STATE_DOWN,
STATION_STATE_MGMT_ERROR
} station_state;
int operating_mode, power_mode;
time_t last_qual;
int beacons_this_sec;
int channel;
int reg_domain, config_reg_domain;
int tx_rate;
int auto_tx_rate;
int rts_threshold;
int frag_threshold;
int long_retry, short_retry;
int preamble;
int default_beacon_period, beacon_period, listen_interval;
int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum;
int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt;
enum {
SITE_SURVEY_IDLE,
SITE_SURVEY_IN_PROGRESS,
unsigned long last_survey;
int station_was_associated, station_is_associated;
int fast_scan;
struct bss_info {
int channel;
int SSIDsize;
int RSSI;
int UsingWEP;
int preamble;
int beacon_period;
int BSStype;
u8 BSSID[6];
u8 SSID[MAX_SSID_LENGTH];
} BSSinfo[MAX_BSS_ENTRIES];
int BSS_list_entries, current_BSS;
int SSID_size, new_SSID_size;
u8 CurrentBSSID[6], BSSID[6];
u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH];
u64 last_beacon_timestamp;
u8 rx_buf[MAX_WIRELESS_BODY];
};
static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16};
static const struct {
int reg_domain;
int min, max;
} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" },
{ REG_DOMAIN_DOC, 1, 11, "Canada" },
{ REG_DOMAIN_ETSI, 1, 13, "Europe" },
{ REG_DOMAIN_SPAIN, 10, 11, "Spain" },
{ REG_DOMAIN_FRANCE, 10, 13, "France" },
{ REG_DOMAIN_MKK, 14, 14, "MKK" },
{ REG_DOMAIN_MKK1, 1, 14, "MKK1" },
{ REG_DOMAIN_ISRAEL, 3, 9, "Israel"} };
static void build_wpa_mib(struct atmel_private *priv);
static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void atmel_copy_to_card(struct net_device *dev, u16 dest,
const unsigned char *src, u16 len);
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest,
u16 src, u16 len);
static void atmel_set_gcr(struct net_device *dev, u16 mask);
static void atmel_clear_gcr(struct net_device *dev, u16 mask);
static int atmel_lock_mac(struct atmel_private *priv);
static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
static void atmel_command_irq(struct atmel_private *priv);
static int atmel_validate_channel(struct atmel_private *priv, int channel);
static void atmel_management_frame(struct atmel_private *priv,
u16 frame_len, u8 rssi);
static void atmel_management_timer(u_long a);
static void atmel_send_command(struct atmel_private *priv, int command,
void *cmd, int cmd_size);
static int atmel_send_command_wait(struct atmel_private *priv, int command,
void *cmd, int cmd_size);
static void atmel_transmit_management_frame(struct atmel_private *priv,
u8 *body, int body_len);
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index,
u8 data);
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
u16 data);
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
u8 *data, int data_len);
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
u8 *data, int data_len);
static void atmel_scan(struct atmel_private *priv, int specific_ssid);
static void atmel_join_bss(struct atmel_private *priv, int bss_index);
static void atmel_smooth_qual(struct atmel_private *priv);
static void atmel_writeAR(struct net_device *dev, u16 data);
static int probe_atmel_card(struct net_device *dev);
static int reset_atmel_card(struct net_device *dev);
static void atmel_enter_state(struct atmel_private *priv, int new_state);
int atmel_open (struct net_device *dev);
static inline u16 atmel_hi(struct atmel_private *priv, u16 offset)
{
return priv->host_info_base + offset;
}
static inline u16 atmel_co(struct atmel_private *priv, u16 offset)
{
return priv->host_info.command_pos + offset;
}
static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc)
{
return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset;
}
static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc)
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
{
return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset;
}
static inline u8 atmel_read8(struct net_device *dev, u16 offset)
{
return inb(dev->base_addr + offset);
}
static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data)
{
outb(data, dev->base_addr + offset);
}
static inline u16 atmel_read16(struct net_device *dev, u16 offset)
{
return inw(dev->base_addr + offset);
}
static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data)
{
outw(data, dev->base_addr + offset);
}
static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos)
{
return atmel_read8(priv->dev, DR);
}
static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data)
{
atmel_write8(priv->dev, DR, data);
}
static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos)
{
return atmel_read16(priv->dev, DR);
}
static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data)
{
atmel_write16(priv->dev, DR, data);
}
static const struct iw_handler_def atmel_handler_def;
static void tx_done_irq(struct atmel_private *priv)
{
int i;
atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE &&
i < priv->host_info.tx_desc_count;
i++) {
u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head));
u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head));
u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head));
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0);
priv->tx_free_mem += msdu_size;
priv->tx_desc_free++;
if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size))
priv->tx_buff_head = 0;
else
priv->tx_buff_head += msdu_size;
if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1))
if (type == TX_PACKET_TYPE_DATA) {
if (status == TX_STATUS_SUCCESS)
priv->dev->stats.tx_packets++;
priv->dev->stats.tx_errors++;
netif_wake_queue(priv->dev);
}
}
}
static u16 find_tx_buff(struct atmel_private *priv, u16 len)
{
u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail;
if (priv->tx_desc_free == 3 || priv->tx_free_mem < len)
if (bottom_free >= len)
return priv->host_info.tx_buff_pos + priv->tx_buff_tail;
if (priv->tx_free_mem - bottom_free >= len) {
priv->tx_buff_tail = 0;
return priv->host_info.tx_buff_pos;
}
static void tx_update_descriptor(struct atmel_private *priv, int is_bcast,
u16 len, u16 buff, u8 type)
{
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff);
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len);
if (!priv->use_wpa)
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0);
if (priv->use_wpa) {
int cipher_type, cipher_length;
if (is_bcast) {
cipher_type = priv->group_cipher_suite;
if (cipher_type == CIPHER_SUITE_WEP_64 ||
cipher_type == CIPHER_SUITE_WEP_128)
cipher_length = 8;
else if (cipher_type == CIPHER_SUITE_TKIP)
cipher_length = 12;
else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 ||
priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) {
cipher_type = priv->pairwise_cipher_suite;
cipher_length = 8;
} else {
cipher_type = CIPHER_SUITE_NONE;
cipher_length = 0;
}
} else {
cipher_type = priv->pairwise_cipher_suite;
if (cipher_type == CIPHER_SUITE_WEP_64 ||
cipher_type == CIPHER_SUITE_WEP_128)
cipher_length = 8;
else if (cipher_type == CIPHER_SUITE_TKIP)
cipher_length = 12;
else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 ||
priv->group_cipher_suite == CIPHER_SUITE_WEP_128) {
cipher_type = priv->group_cipher_suite;
cipher_length = 8;
} else {
cipher_type = CIPHER_SUITE_NONE;
cipher_length = 0;
}
}
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail),
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail),
cipher_length);
}
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN);
if (priv->tx_desc_previous != priv->tx_desc_tail)
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0);
priv->tx_desc_previous = priv->tx_desc_tail;
if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1))
priv->tx_desc_tail++;
else
priv->tx_desc_tail = 0;
priv->tx_desc_free--;
priv->tx_free_mem -= len;
}
static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
unsigned long flags;
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
if (priv->card && priv->present_callback &&
return NETDEV_TX_OK;
return NETDEV_TX_OK;
spin_lock_irqsave(&priv->irqlock, flags);
/* nb doing the above in the opposite order will deadlock */
/* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the
12 first bytes (containing DA/SA) and put them in the appropriate
fields of the Wireless Header. Thus the packet length is then the
initial + 18 (+30-12) */
spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock);
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
frame_ctl |= IEEE80211_FCTL_PROTECTED;
skb_copy_from_linear_data(skb, &header.addr1, 6);
memcpy(&header.addr2, dev->dev_addr, 6);
memcpy(&header.addr3, priv->BSSID, 6);
} else {
memcpy(&header.addr1, priv->CurrentBSSID, 6);
memcpy(&header.addr2, dev->dev_addr, 6);
skb_copy_from_linear_data(skb, &header.addr3, 6);
if (priv->use_wpa)
memcpy(&header.addr4, SNAP_RFC1024, 6);
header.frame_control = cpu_to_le16(frame_ctl);
/* Copy the wireless header into the card */
atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
/* Copy the packet sans its 802.3 header addresses which have been replaced */
atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12);
priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE;
/* low bit of first byte of destination tells us if broadcast */
tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
dev->trans_start = jiffies;
dev->stats.tx_bytes += len;
spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
static void atmel_transmit_management_frame(struct atmel_private *priv,
int len = MGMT_FRAME_BODY_OFFSET + body_len;
if (!(buff = find_tx_buff(priv, len)))
return;
atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET);
atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len);
priv->tx_buff_tail += len;
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
}
static void fast_rx_path(struct atmel_private *priv,
u16 msdu_size, u16 rx_packet_loc, u32 crc)
{
/* fast path: unfragmented packet copy directly into skbuf */
/* get the final, mac 4 header field, this tells us encapsulation */
atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6);
msdu_size -= 6;
if (priv->do_rx_crc) {
crc = crc32_le(crc, mac4, 6);
msdu_size -= 4;
}
priv->dev->stats.rx_dropped++;
return;
}
skb_reserve(skb, 2);
skbp = skb_put(skb, msdu_size + 12);
atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size);
if (priv->do_rx_crc) {
u32 netcrc;
crc = crc32_le(crc, skbp + 12, msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) {
priv->dev->stats.rx_crc_errors++;
memcpy(skbp, header->addr1, 6); /* destination address */
if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
memcpy(&skbp[6], header->addr3, 6);
else
memcpy(&skbp[6], header->addr2, 6); /* source address */
priv->dev->stats.rx_bytes += 12 + msdu_size;
priv->dev->stats.rx_packets++;
}
/* Test to see if the packet in card memory at packet_loc has a valid CRC
It doesn't matter that this is slow: it is only used to proble the first few
packets. */
static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
{
int i = msdu_size - 4;
u32 netcrc, crc = 0xffffffff;
if (msdu_size < 4)
return 0;
atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4);
atmel_writeAR(priv->dev, packet_loc);
while (i--) {
u8 octet = atmel_read8(priv->dev, DR);
crc = crc32_le(crc, &octet, 1);
}
return (crc ^ 0xffffffff) == netcrc;
}
static void frag_rx_path(struct atmel_private *priv,
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
u8 frag_no, int more_frags)
if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
memcpy(source, header->addr2, 6);
if (priv->do_rx_crc)
msdu_size -= 4;
if (frag_no == 0) { /* first fragment */
atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6);
msdu_size -= 6;
rx_packet_loc += 6;
priv->frag_seq = seq_no;
priv->frag_no = 1;
priv->frag_len = msdu_size;
memcpy(priv->frag_source, source, 6);
memcpy(&priv->rx_buf[6], source, 6);
memcpy(priv->rx_buf, header->addr1, 6);