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