10b966c5eSopenharmony_ci/******************************************************************************
20b966c5eSopenharmony_ci *
30b966c5eSopenharmony_ci *  Copyright (C) 2009-2012 Broadcom Corporation
40b966c5eSopenharmony_ci *
50b966c5eSopenharmony_ci *  Licensed under the Apache License, Version 2.0 (the "License");
60b966c5eSopenharmony_ci *  you may not use this file except in compliance with the License.
70b966c5eSopenharmony_ci *  You may obtain a copy of the License at:
80b966c5eSopenharmony_ci *
90b966c5eSopenharmony_ci *  http://www.apache.org/licenses/LICENSE-2.0
100b966c5eSopenharmony_ci *
110b966c5eSopenharmony_ci *  Unless required by applicable law or agreed to in writing, software
120b966c5eSopenharmony_ci *  distributed under the License is distributed on an "AS IS" BASIS,
130b966c5eSopenharmony_ci *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140b966c5eSopenharmony_ci *  See the License for the specific language governing permissions and
150b966c5eSopenharmony_ci *  limitations under the License.
160b966c5eSopenharmony_ci *
170b966c5eSopenharmony_ci ******************************************************************************/
180b966c5eSopenharmony_ci
190b966c5eSopenharmony_ci/******************************************************************************
200b966c5eSopenharmony_ci *
210b966c5eSopenharmony_ci *  Filename:      upio.c
220b966c5eSopenharmony_ci *
230b966c5eSopenharmony_ci *  Description:   Contains I/O functions, like
240b966c5eSopenharmony_ci *                      rfkill control
250b966c5eSopenharmony_ci *                      BT_WAKE/HOST_WAKE control
260b966c5eSopenharmony_ci *
270b966c5eSopenharmony_ci ******************************************************************************/
280b966c5eSopenharmony_ci
290b966c5eSopenharmony_ci#define LOG_TAG "bt_upio"
300b966c5eSopenharmony_ci
310b966c5eSopenharmony_ci#include <fcntl.h>
320b966c5eSopenharmony_ci#include <errno.h>
330b966c5eSopenharmony_ci#include <string.h>
340b966c5eSopenharmony_ci#include <stdio.h>
350b966c5eSopenharmony_ci#include <unistd.h>
360b966c5eSopenharmony_ci#include <time.h>
370b966c5eSopenharmony_ci#include <utils/Log.h>
380b966c5eSopenharmony_ci#include "bt_vendor_brcm.h"
390b966c5eSopenharmony_ci#include "userial_vendor.h"
400b966c5eSopenharmony_ci#include "upio.h"
410b966c5eSopenharmony_ci
420b966c5eSopenharmony_ci/******************************************************************************
430b966c5eSopenharmony_ci**  Constants & Macros
440b966c5eSopenharmony_ci******************************************************************************/
450b966c5eSopenharmony_ci
460b966c5eSopenharmony_ci#ifndef UPIO_DBG
470b966c5eSopenharmony_ci#define UPIO_DBG FALSE
480b966c5eSopenharmony_ci#endif
490b966c5eSopenharmony_ci
500b966c5eSopenharmony_ci#if (UPIO_DBG == TRUE)
510b966c5eSopenharmony_ci#define UPIODBG(param, ...)         \
520b966c5eSopenharmony_ci    {                               \
530b966c5eSopenharmony_ci        HILOGD(param, ##__VA_ARGS__); \
540b966c5eSopenharmony_ci    }
550b966c5eSopenharmony_ci#else
560b966c5eSopenharmony_ci#define UPIODBG(param, ...)         \
570b966c5eSopenharmony_ci    {                               \
580b966c5eSopenharmony_ci        HILOGD(param, ##__VA_ARGS__); \
590b966c5eSopenharmony_ci    }
600b966c5eSopenharmony_ci#endif
610b966c5eSopenharmony_ci
620b966c5eSopenharmony_ci/******************************************************************************
630b966c5eSopenharmony_ci**  Local type definitions
640b966c5eSopenharmony_ci******************************************************************************/
650b966c5eSopenharmony_ci
660b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
670b966c5eSopenharmony_ci
680b966c5eSopenharmony_ci/* proc fs node for enable/disable lpm mode */
690b966c5eSopenharmony_ci#ifndef VENDOR_LPM_PROC_NODE
700b966c5eSopenharmony_ci#define VENDOR_LPM_PROC_NODE "/proc/bluetooth/sleep/lpm"
710b966c5eSopenharmony_ci#endif
720b966c5eSopenharmony_ci
730b966c5eSopenharmony_ci/* proc fs node for notifying write request */
740b966c5eSopenharmony_ci#ifndef VENDOR_BTWRITE_PROC_NODE
750b966c5eSopenharmony_ci#define VENDOR_BTWRITE_PROC_NODE "/proc/bluetooth/sleep/btwrite"
760b966c5eSopenharmony_ci#endif
770b966c5eSopenharmony_ci
780b966c5eSopenharmony_ci/*
790b966c5eSopenharmony_ci * Maximum btwrite assertion holding time without consecutive btwrite kicking.
800b966c5eSopenharmony_ci * This value is correlative(shorter) to the in-working timeout period set in
810b966c5eSopenharmony_ci * the bluesleep LPM code. The current value used in bluesleep is 10sec.
820b966c5eSopenharmony_ci */
830b966c5eSopenharmony_ci#ifndef PROC_BTWRITE_TIMER_TIMEOUT_MS
840b966c5eSopenharmony_ci#define PROC_BTWRITE_TIMER_TIMEOUT_MS 8000
850b966c5eSopenharmony_ci#endif
860b966c5eSopenharmony_ci
870b966c5eSopenharmony_ci/* lpm proc control block */
880b966c5eSopenharmony_citypedef struct {
890b966c5eSopenharmony_ci    uint8_t btwrite_active;
900b966c5eSopenharmony_ci    uint8_t timer_created;
910b966c5eSopenharmony_ci    timer_t timer_id;
920b966c5eSopenharmony_ci    uint32_t timeout_ms;
930b966c5eSopenharmony_ci} vnd_lpm_proc_cb_t;
940b966c5eSopenharmony_ci
950b966c5eSopenharmony_cistatic vnd_lpm_proc_cb_t lpm_proc_cb;
960b966c5eSopenharmony_ci#endif
970b966c5eSopenharmony_ci
980b966c5eSopenharmony_ci/******************************************************************************
990b966c5eSopenharmony_ci**  Static variables
1000b966c5eSopenharmony_ci******************************************************************************/
1010b966c5eSopenharmony_ci
1020b966c5eSopenharmony_cistatic uint8_t upio_state[UPIO_MAX_COUNT];
1030b966c5eSopenharmony_cistatic int rfkill_id = -1;
1040b966c5eSopenharmony_cistatic int bt_emul_enable = 0;
1050b966c5eSopenharmony_cistatic char rfkill_state_path[128];
1060b966c5eSopenharmony_ci
1070b966c5eSopenharmony_ci/******************************************************************************
1080b966c5eSopenharmony_ci**  Static functions
1090b966c5eSopenharmony_ci******************************************************************************/
1100b966c5eSopenharmony_ci
1110b966c5eSopenharmony_ci/* for friendly debugging outpout string */
1120b966c5eSopenharmony_cistatic char *lpm_mode[] = {
1130b966c5eSopenharmony_ci    "UNKNOWN",
1140b966c5eSopenharmony_ci    "disabled",
1150b966c5eSopenharmony_ci    "enabled"
1160b966c5eSopenharmony_ci};
1170b966c5eSopenharmony_ci
1180b966c5eSopenharmony_cistatic char *lpm_state[] = {
1190b966c5eSopenharmony_ci    "UNKNOWN",
1200b966c5eSopenharmony_ci    "de-asserted",
1210b966c5eSopenharmony_ci    "asserted"
1220b966c5eSopenharmony_ci};
1230b966c5eSopenharmony_ci
1240b966c5eSopenharmony_ci/*****************************************************************************
1250b966c5eSopenharmony_ci**   Bluetooth On/Off Static Functions
1260b966c5eSopenharmony_ci*****************************************************************************/
1270b966c5eSopenharmony_cistatic int is_emulator_context(void)
1280b966c5eSopenharmony_ci{
1290b966c5eSopenharmony_ci    return 0;
1300b966c5eSopenharmony_ci}
1310b966c5eSopenharmony_ci
1320b966c5eSopenharmony_cistatic int is_rfkill_disabled(void)
1330b966c5eSopenharmony_ci{
1340b966c5eSopenharmony_ci    return UPIO_BT_POWER_OFF;
1350b966c5eSopenharmony_ci}
1360b966c5eSopenharmony_ci
1370b966c5eSopenharmony_cistatic int init_rfkill(void)
1380b966c5eSopenharmony_ci{
1390b966c5eSopenharmony_ci    char path[64];
1400b966c5eSopenharmony_ci    char buf[16];
1410b966c5eSopenharmony_ci    int fd, sz, id;
1420b966c5eSopenharmony_ci
1430b966c5eSopenharmony_ci    for (id = 0;; id++) {
1440b966c5eSopenharmony_ci        if (snprintf_s(path, sizeof(path), sizeof(path), "/sys/class/rfkill/rfkill%d/type", id) < 0) {
1450b966c5eSopenharmony_ci            return -1;
1460b966c5eSopenharmony_ci        }
1470b966c5eSopenharmony_ci
1480b966c5eSopenharmony_ci        fd = open(path, O_RDONLY);
1490b966c5eSopenharmony_ci        if (fd < 0) {
1500b966c5eSopenharmony_ci            HILOGE("init_rfkill : open(%s) failed: %s (%d)\n",
1510b966c5eSopenharmony_ci                path, strerror(errno), errno);
1520b966c5eSopenharmony_ci            return -1;
1530b966c5eSopenharmony_ci        }
1540b966c5eSopenharmony_ci
1550b966c5eSopenharmony_ci        sz = read(fd, &buf, sizeof(buf));
1560b966c5eSopenharmony_ci        close(fd);
1570b966c5eSopenharmony_ci
1580b966c5eSopenharmony_ci        if (sz >= (int)strlen("bluetooth") && memcmp(buf, "bluetooth", strlen("bluetooth")) == 0) {
1590b966c5eSopenharmony_ci            rfkill_id = id;
1600b966c5eSopenharmony_ci            break;
1610b966c5eSopenharmony_ci        }
1620b966c5eSopenharmony_ci    }
1630b966c5eSopenharmony_ci
1640b966c5eSopenharmony_ci    (void)sprintf_s(rfkill_state_path, sizeof(rfkill_state_path), "/sys/class/rfkill/rfkill%d/state", rfkill_id);
1650b966c5eSopenharmony_ci    return 0;
1660b966c5eSopenharmony_ci}
1670b966c5eSopenharmony_ci
1680b966c5eSopenharmony_ci/*****************************************************************************
1690b966c5eSopenharmony_ci**   LPM Static Functions
1700b966c5eSopenharmony_ci*****************************************************************************/
1710b966c5eSopenharmony_ci
1720b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
1730b966c5eSopenharmony_ci/*******************************************************************************
1740b966c5eSopenharmony_ci**
1750b966c5eSopenharmony_ci** Function        proc_btwrite_timeout
1760b966c5eSopenharmony_ci**
1770b966c5eSopenharmony_ci** Description     Timeout thread of proc/.../btwrite assertion holding timer
1780b966c5eSopenharmony_ci**
1790b966c5eSopenharmony_ci** Returns         None
1800b966c5eSopenharmony_ci**
1810b966c5eSopenharmony_ci*******************************************************************************/
1820b966c5eSopenharmony_cistatic void proc_btwrite_timeout(union sigval arg)
1830b966c5eSopenharmony_ci{
1840b966c5eSopenharmony_ci    UPIODBG("..%s..", __FUNCTION__);
1850b966c5eSopenharmony_ci    lpm_proc_cb.btwrite_active = FALSE;
1860b966c5eSopenharmony_ci    /* drive LPM down; this timer should fire only when BT is awake; */
1870b966c5eSopenharmony_ci    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
1880b966c5eSopenharmony_ci}
1890b966c5eSopenharmony_ci
1900b966c5eSopenharmony_ci/******************************************************************************
1910b966c5eSopenharmony_ci **
1920b966c5eSopenharmony_ci ** Function      upio_start_stop_timer
1930b966c5eSopenharmony_ci **
1940b966c5eSopenharmony_ci ** Description   Arm user space timer in case lpm is left asserted
1950b966c5eSopenharmony_ci **
1960b966c5eSopenharmony_ci ** Returns       None
1970b966c5eSopenharmony_ci **
1980b966c5eSopenharmony_ci *****************************************************************************/
1990b966c5eSopenharmony_civoid upio_start_stop_timer(int action)
2000b966c5eSopenharmony_ci{
2010b966c5eSopenharmony_ci    struct itimerspec ts;
2020b966c5eSopenharmony_ci
2030b966c5eSopenharmony_ci    if (action == UPIO_ASSERT) {
2040b966c5eSopenharmony_ci        lpm_proc_cb.btwrite_active = TRUE;
2050b966c5eSopenharmony_ci        if (lpm_proc_cb.timer_created == TRUE) {
2060b966c5eSopenharmony_ci            ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS / BT_VENDOR_TIME_RAIDX;
2070b966c5eSopenharmony_ci            ts.it_value.tv_nsec = BT_VENDOR_TIME_RAIDX * BT_VENDOR_TIME_RAIDX *
2080b966c5eSopenharmony_ci                (PROC_BTWRITE_TIMER_TIMEOUT_MS % BT_VENDOR_TIME_RAIDX);
2090b966c5eSopenharmony_ci            ts.it_interval.tv_sec = 0;
2100b966c5eSopenharmony_ci            ts.it_interval.tv_nsec = 0;
2110b966c5eSopenharmony_ci        }
2120b966c5eSopenharmony_ci    } else {
2130b966c5eSopenharmony_ci        /* unarm timer if writing 0 to lpm; reduce unnecessary user space wakeup */
2140b966c5eSopenharmony_ci        (void)memset_s(&ts, sizeof(ts), 0, sizeof(ts));
2150b966c5eSopenharmony_ci    }
2160b966c5eSopenharmony_ci
2170b966c5eSopenharmony_ci    if (timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0) == 0) {
2180b966c5eSopenharmony_ci        UPIODBG("%s : timer_settime success", __FUNCTION__);
2190b966c5eSopenharmony_ci    } else {
2200b966c5eSopenharmony_ci        UPIODBG("%s : timer_settime failed", __FUNCTION__);
2210b966c5eSopenharmony_ci    }
2220b966c5eSopenharmony_ci}
2230b966c5eSopenharmony_ci#endif
2240b966c5eSopenharmony_ci
2250b966c5eSopenharmony_ci/*****************************************************************************
2260b966c5eSopenharmony_ci**   UPIO Interface Functions
2270b966c5eSopenharmony_ci*****************************************************************************/
2280b966c5eSopenharmony_ci
2290b966c5eSopenharmony_ci/*******************************************************************************
2300b966c5eSopenharmony_ci**
2310b966c5eSopenharmony_ci** Function        upio_init
2320b966c5eSopenharmony_ci**
2330b966c5eSopenharmony_ci** Description     Initialization
2340b966c5eSopenharmony_ci**
2350b966c5eSopenharmony_ci** Returns         None
2360b966c5eSopenharmony_ci**
2370b966c5eSopenharmony_ci*******************************************************************************/
2380b966c5eSopenharmony_civoid upio_init(void)
2390b966c5eSopenharmony_ci{
2400b966c5eSopenharmony_ci    memset_s(upio_state, sizeof(upio_state), UPIO_UNKNOWN, UPIO_MAX_COUNT);
2410b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
2420b966c5eSopenharmony_ci    memset_s(&lpm_proc_cb, sizeof(vnd_lpm_proc_cb_t), 0, sizeof(vnd_lpm_proc_cb_t));
2430b966c5eSopenharmony_ci#endif
2440b966c5eSopenharmony_ci}
2450b966c5eSopenharmony_ci
2460b966c5eSopenharmony_ci/*******************************************************************************
2470b966c5eSopenharmony_ci**
2480b966c5eSopenharmony_ci** Function        upio_cleanup
2490b966c5eSopenharmony_ci**
2500b966c5eSopenharmony_ci** Description     Clean up
2510b966c5eSopenharmony_ci**
2520b966c5eSopenharmony_ci** Returns         None
2530b966c5eSopenharmony_ci**
2540b966c5eSopenharmony_ci*******************************************************************************/
2550b966c5eSopenharmony_civoid upio_cleanup(void)
2560b966c5eSopenharmony_ci{
2570b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
2580b966c5eSopenharmony_ci    if (lpm_proc_cb.timer_created == TRUE)
2590b966c5eSopenharmony_ci        timer_delete(lpm_proc_cb.timer_id);
2600b966c5eSopenharmony_ci
2610b966c5eSopenharmony_ci    lpm_proc_cb.timer_created = FALSE;
2620b966c5eSopenharmony_ci#endif
2630b966c5eSopenharmony_ci}
2640b966c5eSopenharmony_ci
2650b966c5eSopenharmony_ci/*******************************************************************************
2660b966c5eSopenharmony_ci**
2670b966c5eSopenharmony_ci** Function        upio_set_bluetooth_power
2680b966c5eSopenharmony_ci**
2690b966c5eSopenharmony_ci** Description     Interact with low layer driver to set Bluetooth power
2700b966c5eSopenharmony_ci**                 on/off.
2710b966c5eSopenharmony_ci**
2720b966c5eSopenharmony_ci** Returns         0  : SUCCESS or Not-Applicable
2730b966c5eSopenharmony_ci**                 <0 : ERROR
2740b966c5eSopenharmony_ci**
2750b966c5eSopenharmony_ci*******************************************************************************/
2760b966c5eSopenharmony_ciint upio_set_bluetooth_power(int on)
2770b966c5eSopenharmony_ci{
2780b966c5eSopenharmony_ci    int sz;
2790b966c5eSopenharmony_ci    int fd = -1;
2800b966c5eSopenharmony_ci    int ret = -1;
2810b966c5eSopenharmony_ci    char buffer = '0';
2820b966c5eSopenharmony_ci
2830b966c5eSopenharmony_ci    switch (on) {
2840b966c5eSopenharmony_ci        case UPIO_BT_POWER_OFF:
2850b966c5eSopenharmony_ci            buffer = '0';
2860b966c5eSopenharmony_ci            break;
2870b966c5eSopenharmony_ci
2880b966c5eSopenharmony_ci        case UPIO_BT_POWER_ON:
2890b966c5eSopenharmony_ci            buffer = '1';
2900b966c5eSopenharmony_ci            break;
2910b966c5eSopenharmony_ci        default:
2920b966c5eSopenharmony_ci            return 0;
2930b966c5eSopenharmony_ci    }
2940b966c5eSopenharmony_ci
2950b966c5eSopenharmony_ci    if (is_emulator_context()) {
2960b966c5eSopenharmony_ci        /* if new value is same as current, return -1 */
2970b966c5eSopenharmony_ci        if (bt_emul_enable == on) {
2980b966c5eSopenharmony_ci            return ret;
2990b966c5eSopenharmony_ci        }
3000b966c5eSopenharmony_ci
3010b966c5eSopenharmony_ci        UPIODBG("set_bluetooth_power [emul] %d", on);
3020b966c5eSopenharmony_ci        bt_emul_enable = on;
3030b966c5eSopenharmony_ci        return 0;
3040b966c5eSopenharmony_ci    }
3050b966c5eSopenharmony_ci
3060b966c5eSopenharmony_ci    /* check if we have rfkill interface */
3070b966c5eSopenharmony_ci    if (is_rfkill_disabled()) {
3080b966c5eSopenharmony_ci        return 0;
3090b966c5eSopenharmony_ci    }
3100b966c5eSopenharmony_ci
3110b966c5eSopenharmony_ci    if (rfkill_id == -1) {
3120b966c5eSopenharmony_ci        if (init_rfkill()) {
3130b966c5eSopenharmony_ci            return ret;
3140b966c5eSopenharmony_ci        }
3150b966c5eSopenharmony_ci    }
3160b966c5eSopenharmony_ci
3170b966c5eSopenharmony_ci    fd = open(rfkill_state_path, O_WRONLY);
3180b966c5eSopenharmony_ci    if (fd < 0) {
3190b966c5eSopenharmony_ci        HILOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",
3200b966c5eSopenharmony_ci            rfkill_state_path, strerror(errno), errno);
3210b966c5eSopenharmony_ci        return ret;
3220b966c5eSopenharmony_ci    }
3230b966c5eSopenharmony_ci
3240b966c5eSopenharmony_ci    sz = write(fd, &buffer, 1);
3250b966c5eSopenharmony_ci    if (sz < 0) {
3260b966c5eSopenharmony_ci        HILOGE("set_bluetooth_power : write(%s) failed: %s (%d)",
3270b966c5eSopenharmony_ci            rfkill_state_path, strerror(errno), errno);
3280b966c5eSopenharmony_ci    } else {
3290b966c5eSopenharmony_ci        ret = 0;
3300b966c5eSopenharmony_ci    }
3310b966c5eSopenharmony_ci
3320b966c5eSopenharmony_ci    if (fd >= 0) {
3330b966c5eSopenharmony_ci        close(fd);
3340b966c5eSopenharmony_ci    }
3350b966c5eSopenharmony_ci
3360b966c5eSopenharmony_ci    return ret;
3370b966c5eSopenharmony_ci}
3380b966c5eSopenharmony_ci
3390b966c5eSopenharmony_ci/*******************************************************************************
3400b966c5eSopenharmony_ci**
3410b966c5eSopenharmony_ci** Function        upio_set
3420b966c5eSopenharmony_ci**
3430b966c5eSopenharmony_ci** Description     Set i/o based on polarity
3440b966c5eSopenharmony_ci**
3450b966c5eSopenharmony_ci** Returns         None
3460b966c5eSopenharmony_ci**
3470b966c5eSopenharmony_ci*******************************************************************************/
3480b966c5eSopenharmony_civoid upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
3490b966c5eSopenharmony_ci{
3500b966c5eSopenharmony_ci    int rc;
3510b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
3520b966c5eSopenharmony_ci    int fd = -1;
3530b966c5eSopenharmony_ci    char buffer;
3540b966c5eSopenharmony_ci#endif
3550b966c5eSopenharmony_ci
3560b966c5eSopenharmony_ci    UPIODBG("%s : pio %d action %d, polarity %d", __FUNCTION__, pio, action, polarity);
3570b966c5eSopenharmony_ci    switch (pio) {
3580b966c5eSopenharmony_ci        case UPIO_LPM_MODE:
3590b966c5eSopenharmony_ci            if (upio_state[UPIO_LPM_MODE] == action) {
3600b966c5eSopenharmony_ci                UPIODBG("LPM is %s already", lpm_mode[action]);
3610b966c5eSopenharmony_ci                return;
3620b966c5eSopenharmony_ci            }
3630b966c5eSopenharmony_ci
3640b966c5eSopenharmony_ci            upio_state[UPIO_LPM_MODE] = action;
3650b966c5eSopenharmony_ci
3660b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
3670b966c5eSopenharmony_ci            fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
3680b966c5eSopenharmony_ci            if (fd < 0) {
3690b966c5eSopenharmony_ci                LOGE("upio_set : open(%s) for write failed: %s (%d)",
3700b966c5eSopenharmony_ci                VENDOR_LPM_PROC_NODE, strerror(errno), errno);
3710b966c5eSopenharmony_ci                return;
3720b966c5eSopenharmony_ci            }
3730b966c5eSopenharmony_ci
3740b966c5eSopenharmony_ci            if (action == UPIO_ASSERT) {
3750b966c5eSopenharmony_ci                buffer = '1';
3760b966c5eSopenharmony_ci            } else {
3770b966c5eSopenharmony_ci                buffer = '0';
3780b966c5eSopenharmony_ci
3790b966c5eSopenharmony_ci                // delete btwrite assertion holding timer
3800b966c5eSopenharmony_ci                if (lpm_proc_cb.timer_created == TRUE) {
3810b966c5eSopenharmony_ci                    timer_delete(lpm_proc_cb.timer_id);
3820b966c5eSopenharmony_ci                    lpm_proc_cb.timer_created = FALSE;
3830b966c5eSopenharmony_ci                }
3840b966c5eSopenharmony_ci            }
3850b966c5eSopenharmony_ci
3860b966c5eSopenharmony_ci            if (write(fd, &buffer, 1) < 0) {
3870b966c5eSopenharmony_ci                LOGE("upio_set : write(%s) failed: %s (%d)",
3880b966c5eSopenharmony_ci                VENDOR_LPM_PROC_NODE, strerror(errno),errno);
3890b966c5eSopenharmony_ci            }
3900b966c5eSopenharmony_ci#if (PROC_BTWRITE_TIMER_TIMEOUT_MS != 0)
3910b966c5eSopenharmony_ci            else {
3920b966c5eSopenharmony_ci                if (action == UPIO_ASSERT) {
3930b966c5eSopenharmony_ci                    // create btwrite assertion holding timer
3940b966c5eSopenharmony_ci                    if (lpm_proc_cb.timer_created == FALSE) {
3950b966c5eSopenharmony_ci                        int status;
3960b966c5eSopenharmony_ci                        struct sigevent se;
3970b966c5eSopenharmony_ci
3980b966c5eSopenharmony_ci                        se.sigev_notify = SIGEV_THREAD;
3990b966c5eSopenharmony_ci                        se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id;
4000b966c5eSopenharmony_ci                        se.sigev_notify_function = proc_btwrite_timeout;
4010b966c5eSopenharmony_ci                        se.sigev_notify_attributes = NULL;
4020b966c5eSopenharmony_ci
4030b966c5eSopenharmony_ci                        status = timer_create(CLOCK_MONOTONIC, &se,
4040b966c5eSopenharmony_ci                                              &lpm_proc_cb.timer_id);
4050b966c5eSopenharmony_ci                        if (status == 0)
4060b966c5eSopenharmony_ci                            lpm_proc_cb.timer_created = TRUE;
4070b966c5eSopenharmony_ci                    }
4080b966c5eSopenharmony_ci                }
4090b966c5eSopenharmony_ci            }
4100b966c5eSopenharmony_ci#endif
4110b966c5eSopenharmony_ci
4120b966c5eSopenharmony_ci            if (fd >= 0)
4130b966c5eSopenharmony_ci                close(fd);
4140b966c5eSopenharmony_ci#endif
4150b966c5eSopenharmony_ci            break;
4160b966c5eSopenharmony_ci
4170b966c5eSopenharmony_ci        case UPIO_BT_WAKE:
4180b966c5eSopenharmony_ci            if (upio_state[UPIO_BT_WAKE] == action) {
4190b966c5eSopenharmony_ci                UPIODBG("BT_WAKE is %s already", lpm_state[action]);
4200b966c5eSopenharmony_ci
4210b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC == TRUE)
4220b966c5eSopenharmony_ci                if (lpm_proc_cb.btwrite_active == TRUE)
4230b966c5eSopenharmony_ci                    /*
4240b966c5eSopenharmony_ci                     * The proc btwrite node could have not been updated for
4250b966c5eSopenharmony_ci                     * certain time already due to heavy downstream path flow.
4260b966c5eSopenharmony_ci                     * In this case, we want to explicity touch proc btwrite
4270b966c5eSopenharmony_ci                     * node to keep the bt_wake assertion in the LPM kernel
4280b966c5eSopenharmony_ci                     * driver. The current kernel bluesleep LPM code starts
4290b966c5eSopenharmony_ci                     * a 10sec internal in-activity timeout timer before it
4300b966c5eSopenharmony_ci                     * attempts to deassert BT_WAKE line.
4310b966c5eSopenharmony_ci                     */
4320b966c5eSopenharmony_ci                    return;
4330b966c5eSopenharmony_ci#else
4340b966c5eSopenharmony_ci                return;
4350b966c5eSopenharmony_ci#endif
4360b966c5eSopenharmony_ci            }
4370b966c5eSopenharmony_ci
4380b966c5eSopenharmony_ci            upio_state[UPIO_BT_WAKE] = action;
4390b966c5eSopenharmony_ci
4400b966c5eSopenharmony_ci#if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE)
4410b966c5eSopenharmony_ci
4420b966c5eSopenharmony_ci            userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \
4430b966c5eSopenharmony_ci                      USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),\
4440b966c5eSopenharmony_ci                                  NULL);
4450b966c5eSopenharmony_ci
4460b966c5eSopenharmony_ci#elif (BT_WAKE_VIA_PROC == TRUE)
4470b966c5eSopenharmony_ci
4480b966c5eSopenharmony_ci            /*
4490b966c5eSopenharmony_ci             *  Kick proc btwrite node only at UPIO_ASSERT
4500b966c5eSopenharmony_ci             */
4510b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == FALSE)
4520b966c5eSopenharmony_ci            if (action == UPIO_DEASSERT)
4530b966c5eSopenharmony_ci                return;
4540b966c5eSopenharmony_ci#endif
4550b966c5eSopenharmony_ci            fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
4560b966c5eSopenharmony_ci            if (fd < 0) {
4570b966c5eSopenharmony_ci                LOGE("upio_set : open(%s) for write failed: %s (%d)",
4580b966c5eSopenharmony_ci                VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
4590b966c5eSopenharmony_ci                return;
4600b966c5eSopenharmony_ci            }
4610b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
4620b966c5eSopenharmony_ci            if (action == UPIO_DEASSERT)
4630b966c5eSopenharmony_ci                buffer = '0';
4640b966c5eSopenharmony_ci            else
4650b966c5eSopenharmony_ci#endif
4660b966c5eSopenharmony_ci                buffer = '1';
4670b966c5eSopenharmony_ci
4680b966c5eSopenharmony_ci            if (write(fd, &buffer, 1) < 0) {
4690b966c5eSopenharmony_ci                LOGE("upio_set : write(%s) failed: %s (%d)",
4700b966c5eSopenharmony_ci                VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
4710b966c5eSopenharmony_ci            }
4720b966c5eSopenharmony_ci#if (PROC_BTWRITE_TIMER_TIMEOUT_MS != 0)
4730b966c5eSopenharmony_ci            else {
4740b966c5eSopenharmony_ci                /* arm user space timer based on action */
4750b966c5eSopenharmony_ci                upio_start_stop_timer(action);
4760b966c5eSopenharmony_ci            }
4770b966c5eSopenharmony_ci#endif
4780b966c5eSopenharmony_ci
4790b966c5eSopenharmony_ci#if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
4800b966c5eSopenharmony_ci            lpm_proc_cb.btwrite_active = TRUE;
4810b966c5eSopenharmony_ci#endif
4820b966c5eSopenharmony_ci
4830b966c5eSopenharmony_ci            UPIODBG("%s: proc btwrite assertion, buffer: %c, timer_armed %d %d",
4840b966c5eSopenharmony_ci                    __FUNCTION__, buffer, lpm_proc_cb.btwrite_active, lpm_proc_cb.timer_created);
4850b966c5eSopenharmony_ci
4860b966c5eSopenharmony_ci            if (fd >= 0)
4870b966c5eSopenharmony_ci                close(fd);
4880b966c5eSopenharmony_ci#endif
4890b966c5eSopenharmony_ci
4900b966c5eSopenharmony_ci            break;
4910b966c5eSopenharmony_ci
4920b966c5eSopenharmony_ci        case UPIO_HOST_WAKE:
4930b966c5eSopenharmony_ci            UPIODBG("upio_set: UPIO_HOST_WAKE");
4940b966c5eSopenharmony_ci            break;
4950b966c5eSopenharmony_ci    }
4960b966c5eSopenharmony_ci}
497