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