[PATCH] libertas: reorganize and simplify init sequence
[safe/jmp/linux-2.6] / drivers / net / wireless / libertas / main.c
index 9a46339..6304bd9 100644 (file)
@@ -23,7 +23,7 @@
 #include "assoc.h"
 #include "join.h"
 
-#define DRIVER_RELEASE_VERSION "322.p1"
+#define DRIVER_RELEASE_VERSION "323.p0"
 const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
 #ifdef  DEBUG
     "-dbg"
@@ -768,6 +768,7 @@ static int libertas_thread(void *data)
 
        init_waitqueue_entry(&wait, current);
 
+       set_freezable();
        for (;;) {
                lbs_deb_thread( "main-thread 111: intcounter=%d "
                       "currenttxskb=%p dnld_sent=%d\n",
@@ -790,7 +791,6 @@ static int libertas_thread(void *data)
                } else
                        spin_unlock_irq(&adapter->driver_lock);
 
-
                lbs_deb_thread(
                       "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
                       "dnld_sent=%d\n", adapter->intcounter,
@@ -925,7 +925,7 @@ static int libertas_thread(void *data)
  *  @param priv    A pointer to wlan_private structure
  *  @return       0 or -1
  */
-static int wlan_setup_station_hw(wlan_private * priv)
+static int wlan_setup_firmware(wlan_private * priv)
 {
        int ret = -1;
        wlan_adapter *adapter = priv->adapter;
@@ -933,14 +933,6 @@ static int wlan_setup_station_hw(wlan_private * priv)
 
        lbs_deb_enter(LBS_DEB_FW);
 
-       ret = priv->hw_prog_firmware(priv);
-
-       if (ret) {
-               lbs_deb_fw("bootloader in invalid state\n");
-               ret = -1;
-               goto done;
-       }
-
        /*
         * Read MAC address from HW
         */
@@ -981,14 +973,16 @@ static int wlan_setup_station_hw(wlan_private * priv)
                priv->mesh_autostart_enabled = 0;
        }
 
+       /* Set the boot2 version in firmware */
+       ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER,
+                                   0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
        ret = 0;
 done:
        lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
        return ret;
 }
 
-static void command_timer_fn(unsigned long data);
-
 /**
  *  This function handles the timeout of command sending.
  *  It will re-send the same command again.
@@ -1030,155 +1024,99 @@ static void command_timer_fn(unsigned long data)
        return;
 }
 
-static void libertas_free_adapter(wlan_private * priv)
+static int libertas_init_adapter(wlan_private * priv)
 {
        wlan_adapter *adapter = priv->adapter;
-
-       if (!adapter) {
-               lbs_deb_fw("why double free adapter?\n");
-               return;
-       }
-
-       lbs_deb_fw("free command buffer\n");
-       libertas_free_cmd_buffer(priv);
-
-       lbs_deb_fw("free command_timer\n");
-       del_timer(&adapter->command_timer);
-
-       lbs_deb_fw("free scan results table\n");
-       kfree(adapter->networks);
-       adapter->networks = NULL;
-
-       /* Free the adapter object itself */
-       lbs_deb_fw("free adapter\n");
-       kfree(adapter);
-       priv->adapter = NULL;
-}
-
-static int wlan_allocate_adapter(wlan_private * priv)
-{
        size_t bufsize;
-       wlan_adapter *adapter = priv->adapter;
+       int i, ret = 0;
 
        /* Allocate buffer to store the BSSID list */
        bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
        adapter->networks = kzalloc(bufsize, GFP_KERNEL);
        if (!adapter->networks) {
                lbs_pr_err("Out of memory allocating beacons\n");
-               libertas_free_adapter(priv);
-               return -ENOMEM;
+               ret = -1;
+               goto out;
        }
 
-       /* Allocate the command buffers */
-       libertas_allocate_cmd_buffer(priv);
+       /* Initialize scan result lists */
+       INIT_LIST_HEAD(&adapter->network_free_list);
+       INIT_LIST_HEAD(&adapter->network_list);
+       for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+               list_add_tail(&adapter->networks[i].list,
+                             &adapter->network_free_list);
+       }
 
-       memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
        adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
        adapter->libertas_ps_confirm_sleep.command =
            cpu_to_le16(CMD_802_11_PS_MODE);
        adapter->libertas_ps_confirm_sleep.size =
            cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
-       adapter->libertas_ps_confirm_sleep.result = 0;
        adapter->libertas_ps_confirm_sleep.action =
            cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
 
-       return 0;
-}
-
-static void wlan_init_adapter(wlan_private * priv)
-{
-       wlan_adapter *adapter = priv->adapter;
-       int i;
-
-       adapter->connect_status = LIBERTAS_DISCONNECTED;
        memset(adapter->current_addr, 0xff, ETH_ALEN);
 
-       /* 802.11 specific */
-       adapter->secinfo.wep_enabled = 0;
-       for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
-            i++)
-               memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key));
-       adapter->wep_tx_keyidx = 0;
+       adapter->connect_status = LIBERTAS_DISCONNECTED;
        adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
        adapter->mode = IW_MODE_INFRA;
-
-       adapter->pending_assoc_req = NULL;
-       adapter->in_progress_assoc_req = NULL;
-
-       /* Initialize scan result lists */
-       INIT_LIST_HEAD(&adapter->network_free_list);
-       INIT_LIST_HEAD(&adapter->network_list);
-       for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-               list_add_tail(&adapter->networks[i].list,
-                             &adapter->network_free_list);
-       }
-
-       mutex_init(&adapter->lock);
-
-       memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
        adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-
-       /* PnP and power profile */
-       adapter->surpriseremoved = 0;
-
-       adapter->currentpacketfilter =
-           CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
-
+       adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        adapter->radioon = RADIO_ON;
-
        adapter->auto_rate = 1;
-       adapter->cur_rate = 0;
-
-       // set default capabilities
        adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
-
        adapter->psmode = WLAN802_11POWERMODECAM;
-
        adapter->psstate = PS_STATE_FULL_POWER;
-       adapter->needtowakeup = 0;
-
-       adapter->intcounter = 0;
 
-       adapter->currenttxskb = NULL;
+       mutex_init(&adapter->lock);
 
        memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
        adapter->tx_queue_idx = 0;
        spin_lock_init(&adapter->txqueue_lock);
 
-       return;
-}
+       setup_timer(&adapter->command_timer, command_timer_fn,
+                   (unsigned long)priv);
 
-static int libertas_init_fw(wlan_private * priv)
-{
-       int ret = -1;
-       wlan_adapter *adapter = priv->adapter;
+       INIT_LIST_HEAD(&adapter->cmdfreeq);
+       INIT_LIST_HEAD(&adapter->cmdpendingq);
 
-       lbs_deb_enter(LBS_DEB_FW);
+       spin_lock_init(&adapter->driver_lock);
+       init_waitqueue_head(&adapter->cmd_pending);
+       adapter->nr_cmd_pending = 0;
 
-       /* Allocate adapter structure */
-       if ((ret = wlan_allocate_adapter(priv)) != 0)
-               goto done;
+       /* Allocate the command buffers */
+       if (libertas_allocate_cmd_buffer(priv)) {
+               lbs_pr_err("Out of memory allocating command buffers\n");
+               ret = -1;
+       }
 
-       /* init adapter structure */
-       wlan_init_adapter(priv);
+out:
+       return ret;
+}
 
-       /* init timer etc. */
-       setup_timer(&adapter->command_timer, command_timer_fn,
-                       (unsigned long)priv);
+static void libertas_free_adapter(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
 
-       /* download fimrware etc. */
-       if ((ret = wlan_setup_station_hw(priv)) != 0) {
-               del_timer_sync(&adapter->command_timer);
-               goto done;
+       if (!adapter) {
+               lbs_deb_fw("why double free adapter?\n");
+               return;
        }
 
-       /* init 802.11d */
-       libertas_init_11d(priv);
+       lbs_deb_fw("free command buffer\n");
+       libertas_free_cmd_buffer(priv);
 
-       ret = 0;
-done:
-       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-       return ret;
+       lbs_deb_fw("free command_timer\n");
+       del_timer(&adapter->command_timer);
+
+       lbs_deb_fw("free scan results table\n");
+       kfree(adapter->networks);
+       adapter->networks = NULL;
+
+       /* Free the adapter object itself */
+       lbs_deb_fw("free adapter\n");
+       kfree(adapter);
+       priv->adapter = NULL;
 }
 
 /**
@@ -1198,9 +1136,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
        /* Allocate an Ethernet device and register it */
        if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
                lbs_pr_err("init ethX device failed\n");
-               return NULL;
+               goto done;
        }
-       priv = dev->priv;
+       dmdev->driver_data = priv = dev->priv;
 
        /* allocate buffer for wlan_adapter */
        if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
@@ -1208,10 +1146,16 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
                goto err_kzalloc;
        }
 
+       if (libertas_init_adapter(priv)) {
+               lbs_pr_err("failed to initialize adapter structure.\n");
+               goto err_init_adapter;
+       }
+
        priv->dev = dev;
        priv->card = card;
        priv->mesh_open = 0;
        priv->infra_open = 0;
+       priv->hotplug_device = dmdev;
 
        SET_MODULE_OWNER(dev);
 
@@ -1234,86 +1178,144 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
 
        SET_NETDEV_DEV(dev, dmdev);
 
-       INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
-       INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
-
-       spin_lock_init(&priv->adapter->driver_lock);
-       init_waitqueue_head(&priv->adapter->cmd_pending);
-       priv->adapter->nr_cmd_pending = 0;
        priv->rtap_net_dev = NULL;
        if (device_create_file(dmdev, &dev_attr_libertas_rtap))
-               goto err_kzalloc;
+               goto err_init_adapter;
+
+       lbs_deb_thread("Starting main thread...\n");
+       init_waitqueue_head(&priv->waitq);
+       priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+       if (IS_ERR(priv->main_thread)) {
+               lbs_deb_thread("Error creating main thread.\n");
+               goto err_kthread_run;
+       }
+
+       priv->work_thread = create_singlethread_workqueue("libertas_worker");
+       INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+       INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
+       INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+
        goto done;
 
+err_kthread_run:
+       device_remove_file(dmdev, &dev_attr_libertas_rtap);
+
+err_init_adapter:
+       libertas_free_adapter(priv);
+
 err_kzalloc:
        free_netdev(dev);
        priv = NULL;
+
 done:
        lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
        return priv;
 }
 EXPORT_SYMBOL_GPL(libertas_add_card);
 
-int libertas_activate_card(wlan_private *priv)
+
+int libertas_remove_card(wlan_private *priv)
 {
+       wlan_adapter *adapter = priv->adapter;
        struct net_device *dev = priv->dev;
-       int ret = -1;
+       union iwreq_data wrqu;
 
        lbs_deb_enter(LBS_DEB_MAIN);
 
-       lbs_deb_thread("Starting main thread...\n");
-       init_waitqueue_head(&priv->waitq);
-       priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
-       if (IS_ERR(priv->main_thread)) {
-               lbs_deb_thread("Error creating main thread.\n");
-               goto done;
-       }
+       libertas_remove_rtap(priv);
 
-       priv->assoc_thread =
-               create_singlethread_workqueue("libertas_assoc");
-       INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
-       INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+       dev = priv->dev;
+       device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
 
-       /*
-        * Register the device. Fillup the private data structure with
-        * relevant information from the card and request for the required
-        * IRQ.
-        */
-       if (priv->hw_register_dev(priv) < 0) {
-               lbs_pr_err("failed to register WLAN device\n");
-               goto err_registerdev;
-       }
+       cancel_delayed_work(&priv->scan_work);
+       cancel_delayed_work(&priv->assoc_work);
+       destroy_workqueue(priv->work_thread);
 
-       /* init FW and HW */
-       if (libertas_init_fw(priv)) {
-               lbs_pr_err("firmware init failed\n");
-               goto err_registerdev;
+       if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+               adapter->psmode = WLAN802_11POWERMODECAM;
+               libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
        }
 
+       memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+       /* Stop the thread servicing the interrupts */
+       adapter->surpriseremoved = 1;
+       kthread_stop(priv->main_thread);
+
+       libertas_free_adapter(priv);
+
+       priv->dev = NULL;
+       free_netdev(dev);
+
+       lbs_deb_leave(LBS_DEB_MAIN);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(libertas_remove_card);
+
+
+int libertas_start_card(wlan_private *priv)
+{
+       struct net_device *dev = priv->dev;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       /* poke the firmware */
+       ret = wlan_setup_firmware(priv);
+       if (ret)
+               goto done;
+
+       /* init 802.11d */
+       libertas_init_11d(priv);
+
        if (register_netdev(dev)) {
                lbs_pr_err("cannot register ethX device\n");
-               goto err_init_fw;
+               goto done;
        }
 
-       lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
-
        libertas_debugfs_init_one(priv, dev);
 
+       lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+
        ret = 0;
-       goto done;
 
-err_init_fw:
-       priv->hw_unregister_dev(priv);
-err_registerdev:
-       destroy_workqueue(priv->assoc_thread);
-       /* Stop the thread servicing the interrupts */
-       wake_up_interruptible(&priv->waitq);
-       kthread_stop(priv->main_thread);
 done:
-       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
        return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_activate_card);
+EXPORT_SYMBOL_GPL(libertas_start_card);
+
+
+int libertas_stop_card(wlan_private *priv)
+{
+       struct net_device *dev = priv->dev;
+       int ret = -1;
+       struct cmd_ctrl_node *cmdnode;
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       netif_stop_queue(priv->dev);
+       netif_carrier_off(priv->dev);
+
+       libertas_debugfs_remove_one(priv);
+
+       /* Flush pending command nodes */
+       spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+       list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+               cmdnode->cmdwaitqwoken = 1;
+               wake_up_interruptible(&cmdnode->cmdwait_q);
+       }
+       spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+
+       unregister_netdev(dev);
+
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_stop_card);
 
 
 /**
@@ -1383,88 +1385,12 @@ done:
 }
 EXPORT_SYMBOL_GPL(libertas_add_mesh);
 
-static void wake_pending_cmdnodes(wlan_private *priv)
-{
-       struct cmd_ctrl_node *cmdnode;
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       spin_lock_irqsave(&priv->adapter->driver_lock, flags);
-       list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
-               cmdnode->cmdwaitqwoken = 1;
-               wake_up_interruptible(&cmdnode->cmdwait_q);
-       }
-       spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
-}
-
-
-int libertas_remove_card(wlan_private *priv)
-{
-       wlan_adapter *adapter;
-       struct net_device *dev;
-       union iwreq_data wrqu;
-
-       lbs_deb_enter(LBS_DEB_NET);
-
-       libertas_remove_rtap(priv);
-       if (!priv)
-               goto out;
-
-       adapter = priv->adapter;
-
-       if (!adapter)
-               goto out;
-
-       dev = priv->dev;
-       device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
-
-       netif_stop_queue(priv->dev);
-       netif_carrier_off(priv->dev);
-
-       wake_pending_cmdnodes(priv);
-
-       unregister_netdev(dev);
-
-       cancel_delayed_work(&priv->assoc_work);
-       destroy_workqueue(priv->assoc_thread);
-
-       if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
-               adapter->psmode = WLAN802_11POWERMODECAM;
-               libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-       }
-
-       memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-       adapter->surpriseremoved = 1;
-
-       /* Stop the thread servicing the interrupts */
-       kthread_stop(priv->main_thread);
-
-       libertas_debugfs_remove_one(priv);
-
-       lbs_deb_net("free adapter\n");
-       libertas_free_adapter(priv);
-
-       lbs_deb_net("unregister finish\n");
-
-       priv->dev = NULL;
-       free_netdev(dev);
-
-out:
-       lbs_deb_leave(LBS_DEB_NET);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(libertas_remove_card);
-
 
 void libertas_remove_mesh(wlan_private *priv)
 {
        struct net_device *mesh_dev;
 
-       lbs_deb_enter(LBS_DEB_NET);
+       lbs_deb_enter(LBS_DEB_MAIN);
 
        if (!priv)
                goto out;
@@ -1481,7 +1407,7 @@ void libertas_remove_mesh(wlan_private *priv)
        free_netdev(mesh_dev);
 
 out:
-       lbs_deb_leave(LBS_DEB_NET);
+       lbs_deb_leave(LBS_DEB_MAIN);
 }
 EXPORT_SYMBOL_GPL(libertas_remove_mesh);