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