iwlwifi: add missing rcu_read_lock
[safe/jmp/linux-2.6] / drivers / net / wireless / zd1201.c
index 662ecc8..390d77f 100644 (file)
 
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
 #include <linux/firmware.h>
-#include <net/ieee80211.h>
 #include "zd1201.h"
 
 static struct usb_device_id zd1201_table[] = {
@@ -49,7 +50,7 @@ MODULE_DEVICE_TABLE(usb, zd1201_table);
 static int zd1201_fw_upload(struct usb_device *dev, int apfw)
 {
        const struct firmware *fw_entry;
-       char *data;
+       const char *data;
        unsigned long len;
        int err;
        unsigned char ret;
@@ -112,14 +113,17 @@ exit:
        return err;
 }
 
-static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
+MODULE_FIRMWARE("zd1201-ap.fw");
+MODULE_FIRMWARE("zd1201.fw");
+
+static void zd1201_usbfree(struct urb *urb)
 {
        struct zd1201 *zd = urb->context;
 
        switch(urb->status) {
                case -EILSEQ:
                case -ENODEV:
-               case -ETIMEDOUT:
+               case -ETIME:
                case -ENOENT:
                case -EPIPE:
                case -EOVERFLOW:
@@ -130,7 +134,6 @@ static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
 
        kfree(urb->transfer_buffer);
        usb_free_urb(urb);
-       return;
 }
 
 /* cmdreq message: 
@@ -177,15 +180,14 @@ static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0,
 }
 
 /* Callback after sending out a packet */
-static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs)
+static void zd1201_usbtx(struct urb *urb)
 {
        struct zd1201 *zd = urb->context;
        netif_wake_queue(zd->dev);
-       return;
 }
 
 /* Incoming data */
-static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
+static void zd1201_usbrx(struct urb *urb)
 {
        struct zd1201 *zd = urb->context;
        int free = 0;
@@ -193,15 +195,13 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
        struct sk_buff *skb;
        unsigned char type;
 
-       if (!zd) {
-               free = 1;
-               goto exit;
-       }
+       if (!zd)
+               return;
 
        switch(urb->status) {
                case -EILSEQ:
                case -ENODEV:
-               case -ETIMEDOUT:
+               case -ETIME:
                case -ENOENT:
                case -EPIPE:
                case -EOVERFLOW:
@@ -329,11 +329,9 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
                        memcpy(skb_put(skb, 6), &data[datalen-8], 6);
                        memcpy(skb_put(skb, 2), &data[datalen-24], 2);
                        memcpy(skb_put(skb, len), data, len);
-                       skb->dev = zd->dev;
-                       skb->dev->last_rx = jiffies;
                        skb->protocol = eth_type_trans(skb, zd->dev);
-                       zd->stats.rx_packets++;
-                       zd->stats.rx_bytes += skb->len;
+                       zd->dev->stats.rx_packets++;
+                       zd->dev->stats.rx_bytes += skb->len;
                        netif_rx(skb);
                        goto resubmit;
                }
@@ -349,7 +347,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
                                frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
                                if (!frag)
                                        goto resubmit;
-                               skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
+                               skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
                                if (!skb) {
                                        kfree(frag);
                                        goto resubmit;
@@ -387,11 +385,9 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
                        memcpy(skb_put(skb, 2), &data[6], 2);
                        memcpy(skb_put(skb, len), data+8, len);
                }
-               skb->dev = zd->dev;
-               skb->dev->last_rx = jiffies;
                skb->protocol = eth_type_trans(skb, zd->dev);
-               zd->stats.rx_packets++;
-               zd->stats.rx_bytes += skb->len;
+               zd->dev->stats.rx_packets++;
+               zd->dev->stats.rx_bytes += skb->len;
                netif_rx(skb);
        }
 resubmit:
@@ -409,7 +405,6 @@ exit:
                wake_up(&zd->rxdataq);
                kfree(urb->transfer_buffer);
        }
-       return;
 }
 
 static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
@@ -749,7 +744,7 @@ static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen)
 
 static int zd1201_net_open(struct net_device *dev)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        /* Start MAC with wildcard if no essid set */
        if (!zd->mac_enabled)
@@ -785,17 +780,18 @@ static int zd1201_net_stop(struct net_device *dev)
                                (llc+snap+type+payload)
                zd              1 null byte, zd1201 packet type
  */
-static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb,
+                                               struct net_device *dev)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        unsigned char *txbuf = zd->txdata;
        int txbuflen, pad = 0, err;
        struct urb *urb = zd->tx_urb;
 
        if (!zd->mac_enabled || zd->monitor) {
-               zd->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        netif_stop_queue(dev);
 
@@ -811,10 +807,10 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        txbuf[4] = 0x00;
        txbuf[5] = 0x00;
 
-       memcpy(txbuf+6, skb->data+12, skb->len-12);
+       skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12);
        if (pad)
                txbuf[skb->len-12+6]=0;
-       memcpy(txbuf+skb->len-12+6+pad, skb->data, 12);
+       skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12);
        *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);
        txbuf[txbuflen-1] = 0;
 
@@ -823,36 +819,35 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);
        if (err) {
-               zd->stats.tx_errors++;
+               dev->stats.tx_errors++;
                netif_start_queue(dev);
-               return err;
+       } else {
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += skb->len;
        }
-       zd->stats.tx_packets++;
-       zd->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
        kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void zd1201_tx_timeout(struct net_device *dev)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        if (!zd)
                return;
        dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
            dev->name);
        usb_unlink_urb(zd->tx_urb);
-       zd->stats.tx_errors++;
+       dev->stats.tx_errors++;
        /* Restart the timeout to quiet the watchdog: */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 static int zd1201_set_mac_address(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        int err;
 
        if (!zd)
@@ -867,43 +862,34 @@ static int zd1201_set_mac_address(struct net_device *dev, void *p)
        return zd1201_mac_reset(zd);
 }
 
-static struct net_device_stats *zd1201_get_stats(struct net_device *dev)
-{
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
-
-       return &zd->stats;
-}
-
 static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        return &zd->iwstats;
 }
 
 static void zd1201_set_multicast(struct net_device *dev)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
-       struct dev_mc_list *mc = dev->mc_list;
+       struct zd1201 *zd = netdev_priv(dev);
+       struct netdev_hw_addr *ha;
        unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
        int i;
 
-       if (dev->mc_count > ZD1201_MAXMULTI)
+       if (netdev_mc_count(dev) > ZD1201_MAXMULTI)
                return;
 
-       for (i=0; i<dev->mc_count; i++) {
-               memcpy(reqbuf+i*ETH_ALEN, mc->dmi_addr, ETH_ALEN);
-               mc = mc->next;
-       }
+       i = 0;
+       netdev_for_each_mc_addr(ha, dev)
+               memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
        zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
-           dev->mc_count*ETH_ALEN, 0);
-       
+                        netdev_mc_count(dev) * ETH_ALEN, 0);
 }
 
 static int zd1201_config_commit(struct net_device *dev, 
     struct iw_request_info *info, struct iw_point *data, char *essid)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        return zd1201_mac_reset(zd);
 }
@@ -918,17 +904,16 @@ static int zd1201_get_name(struct net_device *dev,
 static int zd1201_set_freq(struct net_device *dev,
     struct iw_request_info *info, struct iw_freq *freq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short channel = 0;
        int err;
 
        if (freq->e == 0)
                channel = freq->m;
        else {
-               if (freq->m >= 2482)
-                       channel = 14;
-               if (freq->m >= 2407)
-                       channel = (freq->m-2407)/5;
+               channel = ieee80211_freq_to_dsss_chan(freq->m);
+               if (channel < 0)
+                       channel = 0;
        }
 
        err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
@@ -943,7 +928,7 @@ static int zd1201_set_freq(struct net_device *dev,
 static int zd1201_get_freq(struct net_device *dev,
     struct iw_request_info *info, struct iw_freq *freq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short channel;
        int err;
 
@@ -959,7 +944,7 @@ static int zd1201_get_freq(struct net_device *dev,
 static int zd1201_set_mode(struct net_device *dev,
     struct iw_request_info *info, __u32 *mode, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short porttype, monitor = 0;
        unsigned char buffer[IW_ESSID_MAX_SIZE+2];
        int err;
@@ -1021,7 +1006,7 @@ static int zd1201_set_mode(struct net_device *dev,
 static int zd1201_get_mode(struct net_device *dev,
     struct iw_request_info *info, __u32 *mode, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short porttype;
        int err;
 
@@ -1097,7 +1082,7 @@ static int zd1201_get_range(struct net_device *dev,
 static int zd1201_get_wap(struct net_device *dev,
     struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        unsigned char buffer[6];
 
        if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
@@ -1125,7 +1110,7 @@ static int zd1201_set_scan(struct net_device *dev,
 static int zd1201_get_scan(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *srq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        int err, i, j, enabled_save;
        struct iw_event iwe;
        char *cev = extra;
@@ -1156,32 +1141,36 @@ static int zd1201_get_scan(struct net_device *dev,
                iwe.cmd = SIOCGIWAP;
                iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
                memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_ADDR_LEN);
 
                iwe.cmd = SIOCGIWESSID;
                iwe.u.data.length = zd->rxdata[i+16];
                iwe.u.data.flags = 1;
-               cev = iwe_stream_add_point(cev, end_buf, &iwe, zd->rxdata+i+18);
+               cev = iwe_stream_add_point(info, cev, end_buf,
+                                          &iwe, zd->rxdata+i+18);
 
                iwe.cmd = SIOCGIWMODE;
                if (zd->rxdata[i+14]&0x01)
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_UINT_LEN);
                
                iwe.cmd = SIOCGIWFREQ;
                iwe.u.freq.m = zd->rxdata[i+0];
                iwe.u.freq.e = 0;
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_FREQ_LEN);
                
                iwe.cmd = SIOCGIWRATE;
                iwe.u.bitrate.fixed = 0;
                iwe.u.bitrate.disabled = 0;
                for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
                        iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
-                       cev=iwe_stream_add_event(cev, end_buf, &iwe,
-                           IW_EV_PARAM_LEN);
+                       cev = iwe_stream_add_event(info, cev, end_buf,
+                                                  &iwe, IW_EV_PARAM_LEN);
                }
                
                iwe.cmd = SIOCGIWENCODE;
@@ -1190,14 +1179,15 @@ static int zd1201_get_scan(struct net_device *dev,
                        iwe.u.data.flags = IW_ENCODE_ENABLED;
                else
                        iwe.u.data.flags = IW_ENCODE_DISABLED;
-               cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
+               cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
                
                iwe.cmd = IWEVQUAL;
                iwe.u.qual.qual = zd->rxdata[i+4];
                iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
                iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
                iwe.u.qual.updated = 7;
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_QUAL_LEN);
        }
 
        if (!enabled_save)
@@ -1212,13 +1202,13 @@ static int zd1201_get_scan(struct net_device *dev,
 static int zd1201_set_essid(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *data, char *essid)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        if (data->length > IW_ESSID_MAX_SIZE)
                return -EINVAL;
        if (data->length < 1)
                data->length = 1;
-       zd->essidlen = data->length-1;
+       zd->essidlen = data->length;
        memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
        memcpy(zd->essid, essid, data->length);
        return zd1201_join(zd, zd->essid, zd->essidlen);
@@ -1227,7 +1217,7 @@ static int zd1201_set_essid(struct net_device *dev,
 static int zd1201_get_essid(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *data, char *essid)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        memcpy(essid, zd->essid, zd->essidlen);
        data->flags = 1;
@@ -1248,7 +1238,7 @@ static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info,
 static int zd1201_set_rate(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short rate;
        int err;
 
@@ -1281,7 +1271,7 @@ static int zd1201_set_rate(struct net_device *dev,
 static int zd1201_get_rate(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short rate;
        int err;
 
@@ -1314,7 +1304,7 @@ static int zd1201_get_rate(struct net_device *dev,
 static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *rts, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        int err;
        short val = rts->value;
 
@@ -1334,7 +1324,7 @@ static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
 static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *rts, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short rtst;
        int err;
 
@@ -1351,7 +1341,7 @@ static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
 static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *frag, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        int err;
        short val = frag->value;
 
@@ -1372,7 +1362,7 @@ static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
 static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *frag, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short fragt;
        int err;
 
@@ -1401,7 +1391,7 @@ static int zd1201_get_retry(struct net_device *dev,
 static int zd1201_set_encode(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *erq, char *key)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short i;
        int err, rid;
 
@@ -1458,7 +1448,7 @@ static int zd1201_set_encode(struct net_device *dev,
 static int zd1201_get_encode(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *erq, char *key)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short i;
        int err;
 
@@ -1491,7 +1481,7 @@ static int zd1201_get_encode(struct net_device *dev,
 static int zd1201_set_power(struct net_device *dev, 
     struct iw_request_info *info, struct iw_param *vwrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short enabled, duration, level;
        int err;
 
@@ -1530,7 +1520,7 @@ out:
 static int zd1201_get_power(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *vwrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short enabled, level, duration;
        int err;
 
@@ -1617,7 +1607,7 @@ static const iw_handler zd1201_iw_handler[] =
 static int zd1201_set_hostauth(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
 
        if (!zd->ap)
                return -EOPNOTSUPP;
@@ -1628,7 +1618,7 @@ static int zd1201_set_hostauth(struct net_device *dev,
 static int zd1201_get_hostauth(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short hostauth;
        int err;
 
@@ -1647,7 +1637,7 @@ static int zd1201_get_hostauth(struct net_device *dev,
 static int zd1201_auth_sta(struct net_device *dev,
     struct iw_request_info *info, struct sockaddr *sta, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        unsigned char buffer[10];
 
        if (!zd->ap)
@@ -1663,7 +1653,7 @@ static int zd1201_auth_sta(struct net_device *dev,
 static int zd1201_set_maxassoc(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        int err;
 
        if (!zd->ap)
@@ -1678,7 +1668,7 @@ static int zd1201_set_maxassoc(struct net_device *dev,
 static int zd1201_get_maxassoc(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-       struct zd1201 *zd = (struct zd1201 *)dev->priv;
+       struct zd1201 *zd = netdev_priv(dev);
        short maxassoc;
        int err;
 
@@ -1726,10 +1716,22 @@ static const struct iw_handler_def zd1201_iw_handlers = {
        .get_wireless_stats     = zd1201_get_wireless_stats,
 };
 
+static const struct net_device_ops zd1201_netdev_ops = {
+       .ndo_open               = zd1201_net_open,
+       .ndo_stop               = zd1201_net_stop,
+       .ndo_start_xmit         = zd1201_hard_start_xmit,
+       .ndo_tx_timeout         = zd1201_tx_timeout,
+       .ndo_set_multicast_list = zd1201_set_multicast,
+       .ndo_set_mac_address    = zd1201_set_mac_address,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int zd1201_probe(struct usb_interface *interface,
                        const struct usb_device_id *id)
 {
        struct zd1201 *zd;
+       struct net_device *dev;
        struct usb_device *usb;
        int err;
        short porttype;
@@ -1737,9 +1739,12 @@ static int zd1201_probe(struct usb_interface *interface,
 
        usb = interface_to_usbdev(interface);
 
-       zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL);
-       if (!zd)
+       dev = alloc_etherdev(sizeof(*zd));
+       if (!dev)
                return -ENOMEM;
+       zd = netdev_priv(dev);
+       zd->dev = dev;
+
        zd->ap = ap;
        zd->usb = usb;
        zd->removed = 0;
@@ -1774,34 +1779,22 @@ static int zd1201_probe(struct usb_interface *interface,
        if (err)
                goto err_start;
 
-       zd->dev = alloc_etherdev(0);
-       if (!zd->dev)
-               goto err_start;
-
-       zd->dev->priv = zd;
-       zd->dev->open = zd1201_net_open;
-       zd->dev->stop = zd1201_net_stop;
-       zd->dev->get_stats = zd1201_get_stats;
-       zd->dev->wireless_handlers =
-           (struct iw_handler_def *)&zd1201_iw_handlers;
-       zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
-       zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
-       zd->dev->tx_timeout = zd1201_tx_timeout;
-       zd->dev->set_multicast_list = zd1201_set_multicast;
-       zd->dev->set_mac_address = zd1201_set_mac_address;
-       strcpy(zd->dev->name, "wlan%d");
+       dev->netdev_ops = &zd1201_netdev_ops;
+       dev->wireless_handlers = &zd1201_iw_handlers;
+       dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
+       strcpy(dev->name, "wlan%d");
 
        err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, 
-           zd->dev->dev_addr, zd->dev->addr_len);
+           dev->dev_addr, dev->addr_len);
        if (err)
-               goto err_net;
+               goto err_start;
 
        /* Set wildcard essid to match zd->essid */
        *(__le16 *)buf = cpu_to_le16(0);
        err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
            IW_ESSID_MAX_SIZE+2, 1);
        if (err)
-               goto err_net;
+               goto err_start;
 
        if (zd->ap)
                porttype = ZD1201_PORTTYPE_AP;
@@ -1809,30 +1802,28 @@ static int zd1201_probe(struct usb_interface *interface,
                porttype = ZD1201_PORTTYPE_BSS;
        err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
        if (err)
-               goto err_net;
+               goto err_start;
 
-       SET_NETDEV_DEV(zd->dev, &usb->dev);
+       SET_NETDEV_DEV(dev, &usb->dev);
 
-       err = register_netdev(zd->dev);
+       err = register_netdev(dev);
        if (err)
-               goto err_net;
+               goto err_start;
        dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
-           zd->dev->name);
+           dev->name);
 
        usb_set_intfdata(interface, zd);
+       zd1201_enable(zd);      /* zd1201 likes to startup enabled, */
+       zd1201_disable(zd);     /* interfering with all the wifis in range */
        return 0;
 
-err_net:
-       free_netdev(zd->dev);
 err_start:
        /* Leave the device in reset state */
        zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
 err_zd:
-       if (zd->tx_urb)
-               usb_free_urb(zd->tx_urb);
-       if (zd->rx_urb)
-               usb_free_urb(zd->rx_urb);
-       kfree(zd);
+       usb_free_urb(zd->tx_urb);
+       usb_free_urb(zd->rx_urb);
+       free_netdev(dev);
        return err;
 }
 
@@ -1845,10 +1836,6 @@ static void zd1201_disconnect(struct usb_interface *interface)
        if (!zd)
                return;
        usb_set_intfdata(interface, NULL);
-       if (zd->dev) {
-               unregister_netdev(zd->dev);
-               free_netdev(zd->dev);
-       }
 
        hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) {
                hlist_del_init(&frag->fnode);
@@ -1864,7 +1851,11 @@ static void zd1201_disconnect(struct usb_interface *interface)
                usb_kill_urb(zd->rx_urb);
                usb_free_urb(zd->rx_urb);
        }
-       kfree(zd);
+
+       if (zd->dev) {
+               unregister_netdev(zd->dev);
+               free_netdev(zd->dev);
+       }
 }
 
 #ifdef CONFIG_PM