OSDN Git Service

am 5ac0afff: am c1553d3c: Load factory Bluetooth address from system property
[android-x86/system-bt.git] / hci / src / low_power_manager.c
1 /******************************************************************************
2  *
3  *  Copyright (C) 2014 Google, Inc.
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 #define LOG_TAG "bt_low_power_manager"
20
21 #include "low_power_manager.h"
22
23 #include <assert.h>
24 #include <stdint.h>
25
26 #include "osi/include/alarm.h"
27 #include "osi/include/log.h"
28 #include "osi/include/osi.h"
29 #include "osi/include/thread.h"
30 #include "vendor.h"
31
32 typedef enum {
33   LPM_DISABLED = 0,
34   LPM_ENABLED,
35   LPM_ENABLING,
36   LPM_DISABLING
37 } low_power_mode_state_t;
38
39 typedef enum {
40   LPM_WAKE_DEASSERTED = 0,
41   LPM_WAKE_W4_TX_DONE,
42   LPM_WAKE_W4_TIMEOUT,
43   LPM_WAKE_ASSERTED,
44 } wake_state_t;
45
46 // Our interface and modules we import
47 static const low_power_manager_t interface;
48 static const vendor_t *vendor;
49
50 static void vendor_enable_disable_callback(bool success);
51
52 static void event_disable(void *context);
53 static void event_enable(void *context);
54 static void event_wake_assert(void *context);
55 static void event_allow_device_sleep(void *context);
56 static void event_idle_timeout(void *context);
57
58 static void reset_state();
59 static void start_idle_timer();
60 static void stop_idle_timer();
61
62 static thread_fn event_functions[] = {
63   event_disable,
64   event_enable,
65   event_wake_assert,
66   event_allow_device_sleep
67 };
68
69 static thread_t *thread;
70 static low_power_mode_state_t state;
71 static wake_state_t wake_state;
72 static uint32_t idle_timeout_ms;
73 static alarm_t *idle_alarm;
74 static bool transmit_is_done;
75
76 // Interface functions
77
78 static void init(thread_t *post_thread) {
79   assert(post_thread != NULL);
80   thread = post_thread;
81
82   vendor->set_callback(VENDOR_SET_LPM_MODE, vendor_enable_disable_callback);
83   vendor->send_command(VENDOR_GET_LPM_IDLE_TIMEOUT, &idle_timeout_ms);
84
85   idle_alarm = alarm_new();
86   if (!idle_alarm) {
87     LOG_ERROR(LOG_TAG, "%s could not create idle alarm.", __func__);
88   }
89
90   reset_state();
91 }
92
93 static void cleanup() {
94   reset_state();
95   alarm_free(idle_alarm);
96   idle_alarm = NULL;
97 }
98
99 static void post_command(low_power_command_t command) {
100   if (command > LPM_WAKE_DEASSERT) {
101     LOG_ERROR(LOG_TAG, "%s unknown low power command %d", __func__, command);
102     return;
103   }
104
105   thread_post(thread, event_functions[command], NULL);
106 }
107
108 static void wake_assert() {
109   if (state != LPM_DISABLED) {
110     stop_idle_timer();
111
112     uint8_t new_state = BT_VND_LPM_WAKE_ASSERT;
113     vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
114     wake_state = LPM_WAKE_ASSERTED;
115   }
116
117   // TODO(zachoverflow): investigate this interaction. If someone above
118   // HCI asserts wake, we'll wait until we transmit before deasserting.
119   // That doesn't seem quite right.
120   transmit_is_done = false;
121 }
122
123 static void transmit_done() {
124   transmit_is_done = true;
125   if (wake_state == LPM_WAKE_W4_TX_DONE) {
126     wake_state = LPM_WAKE_W4_TIMEOUT;
127     start_idle_timer();
128   }
129 }
130
131 // Internal functions
132
133 static void enable(bool enable) {
134   if (state == LPM_DISABLING) {
135     if (enable)
136       LOG_ERROR(LOG_TAG, "%s still processing prior disable request, cannot enable.", __func__);
137     else
138       LOG_WARN(LOG_TAG, "%s still processing prior disable request, ignoring new request to disable.", __func__);
139   } else if (state == LPM_ENABLING) {
140     if (enable)
141       LOG_ERROR(LOG_TAG, "%s still processing prior enable request, ignoring new request to enable.", __func__);
142     else
143       LOG_WARN(LOG_TAG, "%s still processing prior enable request, cannot disable.", __func__);
144   } else if (state == LPM_ENABLED && enable) {
145     LOG_INFO(LOG_TAG, "%s already enabled.", __func__);
146   } else if (state == LPM_DISABLED && !enable) {
147     LOG_INFO(LOG_TAG, "%s already disabled.", __func__);
148   } else {
149     uint8_t command = enable ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
150     state = enable ? LPM_ENABLING : LPM_DISABLING;
151     vendor->send_async_command(VENDOR_SET_LPM_MODE, &command);
152   }
153 }
154
155 static void allow_device_sleep() {
156   if (state == LPM_ENABLED && wake_state == LPM_WAKE_ASSERTED) {
157     if (transmit_is_done) {
158       wake_state = LPM_WAKE_W4_TIMEOUT;
159       start_idle_timer();
160     } else {
161       wake_state = LPM_WAKE_W4_TX_DONE;
162     }
163   }
164 }
165
166 static void wake_deassert() {
167   if (state == LPM_ENABLED && transmit_is_done) {
168     uint8_t new_state = BT_VND_LPM_WAKE_DEASSERT;
169     vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
170     wake_state = LPM_WAKE_DEASSERTED;
171   }
172 }
173
174 static void reset_state() {
175   state = LPM_DISABLED;
176   wake_state = LPM_WAKE_DEASSERTED;
177   transmit_is_done = true;
178   stop_idle_timer();
179 }
180
181 static void idle_timer_expired(UNUSED_ATTR void *context) {
182   if (state == LPM_ENABLED && wake_state == LPM_WAKE_W4_TIMEOUT)
183     thread_post(thread, event_idle_timeout, NULL);
184 }
185
186 static void start_idle_timer() {
187   if (state == LPM_ENABLED) {
188     alarm_set(idle_alarm, idle_timeout_ms, idle_timer_expired, NULL);
189   }
190 }
191
192 static void stop_idle_timer() {
193   alarm_cancel(idle_alarm);
194 }
195
196 static void event_disable(UNUSED_ATTR void *context) {
197   enable(false);
198 }
199
200 static void event_enable(UNUSED_ATTR void *context) {
201   enable(true);
202 }
203
204 static void event_wake_assert(UNUSED_ATTR void *context) {
205   wake_assert();
206 }
207
208 static void event_allow_device_sleep(UNUSED_ATTR void *context) {
209   allow_device_sleep();
210 }
211
212 static void event_idle_timeout(UNUSED_ATTR void *context) {
213   wake_deassert();
214 }
215
216 static void vendor_enable_disable_callback(bool success) {
217   if (success)
218     state = (state == LPM_ENABLING) ? LPM_ENABLED : LPM_DISABLED;
219   else
220     state = (state == LPM_ENABLING) ? LPM_DISABLED : LPM_ENABLED;
221
222   if (state == LPM_DISABLED) {
223     reset_state();
224   }
225 }
226
227 static const low_power_manager_t interface = {
228   init,
229   cleanup,
230   post_command,
231   wake_assert,
232   transmit_done
233 };
234
235 const low_power_manager_t *low_power_manager_get_interface() {
236   vendor = vendor_get_interface();
237   return &interface;
238 }
239
240 const low_power_manager_t *low_power_manager_get_test_interface(const vendor_t *vendor_interface) {
241   vendor = vendor_interface;
242   return &interface;
243 }