1 /* 2 * 3 * Copyright (C) 2013-2014 NXP Semiconductors 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 #include <errno.h> 19 #include <pthread.h> 20 21 #include <phNxpLog.h> 22 #include <phNxpNciHal.h> 23 #include <phNxpNciHal_utils.h> 24 25 #if (NFC_NXP_CHIP_TYPE == PN548C2) 26 extern uint8_t discovery_cmd[50]; 27 extern uint8_t discovery_cmd_len; 28 extern uint8_t nfcdep_detected; 29 #endif 30 31 /*********************** Link list functions **********************************/ 32 33 /******************************************************************************* 34 ** 35 ** Function listInit 36 ** 37 ** Description List initialization 38 ** 39 ** Returns 1, if list initialized, 0 otherwise 40 ** 41 *******************************************************************************/ 42 int listInit(struct listHead* pList) { 43 pList->pFirst = NULL; 44 if (pthread_mutex_init(&pList->mutex, NULL) == -1) { 45 NXPLOG_NCIHAL_E("Mutex creation failed (errno=0x%08x)", errno); 46 return 0; 47 } 48 49 return 1; 50 } 51 52 /******************************************************************************* 53 ** 54 ** Function listDestroy 55 ** 56 ** Description List destruction 57 ** 58 ** Returns 1, if list destroyed, 0 if failed 59 ** 60 *******************************************************************************/ 61 int listDestroy(struct listHead* pList) { 62 int bListNotEmpty = 1; 63 while (bListNotEmpty) { 64 bListNotEmpty = listGetAndRemoveNext(pList, NULL); 65 } 66 67 if (pthread_mutex_destroy(&pList->mutex) == -1) { 68 NXPLOG_NCIHAL_E("Mutex destruction failed (errno=0x%08x)", errno); 69 return 0; 70 } 71 72 return 1; 73 } 74 75 /******************************************************************************* 76 ** 77 ** Function listAdd 78 ** 79 ** Description Add a node to the list 80 ** 81 ** Returns 1, if added, 0 if otherwise 82 ** 83 *******************************************************************************/ 84 int listAdd(struct listHead* pList, void* pData) { 85 struct listNode* pNode; 86 struct listNode* pLastNode; 87 int result; 88 89 /* Create node */ 90 pNode = (struct listNode*)malloc(sizeof(struct listNode)); 91 if (pNode == NULL) { 92 result = 0; 93 NXPLOG_NCIHAL_E("Failed to malloc"); 94 goto clean_and_return; 95 } 96 pNode->pData = pData; 97 pNode->pNext = NULL; 98 99 pthread_mutex_lock(&pList->mutex); 100 101 /* Add the node to the list */ 102 if (pList->pFirst == NULL) { 103 /* Set the node as the head */ 104 pList->pFirst = pNode; 105 } else { 106 /* Seek to the end of the list */ 107 pLastNode = pList->pFirst; 108 while (pLastNode->pNext != NULL) { 109 pLastNode = pLastNode->pNext; 110 } 111 112 /* Add the node to the current list */ 113 pLastNode->pNext = pNode; 114 } 115 116 result = 1; 117 118 clean_and_return: 119 pthread_mutex_unlock(&pList->mutex); 120 return result; 121 } 122 123 /******************************************************************************* 124 ** 125 ** Function listRemove 126 ** 127 ** Description Remove node from the list 128 ** 129 ** Returns 1, if removed, 0 if otherwise 130 ** 131 *******************************************************************************/ 132 int listRemove(struct listHead* pList, void* pData) { 133 struct listNode* pNode; 134 struct listNode* pRemovedNode; 135 int result; 136 137 pthread_mutex_lock(&pList->mutex); 138 139 if (pList->pFirst == NULL) { 140 /* Empty list */ 141 NXPLOG_NCIHAL_E("Failed to deallocate (list empty)"); 142 result = 0; 143 goto clean_and_return; 144 } 145 146 pNode = pList->pFirst; 147 if (pList->pFirst->pData == pData) { 148 /* Get the removed node */ 149 pRemovedNode = pNode; 150 151 /* Remove the first node */ 152 pList->pFirst = pList->pFirst->pNext; 153 } else { 154 while (pNode->pNext != NULL) { 155 if (pNode->pNext->pData == pData) { 156 /* Node found ! */ 157 break; 158 } 159 pNode = pNode->pNext; 160 } 161 162 if (pNode->pNext == NULL) { 163 /* Node not found */ 164 result = 0; 165 NXPLOG_NCIHAL_E("Failed to deallocate (not found %8p)", pData); 166 goto clean_and_return; 167 } 168 169 /* Get the removed node */ 170 pRemovedNode = pNode->pNext; 171 172 /* Remove the node from the list */ 173 pNode->pNext = pNode->pNext->pNext; 174 } 175 176 /* Deallocate the node */ 177 free(pRemovedNode); 178 179 result = 1; 180 181 clean_and_return: 182 pthread_mutex_unlock(&pList->mutex); 183 return result; 184 } 185 186 /******************************************************************************* 187 ** 188 ** Function listGetAndRemoveNext 189 ** 190 ** Description Get next node on the list and remove it 191 ** 192 ** Returns 1, if successful, 0 if otherwise 193 ** 194 *******************************************************************************/ 195 int listGetAndRemoveNext(struct listHead* pList, void** ppData) { 196 struct listNode* pNode; 197 int result; 198 199 pthread_mutex_lock(&pList->mutex); 200 201 if (pList->pFirst == NULL) { 202 /* Empty list */ 203 NXPLOG_NCIHAL_D("Failed to deallocate (list empty)"); 204 result = 0; 205 goto clean_and_return; 206 } 207 208 /* Work on the first node */ 209 pNode = pList->pFirst; 210 211 /* Return the data */ 212 if (ppData != NULL) { 213 *ppData = pNode->pData; 214 } 215 216 /* Remove and deallocate the node */ 217 pList->pFirst = pNode->pNext; 218 free(pNode); 219 220 result = 1; 221 222 clean_and_return: 223 listDump(pList); 224 pthread_mutex_unlock(&pList->mutex); 225 return result; 226 } 227 228 /******************************************************************************* 229 ** 230 ** Function listDump 231 ** 232 ** Description Dump list information 233 ** 234 ** Returns None 235 ** 236 *******************************************************************************/ 237 void listDump(struct listHead* pList) { 238 struct listNode* pNode = pList->pFirst; 239 240 NXPLOG_NCIHAL_D("Node dump:"); 241 while (pNode != NULL) { 242 NXPLOG_NCIHAL_D("- %8p (%8p)", pNode, pNode->pData); 243 pNode = pNode->pNext; 244 } 245 246 return; 247 } 248 249 /* END Linked list source code */ 250 251 /****************** Semaphore and mutex helper functions **********************/ 252 253 static phNxpNciHal_Monitor_t* nxpncihal_monitor = NULL; 254 255 /******************************************************************************* 256 ** 257 ** Function phNxpNciHal_init_monitor 258 ** 259 ** Description Initialize the semaphore monitor 260 ** 261 ** Returns Pointer to monitor, otherwise NULL if failed 262 ** 263 *******************************************************************************/ 264 phNxpNciHal_Monitor_t* phNxpNciHal_init_monitor(void) { 265 NXPLOG_NCIHAL_D("Entering phNxpNciHal_init_monitor"); 266 267 if (nxpncihal_monitor == NULL) { 268 nxpncihal_monitor = 269 (phNxpNciHal_Monitor_t*)malloc(sizeof(phNxpNciHal_Monitor_t)); 270 } 271 272 if (nxpncihal_monitor != NULL) { 273 memset(nxpncihal_monitor, 0x00, sizeof(phNxpNciHal_Monitor_t)); 274 275 if (pthread_mutex_init(&nxpncihal_monitor->reentrance_mutex, NULL) == -1) { 276 NXPLOG_NCIHAL_E("reentrance_mutex creation returned 0x%08x", errno); 277 goto clean_and_return; 278 } 279 280 if (pthread_mutex_init(&nxpncihal_monitor->concurrency_mutex, NULL) == -1) { 281 NXPLOG_NCIHAL_E("concurrency_mutex creation returned 0x%08x", errno); 282 pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex); 283 goto clean_and_return; 284 } 285 286 if (listInit(&nxpncihal_monitor->sem_list) != 1) { 287 NXPLOG_NCIHAL_E("Semaphore List creation failed"); 288 pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex); 289 pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex); 290 goto clean_and_return; 291 } 292 } else { 293 NXPLOG_NCIHAL_E("nxphal_monitor creation failed"); 294 goto clean_and_return; 295 } 296 297 NXPLOG_NCIHAL_D("Returning with SUCCESS"); 298 299 return nxpncihal_monitor; 300 301 clean_and_return: 302 NXPLOG_NCIHAL_D("Returning with FAILURE"); 303 304 if (nxpncihal_monitor != NULL) { 305 free(nxpncihal_monitor); 306 nxpncihal_monitor = NULL; 307 } 308 309 return NULL; 310 } 311 312 /******************************************************************************* 313 ** 314 ** Function phNxpNciHal_cleanup_monitor 315 ** 316 ** Description Clean up semaphore monitor 317 ** 318 ** Returns None 319 ** 320 *******************************************************************************/ 321 void phNxpNciHal_cleanup_monitor(void) { 322 if (nxpncihal_monitor != NULL) { 323 pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex); 324 REENTRANCE_UNLOCK(); 325 pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex); 326 phNxpNciHal_releaseall_cb_data(); 327 listDestroy(&nxpncihal_monitor->sem_list); 328 } 329 330 free(nxpncihal_monitor); 331 nxpncihal_monitor = NULL; 332 333 return; 334 } 335 336 /******************************************************************************* 337 ** 338 ** Function phNxpNciHal_get_monitor 339 ** 340 ** Description Get monitor 341 ** 342 ** Returns Pointer to monitor 343 ** 344 *******************************************************************************/ 345 phNxpNciHal_Monitor_t* phNxpNciHal_get_monitor(void) { 346 return nxpncihal_monitor; 347 } 348 349 /* Initialize the callback data */ 350 NFCSTATUS phNxpNciHal_init_cb_data(phNxpNciHal_Sem_t* pCallbackData, 351 void* pContext) { 352 /* Create semaphore */ 353 if (sem_init(&pCallbackData->sem, 0, 0) == -1) { 354 NXPLOG_NCIHAL_E("Semaphore creation failed (errno=0x%08x)", errno); 355 return NFCSTATUS_FAILED; 356 } 357 358 /* Set default status value */ 359 pCallbackData->status = NFCSTATUS_FAILED; 360 361 /* Copy the context */ 362 pCallbackData->pContext = pContext; 363 364 /* Add to active semaphore list */ 365 if (listAdd(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1) { 366 NXPLOG_NCIHAL_E("Failed to add the semaphore to the list"); 367 } 368 369 return NFCSTATUS_SUCCESS; 370 } 371 372 /******************************************************************************* 373 ** 374 ** Function phNxpNciHal_cleanup_cb_data 375 ** 376 ** Description Clean up callback data 377 ** 378 ** Returns None 379 ** 380 *******************************************************************************/ 381 void phNxpNciHal_cleanup_cb_data(phNxpNciHal_Sem_t* pCallbackData) { 382 /* Destroy semaphore */ 383 if (sem_destroy(&pCallbackData->sem)) { 384 NXPLOG_NCIHAL_E( 385 "phNxpNciHal_cleanup_cb_data: Failed to destroy semaphore " 386 "(errno=0x%08x)", 387 errno); 388 } 389 390 /* Remove from active semaphore list */ 391 if (listRemove(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1) { 392 NXPLOG_NCIHAL_E( 393 "phNxpNciHal_cleanup_cb_data: Failed to remove semaphore from the " 394 "list"); 395 } 396 397 return; 398 } 399 400 /******************************************************************************* 401 ** 402 ** Function phNxpNciHal_releaseall_cb_data 403 ** 404 ** Description Release all callback data 405 ** 406 ** Returns None 407 ** 408 *******************************************************************************/ 409 void phNxpNciHal_releaseall_cb_data(void) { 410 phNxpNciHal_Sem_t* pCallbackData; 411 412 while (listGetAndRemoveNext(&phNxpNciHal_get_monitor()->sem_list, 413 (void**)&pCallbackData)) { 414 pCallbackData->status = NFCSTATUS_FAILED; 415 sem_post(&pCallbackData->sem); 416 } 417 418 return; 419 } 420 421 /* END Semaphore and mutex helper functions */ 422 423 /**************************** Other functions *********************************/ 424 425 /******************************************************************************* 426 ** 427 ** Function phNxpNciHal_print_packet 428 ** 429 ** Description Print packet 430 ** 431 ** Returns None 432 ** 433 *******************************************************************************/ 434 void phNxpNciHal_print_packet(const char* pString, const uint8_t* p_data, 435 uint16_t len) { 436 uint32_t i, j; 437 char print_buffer[len * 3 + 1]; 438 439 memset(print_buffer, 0, sizeof(print_buffer)); 440 for (i = 0; i < len; i++) { 441 snprintf(&print_buffer[i * 2], 3, "%02X", p_data[i]); 442 } 443 if (0 == memcmp(pString, "SEND", 0x04)) { 444 NXPLOG_NCIX_D("len = %3d > %s", len, print_buffer); 445 } else if (0 == memcmp(pString, "RECV", 0x04)) { 446 NXPLOG_NCIR_D("len = %3d > %s", len, print_buffer); 447 } 448 449 return; 450 } 451 452 /******************************************************************************* 453 ** 454 ** Function phNxpNciHal_emergency_recovery 455 ** 456 ** Description Emergency recovery in case of no other way out 457 ** 458 ** Returns None 459 ** 460 *******************************************************************************/ 461 462 void phNxpNciHal_emergency_recovery(void) { 463 #if (NFC_NXP_CHIP_TYPE == PN548C2) 464 if (nfcdep_detected && discovery_cmd_len != 0) { 465 pthread_t pthread; 466 pthread_attr_t attr; 467 pthread_attr_init(&attr); 468 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 469 if (pthread_create(&pthread, &attr, (void*)phNxpNciHal_core_reset_recovery, 470 NULL) == 0) { 471 return; 472 } 473 } 474 #endif 475 NXPLOG_NCIHAL_E("%s: abort()", __func__); 476 abort(); 477 } 478