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