Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /******************************************************************************
     20  *
     21  *  Filename:      upio.c
     22  *
     23  *  Description:   Contains I/O functions, like
     24  *                      rfkill control
     25  *                      BT_WAKE/HOST_WAKE control
     26  *
     27  ******************************************************************************/
     28 
     29 #define LOG_TAG "bt_upio"
     30 
     31 #include <utils/Log.h>
     32 #include <fcntl.h>
     33 #include <errno.h>
     34 #include <string.h>
     35 #include <cutils/properties.h>
     36 #include "bt_vendor_brcm.h"
     37 #include "upio.h"
     38 #include "userial_vendor.h"
     39 #include <stdio.h>
     40 #include <unistd.h>
     41 #include <time.h>
     42 
     43 /******************************************************************************
     44 **  Constants & Macros
     45 ******************************************************************************/
     46 
     47 #ifndef UPIO_DBG
     48 #define UPIO_DBG FALSE
     49 #endif
     50 
     51 #if (UPIO_DBG == TRUE)
     52 #define UPIODBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
     53 #else
     54 #define UPIODBG(param, ...) {}
     55 #endif
     56 
     57 /******************************************************************************
     58 **  Local type definitions
     59 ******************************************************************************/
     60 
     61 #if (BT_WAKE_VIA_PROC == TRUE)
     62 
     63 /* proc fs node for enable/disable lpm mode */
     64 #ifndef VENDOR_LPM_PROC_NODE
     65 #define VENDOR_LPM_PROC_NODE "/proc/bluetooth/sleep/lpm"
     66 #endif
     67 
     68 /* proc fs node for notifying write request */
     69 #ifndef VENDOR_BTWRITE_PROC_NODE
     70 #define VENDOR_BTWRITE_PROC_NODE "/proc/bluetooth/sleep/btwrite"
     71 #endif
     72 
     73 /*
     74  * Maximum btwrite assertion holding time without consecutive btwrite kicking.
     75  * This value is correlative(shorter) to the in-activity timeout period set in
     76  * the bluesleep LPM code. The current value used in bluesleep is 10sec.
     77  */
     78 #ifndef PROC_BTWRITE_TIMER_TIMEOUT_MS
     79 #define PROC_BTWRITE_TIMER_TIMEOUT_MS   8000
     80 #endif
     81 
     82 /* lpm proc control block */
     83 typedef struct
     84 {
     85     uint8_t btwrite_active;
     86     uint8_t timer_created;
     87     timer_t timer_id;
     88     uint32_t timeout_ms;
     89 } vnd_lpm_proc_cb_t;
     90 
     91 static vnd_lpm_proc_cb_t lpm_proc_cb;
     92 #endif
     93 
     94 /******************************************************************************
     95 **  Static variables
     96 ******************************************************************************/
     97 
     98 static uint8_t upio_state[UPIO_MAX_COUNT];
     99 static int rfkill_id = -1;
    100 static int bt_emul_enable = 0;
    101 static char *rfkill_state_path = NULL;
    102 
    103 /******************************************************************************
    104 **  Static functions
    105 ******************************************************************************/
    106 
    107 /* for friendly debugging outpout string */
    108 static char *lpm_mode[] = {
    109     "UNKNOWN",
    110     "disabled",
    111     "enabled"
    112 };
    113 
    114 static char *lpm_state[] = {
    115     "UNKNOWN",
    116     "de-asserted",
    117     "asserted"
    118 };
    119 
    120 /*****************************************************************************
    121 **   Bluetooth On/Off Static Functions
    122 *****************************************************************************/
    123 static int is_emulator_context(void)
    124 {
    125     char value[PROPERTY_VALUE_MAX];
    126 
    127     property_get("ro.kernel.qemu", value, "0");
    128     UPIODBG("is_emulator_context : %s", value);
    129     if (strcmp(value, "1") == 0) {
    130         return 1;
    131     }
    132     return 0;
    133 }
    134 
    135 static int is_rfkill_disabled(void)
    136 {
    137     char value[PROPERTY_VALUE_MAX];
    138 
    139     property_get("ro.rfkilldisabled", value, "0");
    140     UPIODBG("is_rfkill_disabled ? [%s]", value);
    141 
    142     if (strcmp(value, "1") == 0) {
    143         return UPIO_BT_POWER_ON;
    144     }
    145 
    146     return UPIO_BT_POWER_OFF;
    147 }
    148 
    149 static int init_rfkill()
    150 {
    151     char path[64];
    152     char buf[16];
    153     int fd, sz, id;
    154 
    155     if (is_rfkill_disabled())
    156         return -1;
    157 
    158     for (id = 0; ; id++)
    159     {
    160         snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
    161         fd = open(path, O_RDONLY);
    162         if (fd < 0)
    163         {
    164             ALOGE("init_rfkill : open(%s) failed: %s (%d)\n", \
    165                  path, strerror(errno), errno);
    166             return -1;
    167         }
    168 
    169         sz = read(fd, &buf, sizeof(buf));
    170         close(fd);
    171 
    172         if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0)
    173         {
    174             rfkill_id = id;
    175             break;
    176         }
    177     }
    178 
    179     asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
    180     return 0;
    181 }
    182 
    183 /*****************************************************************************
    184 **   LPM Static Functions
    185 *****************************************************************************/
    186 
    187 #if (BT_WAKE_VIA_PROC == TRUE)
    188 /*******************************************************************************
    189 **
    190 ** Function        proc_btwrite_timeout
    191 **
    192 ** Description     Timeout thread of proc/.../btwrite assertion holding timer
    193 **
    194 ** Returns         None
    195 **
    196 *******************************************************************************/
    197 static void proc_btwrite_timeout(union sigval arg)
    198 {
    199     UPIODBG("..%s..", __FUNCTION__);
    200     lpm_proc_cb.btwrite_active = FALSE;
    201     /* drive LPM down; this timer should fire only when BT is awake; */
    202     upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
    203 }
    204 
    205 /******************************************************************************
    206  **
    207  ** Function      upio_start_stop_timer
    208  **
    209  ** Description   Arm user space timer in case lpm is left asserted
    210  **
    211  ** Returns       None
    212  **
    213  *****************************************************************************/
    214 void upio_start_stop_timer(int action) {
    215     struct itimerspec ts;
    216 
    217     if (action == UPIO_ASSERT) {
    218         lpm_proc_cb.btwrite_active = TRUE;
    219         if (lpm_proc_cb.timer_created == TRUE) {
    220             ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS/1000;
    221             ts.it_value.tv_nsec = 1000000*(PROC_BTWRITE_TIMER_TIMEOUT_MS%1000);
    222             ts.it_interval.tv_sec = 0;
    223             ts.it_interval.tv_nsec = 0;
    224         }
    225     } else {
    226         /* unarm timer if writing 0 to lpm; reduce unnecessary user space wakeup */
    227         memset(&ts, 0, sizeof(ts));
    228     }
    229 
    230     if (timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0) == 0) {
    231         UPIODBG("%s : timer_settime success", __FUNCTION__);
    232     } else {
    233         UPIODBG("%s : timer_settime failed", __FUNCTION__);
    234     }
    235 }
    236 #endif
    237 
    238 /*****************************************************************************
    239 **   UPIO Interface Functions
    240 *****************************************************************************/
    241 
    242 /*******************************************************************************
    243 **
    244 ** Function        upio_init
    245 **
    246 ** Description     Initialization
    247 **
    248 ** Returns         None
    249 **
    250 *******************************************************************************/
    251 void upio_init(void)
    252 {
    253     memset(upio_state, UPIO_UNKNOWN, UPIO_MAX_COUNT);
    254 #if (BT_WAKE_VIA_PROC == TRUE)
    255     memset(&lpm_proc_cb, 0, sizeof(vnd_lpm_proc_cb_t));
    256 #endif
    257 }
    258 
    259 /*******************************************************************************
    260 **
    261 ** Function        upio_cleanup
    262 **
    263 ** Description     Clean up
    264 **
    265 ** Returns         None
    266 **
    267 *******************************************************************************/
    268 void upio_cleanup(void)
    269 {
    270 #if (BT_WAKE_VIA_PROC == TRUE)
    271     if (lpm_proc_cb.timer_created == TRUE)
    272         timer_delete(lpm_proc_cb.timer_id);
    273 
    274     lpm_proc_cb.timer_created = FALSE;
    275 #endif
    276 }
    277 
    278 /*******************************************************************************
    279 **
    280 ** Function        upio_set_bluetooth_power
    281 **
    282 ** Description     Interact with low layer driver to set Bluetooth power
    283 **                 on/off.
    284 **
    285 ** Returns         0  : SUCCESS or Not-Applicable
    286 **                 <0 : ERROR
    287 **
    288 *******************************************************************************/
    289 int upio_set_bluetooth_power(int on)
    290 {
    291     int sz;
    292     int fd = -1;
    293     int ret = -1;
    294     char buffer = '0';
    295 
    296     switch(on)
    297     {
    298         case UPIO_BT_POWER_OFF:
    299             buffer = '0';
    300             break;
    301 
    302         case UPIO_BT_POWER_ON:
    303             buffer = '1';
    304             break;
    305     }
    306 
    307     if (is_emulator_context())
    308     {
    309         /* if new value is same as current, return -1 */
    310         if (bt_emul_enable == on)
    311             return ret;
    312 
    313         UPIODBG("set_bluetooth_power [emul] %d", on);
    314 
    315         bt_emul_enable = on;
    316         return 0;
    317     }
    318 
    319     /* check if we have rfkill interface */
    320     if (is_rfkill_disabled())
    321         return 0;
    322 
    323     if (rfkill_id == -1)
    324     {
    325         if (init_rfkill())
    326             return ret;
    327     }
    328 
    329     fd = open(rfkill_state_path, O_WRONLY);
    330 
    331     if (fd < 0)
    332     {
    333         ALOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",
    334             rfkill_state_path, strerror(errno), errno);
    335         return ret;
    336     }
    337 
    338     sz = write(fd, &buffer, 1);
    339 
    340     if (sz < 0) {
    341         ALOGE("set_bluetooth_power : write(%s) failed: %s (%d)",
    342             rfkill_state_path, strerror(errno),errno);
    343     }
    344     else
    345         ret = 0;
    346 
    347     if (fd >= 0)
    348         close(fd);
    349 
    350     return ret;
    351 }
    352 
    353 
    354 /*******************************************************************************
    355 **
    356 ** Function        upio_set
    357 **
    358 ** Description     Set i/o based on polarity
    359 **
    360 ** Returns         None
    361 **
    362 *******************************************************************************/
    363 void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
    364 {
    365     int rc;
    366 #if (BT_WAKE_VIA_PROC == TRUE)
    367     int fd = -1;
    368     char buffer;
    369 #endif
    370 
    371     UPIODBG("%s : pio %d action %d, polarity %d", __FUNCTION__, pio, action, polarity);
    372 
    373     switch (pio)
    374     {
    375         case UPIO_LPM_MODE:
    376             if (upio_state[UPIO_LPM_MODE] == action)
    377             {
    378                 UPIODBG("LPM is %s already", lpm_mode[action]);
    379                 return;
    380             }
    381 
    382             upio_state[UPIO_LPM_MODE] = action;
    383 
    384 #if (BT_WAKE_VIA_PROC == TRUE)
    385             fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
    386 
    387             if (fd < 0)
    388             {
    389                 ALOGE("upio_set : open(%s) for write failed: %s (%d)",
    390                         VENDOR_LPM_PROC_NODE, strerror(errno), errno);
    391                 return;
    392             }
    393 
    394             if (action == UPIO_ASSERT)
    395             {
    396                 buffer = '1';
    397             }
    398             else
    399             {
    400                 buffer = '0';
    401 
    402                 // delete btwrite assertion holding timer
    403                 if (lpm_proc_cb.timer_created == TRUE)
    404                 {
    405                     timer_delete(lpm_proc_cb.timer_id);
    406                     lpm_proc_cb.timer_created = FALSE;
    407                 }
    408             }
    409 
    410             if (write(fd, &buffer, 1) < 0)
    411             {
    412                 ALOGE("upio_set : write(%s) failed: %s (%d)",
    413                         VENDOR_LPM_PROC_NODE, strerror(errno),errno);
    414             }
    415 #if (PROC_BTWRITE_TIMER_TIMEOUT_MS != 0)
    416             else
    417             {
    418                 if (action == UPIO_ASSERT)
    419                 {
    420                     // create btwrite assertion holding timer
    421                     if (lpm_proc_cb.timer_created == FALSE)
    422                     {
    423                         int status;
    424                         struct sigevent se;
    425 
    426                         se.sigev_notify = SIGEV_THREAD;
    427                         se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id;
    428                         se.sigev_notify_function = proc_btwrite_timeout;
    429                         se.sigev_notify_attributes = NULL;
    430 
    431                         status = timer_create(CLOCK_MONOTONIC, &se,
    432                                                 &lpm_proc_cb.timer_id);
    433 
    434                         if (status == 0)
    435                             lpm_proc_cb.timer_created = TRUE;
    436                     }
    437                 }
    438             }
    439 #endif
    440 
    441             if (fd >= 0)
    442                 close(fd);
    443 #endif
    444             break;
    445 
    446         case UPIO_BT_WAKE:
    447             if (upio_state[UPIO_BT_WAKE] == action)
    448             {
    449                 UPIODBG("BT_WAKE is %s already", lpm_state[action]);
    450 
    451 #if (BT_WAKE_VIA_PROC == TRUE)
    452                 if (lpm_proc_cb.btwrite_active == TRUE)
    453                     /*
    454                      * The proc btwrite node could have not been updated for
    455                      * certain time already due to heavy downstream path flow.
    456                      * In this case, we want to explicity touch proc btwrite
    457                      * node to keep the bt_wake assertion in the LPM kernel
    458                      * driver. The current kernel bluesleep LPM code starts
    459                      * a 10sec internal in-activity timeout timer before it
    460                      * attempts to deassert BT_WAKE line.
    461                      */
    462                     return;
    463 #else
    464                 return;
    465 #endif
    466             }
    467 
    468             upio_state[UPIO_BT_WAKE] = action;
    469 
    470 #if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE)
    471 
    472             userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \
    473                       USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),\
    474                       NULL);
    475 
    476 #elif (BT_WAKE_VIA_PROC == TRUE)
    477 
    478             /*
    479              *  Kick proc btwrite node only at UPIO_ASSERT
    480              */
    481 #if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == FALSE)
    482             if (action == UPIO_DEASSERT)
    483                 return;
    484 #endif
    485             fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
    486 
    487             if (fd < 0)
    488             {
    489                 ALOGE("upio_set : open(%s) for write failed: %s (%d)",
    490                         VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
    491                 return;
    492             }
    493 #if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
    494             if (action == UPIO_DEASSERT)
    495                 buffer = '0';
    496             else
    497 #endif
    498                 buffer = '1';
    499 
    500             if (write(fd, &buffer, 1) < 0)
    501             {
    502                 ALOGE("upio_set : write(%s) failed: %s (%d)",
    503                         VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
    504             }
    505 #if (PROC_BTWRITE_TIMER_TIMEOUT_MS != 0)
    506             else
    507             {
    508                 /* arm user space timer based on action */
    509                 upio_start_stop_timer(action);
    510             }
    511 #endif
    512 
    513 #if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
    514             lpm_proc_cb.btwrite_active = TRUE;
    515 #endif
    516 
    517             UPIODBG("%s: proc btwrite assertion, buffer: %c, timer_armed %d %d",
    518                     __FUNCTION__, buffer, lpm_proc_cb.btwrite_active, lpm_proc_cb.timer_created);
    519 
    520             if (fd >= 0)
    521                 close(fd);
    522 #endif
    523 
    524             break;
    525 
    526         case UPIO_HOST_WAKE:
    527             UPIODBG("upio_set: UPIO_HOST_WAKE");
    528             break;
    529     }
    530 }
    531 
    532 
    533