diff options
Diffstat (limited to 'nxp')
20 files changed, 8755 insertions, 0 deletions
diff --git a/nxp/Android.mk b/nxp/Android.mk new file mode 100644 index 0000000..34f4385 --- /dev/null +++ b/nxp/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH:= $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/nxp/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/nxp/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * 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 <stdlib.h> + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "<init>", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h new file mode 100644 index 0000000..a44bcf0 --- /dev/null +++ b/nxp/jni/com_android_nfc.h @@ -0,0 +1,259 @@ +/* + * 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. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include <JNIHelp.h> +#include <jni.h> + +#include <pthread.h> +#include <sys/queue.h> + +extern "C" { +#include <phNfcStatus.h> +#include <phNfcTypes.h> +#include <phNfcIoctlCode.h> +#include <phLibNfc.h> +#include <phDal4Nfc_messageQueueLib.h> +#include <phFriNfc_NdefMap.h> +#include <cutils/log.h> +#include <com_android_nfc_list.h> +#include <semaphore.h> + +} +#include <cutils/properties.h> // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#else + #define LOG_CALLBACK(...) + #define TRACE(...) +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * 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 <semaphore.h> +#include <errno.h> + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * 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 <semaphore.h> +#include <errno.h> + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * 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 <semaphore.h> +#include <errno.h> + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..704ee6a --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2622 @@ +/* + * 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 + +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 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_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +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; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== 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_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 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) + { + 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); + } +} + +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; + + /* 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) + { + 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); + goto clean_and_return; + } + +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; + + /* 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; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +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/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/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/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/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); + +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); + + /* 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); + + /* 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/nxp/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/nxp/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/nxp/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/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"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/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * 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 <semaphore.h> + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; i<uNofRemoteDev; i++) { + // Always open the phNfc_eISO14443_A_PICC protocol + TRACE("Protocol %d handle=%x type=%d", i, psRemoteDevList[i].hTargetDev, + psRemoteDevList[i].psRemoteDevInfo->RemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i<No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) + { + TRACE("> SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * 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 <semaphore.h> +#include <errno.h> + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) 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); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) 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); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, 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; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() 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; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() 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); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() 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; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() 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; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() 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; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * 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 <semaphore.h> +#include <errno.h> + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;i<sGeneralBytes.length;i++) + { + TRACE("0x%02x ", sGeneralBytes.buffer[i]); + } + + generalBytes = e->NewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * 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 <com_android_nfc_list.h> +#include <com_android_nfc.h> +#include <pthread.h> +#include <errno.h> +#include <cutils/log.h> + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include <pthread.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..f969627 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eddde94 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} |