[net-config] Suspend/Resume WLAN driver
[platform/core/connectivity/net-config.git] / src / wifi-power.c
index e052147..c900012 100755 (executable)
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <glib.h>
 #include <tzplatform_config.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
 
 #include "log.h"
 #include "util.h"
 
 #define NETCONFIG_TECH_WAITING_INTERVAL 500
 #define NETCONFIG_TECH_WAITING_COUNT 6
+#define MAX_DRV_CMD_SIZE 248
+#define WLAN_IOCTL_SUSPEND (SIOCDEVPRIVATE + 1)
 
 static gboolean connman_wifi_technology_state = FALSE;
 static gboolean wifi_firmware_recovery_mode = FALSE;
 static int airplane_mode = 0;
 
+typedef struct {
+       char *buf;
+       int used_len;
+       int total_len;
+} netconfig_wifi_priv_cmd;
+
 static gboolean __is_wifi_restricted(void)
 {
 #if defined TIZEN_WEARABLE
@@ -497,6 +507,66 @@ static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
 
 }
 
+void wifi_set_early_suspend(gboolean value)
+{
+       static gboolean old_state = FALSE;
+       struct ifreq ifr;
+       char buf[MAX_DRV_CMD_SIZE];
+       netconfig_wifi_priv_cmd priv_cmd;
+       int ret = 0;
+       int ioctl_sock = 0;
+       int pm_state = 0;
+       wifi_service_state_e wifi_state;
+
+       if (old_state == value) {
+               DBG("Old and new states are same");
+               return;
+       }
+
+       if (netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state) < 0)
+               ERR("Fail to get VCONFKEY_PM_STATE");
+
+       wifi_state = wifi_state_get_service_state();
+
+       if (value == TRUE &&
+                       (pm_state < VCONFKEY_PM_STATE_LCDOFF ||
+                        wifi_state == NETCONFIG_WIFI_ASSOCIATION ||
+                        wifi_state == NETCONFIG_WIFI_CONFIGURATION)){
+               DBG("");
+               return;
+       }
+
+       memset(buf, 0, sizeof(buf));
+       snprintf(buf, sizeof(buf), "SETSUSPENDMODE %d", value);
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+       g_strlcpy((char *)ifr.ifr_name, WIFI_IFNAME, IFNAMSIZ);
+
+       DBG("Early suspend command: [%s]", buf);
+
+       memset(&priv_cmd, 0, sizeof(priv_cmd));
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = sizeof(buf);
+       priv_cmd.total_len = sizeof(buf);
+       ifr.ifr_data = (char *)&priv_cmd;
+
+       ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+       if (ioctl_sock < 0) {
+               DBG("socket(PF_INET,SOCK_DGRAM) failed");
+               return;
+       }
+
+       ret = ioctl(ioctl_sock, WLAN_IOCTL_SUSPEND, &ifr);
+
+       if (ret < 0)
+               ERR("Fail to issue private commands: %d. %s", ret, strerror(errno));
+       else {
+               old_state = value;
+       }
+
+       close(ioctl_sock);
+}
+
 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
 {
        int new_state = -1;
@@ -523,9 +593,18 @@ static void __pm_state_changed_cb(keynode_t* node, void* user_data)
        DBG("Old PM state: %d, current: %d (1 normal / 2 lcddim / 3 lcdoff / 4 sleep)", prev_state, new_state);
 
        if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
+               /* Send early suspend mode based on LCD state and disallow early suspend count */
+               if (wifi_state != VCONFKEY_WIFI_OFF) {
+                       wifi_set_early_suspend(FALSE);
+                       DBG("Unset early suspend");
+               }
+
                netconfig_wifi_bgscan_stop();
                netconfig_wifi_bgscan_set_interval(SCAN_EXPONENTIAL_MIN);
                netconfig_wifi_bgscan_start(TRUE);
+       } else if ((new_state == VCONFKEY_PM_STATE_LCDOFF) && (prev_state < VCONFKEY_PM_STATE_LCDOFF) && (wifi_state != VCONFKEY_WIFI_OFF)) {
+               wifi_set_early_suspend(TRUE);
+               DBG("Set early suspend");
        }
 
        prev_state = new_state;