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