From 0fb6684e8b12b90313771fcc2ded461e79161baa Mon Sep 17 00:00:00 2001 From: Pradeep Panigrahi Date: Tue, 28 Jan 2014 15:04:08 +0530 Subject: 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 --- libbt-vendor/Android.mk | 4 + libbt-vendor/src/bt_vendor_qcom.c | 169 +++++++++++++++++++++++++++++++++++++- 2 files changed, 172 insertions(+), 1 deletion(-) (limited to 'libbt-vendor') 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 @@ LOCAL_C_FLAGS := \ -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 @@ static const tUSERIAL_CFG userial_init_cfg = void hw_epilog_process(void); #endif +#ifdef WIFI_BT_STATUS_SYNC +#include +#include +#include +#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 @@ void hw_epilog_process(void); /****************************************************************************** ** 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 @@ static int bt_powerup(int en ) 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 @@ static int bt_powerup(int en ) 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 @@ static int bt_powerup(int en ) 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 @@ static int bt_powerup(int en ) 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 @@ static int bt_powerup(int en ) /* 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 @@ static int bt_powerup(int en ) 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 @@ static int init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr) 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 @@ static void cleanup( void ) { ALOGI("cleanup"); bt_vendor_cbacks = NULL; + +#ifdef WIFI_BT_STATUS_SYNC + isInit = 0; +#endif /* WIFI_BT_STATUS_SYNC */ } // Entry point of DLib -- cgit v1.2.3