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