Home | History | Annotate | Download | only in hal
      1 /*
      2  * Copyright (C) 2012-2014 NXP Semiconductors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <phNxpLog.h>
     18 #include <phNxpNciHal.h>
     19 #include <phNxpNciHal_NfcDepSWPrio.h>
     20 
     21 /* Timeout value to wait for NFC-DEP detection.*/
     22 #define CUSTOM_POLL_TIMEOUT 160
     23 #define CLEAN_UP_TIMEOUT 250
     24 #define MAX_WRITE_RETRY 5
     25 
     26 /******************* Global variables *****************************************/
     27 extern phNxpNciHal_Control_t nxpncihal_ctrl;
     28 extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t* p_cmd);
     29 static uint8_t cmd_stop_rf_discovery[] = {0x21, 0x06, 0x01, 0x00}; /* IDLE */
     30 static uint8_t cmd_resume_rf_discovery[] = {0x21, 0x06, 0x01,
     31                                             0x03}; /* RF_DISCOVER */
     32 
     33 /*RF_DISCOVER_SELECT_CMD*/
     34 static uint8_t cmd_select_rf_discovery[] = {0x21, 0x04, 0x03, 0x01, 0x04, 0x02};
     35 
     36 static uint8_t cmd_poll[64];
     37 static uint8_t cmd_poll_len = 0;
     38 int discover_type = 0xFF;
     39 uint32_t cleanup_timer;
     40 
     41 /*PRIO LOGIC related dead functions undefined*/
     42 #ifdef P2P_PRIO_LOGIC_HAL_IMP
     43 
     44 static int iso_dep_detected = 0x00;
     45 static int poll_timer_fired = 0x00;
     46 static uint8_t bIgnorep2plogic = 0;
     47 static uint8_t* p_iso_ntf_buff = NULL; /* buffer to store second notification */
     48 static uint8_t bIgnoreIsoDep = 0;
     49 static uint32_t custom_poll_timer;
     50 
     51 /************** NFC-DEP SW PRIO functions *************************************/
     52 
     53 static NFCSTATUS phNxpNciHal_start_polling_loop(void);
     54 static NFCSTATUS phNxpNciHal_stop_polling_loop(void);
     55 static NFCSTATUS phNxpNciHal_resume_polling_loop(void);
     56 static void phNxpNciHal_NfcDep_store_ntf(uint8_t* p_cmd_data, uint16_t cmd_len);
     57 
     58 /*******************************************************************************
     59 **
     60 ** Function         cleanup_timer_handler
     61 **
     62 ** Description      Callback function for cleanup timer.
     63 **
     64 ** Returns          None
     65 **
     66 *******************************************************************************/
     67 static void cleanup_timer_handler(uint32_t timerId, void* pContext) {
     68   NXPLOG_NCIHAL_D(">> cleanup_timer_handler.");
     69 
     70   NXPLOG_NCIHAL_D(
     71       ">> cleanup_timer_handler. ISO_DEP not detected second time.");
     72 
     73   phOsalNfc_Timer_Delete(cleanup_timer);
     74   cleanup_timer = 0;
     75   iso_dep_detected = 0x00;
     76   EnableP2P_PrioLogic = false;
     77   return;
     78 }
     79 
     80 /*******************************************************************************
     81 **
     82 ** Function         custom_poll_timer_handler
     83 **
     84 ** Description      Callback function for custom poll timer.
     85 **
     86 ** Returns          None
     87 **
     88 *******************************************************************************/
     89 static void custom_poll_timer_handler(uint32_t timerId, void* pContext) {
     90   NXPLOG_NCIHAL_D(">> custom_poll_timer_handler.");
     91 
     92   NXPLOG_NCIHAL_D(
     93       ">> custom_poll_timer_handler. NFC_DEP not detected. so giving early "
     94       "chance to ISO_DEP.");
     95 
     96   phOsalNfc_Timer_Delete(custom_poll_timer);
     97 
     98   if (iso_dep_detected == 0x01) {
     99     poll_timer_fired = 0x01;
    100 
    101     /*
    102      * Restart polling loop.
    103      * When the polling loop is stopped, polling will be restarted.
    104      */
    105     NXPLOG_NCIHAL_D(">> custom_poll_timer_handler - restart polling loop.");
    106 
    107     phNxpNciHal_stop_polling_loop();
    108   } else {
    109     NXPLOG_NCIHAL_E(
    110         ">> custom_poll_timer_handler - invalid flag state (iso_dep_detected)");
    111   }
    112 
    113   return;
    114 }
    115 /*******************************************************************************
    116 **
    117 ** Function         phNxpNciHal_stop_polling_loop
    118 **
    119 ** Description      Sends stop polling cmd to NFCC
    120 **
    121 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
    122 **
    123 *******************************************************************************/
    124 static NFCSTATUS phNxpNciHal_stop_polling_loop() {
    125   NFCSTATUS status = NFCSTATUS_SUCCESS;
    126   phNxpNciHal_Sem_t cb_data;
    127   pthread_t pthread;
    128   discover_type = STOP_POLLING;
    129 
    130   pthread_attr_t attr;
    131   pthread_attr_init(&attr);
    132   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    133   if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
    134     NXPLOG_NCIHAL_E("fail to create pthread");
    135   }
    136   pthread_attr_destroy(&attr);
    137   return status;
    138 }
    139 
    140 /*******************************************************************************
    141 **
    142 ** Function         phNxpNciHal_resume_polling_loop
    143 **
    144 ** Description      Sends resume polling cmd to NFCC
    145 **
    146 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
    147 **
    148 *******************************************************************************/
    149 static NFCSTATUS phNxpNciHal_resume_polling_loop() {
    150   NFCSTATUS status = NFCSTATUS_SUCCESS;
    151   phNxpNciHal_Sem_t cb_data;
    152   pthread_t pthread;
    153   discover_type = RESUME_POLLING;
    154 
    155   pthread_attr_t attr;
    156   pthread_attr_init(&attr);
    157   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    158   if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
    159     NXPLOG_NCIHAL_E("fail to create pthread");
    160   }
    161   pthread_attr_destroy(&attr);
    162   return status;
    163 }
    164 
    165 /*******************************************************************************
    166 **
    167 ** Function         phNxpNciHal_start_polling_loop
    168 **
    169 ** Description      Sends start polling cmd to NFCC
    170 **
    171 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
    172 **
    173 *******************************************************************************/
    174 NFCSTATUS phNxpNciHal_start_polling_loop() {
    175   NFCSTATUS status = NFCSTATUS_FAILED;
    176   phNxpNciHal_Sem_t cb_data;
    177   pthread_t pthread;
    178   discover_type = START_POLLING;
    179 
    180   pthread_attr_t attr;
    181   pthread_attr_init(&attr);
    182   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    183   if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
    184     NXPLOG_NCIHAL_E("fail to create pthread");
    185   }
    186   pthread_attr_destroy(&attr);
    187   return status;
    188 }
    189 
    190 /*******************************************************************************
    191 **
    192 ** Function         phNxpNciHal_NfcDep_rsp_ext
    193 **
    194 ** Description      Implements algorithm for NFC-DEP protocol priority over
    195 **                  ISO-DEP protocol.
    196 **                  Following the algorithm:
    197 **                  IF ISO-DEP detected first time,set the ISO-DEP detected flag
    198 **                  and resume polling loop with 60ms timeout value.
    199 **                      a) if than NFC-DEP detected than send the response to
    200 **                         libnfc-nci stack and stop the timer.
    201 **                      b) if NFC-DEP not detected with in 60ms, than restart
    202 **                         the polling loop to give early chance to ISO-DEP with
    203 **                         a cleanup timer.
    204 **                      c) if ISO-DEP detected second time send the response to
    205 **                         libnfc-nci stack and stop the cleanup timer.
    206 **                      d) if ISO-DEP not detected with in cleanup timeout, than
    207 **                         clear the ISO-DEP detection flag.
    208 **
    209 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
    210 **
    211 *******************************************************************************/
    212 NFCSTATUS phNxpNciHal_NfcDep_rsp_ext(uint8_t* p_ntf, uint16_t* p_len) {
    213   NFCSTATUS status = NFCSTATUS_INVALID_PARAMETER;
    214 
    215   NXPLOG_NCIHAL_D(">> p_ntf[0]=%02x , p_ntf[1]=%02x", p_ntf[0], p_ntf[1]);
    216 
    217   if (p_ntf[0] == 0x41 && p_ntf[1] == 0x04) {
    218     // Tag selected, Disable P2P Prio logic.
    219     bIgnoreIsoDep = 1;
    220     NXPLOG_NCIHAL_D(">> Tag selected, Disable P2P Prio logic.");
    221 
    222   } else if (((p_ntf[0] == 0x61 && p_ntf[1] == 0x06) ||
    223               (p_ntf[0] == 0x41 && p_ntf[1] == 0x06)) &&
    224              bIgnoreIsoDep == 1) {
    225     // Tag deselected, enable P2P Prio logic.
    226     bIgnoreIsoDep = 0x00;
    227     NXPLOG_NCIHAL_D(">> Tag deselected, enable P2P Prio logic.");
    228   }
    229   if (bIgnoreIsoDep == 0x00 && p_ntf[0] == 0x61 && p_ntf[1] == 0x05 &&
    230       *p_len > 5) {
    231     if (p_ntf[5] == 0x04 && p_ntf[6] < 0x80) {
    232       NXPLOG_NCIHAL_D(">> ISO DEP detected.");
    233 
    234       if (iso_dep_detected == 0x00) {
    235         NXPLOG_NCIHAL_D(">> ISO DEP detected first time. Resume polling loop");
    236 
    237         iso_dep_detected = 0x01;
    238         status = phNxpNciHal_resume_polling_loop();
    239 
    240         custom_poll_timer = phOsalNfc_Timer_Create();
    241         NXPLOG_NCIHAL_D("custom poll timer started - %d", custom_poll_timer);
    242 
    243         status = phOsalNfc_Timer_Start(custom_poll_timer, CUSTOM_POLL_TIMEOUT,
    244                                        &custom_poll_timer_handler, NULL);
    245 
    246         if (NFCSTATUS_SUCCESS == status) {
    247           NXPLOG_NCIHAL_D("custom poll timer started");
    248         } else {
    249           NXPLOG_NCIHAL_E("custom poll timer not started!!!");
    250           status = NFCSTATUS_FAILED;
    251         }
    252 
    253         status = NFCSTATUS_FAILED;
    254       } else {
    255         NXPLOG_NCIHAL_D(">> ISO DEP detected second time.");
    256         /* Store notification */
    257         phNxpNciHal_NfcDep_store_ntf(p_ntf, *p_len);
    258 
    259         /* Stop Cleanup_timer */
    260         phOsalNfc_Timer_Stop(cleanup_timer);
    261         phOsalNfc_Timer_Delete(cleanup_timer);
    262         cleanup_timer = 0;
    263         EnableP2P_PrioLogic = false;
    264         iso_dep_detected = 0;
    265         status = NFCSTATUS_SUCCESS;
    266       }
    267     } else if (p_ntf[5] == 0x05) {
    268       NXPLOG_NCIHAL_D(">> NFC-DEP Detected - stopping the custom poll timer");
    269 
    270       phOsalNfc_Timer_Stop(custom_poll_timer);
    271       phOsalNfc_Timer_Delete(custom_poll_timer);
    272       EnableP2P_PrioLogic = false;
    273       iso_dep_detected = 0;
    274       status = NFCSTATUS_SUCCESS;
    275     } else {
    276       NXPLOG_NCIHAL_D(
    277           ">>  detected other technology- stopping the custom poll timer");
    278       phOsalNfc_Timer_Stop(custom_poll_timer);
    279       phOsalNfc_Timer_Delete(custom_poll_timer);
    280       EnableP2P_PrioLogic = false;
    281       iso_dep_detected = 0;
    282       status = NFCSTATUS_INVALID_PARAMETER;
    283     }
    284   } else if (bIgnoreIsoDep == 0x00 &&
    285              ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ||
    286               (p_ntf[0] == 0x61 && p_ntf[1] == 0x06))) {
    287     NXPLOG_NCIHAL_D(">> RF disabled");
    288     if (poll_timer_fired == 0x01) {
    289       poll_timer_fired = 0x00;
    290 
    291       NXPLOG_NCIHAL_D(">>restarting polling loop.");
    292 
    293       /* start polling loop */
    294       phNxpNciHal_start_polling_loop();
    295       EnableP2P_PrioLogic = false;
    296       NXPLOG_NCIHAL_D(
    297           ">> NFC DEP NOT  detected - custom poll timer expired - RF disabled");
    298 
    299       cleanup_timer = phOsalNfc_Timer_Create();
    300 
    301       /* Start cleanup_timer */
    302       NFCSTATUS status = phOsalNfc_Timer_Start(cleanup_timer, CLEAN_UP_TIMEOUT,
    303                                                &cleanup_timer_handler, NULL);
    304 
    305       if (NFCSTATUS_SUCCESS == status) {
    306         NXPLOG_NCIHAL_D("cleanup timer started");
    307       } else {
    308         NXPLOG_NCIHAL_E("cleanup timer not started!!!");
    309         status = NFCSTATUS_FAILED;
    310       }
    311 
    312       status = NFCSTATUS_FAILED;
    313     } else {
    314       status = NFCSTATUS_SUCCESS;
    315     }
    316   }
    317   if (bIgnoreIsoDep == 0x00 && iso_dep_detected == 1) {
    318     if ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ||
    319         (p_ntf[0] == 0x61 && p_ntf[1] == 0x06)) {
    320       NXPLOG_NCIHAL_D(">>iso_dep_detected Disconnect related notification");
    321       status = NFCSTATUS_FAILED;
    322     } else {
    323       NXPLOG_NCIHAL_W("Never come here");
    324     }
    325   }
    326 
    327   return status;
    328 }
    329 /*******************************************************************************
    330 **
    331 ** Function         phNxpNciHal_NfcDep_store_ntf
    332 **
    333 ** Description      Stores the iso dep notification locally.
    334 **
    335 ** Returns          None
    336 **
    337 *******************************************************************************/
    338 static void phNxpNciHal_NfcDep_store_ntf(uint8_t* p_cmd_data,
    339                                          uint16_t cmd_len) {
    340   p_iso_ntf_buff = NULL;
    341 
    342   p_iso_ntf_buff = malloc(sizeof(uint8_t) * cmd_len);
    343   if (p_iso_ntf_buff == NULL) {
    344     NXPLOG_NCIHAL_E("Error allocating memory (p_iso_ntf_buff)");
    345     return;
    346   }
    347   memcpy(p_iso_ntf_buff, p_cmd_data, cmd_len);
    348   bIgnorep2plogic = 1;
    349 }
    350 
    351 /*******************************************************************************
    352 **
    353 ** Function         phNxpNciHal_NfcDep_comapre_ntf
    354 **
    355 ** Description      Compare the notification with previous iso dep notification.
    356 **
    357 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
    358 **
    359 *******************************************************************************/
    360 NFCSTATUS phNxpNciHal_NfcDep_comapre_ntf(uint8_t* p_cmd_data,
    361                                          uint16_t cmd_len) {
    362   NFCSTATUS status = NFCSTATUS_FAILED;
    363   int32_t ret_val = -1;
    364 
    365   if (bIgnorep2plogic == 1) {
    366     ret_val = memcmp(p_cmd_data, p_iso_ntf_buff, cmd_len);
    367     if (ret_val != 0) {
    368       NXPLOG_NCIHAL_E("Third notification is not equal to last");
    369     } else {
    370       NXPLOG_NCIHAL_E(
    371           "Third notification is equal to last (disable p2p logic)");
    372       status = NFCSTATUS_SUCCESS;
    373     }
    374     bIgnorep2plogic = 0;
    375   }
    376   if (p_iso_ntf_buff != NULL) {
    377     free(p_iso_ntf_buff);
    378     p_iso_ntf_buff = NULL;
    379   }
    380 
    381   return status;
    382 }
    383 
    384 extern NFCSTATUS phNxpNciHal_clean_P2P_Prio() {
    385   NFCSTATUS status = NFCSTATUS_SUCCESS;
    386 
    387   iso_dep_detected = 0x00;
    388   EnableP2P_PrioLogic = false;
    389   poll_timer_fired = 0x00;
    390   bIgnorep2plogic = 0x00;
    391   bIgnoreIsoDep = 0x00;
    392 
    393   status = phOsalNfc_Timer_Stop(cleanup_timer);
    394   status |= phOsalNfc_Timer_Delete(cleanup_timer);
    395 
    396   status |= phOsalNfc_Timer_Stop(custom_poll_timer);
    397   status |= phOsalNfc_Timer_Delete(custom_poll_timer);
    398   cleanup_timer = 0;
    399   return status;
    400 }
    401 
    402 #endif
    403 /*******************************************************************************
    404 **
    405 ** Function         hal_write_cb
    406 **
    407 ** Description      Callback function for hal write.
    408 **
    409 ** Returns          None
    410 **
    411 *******************************************************************************/
    412 static void hal_write_cb(void* pContext, phTmlNfc_TransactInfo_t* pInfo) {
    413   phNxpNciHal_Sem_t* p_cb_data = (phNxpNciHal_Sem_t*)pContext;
    414 
    415   if (pInfo->wStatus == NFCSTATUS_SUCCESS) {
    416     NXPLOG_NCIHAL_D("hal_write_cb: write successful status = 0x%x",
    417                     pInfo->wStatus);
    418   } else {
    419     NXPLOG_NCIHAL_E("hal_write_cb: write error status = 0x%x", pInfo->wStatus);
    420   }
    421 
    422   p_cb_data->status = pInfo->wStatus;
    423 
    424   SEM_POST(p_cb_data);
    425   return;
    426 }
    427 
    428 /*******************************************************************************
    429  **
    430  ** Function         tmp_thread
    431  **
    432  ** Description      Thread to execute custom poll commands .
    433  **
    434  ** Returns          None
    435  **
    436  *******************************************************************************/
    437 void* tmp_thread(void* tmp) {
    438   NFCSTATUS status = NFCSTATUS_SUCCESS;
    439   uint16_t data_len;
    440   NXPLOG_NCIHAL_E("tmp_thread: enter type=0x0%x", *((int*)tmp));
    441   usleep(10 * 1000);
    442 
    443   switch (*((int*)tmp)) {
    444     case START_POLLING: {
    445       CONCURRENCY_LOCK();
    446       data_len = phNxpNciHal_write_unlocked(cmd_poll_len, cmd_poll);
    447       CONCURRENCY_UNLOCK();
    448 
    449       if (data_len != cmd_poll_len) {
    450         NXPLOG_NCIHAL_E("phNxpNciHal_start_polling_loop: data len mismatch");
    451         status = NFCSTATUS_FAILED;
    452       }
    453     } break;
    454 
    455     case RESUME_POLLING: {
    456       CONCURRENCY_LOCK();
    457       data_len = phNxpNciHal_write_unlocked(sizeof(cmd_resume_rf_discovery),
    458                                             cmd_resume_rf_discovery);
    459       CONCURRENCY_UNLOCK();
    460 
    461       if (data_len != sizeof(cmd_resume_rf_discovery)) {
    462         NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
    463         status = NFCSTATUS_FAILED;
    464       }
    465     } break;
    466 
    467     case STOP_POLLING: {
    468       CONCURRENCY_LOCK();
    469       data_len = phNxpNciHal_write_unlocked(sizeof(cmd_stop_rf_discovery),
    470                                             cmd_stop_rf_discovery);
    471       CONCURRENCY_UNLOCK();
    472 
    473       if (data_len != sizeof(cmd_stop_rf_discovery)) {
    474         NXPLOG_NCIHAL_E("phNxpNciHal_stop_polling_loop: data len mismatch");
    475         status = NFCSTATUS_FAILED;
    476       }
    477     } break;
    478 
    479     case DISCOVER_SELECT: {
    480       CONCURRENCY_LOCK();
    481       data_len = phNxpNciHal_write_unlocked(sizeof(cmd_select_rf_discovery),
    482                                             cmd_select_rf_discovery);
    483       CONCURRENCY_UNLOCK();
    484 
    485       if (data_len != sizeof(cmd_resume_rf_discovery)) {
    486         NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
    487         status = NFCSTATUS_FAILED;
    488       }
    489     } break;
    490 
    491     default:
    492       NXPLOG_NCIHAL_E("No Matching case");
    493       status = NFCSTATUS_FAILED;
    494       break;
    495   }
    496 
    497   NXPLOG_NCIHAL_E("tmp_thread: exit");
    498   return NULL;
    499 }
    500 /*******************************************************************************
    501  **
    502  ** Function         phNxpNciHal_select_RF_Discovery
    503  **
    504  ** Description     Sends RF_DISCOVER_SELECT_CMD
    505  ** Parameters    RfID ,  RfProtocolType
    506  ** Returns          NFCSTATUS_PENDING if success
    507  **
    508  *******************************************************************************/
    509 NFCSTATUS phNxpNciHal_select_RF_Discovery(unsigned int RfID,
    510                                           unsigned int RfProtocolType) {
    511   NFCSTATUS status = NFCSTATUS_SUCCESS;
    512   phNxpNciHal_Sem_t cb_data;
    513   pthread_t pthread;
    514   discover_type = DISCOVER_SELECT;
    515   cmd_select_rf_discovery[3] = RfID;
    516   cmd_select_rf_discovery[4] = RfProtocolType;
    517 
    518   pthread_attr_t attr;
    519   pthread_attr_init(&attr);
    520   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    521   if (pthread_create(&pthread, &attr, tmp_thread, (void*)&discover_type) != 0) {
    522     NXPLOG_NCIHAL_E("fail to create pthread");
    523   }
    524   pthread_attr_destroy(&attr);
    525   return status;
    526 }
    527 /*******************************************************************************
    528 **
    529 ** Function         phNxpNciHal_NfcDep_cmd_ext
    530 **
    531 ** Description      Stores the polling loop configuration locally.
    532 **
    533 ** Returns          None
    534 **
    535 *******************************************************************************/
    536 void phNxpNciHal_NfcDep_cmd_ext(uint8_t* p_cmd_data, uint16_t* cmd_len) {
    537   if (p_cmd_data[0] == 0x21 && p_cmd_data[1] == 0x03) {
    538     if (*cmd_len == 6 && p_cmd_data[3] == 0x01 && p_cmd_data[4] == 0x02 &&
    539         p_cmd_data[5] == 0x01) {
    540       /* DO NOTHING */
    541     } else {
    542       /* Store the polling loop configuration */
    543       cmd_poll_len = *cmd_len;
    544       memset(&cmd_poll, 0, cmd_poll_len);
    545       memcpy(&cmd_poll, p_cmd_data, cmd_poll_len);
    546     }
    547   }
    548 
    549   return;
    550 }
    551