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