Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / net / wireless / at76c50x-usb.c
index 46ac9e2..0fb4199 100644 (file)
  *
  * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
  *
- * TODO for the mac80211 port:
- * o adhoc support
- * o RTS/CTS support
- * o Power Save Mode support
- * o support for short/long preambles
- * o export variables through debugfs/sysfs
- * o remove hex2str
- * o remove mac2str
+ * TODO list is at the wiki:
+ *
+ * http://wireless.kernel.org/en/users/Drivers/at76c50x-usb#TODO
+ *
  */
 
 #include <linux/init.h>
@@ -125,6 +121,14 @@ static struct fwentry firmwares[] = {
        [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" },
        [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" },
 };
+MODULE_FIRMWARE("atmel_at76c503-i3861.bin");
+MODULE_FIRMWARE("atmel_at76c503-i3863.bin");
+MODULE_FIRMWARE("atmel_at76c503-rfmd.bin");
+MODULE_FIRMWARE("atmel_at76c503-rfmd-acc.bin");
+MODULE_FIRMWARE("atmel_at76c505-rfmd.bin");
+MODULE_FIRMWARE("atmel_at76c505-rfmd2958.bin");
+MODULE_FIRMWARE("atmel_at76c505a-rfmd2958.bin");
+MODULE_FIRMWARE("atmel_at76c505amx-rfmd.bin");
 
 #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
 
@@ -254,6 +258,8 @@ static struct usb_device_id dev_table[] = {
        { USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A) },
        /* Siemens Gigaset USB WLAN Adapter 11 */
        { USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A) },
+       /* OQO Model 01+ Internal Wi-Fi */
+       { USB_DEVICE(0x1557, 0x0002), USB_DEVICE_DATA(BOARD_505A) },
        /*
         * at76c505amx-rfmd
         */
@@ -526,20 +532,6 @@ static char *hex2str(void *buf, int len)
        return ret;
 }
 
-#define MAC2STR_BUFFERS 4
-
-static inline char *mac2str(u8 *mac)
-{
-       static atomic_t a = ATOMIC_INIT(0);
-       static char bufs[MAC2STR_BUFFERS][6 * 3];
-       char *str;
-
-       str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)];
-       sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
-               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-       return str;
-}
-
 /* LED trigger */
 static int tx_activity;
 static void at76_ledtrig_tx_timerfunc(unsigned long data);
@@ -975,13 +967,13 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv)
                goto exit;
        }
 
-       at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x",
+       at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %pM res 0x%x 0x%x",
                 wiphy_name(priv->hw->wiphy),
-                mac2str(m->mac_addr), m->res[0], m->res[1]);
+                m->mac_addr, m->res[0], m->res[1]);
        for (i = 0; i < ARRAY_SIZE(m->group_addr); i++)
-               at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, "
+               at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %pM, "
                         "status %d", wiphy_name(priv->hw->wiphy), i,
-                        mac2str(m->group_addr[i]), m->group_addr_status[i]);
+                        m->group_addr[i], m->group_addr_status[i]);
 exit:
        kfree(m);
 }
@@ -1044,7 +1036,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
        at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
                 "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
                 "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
-                "current_bssid %s current_essid %s current_bss_type %d "
+                "current_bssid %pM current_essid %s current_bss_type %d "
                 "pm_mode %d ibss_change %d res %d "
                 "multi_domain_capability_implemented %d "
                 "international_roaming %d country_string %.3s",
@@ -1053,7 +1045,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
                 le16_to_cpu(m->medium_occupancy_limit),
                 le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
                 m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
-                m->CFP_period, mac2str(m->current_bssid),
+                m->CFP_period, m->current_bssid,
                 hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
                 m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
                 m->res, m->multi_domain_capability_implemented,
@@ -1082,7 +1074,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
                 "cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
                 "scan_type %d scan_channel %d probe_delay %u "
                 "min_channel_time %d max_channel_time %d listen_int %d "
-                "desired_ssid %s desired_bssid %s desired_bsstype %d",
+                "desired_ssid %s desired_bssid %pM desired_bsstype %d",
                 wiphy_name(priv->hw->wiphy),
                 le32_to_cpu(m->max_tx_msdu_lifetime),
                 le32_to_cpu(m->max_rx_lifetime),
@@ -1094,7 +1086,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
                 le16_to_cpu(m->max_channel_time),
                 le16_to_cpu(m->listen_interval),
                 hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
-                mac2str(m->desired_bssid), m->desired_bsstype);
+                m->desired_bssid, m->desired_bsstype);
 exit:
        kfree(m);
 }
@@ -1196,6 +1188,9 @@ static int at76_start_monitor(struct at76_priv *priv)
        scan.channel = priv->channel;
        scan.scan_type = SCAN_TYPE_PASSIVE;
        scan.international_scan = 0;
+       scan.min_channel_time = cpu_to_le16(priv->scan_min_time);
+       scan.max_channel_time = cpu_to_le16(priv->scan_max_time);
+       scan.probe_delay = cpu_to_le16(0);
 
        ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
        if (ret >= 0)
@@ -1497,6 +1492,9 @@ static void at76_work_set_promisc(struct work_struct *work)
                                              work_set_promisc);
        int ret = 0;
 
+       if (priv->device_unplugged)
+               return;
+
        mutex_lock(&priv->mtx);
 
        priv->mib_buf.type = MIB_LOCAL;
@@ -1567,7 +1565,8 @@ static void at76_rx_tasklet(unsigned long param)
 
        at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
                 priv->rx_skb->len, priv->rx_skb->data_len);
-       ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
+       memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status));
+       ieee80211_rx_irqsafe(priv->hw, priv->rx_skb);
 
        /* Use a new skb for the next receive */
        priv->rx_skb = NULL;
@@ -1771,6 +1770,9 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
 
        at76_dbg(DBG_MAC80211, "%s()", __func__);
 
+       cancel_delayed_work(&priv->dwork_hw_scan);
+       cancel_work_sync(&priv->work_set_promisc);
+
        mutex_lock(&priv->mtx);
 
        if (!priv->device_unplugged) {
@@ -1787,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
 }
 
 static int at76_add_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_if_init_conf *conf)
+                             struct ieee80211_vif *vif)
 {
        struct at76_priv *priv = hw->priv;
        int ret = 0;
@@ -1796,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mtx);
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                priv->iw_mode = IW_MODE_INFRA;
                break;
@@ -1812,7 +1814,7 @@ exit:
 }
 
 static void at76_remove_interface(struct ieee80211_hw *hw,
-                                 struct ieee80211_if_init_conf *conf)
+                                 struct ieee80211_vif *vif)
 {
        at76_dbg(DBG_MAC80211, "%s()", __func__);
 }
@@ -1870,20 +1872,20 @@ static void at76_dwork_hw_scan(struct work_struct *work)
        /* FIXME: add maximum time for scan to complete */
 
        if (ret != CMD_STATUS_COMPLETE) {
-               queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
-                                  SCAN_POLL_INTERVAL);
-               goto exit;
+               ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+                                            SCAN_POLL_INTERVAL);
+               mutex_unlock(&priv->mtx);
+               return;
        }
 
-       ieee80211_scan_completed(priv->hw, false);
-
        if (is_valid_ether_addr(priv->bssid))
                at76_join(priv);
 
-       ieee80211_wake_queues(priv->hw);
-
-exit:
        mutex_unlock(&priv->mtx);
+
+       ieee80211_scan_completed(priv->hw, false);
+
+       ieee80211_wake_queues(priv->hw);
 }
 
 static int at76_hw_scan(struct ieee80211_hw *hw,
@@ -1932,8 +1934,8 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
                goto exit;
        }
 
-       queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
-                          SCAN_POLL_INTERVAL);
+       ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+                                    SCAN_POLL_INTERVAL);
 
 exit:
        mutex_unlock(&priv->mtx);
@@ -1945,9 +1947,8 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct at76_priv *priv = hw->priv;
 
-       at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",
-                __func__, hw->conf.channel->hw_value,
-                hw->conf.radio_enabled);
+       at76_dbg(DBG_MAC80211, "%s(): channel %d",
+                __func__, hw->conf.channel->hw_value);
        at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");
 
        mutex_lock(&priv->mtx);
@@ -1964,13 +1965,18 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed)
        return 0;
 }
 
-static int at76_config_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_vif *vif,
-                                struct ieee80211_if_conf *conf)
+static void at76_bss_info_changed(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_bss_conf *conf,
+                                 u32 changed)
 {
        struct at76_priv *priv = hw->priv;
 
        at76_dbg(DBG_MAC80211, "%s():", __func__);
+
+       if (!(changed & BSS_CHANGED_BSSID))
+               return;
+
        at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:");
 
        mutex_lock(&priv->mtx);
@@ -1982,22 +1988,19 @@ static int at76_config_interface(struct ieee80211_hw *hw,
                at76_join(priv);
 
        mutex_unlock(&priv->mtx);
-
-       return 0;
 }
 
 /* must be atomic */
 static void at76_configure_filter(struct ieee80211_hw *hw,
                                  unsigned int changed_flags,
-                                 unsigned int *total_flags, int mc_count,
-                                 struct dev_addr_list *mc_list)
+                                 unsigned int *total_flags, u64 multicast)
 {
        struct at76_priv *priv = hw->priv;
        int flags;
 
        at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
-                "total_flags=0x%08x mc_count=%d",
-                __func__, changed_flags, *total_flags, mc_count);
+                "total_flags=0x%08x",
+                __func__, changed_flags, *total_flags);
 
        flags = changed_flags & AT76_SUPPORTED_FILTERS;
        *total_flags = AT76_SUPPORTED_FILTERS;
@@ -2019,7 +2022,7 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
        } else
                return;
 
-       queue_work(hw->workqueue, &priv->work_set_promisc);
+       ieee80211_queue_work(hw, &priv->work_set_promisc);
 }
 
 static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2075,7 +2078,7 @@ static const struct ieee80211_ops at76_ops = {
        .add_interface = at76_add_interface,
        .remove_interface = at76_remove_interface,
        .config = at76_config,
-       .config_interface = at76_config_interface,
+       .bss_info_changed = at76_bss_info_changed,
        .configure_filter = at76_configure_filter,
        .start = at76_mac80211_start,
        .stop = at76_mac80211_stop,
@@ -2211,6 +2214,8 @@ static struct ieee80211_supported_band at76_supported_band = {
 static int at76_init_new_device(struct at76_priv *priv,
                                struct usb_interface *interface)
 {
+       struct wiphy *wiphy;
+       size_t len;
        int ret;
 
        /* set up the endpoint information */
@@ -2248,7 +2253,9 @@ static int at76_init_new_device(struct at76_priv *priv,
        priv->device_unplugged = 0;
 
        /* mac80211 initialisation */
+       wiphy = priv->hw->wiphy;
        priv->hw->wiphy->max_scan_ssids = 1;
+       priv->hw->wiphy->max_scan_ie_len = 0;
        priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
        priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
        priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
@@ -2258,6 +2265,13 @@ static int at76_init_new_device(struct at76_priv *priv,
        SET_IEEE80211_DEV(priv->hw, &interface->dev);
        SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
+       len = sizeof(wiphy->fw_version);
+       snprintf(wiphy->fw_version, len, "%d.%d.%d-%d",
+                priv->fw_version.major, priv->fw_version.minor,
+                priv->fw_version.patch, priv->fw_version.build);
+
+       wiphy->hw_version = priv->board_type;
+
        ret = ieee80211_register_hw(priv->hw);
        if (ret) {
                printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
@@ -2267,9 +2281,9 @@ static int at76_init_new_device(struct at76_priv *priv,
 
        priv->mac80211_registered = 1;
 
-       printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n",
+       printk(KERN_INFO "%s: USB %s, MAC %pM, firmware %d.%d.%d-%d\n",
               wiphy_name(priv->hw->wiphy),
-              interface->dev.bus_id, mac2str(priv->mac_addr),
+              dev_name(&interface->dev), priv->mac_addr,
               priv->fw_version.major, priv->fw_version.minor,
               priv->fw_version.patch, priv->fw_version.build);
        printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",
@@ -2289,10 +2303,8 @@ static void at76_delete_device(struct at76_priv *priv)
 
        tasklet_kill(&priv->rx_tasklet);
 
-       if (priv->mac80211_registered) {
-               flush_workqueue(priv->hw->workqueue);
+       if (priv->mac80211_registered)
                ieee80211_unregister_hw(priv->hw);
-       }
 
        if (priv->tx_urb) {
                usb_kill_urb(priv->tx_urb);
@@ -2307,8 +2319,9 @@ static void at76_delete_device(struct at76_priv *priv)
 
        kfree(priv->bulk_out_buffer);
 
-       if (priv->rx_skb)
-               kfree_skb(priv->rx_skb);
+       del_timer_sync(&ledtrig_tx_timer);
+
+       kfree_skb(priv->rx_skb);
 
        usb_put_dev(priv->udev);