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