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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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