wlan: Enable statically linked driver to switch modes.

Enable statically linked driver to switch modes based on module param
'con_mode'. add handler function to unload and reload driver when
con_mode is changed by userspace
FTM mode can be entered: echo 5 > /sys/module/wlan/parameters/con_mode
fix a problem where module_init and module_exit functions can't be
called repeatedly

Change-Id: Ief88c09de270df82f11019658876cf0f5a6d5bb7
CRs-Fixed: 394953
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 0abe528..9fa3ed3 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -141,6 +141,7 @@
 /* the Android framework expects this param even though we don't use it */
 #define BUF_LEN 20
 static char fwpath[BUF_LEN];
+static int wlan_hdd_inited = 0;
 
 /*
  * The rate at which the driver sends RESTART event to supplicant
@@ -288,9 +289,17 @@
 void hdd_unregister_mcast_bcast_filter(hdd_context_t *pHddCtx);
 void hdd_register_mcast_bcast_filter(hdd_context_t *pHddCtx);
 #endif
-#ifdef WLAN_SOFTAP_FEATURE
 //variable to hold the insmod parameters
 static int con_mode = 0;
+#ifndef MODULE
+/* current con_mode - used only for statically linked driver
+ * con_mode is changed by userspace to indicate a mode change which will
+ * result in calling the module exit and init functions. The module
+ * exit function will clean up based on the value of con_mode prior to it
+ * being changed by userspace. So curr_con_mode records the current con_mode 
+ * for exit when con_mode becomes the next mode for init
+ */
+static int curr_con_mode = 0;
 #endif
 
 #ifdef FEATURE_WLAN_INTEGRATED_SOC
@@ -4078,12 +4087,11 @@
    }
 #endif // ANI_BUS_TYPE_SDIO
 
-#if defined(FEATURE_WLAN_INTEGRATED_SOC) && defined(ANI_MANF_DIAG)
-      if(5 == con_mode)
-      {
-         hdd_set_conparam(VOS_FTM_MODE);
-      }
-#endif /* FEATURE_WLAN_INTEGRATED_SOC && ANI_MANF_DIAG */
+#ifndef MODULE
+      /* For statically linked driver, call hdd_set_conparam to update curr_con_mode
+       */
+      hdd_set_conparam((v_UINT_t)con_mode);
+#endif
 
       // Call our main init function
       if(hdd_wlan_startup(dev)) {
@@ -4190,13 +4198,11 @@
 static int fwpath_changed_handler(const char *kmessage,
                                  struct kernel_param *kp)
 {
-   static int drv_inited = 0;
-
-   if (drv_inited) {
+   if (wlan_hdd_inited) {
       return 0;
    }
 
-   drv_inited = 1;
+   wlan_hdd_inited = 1;
 
    return hdd_driver_init();
 }
@@ -4205,16 +4211,17 @@
 
 /**---------------------------------------------------------------------------
 
-  \brief hdd_module_exit() - Exit function
+  \brief hdd_driver_exit() - Exit function
 
-  This is the driver exit point (invoked when module is unloaded using rmmod)
+  This is the driver exit point (invoked when module is unloaded using rmmod
+  or con_mode was changed by userspace)
 
   \param  - None
 
   \return - None
 
   --------------------------------------------------------------------------*/
-static void __exit hdd_module_exit(void)
+static void hdd_driver_exit(void)
 {
    hdd_context_t *pHddCtx = NULL;
    v_CONTEXT_t pVosContext = NULL;
@@ -4272,9 +4279,66 @@
    pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME);
 }
 
+/**---------------------------------------------------------------------------
+
+  \brief hdd_module_exit() - Exit function
+
+  This is the driver exit point (invoked when module is unloaded using rmmod)
+
+  \param  - None
+
+  \return - None
+
+  --------------------------------------------------------------------------*/
+static void __exit hdd_module_exit(void)
+{
+   hdd_driver_exit();
+}
+
 #if defined(WLAN_SOFTAP_FEATURE) || defined(ANI_MANF_DIAG)
 /**---------------------------------------------------------------------------
 
+  \brief con_mode_handler() -
+
+  Handler function for module param con_mode when it is changed by userspace
+  Dynamically linked - do nothing
+  Statically linked - exit and init driver, as in rmmod and insmod
+
+  \param  - 
+
+  \return - 
+
+  --------------------------------------------------------------------------*/
+#ifdef MODULE
+static int con_mode_handler(const char *kmessage,
+                                 struct kernel_param *kp)
+{
+   return 0;
+}
+#else /* #ifdef MODULE */
+static int con_mode_handler(const char *kmessage,
+                                 struct kernel_param *kp)
+{
+   int ret = param_set_int(kmessage, kp);
+
+   if (ret)
+       return ret;
+
+   if (!wlan_hdd_inited) {
+      wlan_hdd_inited = 1;
+      return hdd_driver_init();
+   }
+
+   hdd_driver_exit();
+   
+   msleep(200);
+   
+   return hdd_driver_init();
+}
+#endif /* #ifdef MODULE */
+
+/**---------------------------------------------------------------------------
+
   \brief hdd_get_conparam() -
 
   This is the driver exit point (invoked when module is unloaded using rmmod)
@@ -4286,12 +4350,18 @@
   --------------------------------------------------------------------------*/
 tVOS_CON_MODE hdd_get_conparam ( void )
 {
+#ifdef MODULE
     return (tVOS_CON_MODE)con_mode;
-
+#else
+    return (tVOS_CON_MODE)curr_con_mode;
+#endif
 }
 void hdd_set_conparam ( v_UINT_t newParam )
 {
   con_mode = newParam;
+#ifndef MODULE
+  curr_con_mode = con_mode;
+#endif
 }
 /**---------------------------------------------------------------------------
 
@@ -4687,9 +4757,8 @@
 MODULE_AUTHOR("Qualcomm Atheros, Inc.");
 MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER");
 
-#if defined(WLAN_SOFTAP_FEATURE) || defined(ANI_MANF_DIAG)
-module_param(con_mode, int, 0);
-#endif
+module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
 module_param_call(fwpath, fwpath_changed_handler, param_get_string, fwpath,
                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);