From 5c85dac6030b183454d1ecf0a8455e8be60f4131 Mon Sep 17 00:00:00 2001 From: jiamin.miao Date: Mon, 27 May 2013 08:50:23 +0000 Subject: pd#74111:enable BT LPM function --- diff --git a/include/bt_vendor_brcm.h b/include/bt_vendor_brcm.h index e4d1c05..fb26dda 100755 --- a/include/bt_vendor_brcm.h +++ b/include/bt_vendor_brcm.h @@ -202,6 +202,13 @@ #define BT_WAKE_VIA_USERIAL_IOCTL FALSE #endif +/* BT_WAKE_VIA_PROC + + LPM & BT_WAKE control through PROC nodes + */ +#ifndef BT_WAKE_VIA_PROC +#define BT_WAKE_VIA_PROC FALSE +#endif /* SCO_CFG_INCLUDED diff --git a/include/upio.h b/include/upio.h index 32920e6..aa4fadc 100755 --- a/include/upio.h +++ b/include/upio.h @@ -38,6 +38,7 @@ enum { UPIO_BT_WAKE = 0, UPIO_HOST_WAKE, + UPIO_LPM_MODE, UPIO_MAX_COUNT }; diff --git a/include/vnd_40183_lpm.txt b/include/vnd_40183_lpm.txt new file mode 100755 index 0000000..dbf7fbc --- a/dev/null +++ b/include/vnd_40183_lpm.txt @@ -0,0 +1,13 @@ +BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyS1" +FW_PATCHFILE_LOCATION = "/etc/bluetooth/" +BT_WAKE_VIA_PROC = TRUE +BT_WAKE_VIA_USERIAL_IOCTL = FALSE +LPM_SLEEP_MODE = 1 +LPM_IDLE_TIMEOUT_MULTIPLE = 5 +SCO_USE_I2S_INTERFACE = TRUE +BTVND_DBG = FALSE +BTHW_DBG = TRUE +VNDUSERIAL_DBG = FALSE +UPIO_DBG = TRUE +UART_TARGET_BAUD_RATE=2000000 +FW_PATCH_SETTLEMENT_DELAY_MS=200 diff --git a/src/bt_vendor_brcm.c b/src/bt_vendor_brcm.c index d17baa2..9bd8922 100755 --- a/src/bt_vendor_brcm.c +++ b/src/bt_vendor_brcm.c @@ -197,7 +197,7 @@ static int op(bt_vendor_opcode_t opcode, void *param) case BT_VND_OP_LPM_WAKE_SET_STATE: { uint8_t *state = (uint8_t *) param; - uint8_t wake_assert = (state == BT_VND_LPM_WAKE_ASSERT) ? \ + uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \ TRUE : FALSE; hw_lpm_set_wake_state(wake_assert); diff --git a/src/hardware.c b/src/hardware.c index 414ee2e..180325c 100755 --- a/src/hardware.c +++ b/src/hardware.c @@ -1048,10 +1048,12 @@ uint8_t hw_lpm_enable(uint8_t turn_on) if (turn_on) { memcpy(p, &lpm_param, LPM_CMD_PARAM_SIZE); + upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0); } else { memset(p, 0, LPM_CMD_PARAM_SIZE); + upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0); } if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_SLEEP_MODE, p_buf, \ diff --git a/src/upio.c b/src/upio.c index d32f334..4940f8e 100755 --- a/src/upio.c +++ b/src/upio.c @@ -54,6 +54,39 @@ ** Local type definitions ******************************************************************************/ +#if (BT_WAKE_VIA_PROC == TRUE) + +/* proc fs node for enable/disable lpm mode */ +#ifndef VENDOR_LPM_PROC_NODE +#define VENDOR_LPM_PROC_NODE "/proc/bluetooth/sleep/lpm" +#endif + +/* proc fs node for notifying write request */ +#ifndef VENDOR_BTWRITE_PROC_NODE +#define VENDOR_BTWRITE_PROC_NODE "/proc/bluetooth/sleep/btwrite" +#endif + +/* + * Maximum btwrite assertion holding time without consecutive btwrite kicking. + * This value is correlative(shorter) to the in-activity timeout period set in + * the bluesleep LPM code. The current value used in bluesleep is 10sec. + */ +#ifndef PROC_BTWRITE_TIMER_TIMEOUT_MS +#define PROC_BTWRITE_TIMER_TIMEOUT_MS 8000 +#endif + +/* lpm proc control block */ +typedef struct +{ + uint8_t btwrite_active; + uint8_t timer_created; + timer_t timer_id; + uint32_t timeout_ms; +} vnd_lpm_proc_cb_t; + +static vnd_lpm_proc_cb_t lpm_proc_cb; +#endif + /****************************************************************************** ** Static variables ******************************************************************************/ @@ -68,6 +101,12 @@ static char *rfkill_state_path = NULL; ******************************************************************************/ /* for friendly debugging outpout string */ +static char *lpm_mode[] = { + "UNKNOWN", + "disabled", + "enabled" +}; + static char *lpm_state[] = { "UNKNOWN", "de-asserted", @@ -141,6 +180,23 @@ static int init_rfkill() ** LPM Static Functions *****************************************************************************/ +#if (BT_WAKE_VIA_PROC == TRUE) +/******************************************************************************* +** +** Function proc_btwrite_timeout +** +** Description Timeout thread of proc/.../btwrite assertion holding timer +** +** Returns None +** +*******************************************************************************/ +static void proc_btwrite_timeout(union sigval arg) +{ + UPIODBG("..%s..", __FUNCTION__); + lpm_proc_cb.btwrite_active = FALSE; +} +#endif + /***************************************************************************** ** UPIO Interface Functions *****************************************************************************/ @@ -157,6 +213,9 @@ static int init_rfkill() void upio_init(void) { memset(upio_state, UPIO_UNKNOWN, UPIO_MAX_COUNT); +#if (BT_WAKE_VIA_PROC == TRUE) + memset(&lpm_proc_cb, 0, sizeof(vnd_lpm_proc_cb_t)); +#endif } /******************************************************************************* @@ -170,6 +229,12 @@ void upio_init(void) *******************************************************************************/ void upio_cleanup(void) { +#if (BT_WAKE_VIA_PROC == TRUE) + if (lpm_proc_cb.timer_created == TRUE) + timer_delete(lpm_proc_cb.timer_id); + + lpm_proc_cb.timer_created = FALSE; +#endif } /******************************************************************************* @@ -260,14 +325,102 @@ int upio_set_bluetooth_power(int on) void upio_set(uint8_t pio, uint8_t action, uint8_t polarity) { int rc; +#if (BT_WAKE_VIA_PROC == TRUE) + int fd = -1; + char buffer; +#endif switch (pio) { + case UPIO_LPM_MODE: + if (upio_state[UPIO_LPM_MODE] == action) + { + UPIODBG("LPM is %s already", lpm_mode[action]); + return; + } + + upio_state[UPIO_LPM_MODE] = action; + +#if (BT_WAKE_VIA_PROC == TRUE) + fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY); + + if (fd < 0) + { + ALOGE("upio_set : open(%s) for write failed: %s (%d)", + VENDOR_LPM_PROC_NODE, strerror(errno), errno); + return; + } + + if (action == UPIO_ASSERT) + { + UPIODBG("LPM asserted"); + buffer = '1'; + } + else + { + UPIODBG("LPM deasserted"); + buffer = '0'; + + // delete btwrite assertion holding timer + if (lpm_proc_cb.timer_created == TRUE) + { + timer_delete(lpm_proc_cb.timer_id); + lpm_proc_cb.timer_created = FALSE; + } + } + + if (write(fd, &buffer, 1) < 0) + { + ALOGE("upio_set : write(%s) failed: %s (%d)", + VENDOR_LPM_PROC_NODE, strerror(errno),errno); + } + else + { + if (action == UPIO_ASSERT) + { + // create btwrite assertion holding timer + if (lpm_proc_cb.timer_created == FALSE) + { + int status; + struct sigevent se; + + se.sigev_notify = SIGEV_THREAD; + se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id; + se.sigev_notify_function = proc_btwrite_timeout; + se.sigev_notify_attributes = NULL; + + status = timer_create(CLOCK_MONOTONIC, &se, + &lpm_proc_cb.timer_id); + + if (status == 0) + lpm_proc_cb.timer_created = TRUE; + } + } + } + + if (fd >= 0) + close(fd); +#endif + break; + case UPIO_BT_WAKE: if (upio_state[UPIO_BT_WAKE] == action) { UPIODBG("BT_WAKE is %s already", lpm_state[action]); + +#if (BT_WAKE_VIA_PROC == TRUE) + if (lpm_proc_cb.btwrite_active == TRUE) + /* + * The proc btwrite node could have not been updated for + * certain time already due to heavy downstream path flow. + * In this case, we want to explicity touch proc btwrite + * node to keep the bt_wake assertion in the LPM kernel + * driver. The current kernel bluesleep LPM code starts + * a 10sec internal in-activity timeout timer before it + * attempts to deassert BT_WAKE line. + */ +#endif return; } @@ -286,6 +439,55 @@ void upio_set(uint8_t pio, uint8_t action, uint8_t polarity) userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \ USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),\ NULL); + +#elif (BT_WAKE_VIA_PROC == TRUE) + + /* + * Kick proc btwrite node only at UPIO_ASSERT + */ + if (action == UPIO_DEASSERT) + { + UPIODBG("btwake deassertion"); + return; + } + + fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY); + + if (fd < 0) + { + ALOGE("upio_set : open(%s) for write failed: %s (%d)", + VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno); + return; + } + + buffer = '1'; + + if (write(fd, &buffer, 1) < 0) + { + ALOGE("upio_set : write(%s) failed: %s (%d)", + VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno); + } + else + { + lpm_proc_cb.btwrite_active = TRUE; + + if (lpm_proc_cb.timer_created == TRUE) + { + struct itimerspec ts; + + ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS/1000; + ts.it_value.tv_nsec = 1000*(PROC_BTWRITE_TIMER_TIMEOUT_MS%1000); + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0); + } + } + //ms_delay(10); + UPIODBG("proc btwrite assertion"); + + if (fd >= 0) + close(fd); #endif break; diff --git a/vnd_buildcfg.mk b/vnd_buildcfg.mk index b9eace4..d67a79c 100755 --- a/vnd_buildcfg.mk +++ b/vnd_buildcfg.mk @@ -1,6 +1,10 @@ intermediates := $(local-intermediates-dir) +ifeq ($(BCM_BLUETOOTH_LPM_ENABLE),true) +SRC := $(call my-dir)/include/vnd_40183_lpm.txt +else SRC := $(call my-dir)/include/vnd_40183.txt +endif ifeq (,$(wildcard $(SRC))) # configuration file does not exist. Use default one SRC := $(call my-dir)/include/vnd_generic.txt -- cgit