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 else 376 { 377 if (action == UPIO_ASSERT) 378 { 379 // create btwrite assertion holding timer 380 if (lpm_proc_cb.timer_created == FALSE) 381 { 382 int status; 383 struct sigevent se; 384 385 se.sigev_notify = SIGEV_THREAD; 386 se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id; 387 se.sigev_notify_function = proc_btwrite_timeout; 388 se.sigev_notify_attributes = NULL; 389 390 status = timer_create(CLOCK_MONOTONIC, &se, 391 &lpm_proc_cb.timer_id); 392 393 if (status == 0) 394 lpm_proc_cb.timer_created = TRUE; 395 } 396 } 397 } 398 399 if (fd >= 0) 400 close(fd); 401 #endif 402 break; 403 404 case UPIO_BT_WAKE: 405 if (upio_state[UPIO_BT_WAKE] == action) 406 { 407 UPIODBG("BT_WAKE is %s already", lpm_state[action]); 408 409 #if (BT_WAKE_VIA_PROC == TRUE) 410 if (lpm_proc_cb.btwrite_active == TRUE) 411 /* 412 * The proc btwrite node could have not been updated for 413 * certain time already due to heavy downstream path flow. 414 * In this case, we want to explicity touch proc btwrite 415 * node to keep the bt_wake assertion in the LPM kernel 416 * driver. The current kernel bluesleep LPM code starts 417 * a 10sec internal in-activity timeout timer before it 418 * attempts to deassert BT_WAKE line. 419 */ 420 #endif 421 return; 422 } 423 424 upio_state[UPIO_BT_WAKE] = action; 425 426 #if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE) 427 428 userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \ 429 USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),\ 430 NULL); 431 432 #elif (BT_WAKE_VIA_PROC == TRUE) 433 434 /* 435 * Kick proc btwrite node only at UPIO_ASSERT 436 */ 437 if (action == UPIO_DEASSERT) 438 return; 439 440 fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY); 441 442 if (fd < 0) 443 { 444 ALOGE("upio_set : open(%s) for write failed: %s (%d)", 445 VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno); 446 return; 447 } 448 449 buffer = '1'; 450 451 if (write(fd, &buffer, 1) < 0) 452 { 453 ALOGE("upio_set : write(%s) failed: %s (%d)", 454 VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno); 455 } 456 else 457 { 458 lpm_proc_cb.btwrite_active = TRUE; 459 460 if (lpm_proc_cb.timer_created == TRUE) 461 { 462 struct itimerspec ts; 463 464 ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS/1000; 465 ts.it_value.tv_nsec = 1000*(PROC_BTWRITE_TIMER_TIMEOUT_MS%1000); 466 ts.it_interval.tv_sec = 0; 467 ts.it_interval.tv_nsec = 0; 468 469 timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0); 470 } 471 } 472 473 UPIODBG("proc btwrite assertion"); 474 475 if (fd >= 0) 476 close(fd); 477 #endif 478 479 break; 480 481 case UPIO_HOST_WAKE: 482 UPIODBG("upio_set: UPIO_HOST_WAKE"); 483 break; 484 } 485 } 486 487 488