Bluetooth: add bluetooth and wifi status sync change

In QCA6234, there is high power consumption when BT alone
is turned on because BT requires WLAN module to be out of
reset and WLAN module provides clock to BT. After BT turns
on WLAN's HSIC interface goes into reset mode, which consume
a lot of power. So adding sync between BT and WLAN module to
put hsic into auto suspend mode when BT alone is turned on.

Change-Id: I80fa8c784e95c8fc31ba75554676a72e4ae9fac4
diff --git a/libbt-vendor/Android.mk b/libbt-vendor/Android.mk
index 1091239..d57ae57 100644
--- a/libbt-vendor/Android.mk
+++ b/libbt-vendor/Android.mk
@@ -45,6 +45,10 @@
         -DBT_WAKE_VIA_PROC
 endif #BOARD_HAS_QCA_BT_AR3002
 
+ifeq ($(WIFI_BT_STATUS_SYNC), true)
+LOCAL_CFLAGS += -DWIFI_BT_STATUS_SYNC
+endif #WIFI_BT_STATUS_SYNC
+
 LOCAL_SHARED_LIBRARIES := \
         libcutils \
         liblog \
diff --git a/libbt-vendor/src/bt_vendor_qcom.c b/libbt-vendor/src/bt_vendor_qcom.c
index 6ac4abb..bf8c69f 100644
--- a/libbt-vendor/src/bt_vendor_qcom.c
+++ b/libbt-vendor/src/bt_vendor_qcom.c
@@ -69,6 +69,20 @@
 void hw_epilog_process(void);
 #endif
 
+#ifdef WIFI_BT_STATUS_SYNC
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include "cutils/properties.h"
+
+static const char WIFI_PROP_NAME[]    = "wlan.driver.status";
+static const char SERVICE_PROP_NAME[]    = "bluetooth.hsic_ctrl";
+static const char BT_STATUS_NAME[]    = "bluetooth.enabled";
+static const char WIFI_SERVICE_PROP[] = "wlan.hsic_ctrl";
+
+#define WIFI_BT_STATUS_LOCK    "/data/connectivity/wifi_bt_lock"
+int isInit=0;
+#endif /* WIFI_BT_STATUS_SYNC */
 
 /******************************************************************************
 **  Local type definitions
@@ -78,6 +92,82 @@
 /******************************************************************************
 **  Functions
 ******************************************************************************/
+#ifdef WIFI_BT_STATUS_SYNC
+int bt_semaphore_create(void)
+{
+    int fd;
+
+    fd = open(WIFI_BT_STATUS_LOCK, O_RDONLY);
+
+    if (fd < 0)
+        ALOGE("can't create file\n");
+
+    return fd;
+}
+
+int bt_semaphore_get(int fd)
+{
+    int ret;
+
+    if (fd < 0)
+        return -1;
+
+    ret = flock(fd, LOCK_EX);
+    if (ret != 0) {
+        ALOGE("can't hold lock: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return ret;
+}
+
+int bt_semaphore_release(int fd)
+{
+    int ret;
+
+    if (fd < 0)
+        return -1;
+
+    ret = flock(fd, LOCK_UN);
+    if (ret != 0) {
+        ALOGE("can't release lock: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return ret;
+}
+
+int bt_semaphore_destroy(int fd)
+{
+    if (fd < 0)
+        return -1;
+
+    return close (fd);
+}
+
+int bt_wait_for_service_done(void)
+{
+    char service_status[PROPERTY_VALUE_MAX];
+    int count = 30;
+
+    ALOGE("%s: check\n", __func__);
+
+    /* wait for service done */
+    while (count-- > 0) {
+        property_get(WIFI_SERVICE_PROP, service_status, NULL);
+
+        if (strcmp(service_status, "") != 0) {
+            usleep(200000);
+        }
+	else {
+            break;
+	}
+    }
+
+    return 0;
+}
+
+#endif /* WIFI_BT_STATUS_SYNC */
 
 /** Get Bluetooth SoC type from system setting */
 static int get_bt_soc_type()
@@ -203,6 +293,11 @@
     char state;
     char on = (en)?'1':'0';
 
+#ifdef WIFI_BT_STATUS_SYNC
+    char wifi_status[PROPERTY_VALUE_MAX];
+    int lock_fd;
+#endif /*WIFI_BT_STATUS_SYNC*/
+
     ALOGI("bt_powerup: %c", on);
 
     /* Check if rfkill has been disabled */
@@ -217,6 +312,12 @@
         return -1;
     }
 
+#ifdef WIFI_BT_STATUS_SYNC
+    lock_fd = bt_semaphore_create();
+    bt_semaphore_get(lock_fd);
+    bt_wait_for_service_done();
+#endif
+
     /* Assign rfkill_id and find bluetooth rfkill state path*/
     for(i=0;(rfkill_id == -1) && (rfkill_state == NULL);i++)
     {
@@ -224,6 +325,11 @@
         if ((fd = open(rfkill_type, O_RDONLY)) < 0)
         {
             ALOGE("open(%s) failed: %s (%d)\n", rfkill_type, strerror(errno), errno);
+
+#ifdef WIFI_BT_STATUS_SYNC
+            bt_semaphore_release(lock_fd);
+            bt_semaphore_destroy(lock_fd);
+#endif
             return -1;
         }
 
@@ -241,11 +347,20 @@
     if ((fd = open(rfkill_state, O_RDWR)) < 0)
     {
         ALOGE("open(%s) for write failed: %s (%d)",rfkill_state, strerror(errno), errno);
+#ifdef WIFI_BT_STATUS_SYNC
+        bt_semaphore_release(lock_fd);
+        bt_semaphore_destroy(lock_fd);
+#endif
+
         return -1;
     }
 
     if(can_perform_action(on) == false) {
         ALOGE("%s:can't perform action as it is being used by other clients", __func__);
+#ifdef WIFI_BT_STATUS_SYNC
+        bt_semaphore_release(lock_fd);
+        bt_semaphore_destroy(lock_fd);
+#endif
         goto done;
     }
 
@@ -254,7 +369,11 @@
     /* Write value to control rfkill */
     if ((size = write(fd, &on, 1)) < 0) {
         ALOGE("write(%s) failed: %s (%d)",rfkill_state, strerror(errno),errno);
-        return -1;
+#ifdef WIFI_BT_STATUS_SYNC
+        bt_semaphore_release(lock_fd);
+        bt_semaphore_destroy(lock_fd);
+#endif
+	return -1;
     }
 
     if(on == '0'){
@@ -263,6 +382,45 @@
         property_set("wc_transport.soc_initialized", "0");
     }
 
+#ifdef WIFI_BT_STATUS_SYNC
+    /* query wifi status */
+    property_get(WIFI_PROP_NAME, wifi_status, "");
+
+    ALOGE("bt get wifi status: %s, isInit: %d\n",  wifi_status, isInit);
+
+    /* If wlan driver is not loaded, and bt is changed from off => on */
+    if (strncmp(wifi_status, "unloaded", strlen("unloaded")) == 0 || strlen(wifi_status) == 0) {
+        if (on == '1') {
+            ALOGI("%s: BT_VND_PWR_ON\n", __func__);
+            if(property_set(SERVICE_PROP_NAME, "load_wlan") < 0) {
+                ALOGE("%s Property setting failed", SERVICE_PROP_NAME);
+                close(fd);
+                bt_semaphore_release(lock_fd);
+                bt_semaphore_destroy(lock_fd);
+                return -1;
+            }
+        }
+        else if (isInit == 0 && on == '0') {
+            ALOGI("%s: BT_VND_PWR_OFF\n", __func__);
+            if(property_set(SERVICE_PROP_NAME, "unbind_hsic") < 0) {
+                ALOGE("%s Property setting failed", SERVICE_PROP_NAME);
+                close(fd);
+                bt_semaphore_release(lock_fd);
+                bt_semaphore_destroy(lock_fd);
+                return -1;
+            }
+       }
+    }
+
+    if (isInit == 0 && on == '0')
+        property_set(BT_STATUS_NAME, "false");
+    else if (on == '1')
+        property_set(BT_STATUS_NAME, "true");
+
+    bt_semaphore_release(lock_fd);
+    bt_semaphore_destroy(lock_fd);
+#endif /* WIFI_BT_STATUS_SYNC */
+
 done:
     if (fd >= 0)
         close(fd);
@@ -322,6 +480,11 @@
                                                 vnd_local_bd_addr[3],
                                                 vnd_local_bd_addr[4],
                                                 vnd_local_bd_addr[5]);
+
+#ifdef WIFI_BT_STATUS_SYNC
+    isInit = 1;
+#endif /* WIFI_BT_STATUS_SYNC */
+
     return 0;
 }
 
@@ -681,6 +844,10 @@
 {
     ALOGI("cleanup");
     bt_vendor_cbacks = NULL;
+
+#ifdef WIFI_BT_STATUS_SYNC
+    isInit = 0;
+#endif /* WIFI_BT_STATUS_SYNC */
 }
 
 // Entry point of DLib