vserver 1.9.3
[linux-2.6.git] / drivers / net / wireless / airo.c
index 57ef2ac..041b15b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 
 #include <linux/sched.h>
 #include <linux/ptrace.h>
@@ -101,7 +102,7 @@ static struct pci_driver airo_driver = {
    infront of the label, that statistic will not be included in the list
    of statistics in the /proc filesystem */
 
-#define IGNLABEL(comment) 0
+#define IGNLABEL(comment) NULL
 static char *statsLabels[] = {
        "RxOverrun",
        IGNLABEL("RxPlcpCrcErr"),
@@ -1209,6 +1210,8 @@ struct airo_info {
        SsidRid                 *SSID;
        APListRid               *APList;
 #define        PCI_SHARED_LEN          2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
+       u32                     pci_state[16];
+       char                    proc_name[IFNAMSIZ];
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -1813,7 +1816,8 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
        if (!test_bit (FLAG_COMMIT, &ai->flags))
                return SUCCESS;
 
-       clear_bit (FLAG_COMMIT | FLAG_RESET, &ai->flags);
+       clear_bit (FLAG_COMMIT, &ai->flags);
+       clear_bit (FLAG_RESET, &ai->flags);
        checkThrottle(ai);
        cfgr = ai->config;
 
@@ -1963,7 +1967,7 @@ static int mpi_send_packet (struct net_device *dev)
 
        if ((skb = skb_dequeue(&ai->txq)) == 0) {
                printk (KERN_ERR
-                       "airo_mpi: %s: Dequeue'd zero in send_packet()\n",
+                       "airo: %s: Dequeue'd zero in send_packet()\n",
                        __FUNCTION__);
                return 0;
        }
@@ -1977,9 +1981,6 @@ static int mpi_send_packet (struct net_device *dev)
        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
@@ -2009,6 +2010,7 @@ static int mpi_send_packet (struct net_device *dev)
                        return ERROR;
 
                *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
+               ai->txfids[0].tx_desc.len += sizeof(pMic);
                /* copy data into airo dma buffer */
                memcpy (sendbuf, buffer, sizeof(etherHead));
                buffer += sizeof(etherHead);
@@ -2027,6 +2029,9 @@ static int mpi_send_packet (struct net_device *dev)
                memcpy(sendbuf, buffer, len);
        }
 
+       memcpy((char *)ai->txfids[0].card_ram_off,
+               (char *)&ai->txfids[0].tx_desc, sizeof(TxFid));
+
        OUT4500(ai, EVACK, 8);
 
        dev_kfree_skb_any(skb);
@@ -2181,6 +2186,12 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
        struct airo_info *priv = dev->priv;
        u32 *fids = priv->fids;
 
+       if (test_bit(FLAG_MPI, &priv->flags)) {
+               /* Not implemented yet for MPI350 */
+               netif_stop_queue(dev);
+               return -ENETDOWN;
+       }
+
        if ( skb == NULL ) {
                printk( KERN_ERR "airo:  skb == NULL!!!\n" );
                return 0;
@@ -2246,12 +2257,14 @@ struct net_device_stats *airo_get_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->priv;
 
-       /* Get stats out of the card if available */
-       if (down_trylock(&local->sem) != 0) {
-               set_bit(JOB_STATS, &local->flags);
-               wake_up_interruptible(&local->thr_wait);
-       } else
-               airo_read_stats(local);
+       if (!test_bit(JOB_STATS, &local->flags)) {
+               /* Get stats out of the card if available */
+               if (down_trylock(&local->sem) != 0) {
+                       set_bit(JOB_STATS, &local->flags);
+                       wake_up_interruptible(&local->thr_wait);
+               } else
+                       airo_read_stats(local);
+       }
 
        return &local->stats;
 }
@@ -2337,6 +2350,9 @@ static void del_airo_dev( struct net_device *dev );
 void stop_airo_card( struct net_device *dev, int freeres )
 {
        struct airo_info *ai = dev->priv;
+
+       set_bit(FLAG_RADIO_DOWN, &ai->flags);
+       disable_MAC(ai, 1);
        disable_interrupts(ai);
        free_irq( dev->irq, dev );
        takedown_proc_entry( dev, ai );
@@ -2345,7 +2361,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
                if (ai->wifidev) {
                        unregister_netdev(ai->wifidev);
                        free_netdev(ai->wifidev);
-                       ai->wifidev = 0;
+                       ai->wifidev = NULL;
                }
                clear_bit(FLAG_REGISTERED, &ai->flags);
        }
@@ -2357,7 +2373,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
         * Clean out tx queue
         */
        if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) {
-               struct sk_buff *skb = 0;
+               struct sk_buff *skb = NULL;
                for (;(skb = skb_dequeue(&ai->txq));)
                        dev_kfree_skb(skb);
        }
@@ -2613,10 +2629,10 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
 
 static void wifi_setup(struct net_device *dev)
 {
-       dev->hard_header        = 0;
-       dev->rebuild_header     = 0;
-       dev->hard_header_cache  = 0;
-       dev->header_cache_update= 0;
+       dev->hard_header        = NULL;
+       dev->rebuild_header     = NULL;
+       dev->hard_header_cache  = NULL;
+       dev->header_cache_update= NULL;
 
        dev->hard_header_parse  = wll_header_parse;
        dev->hard_start_xmit = &airo_start_xmit11;
@@ -2697,7 +2713,7 @@ struct net_device *_init_airo_card( unsigned short irq, int port,
        }
 
        ai = dev->priv;
-       ai->wifidev = 0;
+       ai->wifidev = NULL;
        ai->flags = 0;
        if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
                printk(KERN_DEBUG "airo: Found an MPI350 card\n");
@@ -2745,6 +2761,9 @@ struct net_device *_init_airo_card( unsigned short irq, int port,
                SET_NETDEV_DEV(dev, &pci->dev);
        }
 
+       if (test_bit(FLAG_MPI,&ai->flags))
+               reset_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 );
@@ -2824,7 +2843,7 @@ err_out_free:
 
 struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
 {
-       return _init_airo_card ( irq, port, is_pcmcia, 0);
+       return _init_airo_card ( irq, port, is_pcmcia, NULL);
 }
 
 EXPORT_SYMBOL(init_airo_card);
@@ -3158,11 +3177,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                        } else
                                hdrlen = ETH_ALEN * 2;
 
-                       skb = dev_alloc_skb( len + hdrlen + 2 );
+                       skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
                        if ( !skb ) {
                                apriv->stats.rx_dropped++;
                                goto badrx;
                        }
+                       skb_reserve(skb, 2); /* This way the IP header is aligned */
                        buffer = (u16*)skb_put (skb, len + hdrlen);
                        if (test_bit(FLAG_802_11, &apriv->flags)) {
                                buffer[0] = fc;
@@ -3399,13 +3419,8 @@ static void disable_MAC( struct airo_info *ai, int lock ) {
 }
 
 static void enable_interrupts( struct airo_info *ai ) {
-       /* Reset the status register */
-       u16 status = IN4500( ai, EVSTAT );
-       OUT4500( ai, EVACK, status );
        /* Enable the interrupts */
        OUT4500( ai, EVINTEN, STATUS_INTS );
-       /* Note there is a race condition between the last two lines that
-          I don't know how to get rid of right now... */
 }
 
 static void disable_interrupts( struct airo_info *ai ) {
@@ -3453,7 +3468,7 @@ static void mpi_receive_802_3(struct airo_info *ai)
                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)) {
+               if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
 badmic:
                        dev_kfree_skb_irq (skb);
                        goto badrx;
@@ -3663,18 +3678,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
                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) &&
-                   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);
                if ( status == SUCCESS ) {
                        if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
@@ -3709,9 +3712,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 
                /* Check to see if there are any insmod configured
                   rates to add */
-               if ( rates ) {
+               if ( rates[0] ) {
                        int i = 0;
-                       if ( rates[0] ) memset(ai->config.rates,0,sizeof(ai->config.rates));
+                       memset(ai->config.rates,0,sizeof(ai->config.rates));
                        for( i = 0; i < 8 && rates[i]; i++ ) {
                                ai->config.rates[i] = rates[i];
                        }
@@ -3778,7 +3781,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
         // Im really paranoid about letting it run forever!
        int max_tries = 600000;
-       u16 cmd;
 
        if (IN4500(ai, EVSTAT) & EV_CMD)
                OUT4500(ai, EVACK, EV_CMD);
@@ -3787,26 +3789,23 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
        OUT4500(ai, PARAM1, pCmd->parm1);
        OUT4500(ai, PARAM2, pCmd->parm2);
        OUT4500(ai, COMMAND, pCmd->cmd);
-       while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0 &&
-               (cmd = IN4500(ai, COMMAND)) != 0 )
-                       if (cmd == pCmd->cmd)
-                               // PC4500 didn't notice command, try again
-                               OUT4500(ai, COMMAND, pCmd->cmd);
-       if ( max_tries == -1 ) {
-               printk( KERN_ERR
-                       "airo: Max tries exceeded when issueing command\n" );
-                return ERROR;
-       }
 
        while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+               if ((IN4500(ai, COMMAND)) == pCmd->cmd)
+                       // PC4500 didn't notice command, try again
+                       OUT4500(ai, COMMAND, pCmd->cmd);
                if (!in_atomic() && (max_tries & 255) == 0)
                        schedule();
        }
+
        if ( max_tries == -1 ) {
                printk( KERN_ERR
-                       "airo: Max tries exceeded waiting for command\n" );
-                return ERROR;
+                       "airo: Max tries exceeded when issueing command\n" );
+               if (IN4500(ai, COMMAND) & COMMAND_BUSY)
+                       OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
+               return ERROR;
        }
+
        // command completed
        pRsp->status = IN4500(ai, STATUS);
        pRsp->rsp0 = IN4500(ai, RESP0);
@@ -4047,7 +4046,8 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
                Resp rsp;
 
                if (test_bit(FLAG_ENABLED, &ai->flags))
-                       printk(KERN_ERR "%s: MAC should be disabled (rid=%d)\n",
+                       printk(KERN_ERR
+                               "%s: MAC should be disabled (rid=%04x)\n",
                                __FUNCTION__, rid);
                memset(&cmd, 0, sizeof(cmd));
                memset(&rsp, 0, sizeof(rsp));
@@ -4344,7 +4344,7 @@ static struct file_operations proc_wepkey_ops = {
        .release        = proc_close
 };
 
-static struct proc_dir_entry *airo_entry = 0;
+static struct proc_dir_entry *airo_entry;
 
 struct proc_data {
        int release_buffer;
@@ -4364,7 +4364,8 @@ static int setup_proc_entry( struct net_device *dev,
                             struct airo_info *apriv ) {
        struct proc_dir_entry *entry;
        /* First setup the device directory */
-       apriv->proc_entry = create_proc_entry(dev->name,
+       strcpy(apriv->proc_name,dev->name);
+       apriv->proc_entry = create_proc_entry(apriv->proc_name,
                                              S_IFDIR|airo_perm,
                                              airo_entry);
         apriv->proc_entry->uid = proc_uid;
@@ -4465,7 +4466,7 @@ static int takedown_proc_entry( struct net_device *dev,
        remove_proc_entry("APList",apriv->proc_entry);
        remove_proc_entry("BSSList",apriv->proc_entry);
        remove_proc_entry("WepKey",apriv->proc_entry);
-       remove_proc_entry(dev->name,airo_entry);
+       remove_proc_entry(apriv->proc_name,airo_entry);
        return 0;
 }
 
@@ -4527,6 +4528,8 @@ static ssize_t proc_write( struct file *file,
                len = priv->maxwritelen - pos;
        if (copy_from_user(priv->wbuffer + pos, buffer, len))
                return -EFAULT;
+       if ( pos + len > priv->writelen )
+               priv->writelen = len + file->f_pos;
        *offset = pos + len;
        return len;
 }
@@ -5127,7 +5130,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
            (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
                index = data->wbuffer[0] - '0';
                if (data->wbuffer[1] == '\n') {
-                       set_wep_key(ai, index, 0, 0, 1, 1);
+                       set_wep_key(ai, index, NULL, 0, 1, 1);
                        return;
                }
                j = 2;
@@ -5312,8 +5315,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
        }
        data->writelen = 0;
        data->maxwritelen = 0;
-       data->wbuffer = 0;
-       data->on_close = 0;
+       data->wbuffer = NULL;
+       data->on_close = NULL;
 
        if (file->f_mode & FMODE_WRITE) {
                if (!(file->f_mode & FMODE_READ)) {
@@ -5374,7 +5377,7 @@ static int proc_close( struct inode *inode, struct file *file )
 static struct net_device_list {
        struct net_device *dev;
        struct net_device_list *next;
-} *airo_devices = 0;
+} *airo_devices;
 
 /* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
@@ -5395,13 +5398,13 @@ static void timer_func( struct net_device *dev ) {
                        break;
                case AUTH_SHAREDKEY:
                        if (apriv->keyindex < auto_wep) {
-                               set_wep_key(apriv, apriv->keyindex, 0, 0, 0, 0);
+                               set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
                                apriv->config.authType = AUTH_SHAREDKEY;
                                apriv->keyindex++;
                        } else {
                                /* Drop to ENCRYPT */
                                apriv->keyindex = 0;
-                               set_wep_key(apriv, apriv->defindex, 0, 0, 0, 0);
+                               set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
                                apriv->config.authType = AUTH_ENCRYPT;
                        }
                        break;
@@ -5470,9 +5473,6 @@ static int airo_pci_suspend(struct pci_dev *pdev, u32 state)
        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;
@@ -5490,7 +5490,10 @@ static int airo_pci_suspend(struct pci_dev *pdev, u32 state)
        ai->power = state;
        cmd.cmd=HOSTSLEEP;
        issuecommand(ai, &cmd, &rsp);
-       return 0;
+
+       pci_enable_wake(pdev, state, 1);
+       pci_save_state(pdev, ai->pci_state);
+       return pci_set_power_state(pdev, state);
 }
 
 static int airo_pci_resume(struct pci_dev *pdev)
@@ -5499,16 +5502,15 @@ static int airo_pci_resume(struct pci_dev *pdev)
        struct airo_info *ai = dev->priv;
        Resp rsp;
 
-       printk(KERN_DEBUG "%s: airo_mpi waking up\n", dev->name);
-
-       if (!ai->power)
-               return 0;
+       pci_set_power_state(pdev, 0);
+       pci_restore_state(pdev, ai->pci_state);
+       pci_enable_wake(pdev, ai->power, 0);
 
        if (ai->power > 1) {
+               reset_card(dev, 0);
                mpi_init_descriptors(ai);
                setup_card(ai, dev->dev_addr, 0);
                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);
@@ -5593,6 +5595,30 @@ static void __exit airo_cleanup_module( void )
  * would not work at all... - Jean II
  */
 
+static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
+{
+       int quality = 0;
+
+       if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) {
+               if (memcmp(cap_rid->prodName, "350", 3))
+                       if (status_rid->signalQuality > 0x20)
+                               quality = 0;
+                       else
+                               quality = 0x20 - status_rid->signalQuality;
+               else
+                       if (status_rid->signalQuality > 0xb0)
+                               quality = 0;
+                       else if (status_rid->signalQuality < 0x10)
+                               quality = 0xa0;
+                       else
+                               quality = 0xb0 - status_rid->signalQuality;
+       }
+       return quality;
+}
+
+#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
+#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
+
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : get protocol name
@@ -6195,7 +6221,7 @@ static int airo_set_encode(struct net_device *dev,
                /* 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))) {
-                       set_wep_key(local, index, 0, 0, 1, 1);
+                       set_wep_key(local, index, NULL, 0, 1, 1);
                } else
                        /* Don't complain if only change the mode */
                        if(!dwrq->flags & IW_ENCODE_MODE) {
@@ -6280,7 +6306,8 @@ static int airo_set_txpow(struct net_device *dev,
        readCapabilityRid(local, &cap_rid, 1);
 
        if (vwrq->disabled) {
-               set_bit (FLAG_RADIO_OFF | FLAG_COMMIT, &local->flags);
+               set_bit (FLAG_RADIO_OFF, &local->flags);
+               set_bit (FLAG_COMMIT, &local->flags);
                return -EINPROGRESS;            /* Call commit handler */
        }
        if (vwrq->flags != IW_TXPOW_MWATT) {
@@ -6419,7 +6446,7 @@ static int airo_get_range(struct net_device *dev,
        range->num_frequency = k;
 
        /* Hum... Should put the right values there */
-       range->max_qual.qual = 10;
+       range->max_qual.qual = airo_get_max_quality(&cap_rid);
        range->max_qual.level = 0x100 - 120;    /* -120 dBm */
        range->max_qual.noise = 0;
        range->sensitivity = 65535;
@@ -6486,7 +6513,7 @@ static int airo_get_range(struct net_device *dev,
        /* Experimental measurements - boundary 11/5.5 Mb/s */
        /* Note : with or without the (local->rssi), results
         * are somewhat different. - Jean II */
-       range->avg_qual.qual = 6;
+       range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
        if (local->rssi)
                range->avg_qual.level = 186;    /* -70 dBm */
        else
@@ -7100,6 +7127,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
 {
        StatusRid status_rid;
        StatsRid stats_rid;
+       CapabilityRid cap_rid;
        u32 *vals = stats_rid.vals;
 
        /* Get stats out of the card */
@@ -7108,6 +7136,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
                up(&local->sem);
                return;
        }
+       readCapabilityRid(local, &cap_rid, 0);
        readStatusRid(local, &status_rid, 0);
        readStatsRid(local, &stats_rid, RID_STATS, 0);
        up(&local->sem);
@@ -7116,7 +7145,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
        local->wstats.status = status_rid.mode;
 
        /* Signal quality and co. But where is the noise level ??? */
-       local->wstats.qual.qual = status_rid.signalQuality;
+       local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
        if (local->rssi)
                local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
        else
@@ -7143,12 +7172,14 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->priv;
 
-       /* Get stats out of the card if available */
-       if (down_trylock(&local->sem) != 0) {
-               set_bit(JOB_WSTATS, &local->flags);
-               wake_up_interruptible(&local->thr_wait);
-       } else
-               airo_read_wireless_stats(local);
+       if (!test_bit(JOB_WSTATS, &local->flags)) {
+               /* Get stats out of the card if available */
+               if (down_trylock(&local->sem) != 0) {
+                       set_bit(JOB_WSTATS, &local->flags);
+                       wake_up_interruptible(&local->thr_wait);
+               } else
+                       airo_read_wireless_stats(local);
+       }
 
        return &local->wstats;
 }
@@ -7166,6 +7197,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
        unsigned char *iobuf;
        int len;
        struct airo_info *ai = dev->priv;
+       Resp rsp;
 
        if (test_bit(FLAG_FLASHING, &ai->flags))
                return -EIO;
@@ -7173,8 +7205,13 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
        switch(comp->command)
        {
        case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-       case AIROGCFG: writeConfigRid (ai, 1);
-                           ridcode = RID_CONFIG;       break;
+       case AIROGCFG:      ridcode = RID_CONFIG;
+               if (test_bit(FLAG_COMMIT, &ai->flags)) {
+                       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;
@@ -7253,6 +7290,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
        case AIROPCAP:      ridcode = RID_CAPABILITIES; break;
        case AIROPAPLIST:   ridcode = RID_APLIST;       break;
        case AIROPCFG: ai->config.len = 0;
+                           clear_bit(FLAG_COMMIT, &ai->flags);
                            ridcode = RID_CONFIG;       break;
        case AIROPWEPKEYNV: ridcode = RID_WEP_PERM;     break;
        case AIROPLEAPUSR:  ridcode = RID_LEAPUSERNAME; break;
@@ -7562,6 +7600,11 @@ int flashrestart(struct airo_info *ai,struct net_device *dev){
        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))