1 /*
2 * Copyright (C) 2012-2014 NXP Semiconductors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <phNxpLog.h>
18 #include <phNxpNciHal.h>
19 #include <phNxpNciHal_NfcDepSWPrio.h>
20
21 /* Timeout value to wait for NFC-DEP detection.*/
22 #define CUSTOM_POLL_TIMEOUT 160
23 #define CLEAN_UP_TIMEOUT 250
24 #define MAX_WRITE_RETRY 5
25
26 /******************* Global variables *****************************************/
27 extern phNxpNciHal_Control_t nxpncihal_ctrl;
28 extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t* p_cmd);
29 static uint8_t cmd_stop_rf_discovery[] = {0x21, 0x06, 0x01, 0x00}; /* IDLE */
30 static uint8_t cmd_resume_rf_discovery[] = {0x21, 0x06, 0x01,
31 0x03}; /* RF_DISCOVER */
32
33 /*RF_DISCOVER_SELECT_CMD*/
34 static uint8_t cmd_select_rf_discovery[] = {0x21, 0x04, 0x03, 0x01, 0x04, 0x02};
35
36 static uint8_t cmd_poll[64];
37 static uint8_t cmd_poll_len = 0;
38 int discover_type = 0xFF;
39 uint32_t cleanup_timer;
40
41 /*PRIO LOGIC related dead functions undefined*/
42 #ifdef P2P_PRIO_LOGIC_HAL_IMP
43
44 static int iso_dep_detected = 0x00;
45 static int poll_timer_fired = 0x00;
46 static uint8_t bIgnorep2plogic = 0;
47 static uint8_t* p_iso_ntf_buff = NULL; /* buffer to store second notification */
48 static uint8_t bIgnoreIsoDep = 0;
49 static uint32_t custom_poll_timer;
50
51 /************** NFC-DEP SW PRIO functions *************************************/
52
53 static NFCSTATUS phNxpNciHal_start_polling_loop(void);
54 static NFCSTATUS phNxpNciHal_stop_polling_loop(void);
55 static NFCSTATUS phNxpNciHal_resume_polling_loop(void);
56 static void phNxpNciHal_NfcDep_store_ntf(uint8_t* p_cmd_data, uint16_t cmd_len);
57
58 /*******************************************************************************
59 **
60 ** Function cleanup_timer_handler
61 **
62 ** Description Callback function for cleanup timer.
63 **
64 ** Returns None
65 **
66 *******************************************************************************/
cleanup_timer_handler(uint32_t timerId,void * pContext)67 static void cleanup_timer_handler(uint32_t timerId, void* pContext) {
68 NXPLOG_NCIHAL_D(">> cleanup_timer_handler.");
69
70 NXPLOG_NCIHAL_D(
71 ">> cleanup_timer_handler. ISO_DEP not detected second time.");
72
73 phOsalNfc_Timer_Delete(cleanup_timer);
74 cleanup_timer = 0;
75 iso_dep_detected = 0x00;
76 EnableP2P_PrioLogic = false;
77 return;
78 }
79
80 /*******************************************************************************
81 **
82 ** Function custom_poll_timer_handler
83 **
84 ** Description Callback function for custom poll timer.
85 **
86 ** Returns None
87 **
88 *******************************************************************************/
custom_poll_timer_handler(uint32_t timerId,void * pContext)89 static void custom_poll_timer_handler(uint32_t timerId, void* pContext) {
90 NXPLOG_NCIHAL_D(">> custom_poll_timer_handler.");
91
92 NXPLOG_NCIHAL_D(
93 ">> custom_poll_timer_handler. NFC_DEP not detected. so giving early "
94 "chance to ISO_DEP.");
95
96 phOsalNfc_Timer_Delete(custom_poll_timer);
97
98 if (iso_dep_detected == 0x01) {
99 poll_timer_fired = 0x01;
100
101 /*
102 * Restart polling loop.
103 * When the polling loop is stopped, polling will be restarted.
104 */
105 NXPLOG_NCIHAL_D(">> custom_poll_timer_handler - restart polling loop.");
106
107 phNxpNciHal_stop_polling_loop();
108 } else {
109 NXPLOG_NCIHAL_E(
110 ">> custom_poll_timer_handler - invalid flag state (iso_dep_detected)");
111 }
112
113 return;
114 }
115 /*******************************************************************************
116 **
117 ** Function phNxpNciHal_stop_polling_loop
118 **
119 ** Description Sends stop polling cmd to NFCC
120 **
121 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
122 **
123 *******************************************************************************/
phNxpNciHal_stop_polling_loop()124 static NFCSTATUS phNxpNciHal_stop_polling_loop() {
125 NFCSTATUS status = NFCSTATUS_SUCCESS;
126 phNxpNciHal_Sem_t cb_data;
127 pthread_t pthread;
128 discover_type = STOP_POLLING;
129
130 pthread_attr_t attr;
131 pthread_attr_init(&attr);
132 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
133 if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
134 NXPLOG_NCIHAL_E("fail to create pthread");
135 }
136 pthread_attr_destroy(&attr);
137 return status;
138 }
139
140 /*******************************************************************************
141 **
142 ** Function phNxpNciHal_resume_polling_loop
143 **
144 ** Description Sends resume polling cmd to NFCC
145 **
146 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
147 **
148 *******************************************************************************/
phNxpNciHal_resume_polling_loop()149 static NFCSTATUS phNxpNciHal_resume_polling_loop() {
150 NFCSTATUS status = NFCSTATUS_SUCCESS;
151 phNxpNciHal_Sem_t cb_data;
152 pthread_t pthread;
153 discover_type = RESUME_POLLING;
154
155 pthread_attr_t attr;
156 pthread_attr_init(&attr);
157 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
158 if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
159 NXPLOG_NCIHAL_E("fail to create pthread");
160 }
161 pthread_attr_destroy(&attr);
162 return status;
163 }
164
165 /*******************************************************************************
166 **
167 ** Function phNxpNciHal_start_polling_loop
168 **
169 ** Description Sends start polling cmd to NFCC
170 **
171 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
172 **
173 *******************************************************************************/
phNxpNciHal_start_polling_loop()174 NFCSTATUS phNxpNciHal_start_polling_loop() {
175 NFCSTATUS status = NFCSTATUS_FAILED;
176 phNxpNciHal_Sem_t cb_data;
177 pthread_t pthread;
178 discover_type = START_POLLING;
179
180 pthread_attr_t attr;
181 pthread_attr_init(&attr);
182 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
183 if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
184 NXPLOG_NCIHAL_E("fail to create pthread");
185 }
186 pthread_attr_destroy(&attr);
187 return status;
188 }
189
190 /*******************************************************************************
191 **
192 ** Function phNxpNciHal_NfcDep_rsp_ext
193 **
194 ** Description Implements algorithm for NFC-DEP protocol priority over
195 ** ISO-DEP protocol.
196 ** Following the algorithm:
197 ** IF ISO-DEP detected first time,set the ISO-DEP detected flag
198 ** and resume polling loop with 60ms timeout value.
199 ** a) if than NFC-DEP detected than send the response to
200 ** libnfc-nci stack and stop the timer.
201 ** b) if NFC-DEP not detected with in 60ms, than restart
202 ** the polling loop to give early chance to ISO-DEP with
203 ** a cleanup timer.
204 ** c) if ISO-DEP detected second time send the response to
205 ** libnfc-nci stack and stop the cleanup timer.
206 ** d) if ISO-DEP not detected with in cleanup timeout, than
207 ** clear the ISO-DEP detection flag.
208 **
209 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
210 **
211 *******************************************************************************/
phNxpNciHal_NfcDep_rsp_ext(uint8_t * p_ntf,uint16_t * p_len)212 NFCSTATUS phNxpNciHal_NfcDep_rsp_ext(uint8_t* p_ntf, uint16_t* p_len) {
213 NFCSTATUS status = NFCSTATUS_INVALID_PARAMETER;
214
215 NXPLOG_NCIHAL_D(">> p_ntf[0]=%02x , p_ntf[1]=%02x", p_ntf[0], p_ntf[1]);
216
217 if (p_ntf[0] == 0x41 && p_ntf[1] == 0x04) {
218 // Tag selected, Disable P2P Prio logic.
219 bIgnoreIsoDep = 1;
220 NXPLOG_NCIHAL_D(">> Tag selected, Disable P2P Prio logic.");
221
222 } else if (((p_ntf[0] == 0x61 && p_ntf[1] == 0x06) ||
223 (p_ntf[0] == 0x41 && p_ntf[1] == 0x06)) &&
224 bIgnoreIsoDep == 1) {
225 // Tag deselected, enable P2P Prio logic.
226 bIgnoreIsoDep = 0x00;
227 NXPLOG_NCIHAL_D(">> Tag deselected, enable P2P Prio logic.");
228 }
229 if (bIgnoreIsoDep == 0x00 && p_ntf[0] == 0x61 && p_ntf[1] == 0x05 &&
230 *p_len > 5) {
231 if (p_ntf[5] == 0x04 && p_ntf[6] < 0x80) {
232 NXPLOG_NCIHAL_D(">> ISO DEP detected.");
233
234 if (iso_dep_detected == 0x00) {
235 NXPLOG_NCIHAL_D(">> ISO DEP detected first time. Resume polling loop");
236
237 iso_dep_detected = 0x01;
238 status = phNxpNciHal_resume_polling_loop();
239
240 custom_poll_timer = phOsalNfc_Timer_Create();
241 NXPLOG_NCIHAL_D("custom poll timer started - %d", custom_poll_timer);
242
243 status = phOsalNfc_Timer_Start(custom_poll_timer, CUSTOM_POLL_TIMEOUT,
244 &custom_poll_timer_handler, NULL);
245
246 if (NFCSTATUS_SUCCESS == status) {
247 NXPLOG_NCIHAL_D("custom poll timer started");
248 } else {
249 NXPLOG_NCIHAL_E("custom poll timer not started!!!");
250 status = NFCSTATUS_FAILED;
251 }
252
253 status = NFCSTATUS_FAILED;
254 } else {
255 NXPLOG_NCIHAL_D(">> ISO DEP detected second time.");
256 /* Store notification */
257 phNxpNciHal_NfcDep_store_ntf(p_ntf, *p_len);
258
259 /* Stop Cleanup_timer */
260 phOsalNfc_Timer_Stop(cleanup_timer);
261 phOsalNfc_Timer_Delete(cleanup_timer);
262 cleanup_timer = 0;
263 EnableP2P_PrioLogic = false;
264 iso_dep_detected = 0;
265 status = NFCSTATUS_SUCCESS;
266 }
267 } else if (p_ntf[5] == 0x05) {
268 NXPLOG_NCIHAL_D(">> NFC-DEP Detected - stopping the custom poll timer");
269
270 phOsalNfc_Timer_Stop(custom_poll_timer);
271 phOsalNfc_Timer_Delete(custom_poll_timer);
272 EnableP2P_PrioLogic = false;
273 iso_dep_detected = 0;
274 status = NFCSTATUS_SUCCESS;
275 } else {
276 NXPLOG_NCIHAL_D(
277 ">> detected other technology- stopping the custom poll timer");
278 phOsalNfc_Timer_Stop(custom_poll_timer);
279 phOsalNfc_Timer_Delete(custom_poll_timer);
280 EnableP2P_PrioLogic = false;
281 iso_dep_detected = 0;
282 status = NFCSTATUS_INVALID_PARAMETER;
283 }
284 } else if (bIgnoreIsoDep == 0x00 &&
285 ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ||
286 (p_ntf[0] == 0x61 && p_ntf[1] == 0x06))) {
287 NXPLOG_NCIHAL_D(">> RF disabled");
288 if (poll_timer_fired == 0x01) {
289 poll_timer_fired = 0x00;
290
291 NXPLOG_NCIHAL_D(">>restarting polling loop.");
292
293 /* start polling loop */
294 phNxpNciHal_start_polling_loop();
295 EnableP2P_PrioLogic = false;
296 NXPLOG_NCIHAL_D(
297 ">> NFC DEP NOT detected - custom poll timer expired - RF disabled");
298
299 cleanup_timer = phOsalNfc_Timer_Create();
300
301 /* Start cleanup_timer */
302 NFCSTATUS status = phOsalNfc_Timer_Start(cleanup_timer, CLEAN_UP_TIMEOUT,
303 &cleanup_timer_handler, NULL);
304
305 if (NFCSTATUS_SUCCESS == status) {
306 NXPLOG_NCIHAL_D("cleanup timer started");
307 } else {
308 NXPLOG_NCIHAL_E("cleanup timer not started!!!");
309 status = NFCSTATUS_FAILED;
310 }
311
312 status = NFCSTATUS_FAILED;
313 } else {
314 status = NFCSTATUS_SUCCESS;
315 }
316 }
317 if (bIgnoreIsoDep == 0x00 && iso_dep_detected == 1) {
318 if ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ||
319 (p_ntf[0] == 0x61 && p_ntf[1] == 0x06)) {
320 NXPLOG_NCIHAL_D(">>iso_dep_detected Disconnect related notification");
321 status = NFCSTATUS_FAILED;
322 } else {
323 NXPLOG_NCIHAL_W("Never come here");
324 }
325 }
326
327 return status;
328 }
329 /*******************************************************************************
330 **
331 ** Function phNxpNciHal_NfcDep_store_ntf
332 **
333 ** Description Stores the iso dep notification locally.
334 **
335 ** Returns None
336 **
337 *******************************************************************************/
phNxpNciHal_NfcDep_store_ntf(uint8_t * p_cmd_data,uint16_t cmd_len)338 static void phNxpNciHal_NfcDep_store_ntf(uint8_t* p_cmd_data,
339 uint16_t cmd_len) {
340 p_iso_ntf_buff = NULL;
341
342 p_iso_ntf_buff = malloc(sizeof(uint8_t) * cmd_len);
343 if (p_iso_ntf_buff == NULL) {
344 NXPLOG_NCIHAL_E("Error allocating memory (p_iso_ntf_buff)");
345 return;
346 }
347 memcpy(p_iso_ntf_buff, p_cmd_data, cmd_len);
348 bIgnorep2plogic = 1;
349 }
350
351 /*******************************************************************************
352 **
353 ** Function phNxpNciHal_NfcDep_comapre_ntf
354 **
355 ** Description Compare the notification with previous iso dep notification.
356 **
357 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
358 **
359 *******************************************************************************/
phNxpNciHal_NfcDep_comapre_ntf(uint8_t * p_cmd_data,uint16_t cmd_len)360 NFCSTATUS phNxpNciHal_NfcDep_comapre_ntf(uint8_t* p_cmd_data,
361 uint16_t cmd_len) {
362 NFCSTATUS status = NFCSTATUS_FAILED;
363 int32_t ret_val = -1;
364
365 if (bIgnorep2plogic == 1) {
366 ret_val = memcmp(p_cmd_data, p_iso_ntf_buff, cmd_len);
367 if (ret_val != 0) {
368 NXPLOG_NCIHAL_E("Third notification is not equal to last");
369 } else {
370 NXPLOG_NCIHAL_E(
371 "Third notification is equal to last (disable p2p logic)");
372 status = NFCSTATUS_SUCCESS;
373 }
374 bIgnorep2plogic = 0;
375 }
376 if (p_iso_ntf_buff != NULL) {
377 free(p_iso_ntf_buff);
378 p_iso_ntf_buff = NULL;
379 }
380
381 return status;
382 }
383
phNxpNciHal_clean_P2P_Prio()384 extern NFCSTATUS phNxpNciHal_clean_P2P_Prio() {
385 NFCSTATUS status = NFCSTATUS_SUCCESS;
386
387 iso_dep_detected = 0x00;
388 EnableP2P_PrioLogic = false;
389 poll_timer_fired = 0x00;
390 bIgnorep2plogic = 0x00;
391 bIgnoreIsoDep = 0x00;
392
393 status = phOsalNfc_Timer_Stop(cleanup_timer);
394 status |= phOsalNfc_Timer_Delete(cleanup_timer);
395
396 status |= phOsalNfc_Timer_Stop(custom_poll_timer);
397 status |= phOsalNfc_Timer_Delete(custom_poll_timer);
398 cleanup_timer = 0;
399 return status;
400 }
401
402 #endif
403 /*******************************************************************************
404 **
405 ** Function hal_write_cb
406 **
407 ** Description Callback function for hal write.
408 **
409 ** Returns None
410 **
411 *******************************************************************************/
hal_write_cb(void * pContext,phTmlNfc_TransactInfo_t * pInfo)412 static void hal_write_cb(void* pContext, phTmlNfc_TransactInfo_t* pInfo) {
413 phNxpNciHal_Sem_t* p_cb_data = (phNxpNciHal_Sem_t*)pContext;
414
415 if (pInfo->wStatus == NFCSTATUS_SUCCESS) {
416 NXPLOG_NCIHAL_D("hal_write_cb: write successful status = 0x%x",
417 pInfo->wStatus);
418 } else {
419 NXPLOG_NCIHAL_E("hal_write_cb: write error status = 0x%x", pInfo->wStatus);
420 }
421
422 p_cb_data->status = pInfo->wStatus;
423
424 SEM_POST(p_cb_data);
425 return;
426 }
427
428 /*******************************************************************************
429 **
430 ** Function tmp_thread
431 **
432 ** Description Thread to execute custom poll commands .
433 **
434 ** Returns None
435 **
436 *******************************************************************************/
tmp_thread(void * tmp)437 void* tmp_thread(void* tmp) {
438 NFCSTATUS status = NFCSTATUS_SUCCESS;
439 uint16_t data_len;
440 NXPLOG_NCIHAL_E("tmp_thread: enter type=0x0%x", *((int*)tmp));
441 usleep(10 * 1000);
442
443 switch (*((int*)tmp)) {
444 case START_POLLING: {
445 CONCURRENCY_LOCK();
446 data_len = phNxpNciHal_write_unlocked(cmd_poll_len, cmd_poll);
447 CONCURRENCY_UNLOCK();
448
449 if (data_len != cmd_poll_len) {
450 NXPLOG_NCIHAL_E("phNxpNciHal_start_polling_loop: data len mismatch");
451 status = NFCSTATUS_FAILED;
452 }
453 } break;
454
455 case RESUME_POLLING: {
456 CONCURRENCY_LOCK();
457 data_len = phNxpNciHal_write_unlocked(sizeof(cmd_resume_rf_discovery),
458 cmd_resume_rf_discovery);
459 CONCURRENCY_UNLOCK();
460
461 if (data_len != sizeof(cmd_resume_rf_discovery)) {
462 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
463 status = NFCSTATUS_FAILED;
464 }
465 } break;
466
467 case STOP_POLLING: {
468 CONCURRENCY_LOCK();
469 data_len = phNxpNciHal_write_unlocked(sizeof(cmd_stop_rf_discovery),
470 cmd_stop_rf_discovery);
471 CONCURRENCY_UNLOCK();
472
473 if (data_len != sizeof(cmd_stop_rf_discovery)) {
474 NXPLOG_NCIHAL_E("phNxpNciHal_stop_polling_loop: data len mismatch");
475 status = NFCSTATUS_FAILED;
476 }
477 } break;
478
479 case DISCOVER_SELECT: {
480 CONCURRENCY_LOCK();
481 data_len = phNxpNciHal_write_unlocked(sizeof(cmd_select_rf_discovery),
482 cmd_select_rf_discovery);
483 CONCURRENCY_UNLOCK();
484
485 if (data_len != sizeof(cmd_resume_rf_discovery)) {
486 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
487 status = NFCSTATUS_FAILED;
488 }
489 } break;
490
491 default:
492 NXPLOG_NCIHAL_E("No Matching case");
493 status = NFCSTATUS_FAILED;
494 break;
495 }
496
497 NXPLOG_NCIHAL_E("tmp_thread: exit");
498 return NULL;
499 }
500 /*******************************************************************************
501 **
502 ** Function phNxpNciHal_select_RF_Discovery
503 **
504 ** Description Sends RF_DISCOVER_SELECT_CMD
505 ** Parameters RfID , RfProtocolType
506 ** Returns NFCSTATUS_PENDING if success
507 **
508 *******************************************************************************/
phNxpNciHal_select_RF_Discovery(unsigned int RfID,unsigned int RfProtocolType)509 NFCSTATUS phNxpNciHal_select_RF_Discovery(unsigned int RfID,
510 unsigned int RfProtocolType) {
511 NFCSTATUS status = NFCSTATUS_SUCCESS;
512 phNxpNciHal_Sem_t cb_data;
513 pthread_t pthread;
514 discover_type = DISCOVER_SELECT;
515 cmd_select_rf_discovery[3] = RfID;
516 cmd_select_rf_discovery[4] = RfProtocolType;
517
518 pthread_attr_t attr;
519 pthread_attr_init(&attr);
520 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
521 if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
522 NXPLOG_NCIHAL_E("fail to create pthread");
523 }
524 pthread_attr_destroy(&attr);
525 return status;
526 }
527 /*******************************************************************************
528 **
529 ** Function phNxpNciHal_NfcDep_cmd_ext
530 **
531 ** Description Stores the polling loop configuration locally.
532 **
533 ** Returns None
534 **
535 *******************************************************************************/
phNxpNciHal_NfcDep_cmd_ext(uint8_t * p_cmd_data,uint16_t * cmd_len)536 void phNxpNciHal_NfcDep_cmd_ext(uint8_t* p_cmd_data, uint16_t* cmd_len) {
537 if (p_cmd_data[0] == 0x21 && p_cmd_data[1] == 0x03) {
538 if (*cmd_len == 6 && p_cmd_data[3] == 0x01 && p_cmd_data[4] == 0x02 &&
539 p_cmd_data[5] == 0x01) {
540 /* DO NOTHING */
541 } else {
542 /* Store the polling loop configuration */
543 cmd_poll_len = *cmd_len;
544 memset(&cmd_poll, 0, cmd_poll_len);
545 memcpy(&cmd_poll, p_cmd_data, cmd_poll_len);
546 }
547 }
548
549 return;
550 }
551