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