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 */ 79typedef 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 87static vnd_lpm_proc_cb_t lpm_proc_cb; 88#endif 89 90/****************************************************************************** 91** Static variables 92******************************************************************************/ 93 94static uint8_t upio_state[UPIO_MAX_COUNT]; 95static int rfkill_id = -1; 96static int bt_emul_enable = 0; 97static char *rfkill_state_path = NULL; 98 99/****************************************************************************** 100** Static functions 101******************************************************************************/ 102 103/* for friendly debugging outpout string */ 104static char *lpm_mode[] = { 105 "UNKNOWN", 106 "disabled", 107 "enabled" 108}; 109 110static char *lpm_state[] = { 111 "UNKNOWN", 112 "de-asserted", 113 "asserted" 114}; 115 116/***************************************************************************** 117** Bluetooth On/Off Static Functions 118*****************************************************************************/ 119static 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 131static 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 145static 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*******************************************************************************/ 193static 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*******************************************************************************/ 213void 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*******************************************************************************/ 230void 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*******************************************************************************/ 251int 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*******************************************************************************/ 325void 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