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