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 *****************************************************************************/
is_emulator_context(void)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
is_rfkill_disabled(void)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
init_rfkill()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 *******************************************************************************/
proc_btwrite_timeout(union sigval arg)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 *****************************************************************************/
upio_start_stop_timer(int action)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 *******************************************************************************/
upio_init(void)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 *******************************************************************************/
upio_cleanup(void)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 *******************************************************************************/
upio_set_bluetooth_power(int on)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 *******************************************************************************/
upio_set(uint8_t pio,uint8_t action,uint8_t polarity)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