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 #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 = phNxpNciHal_write_unlocked(cmd_poll_len, cmd_poll);
425       CONCURRENCY_UNLOCK();
426 
427       if (data_len != cmd_poll_len) {
428         NXPLOG_NCIHAL_E("phNxpNciHal_start_polling_loop: data len mismatch");
429         status = NFCSTATUS_FAILED;
430       }
431     } break;
432 
433     case RESUME_POLLING: {
434       CONCURRENCY_LOCK();
435       data_len = phNxpNciHal_write_unlocked(sizeof(cmd_resume_rf_discovery),
436                                             cmd_resume_rf_discovery);
437       CONCURRENCY_UNLOCK();
438 
439       if (data_len != sizeof(cmd_resume_rf_discovery)) {
440         NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
441         status = NFCSTATUS_FAILED;
442       }
443     } break;
444 
445     case STOP_POLLING: {
446       CONCURRENCY_LOCK();
447       data_len = phNxpNciHal_write_unlocked(sizeof(cmd_stop_rf_discovery),
448                                             cmd_stop_rf_discovery);
449       CONCURRENCY_UNLOCK();
450 
451       if (data_len != sizeof(cmd_stop_rf_discovery)) {
452         NXPLOG_NCIHAL_E("phNxpNciHal_stop_polling_loop: data len mismatch");
453         status = NFCSTATUS_FAILED;
454       }
455     } break;
456 
457     case DISCOVER_SELECT: {
458       CONCURRENCY_LOCK();
459       data_len = phNxpNciHal_write_unlocked(sizeof(cmd_select_rf_discovery),
460                                             cmd_select_rf_discovery);
461       CONCURRENCY_UNLOCK();
462 
463       if (data_len != sizeof(cmd_resume_rf_discovery)) {
464         NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
465         status = NFCSTATUS_FAILED;
466       }
467     } break;
468 
469     default:
470       NXPLOG_NCIHAL_E("No Matching case");
471       status = NFCSTATUS_FAILED;
472       break;
473   }
474 
475   NXPLOG_NCIHAL_W("tmp_thread: exit");
476   return NULL;
477 }
478 /*******************************************************************************
479  **
480  ** Function         phNxpNciHal_select_RF_Discovery
481  **
482  ** Description     Sends RF_DISCOVER_SELECT_CMD
483  ** Parameters    RfID ,  RfProtocolType
484  ** Returns          NFCSTATUS_PENDING if success
485  **
486  *******************************************************************************/
phNxpNciHal_select_RF_Discovery(unsigned int RfID,unsigned int RfProtocolType)487 NFCSTATUS phNxpNciHal_select_RF_Discovery(unsigned int RfID,
488                                           unsigned int RfProtocolType) {
489   NFCSTATUS status = NFCSTATUS_SUCCESS;
490   pthread_t pthread;
491   discover_type = DISCOVER_SELECT;
492   cmd_select_rf_discovery[3] = RfID;
493   cmd_select_rf_discovery[4] = RfProtocolType;
494 
495   pthread_attr_t attr;
496   pthread_attr_init(&attr);
497   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
498   if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
499     NXPLOG_NCIHAL_E("fail to create pthread");
500   }
501   pthread_attr_destroy(&attr);
502   return status;
503 }
504 /*******************************************************************************
505 **
506 ** Function         phNxpNciHal_NfcDep_cmd_ext
507 **
508 ** Description      Stores the polling loop configuration locally.
509 **
510 ** Returns          None
511 **
512 *******************************************************************************/
phNxpNciHal_NfcDep_cmd_ext(uint8_t * p_cmd_data,uint16_t * cmd_len)513 void phNxpNciHal_NfcDep_cmd_ext(uint8_t* p_cmd_data, uint16_t* cmd_len) {
514   if (*cmd_len < NCI_HEADER_SIZE) return;
515   if (p_cmd_data[0] == 0x21 && p_cmd_data[1] == 0x03) {
516     if (*cmd_len == 6 && p_cmd_data[3] == 0x01 && p_cmd_data[4] == 0x02 &&
517         p_cmd_data[5] == 0x01) {
518       /* DO NOTHING */
519     } else {
520       if (*cmd_len > MAX_POLL_CMD_LEN) {
521         NXPLOG_NCIHAL_E("invalid cmd_len");
522         return;
523       }
524       /* Store the polling loop configuration */
525       cmd_poll_len = *cmd_len;
526       memset(&cmd_poll, 0, cmd_poll_len);
527       memcpy(&cmd_poll, p_cmd_data, cmd_poll_len);
528     }
529   }
530 
531   return;
532 }
533