hardware/broadcom/libbt
Revisión | 78e7dccc08db81cc95810dc928d956ecf7199853 (tree) |
---|---|
Tiempo | 2012-10-23 15:59:52 |
Autor | YK Jeffrey Chao <jechao@broa...> |
Commiter | Matthew Xie |
Add new user-to-kernel interface for Bluetooth low power mode control (1/2)
The bluesleep kernel module was used in Tegra3 platform to perform Bluetooth
low power wakelock and interrup control. Add new user-to-kernel interface
through proc fs nodes for Bluedroid to feed bluesleep with the HCI_DEV events
which bluesleep was monitoring on.
bug 7347413
Change-Id: I791be1042d5573e5207aa81e3d59fa418134f9fe
Conflicts:
libbt/include/vnd_manta.txt
@@ -202,6 +202,13 @@ | ||
202 | 202 | #define BT_WAKE_VIA_USERIAL_IOCTL FALSE |
203 | 203 | #endif |
204 | 204 | |
205 | +/* BT_WAKE_VIA_PROC | |
206 | + | |
207 | + LPM & BT_WAKE control through PROC nodes | |
208 | +*/ | |
209 | +#ifndef BT_WAKE_VIA_PROC | |
210 | +#define BT_WAKE_VIA_PROC FALSE | |
211 | +#endif | |
205 | 212 | |
206 | 213 | /* SCO_CFG_INCLUDED |
207 | 214 |
@@ -38,6 +38,7 @@ | ||
38 | 38 | enum { |
39 | 39 | UPIO_BT_WAKE = 0, |
40 | 40 | UPIO_HOST_WAKE, |
41 | + UPIO_LPM_MODE, | |
41 | 42 | UPIO_MAX_COUNT |
42 | 43 | }; |
43 | 44 |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/s3c2410_serial0" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_PCM_IF_CLOCK_RATE = 0 |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/s3c2410_serial0" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_PCM_IF_CLOCK_RATE = 0 |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_USE_I2S_INTERFACE = TRUE |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_USE_I2S_INTERFACE = TRUE |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,6 +1,6 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" |
2 | 2 | FW_PATCHFILE_LOCATION = "/etc/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
3 | +BT_WAKE_VIA_PROC = TRUE | |
4 | 4 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 5 | BTVND_DBG = FALSE |
6 | 6 | BTHW_DBG = TRUE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_USE_I2S_INTERFACE = TRUE |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_USE_I2S_INTERFACE = TRUE |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,7 +1,6 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttySAC0" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | 3 | UART_TARGET_BAUD_RATE = 921600 |
4 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
5 | 4 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
6 | 5 | SCO_USE_I2S_INTERFACE = TRUE |
7 | 6 | SCO_I2SPCM_IF_ROLE = 0 |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" |
2 | 2 | FW_PATCHFILE_LOCATION = "/vendor/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | SCO_USE_I2S_INTERFACE = TRUE |
6 | 5 | BTVND_DBG = FALSE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" |
2 | 2 | FW_PATCHFILE_LOCATION = "/etc/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | BTVND_DBG = FALSE |
6 | 5 | BTHW_DBG = TRUE |
@@ -1,6 +1,6 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" |
2 | 2 | FW_PATCHFILE_LOCATION = "/etc/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
3 | +BT_WAKE_VIA_PROC = TRUE | |
4 | 4 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 5 | BTVND_DBG = FALSE |
6 | 6 | BTHW_DBG = TRUE |
@@ -1,6 +1,5 @@ | ||
1 | 1 | BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2" |
2 | 2 | FW_PATCHFILE_LOCATION = "/etc/firmware/" |
3 | -BT_WAKE_VIA_USERIAL_IOCTL = TRUE | |
4 | 3 | LPM_IDLE_TIMEOUT_MULTIPLE = 5 |
5 | 4 | BTVND_DBG = FALSE |
6 | 5 | BTHW_DBG = TRUE |
@@ -197,7 +197,7 @@ static int op(bt_vendor_opcode_t opcode, void *param) | ||
197 | 197 | case BT_VND_OP_LPM_WAKE_SET_STATE: |
198 | 198 | { |
199 | 199 | uint8_t *state = (uint8_t *) param; |
200 | - uint8_t wake_assert = (state == BT_VND_LPM_WAKE_ASSERT) ? \ | |
200 | + uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \ | |
201 | 201 | TRUE : FALSE; |
202 | 202 | |
203 | 203 | hw_lpm_set_wake_state(wake_assert); |
@@ -1045,10 +1045,12 @@ uint8_t hw_lpm_enable(uint8_t turn_on) | ||
1045 | 1045 | if (turn_on) |
1046 | 1046 | { |
1047 | 1047 | memcpy(p, &lpm_param, LPM_CMD_PARAM_SIZE); |
1048 | + upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0); | |
1048 | 1049 | } |
1049 | 1050 | else |
1050 | 1051 | { |
1051 | 1052 | memset(p, 0, LPM_CMD_PARAM_SIZE); |
1053 | + upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0); | |
1052 | 1054 | } |
1053 | 1055 | |
1054 | 1056 | if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_SLEEP_MODE, p_buf, \ |
@@ -54,6 +54,39 @@ | ||
54 | 54 | ** Local type definitions |
55 | 55 | ******************************************************************************/ |
56 | 56 | |
57 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
58 | + | |
59 | +/* proc fs node for enable/disable lpm mode */ | |
60 | +#ifndef VENDOR_LPM_PROC_NODE | |
61 | +#define VENDOR_LPM_PROC_NODE "/proc/bluetooth/sleep/lpm" | |
62 | +#endif | |
63 | + | |
64 | +/* proc fs node for notifying write request */ | |
65 | +#ifndef VENDOR_BTWRITE_PROC_NODE | |
66 | +#define VENDOR_BTWRITE_PROC_NODE "/proc/bluetooth/sleep/btwrite" | |
67 | +#endif | |
68 | + | |
69 | +/* | |
70 | + * Maximum btwrite assertion holding time without consecutive btwrite kicking. | |
71 | + * This value is correlative(shorter) to the in-activity timeout period set in | |
72 | + * the bluesleep LPM code. The current value used in bluesleep is 10sec. | |
73 | + */ | |
74 | +#ifndef PROC_BTWRITE_TIMER_TIMEOUT_MS | |
75 | +#define PROC_BTWRITE_TIMER_TIMEOUT_MS 8000 | |
76 | +#endif | |
77 | + | |
78 | +/* lpm proc control block */ | |
79 | +typedef struct | |
80 | +{ | |
81 | + uint8_t btwrite_active; | |
82 | + uint8_t timer_created; | |
83 | + timer_t timer_id; | |
84 | + uint32_t timeout_ms; | |
85 | +} vnd_lpm_proc_cb_t; | |
86 | + | |
87 | +static vnd_lpm_proc_cb_t lpm_proc_cb; | |
88 | +#endif | |
89 | + | |
57 | 90 | /****************************************************************************** |
58 | 91 | ** Static variables |
59 | 92 | ******************************************************************************/ |
@@ -68,6 +101,12 @@ static char *rfkill_state_path = NULL; | ||
68 | 101 | ******************************************************************************/ |
69 | 102 | |
70 | 103 | /* for friendly debugging outpout string */ |
104 | +static char *lpm_mode[] = { | |
105 | + "UNKNOWN", | |
106 | + "disabled", | |
107 | + "enabled" | |
108 | +}; | |
109 | + | |
71 | 110 | static char *lpm_state[] = { |
72 | 111 | "UNKNOWN", |
73 | 112 | "de-asserted", |
@@ -141,6 +180,23 @@ static int init_rfkill() | ||
141 | 180 | ** LPM Static Functions |
142 | 181 | *****************************************************************************/ |
143 | 182 | |
183 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
184 | +/******************************************************************************* | |
185 | +** | |
186 | +** Function proc_btwrite_timeout | |
187 | +** | |
188 | +** Description Timeout thread of proc/.../btwrite assertion holding timer | |
189 | +** | |
190 | +** Returns None | |
191 | +** | |
192 | +*******************************************************************************/ | |
193 | +static void proc_btwrite_timeout(union sigval arg) | |
194 | +{ | |
195 | + UPIODBG("..%s..", __FUNCTION__); | |
196 | + lpm_proc_cb.btwrite_active = FALSE; | |
197 | +} | |
198 | +#endif | |
199 | + | |
144 | 200 | /***************************************************************************** |
145 | 201 | ** UPIO Interface Functions |
146 | 202 | *****************************************************************************/ |
@@ -157,6 +213,9 @@ static int init_rfkill() | ||
157 | 213 | void upio_init(void) |
158 | 214 | { |
159 | 215 | memset(upio_state, UPIO_UNKNOWN, UPIO_MAX_COUNT); |
216 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
217 | + memset(&lpm_proc_cb, 0, sizeof(vnd_lpm_proc_cb_t)); | |
218 | +#endif | |
160 | 219 | } |
161 | 220 | |
162 | 221 | /******************************************************************************* |
@@ -170,6 +229,12 @@ void upio_init(void) | ||
170 | 229 | *******************************************************************************/ |
171 | 230 | void upio_cleanup(void) |
172 | 231 | { |
232 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
233 | + if (lpm_proc_cb.timer_created == TRUE) | |
234 | + timer_delete(lpm_proc_cb.timer_id); | |
235 | + | |
236 | + lpm_proc_cb.timer_created = FALSE; | |
237 | +#endif | |
173 | 238 | } |
174 | 239 | |
175 | 240 | /******************************************************************************* |
@@ -260,33 +325,157 @@ int upio_set_bluetooth_power(int on) | ||
260 | 325 | void upio_set(uint8_t pio, uint8_t action, uint8_t polarity) |
261 | 326 | { |
262 | 327 | int rc; |
328 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
329 | + int fd = -1; | |
330 | + char buffer; | |
331 | +#endif | |
263 | 332 | |
264 | 333 | switch (pio) |
265 | 334 | { |
266 | - case UPIO_BT_WAKE: | |
335 | + case UPIO_LPM_MODE: | |
336 | + if (upio_state[UPIO_LPM_MODE] == action) | |
337 | + { | |
338 | + UPIODBG("LPM is %s already", lpm_mode[action]); | |
339 | + return; | |
340 | + } | |
341 | + | |
342 | + upio_state[UPIO_LPM_MODE] = action; | |
343 | + | |
344 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
345 | + fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY); | |
346 | + | |
347 | + if (fd < 0) | |
348 | + { | |
349 | + ALOGE("upio_set : open(%s) for write failed: %s (%d)", | |
350 | + VENDOR_LPM_PROC_NODE, strerror(errno), errno); | |
351 | + return; | |
352 | + } | |
353 | + | |
354 | + if (action == UPIO_ASSERT) | |
355 | + { | |
356 | + buffer = '1'; | |
357 | + } | |
358 | + else | |
359 | + { | |
360 | + buffer = '0'; | |
361 | + | |
362 | + // delete btwrite assertion holding timer | |
363 | + if (lpm_proc_cb.timer_created == TRUE) | |
364 | + { | |
365 | + timer_delete(lpm_proc_cb.timer_id); | |
366 | + lpm_proc_cb.timer_created = FALSE; | |
367 | + } | |
368 | + } | |
369 | + | |
370 | + if (write(fd, &buffer, 1) < 0) | |
371 | + { | |
372 | + ALOGE("upio_set : write(%s) failed: %s (%d)", | |
373 | + VENDOR_LPM_PROC_NODE, strerror(errno),errno); | |
374 | + } | |
375 | + else | |
376 | + { | |
377 | + if (action == UPIO_ASSERT) | |
378 | + { | |
379 | + // create btwrite assertion holding timer | |
380 | + if (lpm_proc_cb.timer_created == FALSE) | |
381 | + { | |
382 | + int status; | |
383 | + struct sigevent se; | |
384 | + | |
385 | + se.sigev_notify = SIGEV_THREAD; | |
386 | + se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id; | |
387 | + se.sigev_notify_function = proc_btwrite_timeout; | |
388 | + se.sigev_notify_attributes = NULL; | |
389 | + | |
390 | + status = timer_create(CLOCK_MONOTONIC, &se, | |
391 | + &lpm_proc_cb.timer_id); | |
392 | + | |
393 | + if (status == 0) | |
394 | + lpm_proc_cb.timer_created = TRUE; | |
395 | + } | |
396 | + } | |
397 | + } | |
267 | 398 | |
399 | + if (fd >= 0) | |
400 | + close(fd); | |
401 | +#endif | |
402 | + break; | |
403 | + | |
404 | + case UPIO_BT_WAKE: | |
268 | 405 | if (upio_state[UPIO_BT_WAKE] == action) |
269 | 406 | { |
270 | 407 | UPIODBG("BT_WAKE is %s already", lpm_state[action]); |
408 | + | |
409 | +#if (BT_WAKE_VIA_PROC == TRUE) | |
410 | + if (lpm_proc_cb.btwrite_active == TRUE) | |
411 | + /* | |
412 | + * The proc btwrite node could have not been updated for | |
413 | + * certain time already due to heavy downstream path flow. | |
414 | + * In this case, we want to explicity touch proc btwrite | |
415 | + * node to keep the bt_wake assertion in the LPM kernel | |
416 | + * driver. The current kernel bluesleep LPM code starts | |
417 | + * a 10sec internal in-activity timeout timer before it | |
418 | + * attempts to deassert BT_WAKE line. | |
419 | + */ | |
420 | +#endif | |
271 | 421 | return; |
272 | 422 | } |
273 | 423 | |
274 | 424 | upio_state[UPIO_BT_WAKE] = action; |
275 | 425 | |
276 | - /**************************************** | |
277 | - * !!! TODO !!! | |
278 | - * | |
279 | - * === Custom Porting Required === | |
280 | - * | |
281 | - * Platform dependent user-to-kernel | |
282 | - * interface is required to set output | |
283 | - * state of physical BT_WAKE pin. | |
284 | - ****************************************/ | |
285 | 426 | #if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE) |
427 | + | |
286 | 428 | userial_vendor_ioctl( ( (action==UPIO_ASSERT) ? \ |
287 | 429 | USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE),\ |
288 | 430 | NULL); |
431 | + | |
432 | +#elif (BT_WAKE_VIA_PROC == TRUE) | |
433 | + | |
434 | + /* | |
435 | + * Kick proc btwrite node only at UPIO_ASSERT | |
436 | + */ | |
437 | + if (action == UPIO_DEASSERT) | |
438 | + return; | |
439 | + | |
440 | + fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY); | |
441 | + | |
442 | + if (fd < 0) | |
443 | + { | |
444 | + ALOGE("upio_set : open(%s) for write failed: %s (%d)", | |
445 | + VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno); | |
446 | + return; | |
447 | + } | |
448 | + | |
449 | + buffer = '1'; | |
450 | + | |
451 | + if (write(fd, &buffer, 1) < 0) | |
452 | + { | |
453 | + ALOGE("upio_set : write(%s) failed: %s (%d)", | |
454 | + VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno); | |
455 | + } | |
456 | + else | |
457 | + { | |
458 | + lpm_proc_cb.btwrite_active = TRUE; | |
459 | + | |
460 | + if (lpm_proc_cb.timer_created == TRUE) | |
461 | + { | |
462 | + struct itimerspec ts; | |
463 | + | |
464 | + ts.it_value.tv_sec = PROC_BTWRITE_TIMER_TIMEOUT_MS/1000; | |
465 | + ts.it_value.tv_nsec = 1000*(PROC_BTWRITE_TIMER_TIMEOUT_MS%1000); | |
466 | + ts.it_interval.tv_sec = 0; | |
467 | + ts.it_interval.tv_nsec = 0; | |
468 | + | |
469 | + timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0); | |
470 | + } | |
471 | + } | |
472 | + | |
473 | + UPIODBG("proc btwrite assertion"); | |
474 | + | |
475 | + if (fd >= 0) | |
476 | + close(fd); | |
289 | 477 | #endif |
478 | + | |
290 | 479 | break; |
291 | 480 | |
292 | 481 | case UPIO_HOST_WAKE: |