summaryrefslogtreecommitdiffstats
path: root/nxp/jni/com_android_nfc_NativeNfcManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nxp/jni/com_android_nfc_NativeNfcManager.cpp')
-rwxr-xr-xnxp/jni/com_android_nfc_NativeNfcManager.cpp3393
1 files changed, 3393 insertions, 0 deletions
diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp
new file mode 100755
index 0000000..af0e4fb
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp
@@ -0,0 +1,3393 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <sys/queue.h>
+#include <hardware/hardware.h>
+#include <hardware/nfc.h>
+#include <cutils/properties.h>
+
+#include "com_android_nfc.h"
+
+#define ERROR_BUFFER_TOO_SMALL -12
+#define ERROR_INSUFFICIENT_RESOURCES -9
+
+/****************************************************************
+* define CONFIG_CE_DEFAULT in order to always enable PCD A
+* discovery while the discovery loop is on.
+* The only case where this is an issue is when a remote device
+* is another android NFC device and has an activity triggered
+* on an intent of ISO14443 technology discovery.
+*
+* if this is the case then the P2P NDEF PUSH service will never
+* get notified there is another NDEF client because the client
+* will actually get discovered as a ISO14443 tag.
+*
+* if CONFIG_CE_DEFAULT is NOT defined, then the issue with
+* this case is mostly solved because the PCD A/B modes can
+* only be activated when the foreground activity calls for them in
+* enableForegroundDispatch
+* and they are de-activated whenever the device turns off
+* discovery loop
+*
+* HOST CARD EMULATION PATCH 1.01
+* Author: doug yeager (doug@simplytapp.com)
+******************************************************************/
+#define HOST_EMULATION
+//#define CONFIG_CE_DEFAULT
+#define TURN_CE_ON 1
+#define TURN_CE_OFF 0
+#define UNBLOCK_CE_CALLBACK 2
+#define INIT_CE 3
+
+extern uint32_t libnfc_llc_error_count;
+
+static phLibNfc_sConfig_t gDrvCfg;
+void *gHWRef;
+static phNfc_sData_t gInputParam;
+static phNfc_sData_t gOutputParam;
+
+uint8_t device_connected_flag;
+static bool driverConfigured = FALSE;
+static bool ceAOn = FALSE;
+static bool ceBOn = FALSE;
+static bool turnCeAOn = FALSE;
+static bool turnCeBOn = FALSE;
+static bool discoveryOn = FALSE;
+
+static phLibNfc_Handle hLlcpHandle;
+static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED;
+static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault;
+
+static jmethodID cached_NfcManager_notifyNdefMessageListeners;
+static jmethodID cached_NfcManager_notifyTransactionListeners;
+static jmethodID cached_NfcManager_notifyLlcpLinkActivation;
+static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated;
+static jmethodID cached_NfcManager_notifyTargetDeselected;
+
+static jmethodID cached_NfcManager_notifySeFieldActivated;
+static jmethodID cached_NfcManager_notifySeFieldDeactivated;
+
+static jmethodID cached_NfcManager_notifySeApduReceived;
+static jmethodID cached_NfcManager_notifySeMifareAccess;
+static jmethodID cached_NfcManager_notifySeEmvCardRemoval;
+
+namespace android {
+
+phLibNfc_Handle storedHandle = 0;
+
+struct nfc_jni_native_data *exported_nat = NULL;
+
+/* Internal functions declaration */
+static void *nfc_jni_client_thread(void *arg);
+static void nfc_jni_init_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_se_set_mode_callback(void *context,
+ phLibNfc_Handle handle, NFCSTATUS status);
+static void nfc_jni_CE_callback(void *context,
+ phLibNfc_eCE_EvtType_t evt_type, uint32_t handle, NFCSTATUS status);
+static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_CEcfg_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume);
+static void set_CE_A_mode(uint8_t mode, struct nfc_jni_native_data *nat);
+static void set_CE_B_mode(uint8_t mode, struct nfc_jni_native_data *nat);
+static void nfc_jni_Discovery_notification_callback(void *pContext,
+ phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNofRemoteDev, NFCSTATUS status);
+static void nfc_jni_transaction_callback(void *context,
+ phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle,
+ phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status);
+static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock);
+
+/*
+ * Deferred callback called when client thread must be exited
+ */
+static void client_kill_deferred_call(void* arg)
+{
+ struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg;
+
+ nat->running = FALSE;
+}
+
+static void kill_client(nfc_jni_native_data *nat)
+{
+ phDal4Nfc_Message_Wrapper_t wrapper;
+ phLibNfc_DeferredCall_t *pMsg;
+
+ usleep(50000);
+
+ ALOGD("Terminating client thread...");
+
+ pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t));
+ pMsg->pCallback = client_kill_deferred_call;
+ pMsg->pParameter = (void*)nat;
+
+ wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
+ wrapper.msg.pMsgData = pMsg;
+ wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t);
+
+ phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0);
+}
+
+static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) {
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_ioctl_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_deinit_download_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update)
+{
+ uint8_t OutputBuffer[1];
+ uint8_t InputBuffer[1];
+ struct timespec ts;
+ NFCSTATUS status = NFCSTATUS_FAILED;
+ phLibNfc_StackCapabilities_t caps;
+ struct nfc_jni_callback_data cb_data;
+ bool result;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ if(update)
+ {
+ //deinit
+ TRACE("phLibNfc_Mgt_DeInitialize() (download)");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 5;
+
+ /* Wait for callback response */
+ if(sem_timedwait(&cb_data.sem, &ts))
+ {
+ ALOGW("Deinitialization timed out (download)");
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("Deinitialization FAILED (download)");
+ }
+ TRACE("Deinitialization SUCCESS (download)");
+ }
+
+ result = performDownload(nat, false);
+
+ if (!result) {
+ status = NFCSTATUS_FAILED;
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_Mgt_Initialize()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_FAILED;
+ goto clean_and_return;
+ }
+
+ /* Initialization Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ status = cb_data.status;
+ goto clean_and_return;
+ }
+
+ /* ====== CAPABILITIES ======= */
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+ else
+ {
+ ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d",
+ caps.psDevCapabilities.hal_version,
+ caps.psDevCapabilities.fw_version,
+ caps.psDevCapabilities.hw_version,
+ caps.psDevCapabilities.model_id,
+ caps.psDevCapabilities.hci_version,
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1],
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2],
+ caps.psDevCapabilities.firmware_update_info);
+ }
+
+ /*Download is successful*/
+ status = NFCSTATUS_SUCCESS;
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ return status;
+}
+
+static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat)
+{
+ char value[PROPERTY_VALUE_MAX];
+ int result = FALSE;
+ NFCSTATUS status;
+
+ /* ====== CONFIGURE DRIVER ======= */
+ /* Configure hardware link */
+ gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600);
+
+ TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId);
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef);
+ REENTRANCE_UNLOCK();
+ if(status == NFCSTATUS_ALREADY_INITIALISED) {
+ ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+ else if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0)
+ {
+ ALOGE("pthread_create failed");
+ goto clean_and_return;
+ }
+
+ driverConfigured = TRUE;
+
+clean_and_return:
+ return result;
+}
+
+static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat)
+{
+ int result = FALSE;
+ NFCSTATUS status;
+
+ /* Unconfigure driver */
+ TRACE("phLibNfc_Mgt_UnConfigureDriver()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_UnConfigureDriver(gHWRef);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status));
+ }
+ else
+ {
+ ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ result = TRUE;
+ }
+
+ driverConfigured = FALSE;
+
+ return result;
+}
+
+/* Initialization function */
+static int nfc_jni_initialize(struct nfc_jni_native_data *nat) {
+ struct timespec ts;
+ uint8_t resp[16];
+ NFCSTATUS status;
+ phLibNfc_StackCapabilities_t caps;
+ 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_Llcp_sLinkParameters_t LlcpConfigInfo;
+ struct nfc_jni_callback_data cb_data;
+ uint8_t firmware_status;
+ uint8_t update = TRUE;
+ int result = JNI_FALSE;
+ const hw_module_t* hw_module;
+ nfc_pn544_device_t* pn544_dev = NULL;
+ int ret = 0;
+ ALOGD("Start Initialization\n");
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+ /* Get EEPROM values and device port from product-specific settings */
+ ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module);
+ if (ret) {
+ ALOGE("hw_get_module() failed.");
+ goto clean_and_return;
+ }
+ ret = nfc_pn544_open(hw_module, &pn544_dev);
+ if (ret) {
+ ALOGE("Could not open pn544 hw_module.");
+ goto clean_and_return;
+ }
+ if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) {
+ ALOGE("Could not load EEPROM settings");
+ goto clean_and_return;
+ }
+
+ /* Reset device connected handle */
+ device_connected_flag = 0;
+
+ /* Reset stored handle */
+ storedHandle = 0;
+
+ /* Initialize Driver */
+ if(!driverConfigured)
+ {
+ nfc_jni_configure_driver(nat);
+ }
+
+ /* ====== INITIALIZE ======= */
+
+ TRACE("phLibNfc_Mgt_Initialize()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ update = FALSE;
+ goto force_download;
+ }
+ TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Initialization Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ update = FALSE;
+ goto force_download;
+ }
+
+ /* ====== CAPABILITIES ======= */
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+ else
+ {
+ ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d",
+ caps.psDevCapabilities.hal_version,
+ caps.psDevCapabilities.fw_version,
+ caps.psDevCapabilities.hw_version,
+ caps.psDevCapabilities.model_id,
+ caps.psDevCapabilities.hci_version,
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1],
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2],
+ caps.psDevCapabilities.firmware_update_info);
+ }
+
+ /* ====== FIRMWARE VERSION ======= */
+ if(caps.psDevCapabilities.firmware_update_info)
+ {
+force_download:
+ for (i=0; i<3; i++)
+ {
+ TRACE("Firmware version not UpToDate");
+ status = nfc_jni_download_locked(nat, update);
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ ALOGI("Firmware update SUCCESS");
+ break;
+ }
+ ALOGW("Firmware update FAILED");
+ update = FALSE;
+ }
+ if(i>=3)
+ {
+ ALOGE("Unable to update firmware, giving up");
+ goto clean_and_return;
+ }
+ }
+ else
+ {
+ TRACE("Firmware version UpToDate");
+ }
+ /* ====== EEPROM SETTINGS ======= */
+
+ // Update EEPROM settings
+ TRACE("****** START EEPROM SETTINGS UPDATE ******");
+ for (i = 0; i < pn544_dev->num_eeprom_settings; i++)
+ {
+ char eeprom_property[PROPERTY_KEY_MAX];
+ char eeprom_value[PROPERTY_VALUE_MAX];
+ uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]);
+ TRACE("> EEPROM SETTING: %d", i);
+
+ // Check for override of this EEPROM value in properties
+ snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X",
+ eeprom_base[1], eeprom_base[2]);
+ TRACE(">> Checking property: %s", eeprom_property);
+ if (property_get(eeprom_property, eeprom_value, "") == 2) {
+ int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16);
+ ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X",
+ eeprom_base[1], eeprom_base[2], eeprom_value_num);
+ eeprom_base[3] = eeprom_value_num;
+ }
+
+ TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2],
+ eeprom_base[3]);
+ gInputParam.buffer = eeprom_base;
+ gInputParam.length = 0x04;
+ gOutputParam.buffer = resp;
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_PENDING) {
+ ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Initialization Status */
+ if (cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+ }
+ TRACE("****** ALL EEPROM SETTINGS UPDATED ******");
+
+ /* ====== SECURE ELEMENTS ======= */
+
+ REENTRANCE_LOCK();
+ ALOGD("phLibNfc_SE_GetSecureElementList()");
+ status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): Error");
+ goto clean_and_return;
+ }
+
+ ALOGD("\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) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement);
+ } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement);
+ }
+
+ /* Set SE mode - Off */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement,
+ phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+ }
+
+ /* ====== LLCP ======= */
+
+ /* LLCP Params */
+ TRACE("****** NFC Config Mode NFCIP1 - LLCP ******");
+ LlcpConfigInfo.miu = nat->miu;
+ LlcpConfigInfo.lto = nat->lto;
+ LlcpConfigInfo.wks = nat->wks;
+ LlcpConfigInfo.option = nat->opt;
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo,
+ nfc_jni_llcpcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* ===== DISCOVERY ==== */
+ nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator
+ nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target
+ nat->discovery_cfg.Duration = 300000; /* in ms */
+ nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE;
+
+#if defined (HOST_EMULATION)
+ /* Register for the card emulation mode */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_CE_NtfRegister(nfc_jni_CE_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("pphLibNfc_CE_RemoteDev_NtfRegister returned 0x%02x",ret);
+ }
+ TRACE("phLibNfc_CE_NtfRegister returned 0x%x\n", ret);
+#else
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+#endif
+ /* ====== END ======= */
+
+ ALOGI("NFC Initialized");
+
+ result = TRUE;
+
+clean_and_return:
+ if (result != TRUE)
+ {
+ if(nat)
+ {
+ kill_client(nat);
+ }
+ }
+ if (pn544_dev != NULL) {
+ nfc_pn544_close(pn544_dev);
+ }
+ nfc_cb_data_deinit(&cb_data);
+
+ return result;
+}
+
+static int is_user_build() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.type", value, "");
+ return !strncmp("user", value, PROPERTY_VALUE_MAX);
+}
+
+/*
+ * Last-chance fallback when there is no clean way to recover
+ * Performs a software reset
+ */
+void emergency_recovery(struct nfc_jni_native_data *nat) {
+ if (!is_user_build()) {
+ ALOGE("emergency_recovery: force restart of NFC service");
+ } else {
+ // dont recover immediately, so we can debug
+ unsigned int t;
+ for (t=1; t < 1000000; t <<= 1) {
+ ALOGE("emergency_recovery: NFC stack dead-locked");
+ sleep(t);
+ }
+ }
+ phLibNfc_Mgt_Recovery();
+ abort(); // force a noisy crash
+}
+
+void nfc_jni_reset_timeout_values()
+{
+ REENTRANCE_LOCK();
+ phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT);
+ phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT);
+ phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT);
+ phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT);
+ REENTRANCE_UNLOCK();
+}
+
+/*
+ * Restart the polling loop when unable to perform disconnect
+ */
+void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat)
+{
+ nfc_jni_start_discovery_locked(nat, true);
+}
+
+ /*
+ * Utility to recover UID from target infos
+ */
+static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo)
+{
+ phNfc_sData_t uid;
+
+ switch(psRemoteDevInfo->RemDevType)
+ {
+ case phNfc_eISO14443_A_PICC:
+ case phNfc_eISO14443_4A_PICC:
+ case phNfc_eISO14443_3A_PICC:
+ case phNfc_eMifare_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength;
+ break;
+ case phNfc_eISO14443_B_PICC:
+ case phNfc_eISO14443_4B_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi;
+ uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi);
+ break;
+ case phNfc_eFelica_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength;
+ break;
+ case phNfc_eJewel_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength;
+ break;
+ case phNfc_eISO15693_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength;
+ break;
+ case phNfc_eNfcIP1_Target:
+ case phNfc_eNfcIP1_Initiator:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length;
+ break;
+ default:
+ uid.buffer = NULL;
+ uid.length = 0;
+ break;
+ }
+
+ return uid;
+}
+
+/*
+ * NFC stack message processing
+ */
+static void *nfc_jni_client_thread(void *arg)
+{
+ struct nfc_jni_native_data *nat;
+ JNIEnv *e;
+ JavaVMAttachArgs thread_args;
+ phDal4Nfc_Message_Wrapper_t wrapper;
+
+ nat = (struct nfc_jni_native_data *)arg;
+
+ thread_args.name = "NFC Message Loop";
+ thread_args.version = nat->env_version;
+ thread_args.group = NULL;
+
+ nat->vm->AttachCurrentThread(&e, &thread_args);
+ pthread_setname_np(pthread_self(), "message");
+
+ TRACE("NFC client started");
+ nat->running = TRUE;
+ while(nat->running == TRUE)
+ {
+ /* Fetch next message from the NFC stack message queue */
+ if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper,
+ sizeof(phLibNfc_Message_t), 0, 0) == -1)
+ {
+ ALOGE("NFC client received bad message");
+ continue;
+ }
+
+ switch(wrapper.msg.eMsgType)
+ {
+ case PH_LIBNFC_DEFERREDCALL_MSG:
+ {
+ phLibNfc_DeferredCall_t *msg =
+ (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData);
+
+ REENTRANCE_LOCK();
+ msg->pCallback(msg->pParameter);
+ REENTRANCE_UNLOCK();
+
+ break;
+ }
+ }
+ }
+ TRACE("NFC client stopped");
+
+ nat->vm->DetachCurrentThread();
+
+ return NULL;
+}
+
+extern uint8_t nfc_jni_is_ndef;
+extern uint8_t *nfc_jni_ndef_buf;
+extern uint32_t nfc_jni_ndef_buf_len;
+
+static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg =
+{
+ 3,
+ { 0x46, 0x66, 0x6D }
+};
+
+/*
+ * Callbacks
+ */
+
+/* P2P - LLCP callbacks */
+static void nfc_jni_llcp_linkStatus_callback(void *pContext,
+ phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus)
+{
+ phFriNfc_Llcp_sLinkParameters_t sLinkParams;
+ JNIEnv *e;
+ NFCSTATUS status;
+
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext;
+
+ nfc_jni_listen_data_t * pListenData = NULL;
+ nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor();
+
+ TRACE("Callback: nfc_jni_llcp_linkStatus_callback()");
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ /* Update link status */
+ g_eLinkStatus = eLinkStatus;
+
+ if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated)
+ {
+ REENTRANCE_LOCK();
+ status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("GetRemote Info failded - Status = %02x",status);
+ }
+ else
+ {
+ ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto,
+ sLinkParams.miu,
+ sLinkParams.option,
+ sLinkParams.wks);
+ device_connected_flag = 1;
+ }
+ }
+ else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated)
+ {
+ ALOGI("LLCP Link deactivated");
+ free(pContextData);
+ /* Reset device connected flag */
+ device_connected_flag = 0;
+
+ /* Reset incoming socket list */
+ while (!LIST_EMPTY(&pMonitor->incoming_socket_head))
+ {
+ pListenData = LIST_FIRST(&pMonitor->incoming_socket_head);
+ LIST_REMOVE(pListenData, entries);
+ free(pListenData);
+ }
+
+ /* Notify manager that the LLCP is lost or deactivated */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+}
+
+static void nfc_jni_checkLlcp_callback(void *context,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context;
+
+ LOG_CALLBACK("nfc_jni_checkLlcp_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcpcfg_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_CEcfg_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_CEcfg_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext,
+ phLibNfc_Handle hIncomingSocket)
+{
+ phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext;
+ nfc_jni_listen_data_t * pListenData = NULL;
+ nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor();
+
+ TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket);
+
+ pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
+
+ /* Store the connection request */
+ pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t));
+ if (pListenData == NULL)
+ {
+ ALOGE("Failed to create structure to handle incoming LLCP connection request");
+ goto clean_and_return;
+ }
+ pListenData->pServerSocket = hServiceSocket;
+ pListenData->pIncomingSocket = hIncomingSocket;
+ LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries);
+
+ /* Signal pending accept operations that the list is updated */
+ pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
+
+clean_and_return:
+ pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
+}
+
+void nfc_jni_llcp_transport_socket_err_callback(void* pContext,
+ uint8_t nErrCode)
+{
+ PHNFC_UNUSED_VARIABLE(pContext);
+
+ TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()");
+
+ if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED)
+ {
+ ALOGW("Frame Rejected - Disconnected");
+ }
+ else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED)
+ {
+ ALOGD("Socket Disconnected");
+ }
+}
+
+
+static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_discover_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void nfc_jni_Discover_14443_4_PCD_callback(void *pContext, phLibNfc_Handle handle, phNfc_sData_t *data, NFCSTATUS status)
+{
+ JNIEnv *e;
+ NFCSTATUS ret;
+ jclass tag_cls = NULL;
+ jobject tag;
+ jmethodID ctor;
+ jfieldID f;
+ struct nfc_jni_native_data *nat;
+ uint16_t j;
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo = (phLibNfc_sRemoteDevInformation_t *) handle;
+ phLibNfc_RemoteDevList_t psRemoteDevList[1];
+ uint8_t *buffer;
+
+ nat = (struct nfc_jni_native_data *)pContext;
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ if(status == NFCSTATUS_DESELECTED)
+ {
+ if(!device_connected_flag)
+ {
+ //free handle memory
+ phOsalNfc_FreeMemory(psRemoteDevInfo);
+ }
+ LOG_CALLBACK("nfc_jni_Discover_14443_4_PCD_callback: Target deselected", status);
+ }
+ else
+ {
+ LOG_CALLBACK("nfc_jni_discover_14443_4_PCD_callback", status);
+
+ storedHandle = handle;
+ /* Reset device connected flag */
+ device_connected_flag = 1;
+
+ //store the incoming data
+ if(psRemoteDevInfo!=NULL)
+ {
+ buffer = (uint8_t*)malloc(data->length);
+ memcpy(buffer, data->buffer, data->length);
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer = buffer;
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length = data->length;
+ }
+
+
+ tag_cls = e->GetObjectClass(nat->cached_NfcTag);
+ if(e->ExceptionCheck())
+ {
+ kill_client(nat);
+ return;
+ }
+
+ /* New tag instance */
+ ctor = e->GetMethodID(tag_cls, "<init>", "()V");
+ tag = e->NewObject(tag_cls, ctor);
+
+ /* Generate technology list */
+ jintArray techList;
+ jintArray handleList;
+ jintArray typeList;
+ psRemoteDevList[0].psRemoteDevInfo = psRemoteDevInfo;
+ psRemoteDevList[0].hTargetDev = handle;
+ nfc_jni_get_technology_tree(e, psRemoteDevList,
+ 1,
+ &techList, &handleList, &typeList);
+
+ /* Push the technology list into the java object */
+ f = e->GetFieldID(tag_cls, "mTechList", "[I");
+ e->SetObjectField(tag, f, techList);
+
+ f = e->GetFieldID(tag_cls, "mTechHandles", "[I");
+ e->SetObjectField(tag, f, handleList);
+
+ f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I");
+ e->SetObjectField(tag, f, typeList);
+
+ f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I");
+ e->SetIntField(tag, f,(jint)-1);
+
+ f = e->GetFieldID(tag_cls, "mConnectedHandle", "I");
+ e->SetIntField(tag, f,(jint)-1);
+
+ if(techList!=NULL)
+ e->DeleteLocalRef(techList);
+ if(handleList!=NULL)
+ e->DeleteLocalRef(handleList);
+ if(typeList!=NULL)
+ e->DeleteLocalRef(typeList);
+
+ if (nat->tag != NULL) {
+ e->DeleteGlobalRef(nat->tag);
+ }
+ nat->tag = e->NewGlobalRef(tag);
+
+ /* Notify the service */
+ TRACE("Notify Nfc Service");
+ /* Notify manager that new a tag was found */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ e->DeleteLocalRef(tag);
+ }
+}
+
+static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNoOfRemoteDev)
+{
+ // Always prefer p2p targets over other targets. Otherwise, select the first target
+ // reported.
+ uint8_t preferred_index = 0;
+ for (uint8_t i = 0; i < uNoOfRemoteDev; i++) {
+ if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) {
+ preferred_index = i;
+ }
+ }
+ return preferred_index;
+}
+
+static void nfc_jni_Discovery_notification_callback(void *pContext,
+ phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNofRemoteDev, NFCSTATUS status)
+{
+ JNIEnv *e;
+ NFCSTATUS ret;
+ jclass tag_cls = NULL;
+ jobject target_array;
+ jobject tag;
+ jmethodID ctor;
+ jfieldID f;
+ const char * typeName;
+ jbyteArray tagUid;
+ jbyteArray generalBytes = NULL;
+ struct nfc_jni_native_data *nat;
+ struct timespec ts;
+ phNfc_sData_t data;
+ int i;
+ int target_index = 0; // Target that will be reported (if multiple can be >0)
+
+ nat = (struct nfc_jni_native_data *)pContext;
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ if(status == NFCSTATUS_DESELECTED)
+ {
+ LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status);
+
+ /* Notify manager that a target was deselected */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+ else
+ {
+ LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status);
+ TRACE("Discovered %d tags", uNofRemoteDev);
+
+ target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev);
+
+ /* Reset device connected flag */
+ device_connected_flag = 1;
+ phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo;
+ phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev;
+ if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target))
+ {
+
+ tag_cls = e->GetObjectClass(nat->cached_P2pDevice);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Get Object Class Error");
+ kill_client(nat);
+ return;
+ }
+
+ /* New target instance */
+ ctor = e->GetMethodID(tag_cls, "<init>", "()V");
+ tag = e->NewObject(tag_cls, ctor);
+
+ /* Set P2P Target mode */
+ f = e->GetFieldID(tag_cls, "mMode", "I");
+
+ if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ {
+ ALOGD("Discovered P2P Initiator");
+ e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR);
+ }
+ else
+ {
+ ALOGD("Discovered P2P Target");
+ e->SetIntField(tag, f, (jint)MODE_P2P_TARGET);
+ }
+
+ if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ {
+ /* Set General Bytes */
+ f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B");
+
+ TRACE("General Bytes length =");
+ for(i=0;i<remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++)
+ {
+ ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]);
+ }
+
+ generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length);
+
+ e->SetByteArrayRegion(generalBytes, 0,
+ remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length,
+ (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo);
+
+ e->SetObjectField(tag, f, generalBytes);
+ }
+
+ /* Set tag handle */
+ f = e->GetFieldID(tag_cls, "mHandle", "I");
+ e->SetIntField(tag, f,(jint)remDevHandle);
+ TRACE("Target handle = 0x%08x",remDevHandle);
+ }
+ else
+ {
+ tag_cls = e->GetObjectClass(nat->cached_NfcTag);
+ if(e->ExceptionCheck())
+ {
+ kill_client(nat);
+ return;
+ }
+
+ /* New tag instance */
+ ctor = e->GetMethodID(tag_cls, "<init>", "()V");
+ tag = e->NewObject(tag_cls, ctor);
+
+ bool multi_protocol = false;
+
+ if(status == NFCSTATUS_MULTIPLE_PROTOCOLS)
+ {
+ TRACE("Multiple Protocol TAG detected\n");
+ multi_protocol = true;
+ }
+
+ /* Set tag UID */
+ f = e->GetFieldID(tag_cls, "mUid", "[B");
+ data = get_target_uid(remDevInfo);
+ tagUid = e->NewByteArray(data.length);
+ if(data.length > 0)
+ {
+ e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer);
+ }
+ e->SetObjectField(tag, f, tagUid);
+
+ /* Generate technology list */
+ jintArray techList;
+ jintArray handleList;
+ jintArray typeList;
+ nfc_jni_get_technology_tree(e, psRemoteDevList,
+ multi_protocol ? uNofRemoteDev : 1,
+ &techList, &handleList, &typeList);
+
+ /* Push the technology list into the java object */
+ f = e->GetFieldID(tag_cls, "mTechList", "[I");
+ e->SetObjectField(tag, f, techList);
+
+ f = e->GetFieldID(tag_cls, "mTechHandles", "[I");
+ e->SetObjectField(tag, f, handleList);
+
+ f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I");
+ e->SetObjectField(tag, f, typeList);
+
+ f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I");
+ e->SetIntField(tag, f,(jint)-1);
+
+ f = e->GetFieldID(tag_cls, "mConnectedHandle", "I");
+ e->SetIntField(tag, f,(jint)-1);
+ }
+
+ storedHandle = remDevHandle;
+ if (nat->tag != NULL) {
+ e->DeleteGlobalRef(nat->tag);
+ }
+ nat->tag = e->NewGlobalRef(tag);
+
+ /* Notify the service */
+ TRACE("Notify Nfc Service");
+ if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target))
+ {
+ /* Store the hanlde of the P2P device */
+ hLlcpHandle = remDevHandle;
+
+ /* Notify manager that new a P2P device was found */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+ else
+ {
+ /* Notify manager that new a tag was found */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+ e->DeleteLocalRef(tag);
+ }
+}
+
+static void nfc_jni_init_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_init_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_deinit_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/* Set Secure Element mode callback*/
+static void nfc_jni_smartMX_setModeCb (void* pContext,
+ phLibNfc_Handle hSecureElement,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/* Card Emulation callback */
+static void nfc_jni_transaction_callback(void *context,
+ phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle,
+ phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status)
+{
+ JNIEnv *e;
+ jobject tmp_array = NULL;
+ jobject mifare_block = NULL;
+ struct nfc_jni_native_data *nat;
+ phNfc_sData_t *aid;
+ phNfc_sData_t *mifare_command;
+ struct nfc_jni_callback_data *pCallbackData;
+ int i=0;
+
+ LOG_CALLBACK("nfc_jni_transaction_callback", status);
+
+ nat = (struct nfc_jni_native_data *)context;
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ switch(evt_type)
+ {
+ case phLibNfc_eSE_EvtStartTransaction:
+ {
+ TRACE("> SE EVT_START_TRANSACTION");
+ if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN)
+ {
+ aid = &(evt_info->UiccEvtInfo.aid);
+
+ ALOGD("> AID DETECTED");
+
+ if(aid != NULL)
+ {
+ if (TRACE_ENABLED == 1) {
+ char aid_str[AID_MAXLEN * 2 + 1];
+ aid_str[0] = '\0';
+ for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) {
+ snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]);
+ }
+ ALOGD("> AID: %s", aid_str);
+ }
+ tmp_array = e->NewByteArray(aid->length);
+ if (tmp_array == NULL)
+ {
+ goto error;
+ }
+
+ e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ goto error;
+ }
+
+ TRACE("Notify Nfc Service");
+ /* Notify manager that a new event occurred on a SE */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ ALOGD("> NO AID DETECTED");
+ }
+ }break;
+
+ case phLibNfc_eSE_EvtApduReceived:
+ {
+ phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid);
+ TRACE("> SE EVT_APDU_RECEIVED");
+
+ if (apdu != NULL) {
+ TRACE(" APDU length=%d", apdu->length);
+ tmp_array = e->NewByteArray(apdu->length);
+ if (tmp_array == NULL) {
+ goto error;
+ }
+ e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer);
+ if (e->ExceptionCheck()) {
+ goto error;
+ }
+ } else {
+ TRACE(" APDU EMPTY");
+ }
+
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array);
+ }break;
+
+ case phLibNfc_eSE_EvtCardRemoval:
+ {
+ TRACE("> SE EVT_EMV_CARD_REMOVAL");
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval);
+ }break;
+
+ case phLibNfc_eSE_EvtMifareAccess:
+ {
+ TRACE("> SE EVT_MIFARE_ACCESS");
+ mifare_command = &(evt_info->UiccEvtInfo.aid);
+ TRACE("> MIFARE Block: %d",mifare_command->buffer[1]);
+ tmp_array = e->NewByteArray(2);
+ if (tmp_array == NULL)
+ {
+ goto error;
+ }
+
+ e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block);
+ }break;
+
+ case phLibNfc_eSE_EvtFieldOn:
+ {
+ TRACE("> SE EVT_FIELD_ON");
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated);
+ }break;
+
+ case phLibNfc_eSE_EvtFieldOff:
+ {
+ TRACE("> SE EVT_FIELD_OFF");
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated);
+ }break;
+
+ default:
+ {
+ TRACE("Unknown SE event");
+ }break;
+ }
+ }
+ else
+ {
+ ALOGE("SE transaction notification error");
+ goto error;
+ }
+
+ /* Function finished, now clean and return */
+ goto clean_and_return;
+
+ error:
+ /* In case of error, just discard the notification */
+ ALOGE("Failed to send SE transaction notification");
+ e->ExceptionClear();
+
+ clean_and_return:
+ if(tmp_array != NULL)
+ {
+ e->DeleteLocalRef(tmp_array);
+ }
+}
+
+/* Card Emulation callback */
+static void nfc_jni_CE_callback(void *context,
+ phLibNfc_eCE_EvtType_t evt_type, uint32_t handle,
+ NFCSTATUS status)
+{
+ JNIEnv *e;
+ jobject tmp_array = NULL;
+ jobject mifare_block = NULL;
+ struct nfc_jni_native_data *nat;
+ phNfc_sData_t *aid;
+ phNfc_sData_t *mifare_command;
+ int i=0;
+
+ LOG_CALLBACK("nfc_jni_CE_callback", status);
+ nat = (struct nfc_jni_native_data *)context;
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ switch(evt_type)
+ {
+ case phLibNfc_eCE_B_EvtActivated:
+ {
+ if(!device_connected_flag)
+ {
+ TRACE("> CE EVT B ACTIVATED");
+ /* Receive */
+ TRACE("phLibNfc_RemoteDev_CE_B_Receive()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_CE_B_Receive(nfc_jni_Discover_14443_4_PCD_callback,(void *)context);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_CE_B_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto error;
+ }
+ }
+ }break;
+ case phLibNfc_eCE_A_EvtActivated:
+ {
+ if(!device_connected_flag)
+ {
+ TRACE("> CE EVT A ACTIVATED");
+ /* Receive */
+ TRACE("phLibNfc_RemoteDev_CE_A_Receive()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_CE_A_Receive(nfc_jni_Discover_14443_4_PCD_callback,(void *)context);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_CE_A_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto error;
+ }
+ }
+ }break;
+ case phLibNfc_eCE_B_EvtDeActivated:
+ case phLibNfc_eCE_A_EvtDeActivated:
+ {
+ LOG_CALLBACK("nfc_jni_Discover_14443_4_PCD_callback: Target deselected", status);
+ if(!device_connected_flag || storedHandle!=handle)
+ {
+ //free handle memory
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo = (phLibNfc_sRemoteDevInformation_t *) handle;
+ phOsalNfc_FreeMemory(psRemoteDevInfo);
+ }
+ TRACE("> CE EVT A DEACTIVATED");
+ }break;
+ case phLibNfc_eCE_EvtFieldOn:
+ {
+ TRACE("> CE EVT_FIELD_ON");
+ }break;
+
+ case phLibNfc_eCE_EvtFieldOff:
+ {
+ TRACE("> CE EVT_FIELD_OFF");
+ }break;
+
+ default:
+ {
+ TRACE("Unknown CE event");
+ }break;
+ }
+ }
+ else
+ {
+ ALOGE("CE transaction notification error");
+ goto error;
+ }
+
+ /* Function finished, now clean and return */
+ goto clean_and_return;
+
+ error:
+ /* In case of error, just discard the notification */
+ ALOGE("Failed to send CE transaction notification");
+ e->ExceptionClear();
+
+ clean_and_return:
+ if(tmp_array != NULL)
+ {
+ e->DeleteLocalRef(tmp_array);
+ }
+}
+
+static void nfc_jni_se_set_mode_callback(void *pContext,
+ phLibNfc_Handle handle, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_se_set_mode_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/*
+ * NFCManager methods
+ */
+
+static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume)
+{
+ NFCSTATUS ret;
+ struct nfc_jni_callback_data cb_data;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+ /* Reset the PN544 ISO XCHG / sw watchdog timeouts */
+ nfc_jni_reset_timeout_values();
+
+ /* Reload the p2p modes */
+ nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator
+ nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target
+ nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE;
+
+ /* Reset device connected flag */
+ device_connected_flag = 0;
+
+ set_CE_A_mode(UNBLOCK_CE_CALLBACK, nat);
+ set_CE_B_mode(UNBLOCK_CE_CALLBACK, nat);
+
+ /* Start Polling loop */
+ TRACE("****** Start NFC Discovery ******");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG,
+ nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"",
+ nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret);
+
+ if(ret != NFCSTATUS_PENDING)
+ {
+ set_CE_A_mode(TURN_CE_OFF, nat);
+ set_CE_B_mode(TURN_CE_OFF, nat);
+ discoveryOn = FALSE;
+ emergency_recovery(nat);
+ goto clean_and_return;
+ }
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ set_CE_A_mode(TURN_CE_OFF, nat);
+ set_CE_B_mode(TURN_CE_OFF, nat);
+ discoveryOn = FALSE;
+ goto clean_and_return;
+ }
+
+ discoveryOn = TRUE;
+#ifndef CONFIG_CE_DEFAULT
+ if(turnCeAOn)
+ set_CE_A_mode(TURN_CE_ON, nat);
+ if(turnCeBOn)
+ set_CE_B_mode(TURN_CE_ON, nat);
+#else
+ set_CE_A_mode(TURN_CE_ON, nat);
+#endif
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+}
+
+static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat)
+{
+ phLibNfc_sADD_Cfg_t discovery_cfg;
+ NFCSTATUS ret;
+ struct nfc_jni_callback_data cb_data;
+
+ set_CE_A_mode(TURN_CE_OFF, nat);
+ set_CE_B_mode(TURN_CE_OFF, nat);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ discovery_cfg.PollDevInfo.PollEnabled = 0;
+ discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode;
+ discovery_cfg.NfcIP_Target_Mode = 0;
+ discovery_cfg.NfcIP_Tgt_Disable = TRUE;
+
+ /* Start Polling loop */
+ TRACE("****** Stop NFC Discovery ******");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"",
+ discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret);
+
+ if(ret != NFCSTATUS_PENDING)
+ {
+ emergency_recovery(nat);
+ }
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ discoveryOn = FALSE;
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+}
+
+static void set_CE_A_mode(uint8_t mode, struct nfc_jni_native_data *nat)
+{
+#if defined (HOST_EMULATION)
+ uint8_t unblocked = FALSE;
+ NFCSTATUS status;
+ struct nfc_jni_callback_data cb_data;
+
+ if(mode==INIT_CE)
+ {
+ ceAOn=FALSE;
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_A_14443_4_ConfigParams(TRUE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status == NFCSTATUS_PENDING)
+ {
+ sem_wait(&cb_data.sem);
+ }
+ TRACE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_A_14443_4_ConfigParams(FALSE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status == NFCSTATUS_PENDING)
+ {
+ sem_wait(&cb_data.sem);
+ }
+ ceAOn=FALSE;
+
+ if(ceAOn==TRUE || ceBOn==TRUE)
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfUnregister();
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+ else
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+
+ return;
+ }
+
+ if(mode==TURN_CE_ON || mode==TURN_CE_OFF)
+ turnCeAOn = FALSE; //reset flag
+
+ if(ceAOn==TRUE && mode==TURN_CE_ON)
+ return; //already on
+ if(ceAOn==FALSE && mode==TURN_CE_OFF)
+ return; //already off
+ if(ceAOn==FALSE && mode==UNBLOCK_CE_CALLBACK)
+ return; //can't block when it is already off
+
+ if(discoveryOn==FALSE && mode==TURN_CE_ON)
+ {
+ turnCeAOn = TRUE; //turn on when discovery turns on
+ return;
+ }
+
+ if(mode==TURN_CE_OFF || mode==UNBLOCK_CE_CALLBACK)
+ if(phLibNfc_Mgt_Unblock_Cb_CE_A_14443_4( )==NFCSTATUS_SUCCESS)
+ unblocked=TRUE;
+
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ if(mode==TURN_CE_OFF || (mode==UNBLOCK_CE_CALLBACK && unblocked==TRUE))
+ {
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_A_14443_4_ConfigParams(FALSE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ ceAOn=FALSE;
+ }
+
+ if(mode==TURN_CE_ON || (mode==UNBLOCK_CE_CALLBACK && unblocked==TRUE && discoveryOn==TRUE))
+ {
+ TRACE("phLibNfc_SE_SetMode()");
+ /* Set SE mode - Default */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault,
+ nfc_jni_se_set_mode_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ TRACE("phLibNfc_SE_SetMode returned 0x%02x", status);
+ if (status != NFCSTATUS_PENDING) {
+ ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if (sem_wait(&cb_data.sem)) {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_A_14443_4_ConfigParams(TRUE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ ceAOn=TRUE;
+ }
+
+clean_and_return:
+
+ if(ceAOn==TRUE || ceBOn==TRUE)
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfUnregister();
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+ else
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+
+#endif //HOST_EMULATION
+}
+
+static void set_CE_B_mode(uint8_t mode, struct nfc_jni_native_data *nat)
+{
+#if defined (HOST_EMULATION)
+ uint8_t unblocked = FALSE;
+ NFCSTATUS status;
+ struct nfc_jni_callback_data cb_data;
+
+ if(mode==INIT_CE)
+ {
+ ceBOn=FALSE;
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_B_14443_4_ConfigParams(TRUE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status == NFCSTATUS_PENDING)
+ {
+ sem_wait(&cb_data.sem);
+ }
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_B_14443_4_ConfigParams(FALSE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status == NFCSTATUS_PENDING)
+ {
+ sem_wait(&cb_data.sem);
+ }
+ ceBOn=FALSE;
+
+ if(ceAOn==TRUE || ceBOn==TRUE)
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfUnregister();
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+ else
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+
+ return;
+ }
+
+ if(mode==TURN_CE_ON || mode==TURN_CE_OFF)
+ turnCeBOn = FALSE; //reset flag
+
+ if(ceBOn==TRUE && mode==TURN_CE_ON)
+ return; //already on
+ if(ceBOn==FALSE && mode==TURN_CE_OFF)
+ return; //already off
+ if(ceBOn==FALSE && mode==UNBLOCK_CE_CALLBACK)
+ return; //can't block when it is already off
+
+ if(discoveryOn==FALSE && mode==TURN_CE_ON)
+ {
+ turnCeBOn = TRUE; //turn on when discovery turns on
+ return;
+ }
+
+ if(mode==TURN_CE_OFF || mode==UNBLOCK_CE_CALLBACK)
+ if(phLibNfc_Mgt_Unblock_Cb_CE_B_14443_4( )==NFCSTATUS_SUCCESS)
+ unblocked=TRUE;
+
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ if(mode==TURN_CE_OFF || (mode==UNBLOCK_CE_CALLBACK && unblocked==TRUE))
+ {
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_B_14443_4_ConfigParams(FALSE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ ceBOn=FALSE;
+ }
+
+ if(mode==TURN_CE_ON || (mode==UNBLOCK_CE_CALLBACK && unblocked==TRUE && discoveryOn==TRUE))
+ {
+ TRACE("phLibNfc_SE_SetMode()");
+ /* Set SE mode - Default */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault,
+ nfc_jni_se_set_mode_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ TRACE("phLibNfc_SE_SetMode returned 0x%02x", status);
+ if (status != NFCSTATUS_PENDING) {
+ ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if (sem_wait(&cb_data.sem)) {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetCE_B_14443_4_ConfigParams(TRUE,
+ nfc_jni_CEcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_SetCE_14443_4_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ ceBOn=TRUE;
+ }
+
+clean_and_return:
+
+ if(ceAOn==TRUE || ceBOn==TRUE)
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfUnregister();
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+ else
+ {
+ /* Register for the SE card emulation mode */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",status);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", status);
+ }
+
+#endif //HOST EMULATION
+}
+
+static void com_android_nfc_NfcManager_disableCE_A(JNIEnv *e, jobject o)
+{
+#ifndef CONFIG_CE_DEFAULT
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ set_CE_A_mode(TURN_CE_OFF, nat);
+ CONCURRENCY_UNLOCK();
+#endif
+ return;
+}
+
+static void com_android_nfc_NfcManager_enableCE_A(JNIEnv *e, jobject o)
+{
+#ifndef CONFIG_CE_DEFAULT
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ set_CE_A_mode(TURN_CE_ON, nat);
+ CONCURRENCY_UNLOCK();
+#endif
+ return;
+}
+
+static void com_android_nfc_NfcManager_disableCE_B(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ set_CE_B_mode(TURN_CE_OFF, nat);
+ CONCURRENCY_UNLOCK();
+ return;
+}
+
+static void com_android_nfc_NfcManager_enableCE_B(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ set_CE_B_mode(TURN_CE_ON, nat);
+ CONCURRENCY_UNLOCK();
+ return;
+}
+
+static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ nfc_jni_stop_discovery_locked(nat);
+
+ CONCURRENCY_UNLOCK();
+
+}
+
+static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Register callback for remote device notifications.
+ * Must re-register every time we turn on discovery, since other operations
+ * (such as opening the Secure Element) can change the remote device
+ * notification callback*/
+ REENTRANCE_LOCK();
+ ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n",
+ nat->registry_info.Jewel==TRUE?"J":"",
+ nat->registry_info.MifareUL==TRUE?"UL":"",
+ nat->registry_info.MifareStd==TRUE?"Mi":"",
+ nat->registry_info.Felica==TRUE?"F":"",
+ nat->registry_info.ISO14443_4A==TRUE?"4A":"",
+ nat->registry_info.ISO14443_4B==TRUE?"4B":"",
+ nat->registry_info.NFC==TRUE?"P2P":"",
+ nat->registry_info.ISO15693==TRUE?"R":"", ret);
+
+ nfc_jni_start_discovery_locked(nat, false);
+clean_and_return:
+ CONCURRENCY_UNLOCK();
+}
+
+static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) {
+ CONCURRENCY_LOCK();
+ nfc_jni_reset_timeout_values();
+ CONCURRENCY_UNLOCK();
+}
+
+static void setFelicaTimeout(jint timeout) {
+ // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms.
+ // It can be set to 0 to disable the timeout altogether, in which case we
+ // use the sw watchdog as a fallback.
+ if (timeout <= 255) {
+ phLibNfc_SetFelicaTimeout(timeout);
+ } else {
+ // Disable hw timeout, use sw watchdog for timeout
+ phLibNfc_SetFelicaTimeout(0);
+ phLibNfc_SetHciTimeout(timeout);
+ }
+
+}
+// Calculates ceiling log2 of value
+static unsigned int log2(int value) {
+ unsigned int ret = 0;
+ bool isPowerOf2 = ((value & (value - 1)) == 0);
+ while ( (value >> ret) > 1 ) ret++;
+ if (!isPowerOf2) ret++;
+ return ret;
+}
+
+// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X
+// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X
+//
+// We keep the constant part of the formula in a static; note the factor
+// 1000 off, which is due to the fact that the formula calculates seconds,
+// but this method gets milliseconds as an argument.
+static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0;
+
+static int calcTimeout(int timeout_in_ms) {
+ // timeout = (256 * 16 / 13560000) * 2 ^ X
+ // First find the first X for which timeout > requested timeout
+ return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor)));
+}
+
+static void setIsoDepTimeout(jint timeout) {
+ if (timeout <= 4900) {
+ int value = calcTimeout(timeout);
+ // Then re-compute the actual timeout based on X
+ double actual_timeout = nxp_nfc_timeout_factor * (1 << value);
+ // Set the sw watchdog a bit longer (The PN544 timeout is very accurate,
+ // but it will take some time to get back through the sw layers.
+ // 500 ms should be enough).
+ phLibNfc_SetHciTimeout(ceil(actual_timeout + 500));
+ value |= 0x10; // bit 4 to enable timeout
+ phLibNfc_SetIsoXchgTimeout(value);
+ }
+ else {
+ // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout
+ // must be disabled completely, to prevent the PN544 from aborting
+ // the transaction. We reuse the HCI sw watchdog to catch the timeout
+ // in that case.
+ phLibNfc_SetIsoXchgTimeout(0x00);
+ phLibNfc_SetHciTimeout(timeout);
+ }
+}
+
+static void setNfcATimeout(jint timeout) {
+ if (timeout <= 4900) {
+ int value = calcTimeout(timeout);
+ phLibNfc_SetMifareRawTimeout(value);
+ }
+ else {
+ // Disable mifare raw timeout, use HCI sw watchdog instead
+ phLibNfc_SetMifareRawTimeout(0x00);
+ phLibNfc_SetHciTimeout(timeout);
+ }
+}
+
+static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o,
+ jint tech, jint timeout) {
+ bool success = false;
+ CONCURRENCY_LOCK();
+ if (timeout <= 0) {
+ ALOGE("Timeout must be positive.");
+ return false;
+ } else {
+ switch (tech) {
+ case TARGET_TYPE_MIFARE_CLASSIC:
+ case TARGET_TYPE_MIFARE_UL:
+ // Intentional fall-through, Mifare UL, Classic
+ // transceive just uses raw 3A frames
+ case TARGET_TYPE_ISO14443_3A:
+ setNfcATimeout(timeout);
+ success = true;
+ break;
+ case TARGET_TYPE_ISO14443_4:
+ setIsoDepTimeout(timeout);
+ success = true;
+ break;
+ case TARGET_TYPE_FELICA:
+ setFelicaTimeout(timeout);
+ success = true;
+ break;
+ default:
+ ALOGW("doSetTimeout: Timeout not supported for tech %d", tech);
+ success = false;
+ }
+ }
+ CONCURRENCY_UNLOCK();
+ return success;
+}
+
+static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o,
+ jint tech) {
+ int timeout = -1;
+ CONCURRENCY_LOCK();
+ switch (tech) {
+ case TARGET_TYPE_MIFARE_CLASSIC:
+ case TARGET_TYPE_MIFARE_UL:
+ // Intentional fall-through, Mifare UL, Classic
+ // transceive just uses raw 3A frames
+ case TARGET_TYPE_ISO14443_3A:
+ timeout = phLibNfc_GetMifareRawTimeout();
+ if (timeout == 0) {
+ timeout = phLibNfc_GetHciTimeout();
+ } else {
+ // Timeout returned from libnfc needs conversion to ms
+ timeout = (nxp_nfc_timeout_factor * (1 << timeout));
+ }
+ break;
+ case TARGET_TYPE_ISO14443_4:
+ timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only
+ if (timeout == 0) {
+ timeout = phLibNfc_GetHciTimeout();
+ } else {
+ // Timeout returned from libnfc needs conversion to ms
+ timeout = (nxp_nfc_timeout_factor * (1 << timeout));
+ }
+ break;
+ case TARGET_TYPE_FELICA:
+ timeout = phLibNfc_GetFelicaTimeout();
+ if (timeout == 0) {
+ timeout = phLibNfc_GetHciTimeout();
+ } else {
+ // Felica timeout already in ms
+ }
+ break;
+ default:
+ ALOGW("doGetTimeout: Timeout not supported for tech %d", tech);
+ break;
+ }
+ CONCURRENCY_UNLOCK();
+ return timeout;
+}
+
+
+static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o)
+{
+ NFCSTATUS status;
+ struct nfc_jni_native_data *nat = NULL;
+ jclass cls;
+ jobject obj;
+ jfieldID f;
+
+ TRACE("****** Init Native Structure ******");
+
+ /* Initialize native structure */
+ nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data));
+ if(nat == NULL)
+ {
+ ALOGD("malloc of nfc_jni_native_data failed");
+ return FALSE;
+ }
+ memset(nat, 0, sizeof(*nat));
+ e->GetJavaVM(&(nat->vm));
+ nat->env_version = e->GetVersion();
+ nat->manager = e->NewGlobalRef(o);
+
+ cls = e->GetObjectClass(o);
+ f = e->GetFieldID(cls, "mNative", "I");
+ e->SetIntField(o, f, (jint)nat);
+
+ /* Initialize native cached references */
+ cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls,
+ "notifyNdefMessageListeners","(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
+
+ cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls,
+ "notifyTransactionListeners", "([B)V");
+
+ cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls,
+ "notifyLlcpLinkActivation","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
+
+ cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls,
+ "notifyLlcpLinkDeactivated","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
+
+ cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls,
+ "notifyTargetDeselected","()V");
+
+ cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls,
+ "notifySeFieldActivated", "()V");
+
+ cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls,
+ "notifySeFieldDeactivated", "()V");
+
+ cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls,
+ "notifySeApduReceived", "([B)V");
+
+ cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls,
+ "notifySeMifareAccess", "([B)V");
+
+ cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls,
+ "notifySeEmvCardRemoval", "()V");
+
+ if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeNfcTag",&(nat->cached_NfcTag)) == -1)
+ {
+ ALOGD("Native Structure initialization failed");
+ return FALSE;
+ }
+
+ if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1)
+ {
+ ALOGD("Native Structure initialization failed");
+ return FALSE;
+ }
+ TRACE("****** Init Native Structure OK ******");
+ return TRUE;
+
+}
+
+/* Init/Deinit method */
+static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat = NULL;
+ int init_result = JNI_FALSE;
+#ifdef TNFC_EMULATOR_ONLY
+ char value[PROPERTY_VALUE_MAX];
+#endif
+ jboolean result;
+
+ CONCURRENCY_LOCK();
+
+#ifdef TNFC_EMULATOR_ONLY
+ if (!property_get("ro.kernel.qemu", value, 0))
+ {
+ ALOGE("NFC Initialization failed: not running in an emulator\n");
+ goto clean_and_return;
+ }
+#endif
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ nat->seId = SMX_SECURE_ELEMENT_ID;
+
+ nat->lto = 150; // LLCP_LTO
+ nat->miu = 128; // LLCP_MIU
+ // WKS indicates well-known services; 1 << sap for each supported SAP.
+ // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4)
+ nat->wks = 0x13; // LLCP_WKS
+ nat->opt = 0; // LLCP_OPT
+ nat->p2p_initiator_modes = phNfc_eP2P_ALL;
+ nat->p2p_target_modes = 0x0E; // All passive except 106, active
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE;
+
+ nat->registry_info.MifareUL = TRUE;
+ nat->registry_info.MifareStd = TRUE;
+ nat->registry_info.ISO14443_4A = TRUE;
+ nat->registry_info.ISO14443_4B = TRUE;
+ nat->registry_info.Jewel = TRUE;
+ nat->registry_info.Felica = TRUE;
+ nat->registry_info.NFC = TRUE;
+ nat->registry_info.ISO15693 = TRUE;
+
+ exported_nat = nat;
+
+ /* Perform the initialization */
+ init_result = nfc_jni_initialize(nat);
+
+ if(init_result==TRUE)
+ {
+ set_CE_A_mode(INIT_CE, nat);
+ set_CE_B_mode(INIT_CE, nat);
+ }
+
+clean_and_return:
+ CONCURRENCY_UNLOCK();
+
+ /* Convert the result and return */
+ return (init_result==TRUE)?JNI_TRUE:JNI_FALSE;
+}
+
+static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o)
+{
+ struct timespec ts;
+ NFCSTATUS status;
+ int result = JNI_FALSE;
+ struct nfc_jni_native_data *nat;
+ int bStackReset = FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Clear previous configuration */
+ memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t));
+ memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t));
+
+ /* Create the local semaphore */
+ if (nfc_cb_data_init(&cb_data, NULL))
+ {
+ TRACE("phLibNfc_Mgt_DeInitialize()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status == NFCSTATUS_PENDING)
+ {
+ TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 5;
+
+ /* Wait for callback response */
+ if(sem_timedwait(&cb_data.sem, &ts) == -1)
+ {
+ ALOGW("Operation timed out");
+ bStackReset = TRUE;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("Failed to deinit the stack");
+ bStackReset = TRUE;
+ }
+ }
+ else
+ {
+ TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ bStackReset = TRUE;
+ }
+ nfc_cb_data_deinit(&cb_data);
+ }
+ else
+ {
+ ALOGE("Failed to create semaphore (errno=0x%08x)", errno);
+ bStackReset = TRUE;
+ }
+
+ kill_client(nat);
+
+ if(bStackReset == TRUE)
+ {
+ /* Complete deinit. failed, try hard restart of NFC */
+ ALOGW("Reseting stack...");
+ emergency_recovery(nat);
+ }
+
+ result = nfc_jni_unconfigure_driver(nat);
+
+ TRACE("NFC Deinitialized");
+
+ CONCURRENCY_UNLOCK();
+
+ return TRUE;
+}
+
+/* Secure Element methods */
+static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ jintArray list= NULL;
+ phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE];
+ uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE;
+
+ TRACE("****** Get Secure Element List ******");
+
+ TRACE("phLibNfc_SE_GetSecureElementList()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count);
+ REENTRANCE_UNLOCK();
+ if (ret != NFCSTATUS_SUCCESS) {
+ ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret,
+ nfc_jni_get_status_name(ret));
+ return list;
+ }
+ TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret,
+ nfc_jni_get_status_name(ret));
+
+ TRACE("Nb SE: %d", se_count);
+ list =e->NewIntArray(se_count);
+ for (i = 0; i < se_count; i++) {
+ if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected");
+ ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement);
+ } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected");
+ ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement);
+ }
+ e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement);
+ }
+
+ e->DeleteLocalRef(list);
+
+ return list;
+}
+
+static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ struct nfc_jni_native_data *nat;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ set_CE_A_mode(TURN_CE_OFF, nat);
+ set_CE_B_mode(TURN_CE_OFF, nat);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL)) {
+ goto clean_and_return;
+ }
+
+ TRACE("****** Select Secure Element ******");
+
+ TRACE("phLibNfc_SE_SetMode()");
+ /* Set SE mode - Virtual */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (ret != NFCSTATUS_PENDING) {
+ ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_SetMode() 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;
+ }
+
+ clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+}
+
+static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ struct nfc_jni_native_data *nat;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ set_CE_A_mode(UNBLOCK_CE_CALLBACK, nat);
+ set_CE_B_mode(UNBLOCK_CE_CALLBACK, nat);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL)) {
+ goto clean_and_return;
+ }
+
+ TRACE("****** Deselect Secure Element ******");
+
+ TRACE("phLibNfc_SE_SetMode()");
+ /* Set SE mode - Default */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault,
+ nfc_jni_se_set_mode_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret);
+ if (ret != NFCSTATUS_PENDING) {
+ ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_SetMode() 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;
+ }
+
+ clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+}
+
+/* Llcp methods */
+
+static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ bool freeData = false;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_native_data *nat;
+ struct nfc_jni_callback_data *cb_data;
+
+
+ CONCURRENCY_LOCK();
+
+ /* Memory allocation for cb_data
+ * This is on the heap because it is used by libnfc
+ * even after this call has succesfully finished. It is only freed
+ * upon link closure in nfc_jni_llcp_linkStatus_callback.
+ */
+ cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data));
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(cb_data, (void*)nat))
+ {
+ goto clean_and_return;
+ }
+
+ /* Check LLCP compliancy */
+ TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle,
+ nfc_jni_checkLlcp_callback,
+ nfc_jni_llcp_linkStatus_callback,
+ (void*)cb_data);
+ REENTRANCE_UNLOCK();
+ /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol
+ * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */
+ if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ freeData = true;
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_CheckLlcp() 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)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(cb_data);
+ if (freeData) {
+ free(cb_data);
+ }
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Activate(hLlcpHandle);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return JNI_TRUE;
+ }
+ else
+ {
+ ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return JNI_FALSE;
+ }
+}
+
+
+
+static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o,
+ jint nSap, jstring sn)
+{
+ NFCSTATUS ret;
+ jobject connectionlessSocket = NULL;
+ phLibNfc_Handle hLlcpSocket;
+ struct nfc_jni_native_data *nat;
+ phNfc_sData_t sWorkingBuffer = {NULL, 0};
+ phNfc_sData_t serviceName = {NULL, 0};
+ phLibNfc_Llcp_sLinkParameters_t sParams;
+ jclass clsNativeConnectionlessSocket;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Allocate Working buffer length */
+ phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams);
+ sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP
+ sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length);
+
+ /* Create socket */
+ TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess,
+ NULL,
+ &sWorkingBuffer,
+ &hLlcpSocket,
+ nfc_jni_llcp_transport_socket_err_callback,
+ (void*)nat);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Service socket */
+ if (sn == NULL) {
+ serviceName.buffer = NULL;
+ serviceName.length = 0;
+ } else {
+ serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
+ serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
+ }
+
+ /* Bind socket */
+ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ /* Close socket created */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+
+ /* Create new NativeLlcpConnectionlessSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1)
+ {
+ goto error;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I");
+ e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket);
+ TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket);
+
+ /* Set the miu link of the connectionless socket */
+ f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I");
+ e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT);
+ TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT);
+
+ /* Set socket SAP */
+ f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I");
+ e->SetIntField(connectionlessSocket, f,(jint)nSap);
+ TRACE("Connectionless socket SAP = %d\n",nSap);
+
+ return connectionlessSocket;
+error:
+ if (serviceName.buffer != NULL) {
+ e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
+ }
+
+ if (sWorkingBuffer.buffer != NULL) {
+ free(sWorkingBuffer.buffer);
+ }
+
+ return NULL;
+}
+
+static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ phLibNfc_Llcp_sSocketOptions_t sOptions;
+ phNfc_sData_t sWorkingBuffer;
+ phNfc_sData_t serviceName;
+ struct nfc_jni_native_data *nat;
+ jobject serviceSocket = NULL;
+ jclass clsNativeLlcpServiceSocket;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Set Connection Oriented socket options */
+ sOptions.miu = miu;
+ sOptions.rw = rw;
+
+ /* Allocate Working buffer length */
+ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
+ sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length);
+
+
+ /* Create socket */
+ TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented,
+ &sOptions,
+ &sWorkingBuffer,
+ &hLlcpSocket,
+ nfc_jni_llcp_transport_socket_err_callback,
+ (void*)nat);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ lastErrorStatus = ret;
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Service socket */
+ if (sn == NULL) {
+ serviceName.buffer = NULL;
+ serviceName.length = 0;
+ } else {
+ serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
+ serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
+ }
+
+ /* Bind socket */
+ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ /* Close socket created */
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Listen( hLlcpSocket,
+ nfc_jni_llcp_transport_listen_socket_callback,
+ (void*)hLlcpSocket);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ lastErrorStatus = ret;
+ /* Close created socket */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Create new NativeLlcpServiceSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpServiceSocket",&(serviceSocket)) == -1)
+ {
+ ALOGE("Llcp Socket object creation error");
+ goto error;
+ }
+
+ /* Get NativeLlcpServiceSocket class object */
+ clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Llcp Socket get object class error");
+ goto error;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I");
+ e->SetIntField(serviceSocket, f,(jint)hLlcpSocket);
+ TRACE("Service socket Handle = %02x\n",hLlcpSocket);
+
+ /* Set socket linear buffer length */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I");
+ e->SetIntField(serviceSocket, f,(jint)linearBufferLength);
+ TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength);
+
+ /* Set socket MIU */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I");
+ e->SetIntField(serviceSocket, f,(jint)miu);
+ TRACE("Service socket MIU = %d\n",miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I");
+ e->SetIntField(serviceSocket, f,(jint)rw);
+ TRACE("Service socket RW = %d\n",rw);
+
+ return serviceSocket;
+error:
+ if (serviceName.buffer != NULL) {
+ e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
+ }
+ return NULL;
+}
+
+static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength)
+{
+ jobject clientSocket = NULL;
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ phLibNfc_Llcp_sSocketOptions_t sOptions;
+ phNfc_sData_t sWorkingBuffer;
+ struct nfc_jni_native_data *nat;
+ jclass clsNativeLlcpSocket;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Set Connection Oriented socket options */
+ sOptions.miu = miu;
+ sOptions.rw = rw;
+
+ /* Allocate Working buffer length */
+ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
+ sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length);
+
+ /* Create socket */
+ TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented,
+ &sOptions,
+ &sWorkingBuffer,
+ &hLlcpSocket,
+ nfc_jni_llcp_transport_socket_err_callback,
+ (void*)nat);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ lastErrorStatus = ret;
+ return NULL;
+ }
+ TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Create new NativeLlcpSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1)
+ {
+ ALOGE("Llcp socket object creation error");
+ return NULL;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsNativeLlcpSocket = e->GetObjectClass(clientSocket);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Get class object error");
+ return NULL;
+ }
+
+ /* Test if an SAP number is present */
+ if(nSap != 0)
+ {
+ /* Bind socket */
+ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ /* Close socket created */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ return NULL;
+ }
+ TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Set socket SAP */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I");
+ e->SetIntField(clientSocket, f,(jint)nSap);
+ TRACE("socket SAP = %d\n",nSap);
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField(clientSocket, f,(jint)hLlcpSocket);
+ TRACE("socket Handle = %02x\n",hLlcpSocket);
+
+ /* Set socket MIU */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField(clientSocket, f,(jint)miu);
+ TRACE("socket MIU = %d\n",miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField(clientSocket, f,(jint)rw);
+ TRACE("socket RW = %d\n",rw);
+
+
+ return clientSocket;
+}
+
+static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o)
+{
+ TRACE("Last Error Status = 0x%02x",lastErrorStatus);
+
+ if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL)
+ {
+ return ERROR_BUFFER_TOO_SMALL;
+ }
+ else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES)
+ {
+ return ERROR_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ return lastErrorStatus;
+ }
+}
+
+static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o)
+{
+ emergency_recovery(NULL);
+}
+
+static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o,
+ jint modes)
+{
+ ALOGE("Setting init modes to %x", modes);
+ struct nfc_jni_native_data *nat = NULL;
+ nat = nfc_jni_get_nat(e, o);
+ nat->p2p_initiator_modes = modes;
+}
+
+static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o,
+ jint modes)
+{
+ ALOGE("Setting target modes to %x", modes);
+ struct nfc_jni_native_data *nat = NULL;
+ nat = nfc_jni_get_nat(e, o);
+ nat->p2p_target_modes = modes;
+}
+
+static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) {
+ bool result = FALSE;
+ int load_result;
+ bool wasDisabled = FALSE;
+ uint8_t OutputBuffer[1];
+ uint8_t InputBuffer[1];
+ NFCSTATUS status = NFCSTATUS_FAILED;
+ struct nfc_jni_callback_data cb_data;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ if (takeLock)
+ {
+ CONCURRENCY_LOCK();
+ }
+
+ /* Initialize Driver */
+ if(!driverConfigured)
+ {
+ result = nfc_jni_configure_driver(nat);
+ wasDisabled = TRUE;
+ }
+ TRACE("com_android_nfc_NfcManager_doDownload()");
+
+ TRACE("Go in Download Mode");
+ phLibNfc_Download_Mode();
+
+ TRACE("Load new Firmware Image");
+ load_result = phLibNfc_Load_Firmware_Image();
+ if(load_result != 0)
+ {
+ TRACE("Load new Firmware Image - status = %d",load_result);
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ // Download
+ gInputParam.buffer = InputBuffer;
+ gInputParam.length = 0x01;
+ gOutputParam.buffer = OutputBuffer;
+ gOutputParam.length = 0x01;
+
+ ALOGD("Download new Firmware");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ result = FALSE;
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we
+ try to download an old-style firmware on top of a new-style
+ firmware. Hence, this is expected behavior, and not an
+ error condition. */
+ if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED)
+ {
+ TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED)
+ {
+ ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip.");
+ }
+
+ /*Download is successful*/
+ result = TRUE;
+clean_and_return:
+ TRACE("phLibNfc_HW_Reset()");
+ phLibNfc_HW_Reset();
+ /* Deinitialize Driver */
+ if(wasDisabled)
+ {
+ result = nfc_jni_unconfigure_driver(nat);
+ }
+ if (takeLock)
+ {
+ CONCURRENCY_UNLOCK();
+ }
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat = NULL;
+ nat = nfc_jni_get_nat(e, o);
+ return performDownload(nat, true);
+}
+
+static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o)
+{
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count);
+ return e->NewStringUTF(buffer);
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doDownload", "()Z",
+ (void *)com_android_nfc_NfcManager_doDownload},
+
+ {"initializeNativeStructure", "()Z",
+ (void *)com_android_nfc_NfcManager_init_native_struc},
+
+ {"doInitialize", "()Z",
+ (void *)com_android_nfc_NfcManager_initialize},
+
+ {"doDeinitialize", "()Z",
+ (void *)com_android_nfc_NfcManager_deinitialize},
+
+ {"enableDiscovery", "()V",
+ (void *)com_android_nfc_NfcManager_enableDiscovery},
+
+ {"doGetSecureElementList", "()[I",
+ (void *)com_android_nfc_NfcManager_doGetSecureElementList},
+
+ {"doSelectSecureElement", "()V",
+ (void *)com_android_nfc_NfcManager_doSelectSecureElement},
+
+ {"doDeselectSecureElement", "()V",
+ (void *)com_android_nfc_NfcManager_doDeselectSecureElement},
+
+ {"doCheckLlcp", "()Z",
+ (void *)com_android_nfc_NfcManager_doCheckLlcp},
+
+ {"doActivateLlcp", "()Z",
+ (void *)com_android_nfc_NfcManager_doActivateLlcp},
+
+ {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;",
+ (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket},
+
+ {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;",
+ (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket},
+
+ {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
+ (void *)com_android_nfc_NfcManager_doCreateLlcpSocket},
+
+ {"doGetLastError", "()I",
+ (void *)com_android_nfc_NfcManager_doGetLastError},
+
+ {"disableCE_A", "()V",
+ (void *)com_android_nfc_NfcManager_disableCE_A},
+
+ {"enableCE_A", "()V",
+ (void *)com_android_nfc_NfcManager_enableCE_A},
+
+ {"enableCE_B", "()V",
+ (void *)com_android_nfc_NfcManager_enableCE_B},
+
+ {"disableCE_B", "()V",
+ (void *)com_android_nfc_NfcManager_disableCE_B},
+
+ {"disableDiscovery", "()V",
+ (void *)com_android_nfc_NfcManager_disableDiscovery},
+
+ {"doSetTimeout", "(II)Z",
+ (void *)com_android_nfc_NfcManager_doSetTimeout},
+
+ {"doGetTimeout", "(I)I",
+ (void *)com_android_nfc_NfcManager_doGetTimeout},
+
+ {"doResetTimeouts", "()V",
+ (void *)com_android_nfc_NfcManager_doResetTimeouts},
+
+ {"doAbort", "()V",
+ (void *)com_android_nfc_NfcManager_doAbort},
+
+ {"doSetP2pInitiatorModes","(I)V",
+ (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes},
+
+ {"doSetP2pTargetModes","(I)V",
+ (void *)com_android_nfc_NfcManager_doSetP2pTargetModes},
+
+ {"doDump", "()Ljava/lang/String;",
+ (void *)com_android_nfc_NfcManager_doDump},
+};
+
+
+int register_com_android_nfc_NativeNfcManager(JNIEnv *e)
+{
+ nfc_jni_native_monitor_t *nfc_jni_native_monitor;
+
+ nfc_jni_native_monitor = nfc_jni_init_monitor();
+ if(nfc_jni_native_monitor == NULL)
+ {
+ ALOGE("NFC Manager cannot recover native monitor %x\n", errno);
+ return -1;
+ }
+
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/dhimpl/NativeNfcManager",
+ gMethods, NELEM(gMethods));
+}
+
+} /* namespace android */