static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hLlcpSocket;
   nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();

   TRACE("Close Service socket");

   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
   /* TODO: implement accept abort */
   pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
   pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);

   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Close(hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_SUCCESS)
   {
      TRACE("Close Service socket OK");
      return TRUE;
   }
   else
   {
      LOGD("Close Service socket KO");
      return FALSE;
   }
}
static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
{
   NFCSTATUS ret;
   struct timespec ts;
   phNfc_sData_t serviceName = {0};
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   struct nfc_jni_callback_data cb_data;
   jboolean result = JNI_FALSE;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Service socket */
   serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
   serviceName.length = (uint32_t)e->GetStringUTFLength(sn);

   TRACE("phLibNfc_Llcp_ConnectByUri()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice,
                                    hLlcpSocket,
                                    &serviceName,
                                    nfc_jni_connect_callback,
                                    (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   if (serviceName.buffer != NULL) {
      e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
   }
   nfc_cb_data_deinit(&cb_data);
   return result;
}
static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
   REENTRANCE_LOCK();
   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
                                               hLlcpSocket,
                                               &remoteSocketOption);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_SUCCESS)
   {
      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return remoteSocketOption.miu;
   }
   else
   {
      ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return 0;
   }
}
static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sSendBuffer = {NULL, 0};
   struct nfc_jni_callback_data cb_data;
   jboolean result = JNI_FALSE;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);

   TRACE("phLibNfc_Llcp_Send()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Send(hRemoteDevice,
                            hLlcpSocket,
                            &sSendBuffer,
                            nfc_jni_send_callback,
                            (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
       goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   if (sSendBuffer.buffer != NULL)
   {
      e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
   }
   nfc_cb_data_deinit(&cb_data);
   return result;
}
static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hLlcpSocket;
   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;

   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);   

   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
   REENTRANCE_LOCK();
   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hLlcpSocket,
                                               &remoteSocketOption);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_SUCCESS)
   {
      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return remoteSocketOption.rw;
   }
   else
   {
      LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return 0;
   }
}
static jboolean com_android_nfc_NativeP2pDevice_doSend(
   JNIEnv *e, jobject o, jbyteArray buf)
{
   NFCSTATUS status;
   phNfc_sData_t data;
   jboolean result = JNI_FALSE;
   struct nfc_jni_callback_data cb_data;
   
   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
   
   CONCURRENCY_LOCK();

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Send */
   TRACE("Send data to the Initiator (handle = 0x%x)", handle);

   data.length = (uint32_t)e->GetArrayLength(buf);
   data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);

   TRACE("phLibNfc_RemoteDev_Send()");
   REENTRANCE_LOCK();
   status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;   
   }
   TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   if (result != JNI_TRUE)
   {
      e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT);
   }
   nfc_cb_data_deinit(&cb_data);
   CONCURRENCY_UNLOCK();
   return result;
}
/*
 * Methods
 */
static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   struct nfc_jni_callback_data cb_data;
   jboolean result = JNI_FALSE;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Connect(hRemoteDevice,
                               hLlcpSocket,
                               nSap,
                               nfc_jni_connect_callback,
                               (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      ALOGW("LLCP Connect request failed");
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   return result;
}
static jbyteArray com_android_nfc_NativeP2pDevice_doReceive(
   JNIEnv *e, jobject o)
{
   NFCSTATUS status;
   struct timespec ts;
   phLibNfc_Handle handle;
   jbyteArray buf = NULL;
   static phNfc_sData_t *data;
   struct nfc_jni_callback_data cb_data;

   CONCURRENCY_LOCK();

   handle = nfc_jni_get_p2p_device_handle(e, o);
   
   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, (void*)data))
   {
      goto clean_and_return;
   }

   /* Receive */
   TRACE("phLibNfc_RemoteDev_Receive()");
   REENTRANCE_LOCK();
   status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;   
   }
   TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(data == NULL)
   {
      goto clean_and_return;
   }

   buf = e->NewByteArray(data->length);
   e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer);

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   CONCURRENCY_UNLOCK();
   return buf;
}
/*******************************************************************************
**
** Function         phNxpNciHal_cleanup_monitor
**
** Description      Clean up semaphore monitor
**
** Returns          None
**
*******************************************************************************/
void phNxpNciHal_cleanup_monitor(void)
{
    if (nxpncihal_monitor != NULL)
    {
        pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex);
        REENTRANCE_UNLOCK();
        pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
        phNxpNciHal_releaseall_cb_data();
        listDestroy(&nxpncihal_monitor->sem_list);
    }

    free(nxpncihal_monitor);
    nxpncihal_monitor = NULL;

    return;
}
static jbyteArray com_android_nfc_NativeNdefTag_doRead(JNIEnv *e,
   jobject o)
{
   phLibNfc_Handle handle = 0;
   jbyteArray buf = NULL;
   NFCSTATUS         status;
   
   CONCURRENCY_LOCK();

   handle = nfc_jni_get_nfc_tag_handle(e, o);

   nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len;
   nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf;

   TRACE("phLibNfc_Ndef_Read()");
   REENTRANCE_LOCK();
   status = phLibNfc_Ndef_Read( handle,
                                &nfc_jni_ndef_rw,
                                phLibNfc_Ndef_EBegin,
                                nfc_jni_tag_rw_callback,
                                (void *)e);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   sem_wait(nfc_jni_ndef_tag_sem);

   if(nfc_jni_cb_status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   buf = e->NewByteArray(nfc_jni_ndef_rw.length);
   e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length,
      (jbyte *)nfc_jni_ndef_rw.buffer);

clean_and_return:
   CONCURRENCY_UNLOCK();
   return buf;
}
static jboolean com_android_nfc_NativeNdefTag_doWrite(JNIEnv *e,
   jobject o, jbyteArray buf)
{
   NFCSTATUS      status;
   jboolean       result = JNI_FALSE;

   CONCURRENCY_LOCK();

   phLibNfc_Handle handle = nfc_jni_get_nfc_tag_handle(e, o);

   nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf);
   nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);

   TRACE("phLibNfc_Ndef_Write()");
   REENTRANCE_LOCK();
   status  = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)e);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   sem_wait(nfc_jni_ndef_tag_sem);

   if(nfc_jni_cb_status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   if (result != JNI_TRUE)
   {
      e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT);
   }

   CONCURRENCY_UNLOCK();

   return result;
}
static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
{
   NFCSTATUS ret;
   struct timespec ts;  
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sReceiveBuffer;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
   sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
   
   TRACE("phLibNfc_Llcp_Recv()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Recv(hLlcpSocket,
                            &sReceiveBuffer,
                            nfc_jni_receive_callback,
                            (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if((ret != NFCSTATUS_SUCCESS) && (ret != NFCSTATUS_PENDING))
   {
       /* Return status should be either SUCCESS or PENDING */
       LOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
       return 0;
   }
   TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response (happen if status is either SUCCESS or PENDING) */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
   {
      return 0;
   }

   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      return sReceiveBuffer.length;
   }
   else
   {
      return 0;
   }
}
/*******************************************************************************
**
** Function         phNxpNciHal_test_rx_thread
**
** Description      Thread to fetch and process messages from message queue.
**
** Returns          NULL
**
*******************************************************************************/
static void *phNxpNciHal_test_rx_thread(void *arg)
{
    phLibNfc_Message_t msg;

    NXPLOG_NCIHAL_D("Self test thread started");

    thread_running = 1;

    while (thread_running == 1)
    {
        /* Fetch next message from the NFC stack message queue */
        if (phDal4Nfc_msgrcv(gDrvCfg.nClientId,
                &msg, 0, 0) == -1)
        {
            NXPLOG_NCIHAL_E("Received bad message");
            continue;
        }

        if(thread_running == 0)
        {
            break;
        }

        switch (msg.eMsgType)
        {
            case PH_LIBNFC_DEFERREDCALL_MSG:
            {
                phLibNfc_DeferredCall_t *deferCall =
                        (phLibNfc_DeferredCall_t *) (msg.pMsgData);

                REENTRANCE_LOCK();
                deferCall->pCallback(deferCall->pParameter);
                REENTRANCE_UNLOCK();

                break;
            }
        }
    }

    NXPLOG_NCIHAL_D("Self test thread stopped");

    return NULL;
}
static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   phLibNfc_Handle hLlcpSocket;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   TRACE("phLibNfc_Llcp_Close()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Close(hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_SUCCESS)
   {
      LOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return FALSE; 
   }
   TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
   return TRUE;
}
static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
{
   NFCSTATUS ret;
   struct timespec ts;  
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sSendBuffer;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
   
   TRACE("phLibNfc_Llcp_Send()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Send(hLlcpSocket,
                            &sSendBuffer,
                            nfc_jni_send_callback,
                            (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return FALSE;
   } 
   TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
   
   /* Wait for callback response */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
      return FALSE;   


   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      return TRUE; 
   }
   else
   {
      return FALSE;    
   }     
}
static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
{
   NFCSTATUS ret;
   struct timespec ts;
   phNfc_sData_t serviceName;   
   phLibNfc_Handle hLlcpSocket;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   /* Service socket */
   serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
   serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
   
   TRACE("phLibNfc_Llcp_ConnectByUri()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_ConnectByUri(hLlcpSocket,
                                    &serviceName,
                                    nfc_jni_connect_callback,
                                    (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      return FALSE;
   }   
   TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
   
   /* Wait for callback response */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
      return FALSE;
   
   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      return TRUE; 
   }
   else
   {
      return FALSE;    
   }   
}
/*
 * Methods
 */
static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hLlcpSocket;
   
   /* Retrieve socket handle */
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   
   TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Connect(hLlcpSocket,
                               nSap,
                               nfc_jni_connect_callback,
                               (void*)hLlcpSocket);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
      return FALSE;
   }
   TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
   
   /* Wait for callback response */
   if(sem_wait(nfc_jni_llcp_sem) == -1)
      return FALSE;
   
   if(nfc_jni_cb_status == NFCSTATUS_SUCCESS)
   {
      TRACE("LLCP Connect request OK");
      return TRUE; 
   }
   else
   {
      LOGD("LLCP Connect request KO");
      return FALSE;    
   }
}
static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle)
{
   jclass cls;
   jfieldID f;
   NFCSTATUS status;
   jboolean result = JNI_FALSE;
   phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
   uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
   uint32_t SmartMX_Handle;
   struct nfc_jni_callback_data cb_data;
   phNfc_sData_t    InParam;
   phNfc_sData_t    OutParam;
   uint8_t          Output_Buff[10];
   uint8_t          GpioGetValue[3] = {0x00, 0xF8, 0x2B};
   uint8_t          GpioSetValue[4];
   uint8_t          gpioValue;

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   TRACE("Close Secure element function ");

   CONCURRENCY_LOCK();
   /* Disconnect */
   TRACE("Disconnecting from SMX (handle = 0x%x)", handle);
   REENTRANCE_LOCK();
   status = phLibNfc_RemoteDev_Disconnect(handle, 
                                          NFC_SMARTMX_RELEASE,
                                          com_android_nfc_jni_disconnect_callback,
                                          (void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;
   }
   TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
       goto clean_and_return;
   }

   /* Disconnect Status */
   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
     ALOGE("\n> Disconnect SE ERROR \n" );
      goto clean_and_return;
   }
   CONCURRENCY_UNLOCK();

   /* Get GPIO information */
   CONCURRENCY_LOCK();
   InParam.buffer = GpioGetValue;
   InParam.length = 3;
   OutParam.buffer = Output_Buff;
   TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value");
   REENTRANCE_LOCK();
   status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status!=NFCSTATUS_PENDING)
   {
       ALOGE("IOCTL status error");
       goto clean_and_return;
   }

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("IOCTL semaphore error");
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      ALOGE("READ MEM ERROR");
      goto clean_and_return;
   }

   gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0];
   TRACE("GpioValue = Ox%02x",gpioValue);

   /* Set GPIO information */
   GpioSetValue[0] = 0x00;
   GpioSetValue[1] = 0xF8;
   GpioSetValue[2] = 0x2B;
   GpioSetValue[3] = (gpioValue & 0xBF);

   TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]);

   for(i=0;i<4;i++)
   {
       TRACE("0x%02x",GpioSetValue[i]);
   }

   InParam.buffer = GpioSetValue;
   InParam.length = 4;
   OutParam.buffer = Output_Buff;
   TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value");
   REENTRANCE_LOCK();
   status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status!=NFCSTATUS_PENDING)
   {
       ALOGE("IOCTL status error");
       goto clean_and_return;
   }

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("IOCTL semaphore error");
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      ALOGE("READ MEM ERROR");
      goto clean_and_return;
   }

   result = JNI_TRUE;

clean_and_return:
   nfc_cb_data_deinit(&cb_data);

   CONCURRENCY_UNLOCK();
   return result;
}
static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu)
{
   NFCSTATUS ret;
   struct timespec ts;
   uint8_t ssap;
   jobject llcpPacket = NULL;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sReceiveBuffer;
   jclass clsLlcpPacket;
   jfieldID f;
   jbyteArray receivedData = NULL;
   struct nfc_jni_callback_data cb_data;

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Create new LlcpPacket object */
   if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1)
   {
      ALOGE("Find LlcpPacket class error");
      goto clean_and_return;
   }

   /* Get NativeConnectionless class object */
   clsLlcpPacket = e->GetObjectClass(llcpPacket);
   if(e->ExceptionCheck())
   {
      ALOGE("Get Object class error");
      goto clean_and_return;
   } 

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
   TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu);

   sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu);
   sReceiveBuffer.length = linkMiu;

   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice,
                                hLlcpSocket,
                                &sReceiveBuffer,
                                nfc_jni_receive_callback,
                                &cb_data);
   REENTRANCE_UNLOCK();
   if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS)
   {
      ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   } 
   TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
       goto clean_and_return;
   }

   ssap = (uint32_t)cb_data.pContext;
   TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length);

   /* Set Llcp Packet remote SAP */
   f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I");
   e->SetIntField(llcpPacket, f,(jbyte)ssap);

   /* Set Llcp Packet Buffer */
   ALOGD("Set LlcpPacket Data Buffer\n");
   f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B");
   receivedData = e->NewByteArray(sReceiveBuffer.length);
   e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer);
   e->SetObjectField(llcpPacket, f, receivedData);

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   return llcpPacket;
}
/*
 * Methods
 */ 
static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
{
   NFCSTATUS ret = NFCSTATUS_SUCCESS;
   struct timespec ts;
   phLibNfc_Llcp_sSocketOptions_t sOptions;
   phNfc_sData_t sWorkingBuffer;
   jfieldID f;   
   jclass clsNativeLlcpSocket;
   jobject clientSocket = NULL;
   struct nfc_jni_callback_data cb_data;
   phLibNfc_Handle hIncomingSocket, hServerSocket;
   nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Get server socket */
   hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Set socket options with the socket options of the service */
   sOptions.miu = miu;
   sOptions.rw = rw;
   
   /* Allocate Working buffer length */
   sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
   sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;

   while(cb_data.status != NFCSTATUS_SUCCESS)
   {
      /* Wait for tag Notification */
      pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
      while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) {
         pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
      }
      pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);

      /* Accept the incomming socket */
      TRACE("phLibNfc_Llcp_Accept()");
      REENTRANCE_LOCK();
      ret = phLibNfc_Llcp_Accept( hIncomingSocket,
                                  &sOptions,
                                  &sWorkingBuffer,
                                  nfc_jni_llcp_transport_socket_err_callback,
                                  nfc_jni_llcp_accept_socket_callback,
                                  (void*)&cb_data);
      REENTRANCE_UNLOCK();
      if(ret != NFCSTATUS_PENDING)
      {
         // NOTE: This may happen if link went down since incoming socket detected, then
         //       just drop it and start a new accept loop.
         LOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
         continue;
      }
      TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

      /* Wait for callback response */
      if(sem_wait(&cb_data.sem))
      {
         LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
         goto clean_and_return;
      }

      if(cb_data.status != NFCSTATUS_SUCCESS)
      {
         /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
         LOGD("Failed to accept incoming socket  0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
      }
   }

   /* Create new LlcpSocket object */
   if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1)
   {
      LOGD("LLCP Socket creation error");
      goto clean_and_return;
   }

   /* Get NativeConnectionOriented class object */
   clsNativeLlcpSocket = e->GetObjectClass(clientSocket);
   if(e->ExceptionCheck())
   {
      LOGD("LLCP Socket get class object error");
      goto clean_and_return;
   }

   /* Set socket handle */
   f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I");
   e->SetIntField(clientSocket, f,(jint)hIncomingSocket);

   /* Set socket MIU */
   f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I");
   e->SetIntField(clientSocket, f,(jint)miu);

   /* Set socket RW */
   f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I");
   e->SetIntField(clientSocket, f,(jint)rw);

   TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);

clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   return clientSocket;
}
static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
   jobject o, jbyteArray data)
{
   NFCSTATUS status;
   uint8_t offset = 2;
   uint8_t *buf;
   uint32_t buflen;
   phLibNfc_sTransceiveInfo_t transceive_info;
   jbyteArray result = NULL;
   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
   phNfc_sData_t * receive_buffer = NULL;
   struct nfc_jni_callback_data cb_data;

   CONCURRENCY_LOCK();

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer))
   {
      goto clean_and_return;
   }

   /* Transceive*/
   TRACE("Transceive data to target (handle = 0x%x)", handle);

   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
   buflen = (uint32_t)e->GetArrayLength(data);
   
   TRACE("Buffer Length = %d\n", buflen);

   transceive_info.sSendData.buffer = buf; //+ offset;
   transceive_info.sSendData.length = buflen; //- offset;
   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
   transceive_info.sRecvData.length = 1024;

   if(transceive_info.sRecvData.buffer == NULL)
   {
      goto clean_and_return;
   }

   TRACE("phLibNfc_RemoteDev_Transceive(P2P)");
   REENTRANCE_LOCK();
   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      LOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;
   }
   TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
      goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   /* Copy results back to Java */
   result = e->NewByteArray(receive_buffer->length);
   if(result != NULL)
      e->SetByteArrayRegion(result, 0,
         receive_buffer->length,
         (jbyte *)receive_buffer->buffer);

clean_and_return:
   if(transceive_info.sRecvData.buffer != NULL)
   {
      free(transceive_info.sRecvData.buffer);
   }

   e->ReleaseByteArrayElements(data,
      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);

   nfc_cb_data_deinit(&cb_data);

   CONCURRENCY_UNLOCK();

   return result;
}
static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o)
{
    phLibNfc_Handle     handle = 0;
    jboolean            result = JNI_FALSE;
    NFCSTATUS           status;
    struct nfc_jni_callback_data cb_data;

    CONCURRENCY_LOCK();

    handle = nfc_jni_get_p2p_device_handle(e, o);

    /* Create the local semaphore */
    if (!nfc_cb_data_init(&cb_data, NULL))
    {
       goto clean_and_return;
    }

    /* Disconnect */
    TRACE("Disconnecting from target (handle = 0x%x)", handle);

    /* NativeNfcTag waits for tag to leave the field here with presence check.
     * We do not in P2P path because presence check is not safe while transceive may be
     * in progress.
     */

    TRACE("phLibNfc_RemoteDev_Disconnect()");
    REENTRANCE_LOCK();
    status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data);
    REENTRANCE_UNLOCK();
    if(status != NFCSTATUS_PENDING)
    {
        LOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
        if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
        {
            LOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected");
        }
        else
        {
            LOGE("phLibNfc_RemoteDev_Disconnect() failed");
            nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
        }

        goto clean_and_return;
    }
    TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

    /* Wait for callback response */
    if(sem_wait(&cb_data.sem))
    {
       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
       goto clean_and_return;
    }

    /* Disconnect Status */
    if(cb_data.status != NFCSTATUS_SUCCESS)
    {
        goto clean_and_return;
    }

    result = JNI_TRUE;

clean_and_return:
    /* Reset device connected flag */
    device_connected_flag = 0;
    nfc_cb_data_deinit(&cb_data);
    CONCURRENCY_UNLOCK();
    return result;
}
static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o)
{
    phLibNfc_Handle handle = 0;
    NFCSTATUS status;
    jboolean result = JNI_FALSE;
    struct nfc_jni_callback_data cb_data;

    jclass target_cls = NULL;
    jobject tag;
    jmethodID ctor;
    jfieldID f;
    jbyteArray generalBytes = NULL;
    phNfc_sData_t sGeneralBytes;
    unsigned int i;

    CONCURRENCY_LOCK();

    handle = nfc_jni_get_p2p_device_handle(e, o);

    /* Create the local semaphore */
    if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes))
    {
       goto clean_and_return;
    }

    TRACE("phLibNfc_RemoteDev_Connect(P2P)");
    REENTRANCE_LOCK();
    status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data);
    REENTRANCE_UNLOCK();
    if(status != NFCSTATUS_PENDING)
    {
      LOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;
    }
    TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

    /* Wait for callback response */
    if(sem_wait(&cb_data.sem))
    {
       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
       goto clean_and_return;
    }

    if(cb_data.status != NFCSTATUS_SUCCESS)
    {
        goto clean_and_return;
    }

    /* Set General Bytes */
    target_cls = e->GetObjectClass(o);

    f = e->GetFieldID(target_cls, "mGeneralBytes", "[B");

    TRACE("General Bytes Length = %d", sGeneralBytes.length);
    TRACE("General Bytes =");
    for(i=0;i<sGeneralBytes.length;i++)
    {
      TRACE("0x%02x ", sGeneralBytes.buffer[i]);
    }

    generalBytes = e->NewByteArray(sGeneralBytes.length);

    e->SetByteArrayRegion(generalBytes, 0,
                         sGeneralBytes.length, 
                         (jbyte *)sGeneralBytes.buffer);

    e->SetObjectField(o, f, generalBytes);

    result = JNI_TRUE;

clean_and_return:
    if (result != JNI_TRUE)
    {
       /* Restart the polling loop if the connection failed */
       nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
    }
    nfc_cb_data_deinit(&cb_data);
    CONCURRENCY_UNLOCK();
    return result;
}
static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e,
   jobject o,jint handle, jbyteArray data)
{
   uint8_t offset = 0;
   uint8_t *buf;
   uint32_t buflen;
   phLibNfc_sTransceiveInfo_t transceive_info;
   jbyteArray result = NULL;
   int res; 
   
   int tech = SecureElementTech;
   NFCSTATUS status;
   struct nfc_jni_callback_data cb_data;

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   TRACE("Exchange APDU function ");
   
   CONCURRENCY_LOCK();
   
   TRACE("Secure Element tech: %d\n", tech);

   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
   buflen = (uint32_t)e->GetArrayLength(data);
 
   /* Prepare transceive info structure */
   if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL)
   {
      offset = 2;
      transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
      transceive_info.addr = (uint8_t)buf[1];
   }
   else if(tech == TARGET_TYPE_ISO14443_4)
   {
      transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw;
      transceive_info.addr = 0;
   }
      
   transceive_info.sSendData.buffer = buf + offset;
   transceive_info.sSendData.length = buflen - offset;
   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
   transceive_info.sRecvData.length = 1024;

   if(transceive_info.sRecvData.buffer == NULL)
   {
      goto clean_and_return;
   }

   TRACE("phLibNfc_RemoteDev_Transceive(SMX)");
   REENTRANCE_LOCK();
   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info,
		   com_android_nfc_jni_transceive_callback, (void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(status != NFCSTATUS_PENDING)
   {
      ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
      goto clean_and_return;
   }
   TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
       ALOGE("TRANSCEIVE semaphore error");
       goto clean_and_return;
   }

   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      ALOGE("TRANSCEIVE error");
      goto clean_and_return;
   }

   /* Copy results back to Java */
   result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length);
   if(result != NULL)
   {
      e->SetByteArrayRegion(result, 0,
    		  com_android_nfc_jni_transceive_buffer->length,
         (jbyte *)com_android_nfc_jni_transceive_buffer->buffer);
   }

clean_and_return:
   nfc_cb_data_deinit(&cb_data);

   if(transceive_info.sRecvData.buffer != NULL)
   {
      free(transceive_info.sRecvData.buffer);
   }

   e->ReleaseByteArrayElements(data,
      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);

   CONCURRENCY_UNLOCK();

   return result;
}
static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o)
{
   NFCSTATUS ret;
   int semResult;
   
   phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
   uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
   phLibNfc_sADD_Cfg_t discovery_cfg;
   phLibNfc_Registry_Info_t registry_info;
   phNfc_sData_t        InParam;
   phNfc_sData_t        OutParam;
   uint8_t              ExternalRFDetected[3] = {0x00, 0xFC, 0x01};
   uint8_t              GpioGetValue[3] = {0x00, 0xF8, 0x2B};
   uint8_t              GpioSetValue[4];
   uint8_t              gpioValue;
   uint8_t              Output_Buff[10];
   uint8_t              reg_value;
   uint8_t              mask_value;
   struct nfc_jni_callback_data cb_data;
   struct nfc_jni_callback_data cb_data_SE_Notification;

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL))
   {
      goto clean_and_return;
   }

   /* Registery */   
   registry_info.MifareUL = TRUE;
   registry_info.MifareStd = TRUE;
   registry_info.ISO14443_4A = TRUE;
   registry_info.ISO14443_4B = TRUE;
   registry_info.Jewel = TRUE;
   registry_info.Felica = TRUE;  
   registry_info.NFC = FALSE;  
     
   CONCURRENCY_LOCK();
   
   TRACE("Open Secure Element");
   
   /* Check if NFC device is already connected to a tag or P2P peer */
   if (device_connected_flag == 1)
   {
       ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag");
       goto clean_and_return;
   }

   /* Test if External RF field is detected */
   InParam.buffer = ExternalRFDetected;
   InParam.length = 3;
   OutParam.buffer = Output_Buff;
   TRACE("phLibNfc_Mgt_IoCtl()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret!=NFCSTATUS_PENDING)
   {
      ALOGE("IOCTL status error");
      goto clean_and_return;
   }

   /* Wait for callback response */
   if(sem_wait(&cb_data.sem))
   {
      ALOGE("IOCTL semaphore error");
      goto clean_and_return;
   }
      
   if(cb_data.status != NFCSTATUS_SUCCESS)
   {
      ALOGE("READ MEM ERROR");
      goto clean_and_return;
   }

   /* Check the value */   
   reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0];
   mask_value = reg_value & 0x40;

   if(mask_value == 0x40)
   {
      // There is an external RF field present, fail the open request
      ALOGD("Unable to open SE connection, external RF Field detected");
      goto clean_and_return;   
   }   

   /* Get Secure Element List */
   TRACE("phLibNfc_SE_GetSecureElementList()");
   ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE);
   if (ret == NFCSTATUS_SUCCESS)
   {
      TRACE("\n> Number of Secure Element(s) : %d\n", No_SE);
      /* Display Secure Element information */
      for (i = 0; i<No_SE; i++)
      {
         if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX)
         {
           TRACE("> SMX detected");
           TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement);
           /* save SMARTMX index */
           SmartMX_detected = 1;
           SmartMX_index = i;
         }
      }

      if(SmartMX_detected)
      {
         REENTRANCE_LOCK();
         TRACE("phLibNfc_RemoteDev_NtfRegister()");
         ret = phLibNfc_RemoteDev_NtfRegister(&registry_info,
                 com_android_nfc_jni_open_secure_element_notification_callback,
                 (void *)&cb_data_SE_Notification);
         REENTRANCE_UNLOCK();
         if(ret != NFCSTATUS_SUCCESS)
         {
            ALOGE("Register Notification error");
            goto clean_and_return;
         }

         /* Set wired mode */
         REENTRANCE_LOCK();
         TRACE("phLibNfc_SE_SetMode: Wired mode");
         ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, 
                                     phLibNfc_SE_ActModeWired,
                                     com_android_nfc_jni_smartMX_setModeCb,
                                     (void *)&cb_data);
         REENTRANCE_UNLOCK();
         if (ret != NFCSTATUS_PENDING )
         {
            ALOGE("\n> SE Set SmartMX mode ERROR \n" );
            goto clean_and_return;
         }

         /* Wait for callback response */
         if(sem_wait(&cb_data.sem))
         {
            ALOGE("Secure Element opening error");
            goto clean_and_return;
         }

         if(cb_data.status != NFCSTATUS_SUCCESS)
         {
            ALOGE("SE set mode failed");
            goto clean_and_return;
         }

         TRACE("Waiting for notification");
         /* Wait for callback response */
         if(sem_wait(&cb_data_SE_Notification.sem))
         {
            ALOGE("Secure Element opening error");
            goto clean_and_return;
         }

         if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS &&
                 cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS)
         {
            ALOGE("SE detection failed");
            goto clean_and_return;
         }
         CONCURRENCY_UNLOCK();

         /* Connect Tag */
         CONCURRENCY_LOCK();
         TRACE("phLibNfc_RemoteDev_Connect(SMX)");
         REENTRANCE_LOCK();
         ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data);
         REENTRANCE_UNLOCK();
         if(ret != NFCSTATUS_PENDING)
         {
            ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
            goto clean_and_return;
         }
         TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

         /* Wait for callback response */
         if(sem_wait(&cb_data.sem))
         {
             ALOGE("CONNECT semaphore error");
             goto clean_and_return;
         }

         /* Connect Status */
         if(cb_data.status != NFCSTATUS_SUCCESS)
         {
            ALOGE("Secure Element connect error");
            goto clean_and_return;
         }

         CONCURRENCY_UNLOCK();

         /* Get GPIO information */
         CONCURRENCY_LOCK();
         InParam.buffer = GpioGetValue;
         InParam.length = 3;
         OutParam.buffer = Output_Buff;
         TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value");
         REENTRANCE_LOCK();
         ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data);
         REENTRANCE_UNLOCK();
         if(ret!=NFCSTATUS_PENDING)
         {
             ALOGE("IOCTL status error");
         }

         /* Wait for callback response */
         if(sem_wait(&cb_data.sem))
         {
            ALOGE("IOCTL semaphore error");
            goto clean_and_return;
         }

         if(cb_data.status != NFCSTATUS_SUCCESS)
         {
            ALOGE("READ MEM ERROR");
            goto clean_and_return;
         }

         gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0];
         TRACE("GpioValue = Ox%02x",gpioValue);

         /* Set GPIO information */
         GpioSetValue[0] = 0x00;
         GpioSetValue[1] = 0xF8;
         GpioSetValue[2] = 0x2B;
         GpioSetValue[3] = (gpioValue | 0x40);

         TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]);

         for(i=0;i<4;i++)
         {
             TRACE("0x%02x",GpioSetValue[i]);
         }

         InParam.buffer = GpioSetValue;
         InParam.length = 4;
         OutParam.buffer = Output_Buff;
         TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value");
         REENTRANCE_LOCK();
         ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data);
         REENTRANCE_UNLOCK();
         if(ret!=NFCSTATUS_PENDING)
         {
             ALOGE("IOCTL status error");
             goto clean_and_return;
         }

         /* Wait for callback response */
         if(sem_wait(&cb_data.sem))
         {
            ALOGE("IOCTL semaphore error");
            goto clean_and_return;
         }

         if(cb_data.status != NFCSTATUS_SUCCESS)
         {
            ALOGE("READ MEM ERROR");
            goto clean_and_return;
         }
         CONCURRENCY_UNLOCK();

         nfc_cb_data_deinit(&cb_data);
         nfc_cb_data_deinit(&cb_data_SE_Notification);

         /* Return the Handle of the SecureElement */
         return secureElementHandle;
      }
      else
      {
         ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected");
         goto clean_and_return; 
      } 
  }
  else
  {
      ALOGE("phLibNfc_SE_GetSecureElementList(): Error");
      goto clean_and_return;
  }
  
clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   nfc_cb_data_deinit(&cb_data_SE_Notification);

   CONCURRENCY_UNLOCK();
   return 0;
}
static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
{
   NFCSTATUS ret;
   struct timespec ts;
   phLibNfc_Handle hRemoteDevice;
   phLibNfc_Handle hLlcpSocket;
   phNfc_sData_t sReceiveBuffer = {NULL, 0};
   struct nfc_jni_callback_data cb_data;
   jint result = -1;

   /* Retrieve handles */
   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, NULL))
   {
      goto clean_and_return;
   }

   sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
   sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);

   TRACE("phLibNfc_Llcp_Recv()");
   REENTRANCE_LOCK();
   ret = phLibNfc_Llcp_Recv(hRemoteDevice,
                            hLlcpSocket,
                            &sReceiveBuffer,
                            nfc_jni_receive_callback,
                            (void*)&cb_data);
   REENTRANCE_UNLOCK();
   if(ret == NFCSTATUS_PENDING)
   {
      /* Wait for callback response */
      if(sem_wait(&cb_data.sem))
      {
         ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
         goto clean_and_return;
      }

      if(cb_data.status == NFCSTATUS_SUCCESS)
      {
         result = sReceiveBuffer.length;
      }
   }
   else if (ret == NFCSTATUS_SUCCESS)
   {
      result = sReceiveBuffer.length;
   }
   else
   {
      /* Return status should be either SUCCESS or PENDING */
      ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
      goto clean_and_return;
   }
   TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));

clean_and_return:
   if (sReceiveBuffer.buffer != NULL)
   {
      e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
   }
   nfc_cb_data_deinit(&cb_data);
   return result;
}