Merge branch 'atmel'
authorJeff Garzik <jgarzik@pobox.com>
Fri, 11 Nov 2005 13:14:56 +0000 (08:14 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Fri, 11 Nov 2005 13:14:56 +0000 (08:14 -0500)
1  2 
drivers/net/wireless/atmel.c
drivers/net/wireless/atmel_cs.c

@@@ -72,7 -72,7 +72,7 @@@
  #include "atmel.h"
  
  #define DRIVER_MAJOR 0
- #define DRIVER_MINOR 96
+ #define DRIVER_MINOR 98
  
  MODULE_AUTHOR("Simon Kelley");
  MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
@@@ -618,12 -618,12 +618,12 @@@ static int atmel_lock_mac(struct atmel_
  static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
  static void atmel_command_irq(struct atmel_private *priv);
  static int atmel_validate_channel(struct atmel_private *priv, int channel);
 -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, 
 +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, 
                                   u16 frame_len, u8 rssi);
  static void atmel_management_timer(u_long a);
  static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size);
  static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size);
 -static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
 +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
                                            u8 *body, int body_len);
  
  static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@@ -827,7 -827,7 +827,7 @@@ static void tx_update_descriptor(struc
  static int start_tx (struct sk_buff *skb, struct net_device *dev)
  {
        struct atmel_private *priv = netdev_priv(dev);
 -      struct ieee80211_hdr header;
 +      struct ieee80211_hdr_4addr header;
        unsigned long flags;
        u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
        u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
  }
  
  static void atmel_transmit_management_frame(struct atmel_private *priv, 
 -                                          struct ieee80211_hdr *header,
 +                                          struct ieee80211_hdr_4addr *header,
                                            u8 *body, int body_len)
  {
        u16 buff;
        tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
  }
        
 -static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, 
 +static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, 
                         u16 msdu_size, u16 rx_packet_loc, u32 crc)
  {
        /* fast path: unfragmented packet copy directly into skbuf */
@@@ -990,7 -990,7 +990,7 @@@ static int probe_crc(struct atmel_priva
        return (crc ^ 0xffffffff) == netcrc;
  }
  
 -static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, 
 +static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, 
                         u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags)
  {
        u8 mac4[6]; 
  static void rx_done_irq(struct atmel_private *priv)
  {
        int i;
 -      struct ieee80211_hdr header;
 +      struct ieee80211_hdr_4addr header;
        
        for (i = 0; 
             atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@@ -1504,7 -1504,7 +1504,7 @@@ static int atmel_read_proc(char *page, 
          return len;
  }
  
- struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWType fw_type,  
+ struct net_device *init_atmel_card( unsigned short irq, unsigned long port, const AtmelFWType fw_type,  
                                    struct device *sys_dev, int (*card_present)(void *), void *card)
  {
        struct net_device *dev;
                goto err_out_free;
        }
  
-       if (priv->bus_type == BUS_TYPE_PCI &&
-           !request_region( dev->base_addr, 64, dev->name )) {
+       if (!request_region(dev->base_addr, 32, 
+                           priv->bus_type == BUS_TYPE_PCCARD ?  "atmel_cs" : "atmel_pci")) {
                goto err_out_irq;
        }
        
        
        create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);        
        
-       printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n",
-              dev->name, DRIVER_MAJOR, DRIVER_MINOR);
+       printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+              dev->name, DRIVER_MAJOR, DRIVER_MINOR,
+              dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+              dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
        
        SET_MODULE_OWNER(dev);
        return dev;
        
   err_out_res:
-       if (priv->bus_type == BUS_TYPE_PCI)
-               release_region( dev->base_addr, 64 );
+       release_region( dev->base_addr, 32);
   err_out_irq:
        free_irq(dev->irq, dev);
   err_out_free:
  
  EXPORT_SYMBOL(init_atmel_card);
  
- void stop_atmel_card(struct net_device *dev, int freeres)
+ void stop_atmel_card(struct net_device *dev)
  {
        struct atmel_private *priv = netdev_priv(dev);
                
        unregister_netdev(dev);
        remove_proc_entry("driver/atmel", NULL);
        free_irq(dev->irq, dev);
 -      if (priv->firmware)
 -              kfree(priv->firmware);
 +      kfree(priv->firmware);
-       if (freeres) {
-               /* PCMCIA frees this stuff, so only for PCI */
-               release_region(dev->base_addr, 64);
-         }
+       release_region(dev->base_addr, 32);
        free_netdev(dev);
  }
  
@@@ -1810,9 -1809,9 +1808,9 @@@ static int atmel_set_encode(struct net_
        }
        if(dwrq->flags & IW_ENCODE_RESTRICTED)
                priv->exclude_unencrypted = 1;
-       if(dwrq->flags & IW_ENCODE_OPEN)
+               if(dwrq->flags & IW_ENCODE_OPEN) 
                priv->exclude_unencrypted = 0;
-       
+        
        return -EINPROGRESS;            /* Call commit handler */
  }
  
@@@ -1827,11 -1826,12 +1825,12 @@@ static int atmel_get_encode(struct net_
        
        if (!priv->wep_is_on)
                dwrq->flags = IW_ENCODE_DISABLED;
-       else if (priv->exclude_unencrypted)
-               dwrq->flags = IW_ENCODE_RESTRICTED;
-       else
-               dwrq->flags = IW_ENCODE_OPEN;
-               
+       else {
+               if (priv->exclude_unencrypted)
+                       dwrq->flags = IW_ENCODE_RESTRICTED;
+               else
+                       dwrq->flags = IW_ENCODE_OPEN;
+       }
                /* Which key do we want ? -1 -> tx index */
        if (index < 0 || index >= 4)
                index = priv->default_key;
@@@ -2217,7 -2217,7 +2216,7 @@@ static int atmel_get_range(struct net_d
        int k,i,j;
  
        dwrq->length = sizeof(struct iw_range);
 -      memset(range, 0, sizeof(range));
 +      memset(range, 0, sizeof(struct iw_range));
        range->min_nwid = 0x0000;
        range->max_nwid = 0x0000;
        range->num_channels = 0;
@@@ -2449,7 -2449,8 +2448,7 @@@ static int atmel_ioctl(struct net_devic
                        break;
                }
  
 -              if (priv->firmware)
 -                      kfree(priv->firmware);
 +              kfree(priv->firmware);
                
                priv->firmware = new_firmware;
                priv->firmware_length = com.len;
@@@ -2645,10 -2646,10 +2644,10 @@@ static void handle_beacon_probe(struct 
        } 
  }
  
-  
- static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len)
+ static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len)
  {
 -      struct ieee80211_hdr header;
 +      struct ieee80211_hdr_4addr header;
        struct auth_body auth;
        
        header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); 
        memcpy(header.addr2, priv->dev->dev_addr, 6);
        memcpy(header.addr3, priv->CurrentBSSID, 6);
        
-       if (priv->wep_is_on) {
-               auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY); 
+       if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) 
                /* no WEP for authentication frames with TrSeqNo 1 */
-               if (priv->CurrentAuthentTransactionSeqNum != 1)
-                       header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-       } else {
-               auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM);
-       }
+                 header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+       
+       auth.alg = cpu_to_le16(system); 
  
        auth.status = 0;
        auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum);
@@@ -2686,7 -2684,7 +2682,7 @@@ static void send_association_request(st
  {
        u8 *ssid_el_p;
        int bodysize;
 -      struct ieee80211_hdr header;
 +      struct ieee80211_hdr_4addr header;
        struct ass_req_format {
                u16 capability;
                u16 listen_interval; 
        atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
  }
  
 -static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header)
 +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr_4addr *header)
  {
        if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
                return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
@@@ -2786,7 -2784,7 +2782,7 @@@ static int retrieve_bss(struct atmel_pr
  }
  
  
 -static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header,
 +static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
                           u16 capability, u16 beacon_period, u8 channel, u8 rssi, 
                           u8 ssid_len, u8 *ssid, int is_beacon)
  {
@@@ -2834,6 -2832,7 +2830,7 @@@ static void authenticate(struct atmel_p
        struct auth_body *auth = (struct auth_body *)priv->rx_buf;
        u16 status = le16_to_cpu(auth->status);
        u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
+       u16 system = le16_to_cpu(auth->alg);
        
        if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) { 
                /* no WEP */
                                
                if (trans_seq_no == 0x0002 &&
                    auth->el_id == C80211_MGMT_ElementID_ChallengeText) {
-                       send_authentication_request(priv, auth->chall_text, auth->chall_text_len);
+                       send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
                        return;
                }
                
                }
        }                       
        
-       if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) {
-               int bss_index;
-               
-               priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
-               
-               if ((bss_index  = retrieve_bss(priv)) != -1) {
-                       atmel_join_bss(priv, bss_index);
-                       return;
+       if (status == C80211_MGMT_SC_AuthAlgNotSupported) {
+               /* Do opensystem first, then try sharedkey */
+               if (system ==  C80211_MGMT_AAN_OPENSYSTEM) {
+                       priv->CurrentAuthentTransactionSeqNum = 0x001;
+                       send_authentication_request(priv, C80211_MGMT_AAN_SHAREDKEY, NULL, 0);
+               } else if (priv->connect_to_any_BSS) {
+                       int bss_index;
+                       
+                       priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
+                       
+                       if ((bss_index  = retrieve_bss(priv)) != -1) {
+                               atmel_join_bss(priv, bss_index);
+                               return;
+                       }
                }
        }
        
@@@ -3070,7 -3075,7 +3073,7 @@@ static void atmel_smooth_qual(struct at
  }
  
  /* deals with incoming managment frames. */
 -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, 
 +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, 
                      u16 frame_len, u8 rssi)
  {
        u16 subtype;
@@@ -3205,7 -3210,7 +3208,7 @@@ static void atmel_management_timer(u_lo
                  priv->AuthenticationRequestRetryCnt++;
                  priv->CurrentAuthentTransactionSeqNum = 0x0001;
                  mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
-                 send_authentication_request(priv, NULL, 0);
+                 send_authentication_request(priv, C80211_MGMT_AAN_OPENSYSTEM, NULL, 0);
          }
          
          break;
@@@ -3312,7 -3317,7 +3315,7 @@@ static void atmel_command_irq(struct at
                                
                                mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
                                priv->CurrentAuthentTransactionSeqNum = 0x0001;
-                               send_authentication_request(priv, NULL, 0);
+                               send_authentication_request(priv, C80211_MGMT_AAN_SHAREDKEY, NULL, 0);
                        }
                        return;
                }
@@@ -3482,11 -3487,6 +3485,6 @@@ static int probe_atmel_card(struct net_
                        printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
                        memcpy(dev->dev_addr, default_mac, 6);
                }
-               printk(KERN_INFO "%s: MAC address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\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] );
-               
        }
        
        return rc;
@@@ -63,6 -63,7 +63,7 @@@
     be present but disabled -- but it can then be enabled for specific
     modules at load time with a 'pc_debug=#' option to insmod.
  */
  #ifdef PCMCIA_DEBUG
  static int pc_debug = PCMCIA_DEBUG;
  module_param(pc_debug, int, 0);
@@@ -180,11 -181,12 +181,11 @@@ static dev_link_t *atmel_attach(void
        DEBUG(0, "atmel_attach()\n");
  
        /* Initialize the dev_link_t structure */
 -      link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
 +      link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
        if (!link) {
                printk(KERN_ERR "atmel_cs: no memory for new device\n");
                return NULL;
        }
 -      memset(link, 0, sizeof(struct dev_link_t));
        
        /* Interrupt setup */
        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
        link->conf.IntType = INT_MEMORY_AND_IO;
        
        /* Allocate space for private device-specific data */
 -      local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
 +      local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local) {
                printk(KERN_ERR "atmel_cs: no memory for new device\n");
                kfree (link);
                return NULL;
        }
 -      memset(local, 0, sizeof(local_info_t));
        link->priv = local;
        
        /* Register with Card Services */
@@@ -257,7 -260,8 +258,7 @@@ static void atmel_detach(dev_link_t *li
  
        /* Unlink device structure, free pieces */
        *linkp = link->next;
 -      if (link->priv)
 -              kfree(link->priv);
 +      kfree(link->priv);
        kfree(link);
  }
  
@@@ -285,41 -289,6 +286,6 @@@ static int card_present(void *arg
        return 0;
  }
  
- /* list of cards we know about and their firmware requirements.
-    Go either by Manfid or version strings.
-    Cards not in this list will need a firmware parameter to the module
-    in all probability. Note that the SMC 2632 V2 and V3 have the same
-    manfids, so we ignore those and use the version1 strings. */
- static struct { 
-       int manf, card;
-       char *ver1;
-       AtmelFWType firmware;
-       char *name;
- } card_table[] = {
-       { 0, 0, "WLAN/802.11b PC CARD", ATMEL_FW_TYPE_502D, "Actiontec 802CAT1" },  
-       { 0, 0, "ATMEL/AT76C502AR", ATMEL_FW_TYPE_502, "NoName-RFMD" }, 
-       { 0, 0, "ATMEL/AT76C502AR_D", ATMEL_FW_TYPE_502D, "NoName-revD" }, 
-       { 0, 0, "ATMEL/AT76C502AR_E", ATMEL_FW_TYPE_502E, "NoName-revE" },
-       { 0, 0, "ATMEL/AT76C504", ATMEL_FW_TYPE_504, "NoName-504" },
-       { 0, 0, "ATMEL/AT76C504A", ATMEL_FW_TYPE_504A_2958, "NoName-504a-2958" },
-       { 0, 0, "ATMEL/AT76C504_R", ATMEL_FW_TYPE_504_2958, "NoName-504-2958" },
-       { MANFID_3COM, 0x0620, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRWE62092B" }, 
-       { MANFID_3COM, 0x0696, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRSHPW196" }, 
-       { 0, 0, "SMC/2632W-V2", ATMEL_FW_TYPE_502, "SMC 2632W-V2" },
-       { 0, 0, "SMC/2632W", ATMEL_FW_TYPE_502D, "SMC 2632W-V3" },
-       { 0xd601, 0x0007, NULL, ATMEL_FW_TYPE_502, "Sitecom WLAN-011" }, 
-       { 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" }, 
-       { 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" },
-       { 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" },
-       { 0, 0, "IEEE 802.11b/Wireless LAN Card S", ATMEL_FW_TYPE_504_2958, "Siemens Gigaset PC Card II" },
-       { 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" },
-       { 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" },
-       { 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" },
-       { 0, 0, "11WAVE/11WP611AL-E", ATMEL_FW_TYPE_502E, "11WAVE WaveBuddy" },
-       { 0, 0, "LG/LW2100N", ATMEL_FW_TYPE_502E, "LG LW2100N 11Mbps WLAN PCMCIA Card" },
- };
  static void atmel_config(dev_link_t *link)
  {
        client_handle_t handle;
        local_info_t *dev;
        int last_fn, last_ret;
        u_char buf[64];
-       int card_index = -1, done = 0;
-       
+       struct pcmcia_device_id *did;
        handle = link->handle;
        dev = link->priv;
+       did = handle_to_dev(handle).driver_data;
  
        DEBUG(0, "atmel_config(0x%p)\n", link);
        
        tuple.TupleDataMax = sizeof(buf);
        tuple.TupleOffset = 0;
        
-       tuple.DesiredTuple = CISTPL_MANFID;
-       if (pcmcia_get_first_tuple(handle, &tuple) == 0) {
-               int i;
-               cistpl_manfid_t *manfid;
-               CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-               CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-               manfid = &(parse.manfid);
-               for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
-                       if (!card_table[i].ver1 &&
-                           manfid->manf == card_table[i].manf &&
-                           manfid->card == card_table[i].card) {
-                               card_index = i;
-                               done = 1;
-                       }
-               }
-       }
-       tuple.DesiredTuple = CISTPL_VERS_1;
-       if (!done && (pcmcia_get_first_tuple(handle, &tuple) == 0)) {
-               int i, j, k;
-               cistpl_vers_1_t *ver1;
-               CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-               CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-               ver1 = &(parse.version_1);
-               
-               for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
-                       for (j = 0; j < ver1->ns; j++) {
-                               char *p = card_table[i].ver1;
-                               char *q = &ver1->str[ver1->ofs[j]];
-                               if (!p)
-                                       goto mismatch;
-                               for (k = 0; k < j; k++) {
-                                       while ((*p != '\0') && (*p != '/')) p++;
-                                       if (*p == '\0') {
-                                               if (*q != '\0')
-                                                       goto mismatch;
-                                       } else {
-                                               p++;
-                                       }
-                               }
-                               while((*q != '\0') && (*p != '\0') && 
-                                     (*p != '/') && (*p == *q)) p++, q++;
-                               if (((*p != '\0') && *p != '/') || *q != '\0')
-                                       goto mismatch;
-                       }
-                       card_index = i;
-                       break;  /* done */
-                       
-               mismatch:
-                       j = 0; /* dummy stmt to shut up compiler */
-               }
-       }               
        /*
          This reads the card's CONFIG tuple to find its configuration
          registers.
        ((local_info_t*)link->priv)->eth_dev = 
                init_atmel_card(link->irq.AssignedIRQ,
                                link->io.BasePort1,
-                               card_index == -1 ? ATMEL_FW_TYPE_NONE :  card_table[card_index].firmware,
+                               did ? did->driver_info : ATMEL_FW_TYPE_NONE,
                                &handle_to_dev(handle),
                                card_present, 
                                link);
        if (!((local_info_t*)link->priv)->eth_dev) 
-               goto cs_failed;
+                       goto cs_failed;
+       
        
        /*
          At this point, the dev_node_t structure(s) need to be
        strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
        dev->node.major = dev->node.minor = 0;
        link->dev = &dev->node;
-       
-       /* Finally, report what we've done */
-       printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d",
-              dev->node.dev_name,
-              card_index == -1 ? "" :  card_table[card_index].name,
-              card_index == -1 ? "" : " ",
-              link->conf.ConfigIndex,
-              link->conf.Vcc/10, link->conf.Vcc%10);
-       if (link->conf.Vpp1)
-               printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %d", link->irq.AssignedIRQ);
-       if (link->io.NumPorts1)
-               printk(", io 0x%04x-0x%04x", link->io.BasePort1,
-                      link->io.BasePort1+link->io.NumPorts1-1);
-       if (link->io.NumPorts2)
-               printk(" & 0x%04x-0x%04x", link->io.BasePort2,
-                      link->io.BasePort2+link->io.NumPorts2-1);
-       printk("\n");
-       
+                       
        link->state &= ~DEV_CONFIG_PENDING;
        return;
        
@@@ -569,7 -468,7 +465,7 @@@ static void atmel_release(dev_link_t *l
        link->dev = NULL;
        
        if (dev) 
-               stop_atmel_card(dev, 0);
+               stop_atmel_card(dev);
        ((local_info_t*)link->priv)->eth_dev = NULL; 
        
        /* Don't bother checking to see if these succeed or not */
@@@ -637,25 -536,47 +533,47 @@@ static int atmel_event(event_t event, i
  } /* atmel_event */
  
  /*====================================================================*/
+ /* We use the driver_info field to store the correct firmware type for a card. */
+ #define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+         .driver_info = (kernel_ulong_t)(info), }
+ #define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+         .driver_info = (kernel_ulong_t)(info), }
  static struct pcmcia_device_id atmel_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
-       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
-       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
-       PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
-       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
-       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
-       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
-       PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
-       PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
-       PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
-       PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
-       PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
-       PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
+       PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
+       PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
+       PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
+       PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
+       PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
+       PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
        PCMCIA_DEVICE_NULL
  };
  MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
  
  static struct pcmcia_driver atmel_driver = {