Home | History | Annotate | Download | only in utils
      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