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