--- airo.c.orig	2004-05-10 04:32:00.000000000 +0200
+++ airo.c	2004-05-27 19:29:56.209715334 +0200
@@ -861,7 +861,9 @@
 #define AIROGMICRID		11
 #define AIROGMICSTATS		12
 #define AIROGFLAGS		13
+#define AIROGID                 14
 #define AIRORRID		15
+#define AIRORSWVERSION          17
 
 /* Leave gap of 40 commands after AIROGSTATSD32 for future */
 
@@ -892,10 +894,13 @@
 #define AUXMEMSIZE	(256 * 1024)
 
 typedef struct aironet_ioctl {
-	unsigned short command;	// What to do
+	unsigned short command;		// What to do
 	unsigned short len;		// Len of data
+	unsigned short ridnum;		// rid number
 	unsigned char *data;		// d-data
 } aironet_ioctl;
+
+static char *swversion = "2.1";
 #endif /* CISCO_EXT */
 
 #define NUM_MODULES       2
@@ -1097,6 +1102,7 @@
 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 void mpi_receive_802_11(struct airo_info *ai);
 static int waitbusy (struct airo_info *ai);
 
 static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
@@ -2451,17 +2457,19 @@
 	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));
 	}
+        ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
+
+	rc=issuecommand(ai, &cmd, &rsp);
+	if (rc != SUCCESS) {
+		printk(KERN_ERR "airo:  Couldn't allocate TX FID\n");
+		return rc;
+	}
 
 	/* Alloc card Rid descriptor */
 	memset(&rsp,0,sizeof(rsp));
@@ -2653,7 +2661,7 @@
 	return dev;
 }
 
-int reset_mpi_card( struct net_device *dev , int lock) {
+int reset_card( struct net_device *dev , int lock) {
 	struct airo_info *ai = dev->priv;
 
 	if (lock && down_interruptible(&ai->sem))
@@ -2737,9 +2745,6 @@
 		SET_NETDEV_DEV(dev, &pci->dev);
 	}
 
-	if (test_bit(FLAG_MPI,&ai->flags))
-		reset_mpi_card (dev, 1);
-
 	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 );
@@ -2776,8 +2781,7 @@
 		printk(KERN_ERR "airo: Couldn't register_netdev\n");
 		goto err_out_map;
 	}
-	if (!test_bit(FLAG_MPI,&ai->flags))
-		ai->wifidev = init_wifidev(ai, dev);
+        ai->wifidev = init_wifidev(ai, dev);
 
 	set_bit(FLAG_REGISTERED,&ai->flags);
 	printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
@@ -2840,9 +2844,13 @@
 	int i;
 	struct airo_info *ai = dev->priv;
 
-	if (reset_mpi_card (dev, 1))
+	if (reset_card (dev, 1))
 		return -1;
 
+        if (test_bit(FLAG_MPI, &ai->flags))
+                if (mpi_init_descriptors(ai) != SUCCESS)
+                        return -1;
+
 	if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
 		printk( KERN_ERR "airo: MAC could not be enabled\n" );
 		return -1;
@@ -3101,7 +3109,10 @@
 			u16 *buffer;
 
 			if (test_bit(FLAG_MPI,&apriv->flags)) {
-				mpi_receive_802_3(apriv);
+                                if test_bit(FLAG_802_11, &apriv->flags)
+                                        mpi_receive_802_11(apriv);
+                                else
+                                        mpi_receive_802_3(apriv);
 				OUT4500(apriv, EVACK, EV_RX);
 				goto exitrx;
 			}
@@ -3483,6 +3494,112 @@
 	}
 }
 
+void mpi_receive_802_11 (struct airo_info *ai)
+{
+        RxFid rxd;
+        struct sk_buff *skb = NULL;
+        u16 fc, len, hdrlen = 0;
+#pragma pack(1)
+        struct {
+                u16 status, len;
+                u8 rssi[2];
+                u8 rate;
+                u8 freq;
+                u16 tmp[4];
+        } hdr;
+#pragma pack()
+        u16 gap;
+        u16 *buffer;
+        char *ptr = ai->rxfids[0].virtual_host_addr+4;
+
+        memcpy ((char *)&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
+        memcpy ((char *)&hdr, ptr, sizeof(hdr));
+        ptr += sizeof(hdr);
+        /* Bad CRC. Ignore packet */
+        if (le16_to_cpu(hdr.status) & 2)
+                hdr.len = 0;
+        if (ai->wifidev == NULL)
+                hdr.len = 0;
+        len = le16_to_cpu(hdr.len);
+        if (len > 2312) {
+                printk( KERN_ERR "airo: Bad size %d\n", len );
+                goto badrx;
+        }
+        if (len == 0) 
+                goto badrx;
+
+        memcpy ((char *)&fc, ptr, sizeof(fc));
+        fc = le16_to_cpu(fc);
+        switch (fc & 0xc) {
+                case 4:
+                        if ((fc & 0xe0) == 0xc0)
+                                hdrlen = 10;
+                        else
+                                hdrlen = 16;
+                        break;
+                case 8:
+                        if ((fc&0x300)==0x300){
+                                hdrlen = 30;
+                                break;
+                        }
+                default:
+                        hdrlen = 24;
+        }
+
+        skb = dev_alloc_skb( len + hdrlen + 2 );
+        if ( !skb ) {
+                ai->stats.rx_dropped++;
+                goto badrx;
+        }
+        buffer = (u16*)skb_put (skb, len + hdrlen); 
+        memcpy ((char *)buffer, ptr, hdrlen);
+        ptr += hdrlen;
+        if (hdrlen == 24)
+                ptr += 6;
+        memcpy ((char *)&gap, ptr, sizeof(gap));
+        ptr += sizeof(gap);
+        gap = le16_to_cpu(gap);
+        if (gap) {
+                if (gap <= 8)
+                        ptr += gap;
+                else
+                        printk(KERN_ERR 
+                            "airo: gaplen too big. Problems will follow...\n");
+        }
+        memcpy ((char *)buffer + hdrlen, ptr, len);
+        ptr += len;
+#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 = (char*)buffer + 10;
+                wstats.qual = hdr.rssi[0];
+                if (ai->rssi)
+                        wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
+                else
+                        wstats.level = (hdr.rssi[1] + 321) / 2;
+                wstats.updated = 3;
+                /* Update spy records */
+                wireless_spy_update(ai->dev, sa, &wstats);
+        }
+#endif /* IW_WIRELESS_SPY */
+        skb->mac.raw = skb->data;
+        skb->pkt_type = PACKET_OTHERHOST;
+        skb->dev = ai->wifidev;
+        skb->protocol = htons(ETH_P_802_2);
+        skb->dev->last_rx = jiffies;
+        skb->ip_summed = CHECKSUM_NONE;
+        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, int lock)
 {
 	Cmd cmd;
@@ -3550,10 +3667,16 @@
 		status = readCapabilityRid(ai, &cap_rid, lock);
 		if ( status != SUCCESS ) return ERROR;
 
+                /*
+                 * This driver supports MPI350 firmwares up to, and
+                 * including 5.30.17
+                 */
 		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"))
+		    strncmp (cap_rid.prodVer, "5.00.", 5) &&
+		    strncmp (cap_rid.prodVer, "5b00.", 5) &&
+		    strncmp (cap_rid.prodVer, "5.02.", 5) &&
+		    strncmp (cap_rid.prodVer, "5.20.", 5) &&
+		    strncmp (cap_rid.prodVer, "5.30.", 5))
 			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),lock);
@@ -3934,7 +4057,7 @@
 		memset(&rsp, 0, sizeof(rsp));
 
 		ai->config_desc.rid_desc.valid = 1;
-		ai->config_desc.rid_desc.len = RIDSIZE;
+		ai->config_desc.rid_desc.len = *((u16 *)pBuf);
 		ai->config_desc.rid_desc.rid = 0;
 
 		cmd.cmd = CMD_WRITERID;
@@ -5378,7 +5501,6 @@
 	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);
 
@@ -5386,13 +5508,6 @@
 		return 0;
 
 	if (ai->power > 1) {
-		err = reset_mpi_card(dev, 0);
-		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, 0);
 		clear_bit(FLAG_RADIO_OFF, &ai->flags);
@@ -6786,7 +6901,10 @@
 
 		readAPListRid(local, &APList_rid);
 		readSsidRid(local, &SSID_rid);
-		reset_airo_card(dev);
+                if (test_bit (FLAG_MPI, &local->flags))
+                    setup_card(local, dev->dev_addr, 1 );
+                else
+                    reset_airo_card(dev);
 		disable_MAC(local, 1);
 		writeSsidRid(local, &SSID_rid, 1);
 		writeAPListRid(local, &APList_rid, 1);
@@ -6946,9 +7064,17 @@
 
 		/* Separate R/W functions bracket legality here
 		 */
-		if ( com.command <= AIRORRID )
+                if ( com.command == AIRORSWVERSION ) {
+                        if (copy_to_user(com.data, swversion, sizeof(swversion)))
+                                rc = -EFAULT;
+                        else
+                                rc = 0;
+                }
+		else if ( com.command == AIRORRID || com.command == AIROGID )
 			rc = readrids(dev,&com);
-		else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
+                else if ( com.command <= AIROGMICSTATS)
+                        rc = readrids(dev,&com);
+		else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) )
 			rc = writerids(dev,&com);
 		else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
 			rc = flashcard(dev,&com);
@@ -7045,6 +7171,7 @@
 	unsigned char *iobuf;
 	int len;
 	struct airo_info *ai = dev->priv;
+        Resp rsp;
 
 	if (test_bit(FLAG_FLASHING, &ai->flags))
 		return -EIO;
@@ -7052,8 +7179,11 @@
 	switch(comp->command)
 	{
 	case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-	case AIROGCFG: writeConfigRid (ai, 1);
-			    ridcode = RID_CONFIG;       break;
+	case AIROGCFG:      ridcode = RID_CONFIG;
+                disable_MAC (ai, 1);
+                writeConfigRid (ai, 1);
+                enable_MAC (ai, &rsp, 1);
+                break;
 	case AIROGSLIST:    ridcode = RID_SSID;         break;
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
 	case AIROGDRVNAM:   ridcode = RID_DRVNAME;      break;
@@ -7078,7 +7208,7 @@
 			return -EFAULT;
 		return 0;
 #endif
-	case AIRORRID:      ridcode = comp->len;        break;
+	case AIRORRID:      ridcode = comp->ridnum;     break;
 	default:
 		return -EINVAL;
 		break;
@@ -7092,10 +7222,7 @@
 	 * then return it to the user
 	 * 9/22/2000 Honor user given length
 	 */
-	if (comp->command == AIRORRID)
-		len = le16_to_cpu(*(unsigned short *)iobuf); /* Yuck! */
-	else
-		len = comp->len;
+	len = comp->len;
 
 	if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
 		kfree (iobuf);
@@ -7141,6 +7268,8 @@
 	case AIROPLEAPPWD:  ridcode = RID_LEAPPASSWORD; break;
 	case AIROPWEPKEY:   ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
 		break;
+        case AIROPLEAPUSR+1: ridcode = 0xFF2A;          break;
+        case AIROPLEAPUSR+2: ridcode = 0xFF2B;          break;
 
 		/* this is not really a rid but a command given to the card
 		 * same with MAC off
@@ -7442,6 +7571,11 @@
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ);          /* Added 12/7/00 */
 	clear_bit (FLAG_FLASHING, &ai->flags);
+        if (test_bit(FLAG_MPI, &ai->flags)) {
+                status = mpi_init_descriptors(ai);
+                if (status != SUCCESS)
+                        return STATUS;
+        }
 	status = setup_card(ai, dev->dev_addr, 1);
 
 	if (!test_bit(FLAG_MPI,&ai->flags))
