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