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.boot.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