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