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