• 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 "userial_vendor.h"
36 #include "upio.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     uint8_t btwrite_active;
85     uint8_t timer_created;
86     timer_t timer_id;
87     uint32_t timeout_ms;
88 } vnd_lpm_proc_cb_t;
89 
90 static vnd_lpm_proc_cb_t lpm_proc_cb;
91 #endif
92 
93 /******************************************************************************
94 **  Static variables
95 ******************************************************************************/
96 
97 static uint8_t upio_state[UPIO_MAX_COUNT];
98 static int rfkill_id = -1;
99 static int bt_emul_enable = 0;
100 static char *rfkill_state_path = NULL;
101 
102 /******************************************************************************
103 **  Static functions
104 ******************************************************************************/
105 
106 /* for friendly debugging outpout string */
107 static char *lpm_mode[] = {"UNKNOWN", "disabled", "enabled"};
108 
109 static char *lpm_state[] = {"UNKNOWN", "de-asserted", "asserted"};
110 
111 /*****************************************************************************
112 **   Bluetooth On/Off Static Functions
113 *****************************************************************************/
is_emulator_context(void)114 static int is_emulator_context(void)
115 {
116     char value[PROPERTY_VALUE_MAX];
117 
118     (void)memset_s(value, sizeof(value), 0, sizeof(value));
119     (void)strcpy_s(value, sizeof(value), "1");
120     UPIODBG("is_emulator_context : %s", value);
121     if (strcmp(value, "1") == 0) {
122         return 1;
123     }
124     return 0;
125 }
126 
is_rfkill_disabled(void)127 static int is_rfkill_disabled(void)
128 {
129     char value[PROPERTY_VALUE_MAX];
130 
131     (void)memset_s(value, sizeof(value), 0, sizeof(value));
132     (void)strcpy_s(value, sizeof(value), "0");
133     UPIODBG("is_rfkill_disabled ? [%s]", value);
134 
135     if (strcmp(value, "1") == 0) {
136         return UPIO_BT_POWER_ON;
137     }
138 
139     return UPIO_BT_POWER_OFF;
140 }
141 
init_rfkill(void)142 static int init_rfkill(void)
143 {
144     char path[64];
145     char buf[16];
146     int fd, sz, id;
147 
148     if (is_rfkill_disabled()) {
149         return -1;
150     }
151 
152     for (id = 0;; id++) {
153         (void)snprintf_s(path, sizeof(path), sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
154         fd = open(path, O_RDONLY);
155         if (fd < 0) {
156             HILOGE("init_rfkill : open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
157             return -1;
158         }
159 
160         sz = read(fd, &buf, sizeof(buf));
161         close(fd);
162 
163 #define SZ_9 9
164         if (sz >= SZ_9 && memcmp(buf, "bluetooth", SZ_9) == 0) {
165             rfkill_id = id;
166 
167             break;
168         }
169     }
170 
171     (void)asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
172     return 0;
173 }
174 
bt_wake_up_host_mode_set(uint8_t mode)175 int bt_wake_up_host_mode_set(uint8_t mode)
176 {
177     char path[64];
178     char buffer = '0';
179     int sz;
180     int fd = -1;
181     int ret = -1;
182     HILOGE("bt_wake_up_host_mode_set");
183 
184     (void)snprintf_s(path, sizeof(path), sizeof(path), "/proc/bluetooth/sleep/lpm");
185     HILOGE("bt_wake_up_host_mode_set path:%s", path);
186 
187     fd = open(path, O_WRONLY);
188     if (fd < 0) {
189         HILOGE("bt_wake_up_host_mode_set fd:%d = open(path, O_RDWR): open(%s) failed: %s (%d)\n", fd, path,
190                strerror(errno), errno);
191         return -1;
192     }
193 
194     HILOGE("bt_wake_up_host_mode_set fd:%d = open(path, O_RDWR): open(%s) success\n", fd, path);
195 
196     if (mode == 1) {
197         buffer = '1';
198     } else {
199         buffer = '0';
200     }
201 
202     HILOGE("bt_wake_up_host_mode_set buffer:%d", buffer);
203     sz = write(fd, &buffer, 1);
204     if (sz < 0) {
205         HILOGE("bt_wake_up_host_mode_set : write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno), errno);
206     } else {
207         ret = 0;
208     }
209 
210     if (fd >= 0) {
211         close(fd);
212     }
213 
214     return ret;
215 }
216 
217 /*****************************************************************************
218 **   LPM Static Functions
219 *****************************************************************************/
220 
221 #if (BT_WAKE_VIA_PROC == TRUE)
222 /*******************************************************************************
223 **
224 ** Function        proc_btwrite_timeout
225 **
226 ** Description     Timeout thread of proc/.../btwrite assertion holding timer
227 **
228 ** Returns         None
229 **
230 *******************************************************************************/
proc_btwrite_timeout(union sigval arg)231 static void proc_btwrite_timeout(union sigval arg)
232 {
233     UPIODBG("..%s..", __FUNCTION__);
234     lpm_proc_cb.btwrite_active = FALSE;
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     (void)memset_s(upio_state, UPIO_MAX_COUNT, UPIO_UNKNOWN, UPIO_MAX_COUNT);
254 #if (BT_WAKE_VIA_PROC == TRUE)
255     (void)memset_s(&lpm_proc_cb, sizeof(vnd_lpm_proc_cb_t), 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 
275     lpm_proc_cb.timer_created = FALSE;
276 #endif
277 }
278 
279 /*******************************************************************************
280 **
281 ** Function        upio_set_bluetooth_power
282 **
283 ** Description     Interact with low layer driver to set Bluetooth power
284 **                 on/off.
285 **
286 ** Returns         0  : SUCCESS or Not-Applicable
287 **                 <0 : ERROR
288 **
289 *******************************************************************************/
upio_set_bluetooth_power(int on)290 int upio_set_bluetooth_power(int on)
291 {
292     int sz;
293     int fd = -1;
294     int ret = -1;
295     char buffer = '0';
296 
297     switch (on) {
298         case UPIO_BT_POWER_OFF:
299             buffer = '0';
300             break;
301 
302         case UPIO_BT_POWER_ON:
303             buffer = '1';
304             break;
305         default:
306             break;
307     }
308 
309     if (is_emulator_context()) {
310         /* if new value is same as current, return -1 */
311         if (bt_emul_enable == on) {
312             return ret;
313         }
314 
315         UPIODBG("set_bluetooth_power [emul] %d", on);
316 
317         bt_emul_enable = on;
318         return 0;
319     }
320 
321     /* check if we have rfkill interface */
322     if (is_rfkill_disabled()) {
323         return 0;
324     }
325 
326     if (rfkill_id == -1) {
327         if (init_rfkill()) {
328             return ret;
329         }
330     }
331 
332     fd = open(rfkill_state_path, O_WRONLY);
333     if (fd < 0) {
334         HILOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)", rfkill_state_path, strerror(errno), errno);
335         return ret;
336     }
337 
338     sz = write(fd, &buffer, 1);
339     if (sz < 0) {
340         HILOGE("set_bluetooth_power : write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno), errno);
341     } else {
342         ret = 0;
343     }
344 
345     if (fd >= 0) {
346         close(fd);
347     }
348 
349     return ret;
350 }
351 
352 /*******************************************************************************
353 **
354 ** Function        upio_set
355 **
356 ** Description     Set i/o based on polarity
357 **
358 ** Returns         None
359 **
360 *******************************************************************************/
361 
upio_set_lpm_mode(uint8_t action_temp)362 void upio_set_lpm_mode(uint8_t action_temp)
363 {
364 #if (BT_WAKE_VIA_PROC == TRUE)
365             int fd = -1;
366             fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
367             if (fd < 0) {
368                 HILOGE("upio_set : open(%s) for write failed: %s (%d)", VENDOR_LPM_PROC_NODE, strerror(errno), errno);
369                 return;
370             }
371 
372             if (action_temp == UPIO_ASSERT) {
373                 buffer = '1';
374             } else {
375                 buffer = '0';
376 
377                 // delete btwrite assertion holding timer
378                 if (lpm_proc_cb.timer_created == TRUE) {
379                     timer_delete(lpm_proc_cb.timer_id);
380                     lpm_proc_cb.timer_created = FALSE;
381                 }
382             }
383 
384             if (write(fd, &buffer, 1) < 0) {
385                 HILOGE("upio_set : write(%s) failed: %s (%d)", VENDOR_LPM_PROC_NODE, strerror(errno), errno);
386             } else {
387                 if (action_temp == UPIO_ASSERT) {
388                     // create btwrite assertion holding timer
389                     if (lpm_proc_cb.timer_created == FALSE) {
390                         int status;
391                         struct sigevent se;
392 
393                         se.sigev_notify = SIGEV_THREAD;
394                         se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id;
395                         se.sigev_notify_function = proc_btwrite_timeout;
396                         se.sigev_notify_attributes = NULL;
397 
398                         status = timer_create(CLOCK_MONOTONIC, &se, &lpm_proc_cb.timer_id);
399                         if (status == 0) {
400                             lpm_proc_cb.timer_created = TRUE;
401                         }
402                     }
403                 }
404             }
405 
406             if (fd >= 0) {
407                 close(fd);
408             }
409 #endif
410 }
411 
upio_set_bt_wake(uint8_t action_temp)412 void upio_set_bt_wake(uint8_t action_temp)
413 {
414 #if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE)
415 
416         userial_vendor_ioctl(((action_temp == UPIO_ASSERT) ? USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),
417                              NULL);
418 
419 #elif (BT_WAKE_VIA_PROC == TRUE)
420 
421             /*
422              *  Kick proc btwrite node only at UPIO_ASSERT
423              */
424             int fd = -1;
425             if (action_temp == UPIO_DEASSERT) {
426                 return;
427             }
428 
429             fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
430             if (fd_temp < 0) {
431                 HILOGE("upio_set : open(%s) for write failed: %s (%d)", VENDOR_BTWRITE_PROC_NODE, strerror(errno),
432                        errno);
433                 return;
434             }
435 
436             buffer = '1';
437 
438             if (write(fd, &buffer, 1) < 0) {
439                 HILOGE("upio_set : write(%s) failed: %s (%d)", VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
440             } else {
441                 lpm_proc_cb.btwrite_active = TRUE;
442 
443                 if (lpm_proc_cb.timer_created == TRUE) {
444                     struct itimerspec ts;
445 
446                     ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS / 1000L;
447                     ts.it_value.tv_nsec = 1000L * (PROC_BTWRITE_TIMER_TIMEOUT_MS % 1000L);
448                     ts.it_interval.tv_sec = 0;
449                     ts.it_interval.tv_nsec = 0;
450 
451                     timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0);
452                 }
453             }
454 
455             UPIODBG("proc btwrite assertion");
456 
457             if (fd >= 0) {
458                 close(fd);
459             }
460 #endif
461 }
462 
upio_set(uint8_t pio,uint8_t action,uint8_t polarity)463 void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
464 {
465     RTK_UNUSED(polarity);
466 #if (BT_WAKE_VIA_PROC == TRUE)
467     int fd = -1;
468     char buffer;
469 #endif
470 
471     switch (pio) {
472         case UPIO_LPM_MODE:
473             if (upio_state[UPIO_LPM_MODE] == action) {
474                 RTK_UNUSED(lpm_mode[action]);
475                 UPIODBG("LPM is %s already", lpm_mode[action]);
476                 return;
477             }
478 
479             upio_state[UPIO_LPM_MODE] = action;
480             upio_set_lpm_mode(action);
481             break;
482 
483         case UPIO_BT_WAKE:
484             if (upio_state[UPIO_BT_WAKE] == action) {
485                 RTK_UNUSED(lpm_state[action]);
486                 UPIODBG("BT_WAKE is %s already", lpm_state[action]);
487 
488 #if (BT_WAKE_VIA_PROC == TRUE)
489                 if (lpm_proc_cb.btwrite_active == TRUE)
490                 /*
491                  * The proc btwrite node could have not been updated for
492                  * certain time already due to heavy downstream path flow.
493                  * In this case, we want to explicity touch proc btwrite
494                  * node to keep the bt_wake assertion in the LPM kernel
495                  * driver. The current kernel bluesleep LPM code starts
496                  * a 10sec internal in-activity timeout timer before it
497                  * attempts to deassert BT_WAKE line.
498                  */
499 #endif
500                     return;
501             }
502 
503             upio_state[UPIO_BT_WAKE] = action;
504             upio_set_bt_wake(action);
505             break;
506 
507         case UPIO_HOST_WAKE:
508             UPIODBG("upio_set: UPIO_HOST_WAKE");
509             break;
510     }
511 }
512