• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <fcntl.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <time.h>
37 #include <utils/Log.h>
38 #include "bt_vendor_brcm.h"
39 #include "userial_vendor.h"
40 #include "upio.h"
41 
42 /******************************************************************************
43 **  Constants & Macros
44 ******************************************************************************/
45 
46 #ifndef UPIO_DBG
47 #define UPIO_DBG FALSE
48 #endif
49 
50 #if (UPIO_DBG == TRUE)
51 #define UPIODBG(param, ...)         \
52     {                               \
53         HILOGD(param, ##__VA_ARGS__); \
54     }
55 #else
56 #define UPIODBG(param, ...)         \
57     {                               \
58         HILOGD(param, ##__VA_ARGS__); \
59     }
60 #endif
61 
62 /******************************************************************************
63 **  Local type definitions
64 ******************************************************************************/
65 
66 #if (BT_WAKE_VIA_PROC == TRUE)
67 
68 /* proc fs node for enable/disable lpm mode */
69 #ifndef VENDOR_LPM_PROC_NODE
70 #define VENDOR_LPM_PROC_NODE "/proc/bluetooth/sleep/lpm"
71 #endif
72 
73 /* proc fs node for notifying write request */
74 #ifndef VENDOR_BTWRITE_PROC_NODE
75 #define VENDOR_BTWRITE_PROC_NODE "/proc/bluetooth/sleep/btwrite"
76 #endif
77 
78 /*
79  * Maximum btwrite assertion holding time without consecutive btwrite kicking.
80  * This value is correlative(shorter) to the in-working timeout period set in
81  * the bluesleep LPM code. The current value used in bluesleep is 10sec.
82  */
83 #ifndef PROC_BTWRITE_TIMER_TIMEOUT_MS
84 #define PROC_BTWRITE_TIMER_TIMEOUT_MS 8000
85 #endif
86 
87 /* lpm proc control block */
88 typedef struct {
89     uint8_t btwrite_active;
90     uint8_t timer_created;
91     timer_t timer_id;
92     uint32_t timeout_ms;
93 } vnd_lpm_proc_cb_t;
94 
95 static vnd_lpm_proc_cb_t lpm_proc_cb;
96 #endif
97 
98 /******************************************************************************
99 **  Static variables
100 ******************************************************************************/
101 
102 static uint8_t upio_state[UPIO_MAX_COUNT];
103 static int rfkill_id = -1;
104 static int bt_emul_enable = 0;
105 static char rfkill_state_path[128];
106 
107 /******************************************************************************
108 **  Static functions
109 ******************************************************************************/
110 
111 /* for friendly debugging outpout string */
112 static char *lpm_mode[] = {
113     "UNKNOWN",
114     "disabled",
115     "enabled"
116 };
117 
118 static char *lpm_state[] = {
119     "UNKNOWN",
120     "de-asserted",
121     "asserted"
122 };
123 
124 /*****************************************************************************
125 **   Bluetooth On/Off Static Functions
126 *****************************************************************************/
is_emulator_context(void)127 static int is_emulator_context(void)
128 {
129     return 0;
130 }
131 
is_rfkill_disabled(void)132 static int is_rfkill_disabled(void)
133 {
134     return UPIO_BT_POWER_OFF;
135 }
136 
init_rfkill(void)137 static int init_rfkill(void)
138 {
139     char path[64];
140     char buf[16];
141     int fd, sz, id;
142 
143     for (id = 0;; id++) {
144         if (snprintf_s(path, sizeof(path), sizeof(path), "/sys/class/rfkill/rfkill%d/type", id) < 0) {
145             return -1;
146         }
147 
148         fd = open(path, O_RDONLY);
149         if (fd < 0) {
150             HILOGE("init_rfkill : open(%s) failed: %s (%d)\n",
151                 path, strerror(errno), errno);
152             return -1;
153         }
154 
155         sz = read(fd, &buf, sizeof(buf));
156         close(fd);
157 
158         if (sz >= (int)strlen("bluetooth") && memcmp(buf, "bluetooth", strlen("bluetooth")) == 0) {
159             rfkill_id = id;
160             break;
161         }
162     }
163 
164     (void)sprintf_s(rfkill_state_path, sizeof(rfkill_state_path), "/sys/class/rfkill/rfkill%d/state", rfkill_id);
165     return 0;
166 }
167 
168 /*****************************************************************************
169 **   LPM Static Functions
170 *****************************************************************************/
171 
172 #if (BT_WAKE_VIA_PROC == TRUE)
173 /*******************************************************************************
174 **
175 ** Function        proc_btwrite_timeout
176 **
177 ** Description     Timeout thread of proc/.../btwrite assertion holding timer
178 **
179 ** Returns         None
180 **
181 *******************************************************************************/
proc_btwrite_timeout(union sigval arg)182 static void proc_btwrite_timeout(union sigval arg)
183 {
184     UPIODBG("..%s..", __FUNCTION__);
185     lpm_proc_cb.btwrite_active = FALSE;
186     /* drive LPM down; this timer should fire only when BT is awake; */
187     upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
188 }
189 
190 /******************************************************************************
191  **
192  ** Function      upio_start_stop_timer
193  **
194  ** Description   Arm user space timer in case lpm is left asserted
195  **
196  ** Returns       None
197  **
198  *****************************************************************************/
upio_start_stop_timer(int action)199 void upio_start_stop_timer(int action)
200 {
201     struct itimerspec ts;
202 
203     if (action == UPIO_ASSERT) {
204         lpm_proc_cb.btwrite_active = TRUE;
205         if (lpm_proc_cb.timer_created == TRUE) {
206             ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS / BT_VENDOR_TIME_RAIDX;
207             ts.it_value.tv_nsec = BT_VENDOR_TIME_RAIDX * BT_VENDOR_TIME_RAIDX *
208                 (PROC_BTWRITE_TIMER_TIMEOUT_MS % BT_VENDOR_TIME_RAIDX);
209             ts.it_interval.tv_sec = 0;
210             ts.it_interval.tv_nsec = 0;
211         }
212     } else {
213         /* unarm timer if writing 0 to lpm; reduce unnecessary user space wakeup */
214         (void)memset_s(&ts, sizeof(ts), 0, sizeof(ts));
215     }
216 
217     if (timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0) == 0) {
218         UPIODBG("%s : timer_settime success", __FUNCTION__);
219     } else {
220         UPIODBG("%s : timer_settime failed", __FUNCTION__);
221     }
222 }
223 #endif
224 
225 /*****************************************************************************
226 **   UPIO Interface Functions
227 *****************************************************************************/
228 
229 /*******************************************************************************
230 **
231 ** Function        upio_init
232 **
233 ** Description     Initialization
234 **
235 ** Returns         None
236 **
237 *******************************************************************************/
upio_init(void)238 void upio_init(void)
239 {
240     memset_s(upio_state, sizeof(upio_state), UPIO_UNKNOWN, UPIO_MAX_COUNT);
241 #if (BT_WAKE_VIA_PROC == TRUE)
242     memset_s(&lpm_proc_cb, sizeof(vnd_lpm_proc_cb_t), 0, sizeof(vnd_lpm_proc_cb_t));
243 #endif
244 }
245 
246 /*******************************************************************************
247 **
248 ** Function        upio_cleanup
249 **
250 ** Description     Clean up
251 **
252 ** Returns         None
253 **
254 *******************************************************************************/
upio_cleanup(void)255 void upio_cleanup(void)
256 {
257 #if (BT_WAKE_VIA_PROC == TRUE)
258     if (lpm_proc_cb.timer_created == TRUE)
259         timer_delete(lpm_proc_cb.timer_id);
260 
261     lpm_proc_cb.timer_created = FALSE;
262 #endif
263 }
264 
265 /*******************************************************************************
266 **
267 ** Function        upio_set_bluetooth_power
268 **
269 ** Description     Interact with low layer driver to set Bluetooth power
270 **                 on/off.
271 **
272 ** Returns         0  : SUCCESS or Not-Applicable
273 **                 <0 : ERROR
274 **
275 *******************************************************************************/
upio_set_bluetooth_power(int on)276 int upio_set_bluetooth_power(int on)
277 {
278     int sz;
279     int fd = -1;
280     int ret = -1;
281     char buffer = '0';
282 
283     switch (on) {
284         case UPIO_BT_POWER_OFF:
285             buffer = '0';
286             break;
287 
288         case UPIO_BT_POWER_ON:
289             buffer = '1';
290             break;
291         default:
292             return 0;
293     }
294 
295     if (is_emulator_context()) {
296         /* if new value is same as current, return -1 */
297         if (bt_emul_enable == on) {
298             return ret;
299         }
300 
301         UPIODBG("set_bluetooth_power [emul] %d", on);
302         bt_emul_enable = on;
303         return 0;
304     }
305 
306     /* check if we have rfkill interface */
307     if (is_rfkill_disabled()) {
308         return 0;
309     }
310 
311     if (rfkill_id == -1) {
312         if (init_rfkill()) {
313             return ret;
314         }
315     }
316 
317     fd = open(rfkill_state_path, O_WRONLY);
318     if (fd < 0) {
319         HILOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",
320             rfkill_state_path, strerror(errno), errno);
321         return ret;
322     }
323 
324     sz = write(fd, &buffer, 1);
325     if (sz < 0) {
326         HILOGE("set_bluetooth_power : write(%s) failed: %s (%d)",
327             rfkill_state_path, strerror(errno), errno);
328     } else {
329         ret = 0;
330     }
331 
332     if (fd >= 0) {
333         close(fd);
334     }
335 
336     return ret;
337 }
338 
339 /*******************************************************************************
340 **
341 ** Function        upio_set
342 **
343 ** Description     Set i/o based on polarity
344 **
345 ** Returns         None
346 **
347 *******************************************************************************/
upio_set(uint8_t pio,uint8_t action,uint8_t polarity)348 void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
349 {
350     int rc;
351 
352     UPIODBG("%s : pio %d action %d, polarity %d", __FUNCTION__, pio, action, polarity);
353     switch (pio) {
354         case UPIO_LPM_MODE:
355             if (upio_state[UPIO_LPM_MODE] == action) {
356                 UPIODBG("LPM is %s already", lpm_mode[action]);
357                 return;
358             }
359 
360             upio_state[UPIO_LPM_MODE] = action;
361             break;
362 
363         case UPIO_BT_WAKE:
364             if (upio_state[UPIO_BT_WAKE] == action) {
365                 UPIODBG("BT_WAKE is %s already", lpm_state[action]);
366                 return;
367             }
368 
369             upio_state[UPIO_BT_WAKE] = action;
370 
371 #if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE)
372 
373             userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \
374                 USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE), NULL);
375 
376 #elif (BT_WAKE_VIA_PROC == TRUE)
377 
378             /*
379              *  Kick proc btwrite node only at UPIO_ASSERT
380              */
381 #if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == FALSE)
382             if (action == UPIO_DEASSERT)
383                 return;
384 #endif
385             fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
386             if (fd < 0) {
387                 return;
388             }
389 #if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
390             if (action == UPIO_DEASSERT)
391                 buffer = '0';
392             else
393 #endif
394                 buffer = '1';
395 
396             if (write(fd, &buffer, 1) < 0) {
397                 LOGE("upio_set : write(%s) failed: %s (%d)", VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
398             } else {
399                 /* arm user space timer based on action */
400                 upio_start_stop_timer(action);
401             }
402 
403 #if (BT_WAKE_VIA_PROC_NOTIFY_DEASSERT == TRUE)
404             lpm_proc_cb.btwrite_active = TRUE;
405 #endif
406 
407             if (fd >= 0)
408                 close(fd);
409 #endif
410 
411             break;
412 
413         case UPIO_HOST_WAKE:
414             UPIODBG("upio_set: UPIO_HOST_WAKE");
415             break;
416     }
417 }
418