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