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 @@
Aironet. Major code contributions were received from Javier Achirica
<achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>.
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[] = {
{ 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x0340, 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, }
};
MODULE_DEVICE_TABLE(pci, card_ids);
static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
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 = {
.name = "airo",
.id_table = card_ids,
.probe = airo_pci_probe,
.remove = __devexit_p(airo_pci_remove),
.suspend = airo_pci_suspend,
.resume = airo_pci_resume,
};
#endif /* CONFIG_PCI */
/* Include Wireless Extension definition and check version - Jean II */
#include <linux/wireless.h>
#define WIRELESS_SPY // enable iwspy support
#if WIRELESS_EXT > 12
#include <net/iw_handler.h> // New driver API
#endif /* WIRELESS_EXT > 12 */
#define CISCO_EXT // enable Cisco extensions
#ifdef CISCO_EXT
......@@ -235,10 +241,10 @@ static int proc_perm = 0644;
MODULE_AUTHOR("Benjamin Reed");
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.");
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(irq,"1-4i");
MODULE_PARM(basic_rate,"i");
......@@ -380,6 +386,16 @@ static int do8bitIO = 0;
#define AUXOFF 0x3C
#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 */
#define BAP0 0 // Used for receiving packets
#define BAP1 2 // Used for xmiting packets and working with RIDS
......@@ -405,7 +421,8 @@ static int do8bitIO = 0;
#define EV_TXCPY 0x400
#define EV_UNKNOWN 0x800
#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
#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
......@@ -413,6 +430,9 @@ static int do8bitIO = 0;
#define IGNORE_INTS (~STATUS_INTS)
#endif
/* RID TYPES */
#define RID_RW 0x20
/* The RIDs */
#define RID_CAPABILITIES 0xFF00
#define RID_APINFO 0xFF01
......@@ -615,7 +635,7 @@ typedef struct {
/*---------- Aironet Extensions ----------*/
u8 magicAction;
#define MAGIC_ACTION_STSCHG 1
#define MACIC_ACTION_RESUME 2
#define MAGIC_ACTION_RESUME 2
#define MAGIC_IGNORE_MCAST (1<<8)
#define MAGIC_IGNORE_BCAST (1<<9)
#define MAGIC_SWITCH_TO_PSP (0<<10)
......@@ -869,6 +889,7 @@ typedef struct {
#define AIRORESTART AIROFLPUTBUF + 1
#define FLASHSIZE 32768
#define AUXMEMSIZE (256 * 1024)
typedef struct aironet_ioctl {
unsigned short command; // What to do
......@@ -916,6 +937,110 @@ typedef struct {
miccntx uCtx; // Unicast context
} 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
// Frequency list (map channels to frequencies)
static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
......@@ -935,14 +1060,8 @@ typedef struct wep_key_t {
#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
#endif /* IW_ENCODE_NOKEY */
#if WIRELESS_EXT > 12
/* List of Wireless Handlers (new API) */
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 */
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);
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 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
*regs);
static int airo_thread(void *data);
......@@ -1000,26 +1124,23 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket,
struct airo_info {
struct net_device_stats stats;
int open;
struct net_device *dev;
/* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
use the high bit to mark whether it is in use. */
#define MAX_FIDS 6
#define MPI_MAX_FIDS 1
int fids[MAX_FIDS];
int registered;
ConfigRid config;
int need_commit; // Need to set config
char keyindex; // Used with auto wep
char defindex; // Used with auto wep
struct proc_dir_entry *proc_entry;
struct airo_info *next;
spinlock_t aux_lock;
unsigned long flags;
#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
#define FLAG_RADIO_MASK 0x03
#define FLAG_FLASHING 2
#define FLAG_ENABLED 2
#define FLAG_ADHOC 3 /* Needed by MIC */
#define FLAG_MIC_CAPABLE 4
#define FLAG_UPDATE_MULTI 5
......@@ -1027,6 +1148,11 @@ struct airo_info {
#define FLAG_802_11 7
#define FLAG_PENDING_XMIT 9
#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_DIE 16
#define JOB_XMIT 17
......@@ -1055,15 +1181,7 @@ struct airo_info {
#ifdef WIRELESS_EXT
struct iw_statistics wstats; // wireless stats
unsigned long scan_timestamp; /* Time started to scan */
#if WIRELESS_EXT > 15
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 */
#ifdef MICSUPPORT
/* MIC stuff */
......@@ -1071,6 +1189,20 @@ struct airo_info {
mic_module mod[2];
mic_statistics micstats;
#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,
......@@ -1550,6 +1682,7 @@ static int readBSSListRid(struct airo_info *ai, int first,
Resp rsp;
if (first == 1) {
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem))
......@@ -1647,8 +1780,11 @@ static int readConfigRid(struct airo_info*ai, int lock) {
for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
*s = le16_to_cpu(*s);
for(s = &cfg.arlThreshold; s <= &cfg.autoWake; s++)
*s = le16_to_cpu(*s);
for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
*s = cpu_to_le16(*s);
for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
*s = cpu_to_le16(*s);
ai->config = cfg;
return SUCCESS;
......@@ -1668,10 +1804,10 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
u16 *s;
ConfigRid cfgr;
if (!ai->need_commit)
if (!test_bit (FLAG_COMMIT, &ai->flags))
return SUCCESS;
ai->need_commit = 0;
clear_bit (FLAG_COMMIT | FLAG_RESET, &ai->flags);
checkThrottle(ai);
cfgr = ai->config;
......@@ -1688,7 +1824,10 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; 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);
return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
......@@ -1749,7 +1888,7 @@ static int airo_open(struct net_device *dev) {
* Wireless Extensions may postpone config changes until the card
* is open (to pipeline changes and speed-up card setup). If
* 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);
writeConfigRid(info, 1);
}
......@@ -1765,52 +1904,177 @@ static int airo_open(struct net_device *dev) {
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)
{
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);
if (le16_to_cpu(status) & 2) /* Too many retries */
ai->stats.tx_aborted_errors++;
if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
ai->stats.tx_heartbeat_errors++;
if (le16_to_cpu(status) & 8) /* Aid fail */
{ }
if (le16_to_cpu(status) & 0x10) /* MAC disabled */
ai->stats.tx_carrier_errors++;
if (le16_to_cpu(status) & 0x20) /* Association lost */
{ }
#if WIRELESS_EXT > 13
/* We produce a TXDROP event only for retry or lifetime
* exceeded, because that's the only status that really mean
* that this particular node went away.
* Other errors means that *we* screwed up. - Jean II */
if ((le16_to_cpu(status) & 2) ||
(le16_to_cpu(status) & 4)) {
union iwreq_data wrqu;
char junk[0x18];
/* Faster to skip over useless data than to do
* another bap_setup(). We are at offset 0x6 and
* need to go to 0x18 and read 6 bytes - Jean II */
bap_read(ai, (u16 *) junk, 0x18, BAP0);
/* Copy 802.11 dest address.
* We use the 802.11 header because the frame may
* not be 802.3 or may be mangled...
* In Ad-Hoc mode, it will be the node address.
* In managed mode, it will be most likely the AP addr
* User space will figure out how to convert it to
* whatever it needs (IP address or else).
* - Jean II */
memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
/* Send event to user space */
wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
}
#endif /* WIRELESS_EXT > 13 */
}
if (le16_to_cpu(status) & 2) /* Too many retries */
ai->stats.tx_aborted_errors++;
if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
ai->stats.tx_heartbeat_errors++;
if (le16_to_cpu(status) & 8) /* Aid fail */
{ }
if (le16_to_cpu(status) & 0x10) /* MAC disabled */
ai->stats.tx_carrier_errors++;
if (le16_to_cpu(status) & 0x20) /* Association lost */
{ }
/* We produce a TXDROP event only for retry or lifetime
* exceeded, because that's the only status that really mean
* that this particular node went away.
* Other errors means that *we* screwed up. - Jean II */
if ((le16_to_cpu(status) & 2) ||
(le16_to_cpu(status) & 4)) {
union iwreq_data wrqu;
char junk[0x18];
/* Faster to skip over useless data than to do
* another bap_setup(). We are at offset 0x6 and
* need to go to 0x18 and read 6 bytes - Jean II */
bap_read(ai, (u16 *) junk, 0x18, BAP0);
/* Copy 802.11 dest address.
* We use the 802.11 header because the frame may
* not be 802.3 or may be mangled...
* In Ad-Hoc mode, it will be the node address.
* In managed mode, it will be most likely the AP addr
* User space will figure out how to convert it to
* whatever it needs (IP address or else).
* - Jean II */
memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
/* Send event to user space */
wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
}
}
......@@ -2019,7 +2283,7 @@ static int airo_set_mac_address(struct net_device *dev, void *p)
readConfigRid(ai, 1);
memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
disable_MAC(ai, 1);
writeConfigRid (ai, 1);
enable_MAC(ai, &rsp, 1);
......@@ -2066,25 +2330,49 @@ void stop_airo_card( struct net_device *dev, int freeres )
disable_interrupts(ai);
free_irq( dev->irq, dev );
takedown_proc_entry( dev, ai );
if (ai->registered) {
if (test_bit(FLAG_REGISTERED, &ai->flags)) {
unregister_netdev( dev );
if (ai->wifidev) {
unregister_netdev(ai->wifidev);
free_netdev(ai->wifidev);
ai->wifidev = 0;
}
ai->registered = 0;
clear_bit(FLAG_REGISTERED, &ai->flags);
}
set_bit(JOB_DIE, &ai->flags);
kill_proc(ai->thr_pid, SIGTERM, 1);
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)
kfree(ai->flash);
if (ai->rssi)
kfree(ai->rssi);
if (ai->APList)
kfree(ai->APList);
if (ai->SSID)
kfree(ai->SSID);
if (freeres) {
/* PCMCIA frees this stuff, so only for PCI and ISA */
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
if (ai->tfm)
......@@ -2104,6 +2392,213 @@ int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
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)
{
struct airo_info *ai = ethdev->priv;
......@@ -2120,9 +2615,7 @@ static void wifi_setup(struct net_device *dev, struct net_device *ethdev)
dev->do_ioctl = &airo_ioctl;
#ifdef WIRELESS_EXT
dev->get_wireless_stats = airo_get_wireless_stats;
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open;
......@@ -2161,7 +2654,24 @@ static struct net_device *init_wifidev(struct airo_info *ai,
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 airo_info *ai;
......@@ -2180,12 +2690,16 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
ai = dev->priv;
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->aux_lock = SPIN_LOCK_UNLOCKED;
sema_init(&ai->sem, 1);
ai->need_commit = 0;
ai->config.len = 0;
ai->pci = pci;
init_waitqueue_head (&ai->thr_wait);
init_completion (&ai->thr_exited);
ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
......@@ -2199,16 +2713,18 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
goto err_out_thr;
/* The Airo-specific entries in the device structure. */
dev->hard_start_xmit = &airo_start_xmit;
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->get_stats = &airo_get_stats;
dev->set_multicast_list = &airo_set_multicast_list;
dev->set_mac_address = &airo_set_mac_address;
dev->do_ioctl = &airo_ioctl;
#ifdef WIRELESS_EXT
dev->get_wireless_stats = airo_get_wireless_stats;
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open;
......@@ -2216,6 +2732,9 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
dev->irq = irq;
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 );
if (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 )
if (!is_pcmcia) {
if (!request_region( dev->base_addr, 64, dev->name )) {
rc = -EBUSY;
printk(KERN_ERR "airo: Couldn't request region\n");
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 ( setup_card( ai, dev->dev_addr ) != SUCCESS ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" );
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;
set_bit(FLAG_FLASHING, &ai->flags);
}
rc = register_netdev(dev);
if (rc)
goto err_out_res;
ai->wifidev = init_wifidev(ai, dev);
if (rc) {
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->registered = 1;
set_bit(FLAG_REGISTERED,&ai->flags);
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 (probe)
if (probe && !test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
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 )
SET_MODULE_OWNER(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:
if (!is_pcmcia)
release_region( dev->base_addr, 64 );
......@@ -2276,59 +2813,50 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
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);
static int waitbusy (struct airo_info *ai) {
int delay = 0;
while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
udelay (10);
if (++delay % 20)
if ((++delay % 20) == 0)
OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
}
return delay < 10000;
}
int reset_airo_card( struct net_device *dev ) {
int reset_airo_card( struct net_device *dev )
{
int i;
struct airo_info *ai = dev->priv;
if (down_interruptible(&ai->sem))
if (reset_mpi_card (dev))
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 ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" );
up(&ai->sem);
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 );
netif_wake_queue(dev);
up(&ai->sem);
return 0;
}
EXPORT_SYMBOL(reset_airo_card);
#if WIRELESS_EXT > 13
static void airo_send_event(struct net_device *dev) {
struct airo_info *ai = dev->priv;
union iwreq_data wrqu;
......@@ -2345,7 +2873,6 @@ static void airo_send_event(struct net_device *dev) {
/* Send event to user space */
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
}
#endif
static int airo_thread(void *data) {
struct net_device *dev = data;
......@@ -2405,7 +2932,7 @@ static int airo_thread(void *data) {
break;
}
if (test_bit(FLAG_FLASHING, &ai->flags)) {
if (ai->power || test_bit(FLAG_FLASHING, &ai->flags)) {
up(&ai->sem);
continue;
}
......@@ -2424,10 +2951,8 @@ static int airo_thread(void *data) {
else if (test_bit(JOB_MIC, &ai->flags))
micinit(ai);
#endif
#if WIRELESS_EXT > 13
else if (test_bit(JOB_EVENT, &ai->flags))
airo_send_event(dev);
#endif
else if (test_bit(JOB_AUTOWEP, &ai->flags))
timer_func(dev);
}
......@@ -2471,9 +2996,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
#endif
}
if ( status & EV_LINK ) {
#if WIRELESS_EXT > 13
union iwreq_data wrqu;
#endif /* WIRELESS_EXT > 13 */
/* The link status has changed, if you want to put a
monitor hook in, do it here. (Remember that
interrupts are still disabled!)
......@@ -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_MULTI, &apriv->flags);
}
#if WIRELESS_EXT > 13
/* Question : is ASSOCIATED the only status
* that is valid ? We want to catch handover
* and reassociations as valid status
......@@ -2554,7 +3076,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
/* Send event to user space */
wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
}
#endif /* WIRELESS_EXT > 13 */
}
/* 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)
u16 tmpbuf[4];
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 );
/* Get the packet length */
......@@ -2672,7 +3199,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
goto exitrx;
}
}
#if WIRELESS_EXT > 15
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
if (apriv->spy_data.spy_number > 0) {
char *sa;
......@@ -2694,33 +3220,6 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
wireless_spy_update(dev, sa, &wstats);
}
#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);
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)
exitrx:
/* 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 len = 0;
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);
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)
netif_wake_queue(apriv->wifidev);
}
} 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" );
}
}
exittx:
if ( status & ~STATUS_INTS & ~IGNORE_INTS )
printk( KERN_WARNING "airo: Got weird status %x\n",
status & ~STATUS_INTS & ~IGNORE_INTS );
......@@ -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?!?
*/
static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
if (test_bit(FLAG_MPI,&ai->flags))
reg <<= 1;
if ( !do8bitIO )
outw( val, ai->dev->base_addr + reg );
else {
......@@ -2804,6 +3325,8 @@ static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
static u16 IN4500( struct airo_info *ai, u16 reg ) {
unsigned short rc;
if (test_bit(FLAG_MPI,&ai->flags))
reg <<= 1;
if ( !do8bitIO )
rc = inw( ai->dev->base_addr + reg );
else {
......@@ -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
* "cheaper" - Jean II */
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;
rc = issuecommand(ai, &cmd, rsp);
up(&ai->sem);
if (!test_bit(FLAG_ENABLED, &ai->flags)) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE;
rc = issuecommand(ai, &cmd, rsp);
if (rc == SUCCESS)
set_bit(FLAG_ENABLED, &ai->flags);
} else
rc = SUCCESS;
if (lock)
up(&ai->sem);
if (rc)
printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n",
__FUNCTION__,rc);
return rc;
}
......@@ -2840,17 +3373,17 @@ static void disable_MAC( struct airo_info *ai, int lock ) {
Cmd cmd;
Resp rsp;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
if (!lock) {
issuecommand(ai, &cmd, &rsp);
if (lock && down_interruptible(&ai->sem))
return;
}
if (down_interruptible(&ai->sem))
return;
issuecommand(ai, &cmd, &rsp);
up(&ai->sem);
if (test_bit(FLAG_ENABLED, &ai->flags)) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
issuecommand(ai, &cmd, &rsp);
clear_bit(FLAG_ENABLED, &ai->flags);
}
if (lock)
up(&ai->sem);
}
static void enable_interrupts( struct airo_info *ai ) {
......@@ -2863,8 +3396,86 @@ static void enable_interrupts( struct airo_info *ai ) {
I don't know how to get rid of right now... */
}
static void disable_interrupts( struct airo_info *ai ) {
OUT4500( ai, EVINTEN, 0 );
static void disable_interrupts( struct airo_info *ai ) {
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)
......@@ -2893,32 +3504,37 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
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 ) {
up(&ai->sem);
return ERROR;
}
disable_MAC( ai, 0);
// Let's figure out if we need to use the AUX port
cmd.cmd = CMD_ENABLEAUX;
if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
up(&ai->sem);
printk(KERN_ERR "airo: Error checking for AUX port\n");
return ERROR;
}
if (!aux_bap || rsp.status & 0xff00) {
ai->bap_read = fast_bap_read;
printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
} else {
ai->bap_read = aux_bap_read;
printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
if (!test_bit(FLAG_MPI,&ai->flags)) {
cmd.cmd = CMD_ENABLEAUX;
if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
up(&ai->sem);
printk(KERN_ERR "airo: Error checking for AUX port\n");
return ERROR;
}
if (!aux_bap || rsp.status & 0xff00) {
ai->bap_read = fast_bap_read;
printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
} else {
ai->bap_read = aux_bap_read;
printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
}
}
up(&ai->sem);
if (ai->config.len == 0) {
tdsRssiRid rssi_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)
status = readConfigRid(ai, 1);
if ( status != SUCCESS ) return ERROR;
......@@ -2926,6 +3542,12 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
status = readCapabilityRid(ai, &cap_rid);
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);
if ( status == SUCCESS ) {
if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
......@@ -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 */
......@@ -2997,8 +3619,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
if ( status != SUCCESS ) return ERROR;
/* Set up the SSID list */
status = writeSsidRid(ai, &mySsid);
if ( status != SUCCESS ) return ERROR;
if ( ssids[0] ) {
status = writeSsidRid(ai, &mySsid);
if ( status != SUCCESS ) return ERROR;
}
status = enable_MAC(ai, &rsp, 1);
if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
......@@ -3029,6 +3653,9 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
int max_tries = 600000;
u16 cmd;
if (IN4500(ai, EVSTAT) & EV_CMD)
OUT4500(ai, EVACK, EV_CMD);
OUT4500(ai, PARAM0, pCmd->parm0);
OUT4500(ai, PARAM1, pCmd->parm1);
OUT4500(ai, PARAM2, pCmd->parm2);
......@@ -3058,6 +3685,13 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
pRsp->rsp0 = IN4500(ai, RESP0);
pRsp->rsp1 = IN4500(ai, RESP1);
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
if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
......@@ -3213,29 +3847,54 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
if (down_interruptible(&ai->sem))
return ERROR;
}
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
rc = status;
goto done;
}
if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
rc = ERROR;
goto done;
}
// read the rid length field
bap_read(ai, pBuf, 2, BAP1);
// length for remaining part of rid
len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
if (test_bit(FLAG_MPI,&ai->flags)) {
Cmd cmd;
Resp rsp;
if ( len <= 2 ) {
printk( KERN_ERR
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;
goto done;
}
if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
rc = ERROR;
goto done;
}
// read the rid length field
bap_read(ai, pBuf, 2, BAP1);
// length for remaining part of rid
len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
if ( len <= 2 ) {
printk( KERN_ERR
"airo: Rid %x has a length of %d which is too short\n",
(int)rid,
(int)len );
rc = ERROR;
goto done;
(int)rid, (int)len );
rc = ERROR;
goto done;
}
// read remainder of the rid
rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
}
// read remainder of the rid
rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
done:
if (lock)
up(&ai->sem);
......@@ -3256,20 +3915,60 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
if (down_interruptible(&ai->sem))
return ERROR;
}
// --- first access so that we can write the rid data
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
rc = status;
goto done;
}
// --- now write the rid data
if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
rc = ERROR;
goto done;
}
bap_write(ai, pBuf, len, BAP1);
// ---now commit the rid data
rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
done:
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
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
rc = status;
goto done;
}
// --- now write the rid data
if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
rc = ERROR;
goto done;
}
bap_write(ai, pBuf, len, BAP1);
// ---now commit the rid data
rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
}
done:
if (lock)
up(&ai->sem);
return rc;
......@@ -3791,7 +4490,7 @@ static int proc_stats_rid_open( struct inode *inode,
struct airo_info *apriv = dev->priv;
StatsRid stats;
int i, j;
int *vals = stats.vals;
u32 *vals = stats.vals;
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
......@@ -3813,7 +4512,7 @@ static int proc_stats_rid_open( struct inode *inode,
"airo: Potentially disasterous buffer overflow averted!\n");
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){
printk(KERN_WARNING
......@@ -3851,7 +4550,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
if ( !data->writelen ) return;
readConfigRid(ai, 1);
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
line = data->wbuffer;
while( line[0] ) {
......@@ -3859,7 +4558,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
if ( !strncmp( line, "Mode: ", 6 ) ) {
line += 6;
if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
ai->need_commit = 2;
set_bit (FLAG_RESET, &ai->flags);
ai->config.rmode &= 0xfe00;
clear_bit (FLAG_802_11, &ai->flags);
ai->config.opmode &= 0xFF00;
......@@ -3879,7 +4578,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
} else if ( line[0] == 'l' )
ai->config.rmode |= RXMODE_LANMON;
}
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
}
/*** Radio status */
......@@ -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++ ) {
ai->config.nodeName[j] = line[j];
}
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
}
/*** PowerMode processing */
......@@ -3909,13 +4608,13 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
line += 11;
if ( !strncmp( line, "PSPCAM", 6 ) ) {
ai->config.powerSaveMode = POWERSAVE_PSPCAM;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "PSP", 3 ) ) {
ai->config.powerSaveMode = POWERSAVE_PSP;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else {
ai->config.powerSaveMode = POWERSAVE_CAM;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
}
} else if ( !strncmp( line, "DataRates: ", 11 ) ) {
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 ) {
line += i + 1;
i = 0;
}
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "Channel: ", 9 ) ) {
int v, i = 0;
line += 9;
v = get_dec_u16(line, &i, i+3);
if ( v != -1 ) {
ai->config.channelSet = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
}
} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
int v, i = 0;
......@@ -3942,7 +4641,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, i+3);
if ( v != -1 ) {
ai->config.txPower = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
}
} else if ( !strncmp( line, "WEP: ", 5 ) ) {
line += 5;
......@@ -3957,7 +4656,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
ai->config.authType = (u16)AUTH_OPEN;
break;
}
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
int v, i = 0;
......@@ -3965,7 +4664,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 3);
v = (v<0) ? 0 : ((v>255) ? 255 : v);
ai->config.longRetryLimit = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
int v, i = 0;
......@@ -3973,7 +4672,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 3);
v = (v<0) ? 0 : ((v>255) ? 255 : v);
ai->config.shortRetryLimit = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
int v, i = 0;
......@@ -3981,7 +4680,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 4);
v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
ai->config.rtsThres = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
int v, i = 0;
......@@ -3989,7 +4688,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 5);
v = (v<0) ? 0 : v;
ai->config.txLifetime = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
int v, i = 0;
......@@ -3997,17 +4696,17 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
v = get_dec_u16(line, &i, 5);
v = (v<0) ? 0 : v;
ai->config.rxLifetime = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
ai->config.txDiversity =
(line[13]=='l') ? 1 :
((line[13]=='r')? 2: 3);
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
ai->config.rxDiversity =
(line[13]=='l') ? 1 :
((line[13]=='r')? 2: 3);
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
int v, i = 0;
......@@ -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 & 0xfffe; /* Make sure its even */
ai->config.fragThresh = (u16)v;
ai->need_commit = 1;
set_bit (FLAG_COMMIT, &ai->flags);
} else if (!strncmp(line, "Modulation: ", 12)) {
line += 12;
switch(*line) {
case 'd': ai->config.modulation=MOD_DEFAULT; ai->need_commit=1; break;
case 'c': ai->config.modulation=MOD_CCK; ai->need_commit=1; break;
case 'm': ai->config.modulation=MOD_MOK; 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; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
default:
printk( KERN_WARNING "airo: Unknown modulation\n" );
}
} else if (!strncmp(line, "Preamble: ", 10)) {
line += 10;
switch(*line) {
case 'a': ai->config.preamble=PREAMBLE_AUTO; ai->need_commit=1; break;
case 'l': ai->config.preamble=PREAMBLE_LONG; ai->need_commit=1; break;
case 's': ai->config.preamble=PREAMBLE_SHORT; 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; set_bit(FLAG_COMMIT, &ai->flags); break;
case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
default: printk(KERN_WARNING "airo: Unknown preamble\n");
}
} else {
......@@ -4255,6 +4954,7 @@ static int set_wep_key(struct airo_info *ai, u16 index,
const char *key, u16 keylen, int perm, int lock ) {
static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
WepKeyRid wkr;
Resp rsp;
memset(&wkr, 0, sizeof(wkr));
if (keylen == 0) {
......@@ -4274,7 +4974,9 @@ static int set_wep_key(struct airo_info *ai, u16 index,
printk(KERN_INFO "Setting key %d\n", index);
}
disable_MAC(ai, lock);
writeWepKeyRid(ai, &wkr, perm, lock);
enable_MAC(ai, &rsp, lock);
return 0;
}
......@@ -4490,6 +5192,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
Cmd cmd;
Resp rsp;
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem))
......@@ -4577,7 +5280,7 @@ static void timer_func( struct net_device *dev ) {
default: /* We'll escalate to SHAREDKEY */
apriv->config.authType = AUTH_SHAREDKEY;
}
apriv->need_commit = 1;
set_bit (FLAG_COMMIT, &apriv->flags);
writeConfigRid(apriv, 0);
enable_MAC(apriv, &rsp, 0);
up(&apriv->sem);
......@@ -4617,7 +5320,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
return -ENODEV;
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)
return -ENODEV;
......@@ -4627,7 +5333,89 @@ static int __devinit airo_pci_probe(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
......@@ -4667,11 +5455,10 @@ static void __exit airo_cleanup_module( void )
printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
stop_airo_card( airo_devices->dev, 1 );
}
remove_proc_entry("aironet", proc_root_driver);
#ifdef CONFIG_PCI
pci_unregister_driver(&airo_driver);
#endif
remove_proc_entry("aironet", proc_root_driver);
}
#ifdef WIRELESS_EXT
......@@ -4736,7 +5523,7 @@ static int airo_set_freq(struct net_device *dev,
readConfigRid(local, 1);
/* Yes ! We can set it !!! */
local->config.channelSet = (u16)(channel - 1);
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
}
}
return rc;
......@@ -4811,8 +5598,8 @@ static int airo_set_essid(struct net_device *dev,
sizeof(SSID_rid.ssids[index].ssid));
memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
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 */
disable_MAC(local, 1);
writeSsidRid(local, &SSID_rid);
......@@ -4924,7 +5711,7 @@ static int airo_set_nick(struct net_device *dev,
readConfigRid(local, 1);
memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
memcpy(local->config.nodeName, extra, dwrq->length);
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
......@@ -5013,7 +5800,7 @@ static int airo_set_rate(struct net_device *dev,
memset(local->config.rates, 0, 8);
local->config.rates[0] = brate;
}
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
......@@ -5059,7 +5846,7 @@ static int airo_set_rts(struct net_device *dev,
}
readConfigRid(local, 1);
local->config.rtsThres = rthr;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
......@@ -5103,7 +5890,7 @@ static int airo_set_frag(struct net_device *dev,
fthr &= ~0x1; /* Get an even value - is it really needed ??? */
readConfigRid(local, 1);
local->config.fragThresh = (u16)fthr;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
......@@ -5137,11 +5924,11 @@ static int airo_set_mode(struct net_device *dev,
char *extra)
{
struct airo_info *local = dev->priv;
int commit = 1;
int reset = 0;
readConfigRid(local, 1);
if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
commit = 2;
reset = 1;
switch(*uwrq) {
case IW_MODE_ADHOC:
......@@ -5183,7 +5970,9 @@ static int airo_set_mode(struct net_device *dev,
default:
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 */
}
......@@ -5253,7 +6042,7 @@ static int airo_set_encode(struct net_device *dev,
return -EINVAL;
}
/* 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;
/* Set the length */
if (dwrq->length > MIN_KEY_SIZE)
......@@ -5279,12 +6068,12 @@ static int airo_set_encode(struct net_device *dev,
if((index == current_index) && (key.len > 0) &&
(local->config.authType == AUTH_OPEN)) {
local->config.authType = AUTH_ENCRYPT;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
}
} else {
/* Do we want to just set the transmit key index ? */
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);
} else
/* Don't complain if only change the mode */
......@@ -5301,7 +6090,7 @@ static int airo_set_encode(struct net_device *dev,
local->config.authType = AUTH_ENCRYPT; // Only Wep
/* Commit the changes to flags if needed */
if(dwrq->flags & IW_ENCODE_MODE)
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
......@@ -5342,7 +6131,7 @@ static int airo_get_encode(struct net_device *dev,
memset(extra, 0, 16);
/* 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);
dwrq->flags |= index + 1;
/* Copy the key to the user buffer */
......@@ -5370,8 +6159,7 @@ static int airo_set_txpow(struct net_device *dev,
readCapabilityRid(local, &cap_rid);
if (vwrq->disabled) {
set_bit (FLAG_RADIO_OFF, &local->flags);
local->need_commit = 1;
set_bit (FLAG_RADIO_OFF | FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
if (vwrq->flags != IW_TXPOW_MWATT) {
......@@ -5382,7 +6170,7 @@ static int airo_set_txpow(struct net_device *dev,
if ((vwrq->value==cap_rid.txPowerLevels[i])) {
readConfigRid(local, 1);
local->config.txPower = vwrq->value;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
rc = -EINPROGRESS; /* Call commit handler */
break;
}
......@@ -5435,12 +6223,12 @@ static int airo_set_retry(struct net_device *dev,
local->config.longRetryLimit = vwrq->value;
local->config.shortRetryLimit = vwrq->value;
}
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
rc = -EINPROGRESS; /* Call commit handler */
}
if(vwrq->flags & IW_RETRY_LIFETIME) {
local->config.txLifetime = vwrq->value / 1024;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
rc = -EINPROGRESS; /* Call commit handler */
}
return rc;
......@@ -5606,17 +6394,17 @@ static int airo_set_power(struct net_device *dev,
local->config.powerSaveMode = POWERSAVE_CAM;
local->config.rmode &= 0xFF00;
local->config.rmode |= RXMODE_BC_MC_ADDR;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
local->config.fastListenDelay = (vwrq->value + 500) / 1024;
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) {
local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
local->config.powerSaveMode = POWERSAVE_PSPCAM;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
}
switch (vwrq->flags & IW_POWER_MODE) {
case IW_POWER_UNICAST_R:
......@@ -5625,7 +6413,7 @@ static int airo_set_power(struct net_device *dev,
}
local->config.rmode &= 0xFF00;
local->config.rmode |= RXMODE_ADDR;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
break;
case IW_POWER_ALL_R:
if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
......@@ -5633,7 +6421,7 @@ static int airo_set_power(struct net_device *dev,
}
local->config.rmode &= 0xFF00;
local->config.rmode |= RXMODE_BC_MC_ADDR;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
case IW_POWER_ON:
break;
default:
......@@ -5688,7 +6476,7 @@ static int airo_set_sens(struct net_device *dev,
readConfigRid(local, 1);
local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
local->need_commit = 1;
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}
......@@ -5776,7 +6564,6 @@ static int airo_get_aplist(struct net_device *dev,
return 0;
}
#if WIRELESS_EXT > 13
/*------------------------------------------------------------------*/
/*
* Wireless Handler : Initiate Scan
......@@ -5796,6 +6583,7 @@ static int airo_set_scan(struct net_device *dev,
* This is not an error, while the device perform scanning,
* traffic doesn't flow, so it's a perfect DoS...
* Jean II */
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
/* Initiate a scan command */
memset(&cmd, 0, sizeof(cmd));
......@@ -5964,72 +6752,6 @@ static int airo_get_scan(struct net_device *dev,
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,
struct airo_info *local = dev->priv;
Resp rsp;
if (!local->need_commit)
if (!test_bit (FLAG_COMMIT, &local->flags))
return 0;
/* Some of the "SET" function may have modified some of the
* parameters. It's now time to commit them in the card */
disable_MAC(local, 1);
if (local->need_commit > 1) {
if (test_bit (FLAG_RESET, &local->flags)) {
APListRid APList_rid;
SsidRid SSID_rid;
......@@ -6064,7 +6786,7 @@ static int airo_config_commit(struct net_device *dev,
return -ERESTARTSYS;
writeConfigRid(local, 0);
enable_MAC(local, &rsp, 0);
if (local->need_commit > 1)
if (test_bit (FLAG_RESET, &local->flags))
airo_set_promisc(local);
else
up(&local->sem);
......@@ -6085,7 +6807,6 @@ static const struct iw_priv_args airo_private_args[] = {
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
};
#if WIRELESS_EXT > 12
static const iw_handler airo_handler[] =
{
(iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
......@@ -6104,33 +6825,16 @@ static const iw_handler airo_handler[] =
(iw_handler) NULL, /* SIOCGIWPRIV */
(iw_handler) NULL, /* SIOCSIWSTATS */
(iw_handler) NULL, /* SIOCGIWSTATS */
#if WIRELESS_EXT > 15
iw_handler_set_spy, /* SIOCSIWSPY */
iw_handler_get_spy, /* SIOCGIWSPY */
iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
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_get_wap, /* SIOCGIWAP */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
#if WIRELESS_EXT > 13
(iw_handler) airo_set_scan, /* SIOCSIWSCAN */
(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_get_essid, /* SIOCGIWESSID */
(iw_handler) airo_set_nick, /* SIOCSIWNICKN */
......@@ -6173,14 +6877,11 @@ static const struct iw_handler_def airo_handler_def =
.standard = (iw_handler *) airo_handler,
.private = (iw_handler *) airo_private_handler,
.private_args = (struct iw_priv_args *) airo_private_args,
#if WIRELESS_EXT > 15
.spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) -
(void *) NULL),
#endif /* WIRELESS_EXT > 15 */
};
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */
/*
......@@ -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)
{
int rc = 0;
#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
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;
struct airo_info *ai = (struct airo_info *)dev->priv;
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
case SIOCGIWPRIV:
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 */
if (ai->power)
return 0;
switch (cmd) {
#ifdef CISCO_EXT
case AIROIDIFC:
#ifdef AIROOLDIDIFC
......@@ -6530,16 +6953,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
default:
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;
}
......@@ -6561,6 +6974,10 @@ static void airo_read_wireless_stats(struct airo_info *local)
/* Get stats out of the card */
clear_bit(JOB_WSTATS, &local->flags);
if (local->power) {
up(&local->sem);
return;
}
readStatusRid(local, &status_rid, 0);
readStatsRid(local, &stats_rid, RID_STATS, 0);
up(&local->sem);
......@@ -6608,7 +7025,6 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
#endif /* WIRELESS_EXT */
#ifdef CISCO_EXT
#define RIDS_SIZE 2048
/*
* This just translates from driver IOCTL codes to the command codes to
* 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) {
break;
}
if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
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.
* then return it to the user
* 9/22/2000 Honor user given length
......@@ -6672,7 +7088,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
else
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);
return -EFAULT;
}
......@@ -6735,10 +7151,10 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* writerid routines.
*/
case AIROPSTCLR:
if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
return -ENOMEM;
PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1);
PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
#ifdef MICSUPPORT
enabled = ai->micstats.enabled;
......@@ -6747,7 +7163,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
#endif
if (copy_to_user(comp->data, iobuf,
min((int)comp->len, (int)RIDS_SIZE))) {
min((int)comp->len, (int)RIDSIZE))) {
kfree (iobuf);
return -EFAULT;
}
......@@ -6757,10 +7173,10 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
default:
return -EOPNOTSUPP; /* Blarg! */
}
if(comp->len > RIDS_SIZE)
if(comp->len > RIDSIZE)
return -EINVAL;
if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
return -ENOMEM;
if (copy_from_user(iobuf,comp->data,comp->len)) {
......@@ -6990,13 +7406,16 @@ int flashputbuf(struct airo_info *ai){
int nwords;
/* Write stuff */
OUT4500(ai,AUXPAGE,0x100);
OUT4500(ai,AUXOFF,0);
if (test_bit(FLAG_MPI,&ai->flags))
memcpy(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
else {
OUT4500(ai,AUXPAGE,0x100);
OUT4500(ai,AUXOFF,0);
for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
}
}
OUT4500(ai,SWS0,0x8000);
return 0;
......@@ -7013,9 +7432,11 @@ int flashrestart(struct airo_info *ai,struct net_device *dev){
clear_bit (FLAG_FLASHING, &ai->flags);
status = setup_card(ai, dev->dev_addr);
for( i = 0; i < MAX_FIDS; i++ ) {
ai->fids[i] = transmit_allocate( ai, 2312, i >= MAX_FIDS / 2 );
}
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 );
}
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ); /* Added 12/7/00 */
......
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