1/******************************************************************************
2 *
3 *  Copyright (C) 2010-2014 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 *  This is the main implementation file for the NFA system manager.
22 *
23 ******************************************************************************/
24#include <string.h>
25
26#include <android-base/stringprintf.h>
27#include <base/logging.h>
28
29#include "nfa_api.h"
30#include "nfa_dm_int.h"
31#include "nfa_sys_int.h"
32
33using android::base::StringPrintf;
34
35extern bool nfc_debug_enabled;
36
37/* protocol timer update period, in milliseconds */
38#ifndef NFA_SYS_TIMER_PERIOD
39#define NFA_SYS_TIMER_PERIOD 10
40#endif
41
42/* system manager control block definition */
43tNFA_SYS_CB nfa_sys_cb = {};
44/* nfa_sys control block. statically initialize 'flags' field to 0 */
45
46/*******************************************************************************
47**
48** Function         nfa_sys_init
49**
50** Description      NFA initialization; called from task initialization.
51**
52**
53** Returns          void
54**
55*******************************************************************************/
56void nfa_sys_init(void) {
57  memset(&nfa_sys_cb, 0, sizeof(tNFA_SYS_CB));
58  nfa_sys_cb.flags |= NFA_SYS_FL_INITIALIZED;
59  nfa_sys_ptim_init(&nfa_sys_cb.ptim_cb, NFA_SYS_TIMER_PERIOD,
60                    p_nfa_sys_cfg->timer);
61}
62
63/*******************************************************************************
64**
65** Function         nfa_sys_event
66**
67** Description      BTA event handler; called from task event handler.
68**
69**
70** Returns          void
71**
72*******************************************************************************/
73void nfa_sys_event(NFC_HDR* p_msg) {
74  uint8_t id;
75  bool freebuf = true;
76
77  DLOG_IF(INFO, nfc_debug_enabled)
78      << StringPrintf("NFA got event 0x%04X", p_msg->event);
79
80  /* get subsystem id from event */
81  id = (uint8_t)(p_msg->event >> 8);
82
83  /* verify id and call subsystem event handler */
84  if ((id < NFA_ID_MAX) && (nfa_sys_cb.is_reg[id])) {
85    freebuf = (*nfa_sys_cb.reg[id]->evt_hdlr)(p_msg);
86  } else {
87    LOG(WARNING) << StringPrintf("NFA got unregistered event id %d", id);
88  }
89
90  if (freebuf) {
91    GKI_freebuf(p_msg);
92  }
93}
94
95/*******************************************************************************
96**
97** Function         nfa_sys_timer_update
98**
99** Description      Update the BTA timer list and handle expired timers.
100**
101** Returns          void
102**
103*******************************************************************************/
104void nfa_sys_timer_update(void) {
105  if (!nfa_sys_cb.timers_disabled) {
106    nfa_sys_ptim_timer_update(&nfa_sys_cb.ptim_cb);
107  }
108}
109
110/*******************************************************************************
111**
112** Function         nfa_sys_register
113**
114** Description      Called by other BTA subsystems to register their event
115**                  handler.
116**
117**
118** Returns          void
119**
120*******************************************************************************/
121void nfa_sys_register(uint8_t id, const tNFA_SYS_REG* p_reg) {
122  nfa_sys_cb.reg[id] = (tNFA_SYS_REG*)p_reg;
123  nfa_sys_cb.is_reg[id] = true;
124
125  if ((id != NFA_ID_DM) && (id != NFA_ID_SYS))
126    nfa_sys_cb.enable_cplt_mask |= (0x0001 << id);
127
128  if (id != NFA_ID_SYS) {
129    if (p_reg->proc_nfcc_pwr_mode)
130      nfa_sys_cb.proc_nfcc_pwr_mode_cplt_mask |= (0x0001 << id);
131  }
132
133  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
134      "id=%i, enable_cplt_mask=0x%x", id, nfa_sys_cb.enable_cplt_mask);
135}
136
137/*******************************************************************************
138**
139** Function         nfa_sys_check_disabled
140**
141** Description      If all subsystems above DM have been disabled, then
142**                  disable DM. Called during NFA shutdown
143**
144** Returns          void
145**
146*******************************************************************************/
147void nfa_sys_check_disabled(void) {
148  uint8_t id;
149  uint8_t done = true;
150
151  /* Check if all subsystems above DM have been disabled. */
152  for (id = (NFA_ID_DM + 1); id < NFA_ID_MAX; id++) {
153    if (nfa_sys_cb.is_reg[id]) {
154      /* as long as one subsystem is not done */
155      done = false;
156      break;
157    }
158  }
159
160  /* All subsystems disabled. disable DM */
161  if ((done) && (nfa_sys_cb.is_reg[NFA_ID_DM])) {
162    (*nfa_sys_cb.reg[NFA_ID_DM]->disable)();
163  }
164}
165
166/*******************************************************************************
167**
168** Function         nfa_sys_deregister
169**
170** Description      Called by other BTA subsystems to de-register
171**                  handler.
172**
173**
174** Returns          void
175**
176*******************************************************************************/
177void nfa_sys_deregister(uint8_t id) {
178  DLOG_IF(INFO, nfc_debug_enabled)
179      << StringPrintf("nfa_sys: deregistering subsystem %i", id);
180
181  nfa_sys_cb.is_reg[id] = false;
182
183  /* If not deregistering DM, then check if any other subsystems above DM are
184   * still  */
185  /* registered. */
186  if (id != NFA_ID_DM) {
187    /* If all subsystems above NFA_DM have been disabled, then okay to disable
188     * DM */
189    nfa_sys_check_disabled();
190  } else {
191    /* DM (the final sub-system) is deregistering. Clear pending timer events in
192     * nfa_sys. */
193    nfa_sys_ptim_init(&nfa_sys_cb.ptim_cb, NFA_SYS_TIMER_PERIOD,
194                      p_nfa_sys_cfg->timer);
195  }
196}
197
198/*******************************************************************************
199**
200** Function         nfa_sys_is_register
201**
202** Description      Called by other BTA subsystems to get registeration
203**                  status.
204**
205**
206** Returns          void
207**
208*******************************************************************************/
209bool nfa_sys_is_register(uint8_t id) { return nfa_sys_cb.is_reg[id]; }
210
211/*******************************************************************************
212**
213** Function         nfa_sys_is_graceful_disable
214**
215** Description      Called by other BTA subsystems to get disable
216**                  parameter.
217**
218**
219** Returns          void
220**
221*******************************************************************************/
222bool nfa_sys_is_graceful_disable(void) { return nfa_sys_cb.graceful_disable; }
223
224/*******************************************************************************
225**
226** Function         nfa_sys_enable_subsystems
227**
228** Description      Call on NFA Start up
229**
230** Returns          void
231**
232*******************************************************************************/
233void nfa_sys_enable_subsystems(void) {
234  uint8_t id;
235
236  DLOG_IF(INFO, nfc_debug_enabled)
237      << StringPrintf("nfa_sys: enabling subsystems");
238
239  /* Enable all subsystems except SYS */
240  for (id = NFA_ID_DM; id < NFA_ID_MAX; id++) {
241    if (nfa_sys_cb.is_reg[id]) {
242      if (nfa_sys_cb.reg[id]->enable != NULL) {
243        /* Subsytem has a Disable funciton. Call it now */
244        (*nfa_sys_cb.reg[id]->enable)();
245      } else {
246        /* Subsytem does not have a Enable function. Report Enable on behalf of
247         * subsystem */
248        nfa_sys_cback_notify_enable_complete(id);
249      }
250    }
251  }
252}
253
254/*******************************************************************************
255**
256** Function         nfa_sys_disable_subsystems
257**
258** Description      Call on NFA shutdown. Disable all subsystems above NFA_DM
259**
260** Returns          void
261**
262*******************************************************************************/
263void nfa_sys_disable_subsystems(bool graceful) {
264  uint8_t id;
265  bool done = true;
266
267  DLOG_IF(INFO, nfc_debug_enabled)
268      << StringPrintf("nfa_sys: disabling subsystems:%d", graceful);
269  nfa_sys_cb.graceful_disable = graceful;
270
271  /* Disable all subsystems above NFA_DM. (NFA_DM and NFA_SYS will be disabled
272   * last) */
273  for (id = (NFA_ID_DM + 1); id < NFA_ID_MAX; id++) {
274    if (nfa_sys_cb.is_reg[id]) {
275      done = false;
276      if (nfa_sys_cb.reg[id]->disable != NULL) {
277        /* Subsytem has a Disable funciton. Call it now */
278        (*nfa_sys_cb.reg[id]->disable)();
279      } else {
280        /* Subsytem does not have a Disable function. Deregister on behalf of
281         * subsystem */
282        nfa_sys_deregister(id);
283      }
284    }
285  }
286
287  /* If All subsystems disabled. disable DM */
288  if ((done) && (nfa_sys_cb.is_reg[NFA_ID_DM])) {
289    (*nfa_sys_cb.reg[NFA_ID_DM]->disable)();
290  }
291}
292
293/*******************************************************************************
294**
295** Function         nfa_sys_notify_nfcc_power_mode
296**
297** Description      Call to notify NFCC power mode to NFA sub-modules
298**
299** Returns          void
300**
301*******************************************************************************/
302void nfa_sys_notify_nfcc_power_mode(uint8_t nfcc_power_mode) {
303  uint8_t id;
304
305  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
306      "nfa_sys: notify NFCC power mode(%d) to subsystems", nfcc_power_mode);
307
308  /* Notify NFCC power state to all subsystems except NFA_SYS */
309  for (id = NFA_ID_DM; id < NFA_ID_MAX; id++) {
310    if ((nfa_sys_cb.is_reg[id]) && (nfa_sys_cb.reg[id]->proc_nfcc_pwr_mode)) {
311      /* Subsytem has a funciton for processing NFCC power mode. Call it now */
312      (*nfa_sys_cb.reg[id]->proc_nfcc_pwr_mode)(nfcc_power_mode);
313    }
314  }
315}
316
317/*******************************************************************************
318**
319** Function         nfa_sys_sendmsg
320**
321** Description      Send a GKI message to BTA.  This function is designed to
322**                  optimize sending of messages to BTA.  It is called by BTA
323**                  API functions and call-in functions.
324**
325**
326** Returns          void
327**
328*******************************************************************************/
329void nfa_sys_sendmsg(void* p_msg) {
330  GKI_send_msg(NFC_TASK, p_nfa_sys_cfg->mbox, p_msg);
331}
332
333/*******************************************************************************
334**
335** Function         nfa_sys_start_timer
336**
337** Description      Start a protocol timer for the specified amount
338**                  of time in milliseconds.
339**
340** Returns          void
341**
342*******************************************************************************/
343void nfa_sys_start_timer(TIMER_LIST_ENT* p_tle, uint16_t type,
344                         int32_t timeout) {
345  nfa_sys_ptim_start_timer(&nfa_sys_cb.ptim_cb, p_tle, type, timeout);
346}
347
348/*******************************************************************************
349**
350** Function         nfa_sys_stop_timer
351**
352** Description      Stop a BTA timer.
353**
354** Returns          void
355**
356*******************************************************************************/
357void nfa_sys_stop_timer(TIMER_LIST_ENT* p_tle) {
358  nfa_sys_ptim_stop_timer(&nfa_sys_cb.ptim_cb, p_tle);
359}
360
361/*******************************************************************************
362**
363** Function         nfa_sys_disable_timers
364**
365** Description      Disable sys timer event handling
366**
367** Returns          void
368**
369*******************************************************************************/
370void nfa_sys_disable_timers(void) { nfa_sys_cb.timers_disabled = true; }
371