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