Commit e2b22293 authored by Javier Achirica's avatar Javier Achirica Committed by Jeff Garzik

[wireless airo] Add support for mini-pci based cards

parent b0f4ffe8
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
Aironet. Major code contributions were received from Javier Achirica Aironet. Major code contributions were received from Javier Achirica
<achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>. <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>.
Code was also integrated from the Cisco Aironet driver for Linux. Code was also integrated from the Cisco Aironet driver for Linux.
Support for MPI350 cards was added by Fabrice Bellet
<fabrice@bellet.info>.
======================================================================*/ ======================================================================*/
...@@ -51,27 +53,31 @@ static struct pci_device_id card_ids[] = { ...@@ -51,27 +53,31 @@ static struct pci_device_id card_ids[] = {
{ 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, card_ids); MODULE_DEVICE_TABLE(pci, card_ids);
static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
static void airo_pci_remove(struct pci_dev *); static void airo_pci_remove(struct pci_dev *);
static int airo_pci_suspend(struct pci_dev *pdev, u32 state);
static int airo_pci_resume(struct pci_dev *pdev);
static struct pci_driver airo_driver = { static struct pci_driver airo_driver = {
.name = "airo", .name = "airo",
.id_table = card_ids, .id_table = card_ids,
.probe = airo_pci_probe, .probe = airo_pci_probe,
.remove = __devexit_p(airo_pci_remove), .remove = __devexit_p(airo_pci_remove),
.suspend = airo_pci_suspend,
.resume = airo_pci_resume,
}; };
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/* Include Wireless Extension definition and check version - Jean II */ /* Include Wireless Extension definition and check version - Jean II */
#include <linux/wireless.h> #include <linux/wireless.h>
#define WIRELESS_SPY // enable iwspy support #define WIRELESS_SPY // enable iwspy support
#if WIRELESS_EXT > 12
#include <net/iw_handler.h> // New driver API #include <net/iw_handler.h> // New driver API
#endif /* WIRELESS_EXT > 12 */
#define CISCO_EXT // enable Cisco extensions #define CISCO_EXT // enable Cisco extensions
#ifdef CISCO_EXT #ifdef CISCO_EXT
...@@ -235,10 +241,10 @@ static int proc_perm = 0644; ...@@ -235,10 +241,10 @@ static int proc_perm = 0644;
MODULE_AUTHOR("Benjamin Reed"); MODULE_AUTHOR("Benjamin Reed");
MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
cards. Direct support for ISA/PCI cards and support \ cards. Direct support for ISA/PCI/MPI cards and support \
for PCMCIA when used with airo_cs."); for PCMCIA when used with airo_cs.");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340"); MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
MODULE_PARM(io,"1-4i"); MODULE_PARM(io,"1-4i");
MODULE_PARM(irq,"1-4i"); MODULE_PARM(irq,"1-4i");
MODULE_PARM(basic_rate,"i"); MODULE_PARM(basic_rate,"i");
...@@ -380,6 +386,16 @@ static int do8bitIO = 0; ...@@ -380,6 +386,16 @@ static int do8bitIO = 0;
#define AUXOFF 0x3C #define AUXOFF 0x3C
#define AUXDATA 0x3E #define AUXDATA 0x3E
#define FID_TX 1
#define FID_RX 2
/* Offset into aux memory for descriptors */
#define AUX_OFFSET 0x800
/* Size of allocated packets */
#define PKTSIZE 1840
#define RIDSIZE 2048
/* Size of the transmit queue */
#define MAXTXQ 64
/* BAP selectors */ /* BAP selectors */
#define BAP0 0 // Used for receiving packets #define BAP0 0 // Used for receiving packets
#define BAP1 2 // Used for xmiting packets and working with RIDS #define BAP1 2 // Used for xmiting packets and working with RIDS
...@@ -405,7 +421,8 @@ static int do8bitIO = 0; ...@@ -405,7 +421,8 @@ static int do8bitIO = 0;
#define EV_TXCPY 0x400 #define EV_TXCPY 0x400
#define EV_UNKNOWN 0x800 #define EV_UNKNOWN 0x800
#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ #define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_MIC ) #define EV_AWAKEN 0x2000
#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC)
#ifdef CHECK_UNKNOWN_INTS #ifdef CHECK_UNKNOWN_INTS
#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN) #define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
...@@ -413,6 +430,9 @@ static int do8bitIO = 0; ...@@ -413,6 +430,9 @@ static int do8bitIO = 0;
#define IGNORE_INTS (~STATUS_INTS) #define IGNORE_INTS (~STATUS_INTS)
#endif #endif
/* RID TYPES */
#define RID_RW 0x20
/* The RIDs */ /* The RIDs */
#define RID_CAPABILITIES 0xFF00 #define RID_CAPABILITIES 0xFF00
#define RID_APINFO 0xFF01 #define RID_APINFO 0xFF01
...@@ -615,7 +635,7 @@ typedef struct { ...@@ -615,7 +635,7 @@ typedef struct {
/*---------- Aironet Extensions ----------*/ /*---------- Aironet Extensions ----------*/
u8 magicAction; u8 magicAction;
#define MAGIC_ACTION_STSCHG 1 #define MAGIC_ACTION_STSCHG 1
#define MACIC_ACTION_RESUME 2 #define MAGIC_ACTION_RESUME 2
#define MAGIC_IGNORE_MCAST (1<<8) #define MAGIC_IGNORE_MCAST (1<<8)
#define MAGIC_IGNORE_BCAST (1<<9) #define MAGIC_IGNORE_BCAST (1<<9)
#define MAGIC_SWITCH_TO_PSP (0<<10) #define MAGIC_SWITCH_TO_PSP (0<<10)
...@@ -869,6 +889,7 @@ typedef struct { ...@@ -869,6 +889,7 @@ typedef struct {
#define AIRORESTART AIROFLPUTBUF + 1 #define AIRORESTART AIROFLPUTBUF + 1
#define FLASHSIZE 32768 #define FLASHSIZE 32768
#define AUXMEMSIZE (256 * 1024)
typedef struct aironet_ioctl { typedef struct aironet_ioctl {
unsigned short command; // What to do unsigned short command; // What to do
...@@ -916,6 +937,110 @@ typedef struct { ...@@ -916,6 +937,110 @@ typedef struct {
miccntx uCtx; // Unicast context miccntx uCtx; // Unicast context
} mic_module; } mic_module;
typedef struct {
unsigned int rid: 16;
unsigned int len: 15;
unsigned int valid: 1;
dma_addr_t host_addr;
} Rid;
typedef struct {
unsigned int offset: 15;
unsigned int eoc: 1;
unsigned int len: 15;
unsigned int valid: 1;
dma_addr_t host_addr;
} TxFid;
typedef struct {
unsigned int ctl: 15;
unsigned int rdy: 1;
unsigned int len: 15;
unsigned int valid: 1;
dma_addr_t host_addr;
} RxFid;
/*
* Host receive descriptor
*/
typedef struct {
unsigned char *card_ram_off; /* offset into card memory of the
desc */
RxFid rx_desc; /* card receive descriptor */
char *virtual_host_addr; /* virtual address of host receive
buffer */
int pending;
} HostRxDesc;
/*
* Host transmit descriptor
*/
typedef struct {
unsigned char *card_ram_off; /* offset into card memory of the
desc */
TxFid tx_desc; /* card transmit descriptor */
char *virtual_host_addr; /* virtual address of host receive
buffer */
int pending;
} HostTxDesc;
/*
* Host RID descriptor
*/
typedef struct {
unsigned char *card_ram_off; /* offset into card memory of the
descriptor */
Rid rid_desc; /* card RID descriptor */
char *virtual_host_addr; /* virtual address of host receive
buffer */
} HostRidDesc;
typedef struct {
u16 sw0;
u16 sw1;
u16 status;
u16 len;
#define HOST_SET (1 << 0)
#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */
#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */
#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */
#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */
#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */
#define HOST_CLR_AID (1 << 7) /* clear AID failure */
#define HOST_RTS (1 << 9) /* Force RTS use */
#define HOST_SHORT (1 << 10) /* Do short preamble */
u16 ctl;
u16 aid;
u16 retries;
u16 fill;
} TxCtlHdr;
typedef struct {
u16 ctl;
u16 duration;
char addr1[6];
char addr2[6];
char addr3[6];
u16 seq;
char addr4[6];
} WifiHdr;
typedef struct {
TxCtlHdr ctlhdr;
u16 fill1;
u16 fill2;
WifiHdr wifihdr;
u16 gaplen;
u16 status;
} WifiCtlHdr;
WifiCtlHdr wifictlhdr8023 = {
ctlhdr: {
ctl: HOST_DONT_RLSE,
}
};
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
// Frequency list (map channels to frequencies) // Frequency list (map channels to frequencies)
static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
...@@ -935,14 +1060,8 @@ typedef struct wep_key_t { ...@@ -935,14 +1060,8 @@ typedef struct wep_key_t {
#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN) #define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
#endif /* IW_ENCODE_NOKEY */ #endif /* IW_ENCODE_NOKEY */
#if WIRELESS_EXT > 12
/* List of Wireless Handlers (new API) */ /* List of Wireless Handlers (new API) */
static const struct iw_handler_def airo_handler_def; static const struct iw_handler_def airo_handler_def;
#else /* WIRELESS_EXT > 12 */
/* More Wireless Extensions backward compatibility */
/* Part of iw_handler prototype we need (apart that we don't need it) */
struct iw_request_info {};
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
...@@ -975,6 +1094,11 @@ static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); ...@@ -975,6 +1094,11 @@ static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket); static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket); static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
static int mpi_send_packet (struct net_device *dev);
static void mpi_unmap_card(struct pci_dev *pci);
static void mpi_receive_802_3(struct airo_info *ai);
static int waitbusy (struct airo_info *ai);
static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
*regs); *regs);
static int airo_thread(void *data); static int airo_thread(void *data);
...@@ -1000,26 +1124,23 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, ...@@ -1000,26 +1124,23 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket,
struct airo_info { struct airo_info {
struct net_device_stats stats; struct net_device_stats stats;
int open;
struct net_device *dev; struct net_device *dev;
/* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
use the high bit to mark whether it is in use. */ use the high bit to mark whether it is in use. */
#define MAX_FIDS 6 #define MAX_FIDS 6
#define MPI_MAX_FIDS 1
int fids[MAX_FIDS]; int fids[MAX_FIDS];
int registered;
ConfigRid config; ConfigRid config;
int need_commit; // Need to set config
char keyindex; // Used with auto wep char keyindex; // Used with auto wep
char defindex; // Used with auto wep char defindex; // Used with auto wep
struct proc_dir_entry *proc_entry; struct proc_dir_entry *proc_entry;
struct airo_info *next;
spinlock_t aux_lock; spinlock_t aux_lock;
unsigned long flags; unsigned long flags;
#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */ #define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
#define FLAG_RADIO_OFF 0 /* User disabling of MAC */ #define FLAG_RADIO_OFF 0 /* User disabling of MAC */
#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ #define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
#define FLAG_RADIO_MASK 0x03 #define FLAG_RADIO_MASK 0x03
#define FLAG_FLASHING 2 #define FLAG_ENABLED 2
#define FLAG_ADHOC 3 /* Needed by MIC */ #define FLAG_ADHOC 3 /* Needed by MIC */
#define FLAG_MIC_CAPABLE 4 #define FLAG_MIC_CAPABLE 4
#define FLAG_UPDATE_MULTI 5 #define FLAG_UPDATE_MULTI 5
...@@ -1027,6 +1148,11 @@ struct airo_info { ...@@ -1027,6 +1148,11 @@ struct airo_info {
#define FLAG_802_11 7 #define FLAG_802_11 7
#define FLAG_PENDING_XMIT 9 #define FLAG_PENDING_XMIT 9
#define FLAG_PENDING_XMIT11 10 #define FLAG_PENDING_XMIT11 10
#define FLAG_MPI 11
#define FLAG_REGISTERED 12
#define FLAG_COMMIT 13
#define FLAG_RESET 14
#define FLAG_FLASHING 15
#define JOB_MASK 0x1ff0000 #define JOB_MASK 0x1ff0000
#define JOB_DIE 16 #define JOB_DIE 16
#define JOB_XMIT 17 #define JOB_XMIT 17
...@@ -1055,15 +1181,7 @@ struct airo_info { ...@@ -1055,15 +1181,7 @@ struct airo_info {
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
struct iw_statistics wstats; // wireless stats struct iw_statistics wstats; // wireless stats
unsigned long scan_timestamp; /* Time started to scan */ unsigned long scan_timestamp; /* Time started to scan */
#if WIRELESS_EXT > 15
struct iw_spy_data spy_data; struct iw_spy_data spy_data;
#else /* WIRELESS_EXT > 15 */
#ifdef WIRELESS_SPY
int spy_number;
u_char spy_address[IW_MAX_SPY][ETH_ALEN];
struct iw_quality spy_stat[IW_MAX_SPY];
#endif /* WIRELESS_SPY */
#endif /* WIRELESS_EXT > 15 */
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
#ifdef MICSUPPORT #ifdef MICSUPPORT
/* MIC stuff */ /* MIC stuff */
...@@ -1071,6 +1189,20 @@ struct airo_info { ...@@ -1071,6 +1189,20 @@ struct airo_info {
mic_module mod[2]; mic_module mod[2];
mic_statistics micstats; mic_statistics micstats;
#endif #endif
HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
HostTxDesc txfids[MPI_MAX_FIDS];
HostRidDesc config_desc;
unsigned long ridbus; // phys addr of config_desc
struct sk_buff_head txq;// tx queue used by mpi350 code
struct pci_dev *pci;
unsigned char *pcimem;
unsigned char *pciaux;
unsigned char *shared;
dma_addr_t shared_dma;
int power;
SsidRid *SSID;
APListRid *APList;
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
}; };
static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
...@@ -1550,6 +1682,7 @@ static int readBSSListRid(struct airo_info *ai, int first, ...@@ -1550,6 +1682,7 @@ static int readBSSListRid(struct airo_info *ai, int first,
Resp rsp; Resp rsp;
if (first == 1) { if (first == 1) {
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS; cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem)) if (down_interruptible(&ai->sem))
...@@ -1647,8 +1780,11 @@ static int readConfigRid(struct airo_info*ai, int lock) { ...@@ -1647,8 +1780,11 @@ static int readConfigRid(struct airo_info*ai, int lock) {
for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++) for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
*s = le16_to_cpu(*s); *s = le16_to_cpu(*s);
for(s = &cfg.arlThreshold; s <= &cfg.autoWake; s++) for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
*s = le16_to_cpu(*s); *s = cpu_to_le16(*s);
for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
*s = cpu_to_le16(*s);
ai->config = cfg; ai->config = cfg;
return SUCCESS; return SUCCESS;
...@@ -1668,10 +1804,10 @@ static int writeConfigRid(struct airo_info*ai, int lock) { ...@@ -1668,10 +1804,10 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
u16 *s; u16 *s;
ConfigRid cfgr; ConfigRid cfgr;
if (!ai->need_commit) if (!test_bit (FLAG_COMMIT, &ai->flags))
return SUCCESS; return SUCCESS;
ai->need_commit = 0; clear_bit (FLAG_COMMIT | FLAG_RESET, &ai->flags);
checkThrottle(ai); checkThrottle(ai);
cfgr = ai->config; cfgr = ai->config;
...@@ -1688,7 +1824,10 @@ static int writeConfigRid(struct airo_info*ai, int lock) { ...@@ -1688,7 +1824,10 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++) for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
*s = cpu_to_le16(*s); *s = cpu_to_le16(*s);
for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++) for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++)
*s = cpu_to_le16(*s);
for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
*s = cpu_to_le16(*s); *s = cpu_to_le16(*s);
return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
...@@ -1749,7 +1888,7 @@ static int airo_open(struct net_device *dev) { ...@@ -1749,7 +1888,7 @@ static int airo_open(struct net_device *dev) {
* Wireless Extensions may postpone config changes until the card * Wireless Extensions may postpone config changes until the card
* is open (to pipeline changes and speed-up card setup). If * is open (to pipeline changes and speed-up card setup). If
* those changes are not yet commited, do it now - Jean II */ * those changes are not yet commited, do it now - Jean II */
if(info->need_commit) { if (test_bit (FLAG_COMMIT, &info->flags)) {
disable_MAC(info, 1); disable_MAC(info, 1);
writeConfigRid(info, 1); writeConfigRid(info, 1);
} }
...@@ -1765,12 +1904,140 @@ static int airo_open(struct net_device *dev) { ...@@ -1765,12 +1904,140 @@ static int airo_open(struct net_device *dev) {
return 0; return 0;
} }
static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
int npacks, pending;
unsigned long flags;
struct airo_info *ai = dev->priv;
if (!skb) {
printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__);
return 0;
}
npacks = skb_queue_len (&ai->txq);
if (npacks >= MAXTXQ - 1) {
netif_stop_queue (dev);
if (npacks > MAXTXQ) {
ai->stats.tx_fifo_errors++;
return 1;
}
skb_queue_tail (&ai->txq, skb);
return 0;
}
spin_lock_irqsave(&ai->aux_lock, flags);
skb_queue_tail (&ai->txq, skb);
pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
spin_unlock_irqrestore(&ai->aux_lock,flags);
netif_wake_queue (dev);
if (pending == 0) {
set_bit(FLAG_PENDING_XMIT, &ai->flags);
mpi_send_packet (dev);
}
return 0;
}
/*
* @mpi_send_packet
*
* Attempt to transmit a packet. Can be called from interrupt
* or transmit . return number of packets we tried to send
*/
static int mpi_send_packet (struct net_device *dev)
{
struct sk_buff *skb;
unsigned char *buffer;
s16 len, *payloadLen;
struct airo_info *ai = dev->priv;
u8 *sendbuf;
/* get a packet to send */
if ((skb = skb_dequeue(&ai->txq)) == 0) {
printk (KERN_ERR
"airo_mpi: %s: Dequeue'd zero in send_packet()\n",
__FUNCTION__);
return 0;
}
/* check min length*/
len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
buffer = skb->data;
ai->txfids[0].tx_desc.offset = 0;
ai->txfids[0].tx_desc.valid = 1;
ai->txfids[0].tx_desc.eoc = 1;
ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
memcpy((char *)ai->txfids[0].card_ram_off,
(char *)&ai->txfids[0].tx_desc, sizeof(TxFid));
/*
* Magic, the cards firmware needs a length count (2 bytes) in the host buffer
* right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
* is immediatly after it. ------------------------------------------------
* |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
* ------------------------------------------------
*/
memcpy((char *)ai->txfids[0].virtual_host_addr,
(char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr +
sizeof(wifictlhdr8023));
sendbuf = ai->txfids[0].virtual_host_addr +
sizeof(wifictlhdr8023) + 2 ;
/*
* Firmware automaticly puts 802 header on so
* we don't need to account for it in the length
*/
#ifdef MICSUPPORT
if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
(ntohs(((u16 *)buffer)[6]) != 0x888E)) {
MICBuffer pMic;
if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
return ERROR;
*payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
/* copy data into airo dma buffer */
memcpy (sendbuf, buffer, sizeof(etherHead));
buffer += sizeof(etherHead);
sendbuf += sizeof(etherHead);
memcpy (sendbuf, &pMic, sizeof(pMic));
sendbuf += sizeof(pMic);
memcpy (sendbuf, buffer, len - sizeof(etherHead));
} else
#endif
{
*payloadLen = cpu_to_le16(len - sizeof(etherHead));
dev->trans_start = jiffies;
/* copy data into airo dma buffer */
memcpy(sendbuf, buffer, len);
}
OUT4500(ai, EVACK, 8);
dev_kfree_skb_any(skb);
return 1;
}
static void get_tx_error(struct airo_info *ai, u32 fid) static void get_tx_error(struct airo_info *ai, u32 fid)
{ {
u16 status; u16 status;
if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) == SUCCESS) { if (fid < 0)
status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
else {
if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
return;
bap_read(ai, &status, 2, BAP0); bap_read(ai, &status, 2, BAP0);
}
if (le16_to_cpu(status) & 2) /* Too many retries */ if (le16_to_cpu(status) & 2) /* Too many retries */
ai->stats.tx_aborted_errors++; ai->stats.tx_aborted_errors++;
if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
...@@ -1781,7 +2048,6 @@ static void get_tx_error(struct airo_info *ai, u32 fid) ...@@ -1781,7 +2048,6 @@ static void get_tx_error(struct airo_info *ai, u32 fid)
ai->stats.tx_carrier_errors++; ai->stats.tx_carrier_errors++;
if (le16_to_cpu(status) & 0x20) /* Association lost */ if (le16_to_cpu(status) & 0x20) /* Association lost */
{ } { }
#if WIRELESS_EXT > 13
/* We produce a TXDROP event only for retry or lifetime /* We produce a TXDROP event only for retry or lifetime
* exceeded, because that's the only status that really mean * exceeded, because that's the only status that really mean
* that this particular node went away. * that this particular node went away.
...@@ -1810,8 +2076,6 @@ static void get_tx_error(struct airo_info *ai, u32 fid) ...@@ -1810,8 +2076,6 @@ static void get_tx_error(struct airo_info *ai, u32 fid)
/* Send event to user space */ /* Send event to user space */
wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
} }
#endif /* WIRELESS_EXT > 13 */
}
} }
static void airo_end_xmit(struct net_device *dev) { static void airo_end_xmit(struct net_device *dev) {
...@@ -2019,7 +2283,7 @@ static int airo_set_mac_address(struct net_device *dev, void *p) ...@@ -2019,7 +2283,7 @@ static int airo_set_mac_address(struct net_device *dev, void *p)
readConfigRid(ai, 1); readConfigRid(ai, 1);
memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
disable_MAC(ai, 1); disable_MAC(ai, 1);
writeConfigRid (ai, 1); writeConfigRid (ai, 1);
enable_MAC(ai, &rsp, 1); enable_MAC(ai, &rsp, 1);
...@@ -2066,25 +2330,49 @@ void stop_airo_card( struct net_device *dev, int freeres ) ...@@ -2066,25 +2330,49 @@ void stop_airo_card( struct net_device *dev, int freeres )
disable_interrupts(ai); disable_interrupts(ai);
free_irq( dev->irq, dev ); free_irq( dev->irq, dev );
takedown_proc_entry( dev, ai ); takedown_proc_entry( dev, ai );
if (ai->registered) { if (test_bit(FLAG_REGISTERED, &ai->flags)) {
unregister_netdev( dev ); unregister_netdev( dev );
if (ai->wifidev) { if (ai->wifidev) {
unregister_netdev(ai->wifidev); unregister_netdev(ai->wifidev);
free_netdev(ai->wifidev); free_netdev(ai->wifidev);
ai->wifidev = 0; ai->wifidev = 0;
} }
ai->registered = 0; clear_bit(FLAG_REGISTERED, &ai->flags);
} }
set_bit(JOB_DIE, &ai->flags); set_bit(JOB_DIE, &ai->flags);
kill_proc(ai->thr_pid, SIGTERM, 1); kill_proc(ai->thr_pid, SIGTERM, 1);
wait_for_completion(&ai->thr_exited); wait_for_completion(&ai->thr_exited);
/*
* Clean out tx queue
*/
if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) {
struct sk_buff *skb = 0;
for (;(skb = skb_dequeue(&ai->txq));)
dev_kfree_skb(skb);
}
if (ai->flash) if (ai->flash)
kfree(ai->flash); kfree(ai->flash);
if (ai->rssi) if (ai->rssi)
kfree(ai->rssi); kfree(ai->rssi);
if (ai->APList)
kfree(ai->APList);
if (ai->SSID)
kfree(ai->SSID);
if (freeres) { if (freeres) {
/* PCMCIA frees this stuff, so only for PCI and ISA */ /* PCMCIA frees this stuff, so only for PCI and ISA */
release_region( dev->base_addr, 64 ); release_region( dev->base_addr, 64 );
if (test_bit(FLAG_MPI, &ai->flags)) {
if (ai->pci)
mpi_unmap_card(ai->pci);
if (ai->pcimem)
iounmap(ai->pcimem);
if (ai->pciaux)
iounmap(ai->pciaux);
pci_free_consistent(ai->pci, PCI_SHARED_LEN,
ai->shared, ai->shared_dma);
}
} }
#ifdef MICSUPPORT #ifdef MICSUPPORT
if (ai->tfm) if (ai->tfm)
...@@ -2104,6 +2392,213 @@ int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) ...@@ -2104,6 +2392,213 @@ int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
return ETH_ALEN; return ETH_ALEN;
} }
static void mpi_unmap_card(struct pci_dev *pci)
{
unsigned long mem_start = pci_resource_start(pci, 1);
unsigned long mem_len = pci_resource_len(pci, 1);
unsigned long aux_start = pci_resource_start(pci, 2);
unsigned long aux_len = AUXMEMSIZE;
release_mem_region(aux_start, aux_len);
release_mem_region(mem_start, mem_len);
}
/*************************************************************
* This routine assumes that descriptors have been setup .
* Run at insmod time or after reset when the decriptors
* have been initialized . Returns 0 if all is well nz
* otherwise . Does not allocate memory but sets up card
* using previously allocated descriptors.
*/
static int mpi_init_descriptors (struct airo_info *ai)
{
Cmd cmd;
Resp rsp;
int i;
int rc = SUCCESS;
/* Alloc card RX descriptors */
netif_stop_queue(ai->dev);
memset(&rsp,0,sizeof(rsp));
memset(&cmd,0,sizeof(cmd));
cmd.cmd = CMD_ALLOCATEAUX;
cmd.parm0 = FID_RX;
cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
cmd.parm2 = MPI_MAX_FIDS;
rc=issuecommand(ai, &cmd, &rsp);
if (rc != SUCCESS) {
printk(KERN_ERR "airo: Couldn't allocate RX FID\n");
return rc;
}
for (i=0; i<MPI_MAX_FIDS; i++) {
memcpy(ai->rxfids[i].card_ram_off,
&ai->rxfids[i].rx_desc, sizeof(RxFid));
}
/* Alloc card TX descriptors */
memset(&rsp,0,sizeof(rsp));
memset(&cmd,0,sizeof(cmd));
cmd.cmd = CMD_ALLOCATEAUX;
cmd.parm0 = FID_TX;
cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
cmd.parm2 = MPI_MAX_FIDS;
rc=issuecommand(ai, &cmd, &rsp);
if (rc != SUCCESS) {
printk(KERN_ERR "airo: Couldn't allocate TX FID\n");
return rc;
}
for (i=0; i<MPI_MAX_FIDS; i++) {
ai->txfids[i].tx_desc.valid = 1;
memcpy((char *)ai->txfids[i].card_ram_off,
&ai->txfids[i].tx_desc, sizeof(TxFid));
}
/* Alloc card Rid descriptor */
memset(&rsp,0,sizeof(rsp));
memset(&cmd,0,sizeof(cmd));
cmd.cmd = CMD_ALLOCATEAUX;
cmd.parm0 = RID_RW;
cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
cmd.parm2 = 1; /* Magic number... */
rc=issuecommand(ai, &cmd, &rsp);
if (rc != SUCCESS) {
printk(KERN_ERR "airo: Couldn't allocate RID\n");
return rc;
}
memcpy((char *)ai->config_desc.card_ram_off,
(char *)&ai->config_desc.rid_desc, sizeof(Rid));
return rc;
}
/*
* We are setting up three things here:
* 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
* 2) Map PCI memory for issueing commands.
* 3) Allocate memory (shared) to send and receive ethernet frames.
*/
static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
const char *name)
{
unsigned long mem_start, mem_len, aux_start, aux_len;
int rc = -1;
int i;
unsigned char *busaddroff,*vpackoff;
unsigned char *pciaddroff;
mem_start = pci_resource_start(pci, 1);
mem_len = pci_resource_len(pci, 1);
aux_start = pci_resource_start(pci, 2);
aux_len = AUXMEMSIZE;
if (!request_mem_region(mem_start, mem_len, name)) {
printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
(int)mem_start, (int)mem_len, name);
goto out;
}
if (!request_mem_region(aux_start, aux_len, name)) {
printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
(int)aux_start, (int)aux_len, name);
goto free_region1;
}
ai->pcimem = ioremap(mem_start, mem_len);
if (!ai->pcimem) {
printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
(int)mem_start, (int)mem_len, name);
goto free_region2;
}
ai->pciaux = ioremap(aux_start, aux_len);
if (!ai->pciaux) {
printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
(int)aux_start, (int)aux_len, name);
goto free_memmap;
}
/* Reserve PKTSIZE for each fid and 2K for the Rids */
ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
if (!ai->shared) {
printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n",
PCI_SHARED_LEN);
goto free_auxmap;
}
/*
* Setup descriptor RX, TX, CONFIG
*/
busaddroff = (unsigned char *)ai->shared_dma;
pciaddroff = ai->pciaux + AUX_OFFSET;
vpackoff = ai->shared;
/* RX descriptor setup */
for(i = 0; i < MPI_MAX_FIDS; i++) {
ai->rxfids[i].pending = 0;
ai->rxfids[i].card_ram_off = pciaddroff;
ai->rxfids[i].virtual_host_addr = vpackoff;
ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff;
ai->rxfids[i].rx_desc.valid = 1;
ai->rxfids[i].rx_desc.len = PKTSIZE;
ai->rxfids[i].rx_desc.rdy = 0;
pciaddroff += sizeof(RxFid);
busaddroff += PKTSIZE;
vpackoff += PKTSIZE;
}
/* TX descriptor setup */
for(i = 0; i < MPI_MAX_FIDS; i++) {
ai->txfids[i].card_ram_off = pciaddroff;
ai->txfids[i].virtual_host_addr = vpackoff;
ai->txfids[i].tx_desc.valid = 1;
ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff;
memcpy(ai->txfids[i].virtual_host_addr,
&wifictlhdr8023, sizeof(wifictlhdr8023));
pciaddroff += sizeof(TxFid);
busaddroff += PKTSIZE;
vpackoff += PKTSIZE;
}
ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
/* Rid descriptor setup */
ai->config_desc.card_ram_off = pciaddroff;
ai->config_desc.virtual_host_addr = vpackoff;
ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff;
ai->ridbus = (dma_addr_t)busaddroff;
ai->config_desc.rid_desc.rid = 0;
ai->config_desc.rid_desc.len = RIDSIZE;
ai->config_desc.rid_desc.valid = 1;
pciaddroff += sizeof(Rid);
busaddroff += RIDSIZE;
vpackoff += RIDSIZE;
/* Tell card about descriptors */
if (mpi_init_descriptors (ai) != SUCCESS)
goto free_shared;
return 0;
free_shared:
pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
free_auxmap:
iounmap(ai->pciaux);
free_memmap:
iounmap(ai->pcimem);
free_region2:
release_mem_region(aux_start, aux_len);
free_region1:
release_mem_region(mem_start, mem_len);
out:
return rc;
}
static void wifi_setup(struct net_device *dev, struct net_device *ethdev) static void wifi_setup(struct net_device *dev, struct net_device *ethdev)
{ {
struct airo_info *ai = ethdev->priv; struct airo_info *ai = ethdev->priv;
...@@ -2120,9 +2615,7 @@ static void wifi_setup(struct net_device *dev, struct net_device *ethdev) ...@@ -2120,9 +2615,7 @@ static void wifi_setup(struct net_device *dev, struct net_device *ethdev)
dev->do_ioctl = &airo_ioctl; dev->do_ioctl = &airo_ioctl;
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
dev->get_wireless_stats = airo_get_wireless_stats; dev->get_wireless_stats = airo_get_wireless_stats;
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def; dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu; dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open; dev->open = &airo_open;
...@@ -2161,7 +2654,24 @@ static struct net_device *init_wifidev(struct airo_info *ai, ...@@ -2161,7 +2654,24 @@ static struct net_device *init_wifidev(struct airo_info *ai,
return dev; return dev;
} }
struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) int reset_mpi_card( struct net_device *dev ) {
struct airo_info *ai = dev->priv;
if (down_interruptible(&ai->sem))
return -1;
waitbusy (ai);
OUT4500(ai,COMMAND,CMD_SOFTRESET);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/5);
waitbusy (ai);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/5);
up(&ai->sem);
return 0;
}
struct net_device *_init_airo_card( unsigned short irq, int port,
int is_pcmcia, struct pci_dev *pci )
{ {
struct net_device *dev; struct net_device *dev;
struct airo_info *ai; struct airo_info *ai;
...@@ -2180,12 +2690,16 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2180,12 +2690,16 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
ai = dev->priv; ai = dev->priv;
ai->wifidev = 0; ai->wifidev = 0;
ai->registered = 0; ai->flags = 0;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
printk(KERN_DEBUG "airo: Found an MPI350 card\n");
set_bit(FLAG_MPI, &ai->flags);
}
ai->dev = dev; ai->dev = dev;
ai->aux_lock = SPIN_LOCK_UNLOCKED; ai->aux_lock = SPIN_LOCK_UNLOCKED;
sema_init(&ai->sem, 1); sema_init(&ai->sem, 1);
ai->need_commit = 0;
ai->config.len = 0; ai->config.len = 0;
ai->pci = pci;
init_waitqueue_head (&ai->thr_wait); init_waitqueue_head (&ai->thr_wait);
init_completion (&ai->thr_exited); init_completion (&ai->thr_exited);
ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES); ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
...@@ -2199,6 +2713,10 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2199,6 +2713,10 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
goto err_out_thr; goto err_out_thr;
/* The Airo-specific entries in the device structure. */ /* The Airo-specific entries in the device structure. */
if (test_bit(FLAG_MPI,&ai->flags)) {
skb_queue_head_init (&ai->txq);
dev->hard_start_xmit = &mpi_start_xmit;
} else
dev->hard_start_xmit = &airo_start_xmit; dev->hard_start_xmit = &airo_start_xmit;
dev->get_stats = &airo_get_stats; dev->get_stats = &airo_get_stats;
dev->set_multicast_list = &airo_set_multicast_list; dev->set_multicast_list = &airo_set_multicast_list;
...@@ -2206,9 +2724,7 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2206,9 +2724,7 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
dev->do_ioctl = &airo_ioctl; dev->do_ioctl = &airo_ioctl;
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
dev->get_wireless_stats = airo_get_wireless_stats; dev->get_wireless_stats = airo_get_wireless_stats;
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def; dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu; dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open; dev->open = &airo_open;
...@@ -2216,6 +2732,9 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2216,6 +2732,9 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
dev->irq = irq; dev->irq = irq;
dev->base_addr = port; dev->base_addr = port;
if (test_bit(FLAG_MPI,&ai->flags))
reset_mpi_card (dev);
rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
if (rc) { if (rc) {
printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc ); printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
...@@ -2224,34 +2743,45 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2224,34 +2743,45 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
if (!is_pcmcia) { if (!is_pcmcia) {
if (!request_region( dev->base_addr, 64, dev->name )) { if (!request_region( dev->base_addr, 64, dev->name )) {
rc = -EBUSY; rc = -EBUSY;
printk(KERN_ERR "airo: Couldn't request region\n");
goto err_out_irq; goto err_out_irq;
} }
} }
if (test_bit(FLAG_MPI,&ai->flags)) {
if (mpi_map_card(ai, pci, dev->name)) {
printk(KERN_ERR "airo: Could not map memory\n");
goto err_out_res;
}
}
if (probe) { if (probe) {
if ( setup_card( ai, dev->dev_addr ) != SUCCESS ) { if ( setup_card( ai, dev->dev_addr ) != SUCCESS ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" ); printk( KERN_ERR "airo: MAC could not be enabled\n" );
rc = -EIO; rc = -EIO;
goto err_out_res; goto err_out_map;
} }
} else { } else if (!test_bit(FLAG_MPI,&ai->flags)) {
ai->bap_read = fast_bap_read; ai->bap_read = fast_bap_read;
set_bit(FLAG_FLASHING, &ai->flags); set_bit(FLAG_FLASHING, &ai->flags);
} }
rc = register_netdev(dev); rc = register_netdev(dev);
if (rc) if (rc) {
goto err_out_res; printk(KERN_ERR "airo: Couldn't register_netdev\n");
goto err_out_map;
}
if (!test_bit(FLAG_MPI,&ai->flags))
ai->wifidev = init_wifidev(ai, dev); ai->wifidev = init_wifidev(ai, dev);
ai->registered = 1; set_bit(FLAG_REGISTERED,&ai->flags);
printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
dev->name, dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
/* Allocate the transmit buffers */ /* Allocate the transmit buffers */
if (probe) if (probe && !test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ ) for( i = 0; i < MAX_FIDS; i++ )
ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2); ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
...@@ -2260,6 +2790,13 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2260,6 +2790,13 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
return dev; return dev;
err_out_map:
if (test_bit(FLAG_MPI,&ai->flags) && pci) {
pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
iounmap(ai->pciaux);
iounmap(ai->pcimem);
mpi_unmap_card(ai->pci);
}
err_out_res: err_out_res:
if (!is_pcmcia) if (!is_pcmcia)
release_region( dev->base_addr, 64 ); release_region( dev->base_addr, 64 );
...@@ -2276,59 +2813,50 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -2276,59 +2813,50 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
return NULL; return NULL;
} }
struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
{
return _init_airo_card ( irq, port, is_pcmcia, 0);
}
EXPORT_SYMBOL(init_airo_card); EXPORT_SYMBOL(init_airo_card);
static int waitbusy (struct airo_info *ai) { static int waitbusy (struct airo_info *ai) {
int delay = 0; int delay = 0;
while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) { while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
udelay (10); udelay (10);
if (++delay % 20) if ((++delay % 20) == 0)
OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
} }
return delay < 10000; return delay < 10000;
} }
int reset_airo_card( struct net_device *dev ) { int reset_airo_card( struct net_device *dev )
{
int i; int i;
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
if (reset_mpi_card (dev))
if (down_interruptible(&ai->sem))
return -1; return -1;
waitbusy (ai);
OUT4500(ai,COMMAND,CMD_SOFTRESET);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/5);
waitbusy (ai);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/5);
if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) { if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" ); printk( KERN_ERR "airo: MAC could not be enabled\n" );
up(&ai->sem);
return -1; return -1;
} else {
printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
dev->name,
dev->dev_addr[0],
dev->dev_addr[1],
dev->dev_addr[2],
dev->dev_addr[3],
dev->dev_addr[4],
dev->dev_addr[5]
);
/* Allocate the transmit buffers */
for( i = 0; i < MAX_FIDS; i++ )
ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
} }
printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* Allocate the transmit buffers if needed */
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2);
enable_interrupts( ai ); enable_interrupts( ai );
netif_wake_queue(dev); netif_wake_queue(dev);
up(&ai->sem);
return 0; return 0;
} }
EXPORT_SYMBOL(reset_airo_card); EXPORT_SYMBOL(reset_airo_card);
#if WIRELESS_EXT > 13
static void airo_send_event(struct net_device *dev) { static void airo_send_event(struct net_device *dev) {
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
union iwreq_data wrqu; union iwreq_data wrqu;
...@@ -2345,7 +2873,6 @@ static void airo_send_event(struct net_device *dev) { ...@@ -2345,7 +2873,6 @@ static void airo_send_event(struct net_device *dev) {
/* Send event to user space */ /* Send event to user space */
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
} }
#endif
static int airo_thread(void *data) { static int airo_thread(void *data) {
struct net_device *dev = data; struct net_device *dev = data;
...@@ -2405,7 +2932,7 @@ static int airo_thread(void *data) { ...@@ -2405,7 +2932,7 @@ static int airo_thread(void *data) {
break; break;
} }
if (test_bit(FLAG_FLASHING, &ai->flags)) { if (ai->power || test_bit(FLAG_FLASHING, &ai->flags)) {
up(&ai->sem); up(&ai->sem);
continue; continue;
} }
...@@ -2424,10 +2951,8 @@ static int airo_thread(void *data) { ...@@ -2424,10 +2951,8 @@ static int airo_thread(void *data) {
else if (test_bit(JOB_MIC, &ai->flags)) else if (test_bit(JOB_MIC, &ai->flags))
micinit(ai); micinit(ai);
#endif #endif
#if WIRELESS_EXT > 13
else if (test_bit(JOB_EVENT, &ai->flags)) else if (test_bit(JOB_EVENT, &ai->flags))
airo_send_event(dev); airo_send_event(dev);
#endif
else if (test_bit(JOB_AUTOWEP, &ai->flags)) else if (test_bit(JOB_AUTOWEP, &ai->flags))
timer_func(dev); timer_func(dev);
} }
...@@ -2471,9 +2996,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2471,9 +2996,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
#endif #endif
} }
if ( status & EV_LINK ) { if ( status & EV_LINK ) {
#if WIRELESS_EXT > 13
union iwreq_data wrqu; union iwreq_data wrqu;
#endif /* WIRELESS_EXT > 13 */
/* The link status has changed, if you want to put a /* The link status has changed, if you want to put a
monitor hook in, do it here. (Remember that monitor hook in, do it here. (Remember that
interrupts are still disabled!) interrupts are still disabled!)
...@@ -2523,7 +3046,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2523,7 +3046,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
set_bit(FLAG_UPDATE_UNI, &apriv->flags); set_bit(FLAG_UPDATE_UNI, &apriv->flags);
set_bit(FLAG_UPDATE_MULTI, &apriv->flags); set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
} }
#if WIRELESS_EXT > 13
/* Question : is ASSOCIATED the only status /* Question : is ASSOCIATED the only status
* that is valid ? We want to catch handover * that is valid ? We want to catch handover
* and reassociations as valid status * and reassociations as valid status
...@@ -2554,7 +3076,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2554,7 +3076,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
/* Send event to user space */ /* Send event to user space */
wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
} }
#endif /* WIRELESS_EXT > 13 */
} }
/* Check to see if there is something to receive */ /* Check to see if there is something to receive */
...@@ -2574,6 +3095,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2574,6 +3095,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
u16 tmpbuf[4]; u16 tmpbuf[4];
u16 *buffer; u16 *buffer;
if (test_bit(FLAG_MPI,&apriv->flags)) {
mpi_receive_802_3(apriv);
OUT4500(apriv, EVACK, EV_RX);
goto exitrx;
}
fid = IN4500( apriv, RXFID ); fid = IN4500( apriv, RXFID );
/* Get the packet length */ /* Get the packet length */
...@@ -2672,7 +3199,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2672,7 +3199,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
goto exitrx; goto exitrx;
} }
} }
#if WIRELESS_EXT > 15
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
if (apriv->spy_data.spy_number > 0) { if (apriv->spy_data.spy_number > 0) {
char *sa; char *sa;
...@@ -2694,33 +3220,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2694,33 +3220,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
wireless_spy_update(dev, sa, &wstats); wireless_spy_update(dev, sa, &wstats);
} }
#endif /* IW_WIRELESS_SPY */ #endif /* IW_WIRELESS_SPY */
#else /* WIRELESS_EXT > 15 */
#ifdef WIRELESS_SPY
if (apriv->spy_number > 0) {
int i;
char *sa;
sa = (char*)buffer + (test_bit(FLAG_802_11, &apriv->flags) ? 10 : 6);
for (i=0; i<apriv->spy_number; i++)
if (!memcmp(sa,apriv->spy_address[i],ETH_ALEN))
{
if (!test_bit(FLAG_802_11, &apriv->flags)) {
bap_setup (apriv, fid, 8, BAP0);
bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
}
apriv->spy_stat[i].qual = hdr.rssi[0];
if (apriv->rssi)
apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
else
apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
apriv->spy_stat[i].noise = 0;
apriv->spy_stat[i].updated = 3;
break;
}
}
#endif /* WIRELESS_SPY */
#endif /* WIRELESS_EXT > 15 */
OUT4500( apriv, EVACK, EV_RX); OUT4500( apriv, EVACK, EV_RX);
if (test_bit(FLAG_802_11, &apriv->flags)) { if (test_bit(FLAG_802_11, &apriv->flags)) {
...@@ -2740,11 +3239,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2740,11 +3239,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
exitrx: exitrx:
/* Check to see if a packet has been transmitted */ /* Check to see if a packet has been transmitted */
if ( status & ( EV_TX|EV_TXEXC ) ) { if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
int i; int i;
int len = 0; int len = 0;
int index = -1; int index = -1;
if (test_bit(FLAG_MPI,&apriv->flags)) {
unsigned long flags;
if (status & EV_TXEXC)
get_tx_error(apriv, -1);
spin_lock_irqsave(&apriv->aux_lock, flags);
if (skb_queue_len (&apriv->txq)) {
spin_unlock_irqrestore(&apriv->aux_lock,flags);
mpi_send_packet (dev);
} else {
clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
spin_unlock_irqrestore(&apriv->aux_lock,flags);
netif_wake_queue (dev);
}
OUT4500( apriv, EVACK,
status & (EV_TX|EV_TXCPY|EV_TXEXC));
goto exittx;
}
fid = IN4500(apriv, TXCOMPLFID); fid = IN4500(apriv, TXCOMPLFID);
for( i = 0; i < MAX_FIDS; i++ ) { for( i = 0; i < MAX_FIDS; i++ ) {
...@@ -2767,10 +3285,11 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2767,10 +3285,11 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
netif_wake_queue(apriv->wifidev); netif_wake_queue(apriv->wifidev);
} }
} else { } else {
OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
} }
} }
exittx:
if ( status & ~STATUS_INTS & ~IGNORE_INTS ) if ( status & ~STATUS_INTS & ~IGNORE_INTS )
printk( KERN_WARNING "airo: Got weird status %x\n", printk( KERN_WARNING "airo: Got weird status %x\n",
status & ~STATUS_INTS & ~IGNORE_INTS ); status & ~STATUS_INTS & ~IGNORE_INTS );
...@@ -2793,6 +3312,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2793,6 +3312,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
* Why would some one do 8 bit IO in an SMP machine?!? * Why would some one do 8 bit IO in an SMP machine?!?
*/ */
static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) { static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
if (test_bit(FLAG_MPI,&ai->flags))
reg <<= 1;
if ( !do8bitIO ) if ( !do8bitIO )
outw( val, ai->dev->base_addr + reg ); outw( val, ai->dev->base_addr + reg );
else { else {
...@@ -2804,6 +3325,8 @@ static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) { ...@@ -2804,6 +3325,8 @@ static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
static u16 IN4500( struct airo_info *ai, u16 reg ) { static u16 IN4500( struct airo_info *ai, u16 reg ) {
unsigned short rc; unsigned short rc;
if (test_bit(FLAG_MPI,&ai->flags))
reg <<= 1;
if ( !do8bitIO ) if ( !do8bitIO )
rc = inw( ai->dev->base_addr + reg ); rc = inw( ai->dev->base_addr + reg );
else { else {
...@@ -2824,15 +3347,25 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { ...@@ -2824,15 +3347,25 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
* open/close functions, and testing both flags together is * open/close functions, and testing both flags together is
* "cheaper" - Jean II */ * "cheaper" - Jean II */
if (ai->flags & FLAG_RADIO_MASK) return SUCCESS; if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE;
if (!lock)
return issuecommand(ai, &cmd, rsp);
if (down_interruptible(&ai->sem)) if (lock && down_interruptible(&ai->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if (!test_bit(FLAG_ENABLED, &ai->flags)) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE;
rc = issuecommand(ai, &cmd, rsp); rc = issuecommand(ai, &cmd, rsp);
if (rc == SUCCESS)
set_bit(FLAG_ENABLED, &ai->flags);
} else
rc = SUCCESS;
if (lock)
up(&ai->sem); up(&ai->sem);
if (rc)
printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n",
__FUNCTION__,rc);
return rc; return rc;
} }
...@@ -2840,16 +3373,16 @@ static void disable_MAC( struct airo_info *ai, int lock ) { ...@@ -2840,16 +3373,16 @@ static void disable_MAC( struct airo_info *ai, int lock ) {
Cmd cmd; Cmd cmd;
Resp rsp; Resp rsp;
if (lock && down_interruptible(&ai->sem))
return;
if (test_bit(FLAG_ENABLED, &ai->flags)) {
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled cmd.cmd = MAC_DISABLE; // disable in case already enabled
if (!lock) {
issuecommand(ai, &cmd, &rsp); issuecommand(ai, &cmd, &rsp);
return; clear_bit(FLAG_ENABLED, &ai->flags);
} }
if (lock)
if (down_interruptible(&ai->sem))
return;
issuecommand(ai, &cmd, &rsp);
up(&ai->sem); up(&ai->sem);
} }
...@@ -2867,6 +3400,84 @@ static void disable_interrupts( struct airo_info *ai ) { ...@@ -2867,6 +3400,84 @@ static void disable_interrupts( struct airo_info *ai ) {
OUT4500( ai, EVINTEN, 0 ); OUT4500( ai, EVINTEN, 0 );
} }
static void mpi_receive_802_3(struct airo_info *ai)
{
RxFid rxd;
int len = 0;
struct sk_buff *skb;
char *buffer;
#ifdef MICSUPPORT
int off = 0;
MICBuffer micbuf;
#endif
memcpy ((char *)&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
/* Make sure we got something */
if (rxd.rdy && rxd.valid == 0) {
len = rxd.len + 12;
if (len < 12 && len > 2048)
goto badrx;
skb = dev_alloc_skb(len);
if (!skb) {
ai->stats.rx_dropped++;
goto badrx;
}
buffer = skb_put(skb,len);
#ifdef MICSUPPORT
memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
if (ai->micstats.enabled) {
memcpy(&micbuf,
ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
sizeof(micbuf));
if (ntohs(micbuf.typelen) <= 0x05DC) {
if (len <= sizeof(micbuf) + ETH_ALEN * 2)
goto badmic;
off = sizeof(micbuf);
skb_trim (skb, len - off);
}
}
memcpy(buffer + ETH_ALEN * 2,
ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
len - ETH_ALEN * 2 - off);
if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off)) {
badmic:
dev_kfree_skb_irq (skb);
goto badrx;
}
#else
memcpy(buffer, ai->rxfids[0].virtual_host_addr, len);
#endif
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
if (ai->spy_data.spy_number > 0) {
char *sa;
struct iw_quality wstats;
/* Prepare spy data : addr + qual */
sa = buffer + ETH_ALEN;
wstats.qual = 0; /* XXX Where do I get that info from ??? */
wstats.level = 0;
wstats.updated = 0;
/* Update spy records */
wireless_spy_update(ai->dev, sa, &wstats);
}
#endif /* IW_WIRELESS_SPY */
skb->dev = ai->dev;
skb->ip_summed = CHECKSUM_NONE;
skb->protocol = eth_type_trans(skb, ai->dev);
skb->dev->last_rx = jiffies;
netif_rx(skb);
}
badrx:
if (rxd.valid == 0) {
rxd.valid = 1;
rxd.rdy = 0;
rxd.len = PKTSIZE;
memcpy (ai->rxfids[0].card_ram_off, (char *)&rxd, sizeof(rxd));
}
}
static u16 setup_card(struct airo_info *ai, u8 *mac) static u16 setup_card(struct airo_info *ai, u8 *mac)
{ {
Cmd cmd; Cmd cmd;
...@@ -2888,19 +3499,15 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2888,19 +3499,15 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
cmd.cmd = NOP; cmd.cmd = NOP;
cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
if (down_interruptible(&ai->sem)) if (down_interruptible(&ai->sem))
return ERROR; return ERROR;
if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
up(&ai->sem);
return ERROR;
}
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) { if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
up(&ai->sem); up(&ai->sem);
return ERROR; return ERROR;
} }
disable_MAC( ai, 0);
// Let's figure out if we need to use the AUX port // Let's figure out if we need to use the AUX port
if (!test_bit(FLAG_MPI,&ai->flags)) {
cmd.cmd = CMD_ENABLEAUX; cmd.cmd = CMD_ENABLEAUX;
if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
up(&ai->sem); up(&ai->sem);
...@@ -2914,11 +3521,20 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2914,11 +3521,20 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
ai->bap_read = aux_bap_read; ai->bap_read = aux_bap_read;
printk(KERN_DEBUG "airo: Doing AUX bap_reads\n"); printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
} }
}
up(&ai->sem); up(&ai->sem);
if (ai->config.len == 0) { if (ai->config.len == 0) {
tdsRssiRid rssi_rid; tdsRssiRid rssi_rid;
CapabilityRid cap_rid; CapabilityRid cap_rid;
if (ai->APList) {
kfree(ai->APList);
ai->APList = NULL;
}
if (ai->SSID) {
kfree(ai->SSID);
ai->SSID = NULL;
}
// general configuration (read/modify/write) // general configuration (read/modify/write)
status = readConfigRid(ai, 1); status = readConfigRid(ai, 1);
if ( status != SUCCESS ) return ERROR; if ( status != SUCCESS ) return ERROR;
...@@ -2926,6 +3542,12 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2926,6 +3542,12 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
status = readCapabilityRid(ai, &cap_rid); status = readCapabilityRid(ai, &cap_rid);
if ( status != SUCCESS ) return ERROR; if ( status != SUCCESS ) return ERROR;
if (test_bit(FLAG_MPI, &ai->flags) &&
strcmp (cap_rid.prodVer, "5.00.01") &&
strcmp (cap_rid.prodVer, "5.00.03") &&
strcmp (cap_rid.prodVer, "5b00.08"))
printk(KERN_ERR "airo: Firmware version %s is not supported. Use it at your own risk!\n", cap_rid.prodVer);
status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),1); status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),1);
if ( status == SUCCESS ) { if ( status == SUCCESS ) {
if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
...@@ -2977,7 +3599,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2977,7 +3599,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
} }
} }
} }
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} }
/* Setup the SSIDs if present */ /* Setup the SSIDs if present */
...@@ -2997,8 +3619,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2997,8 +3619,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
if ( status != SUCCESS ) return ERROR; if ( status != SUCCESS ) return ERROR;
/* Set up the SSID list */ /* Set up the SSID list */
if ( ssids[0] ) {
status = writeSsidRid(ai, &mySsid); status = writeSsidRid(ai, &mySsid);
if ( status != SUCCESS ) return ERROR; if ( status != SUCCESS ) return ERROR;
}
status = enable_MAC(ai, &rsp, 1); status = enable_MAC(ai, &rsp, 1);
if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
...@@ -3029,6 +3653,9 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { ...@@ -3029,6 +3653,9 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
int max_tries = 600000; int max_tries = 600000;
u16 cmd; u16 cmd;
if (IN4500(ai, EVSTAT) & EV_CMD)
OUT4500(ai, EVACK, EV_CMD);
OUT4500(ai, PARAM0, pCmd->parm0); OUT4500(ai, PARAM0, pCmd->parm0);
OUT4500(ai, PARAM1, pCmd->parm1); OUT4500(ai, PARAM1, pCmd->parm1);
OUT4500(ai, PARAM2, pCmd->parm2); OUT4500(ai, PARAM2, pCmd->parm2);
...@@ -3058,6 +3685,13 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { ...@@ -3058,6 +3685,13 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
pRsp->rsp0 = IN4500(ai, RESP0); pRsp->rsp0 = IN4500(ai, RESP0);
pRsp->rsp1 = IN4500(ai, RESP1); pRsp->rsp1 = IN4500(ai, RESP1);
pRsp->rsp2 = IN4500(ai, RESP2); pRsp->rsp2 = IN4500(ai, RESP2);
if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd);
printk (KERN_ERR "airo: status= %x\n", pRsp->status);
printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0);
printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1);
printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2);
}
// clear stuck command busy if necessary // clear stuck command busy if necessary
if (IN4500(ai, COMMAND) & COMMAND_BUSY) { if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
...@@ -3213,7 +3847,32 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in ...@@ -3213,7 +3847,32 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
if (down_interruptible(&ai->sem)) if (down_interruptible(&ai->sem))
return ERROR; return ERROR;
} }
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) { if (test_bit(FLAG_MPI,&ai->flags)) {
Cmd cmd;
Resp rsp;
memset(&cmd, 0, sizeof(cmd));
memset(&rsp, 0, sizeof(rsp));
ai->config_desc.rid_desc.valid = 1;
ai->config_desc.rid_desc.len = RIDSIZE;
ai->config_desc.rid_desc.rid = 0;
ai->config_desc.rid_desc.host_addr = ai->ridbus;
cmd.cmd = CMD_ACCESS;
cmd.parm0 = rid;
memcpy((char *)ai->config_desc.card_ram_off,
(char *)&ai->config_desc.rid_desc, sizeof(Rid));
rc = issuecommand(ai, &cmd, &rsp);
if (rsp.status & 0x7f00)
rc = rsp.rsp0;
if (!rc)
memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
goto done;
} else {
if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
rc = status; rc = status;
goto done; goto done;
} }
...@@ -3229,13 +3888,13 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in ...@@ -3229,13 +3888,13 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
if ( len <= 2 ) { if ( len <= 2 ) {
printk( KERN_ERR printk( KERN_ERR
"airo: Rid %x has a length of %d which is too short\n", "airo: Rid %x has a length of %d which is too short\n",
(int)rid, (int)rid, (int)len );
(int)len );
rc = ERROR; rc = ERROR;
goto done; goto done;
} }
// read remainder of the rid // read remainder of the rid
rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1); rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
}
done: done:
if (lock) if (lock)
up(&ai->sem); up(&ai->sem);
...@@ -3256,6 +3915,45 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, ...@@ -3256,6 +3915,45 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
if (down_interruptible(&ai->sem)) if (down_interruptible(&ai->sem))
return ERROR; return ERROR;
} }
if (test_bit(FLAG_MPI,&ai->flags)) {
Cmd cmd;
Resp rsp;
if (test_bit(FLAG_ENABLED, &ai->flags))
printk(KERN_ERR "%s: MAC should be disabled (rid=%d)\n",
__FUNCTION__, rid);
memset(&cmd, 0, sizeof(cmd));
memset(&rsp, 0, sizeof(rsp));
ai->config_desc.rid_desc.valid = 1;
ai->config_desc.rid_desc.len = RIDSIZE;
ai->config_desc.rid_desc.rid = 0;
cmd.cmd = CMD_WRITERID;
cmd.parm0 = rid;
memcpy((char *)ai->config_desc.card_ram_off,
(char *)&ai->config_desc.rid_desc, sizeof(Rid));
if (len < 4 || len > 2047) {
printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len);
rc = -1;
} else {
memcpy((char *)ai->config_desc.virtual_host_addr,
pBuf, len);
rc = issuecommand(ai, &cmd, &rsp);
if ((rc & 0xff00) != 0) {
printk(KERN_ERR "%s: Write rid Error %d\n",
__FUNCTION__,rc);
printk(KERN_ERR "%s: Cmd=%04x\n",
__FUNCTION__,cmd.cmd);
}
if ((rsp.status & 0x7f00))
rc = rsp.rsp0;
}
} else {
// --- first access so that we can write the rid data // --- first access so that we can write the rid data
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
rc = status; rc = status;
...@@ -3269,7 +3967,8 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, ...@@ -3269,7 +3967,8 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
bap_write(ai, pBuf, len, BAP1); bap_write(ai, pBuf, len, BAP1);
// ---now commit the rid data // ---now commit the rid data
rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
done: }
done:
if (lock) if (lock)
up(&ai->sem); up(&ai->sem);
return rc; return rc;
...@@ -3791,7 +4490,7 @@ static int proc_stats_rid_open( struct inode *inode, ...@@ -3791,7 +4490,7 @@ static int proc_stats_rid_open( struct inode *inode,
struct airo_info *apriv = dev->priv; struct airo_info *apriv = dev->priv;
StatsRid stats; StatsRid stats;
int i, j; int i, j;
int *vals = stats.vals; u32 *vals = stats.vals;
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -3813,7 +4512,7 @@ static int proc_stats_rid_open( struct inode *inode, ...@@ -3813,7 +4512,7 @@ static int proc_stats_rid_open( struct inode *inode,
"airo: Potentially disasterous buffer overflow averted!\n"); "airo: Potentially disasterous buffer overflow averted!\n");
break; break;
} }
j+=sprintf(data->rbuffer+j, "%s: %d\n", statsLabels[i], vals[i]); j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
} }
if (i*4>=stats.len){ if (i*4>=stats.len){
printk(KERN_WARNING printk(KERN_WARNING
...@@ -3851,7 +4550,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3851,7 +4550,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
if ( !data->writelen ) return; if ( !data->writelen ) return;
readConfigRid(ai, 1); readConfigRid(ai, 1);
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
line = data->wbuffer; line = data->wbuffer;
while( line[0] ) { while( line[0] ) {
...@@ -3859,7 +4558,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3859,7 +4558,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
if ( !strncmp( line, "Mode: ", 6 ) ) { if ( !strncmp( line, "Mode: ", 6 ) ) {
line += 6; line += 6;
if ((ai->config.rmode & 0xff) >= RXMODE_RFMON) if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
ai->need_commit = 2; set_bit (FLAG_RESET, &ai->flags);
ai->config.rmode &= 0xfe00; ai->config.rmode &= 0xfe00;
clear_bit (FLAG_802_11, &ai->flags); clear_bit (FLAG_802_11, &ai->flags);
ai->config.opmode &= 0xFF00; ai->config.opmode &= 0xFF00;
...@@ -3879,7 +4578,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3879,7 +4578,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
} else if ( line[0] == 'l' ) } else if ( line[0] == 'l' )
ai->config.rmode |= RXMODE_LANMON; ai->config.rmode |= RXMODE_LANMON;
} }
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} }
/*** Radio status */ /*** Radio status */
...@@ -3901,7 +4600,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3901,7 +4600,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
for( j = 0; j < 16 && line[j] != '\n'; j++ ) { for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
ai->config.nodeName[j] = line[j]; ai->config.nodeName[j] = line[j];
} }
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} }
/*** PowerMode processing */ /*** PowerMode processing */
...@@ -3909,13 +4608,13 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3909,13 +4608,13 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
line += 11; line += 11;
if ( !strncmp( line, "PSPCAM", 6 ) ) { if ( !strncmp( line, "PSPCAM", 6 ) ) {
ai->config.powerSaveMode = POWERSAVE_PSPCAM; ai->config.powerSaveMode = POWERSAVE_PSPCAM;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "PSP", 3 ) ) { } else if ( !strncmp( line, "PSP", 3 ) ) {
ai->config.powerSaveMode = POWERSAVE_PSP; ai->config.powerSaveMode = POWERSAVE_PSP;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else { } else {
ai->config.powerSaveMode = POWERSAVE_CAM; ai->config.powerSaveMode = POWERSAVE_CAM;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} }
} else if ( !strncmp( line, "DataRates: ", 11 ) ) { } else if ( !strncmp( line, "DataRates: ", 11 ) ) {
int v, i = 0, k = 0; /* i is index into line, int v, i = 0, k = 0; /* i is index into line,
...@@ -3927,14 +4626,14 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3927,14 +4626,14 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
line += i + 1; line += i + 1;
i = 0; i = 0;
} }
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "Channel: ", 9 ) ) { } else if ( !strncmp( line, "Channel: ", 9 ) ) {
int v, i = 0; int v, i = 0;
line += 9; line += 9;
v = get_dec_u16(line, &i, i+3); v = get_dec_u16(line, &i, i+3);
if ( v != -1 ) { if ( v != -1 ) {
ai->config.channelSet = (u16)v; ai->config.channelSet = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} }
} else if ( !strncmp( line, "XmitPower: ", 11 ) ) { } else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
int v, i = 0; int v, i = 0;
...@@ -3942,7 +4641,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3942,7 +4641,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, i+3); v = get_dec_u16(line, &i, i+3);
if ( v != -1 ) { if ( v != -1 ) {
ai->config.txPower = (u16)v; ai->config.txPower = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} }
} else if ( !strncmp( line, "WEP: ", 5 ) ) { } else if ( !strncmp( line, "WEP: ", 5 ) ) {
line += 5; line += 5;
...@@ -3957,7 +4656,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3957,7 +4656,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
ai->config.authType = (u16)AUTH_OPEN; ai->config.authType = (u16)AUTH_OPEN;
break; break;
} }
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) { } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
int v, i = 0; int v, i = 0;
...@@ -3965,7 +4664,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3965,7 +4664,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 3); v = get_dec_u16(line, &i, 3);
v = (v<0) ? 0 : ((v>255) ? 255 : v); v = (v<0) ? 0 : ((v>255) ? 255 : v);
ai->config.longRetryLimit = (u16)v; ai->config.longRetryLimit = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) { } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
int v, i = 0; int v, i = 0;
...@@ -3973,7 +4672,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3973,7 +4672,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 3); v = get_dec_u16(line, &i, 3);
v = (v<0) ? 0 : ((v>255) ? 255 : v); v = (v<0) ? 0 : ((v>255) ? 255 : v);
ai->config.shortRetryLimit = (u16)v; ai->config.shortRetryLimit = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) { } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
int v, i = 0; int v, i = 0;
...@@ -3981,7 +4680,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3981,7 +4680,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 4); v = get_dec_u16(line, &i, 4);
v = (v<0) ? 0 : ((v>2312) ? 2312 : v); v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
ai->config.rtsThres = (u16)v; ai->config.rtsThres = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) { } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
int v, i = 0; int v, i = 0;
...@@ -3989,7 +4688,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3989,7 +4688,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 5); v = get_dec_u16(line, &i, 5);
v = (v<0) ? 0 : v; v = (v<0) ? 0 : v;
ai->config.txLifetime = (u16)v; ai->config.txLifetime = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) { } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
int v, i = 0; int v, i = 0;
...@@ -3997,17 +4696,17 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -3997,17 +4696,17 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 5); v = get_dec_u16(line, &i, 5);
v = (v<0) ? 0 : v; v = (v<0) ? 0 : v;
ai->config.rxLifetime = (u16)v; ai->config.rxLifetime = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) { } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
ai->config.txDiversity = ai->config.txDiversity =
(line[13]=='l') ? 1 : (line[13]=='l') ? 1 :
((line[13]=='r')? 2: 3); ((line[13]=='r')? 2: 3);
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) { } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
ai->config.rxDiversity = ai->config.rxDiversity =
(line[13]=='l') ? 1 : (line[13]=='l') ? 1 :
((line[13]=='r')? 2: 3); ((line[13]=='r')? 2: 3);
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) { } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
int v, i = 0; int v, i = 0;
...@@ -4016,22 +4715,22 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { ...@@ -4016,22 +4715,22 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = (v<256) ? 256 : ((v>2312) ? 2312 : v); v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
v = v & 0xfffe; /* Make sure its even */ v = v & 0xfffe; /* Make sure its even */
ai->config.fragThresh = (u16)v; ai->config.fragThresh = (u16)v;
ai->need_commit = 1; set_bit (FLAG_COMMIT, &ai->flags);
} else if (!strncmp(line, "Modulation: ", 12)) { } else if (!strncmp(line, "Modulation: ", 12)) {
line += 12; line += 12;
switch(*line) { switch(*line) {
case 'd': ai->config.modulation=MOD_DEFAULT; ai->need_commit=1; break; case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'c': ai->config.modulation=MOD_CCK; ai->need_commit=1; break; case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'm': ai->config.modulation=MOD_MOK; ai->need_commit=1; break; case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
default: default:
printk( KERN_WARNING "airo: Unknown modulation\n" ); printk( KERN_WARNING "airo: Unknown modulation\n" );
} }
} else if (!strncmp(line, "Preamble: ", 10)) { } else if (!strncmp(line, "Preamble: ", 10)) {
line += 10; line += 10;
switch(*line) { switch(*line) {
case 'a': ai->config.preamble=PREAMBLE_AUTO; ai->need_commit=1; break; case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'l': ai->config.preamble=PREAMBLE_LONG; ai->need_commit=1; break; case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
case 's': ai->config.preamble=PREAMBLE_SHORT; ai->need_commit=1; break; case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
default: printk(KERN_WARNING "airo: Unknown preamble\n"); default: printk(KERN_WARNING "airo: Unknown preamble\n");
} }
} else { } else {
...@@ -4255,6 +4954,7 @@ static int set_wep_key(struct airo_info *ai, u16 index, ...@@ -4255,6 +4954,7 @@ static int set_wep_key(struct airo_info *ai, u16 index,
const char *key, u16 keylen, int perm, int lock ) { const char *key, u16 keylen, int perm, int lock ) {
static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
WepKeyRid wkr; WepKeyRid wkr;
Resp rsp;
memset(&wkr, 0, sizeof(wkr)); memset(&wkr, 0, sizeof(wkr));
if (keylen == 0) { if (keylen == 0) {
...@@ -4274,7 +4974,9 @@ static int set_wep_key(struct airo_info *ai, u16 index, ...@@ -4274,7 +4974,9 @@ static int set_wep_key(struct airo_info *ai, u16 index,
printk(KERN_INFO "Setting key %d\n", index); printk(KERN_INFO "Setting key %d\n", index);
} }
disable_MAC(ai, lock);
writeWepKeyRid(ai, &wkr, perm, lock); writeWepKeyRid(ai, &wkr, perm, lock);
enable_MAC(ai, &rsp, lock);
return 0; return 0;
} }
...@@ -4490,6 +5192,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { ...@@ -4490,6 +5192,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
Cmd cmd; Cmd cmd;
Resp rsp; Resp rsp;
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS; cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem)) if (down_interruptible(&ai->sem))
...@@ -4577,7 +5280,7 @@ static void timer_func( struct net_device *dev ) { ...@@ -4577,7 +5280,7 @@ static void timer_func( struct net_device *dev ) {
default: /* We'll escalate to SHAREDKEY */ default: /* We'll escalate to SHAREDKEY */
apriv->config.authType = AUTH_SHAREDKEY; apriv->config.authType = AUTH_SHAREDKEY;
} }
apriv->need_commit = 1; set_bit (FLAG_COMMIT, &apriv->flags);
writeConfigRid(apriv, 0); writeConfigRid(apriv, 0);
enable_MAC(apriv, &rsp, 0); enable_MAC(apriv, &rsp, 0);
up(&apriv->sem); up(&apriv->sem);
...@@ -4617,7 +5320,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, ...@@ -4617,7 +5320,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
return -ENODEV; return -ENODEV;
pci_set_master(pdev); pci_set_master(pdev);
dev = init_airo_card(pdev->irq, pdev->resource[2].start, 0); if (pdev->device == 0x5000 || pdev->device == 0xa504)
dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev);
else
dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
...@@ -4627,7 +5333,89 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, ...@@ -4627,7 +5333,89 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
static void __devexit airo_pci_remove(struct pci_dev *pdev) static void __devexit airo_pci_remove(struct pci_dev *pdev)
{ {
stop_airo_card(pci_get_drvdata(pdev), 1); }
static int airo_pci_suspend(struct pci_dev *pdev, u32 state)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct airo_info *ai = dev->priv;
Cmd cmd;
Resp rsp;
printk(KERN_DEBUG "%s: airo_mpi entering sleep mode (state=%d)\n",
dev->name, state);
if ((ai->APList == NULL) &&
(ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
return -ENOMEM;
if ((ai->SSID == NULL) &&
(ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
return -ENOMEM;
readAPListRid(ai, ai->APList);
readSsidRid(ai, ai->SSID);
memset(&cmd, 0, sizeof(cmd));
if (down_interruptible(&ai->sem))
return -EAGAIN;
disable_MAC(ai, 0);
netif_device_detach(dev);
ai->power = state;
cmd.cmd=HOSTSLEEP;
issuecommand(ai, &cmd, &rsp);
up(&ai->sem);
return 0;
}
static int airo_pci_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct airo_info *ai = dev->priv;
Resp rsp;
int err;
printk(KERN_DEBUG "%s: airo_mpi waking up\n", dev->name);
if (!ai->power)
return 0;
if (ai->power > 2) {
err = reset_mpi_card(dev);
if (err) {
printk(KERN_ERR "%s: Error %d resetting on %s()\n",
dev->name, err, __FUNCTION__);
return err;
}
schedule_timeout (HZ/2);
mpi_init_descriptors(ai);
setup_card(ai, dev->dev_addr);
clear_bit(FLAG_RADIO_OFF, &ai->flags);
clear_bit(FLAG_RADIO_DOWN, &ai->flags);
clear_bit(FLAG_PENDING_XMIT, &ai->flags);
} else {
OUT4500(ai, EVACK, EV_AWAKEN);
OUT4500(ai, EVACK, EV_AWAKEN);
schedule_timeout(HZ/10);
}
set_bit (FLAG_COMMIT, &ai->flags);
disable_MAC(ai, 1);
schedule_timeout (HZ/5);
if (ai->SSID) {
writeSsidRid(ai, ai->SSID);
kfree(ai->SSID);
ai->SSID = NULL;
}
if (ai->APList) {
writeAPListRid(ai, ai->APList);
kfree(ai->APList);
ai->APList = NULL;
}
writeConfigRid(ai, 1);
enable_MAC(ai, &rsp, 1);
ai->power = 0;
netif_device_attach(dev);
netif_wake_queue(dev);
enable_interrupts(ai);
return 0;
} }
#endif #endif
...@@ -4667,11 +5455,10 @@ static void __exit airo_cleanup_module( void ) ...@@ -4667,11 +5455,10 @@ static void __exit airo_cleanup_module( void )
printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
stop_airo_card( airo_devices->dev, 1 ); stop_airo_card( airo_devices->dev, 1 );
} }
remove_proc_entry("aironet", proc_root_driver);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
pci_unregister_driver(&airo_driver); pci_unregister_driver(&airo_driver);
#endif #endif
remove_proc_entry("aironet", proc_root_driver);
} }
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
...@@ -4736,7 +5523,7 @@ static int airo_set_freq(struct net_device *dev, ...@@ -4736,7 +5523,7 @@ static int airo_set_freq(struct net_device *dev,
readConfigRid(local, 1); readConfigRid(local, 1);
/* Yes ! We can set it !!! */ /* Yes ! We can set it !!! */
local->config.channelSet = (u16)(channel - 1); local->config.channelSet = (u16)(channel - 1);
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
} }
} }
return rc; return rc;
...@@ -4811,8 +5598,8 @@ static int airo_set_essid(struct net_device *dev, ...@@ -4811,8 +5598,8 @@ static int airo_set_essid(struct net_device *dev,
sizeof(SSID_rid.ssids[index].ssid)); sizeof(SSID_rid.ssids[index].ssid));
memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
SSID_rid.ssids[index].len = dwrq->length - 1; SSID_rid.ssids[index].len = dwrq->length - 1;
SSID_rid.len = sizeof(SSID_rid);
} }
SSID_rid.len = sizeof(SSID_rid);
/* Write it to the card */ /* Write it to the card */
disable_MAC(local, 1); disable_MAC(local, 1);
writeSsidRid(local, &SSID_rid); writeSsidRid(local, &SSID_rid);
...@@ -4924,7 +5711,7 @@ static int airo_set_nick(struct net_device *dev, ...@@ -4924,7 +5711,7 @@ static int airo_set_nick(struct net_device *dev,
readConfigRid(local, 1); readConfigRid(local, 1);
memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
memcpy(local->config.nodeName, extra, dwrq->length); memcpy(local->config.nodeName, extra, dwrq->length);
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5013,7 +5800,7 @@ static int airo_set_rate(struct net_device *dev, ...@@ -5013,7 +5800,7 @@ static int airo_set_rate(struct net_device *dev,
memset(local->config.rates, 0, 8); memset(local->config.rates, 0, 8);
local->config.rates[0] = brate; local->config.rates[0] = brate;
} }
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5059,7 +5846,7 @@ static int airo_set_rts(struct net_device *dev, ...@@ -5059,7 +5846,7 @@ static int airo_set_rts(struct net_device *dev,
} }
readConfigRid(local, 1); readConfigRid(local, 1);
local->config.rtsThres = rthr; local->config.rtsThres = rthr;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5103,7 +5890,7 @@ static int airo_set_frag(struct net_device *dev, ...@@ -5103,7 +5890,7 @@ static int airo_set_frag(struct net_device *dev,
fthr &= ~0x1; /* Get an even value - is it really needed ??? */ fthr &= ~0x1; /* Get an even value - is it really needed ??? */
readConfigRid(local, 1); readConfigRid(local, 1);
local->config.fragThresh = (u16)fthr; local->config.fragThresh = (u16)fthr;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5137,11 +5924,11 @@ static int airo_set_mode(struct net_device *dev, ...@@ -5137,11 +5924,11 @@ static int airo_set_mode(struct net_device *dev,
char *extra) char *extra)
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
int commit = 1; int reset = 0;
readConfigRid(local, 1); readConfigRid(local, 1);
if ((local->config.rmode & 0xff) >= RXMODE_RFMON) if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
commit = 2; reset = 1;
switch(*uwrq) { switch(*uwrq) {
case IW_MODE_ADHOC: case IW_MODE_ADHOC:
...@@ -5183,7 +5970,9 @@ static int airo_set_mode(struct net_device *dev, ...@@ -5183,7 +5970,9 @@ static int airo_set_mode(struct net_device *dev,
default: default:
return -EINVAL; return -EINVAL;
} }
local->need_commit = commit; if (reset)
set_bit (FLAG_RESET, &local->flags);
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5253,7 +6042,7 @@ static int airo_set_encode(struct net_device *dev, ...@@ -5253,7 +6042,7 @@ static int airo_set_encode(struct net_device *dev,
return -EINVAL; return -EINVAL;
} }
/* Check the index (none -> use current) */ /* Check the index (none -> use current) */
if ((index < 0) || (index>=(cap_rid.softCap&0x80)?4:1)) if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1)))
index = current_index; index = current_index;
/* Set the length */ /* Set the length */
if (dwrq->length > MIN_KEY_SIZE) if (dwrq->length > MIN_KEY_SIZE)
...@@ -5279,12 +6068,12 @@ static int airo_set_encode(struct net_device *dev, ...@@ -5279,12 +6068,12 @@ static int airo_set_encode(struct net_device *dev,
if((index == current_index) && (key.len > 0) && if((index == current_index) && (key.len > 0) &&
(local->config.authType == AUTH_OPEN)) { (local->config.authType == AUTH_OPEN)) {
local->config.authType = AUTH_ENCRYPT; local->config.authType = AUTH_ENCRYPT;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
} }
} else { } else {
/* Do we want to just set the transmit key index ? */ /* Do we want to just set the transmit key index ? */
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) { if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
set_wep_key(local, index, 0, 0, 1, 1); set_wep_key(local, index, 0, 0, 1, 1);
} else } else
/* Don't complain if only change the mode */ /* Don't complain if only change the mode */
...@@ -5301,7 +6090,7 @@ static int airo_set_encode(struct net_device *dev, ...@@ -5301,7 +6090,7 @@ static int airo_set_encode(struct net_device *dev,
local->config.authType = AUTH_ENCRYPT; // Only Wep local->config.authType = AUTH_ENCRYPT; // Only Wep
/* Commit the changes to flags if needed */ /* Commit the changes to flags if needed */
if(dwrq->flags & IW_ENCODE_MODE) if(dwrq->flags & IW_ENCODE_MODE)
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5342,7 +6131,7 @@ static int airo_get_encode(struct net_device *dev, ...@@ -5342,7 +6131,7 @@ static int airo_get_encode(struct net_device *dev,
memset(extra, 0, 16); memset(extra, 0, 16);
/* Which key do we want ? -1 -> tx index */ /* Which key do we want ? -1 -> tx index */
if((index < 0) || (index >= (cap_rid.softCap & 0x80) ? 4 : 1)) if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1)))
index = get_wep_key(local, 0xffff); index = get_wep_key(local, 0xffff);
dwrq->flags |= index + 1; dwrq->flags |= index + 1;
/* Copy the key to the user buffer */ /* Copy the key to the user buffer */
...@@ -5370,8 +6159,7 @@ static int airo_set_txpow(struct net_device *dev, ...@@ -5370,8 +6159,7 @@ static int airo_set_txpow(struct net_device *dev,
readCapabilityRid(local, &cap_rid); readCapabilityRid(local, &cap_rid);
if (vwrq->disabled) { if (vwrq->disabled) {
set_bit (FLAG_RADIO_OFF, &local->flags); set_bit (FLAG_RADIO_OFF | FLAG_COMMIT, &local->flags);
local->need_commit = 1;
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
if (vwrq->flags != IW_TXPOW_MWATT) { if (vwrq->flags != IW_TXPOW_MWATT) {
...@@ -5382,7 +6170,7 @@ static int airo_set_txpow(struct net_device *dev, ...@@ -5382,7 +6170,7 @@ static int airo_set_txpow(struct net_device *dev,
if ((vwrq->value==cap_rid.txPowerLevels[i])) { if ((vwrq->value==cap_rid.txPowerLevels[i])) {
readConfigRid(local, 1); readConfigRid(local, 1);
local->config.txPower = vwrq->value; local->config.txPower = vwrq->value;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
rc = -EINPROGRESS; /* Call commit handler */ rc = -EINPROGRESS; /* Call commit handler */
break; break;
} }
...@@ -5435,12 +6223,12 @@ static int airo_set_retry(struct net_device *dev, ...@@ -5435,12 +6223,12 @@ static int airo_set_retry(struct net_device *dev,
local->config.longRetryLimit = vwrq->value; local->config.longRetryLimit = vwrq->value;
local->config.shortRetryLimit = vwrq->value; local->config.shortRetryLimit = vwrq->value;
} }
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
rc = -EINPROGRESS; /* Call commit handler */ rc = -EINPROGRESS; /* Call commit handler */
} }
if(vwrq->flags & IW_RETRY_LIFETIME) { if(vwrq->flags & IW_RETRY_LIFETIME) {
local->config.txLifetime = vwrq->value / 1024; local->config.txLifetime = vwrq->value / 1024;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
rc = -EINPROGRESS; /* Call commit handler */ rc = -EINPROGRESS; /* Call commit handler */
} }
return rc; return rc;
...@@ -5606,17 +6394,17 @@ static int airo_set_power(struct net_device *dev, ...@@ -5606,17 +6394,17 @@ static int airo_set_power(struct net_device *dev,
local->config.powerSaveMode = POWERSAVE_CAM; local->config.powerSaveMode = POWERSAVE_CAM;
local->config.rmode &= 0xFF00; local->config.rmode &= 0xFF00;
local->config.rmode |= RXMODE_BC_MC_ADDR; local->config.rmode |= RXMODE_BC_MC_ADDR;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
local->config.fastListenDelay = (vwrq->value + 500) / 1024; local->config.fastListenDelay = (vwrq->value + 500) / 1024;
local->config.powerSaveMode = POWERSAVE_PSPCAM; local->config.powerSaveMode = POWERSAVE_PSPCAM;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024; local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
local->config.powerSaveMode = POWERSAVE_PSPCAM; local->config.powerSaveMode = POWERSAVE_PSPCAM;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
} }
switch (vwrq->flags & IW_POWER_MODE) { switch (vwrq->flags & IW_POWER_MODE) {
case IW_POWER_UNICAST_R: case IW_POWER_UNICAST_R:
...@@ -5625,7 +6413,7 @@ static int airo_set_power(struct net_device *dev, ...@@ -5625,7 +6413,7 @@ static int airo_set_power(struct net_device *dev,
} }
local->config.rmode &= 0xFF00; local->config.rmode &= 0xFF00;
local->config.rmode |= RXMODE_ADDR; local->config.rmode |= RXMODE_ADDR;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
break; break;
case IW_POWER_ALL_R: case IW_POWER_ALL_R:
if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
...@@ -5633,7 +6421,7 @@ static int airo_set_power(struct net_device *dev, ...@@ -5633,7 +6421,7 @@ static int airo_set_power(struct net_device *dev,
} }
local->config.rmode &= 0xFF00; local->config.rmode &= 0xFF00;
local->config.rmode |= RXMODE_BC_MC_ADDR; local->config.rmode |= RXMODE_BC_MC_ADDR;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
case IW_POWER_ON: case IW_POWER_ON:
break; break;
default: default:
...@@ -5688,7 +6476,7 @@ static int airo_set_sens(struct net_device *dev, ...@@ -5688,7 +6476,7 @@ static int airo_set_sens(struct net_device *dev,
readConfigRid(local, 1); readConfigRid(local, 1);
local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value; local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
local->need_commit = 1; set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */ return -EINPROGRESS; /* Call commit handler */
} }
...@@ -5776,7 +6564,6 @@ static int airo_get_aplist(struct net_device *dev, ...@@ -5776,7 +6564,6 @@ static int airo_get_aplist(struct net_device *dev,
return 0; return 0;
} }
#if WIRELESS_EXT > 13
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Wireless Handler : Initiate Scan * Wireless Handler : Initiate Scan
...@@ -5796,6 +6583,7 @@ static int airo_set_scan(struct net_device *dev, ...@@ -5796,6 +6583,7 @@ static int airo_set_scan(struct net_device *dev,
* This is not an error, while the device perform scanning, * This is not an error, while the device perform scanning,
* traffic doesn't flow, so it's a perfect DoS... * traffic doesn't flow, so it's a perfect DoS...
* Jean II */ * Jean II */
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
/* Initiate a scan command */ /* Initiate a scan command */
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
...@@ -5964,72 +6752,6 @@ static int airo_get_scan(struct net_device *dev, ...@@ -5964,72 +6752,6 @@ static int airo_get_scan(struct net_device *dev,
return 0; return 0;
} }
#endif /* WIRELESS_EXT > 13 */
#if WIRELESS_EXT <= 15
#ifdef WIRELESS_SPY
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set Spy List
*/
static int airo_set_spy(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq,
char *extra)
{
struct airo_info *local = dev->priv;
struct sockaddr *address = (struct sockaddr *) extra;
/* Disable spy while we copy the addresses.
* As we don't disable interrupts, we need to do this to avoid races */
local->spy_number = 0;
if (dwrq->length > 0) {
int i;
/* Copy addresses */
for (i = 0; i < dwrq->length; i++)
memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN);
/* Reset stats */
memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
}
/* Enable addresses */
local->spy_number = dwrq->length;
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get Spy List
*/
static int airo_get_spy(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq,
char *extra)
{
struct airo_info *local = dev->priv;
struct sockaddr *address = (struct sockaddr *) extra;
int i;
dwrq->length = local->spy_number;
/* Copy addresses. */
for(i = 0; i < local->spy_number; i++) {
memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN);
address[i].sa_family = AF_UNIX;
}
/* Copy stats to the user buffer (just after). */
if(local->spy_number > 0)
memcpy(extra + (sizeof(struct sockaddr) * local->spy_number),
local->spy_stat, sizeof(struct iw_quality) * local->spy_number);
/* Reset updated flags. */
for (i=0; i<local->spy_number; i++)
local->spy_stat[i].updated = 0;
return 0;
}
#endif /* WIRELESS_SPY */
#endif /* WIRELESS_EXT <= 15 */
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
...@@ -6043,13 +6765,13 @@ static int airo_config_commit(struct net_device *dev, ...@@ -6043,13 +6765,13 @@ static int airo_config_commit(struct net_device *dev,
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
Resp rsp; Resp rsp;
if (!local->need_commit) if (!test_bit (FLAG_COMMIT, &local->flags))
return 0; return 0;
/* Some of the "SET" function may have modified some of the /* Some of the "SET" function may have modified some of the
* parameters. It's now time to commit them in the card */ * parameters. It's now time to commit them in the card */
disable_MAC(local, 1); disable_MAC(local, 1);
if (local->need_commit > 1) { if (test_bit (FLAG_RESET, &local->flags)) {
APListRid APList_rid; APListRid APList_rid;
SsidRid SSID_rid; SsidRid SSID_rid;
...@@ -6064,7 +6786,7 @@ static int airo_config_commit(struct net_device *dev, ...@@ -6064,7 +6786,7 @@ static int airo_config_commit(struct net_device *dev,
return -ERESTARTSYS; return -ERESTARTSYS;
writeConfigRid(local, 0); writeConfigRid(local, 0);
enable_MAC(local, &rsp, 0); enable_MAC(local, &rsp, 0);
if (local->need_commit > 1) if (test_bit (FLAG_RESET, &local->flags))
airo_set_promisc(local); airo_set_promisc(local);
else else
up(&local->sem); up(&local->sem);
...@@ -6085,7 +6807,6 @@ static const struct iw_priv_args airo_private_args[] = { ...@@ -6085,7 +6807,6 @@ static const struct iw_priv_args airo_private_args[] = {
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" }, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
}; };
#if WIRELESS_EXT > 12
static const iw_handler airo_handler[] = static const iw_handler airo_handler[] =
{ {
(iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */ (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
...@@ -6104,33 +6825,16 @@ static const iw_handler airo_handler[] = ...@@ -6104,33 +6825,16 @@ static const iw_handler airo_handler[] =
(iw_handler) NULL, /* SIOCGIWPRIV */ (iw_handler) NULL, /* SIOCGIWPRIV */
(iw_handler) NULL, /* SIOCSIWSTATS */ (iw_handler) NULL, /* SIOCSIWSTATS */
(iw_handler) NULL, /* SIOCGIWSTATS */ (iw_handler) NULL, /* SIOCGIWSTATS */
#if WIRELESS_EXT > 15
iw_handler_set_spy, /* SIOCSIWSPY */ iw_handler_set_spy, /* SIOCSIWSPY */
iw_handler_get_spy, /* SIOCGIWSPY */ iw_handler_get_spy, /* SIOCGIWSPY */
iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
#else /* WIRELESS_EXT > 15 */
#ifdef WIRELESS_SPY
(iw_handler) airo_set_spy, /* SIOCSIWSPY */
(iw_handler) airo_get_spy, /* SIOCGIWSPY */
#else /* WIRELESS_SPY */
(iw_handler) NULL, /* SIOCSIWSPY */
(iw_handler) NULL, /* SIOCGIWSPY */
#endif /* WIRELESS_SPY */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
#endif /* WIRELESS_EXT > 15 */
(iw_handler) airo_set_wap, /* SIOCSIWAP */ (iw_handler) airo_set_wap, /* SIOCSIWAP */
(iw_handler) airo_get_wap, /* SIOCGIWAP */ (iw_handler) airo_get_wap, /* SIOCGIWAP */
(iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */
(iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */ (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
#if WIRELESS_EXT > 13
(iw_handler) airo_set_scan, /* SIOCSIWSCAN */ (iw_handler) airo_set_scan, /* SIOCSIWSCAN */
(iw_handler) airo_get_scan, /* SIOCGIWSCAN */ (iw_handler) airo_get_scan, /* SIOCGIWSCAN */
#else /* WIRELESS_EXT > 13 */
(iw_handler) NULL, /* SIOCSIWSCAN */
(iw_handler) NULL, /* SIOCGIWSCAN */
#endif /* WIRELESS_EXT > 13 */
(iw_handler) airo_set_essid, /* SIOCSIWESSID */ (iw_handler) airo_set_essid, /* SIOCSIWESSID */
(iw_handler) airo_get_essid, /* SIOCGIWESSID */ (iw_handler) airo_get_essid, /* SIOCGIWESSID */
(iw_handler) airo_set_nick, /* SIOCSIWNICKN */ (iw_handler) airo_set_nick, /* SIOCSIWNICKN */
...@@ -6173,14 +6877,11 @@ static const struct iw_handler_def airo_handler_def = ...@@ -6173,14 +6877,11 @@ static const struct iw_handler_def airo_handler_def =
.standard = (iw_handler *) airo_handler, .standard = (iw_handler *) airo_handler,
.private = (iw_handler *) airo_private_handler, .private = (iw_handler *) airo_private_handler,
.private_args = (struct iw_priv_args *) airo_private_args, .private_args = (struct iw_priv_args *) airo_private_args,
#if WIRELESS_EXT > 15
.spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) - .spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) -
(void *) NULL), (void *) NULL),
#endif /* WIRELESS_EXT > 15 */
}; };
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
/* /*
...@@ -6199,290 +6900,12 @@ static const struct iw_handler_def airo_handler_def = ...@@ -6199,290 +6900,12 @@ static const struct iw_handler_def airo_handler_def =
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
int rc = 0; int rc = 0;
#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13 struct airo_info *ai = (struct airo_info *)dev->priv;
struct iwreq *wrq = (struct iwreq *) rq;
#endif /* WIRELESS_EXT < 13 */
switch (cmd) {
/* WE 13 and higher will use airo_handler_def */
#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
case SIOCGIWNAME: // Get name
airo_get_name(dev, NULL, (char *) &(wrq->u.name), NULL);
break;
case SIOCSIWFREQ: // Set frequency/channel
rc = airo_set_freq(dev, NULL, &(wrq->u.freq), NULL);
break;
case SIOCGIWFREQ: // Get frequency/channel
rc = airo_get_freq(dev, NULL, &(wrq->u.freq), NULL);
break;
case SIOCSIWESSID: // Set desired network name (ESSID)
{
char essidbuf[IW_ESSID_MAX_SIZE+1];
if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
rc = -E2BIG;
break;
}
if (copy_from_user(essidbuf, wrq->u.essid.pointer,
wrq->u.essid.length)) {
rc = -EFAULT;
break;
}
rc = airo_set_essid(dev, NULL,
&(wrq->u.essid), essidbuf);
}
break;
case SIOCGIWESSID: // Get current network name (ESSID)
{
char essidbuf[IW_ESSID_MAX_SIZE+1];
if (wrq->u.essid.pointer)
rc = airo_get_essid(dev, NULL,
&(wrq->u.essid), essidbuf);
if ( copy_to_user(wrq->u.essid.pointer,
essidbuf,
wrq->u.essid.length) )
rc = -EFAULT;
}
break;
case SIOCSIWAP:
rc = airo_set_wap(dev, NULL, &(wrq->u.ap_addr), NULL);
break;
case SIOCGIWAP: // Get current Access Point (BSSID)
rc = airo_get_wap(dev, NULL, &(wrq->u.ap_addr), NULL);
break;
case SIOCSIWNICKN: // Set desired station name
{
char nickbuf[IW_ESSID_MAX_SIZE+1];
if (wrq->u.data.length > IW_ESSID_MAX_SIZE) {
rc = -E2BIG;
break;
}
if (copy_from_user(nickbuf, wrq->u.data.pointer,
wrq->u.data.length)) {
rc = -EFAULT;
break;
}
rc = airo_set_nick(dev, NULL,
&(wrq->u.data), nickbuf);
}
break;
case SIOCGIWNICKN: // Get current station name
{
char nickbuf[IW_ESSID_MAX_SIZE+1];
if (wrq->u.data.pointer)
rc = airo_get_nick(dev, NULL,
&(wrq->u.data), nickbuf);
if ( copy_to_user(wrq->u.data.pointer,
nickbuf,
wrq->u.data.length) )
rc = -EFAULT;
}
break;
case SIOCSIWRATE: // Set the desired bit-rate
rc = airo_set_rate(dev, NULL, &(wrq->u.bitrate), NULL);
break;
case SIOCGIWRATE: // Get the current bit-rate
rc = airo_get_rate(dev, NULL, &(wrq->u.bitrate), NULL);
break;
case SIOCSIWRTS: // Set the desired RTS threshold
rc = airo_set_rts(dev, NULL, &(wrq->u.rts), NULL);
break;
case SIOCGIWRTS: // Get the current RTS threshold
rc = airo_get_rts(dev, NULL, &(wrq->u.rts), NULL);
break;
case SIOCSIWFRAG: // Set the desired fragmentation threshold
rc = airo_set_frag(dev, NULL, &(wrq->u.frag), NULL);
break;
case SIOCGIWFRAG: // Get the current fragmentation threshold
rc = airo_get_frag(dev, NULL, &(wrq->u.frag), NULL);
break;
case SIOCSIWMODE: // Set mode of operation
rc = airo_set_mode(dev, NULL, &(wrq->u.mode), NULL);
break;
case SIOCGIWMODE: // Get mode of operation
rc = airo_get_mode(dev, NULL, &(wrq->u.mode), NULL);
break;
case SIOCSIWENCODE: // Set WEP keys and mode
{
char keybuf[MAX_KEY_SIZE];
if (wrq->u.encoding.pointer) {
/* We actually have a key to set */
if (wrq->u.encoding.length > MAX_KEY_SIZE) {
rc = -E2BIG;
break;
}
if (copy_from_user(keybuf,
wrq->u.encoding.pointer,
wrq->u.encoding.length)) {
rc = -EFAULT;
break;
}
} else if (wrq->u.encoding.length != 0) {
rc = -EINVAL;
break;
}
rc = airo_set_encode(dev, NULL,
&(wrq->u.encoding), keybuf);
}
break;
case SIOCGIWENCODE: // Get the WEP keys and mode
// Only super-user can see WEP key
// Note : this is needed only for very old versions of WE
if (!capable(CAP_NET_ADMIN)) {
rc = -EPERM;
break;
}
{
char keybuf[MAX_KEY_SIZE];
rc = airo_get_encode(dev, NULL,
&(wrq->u.encoding), keybuf);
if (wrq->u.encoding.pointer) {
if (copy_to_user(wrq->u.encoding.pointer,
keybuf,
wrq->u.encoding.length))
rc = -EFAULT;
}
}
break;
case SIOCGIWTXPOW: // Get the current Tx-Power
rc=airo_get_txpow(dev, NULL, &(wrq->u.txpower), NULL);
break;
case SIOCSIWTXPOW:
rc=airo_set_txpow(dev, NULL, &(wrq->u.txpower), NULL);
break;
case SIOCSIWRETRY:
rc=airo_set_retry(dev, NULL, &(wrq->u.retry), NULL);
break;
case SIOCGIWRETRY:
rc=airo_get_retry(dev, NULL, &(wrq->u.retry), NULL);
break;
case SIOCGIWRANGE: // Get range of parameters
{
struct iw_range range;
rc = airo_get_range(dev, NULL,
&(wrq->u.data), (char *) &range);
if (copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range)))
rc = -EFAULT;
}
break;
case SIOCGIWPOWER:
rc=airo_get_power(dev, NULL, &(wrq->u.power), NULL);
break;
case SIOCSIWPOWER:
rc=airo_set_power(dev, NULL, &(wrq->u.power), NULL);
break;
case SIOCGIWSENS:
rc = airo_get_sens(dev, NULL, &(wrq->u.sens), NULL);
break;
case SIOCSIWSENS:
rc = airo_set_sens(dev, NULL, &(wrq->u.sens), NULL);
break;
case SIOCGIWAPLIST:
{
char buffer[IW_MAX_AP * (sizeof(struct sockaddr) +
sizeof(struct iw_quality))];
if (wrq->u.data.pointer) {
rc = airo_get_aplist(dev, NULL,
&(wrq->u.data), buffer);
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length *
(sizeof(struct sockaddr) +
sizeof(struct iw_quality)))
))
rc = -EFAULT;
}
}
break;
#ifdef WIRELESS_SPY
case SIOCSIWSPY: // Set the spy list
{
struct sockaddr address[IW_MAX_SPY];
/* Check the number of addresses */
if (wrq->u.data.length > IW_MAX_SPY) {
rc = -E2BIG;
break;
}
/* Get the data in the driver */
if (wrq->u.data.pointer) {
if (copy_from_user((char *) address,
wrq->u.data.pointer,
sizeof(struct sockaddr) *
wrq->u.data.length)) {
rc = -EFAULT;
break;
}
} else if (wrq->u.data.length != 0) {
rc = -EINVAL;
break;
}
rc=airo_set_spy(dev, NULL, &(wrq->u.data),
(char *) address);
}
break;
case SIOCGIWSPY: // Get the spy list
{
char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
sizeof(struct iw_quality))];
if (wrq->u.data.pointer) {
rc = airo_get_spy(dev, NULL,
&(wrq->u.data), buffer);
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length *
(sizeof(struct sockaddr) +
sizeof(struct iw_quality)))
))
rc = -EFAULT;
}
}
break;
#endif /* WIRELESS_SPY */
#ifdef CISCO_EXT if (ai->power)
case SIOCGIWPRIV: return 0;
if(wrq->u.data.pointer) {
/* Set the number of ioctl available */
wrq->u.data.length = sizeof(airo_private_args) / sizeof( airo_private_args[0]);
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer,
(u_char *) airo_private_args,
sizeof(airo_private_args)))
rc = -EFAULT;
}
break;
#endif /* CISCO_EXT */
#endif /* WIRELESS_EXT < 13 */
switch (cmd) {
#ifdef CISCO_EXT #ifdef CISCO_EXT
case AIROIDIFC: case AIROIDIFC:
#ifdef AIROOLDIDIFC #ifdef AIROOLDIDIFC
...@@ -6530,16 +6953,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -6530,16 +6953,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
default: default:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
/* WE 13 and higher will use airo_config_commit */
/* Some of the "SET" function may have modified some of the
* parameters. It's now time to commit them in the card */
airo_config_commit(dev, NULL, NULL, NULL);
if (rc == -EINPROGRESS)
return 0;
#endif /* WIRELESS_EXT < 13 */
return rc; return rc;
} }
...@@ -6561,6 +6974,10 @@ static void airo_read_wireless_stats(struct airo_info *local) ...@@ -6561,6 +6974,10 @@ static void airo_read_wireless_stats(struct airo_info *local)
/* Get stats out of the card */ /* Get stats out of the card */
clear_bit(JOB_WSTATS, &local->flags); clear_bit(JOB_WSTATS, &local->flags);
if (local->power) {
up(&local->sem);
return;
}
readStatusRid(local, &status_rid, 0); readStatusRid(local, &status_rid, 0);
readStatsRid(local, &stats_rid, RID_STATS, 0); readStatsRid(local, &stats_rid, RID_STATS, 0);
up(&local->sem); up(&local->sem);
...@@ -6608,7 +7025,6 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) ...@@ -6608,7 +7025,6 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
#ifdef CISCO_EXT #ifdef CISCO_EXT
#define RIDS_SIZE 2048
/* /*
* This just translates from driver IOCTL codes to the command codes to * This just translates from driver IOCTL codes to the command codes to
* feed to the radio's host interface. Things can be added/deleted * feed to the radio's host interface. Things can be added/deleted
...@@ -6659,10 +7075,10 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6659,10 +7075,10 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
break; break;
} }
if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL) if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
PC4500_readrid(ai,ridcode,iobuf,RIDS_SIZE, 1); PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
/* get the count of bytes in the rid docs say 1st 2 bytes is it. /* get the count of bytes in the rid docs say 1st 2 bytes is it.
* then return it to the user * then return it to the user
* 9/22/2000 Honor user given length * 9/22/2000 Honor user given length
...@@ -6672,7 +7088,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6672,7 +7088,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
else else
len = comp->len; len = comp->len;
if (copy_to_user(comp->data, iobuf, min(len, (int)RIDS_SIZE))) { if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
kfree (iobuf); kfree (iobuf);
return -EFAULT; return -EFAULT;
} }
...@@ -6735,10 +7151,10 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6735,10 +7151,10 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* writerid routines. * writerid routines.
*/ */
case AIROPSTCLR: case AIROPSTCLR:
if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL) if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1); PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
#ifdef MICSUPPORT #ifdef MICSUPPORT
enabled = ai->micstats.enabled; enabled = ai->micstats.enabled;
...@@ -6747,7 +7163,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6747,7 +7163,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
#endif #endif
if (copy_to_user(comp->data, iobuf, if (copy_to_user(comp->data, iobuf,
min((int)comp->len, (int)RIDS_SIZE))) { min((int)comp->len, (int)RIDSIZE))) {
kfree (iobuf); kfree (iobuf);
return -EFAULT; return -EFAULT;
} }
...@@ -6757,10 +7173,10 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6757,10 +7173,10 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
default: default:
return -EOPNOTSUPP; /* Blarg! */ return -EOPNOTSUPP; /* Blarg! */
} }
if(comp->len > RIDS_SIZE) if(comp->len > RIDSIZE)
return -EINVAL; return -EINVAL;
if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL) if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(iobuf,comp->data,comp->len)) { if (copy_from_user(iobuf,comp->data,comp->len)) {
...@@ -6990,13 +7406,16 @@ int flashputbuf(struct airo_info *ai){ ...@@ -6990,13 +7406,16 @@ int flashputbuf(struct airo_info *ai){
int nwords; int nwords;
/* Write stuff */ /* Write stuff */
if (test_bit(FLAG_MPI,&ai->flags))
memcpy(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
else {
OUT4500(ai,AUXPAGE,0x100); OUT4500(ai,AUXPAGE,0x100);
OUT4500(ai,AUXOFF,0); OUT4500(ai,AUXOFF,0);
for(nwords=0;nwords != FLASHSIZE / 2;nwords++){ for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff); OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
} }
}
OUT4500(ai,SWS0,0x8000); OUT4500(ai,SWS0,0x8000);
return 0; return 0;
...@@ -7013,8 +7432,10 @@ int flashrestart(struct airo_info *ai,struct net_device *dev){ ...@@ -7013,8 +7432,10 @@ int flashrestart(struct airo_info *ai,struct net_device *dev){
clear_bit (FLAG_FLASHING, &ai->flags); clear_bit (FLAG_FLASHING, &ai->flags);
status = setup_card(ai, dev->dev_addr); status = setup_card(ai, dev->dev_addr);
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ ) { for( i = 0; i < MAX_FIDS; i++ ) {
ai->fids[i] = transmit_allocate( ai, 2312, i >= MAX_FIDS / 2 ); ai->fids[i] = transmit_allocate
( ai, 2312, i >= MAX_FIDS / 2 );
} }
set_current_state (TASK_UNINTERRUPTIBLE); set_current_state (TASK_UNINTERRUPTIBLE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment