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