net: spread __net_init, __net_exit
[safe/jmp/linux-2.6] / drivers / net / ps3_gelic_wireless.c
index 5f69809..227b141 100644 (file)
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include <linux/dma-mapping.h>
 #include <net/checksum.h>
@@ -45,7 +46,8 @@
 #include "ps3_gelic_wireless.h"
 
 
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan);
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+                              u8 *essid, size_t essid_len);
 static int gelic_wl_try_associate(struct net_device *netdev);
 
 /*
@@ -105,6 +107,7 @@ static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
        [GELIC_EURUS_CMD_GET_WEP_CFG]    = { .post_arg = 1},
        [GELIC_EURUS_CMD_GET_WPA_CFG]    = { .post_arg = 1},
        [GELIC_EURUS_CMD_GET_RSSI_CFG]   = { .post_arg = 1},
+       [GELIC_EURUS_CMD_START_SCAN]     = { .pre_arg = 1},
        [GELIC_EURUS_CMD_GET_SCAN]       = { .post_arg = 1},
 };
 
@@ -163,7 +166,9 @@ static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
        card = port_to_card(wl_port(wl));
 
        if (cmd_info[cmd->cmd].pre_arg) {
-               arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
+               arg1 = (cmd->buffer) ?
+                       ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
+                       0;
                arg2 = cmd->buf_size;
        } else {
                arg1 = 0;
@@ -360,6 +365,9 @@ static int gelic_wl_get_range(struct net_device *netdev,
        range->num_encoding_sizes = 3;
        range->max_encoding_tokens = GELIC_WEP_KEYS;
 
+       /* scan capability */
+       range->scan_capa = IW_SCAN_CAPA_ESSID;
+
        pr_debug("%s: ->\n", __func__);
        return 0;
 
@@ -371,8 +379,18 @@ static int gelic_wl_set_scan(struct net_device *netdev,
                           union iwreq_data *wrqu, char *extra)
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-
-       return gelic_wl_start_scan(wl, 1);
+       struct iw_scan_req *req;
+       u8 *essid = NULL;
+       size_t essid_len = 0;
+
+       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+               req = (struct iw_scan_req*)extra;
+               essid = req->essid;
+               essid_len = req->essid_len;
+               pr_debug("%s: ESSID scan =%s\n", __func__, essid);
+       }
+       return gelic_wl_start_scan(wl, 1, essid, essid_len);
 }
 
 #define OUI_LEN 3
@@ -432,9 +450,9 @@ static size_t gelic_wl_synthesize_ie(u8 *buf,
 
        /* element id */
        if (rsn)
-               *buf++ = MFIE_TYPE_RSN;
+               *buf++ = WLAN_EID_RSN;
        else
-               *buf++ = MFIE_TYPE_GENERIC;
+               *buf++ = WLAN_EID_GENERIC;
 
        /* length filed; set later */
        buf++;
@@ -522,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
                        break;
 
                switch (item_id) {
-               case MFIE_TYPE_GENERIC:
+               case WLAN_EID_GENERIC:
                        if ((OUI_LEN + 1 <= item_len) &&
                            !memcmp(pos, wpa_oui, OUI_LEN) &&
                            pos[OUI_LEN] == 0x01) {
@@ -530,7 +548,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
                                ie_info->wpa.len = item_len + 2;
                        }
                        break;
-               case MFIE_TYPE_RSN:
+               case WLAN_EID_RSN:
                        ie_info->rsn.data = pos - 2;
                        /* length includes the header */
                        ie_info->rsn.len = item_len + 2;
@@ -554,6 +572,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
  * independent format
  */
 static char *gelic_wl_translate_scan(struct net_device *netdev,
+                                    struct iw_request_info *info,
                                     char *ev,
                                     char *stop,
                                     struct gelic_wl_scan_info *network)
@@ -563,7 +582,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        char *tmp;
        u8 rate;
        unsigned int i, j, len;
-       u8 buf[MAX_WPA_IE_LEN];
+       u8 buf[64]; /* arbitrary size large enough */
 
        pr_debug("%s: <-\n", __func__);
 
@@ -571,26 +590,26 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
-       ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN);
+       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN);
 
        /* ESSID */
        iwe.cmd = SIOCGIWESSID;
        iwe.u.data.flags = 1;
        iwe.u.data.length = strnlen(scan->essid, 32);
-       ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
+       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
 
        /* FREQUENCY */
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = be16_to_cpu(scan->channel);
        iwe.u.freq.e = 0; /* table value in MHz */
        iwe.u.freq.i = 0;
-       ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN);
+       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN);
 
        /* RATES */
        iwe.cmd = SIOCGIWRATE;
        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
        /* to stuff multiple values in one event */
-       tmp = ev + IW_EV_LCP_LEN;
+       tmp = ev + iwe_stream_lcp_len(info);
        /* put them in ascendant order (older is first) */
        i = 0;
        j = 0;
@@ -603,16 +622,16 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                else
                    rate = scan->rate[i++] & 0x7f;
                iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
-               tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
+               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
                                           IW_EV_PARAM_LEN);
        }
        while (j < network->rate_ext_len) {
                iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
-               tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
+               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
                                           IW_EV_PARAM_LEN);
        }
        /* Check if we added any rate */
-       if (IW_EV_LCP_LEN < (tmp - ev))
+       if (iwe_stream_lcp_len(info) < (tmp - ev))
                ev = tmp;
 
        /* ENCODE */
@@ -622,7 +641,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
+       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
 
        /* MODE */
        iwe.cmd = SIOCGIWMODE;
@@ -632,7 +651,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN);
+               ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN);
        }
 
        /* QUAL */
@@ -642,7 +661,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        iwe.u.qual.level = be16_to_cpu(scan->rssi);
        iwe.u.qual.qual = be16_to_cpu(scan->rssi);
        iwe.u.qual.noise = 0;
-       ev  = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN);
+       ev  = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN);
 
        /* RSN */
        memset(&iwe, 0, sizeof(iwe));
@@ -652,7 +671,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                if (len) {
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = len;
-                       ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
                }
        } else {
                /* this scan info has IE data */
@@ -667,7 +686,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                        memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = ie_info.wpa.len;
-                       ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
                }
 
                if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
@@ -675,7 +694,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                        memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = ie_info.rsn.len;
-                       ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
                }
        }
 
@@ -720,7 +739,8 @@ static int gelic_wl_get_scan(struct net_device *netdev,
                if (wl->scan_age == 0 ||
                    time_after(scan_info->last_scanned + wl->scan_age,
                               this_time))
-                       ev = gelic_wl_translate_scan(netdev, ev, stop,
+                       ev = gelic_wl_translate_scan(netdev, info,
+                                                    ev, stop,
                                                     scan_info);
                else
                        pr_debug("%s:entry too old\n", __func__);
@@ -744,7 +764,6 @@ static void scan_list_dump(struct gelic_wl_info *wl)
 {
        struct gelic_wl_scan_info *scan_info;
        int i;
-       DECLARE_MAC_BUF(mac);
 
        i = 0;
        list_for_each_entry(scan_info, &wl->network_list, list) {
@@ -756,8 +775,7 @@ static void scan_list_dump(struct gelic_wl_info *wl)
                         scan_info->rate_len, scan_info->rate_ext_len,
                         scan_info->essid_len);
                /* -- */
-               pr_debug("bssid=%s\n",
-                        print_mac(mac, &scan_info->hwinfo->bssid[2]));
+               pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]);
                pr_debug("essid=%s\n", scan_info->hwinfo->essid);
        }
 }
@@ -1005,7 +1023,7 @@ static int gelic_wl_set_encode(struct net_device *netdev,
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        struct iw_point *enc = &data->encoding;
        __u16 flags;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int key_index, index_specified;
        int ret = 0;
 
@@ -1078,7 +1096,7 @@ static int gelic_wl_get_encode(struct net_device *netdev,
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        struct iw_point *enc = &data->encoding;
-       unsigned int irqflag;
+       unsigned long irqflag;
        unsigned int key_index, index_specified;
        int ret = 0;
 
@@ -1148,11 +1166,7 @@ static int gelic_wl_set_ap(struct net_device *netdev,
                       ETH_ALEN);
                set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
                set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-               pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n",
-                        __func__,
-                        wl->bssid[0], wl->bssid[1],
-                        wl->bssid[2], wl->bssid[3],
-                        wl->bssid[4], wl->bssid[5]);
+               pr_debug("%s: bss=%pM\n", __func__, wl->bssid);
        } else {
                pr_debug("%s: clear bssid\n", __func__);
                clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
@@ -1196,7 +1210,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        __u16 alg;
        __u16 flags;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int key_index;
        int ret = 0;
 
@@ -1284,7 +1298,7 @@ static int gelic_wl_get_encodeext(struct net_device *netdev,
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        struct iw_point *enc = &data->encoding;
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int key_index;
        int ret = 0;
        int max_key_len;
@@ -1375,6 +1389,7 @@ static int gelic_wl_get_mode(struct net_device *netdev,
        return 0;
 }
 
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
 /* SIOCIWFIRSTPRIV */
 static int hex2bin(u8 *str, u8 *bin, unsigned int len)
 {
@@ -1406,7 +1421,7 @@ static int gelic_wl_priv_set_psk(struct net_device *net_dev,
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
        unsigned int len;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int ret = 0;
 
        pr_debug("%s:<- len=%d\n", __func__, data->data.length);
@@ -1447,7 +1462,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev,
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
        char *p;
-       unsigned int irqflag;
+       unsigned long irqflag;
        unsigned int i;
 
        pr_debug("%s:<-\n", __func__);
@@ -1479,6 +1494,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev,
        pr_debug("%s:-> %d\n", __func__, data->data.length);
        return 0;
 }
+#endif
 
 /* SIOCGIWNICKN */
 static int gelic_wl_get_nick(struct net_device *net_dev,
@@ -1532,10 +1548,13 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
 /*
  *  scanning helpers
  */
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+                              u8 *essid, size_t essid_len)
 {
        struct gelic_eurus_cmd *cmd;
        int ret = 0;
+       void *buf = NULL;
+       size_t len;
 
        pr_debug("%s: <- always=%d\n", __func__, always_scan);
        if (mutex_lock_interruptible(&wl->scan_lock))
@@ -1558,12 +1577,27 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
                complete(&wl->scan_done);
                goto out;
        }
+
+       /* ESSID scan ? */
+       if (essid_len && essid) {
+               buf = (void *)__get_free_page(GFP_KERNEL);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
+               memset(buf, 0, len);
+               memcpy(buf, essid, essid_len);
+               pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
+       } else
+               len = 0;
+
        /*
         * issue start scan request
         */
        wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
        cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
-                                  NULL, 0);
+                                  buf, len);
        if (!cmd || cmd->status || cmd->cmd_status) {
                wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
                complete(&wl->scan_done);
@@ -1572,6 +1606,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
        }
        kfree(cmd);
 out:
+       free_page((unsigned long)buf);
        mutex_unlock(&wl->scan_lock);
        pr_debug("%s: ->\n", __func__);
        return ret;
@@ -1592,7 +1627,6 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
        unsigned long this_time = jiffies;
        unsigned int data_len, i, found, r;
        void *buf;
-       DECLARE_MAC_BUF(mac);
 
        pr_debug("%s:start\n", __func__);
        mutex_lock(&wl->scan_lock);
@@ -1644,9 +1678,9 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
             scan_info_size < data_len;
             i++, scan_info_size += be16_to_cpu(scan_info->size),
             scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
-               pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__,
+               pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__,
                         be16_to_cpu(scan_info->size),
-                        print_mac(mac, &scan_info->bssid[2]), scan_info);
+                        &scan_info->bssid[2], scan_info);
 
                /*
                 * The wireless firmware may return invalid channel 0 and/or
@@ -1701,14 +1735,14 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
                target->essid_len = strnlen(scan_info->essid,
                                            sizeof(scan_info->essid));
                target->rate_len = 0;
-               for (r = 0; r < MAX_RATES_LENGTH; r++)
+               for (r = 0; r < 12; r++)
                        if (scan_info->rate[r])
                                target->rate_len++;
                if (8 < target->rate_len)
                        pr_info("%s: AP returns %d rates\n", __func__,
                                target->rate_len);
                target->rate_ext_len = 0;
-               for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
+               for (r = 0; r < 16; r++)
                        if (scan_info->ext_rate[r])
                                target->rate_ext_len++;
                list_move_tail(&target->list, &wl->network_list);
@@ -1747,7 +1781,6 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
        struct gelic_wl_scan_info *best_bss;
        int weight, best_weight;
        u16 security;
-       DECLARE_MAC_BUF(mac);
 
        pr_debug("%s: <-\n", __func__);
 
@@ -1817,8 +1850,8 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
 #ifdef DEBUG
        pr_debug("%s: -> bss=%p\n", __func__, best_bss);
        if (best_bss) {
-               pr_debug("%s:addr=%s\n", __func__,
-                        print_mac(mac, &best_bss->hwinfo->bssid[2]));
+               pr_debug("%s:addr=%pM\n", __func__,
+                        &best_bss->hwinfo->bssid[2]);
        }
 #endif
        return best_bss;
@@ -2068,6 +2101,9 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
        if (ret) {
                pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
                         ret);
+               ret = -EPERM;
+               gelic_wl_send_iwap_event(wl, NULL);
+               goto out;
        }
 
        /* start association */
@@ -2135,7 +2171,7 @@ static void gelic_wl_connected_event(struct gelic_wl_info *wl,
                complete(&wl->assoc_done);
                netif_carrier_on(port_to_netdev(wl_port(wl)));
        } else
-               pr_debug("%s: event %#lx under wpa\n",
+               pr_debug("%s: event %#llx under wpa\n",
                                 __func__, event);
 }
 
@@ -2259,6 +2295,9 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
 
        struct gelic_wl_scan_info *best_bss;
        int ret;
+       unsigned long irqflag;
+       u8 *essid;
+       size_t essid_len;
 
        wl = container_of(work, struct gelic_wl_info, assoc_work.work);
 
@@ -2267,7 +2306,19 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
        if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
                goto out;
 
-       ret = gelic_wl_start_scan(wl, 0);
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
+               pr_debug("%s: assoc ESSID configured %s\n", __func__,
+                        wl->essid);
+               essid = wl->essid;
+               essid_len = wl->essid_len;
+       } else {
+               essid = NULL;
+               essid_len = 0;
+       }
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+
+       ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
        if (ret == -ERESTARTSYS) {
                pr_debug("%s: scan start failed association\n", __func__);
                schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
@@ -2355,6 +2406,7 @@ static const iw_handler gelic_wl_wext_handler[] =
        IW_IOCTL(SIOCGIWNICKN)          = gelic_wl_get_nick,
 };
 
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
 static struct iw_priv_args gelic_wl_private_args[] =
 {
        {
@@ -2376,18 +2428,21 @@ static const iw_handler gelic_wl_private_handler[] =
        gelic_wl_priv_set_psk,
        gelic_wl_priv_get_psk,
 };
+#endif
 
 static const struct iw_handler_def gelic_wl_wext_handler_def = {
        .num_standard           = ARRAY_SIZE(gelic_wl_wext_handler),
        .standard               = gelic_wl_wext_handler,
        .get_wireless_stats     = gelic_wl_get_wireless_stats,
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
        .num_private            = ARRAY_SIZE(gelic_wl_private_handler),
        .num_private_args       = ARRAY_SIZE(gelic_wl_private_args),
        .private                = gelic_wl_private_handler,
        .private_args           = gelic_wl_private_args,
+#endif
 };
 
-static struct net_device *gelic_wl_alloc(struct gelic_card *card)
+static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
 {
        struct net_device *netdev;
        struct gelic_port *port;
@@ -2645,7 +2700,21 @@ static int gelic_wl_stop(struct net_device *netdev)
 
 /* -- */
 
-static struct ethtool_ops gelic_wl_ethtool_ops = {
+static const struct net_device_ops gelic_wl_netdevice_ops = {
+       .ndo_open = gelic_wl_open,
+       .ndo_stop = gelic_wl_stop,
+       .ndo_start_xmit = gelic_net_xmit,
+       .ndo_set_multicast_list = gelic_net_set_multi,
+       .ndo_change_mtu = gelic_net_change_mtu,
+       .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = gelic_net_poll_controller,
+#endif
+};
+
+static const struct ethtool_ops gelic_wl_ethtool_ops = {
        .get_drvinfo    = gelic_net_get_drvinfo,
        .get_link       = gelic_wl_get_link,
        .get_tx_csum    = ethtool_op_get_tx_csum,
@@ -2654,32 +2723,23 @@ static struct ethtool_ops gelic_wl_ethtool_ops = {
        .set_rx_csum    = gelic_net_set_rx_csum,
 };
 
-static void gelic_wl_setup_netdev_ops(struct net_device *netdev)
+static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev)
 {
        struct gelic_wl_info *wl;
        wl = port_wl(netdev_priv(netdev));
        BUG_ON(!wl);
-       netdev->open = &gelic_wl_open;
-       netdev->stop = &gelic_wl_stop;
-       netdev->hard_start_xmit = &gelic_net_xmit;
-       netdev->set_multicast_list = &gelic_net_set_multi;
-       netdev->change_mtu = &gelic_net_change_mtu;
-       netdev->wireless_data = &wl->wireless_data;
-       netdev->wireless_handlers = &gelic_wl_wext_handler_def;
-       /* tx watchdog */
-       netdev->tx_timeout = &gelic_net_tx_timeout;
        netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
 
        netdev->ethtool_ops = &gelic_wl_ethtool_ops;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       netdev->poll_controller = gelic_net_poll_controller;
-#endif
+       netdev->netdev_ops = &gelic_wl_netdevice_ops;
+       netdev->wireless_data = &wl->wireless_data;
+       netdev->wireless_handlers = &gelic_wl_wext_handler_def;
 }
 
 /*
  * driver probe/remove
  */
-int gelic_wl_driver_probe(struct gelic_card *card)
+int __devinit gelic_wl_driver_probe(struct gelic_card *card)
 {
        int ret;
        struct net_device *netdev;