From 105961ebfd8349e3789d23086b84640b5100e43e Mon Sep 17 00:00:00 2001 From: YK Jeffrey Chao Date: Wed, 17 Oct 2012 21:31:07 -0700 Subject: Add new user-to-kernel interface for Bluetooth low power mode control (1/2) The bluesleep kernel module was used in Tegra3 platform to perform Bluetooth low power wakelock and interrup control. Add new user-to-kernel interface through proc fs nodes for Bluedroid to feed bluesleep with the HCI_DEV events which bluesleep was monitoring on. bug 7347413 Change-Id: I791be1042d5573e5207aa81e3d59fa418134f9fe Conflicts: libbt/include/vnd_manta.txt --- libbt/include/bt_vendor_brcm.h | 7 ++ libbt/include/upio.h | 1 + libbt/include/vnd_crespo.txt | 1 - libbt/include/vnd_crespo4g.txt | 1 - libbt/include/vnd_generic.txt | 1 - libbt/include/vnd_generic_x86.txt | 1 - libbt/include/vnd_grouper.txt | 2 +- libbt/include/vnd_maguro.txt | 1 - libbt/include/vnd_mako.txt | 1 - libbt/include/vnd_manta.txt | 1 - libbt/include/vnd_phantasm.txt | 1 - libbt/include/vnd_stingray.txt | 1 - libbt/include/vnd_tilapia.txt | 2 +- libbt/include/vnd_wingray.txt | 1 - libbt/src/bt_vendor_brcm.c | 2 +- libbt/src/hardware.c | 2 + libbt/src/upio.c | 209 ++++++++++++++++++++++++++++++++++++-- 17 files changed, 212 insertions(+), 23 deletions(-) diff --git a/libbt/include/bt_vendor_brcm.h b/libbt/include/bt_vendor_brcm.h index fff1925..858b71b 100644 --- a/libbt/include/bt_vendor_brcm.h +++ b/libbt/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/libbt/include/upio.h b/libbt/include/upio.h index 32920e6..aa4fadc 100644 --- a/libbt/include/upio.h +++ b/libbt/include/upio.h @@ -38,6 +38,7 @@ enum { UPIO_BT_WAKE = 0, UPIO_HOST_WAKE, + UPIO_LPM_MODE, UPIO_MAX_COUNT }; diff --git a/libbt/include/vnd_crespo.txt b/libbt/include/vnd_crespo.txt index 3596b6f..2ba0780 100644 --- a/libbt/include/vnd_crespo.txt +++ b/libbt/include/vnd_crespo.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/s3c2410_serial0" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_PCM_IF_CLOCK_RATE = 0 BTVND_DBG = FALSE diff --git a/libbt/include/vnd_crespo4g.txt b/libbt/include/vnd_crespo4g.txt index 3596b6f..2ba0780 100644 --- a/libbt/include/vnd_crespo4g.txt +++ b/libbt/include/vnd_crespo4g.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/s3c2410_serial0" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_PCM_IF_CLOCK_RATE = 0 BTVND_DBG = FALSE diff --git a/libbt/include/vnd_generic.txt b/libbt/include/vnd_generic.txt index 43e790c..18964f2 100644 --- a/libbt/include/vnd_generic.txt +++ b/libbt/include/vnd_generic.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_USE_I2S_INTERFACE = TRUE BTVND_DBG = FALSE diff --git a/libbt/include/vnd_generic_x86.txt b/libbt/include/vnd_generic_x86.txt index 43e790c..18964f2 100644 --- a/libbt/include/vnd_generic_x86.txt +++ b/libbt/include/vnd_generic_x86.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_USE_I2S_INTERFACE = TRUE BTVND_DBG = FALSE diff --git a/libbt/include/vnd_grouper.txt b/libbt/include/vnd_grouper.txt index 65ef840..3e4d71c 100755 --- a/libbt/include/vnd_grouper.txt +++ b/libbt/include/vnd_grouper.txt @@ -1,6 +1,6 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" FW_PATCHFILE_LOCATION = "/etc/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE +BT_WAKE_VIA_PROC = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 BTVND_DBG = FALSE BTHW_DBG = TRUE diff --git a/libbt/include/vnd_maguro.txt b/libbt/include/vnd_maguro.txt index 43e790c..18964f2 100644 --- a/libbt/include/vnd_maguro.txt +++ b/libbt/include/vnd_maguro.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_USE_I2S_INTERFACE = TRUE BTVND_DBG = FALSE diff --git a/libbt/include/vnd_mako.txt b/libbt/include/vnd_mako.txt index 43e790c..18964f2 100644 --- a/libbt/include/vnd_mako.txt +++ b/libbt/include/vnd_mako.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_USE_I2S_INTERFACE = TRUE BTVND_DBG = FALSE diff --git a/libbt/include/vnd_manta.txt b/libbt/include/vnd_manta.txt index fc58fb3..b2809d1 100644 --- a/libbt/include/vnd_manta.txt +++ b/libbt/include/vnd_manta.txt @@ -1,7 +1,6 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttySAC0" FW_PATCHFILE_LOCATION = "/vendor/firmware/" UART_TARGET_BAUD_RATE = 921600 -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_USE_I2S_INTERFACE = TRUE SCO_I2SPCM_IF_ROLE = 0 diff --git a/libbt/include/vnd_phantasm.txt b/libbt/include/vnd_phantasm.txt index 43e790c..18964f2 100644 --- a/libbt/include/vnd_phantasm.txt +++ b/libbt/include/vnd_phantasm.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" FW_PATCHFILE_LOCATION = "/vendor/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 SCO_USE_I2S_INTERFACE = TRUE BTVND_DBG = FALSE diff --git a/libbt/include/vnd_stingray.txt b/libbt/include/vnd_stingray.txt index 3667e65..f5eb1d0 100755 --- a/libbt/include/vnd_stingray.txt +++ b/libbt/include/vnd_stingray.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" FW_PATCHFILE_LOCATION = "/etc/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 BTVND_DBG = FALSE BTHW_DBG = TRUE diff --git a/libbt/include/vnd_tilapia.txt b/libbt/include/vnd_tilapia.txt index 65ef840..3e4d71c 100755 --- a/libbt/include/vnd_tilapia.txt +++ b/libbt/include/vnd_tilapia.txt @@ -1,6 +1,6 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" FW_PATCHFILE_LOCATION = "/etc/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE +BT_WAKE_VIA_PROC = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 BTVND_DBG = FALSE BTHW_DBG = TRUE diff --git a/libbt/include/vnd_wingray.txt b/libbt/include/vnd_wingray.txt index 3667e65..f5eb1d0 100755 --- a/libbt/include/vnd_wingray.txt +++ b/libbt/include/vnd_wingray.txt @@ -1,6 +1,5 @@ BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" FW_PATCHFILE_LOCATION = "/etc/firmware/" -BT_WAKE_VIA_USERIAL_IOCTL = TRUE LPM_IDLE_TIMEOUT_MULTIPLE = 5 BTVND_DBG = FALSE BTHW_DBG = TRUE diff --git a/libbt/src/bt_vendor_brcm.c b/libbt/src/bt_vendor_brcm.c index d17baa2..9bd8922 100644 --- a/libbt/src/bt_vendor_brcm.c +++ b/libbt/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/libbt/src/hardware.c b/libbt/src/hardware.c index 397507d..45008ef 100644 --- a/libbt/src/hardware.c +++ b/libbt/src/hardware.c @@ -1045,10 +1045,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/libbt/src/upio.c b/libbt/src/upio.c index d32f334..2de171c 100644 --- a/libbt/src/upio.c +++ b/libbt/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,33 +325,157 @@ 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_BT_WAKE: + 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) + { + buffer = '1'; + } + else + { + 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; } upio_state[UPIO_BT_WAKE] = action; - /**************************************** - * !!! TODO !!! - * - * === Custom Porting Required === - * - * Platform dependent user-to-kernel - * interface is required to set output - * state of physical BT_WAKE pin. - ****************************************/ #if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE) + 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) + 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); + } + } + + UPIODBG("proc btwrite assertion"); + + if (fd >= 0) + close(fd); #endif + break; case UPIO_HOST_WAKE: -- cgit v1.1