--- airo.c.orig	2004-01-06 11:27:19.000000000 +0100
+++ airo.c	2004-01-06 12:21:10.677186556 +0100
@@ -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,18 +53,24 @@
 	{ 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 */
 
@@ -235,10 +243,10 @@
 
 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 +388,16 @@
 #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 +423,7 @@
 #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 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 +431,9 @@
 #define IGNORE_INTS (~STATUS_INTS)
 #endif
 
+/* RID TYPES */
+#define RID_RW 0x20
+
 /* The RIDs */
 #define RID_CAPABILITIES 0xFF00
 #define RID_APINFO     0xFF01
@@ -615,7 +636,7 @@
 	/*---------- 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 +890,7 @@
 #define AIRORESTART            AIROFLPUTBUF   + 1
 
 #define FLASHSIZE	32768
+#define AUXMEMSIZE	(256 * 1024)
 
 typedef struct aironet_ioctl {
 	unsigned short command;	// What to do
@@ -916,6 +938,110 @@
 	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,
@@ -975,6 +1101,12 @@
 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 mpi_transmit (struct net_device *dev);
+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);
@@ -1005,8 +1137,17 @@
 	/* 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;
+	int mpi350;	// Used to identify a MPI350 card
+	int macstatus;	// Needed to avoid to disable/enable MAC twice
+	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
+	int hw_unavailable;	// card is unavailable due to power management
+	struct sk_buff_head txq;// tx queue used by mpi350 code
 	ConfigRid config;
 	int need_commit;	// Need to set config
 	char keyindex; // Used with auto wep
@@ -1014,6 +1155,7 @@
 	struct proc_dir_entry *proc_entry;
 	struct airo_info *next;
         spinlock_t aux_lock;
+	spinlock_t mpi_lock;
         unsigned long flags;
 #define FLAG_PROMISC	8	/* IFF_PROMISC 0x100 - include/linux/if.h */
 #define FLAG_RADIO_OFF	0	/* User disabling of MAC */
@@ -1071,6 +1213,12 @@
 	mic_module		mod[2];
 	mic_statistics		micstats;
 #endif
+	struct pci_dev          *pci;
+	unsigned char *pcimem;
+	unsigned char *pciaux;
+	unsigned char *shared;
+	dma_addr_t shared_dma;
+	int shared_len;
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -1647,8 +1795,11 @@
 	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;
@@ -1688,7 +1839,10 @@
 	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);
@@ -1765,6 +1919,154 @@
 	return 0;
 }
 
+static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	struct airo_info *priv = dev->priv;
+
+	if (priv->hw_unavailable)
+		return 0;
+
+	priv->xmit.skb = skb;
+	mpi_transmit(dev);
+	return 0;	
+}
+
+static int mpi_transmit (struct net_device *dev) {
+	int npacks;
+	unsigned long flags;
+	struct airo_info *ai = dev->priv;
+	struct sk_buff *skb = ai->xmit.skb;
+
+	if (!skb) {
+		printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__);
+		return 0;
+	}
+	spin_lock_irqsave(&ai->mpi_lock, flags);
+	npacks = skb_queue_len (&ai->txq);
+	
+	if (npacks >= MAXTXQ) {
+		netif_stop_queue (dev);
+		dev_kfree_skb (skb);	/* Throw on floor */
+		goto done;
+	}
+
+	if (npacks >= MAXTXQ - 20) {
+		netif_stop_queue (dev);
+		skb_queue_tail (&ai->txq, skb);
+		goto done;
+	}
+
+	skb_queue_tail (&ai->txq, skb);
+	netif_wake_queue (dev);
+
+	if (test_bit(FLAG_PENDING_XMIT, &ai->flags) == 0) {
+		set_bit(FLAG_PENDING_XMIT, &ai->flags);
+		mpi_send_packet (dev);
+	}
+done:
+	spin_unlock_irqrestore(&ai->mpi_lock,flags);
+	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;
+	int npacks;
+	unsigned char *buffer;
+	s16 len, *payloadLen;
+	struct airo_info *ai = dev->priv;
+	u8 *sendbuf;
+
+	npacks = skb_queue_len (&ai->txq);
+
+	if (!npacks) {
+		clear_bit(FLAG_PENDING_XMIT, &ai->flags);
+		return 0;
+	}
+	
+	/* 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);
+
+	if (in_irq())
+		dev_kfree_skb_irq(skb);
+	else
+		dev_kfree_skb(skb);
+	return 1;
+}
+
 static void get_tx_error(struct airo_info *ai, u32 fid)
 {
 	u16 status;
@@ -2078,6 +2380,16 @@
 	set_bit(JOB_DIE, &ai->flags);
 	kill_proc(ai->thr_pid, SIGTERM, 1);
 	wait_for_completion(&ai->thr_exited);
+
+	/*
+	 * Clean out tx queue
+	 */
+	if (ai->mpi350 && 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)
@@ -2085,6 +2397,16 @@
 	if (freeres) {
 		/* PCMCIA frees this stuff, so only for PCI and ISA */
 	        release_region( dev->base_addr, 64 );
+		if (ai->mpi350) {
+			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, ai->shared_len, 
+				ai->shared, ai->shared_dma);
+		}
         }
 #ifdef MICSUPPORT
 	if (ai->tfm)
@@ -2104,6 +2426,215 @@
 	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_len = 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE;
+	ai->shared = pci_alloc_consistent(pci, ai->shared_len,
+					  &ai->shared_dma);
+	if (!ai->shared) {
+		printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n",
+		       ai->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, ai->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;
@@ -2161,7 +2692,24 @@
 	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;
@@ -2181,11 +2729,22 @@
 	ai = dev->priv;
 	ai->wifidev = 0;
 	ai->registered = 0;
+	if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
+		printk(KERN_DEBUG "airo:  Found an MPI350 card\n");
+		ai->mpi350 = 1;
+	}
+	else
+		ai->mpi350 = 0;
+	ai->macstatus = 0;
         ai->dev = dev;
 	ai->aux_lock = SPIN_LOCK_UNLOCKED;
+	ai->mpi_lock = SPIN_LOCK_UNLOCKED;
+	skb_queue_head_init (&ai->txq);
 	sema_init(&ai->sem, 1);
 	ai->need_commit = 0;
+	ai->hw_unavailable = 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,7 +2758,10 @@
 		goto err_out_thr;
 
 	/* The Airo-specific entries in the device structure. */
-	dev->hard_start_xmit = &airo_start_xmit;
+	if (ai->mpi350)
+		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;
@@ -2216,6 +2778,9 @@
 	dev->irq = irq;
 	dev->base_addr = port;
 
+	if (ai->mpi350)
+		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,25 +2789,36 @@
 	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 (ai->mpi350) {
+		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 (ai->mpi350 == 0) {
 		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_mpi: Couldn't register_netdev\n");
+		goto err_out_map;
+	}
+	if (ai->mpi350 == 0)
+		ai->wifidev = init_wifidev(ai, dev);
 
 	ai->registered = 1;
 	printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
@@ -2251,15 +2827,27 @@
 		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
 
 	/* Allocate the transmit buffers */
-	if (probe)
-		for( i = 0; i < MAX_FIDS; i++ )
-			ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
+	if (probe) {
+		if (ai->mpi350)
+			ai->fids[0] = 0;
+		else
+			for( i = 0; i < MAX_FIDS; i++ )
+				ai->fids[i] = transmit_allocate
+					(ai,2312,i>=MAX_FIDS/2);
+	}
 
 	setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
 	netif_start_queue(dev);
 	SET_MODULE_OWNER(dev);
 	return dev;
 
+err_out_map:
+	if (ai->mpi350 && pci) {
+		pci_free_consistent(pci, ai->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,35 +2864,30 @@
 	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 setup_airo_card( struct net_device *dev ) 
+{
 	int i;
 	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);
 	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",
@@ -2317,15 +2900,24 @@
 			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);
+		if (ai->mpi350)
+			ai->fids[0] = 0;
+		else
+			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;
 }
 
+int reset_airo_card( struct net_device *dev ) {
+	if (reset_mpi_card (dev))
+		return -1;
+	return setup_airo_card (dev);
+}
+
 EXPORT_SYMBOL(reset_airo_card);
 
 #if WIRELESS_EXT > 13
@@ -2442,7 +3034,7 @@
 	u16 savedInterrupts = 0;
 	int handled = 0;
 
-	if (!netif_device_present(dev))
+	if (!netif_device_present(dev) || apriv->hw_unavailable)
 		return IRQ_NONE;
 
 	for (;;) {
@@ -2574,6 +3166,12 @@
 			u16 tmpbuf[4];
 			u16 *buffer;
 
+			if (apriv->mpi350) {
+				mpi_receive_802_3(apriv);
+				OUT4500(apriv, EVACK, EV_RX);
+				goto exitrx;
+			}
+
 			fid = IN4500( apriv, RXFID );
 
 			/* Get the packet length */
@@ -2740,11 +3338,29 @@
 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 (apriv->mpi350) {
+				unsigned long flags;
+
+				spin_lock_irqsave(&apriv->mpi_lock, flags);
+				if (skb_queue_len(&apriv->txq))
+					mpi_send_packet (dev);
+				else {
+					clear_bit(FLAG_PENDING_XMIT,
+						&apriv->flags);
+					netif_wake_queue (dev);
+				}
+				spin_unlock_irqrestore(&apriv->mpi_lock,
+					flags);
+				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 +3383,11 @@
 						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 +3410,8 @@
  *         Why would some one do 8 bit IO in an SMP machine?!?
  */
 static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
+	if (ai->mpi350)
+		reg <<= 1;
 	if ( !do8bitIO )
 		outw( val, ai->dev->base_addr + reg );
 	else {
@@ -2804,6 +3423,8 @@
 static u16 IN4500( struct airo_info *ai, u16 reg ) {
 	unsigned short rc;
 
+	if (ai->mpi350)
+		reg <<= 1;
 	if ( !do8bitIO )
 		rc = inw( ai->dev->base_addr + reg );
 	else {
@@ -2823,16 +3444,27 @@
 	 * instead of this flag, but I don't trust it *within* the
 	 * 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 (test_bit(FLAG_RADIO_OFF, &ai->flags) ||
+	    test_bit(FLAG_RADIO_DOWN, &ai->flags))
+	    return SUCCESS;
+	
+	if (lock && down_interruptible(&ai->sem)) {
 		return -ERESTARTSYS;
-	rc = issuecommand(ai, &cmd, rsp);
-	up(&ai->sem);
+	}
+
+	if (ai->macstatus == 0) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.cmd = MAC_ENABLE;
+		rc = issuecommand(ai, &cmd, rsp);
+		ai->macstatus = 1;
+	} 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 +3472,18 @@
         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 (ai->macstatus == 1) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.cmd = MAC_DISABLE; // disable in case already enabled
+		issuecommand(ai, &cmd, &rsp);
+		ai->macstatus = 0;
+	}
+	if (lock)
+		up(&ai->sem);
 }
 
 static void enable_interrupts( struct airo_info *ai ) {
@@ -2867,6 +3500,35 @@
 	OUT4500( ai, EVINTEN, 0 );
 }
 
+static void mpi_receive_802_3(struct airo_info *ai)
+{
+	RxFid rxd;
+	int len = 0;
+	struct sk_buff *skb;
+
+	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) {
+			skb = dev_alloc_skb(len);
+			memcpy(skb_put(skb,len),
+				ai->rxfids[0].virtual_host_addr, len);
+			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);
+		}
+	}
+	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)
 {
 	Cmd cmd;
@@ -2893,26 +3555,23 @@
 		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 (ai->mpi350 == 0) {
+		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) {
@@ -2997,8 +3656,10 @@
 	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 +3690,9 @@
 	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 +3722,13 @@
 	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,6 +3884,31 @@
 		if (down_interruptible(&ai->sem))
 			return ERROR;
 	}
+	if (ai->mpi350) {
+		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;
+	} 
 	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
                 rc = status;
                 goto done;
@@ -3256,6 +3952,53 @@
 		if (down_interruptible(&ai->sem))
 			return ERROR;
 	}
+	if (ai->mpi350) {
+		Cmd cmd;
+		Resp rsp;
+		int savedInterrupts = 0;
+
+		savedInterrupts = IN4500(ai, EVINTEN );
+		disable_interrupts(ai);
+
+		if (ai->macstatus) 
+			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;
+		}
+		if (savedInterrupts)
+			OUT4500( ai, EVINTEN, savedInterrupts);
+		goto done;
+	}
 	// --- first access so that we can write the rid data
 	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
                 rc = status;
@@ -3791,7 +4534,7 @@
 	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 +4556,7 @@
 			       "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
@@ -4255,6 +4998,7 @@
 		       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 +5018,9 @@
 		printk(KERN_INFO "Setting key %d\n", index);
 	}
 
+	disable_MAC(ai, lock);
 	writeWepKeyRid(ai, &wkr, perm, lock);
+	enable_MAC(ai, &rsp, lock);
 	return 0;
 }
 
@@ -4617,7 +5363,10 @@
 		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 +5376,91 @@
 
 static void __devexit airo_pci_remove(struct pci_dev *pdev)
 {
-	stop_airo_card(pci_get_drvdata(pdev), 1);
+}
+
+static void airo_stop(struct net_device *dev)
+{
+	struct airo_info *ai = dev->priv;
+	Cmd cmd;
+	Resp rsp;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd=CMD_LOSE_SYNC;
+	issuecommand(ai, &cmd, &rsp);
+	disable_MAC(ai, 1);
+}
+static APListRid APList_rid;
+static SsidRid SSID_rid;
+static ConfigRid Config_rid;
+
+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;
+	
+	printk(KERN_DEBUG "%s: airo_mpi entering sleep mode (state=%d)\n",
+	       dev->name, state);
+
+	readAPListRid(ai, &APList_rid);
+	readSsidRid(ai, &SSID_rid);
+	readConfigRid(ai, 1);
+	memcpy (&Config_rid, &ai->config, sizeof(ConfigRid));
+
+	/* No need to save/restore the wep key, as it is stored
+	   in the EEPROM of the card */
+
+	if (ai->macstatus == 1)
+		airo_stop(dev);
+	netif_device_detach(dev);
+	ai->hw_unavailable++;
+	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 macstatus;
+	int err;
+
+	printk(KERN_DEBUG "%s: airo_mpi waking up\n", dev->name);
+	err = reset_mpi_card(dev);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d resetting on %s()\n",
+		       dev->name, err, __FUNCTION__);
+		return err;
+	}
+	netif_device_attach(dev);
+	if (ai->hw_unavailable == 1) {
+		ai->config.len = 0;
+
+		schedule_timeout (HZ/2);
+		mpi_init_descriptors(ai);
+		setup_card(ai, dev->dev_addr);
+		macstatus = ai->macstatus;
+		/* Depending on the value of FLAG_RADIO_OFF, MAC may still 
+		   be disabled after setup_card(), we have to handle this 
+		   here. FLAG_RADIO_OFF is is set when the interface is 
+		   closed by the apm scripts before suspend
+		 */
+		if (macstatus)
+			disable_MAC(ai, 1);
+		schedule_timeout (HZ/5);
+		writeSsidRid(ai, &SSID_rid);
+		writeAPListRid(ai, &APList_rid);
+		memcpy (&ai->config, &Config_rid, sizeof(ConfigRid));
+		ai->need_commit = 1;
+		writeConfigRid(ai, 1);
+		if (macstatus)
+			enable_MAC(ai, &rsp, 1);
+		netif_wake_queue(dev);
+		ai->hw_unavailable--;
+		enable_interrupts(ai);
+	} else
+		ai->hw_unavailable--;
+	return 0;
 }
 #endif
 
@@ -4667,11 +5500,10 @@
 		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
@@ -4794,6 +5626,7 @@
 	if(dwrq->flags == 0) {
 		/* Just send an empty SSID list */
 		memset(&SSID_rid, 0, sizeof(SSID_rid));
+		SSID_rid.len = sizeof(SSID_rid);
 	} else {
 		int	index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
@@ -5253,7 +6086,7 @@
 			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)
@@ -5284,7 +6117,7 @@
 	} 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 */
@@ -5342,7 +6175,7 @@
 	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 */
@@ -6199,10 +7032,17 @@
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int rc = 0;
+	struct airo_info *ai;
 #if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
 	struct iwreq *wrq = (struct iwreq *) rq;
 #endif /* WIRELESS_EXT < 13 */
 
+	ai=(struct airo_info *)dev->priv;
+
+	if (ai->hw_unavailable) {
+		return 0;
+	}
+
 	switch (cmd) {
 /* WE 13 and higher will use airo_handler_def */
 #if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
@@ -6519,7 +7359,10 @@
 		else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
 			rc = writerids(dev,&com);
 		else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
-			rc = flashcard(dev,&com);
+			if (ai->mpi350 == 0)
+				rc = flashcard(dev,&com);
+			else
+				rc = -EINVAL;
 		else
 			rc = -EINVAL;      /* Bad command in ioctl */
 	}
@@ -6561,6 +7404,10 @@
 
 	/* Get stats out of the card */
 	clear_bit(JOB_WSTATS, &local->flags);
+	if (local->hw_unavailable) {
+		up(&local->sem);
+		return;
+	}
 	readStatusRid(local, &status_rid, 0);
 	readStatsRid(local, &stats_rid, RID_STATS, 0);
 	up(&local->sem);
@@ -6608,7 +7455,6 @@
 #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 +7505,10 @@
 		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 +7518,7 @@
 	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 +7581,10 @@
 		 * 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 +7593,7 @@
 #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 +7603,10 @@
 	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,14 +7836,18 @@
 	int            nwords;
 
 	/* Write stuff */
-	OUT4500(ai,AUXPAGE,0x100);
-	OUT4500(ai,AUXOFF,0);
+	if (ai->mpi350)
+		memcpy(ai->pciaux + 0x8000, ai->flash, 1024 * 32);
+	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);
+		OUT4500(ai,SWS0,0x8000);
+	}
 
 	return 0;
 }
@@ -7013,9 +7863,13 @@
 	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 (ai->mpi350)
+		ai->fids[0] = 0;
+	else
+		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 */
