summaryrefslogtreecommitdiff
path: root/src/upio.c (plain)
blob: 8c87793f311bbb41cb642a881292f702045f7583
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#include "sysbridge.h"
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 */
80typedef 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
88static vnd_lpm_proc_cb_t lpm_proc_cb;
89#endif
90
91/******************************************************************************
92** Static variables
93******************************************************************************/
94
95static uint8_t upio_state[UPIO_MAX_COUNT];
96static int rfkill_id = -1;
97static int bt_emul_enable = 0;
98static char *rfkill_state_path = NULL;
99
100/******************************************************************************
101** Static functions
102******************************************************************************/
103
104/* for friendly debugging outpout string */
105static char *lpm_mode[] = {
106 "UNKNOWN",
107 "disabled",
108 "enabled"
109};
110
111static char *lpm_state[] = {
112 "UNKNOWN",
113 "de-asserted",
114 "asserted"
115};
116
117/*****************************************************************************
118** Bluetooth On/Off Static Functions
119*****************************************************************************/
120static 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
132static 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
146static int init_rfkill()
147{
148 char path[64];
149 char buf[16];
150 int fd, sz, id;
151 sz = -1;//initial
152 if (is_rfkill_disabled())
153 return -1;
154
155 for (id = 0; ; id++)
156 {
157
158 snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
159 fd = open(path, O_RDONLY);
160 if (fd < 0)
161 {
162 ALOGE("init_rfkill : open(%s) failed: %s (%d)\n", \
163 path, strerror(errno), errno);
164 ALOGE("open failed,use syscontrol\n");
165 sz = amSystemWriteGetProperty(path,&buf);
166 goto end;
167 //return -1;
168 }
169
170 sz = read(fd, &buf, sizeof(buf));
171 close(fd);
172 end:if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0)
173 {
174 ALOGE("break");
175 rfkill_id = id;
176 break;
177 }
178 else if (sz == -1)
179 {
180 ALOGE("init_rfkill : open(%s) failed: %s (%d)\n", \
181 path, strerror(errno), errno);
182 return -1;
183 }
184 }
185
186 asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
187 return 0;
188}
189
190/*****************************************************************************
191** LPM Static Functions
192*****************************************************************************/
193
194#if (BT_WAKE_VIA_PROC == TRUE)
195/*******************************************************************************
196**
197** Function proc_btwrite_timeout
198**
199** Description Timeout thread of proc/.../btwrite assertion holding timer
200**
201** Returns None
202**
203*******************************************************************************/
204static void proc_btwrite_timeout(union sigval arg)
205{
206 UPIODBG("..%s..", __FUNCTION__);
207 lpm_proc_cb.btwrite_active = FALSE;
208 /* drive LPM down; this timer should fire only when BT is awake; */
209 upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
210}
211
212/******************************************************************************
213 **
214 ** Function upio_start_stop_timer
215 **
216 ** Description Arm user space timer in case lpm is left asserted
217 **
218 ** Returns None
219 **
220 *****************************************************************************/
221void upio_start_stop_timer(int action) {
222 struct itimerspec ts;
223
224 if (action == UPIO_ASSERT) {
225 lpm_proc_cb.btwrite_active = TRUE;
226 if (lpm_proc_cb.timer_created == TRUE) {
227 ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS/1000;
228 ts.it_value.tv_nsec = 1000000*(PROC_BTWRITE_TIMER_TIMEOUT_MS%1000);
229 ts.it_interval.tv_sec = 0;
230 ts.it_interval.tv_nsec = 0;
231 }
232 } else {
233 /* unarm timer if writing 0 to lpm; reduce unnecessary user space wakeup */
234 memset(&ts, 0, sizeof(ts));
235 }
236
237 if (timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0) == 0) {
238 UPIODBG("%s : timer_settime success", __FUNCTION__);
239 } else {
240 UPIODBG("%s : timer_settime failed", __FUNCTION__);
241 }
242}
243#endif
244
245/*****************************************************************************
246** UPIO Interface Functions
247*****************************************************************************/
248
249/*******************************************************************************
250**
251** Function upio_init
252**
253** Description Initialization
254**
255** Returns None
256**
257*******************************************************************************/
258void upio_init(void)
259{
260 memset(upio_state, UPIO_UNKNOWN, UPIO_MAX_COUNT);
261#if (BT_WAKE_VIA_PROC == TRUE)
262 memset(&lpm_proc_cb, 0, sizeof(vnd_lpm_proc_cb_t));
263#endif
264}
265
266/*******************************************************************************
267**
268** Function upio_cleanup
269**
270** Description Clean up
271**
272** Returns None
273**
274*******************************************************************************/
275void upio_cleanup(void)
276{
277#if (BT_WAKE_VIA_PROC == TRUE)
278 if (lpm_proc_cb.timer_created == TRUE)
279 timer_delete(lpm_proc_cb.timer_id);
280
281 lpm_proc_cb.timer_created = FALSE;
282#endif
283}
284
285/*******************************************************************************
286**
287** Function upio_set_bluetooth_power
288**
289** Description Interact with low layer driver to set Bluetooth power
290** on/off.
291**
292** Returns 0 : SUCCESS or Not-Applicable
293** <0 : ERROR
294**
295*******************************************************************************/
296int upio_set_bluetooth_power(int on)
297{
298 int sz;
299 int fd = -1;
300 int ret = -1;
301 char buffer = '0';
302
303 switch(on)
304 {
305 case UPIO_BT_POWER_OFF:
306 buffer = '0';
307 break;
308
309 case UPIO_BT_POWER_ON:
310 buffer = '1';
311 break;
312 }
313
314 if (is_emulator_context())
315 {
316 /* if new value is same as current, return -1 */
317 if (bt_emul_enable == on)
318 return ret;
319
320 UPIODBG("set_bluetooth_power [emul] %d", on);
321
322 bt_emul_enable = on;
323 return 0;
324 }
325
326 /* check if we have rfkill interface */
327 if (is_rfkill_disabled())
328 return 0;
329
330 if (rfkill_id == -1)
331 {
332 if (init_rfkill())
333 return ret;
334 }
335
336 fd = open(rfkill_state_path, O_WRONLY);
337
338 if (fd < 0)
339 {
340 ALOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",
341 rfkill_state_path, strerror(errno), errno);
342 sz = amSystemWriteSetProperty(rfkill_state_path, &buffer, 1);
343 goto last;
344 //return ret;
345 }
346
347 sz = write(fd, &buffer, 1);
348 if (fd >= 0)
349 close(fd);
350 last: if (sz < 0) {
351 ALOGE("set_bluetooth_power : write(%s) failed: %s (%d)",
352 rfkill_state_path, strerror(errno),errno);
353 }
354 else
355 ret = 0;
356
357 return ret;
358}
359
360
361/*******************************************************************************
362**
363** Function upio_set
364**
365** Description Set i/o based on polarity
366**
367** Returns None
368**
369*******************************************************************************/
370void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
371{
372 int rc;
373#if (BT_WAKE_VIA_PROC == TRUE)
374 int fd = -1;
375 char buffer;
376#endif
377
378 UPIODBG("%s : pio %d action %d, polarity %d", __FUNCTION__, pio, action, polarity);
379
380 switch (pio)
381 {
382 case UPIO_LPM_MODE:
383 if (upio_state[UPIO_LPM_MODE] == action)
384 {
385 UPIODBG("LPM is %s already", lpm_mode[action]);
386 return;
387 }
388
389 upio_state[UPIO_LPM_MODE] = action;
390
391#if (BT_WAKE_VIA_PROC == TRUE)
392 fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
393
394 if (fd < 0)
395 {
396 ALOGE("upio_set : open(%s) for write failed: %s (%d)",
397 VENDOR_LPM_PROC_NODE, strerror(errno), errno);
398 return;
399 }
400
401 if (action == UPIO_ASSERT)
402 {
403 buffer = '1';
404 }
405 else
406 {
407 buffer = '0';
408
409 // delete btwrite assertion holding timer
410 if (lpm_proc_cb.timer_created == TRUE)
411 {
412 timer_delete(lpm_proc_cb.timer_id);
413 lpm_proc_cb.timer_created = FALSE;
414 }
415 }
416
417 if (write(fd, &buffer, 1) < 0)
418 {
419 ALOGE("upio_set : write(%s) failed: %s (%d)",
420 VENDOR_LPM_PROC_NODE, strerror(errno),errno);
421 }
422#if (PROC_BTWRITE_TIMER_TIMEOUT_MS != 0)
423 else
424 {
425 if (action == UPIO_ASSERT)
426 {
427 // create btwrite assertion holding timer
428 if (lpm_proc_cb.timer_created == FALSE)
429 {
430 int status;
431 struct sigevent se;
432
433 se.sigev_notify = SIGEV_THREAD;
434 se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id;
435 se.sigev_notify_function = proc_btwrite_timeout;
436 se.sigev_notify_attributes = NULL;
437
438 status = timer_create(CLOCK_MONOTONIC, &se,
439 &lpm_proc_cb.timer_id);
440
441 if (status == 0)
442 lpm_proc_cb.timer_created = TRUE;
443 }
444 }
445 }
446#endif
447
448 if (fd >= 0)
449 close(fd);
450#endif
451 break;
452
453 case UPIO_BT_WAKE:
454 if (upio_state[UPIO_BT_WAKE] == action)
455 {
456 UPIODBG("BT_WAKE is %s already", lpm_state[action]);
457
458#if (BT_WAKE_VIA_PROC == TRUE)
459 if (lpm_proc_cb.btwrite_active == TRUE)
460 /*
461 * The proc btwrite node could have not been updated for
462 * certain time already due to heavy downstream path flow.
463 * In this case, we want to explicity touch proc btwrite
464 * node to keep the bt_wake assertion in the LPM kernel
465 * driver. The current kernel bluesleep LPM code starts
466 * a 10sec internal in-activity timeout timer before it
467 * attempts to deassert BT_WAKE line.
468 */
469 return;
470#else
471 return;
472#endif
473 }
474
475 upio_state[UPIO_BT_WAKE] = action;
476
477#if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE)
478
479 userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \
480 USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),\
481 NULL);
482
483#elif (BT_WAKE_VIA_PROC == TRUE)
484
485 /*
486 * Kick proc btwrite node only at UPIO_ASSERT
487 */
488#if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == FALSE)
489 if (action == UPIO_DEASSERT)
490 return;
491#endif
492 fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
493
494 if (fd < 0)
495 {
496 ALOGE("upio_set : open(%s) for write failed: %s (%d)",
497 VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
498 return;
499 }
500#if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
501 if (action == UPIO_DEASSERT)
502 buffer = '0';
503 else
504#endif
505 buffer = '1';
506
507 if (write(fd, &buffer, 1) < 0)
508 {
509 ALOGE("upio_set : write(%s) failed: %s (%d)",
510 VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
511 }
512#if (PROC_BTWRITE_TIMER_TIMEOUT_MS != 0)
513 else
514 {
515 /* arm user space timer based on action */
516 upio_start_stop_timer(action);
517 }
518#endif
519
520 UPIODBG("%s: proc btwrite assertion, buffer: %c, timer_armed %d %d",
521 __FUNCTION__, buffer, lpm_proc_cb.btwrite_active, lpm_proc_cb.timer_created);
522
523 if (fd >= 0)
524 close(fd);
525#endif
526
527 break;
528
529 case UPIO_HOST_WAKE:
530 UPIODBG("upio_set: UPIO_HOST_WAKE");
531 break;
532 }
533}
534
535
536