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