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