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