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