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("phNxpNciHal_resume_polling_loop");
137 }
138 return status;
139 }
140
141 /*******************************************************************************
142 **
143 ** Function phNxpNciHal_resume_polling_loop
144 **
145 ** Description Sends resume polling cmd to NFCC
146 **
147 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
148 **
149 *******************************************************************************/
phNxpNciHal_resume_polling_loop()150 static NFCSTATUS phNxpNciHal_resume_polling_loop()
151 {
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 {
162 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
163 }
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 {
178 NFCSTATUS status = NFCSTATUS_FAILED;
179 phNxpNciHal_Sem_t cb_data;
180 pthread_t pthread;
181 discover_type = START_POLLING;
182
183 pthread_attr_t attr;
184 pthread_attr_init(&attr);
185 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
186 if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
187 {
188 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
189 }
190 return status;
191 }
192
193 /*******************************************************************************
194 **
195 ** Function phNxpNciHal_NfcDep_rsp_ext
196 **
197 ** Description Implements algorithm for NFC-DEP protocol priority over
198 ** ISO-DEP protocol.
199 ** Following the algorithm:
200 ** IF ISO-DEP detected first time,set the ISO-DEP detected flag
201 ** and resume polling loop with 60ms timeout value.
202 ** a) if than NFC-DEP detected than send the response to
203 ** libnfc-nci stack and stop the timer.
204 ** b) if NFC-DEP not detected with in 60ms, than restart the
205 ** polling loop to give early chance to ISO-DEP with a
206 ** cleanup timer.
207 ** c) if ISO-DEP detected second time send the response to
208 ** libnfc-nci stack and stop the cleanup timer.
209 ** d) if ISO-DEP not detected with in cleanup timeout, than
210 ** clear the ISO-DEP detection flag.
211 **
212 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
213 **
214 *******************************************************************************/
phNxpNciHal_NfcDep_rsp_ext(uint8_t * p_ntf,uint16_t * p_len)215 NFCSTATUS phNxpNciHal_NfcDep_rsp_ext(uint8_t *p_ntf, uint16_t *p_len)
216 {
217 NFCSTATUS status = NFCSTATUS_INVALID_PARAMETER;
218
219 NXPLOG_NCIHAL_D(">> p_ntf[0]=%02x , p_ntf[1]=%02x",p_ntf[0],p_ntf[1]);
220
221 if(p_ntf[0] == 0x41 && p_ntf[1] == 0x04)
222 {
223 //Tag selected, Disable P2P Prio logic.
224 bIgnoreIsoDep = 1;
225 NXPLOG_NCIHAL_D(">> Tag selected, Disable P2P Prio logic.");
226
227 }
228 else if( ((p_ntf[0] == 0x61 && p_ntf[1] == 0x06) ||
229 (p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ) && bIgnoreIsoDep == 1
230 )
231 {
232 //Tag deselected, enable P2P Prio logic.
233 bIgnoreIsoDep = 0x00;
234 NXPLOG_NCIHAL_D(">> Tag deselected, enable P2P Prio logic.");
235
236 }
237 if (bIgnoreIsoDep == 0x00 &&
238 p_ntf[0] == 0x61 &&
239 p_ntf[1] == 0x05 && *p_len > 5)
240 {
241 if (p_ntf[5] == 0x04 && p_ntf[6] < 0x80)
242 {
243 NXPLOG_NCIHAL_D(">> ISO DEP detected.");
244
245 if (iso_dep_detected == 0x00)
246 {
247 NXPLOG_NCIHAL_D(
248 ">> ISO DEP detected first time. Resume polling loop");
249
250 iso_dep_detected = 0x01;
251 status = phNxpNciHal_resume_polling_loop();
252
253 custom_poll_timer = phOsalNfc_Timer_Create();
254 NXPLOG_NCIHAL_D("custom poll timer started - %d", custom_poll_timer);
255
256 status = phOsalNfc_Timer_Start(custom_poll_timer,
257 CUSTOM_POLL_TIMEOUT,
258 &custom_poll_timer_handler,
259 NULL);
260
261 if (NFCSTATUS_SUCCESS == status)
262 {
263 NXPLOG_NCIHAL_D("custom poll timer started");
264 }
265 else
266 {
267 NXPLOG_NCIHAL_E("custom poll timer not started!!!");
268 status = NFCSTATUS_FAILED;
269 }
270
271 status = NFCSTATUS_FAILED;
272 }
273 else
274 {
275 NXPLOG_NCIHAL_D(">> ISO DEP detected second time.");
276 /* Store notification */
277 phNxpNciHal_NfcDep_store_ntf(p_ntf, *p_len);
278
279 /* Stop Cleanup_timer */
280 phOsalNfc_Timer_Stop(cleanup_timer);
281 phOsalNfc_Timer_Delete(cleanup_timer);
282 cleanup_timer=0;
283 EnableP2P_PrioLogic = FALSE;
284 iso_dep_detected = 0;
285 status = NFCSTATUS_SUCCESS;
286 }
287 }
288 else if (p_ntf[5] == 0x05)
289 {
290 NXPLOG_NCIHAL_D(">> NFC-DEP Detected - stopping the custom poll timer");
291
292 phOsalNfc_Timer_Stop(custom_poll_timer);
293 phOsalNfc_Timer_Delete(custom_poll_timer);
294 EnableP2P_PrioLogic = FALSE;
295 iso_dep_detected = 0;
296 status = NFCSTATUS_SUCCESS;
297 }
298 else
299 {
300 NXPLOG_NCIHAL_D(">> detected other technology- stopping the custom poll timer");
301 phOsalNfc_Timer_Stop(custom_poll_timer);
302 phOsalNfc_Timer_Delete(custom_poll_timer);
303 EnableP2P_PrioLogic = FALSE;
304 iso_dep_detected = 0;
305 status = NFCSTATUS_INVALID_PARAMETER;
306 }
307 }
308 else if( bIgnoreIsoDep == 0x00 &&
309 ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) || (p_ntf[0] == 0x61
310 && p_ntf[1] == 0x06))
311 )
312 {
313 NXPLOG_NCIHAL_D(">> RF disabled");
314 if (poll_timer_fired == 0x01)
315 {
316 poll_timer_fired = 0x00;
317
318 NXPLOG_NCIHAL_D(">>restarting polling loop.");
319
320 /* start polling loop */
321 phNxpNciHal_start_polling_loop();
322 EnableP2P_PrioLogic = FALSE;
323 NXPLOG_NCIHAL_D (">> NFC DEP NOT detected - custom poll timer expired - RF disabled");
324
325 cleanup_timer = phOsalNfc_Timer_Create();
326
327 /* Start cleanup_timer */
328 NFCSTATUS status = phOsalNfc_Timer_Start(cleanup_timer,
329 CLEAN_UP_TIMEOUT,
330 &cleanup_timer_handler,
331 NULL);
332
333 if (NFCSTATUS_SUCCESS == status)
334 {
335 NXPLOG_NCIHAL_D("cleanup timer started");
336 }
337 else
338 {
339 NXPLOG_NCIHAL_E("cleanup timer not started!!!");
340 status = NFCSTATUS_FAILED;
341 }
342
343 status = NFCSTATUS_FAILED;
344 }
345 else
346 {
347 status = NFCSTATUS_SUCCESS;
348 }
349 }
350 if (bIgnoreIsoDep == 0x00 &&
351 iso_dep_detected == 1)
352 {
353 if ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) || (p_ntf[0] == 0x61
354 && p_ntf[1] == 0x06))
355 {
356 NXPLOG_NCIHAL_D(">>iso_dep_detected Disconnect related notification");
357 status = NFCSTATUS_FAILED;
358 }
359 else
360 {
361 NXPLOG_NCIHAL_W("Never come here");
362 }
363 }
364
365 return status;
366 }
367 /*******************************************************************************
368 **
369 ** Function phNxpNciHal_NfcDep_store_ntf
370 **
371 ** Description Stores the iso dep notification locally.
372 **
373 ** Returns None
374 **
375 *******************************************************************************/
phNxpNciHal_NfcDep_store_ntf(uint8_t * p_cmd_data,uint16_t cmd_len)376 static void phNxpNciHal_NfcDep_store_ntf(uint8_t *p_cmd_data, uint16_t cmd_len)
377 {
378 p_iso_ntf_buff = NULL;
379
380 p_iso_ntf_buff = malloc(sizeof (uint8_t) * cmd_len);
381 if (p_iso_ntf_buff == NULL)
382 {
383 NXPLOG_NCIHAL_E("Error allocating memory (p_iso_ntf_buff)");
384 return;
385 }
386 memcpy(p_iso_ntf_buff, p_cmd_data, cmd_len);
387 bIgnorep2plogic = 1;
388 }
389
390 /*******************************************************************************
391 **
392 ** Function phNxpNciHal_NfcDep_comapre_ntf
393 **
394 ** Description Compare the notification with previous iso dep notification.
395 **
396 ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
397 **
398 *******************************************************************************/
phNxpNciHal_NfcDep_comapre_ntf(uint8_t * p_cmd_data,uint16_t cmd_len)399 NFCSTATUS phNxpNciHal_NfcDep_comapre_ntf(uint8_t *p_cmd_data, uint16_t cmd_len)
400 {
401 NFCSTATUS status = NFCSTATUS_FAILED;
402 int32_t ret_val = -1;
403
404 if (bIgnorep2plogic == 1)
405 {
406 ret_val = memcmp(p_cmd_data,p_iso_ntf_buff, cmd_len);
407 if(ret_val != 0)
408 {
409 NXPLOG_NCIHAL_E("Third notification is not equal to last");
410 }
411 else
412 {
413 NXPLOG_NCIHAL_E("Third notification is equal to last (disable p2p logic)");
414 status = NFCSTATUS_SUCCESS;
415 }
416 bIgnorep2plogic = 0;
417 }
418 if (p_iso_ntf_buff != NULL)
419 {
420 free(p_iso_ntf_buff);
421 p_iso_ntf_buff = NULL;
422 }
423
424 return status;
425 }
426
427
phNxpNciHal_clean_P2P_Prio()428 extern NFCSTATUS phNxpNciHal_clean_P2P_Prio()
429 {
430 NFCSTATUS status = NFCSTATUS_SUCCESS;
431
432 iso_dep_detected = 0x00;
433 EnableP2P_PrioLogic = FALSE;
434 poll_timer_fired = 0x00;
435 bIgnorep2plogic = 0x00;
436 bIgnoreIsoDep = 0x00;
437
438 status = phOsalNfc_Timer_Stop(cleanup_timer);
439 status |= phOsalNfc_Timer_Delete(cleanup_timer);
440
441 status |= phOsalNfc_Timer_Stop(custom_poll_timer);
442 status |= phOsalNfc_Timer_Delete(custom_poll_timer);
443 cleanup_timer=0;
444 return status;
445 }
446
447 #endif
448 /*******************************************************************************
449 **
450 ** Function hal_write_cb
451 **
452 ** Description Callback function for hal write.
453 **
454 ** Returns None
455 **
456 *******************************************************************************/
hal_write_cb(void * pContext,phTmlNfc_TransactInfo_t * pInfo)457 static void hal_write_cb(void *pContext, phTmlNfc_TransactInfo_t *pInfo)
458 {
459 phNxpNciHal_Sem_t *p_cb_data = (phNxpNciHal_Sem_t*) pContext;
460
461 if (pInfo->wStatus == NFCSTATUS_SUCCESS)
462 {
463 NXPLOG_NCIHAL_D("hal_write_cb: write successful status = 0x%x", pInfo->wStatus);
464 }
465 else
466 {
467 NXPLOG_NCIHAL_E("hal_write_cb: write error status = 0x%x", pInfo->wStatus);
468 }
469
470 p_cb_data->status = pInfo->wStatus;
471
472 SEM_POST(p_cb_data);
473 return;
474 }
475
476 /*******************************************************************************
477 **
478 ** Function tmp_thread
479 **
480 ** Description Thread to execute custom poll commands .
481 **
482 ** Returns None
483 **
484 *******************************************************************************/
tmp_thread(void * tmp)485 void *tmp_thread(void *tmp)
486 {
487 NFCSTATUS status = NFCSTATUS_SUCCESS;
488 uint16_t data_len;
489 NXPLOG_NCIHAL_E("tmp_thread: enter type=0x0%x", *((int*)tmp));
490 usleep(10*1000);
491
492 switch( *((int*)tmp) )
493 {
494 case START_POLLING:
495 {
496 CONCURRENCY_LOCK();
497 data_len = phNxpNciHal_write_unlocked(cmd_poll_len, cmd_poll);
498 CONCURRENCY_UNLOCK();
499
500 if(data_len != cmd_poll_len)
501 {
502 NXPLOG_NCIHAL_E("phNxpNciHal_start_polling_loop: data len mismatch");
503 status = NFCSTATUS_FAILED;
504 }
505 }
506 break;
507
508 case RESUME_POLLING:
509 {
510 CONCURRENCY_LOCK();
511 data_len = phNxpNciHal_write_unlocked(sizeof(cmd_resume_rf_discovery),
512 cmd_resume_rf_discovery);
513 CONCURRENCY_UNLOCK();
514
515 if(data_len != sizeof(cmd_resume_rf_discovery))
516 {
517 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
518 status = NFCSTATUS_FAILED;
519 }
520 }
521 break;
522
523 case STOP_POLLING:
524 {
525 CONCURRENCY_LOCK();
526 data_len = phNxpNciHal_write_unlocked(sizeof(cmd_stop_rf_discovery),
527 cmd_stop_rf_discovery);
528 CONCURRENCY_UNLOCK();
529
530 if(data_len != sizeof(cmd_stop_rf_discovery))
531 {
532 NXPLOG_NCIHAL_E("phNxpNciHal_stop_polling_loop: data len mismatch");
533 status = NFCSTATUS_FAILED;
534 }
535 }
536 break;
537
538 case DISCOVER_SELECT:
539 {
540 CONCURRENCY_LOCK();
541 data_len = phNxpNciHal_write_unlocked(sizeof(cmd_select_rf_discovery),
542 cmd_select_rf_discovery);
543 CONCURRENCY_UNLOCK();
544
545 if(data_len != sizeof(cmd_resume_rf_discovery))
546 {
547 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
548 status = NFCSTATUS_FAILED;
549 }
550 }
551 break;
552
553 default:
554 NXPLOG_NCIHAL_E("No Matching case");
555 status = NFCSTATUS_FAILED;
556 break;
557 }
558
559 NXPLOG_NCIHAL_E("tmp_thread: exit");
560 return NULL;
561 }
562 /*******************************************************************************
563 **
564 ** Function phNxpNciHal_select_RF_Discovery
565 **
566 ** Description Sends RF_DISCOVER_SELECT_CMD
567 ** Parameters RfID , RfProtocolType
568 ** Returns NFCSTATUS_PENDING if success
569 **
570 *******************************************************************************/
phNxpNciHal_select_RF_Discovery(unsigned int RfID,unsigned int RfProtocolType)571 NFCSTATUS phNxpNciHal_select_RF_Discovery(unsigned int RfID,unsigned int RfProtocolType)
572 {
573 NFCSTATUS status = NFCSTATUS_SUCCESS;
574 phNxpNciHal_Sem_t cb_data;
575 pthread_t pthread;
576 discover_type = DISCOVER_SELECT;
577 cmd_select_rf_discovery[3]=RfID;
578 cmd_select_rf_discovery[4]=RfProtocolType;
579
580 pthread_attr_t attr;
581 pthread_attr_init(&attr);
582 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
583 if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
584 {
585 NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
586 }
587
588 return status;
589 }
590 /*******************************************************************************
591 **
592 ** Function phNxpNciHal_NfcDep_cmd_ext
593 **
594 ** Description Stores the polling loop configuration locally.
595 **
596 ** Returns None
597 **
598 *******************************************************************************/
phNxpNciHal_NfcDep_cmd_ext(uint8_t * p_cmd_data,uint16_t * cmd_len)599 void phNxpNciHal_NfcDep_cmd_ext(uint8_t *p_cmd_data, uint16_t *cmd_len)
600 {
601 if (p_cmd_data[0] == 0x21 && p_cmd_data[1] == 0x03)
602 {
603 if (*cmd_len == 6 && p_cmd_data[3] == 0x01 && p_cmd_data[4] == 0x02
604 && p_cmd_data[5] == 0x01)
605 {
606 /* DO NOTHING */
607 }
608 else
609 {
610 /* Store the polling loop configuration */
611 cmd_poll_len = *cmd_len;
612 memset(&cmd_poll, 0, cmd_poll_len);
613 memcpy(&cmd_poll, p_cmd_data, cmd_poll_len);
614 }
615 }
616
617 return;
618 }
619