summaryrefslogtreecommitdiffstats
path: root/nxp
diff options
context:
space:
mode:
authorMartijn Coenen <maco@google.com>2012-07-20 15:09:37 -0400
committerMartijn Coenen <maco@google.com>2012-08-01 12:34:20 -0700
commitc2b3f02b1217c761d5247c3cda9444f0418b51cb (patch)
tree2e0eee4e19db19cfa525fbea5ef51bfa0b49279f /nxp
parente926ef2bdf7a2e77bac3582b2e5b7413d1e080c4 (diff)
downloadpackages_apps_nfc-c2b3f02b1217c761d5247c3cda9444f0418b51cb.zip
packages_apps_nfc-c2b3f02b1217c761d5247c3cda9444f0418b51cb.tar.gz
packages_apps_nfc-c2b3f02b1217c761d5247c3cda9444f0418b51cb.tar.bz2
Move NXP JNI and DeviceHost implementation into separate dir. (DO NOT MERGE)
Preparation for the new NCI stack. The idea is to build either the NXP or the NCI stack, triggered by a makefile switch. To that end, move the DeviceHost and JNI implementations in their own directory, so we can build them only if needed. Change-Id: Ibb6aeb11f0bb887e153fd457860b1ad0e39e7933
Diffstat (limited to 'nxp')
-rw-r--r--nxp/jni/Android.mk35
-rw-r--r--nxp/jni/com_android_nfc.cpp564
-rw-r--r--nxp/jni/com_android_nfc.h259
-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
-rw-r--r--nxp/jni/com_android_nfc_NativeNfcManager.cpp2622
-rwxr-xr-xnxp/jni/com_android_nfc_NativeNfcSecureElement.cpp770
-rw-r--r--nxp/jni/com_android_nfc_NativeNfcTag.cpp1255
-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.java373
-rwxr-xr-xnxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java67
-rwxr-xr-xnxp/src/com/android/nfc/dhimpl/NativeNfcTag.java803
-rwxr-xr-xnxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java77
19 files changed, 8752 insertions, 0 deletions
diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk
new file mode 100644
index 0000000..8ae792a
--- /dev/null
+++ b/nxp/jni/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+
+
+LOCAL_SRC_FILES:= \
+ com_android_nfc_NativeLlcpConnectionlessSocket.cpp \
+ com_android_nfc_NativeLlcpServiceSocket.cpp \
+ com_android_nfc_NativeLlcpSocket.cpp \
+ com_android_nfc_NativeNfcManager.cpp \
+ com_android_nfc_NativeNfcTag.cpp \
+ com_android_nfc_NativeP2pDevice.cpp \
+ com_android_nfc_NativeNfcSecureElement.cpp \
+ com_android_nfc_list.cpp \
+ com_android_nfc.cpp
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ external/libnfc-nxp/src \
+ external/libnfc-nxp/inc
+
+LOCAL_SHARED_LIBRARIES := \
+ libnativehelper \
+ libcutils \
+ libutils \
+ libnfc \
+ libhardware
+
+#LOCAL_CFLAGS += -O0 -g
+
+LOCAL_MODULE := libnfc_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp
new file mode 100644
index 0000000..d794d6e
--- /dev/null
+++ b/nxp/jni/com_android_nfc.cpp
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "errno.h"
+#include "com_android_nfc.h"
+#include "com_android_nfc_list.h"
+#include "phLibNfcStatus.h"
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM *jvm, void *reserved)
+{
+ JNIEnv *e;
+
+ ALOGD("NFC Service : loading JNI\n");
+
+ // Check JNI version
+ if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6))
+ return JNI_ERR;
+
+ android::vm = jvm;
+
+ if (android::register_com_android_nfc_NativeNfcManager(e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeNfcTag(e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeP2pDevice(e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1)
+ return JNI_ERR;
+
+ return JNI_VERSION_1_6;
+}
+
+namespace android {
+
+extern struct nfc_jni_native_data *exported_nat;
+
+JavaVM *vm;
+
+/*
+ * JNI Utils
+ */
+JNIEnv *nfc_get_env()
+{
+ JNIEnv *e;
+ if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("Current thread is not attached to VM");
+ phLibNfc_Mgt_Recovery();
+ abort();
+ }
+ return e;
+}
+
+bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext)
+{
+ /* Create semaphore */
+ if(sem_init(&pCallbackData->sem, 0, 0) == -1)
+ {
+ ALOGE("Semaphore creation failed (errno=0x%08x)", errno);
+ return false;
+ }
+
+ /* Set default status value */
+ pCallbackData->status = NFCSTATUS_FAILED;
+
+ /* Copy the context */
+ pCallbackData->pContext = pContext;
+
+ /* Add to active semaphore list */
+ if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData))
+ {
+ ALOGE("Failed to add the semaphore to the list");
+ }
+
+ return true;
+}
+
+void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData)
+{
+ /* Destroy semaphore */
+ if (sem_destroy(&pCallbackData->sem))
+ {
+ ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno);
+ }
+
+ /* Remove from active semaphore list */
+ if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData))
+ {
+ ALOGE("Failed to remove semaphore from the list");
+ }
+
+}
+
+void nfc_cb_data_releaseAll()
+{
+ nfc_jni_callback_data* pCallbackData;
+
+ while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData))
+ {
+ pCallbackData->status = NFCSTATUS_FAILED;
+ sem_post(&pCallbackData->sem);
+ }
+}
+
+int nfc_jni_cache_object(JNIEnv *e, const char *clsname,
+ jobject *cached_obj)
+{
+ jclass cls;
+ jobject obj;
+ jmethodID ctor;
+
+ cls = e->FindClass(clsname);
+ if(cls == NULL)
+ {
+ return -1;
+ ALOGD("Find class error\n");
+ }
+
+
+ ctor = e->GetMethodID(cls, "<init>", "()V");
+
+ obj = e->NewObject(cls, ctor);
+ if(obj == NULL)
+ {
+ return -1;
+ ALOGD("Create object error\n");
+ }
+
+ *cached_obj = e->NewGlobalRef(obj);
+ if(*cached_obj == NULL)
+ {
+ e->DeleteLocalRef(obj);
+ ALOGD("Global ref error\n");
+ return -1;
+ }
+
+ e->DeleteLocalRef(obj);
+
+ return 0;
+}
+
+
+struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mNative", "I");
+ return (struct nfc_jni_native_data*)e->GetIntField(o, f);
+}
+
+struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e)
+{
+ return exported_nat;
+}
+
+static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL;
+
+nfc_jni_native_monitor_t* nfc_jni_init_monitor(void)
+{
+
+ pthread_mutexattr_t recursive_attr;
+
+ pthread_mutexattr_init(&recursive_attr);
+ pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP);
+
+ if(nfc_jni_native_monitor == NULL)
+ {
+ nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t));
+ }
+
+ if(nfc_jni_native_monitor != NULL)
+ {
+ memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t));
+
+ if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1)
+ {
+ ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno);
+ return NULL;
+ }
+
+ if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1)
+ {
+ ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno);
+ return NULL;
+ }
+
+ if(!listInit(&nfc_jni_native_monitor->sem_list))
+ {
+ ALOGE("NFC Manager Semaphore List creation failed");
+ return NULL;
+ }
+
+ LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head);
+
+ if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1)
+ {
+ ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno);
+ return NULL;
+ }
+
+ if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1)
+ {
+ ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno);
+ return NULL;
+ }
+
+}
+
+ return nfc_jni_native_monitor;
+}
+
+nfc_jni_native_monitor_t* nfc_jni_get_monitor(void)
+{
+ return nfc_jni_native_monitor;
+}
+
+
+phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mHandle", "I");
+
+ return e->GetIntField(o, f);
+}
+
+jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mMode", "S");
+
+ return e->GetShortField(o, f);
+}
+
+
+int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o)
+{
+
+ jclass c;
+ jfieldID f;
+
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mConnectedTechIndex", "I");
+
+ return e->GetIntField(o, f);
+
+}
+
+jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+ int connectedTech = -1;
+
+ int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
+ jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o);
+
+ if ((connectedTechIndex != -1) && (techTypes != NULL) &&
+ (connectedTechIndex < e->GetArrayLength(techTypes))) {
+ jint* technologies = e->GetIntArrayElements(techTypes, 0);
+ if (technologies != NULL) {
+ connectedTech = technologies[connectedTechIndex];
+ e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT);
+ }
+ }
+
+ return connectedTech;
+
+}
+
+jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+ jint connectedLibNfcType = -1;
+
+ int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mTechLibNfcTypes", "[I");
+ jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f);
+
+ if ((connectedTechIndex != -1) && (libNfcTypes != NULL) &&
+ (connectedTechIndex < e->GetArrayLength(libNfcTypes))) {
+ jint* types = e->GetIntArrayElements(libNfcTypes, 0);
+ if (types != NULL) {
+ connectedLibNfcType = types[connectedTechIndex];
+ e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT);
+ }
+ }
+ return connectedLibNfcType;
+
+}
+
+phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mConnectedHandle", "I");
+
+ return e->GetIntField(o, f);
+}
+
+phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mHandle", "I");
+
+ return e->GetIntField(o, f);
+}
+
+jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o)
+{
+ jclass c;
+ jfieldID f;
+ jintArray techtypes;
+
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mTechList","[I");
+
+ /* Read the techtypes */
+ techtypes = (jintArray) e->GetObjectField(o, f);
+
+ return techtypes;
+}
+
+
+
+//Display status code
+const char* nfc_jni_get_status_name(NFCSTATUS status)
+{
+ #define STATUS_ENTRY(status) { status, #status }
+
+ struct status_entry {
+ NFCSTATUS code;
+ const char *name;
+ };
+
+ const struct status_entry sNameTable[] = {
+ STATUS_ENTRY(NFCSTATUS_SUCCESS),
+ STATUS_ENTRY(NFCSTATUS_FAILED),
+ STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER),
+ STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES),
+ STATUS_ENTRY(NFCSTATUS_TARGET_LOST),
+ STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE),
+ STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS),
+ STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED),
+ STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED),
+ STATUS_ENTRY(NFCSTATUS_SHUTDOWN),
+ STATUS_ENTRY(NFCSTATUS_ABORTED),
+ STATUS_ENTRY(NFCSTATUS_REJECTED ),
+ STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED),
+ STATUS_ENTRY(NFCSTATUS_PENDING),
+ STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL),
+ STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED),
+ STATUS_ENTRY(NFCSTATUS_BUSY),
+ STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED),
+ STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS),
+ STATUS_ENTRY(NFCSTATUS_DESELECTED),
+ STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE),
+ STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION),
+ STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT),
+ STATUS_ENTRY(NFCSTATUS_RF_ERROR),
+ STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR),
+ STATUS_ENTRY(NFCSTATUS_INVALID_STATE),
+ STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED),
+ STATUS_ENTRY(NFCSTATUS_RELEASED),
+ STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED),
+ STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE),
+ STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED),
+ STATUS_ENTRY(NFCSTATUS_READ_FAILED),
+ STATUS_ENTRY(NFCSTATUS_WRITE_FAILED),
+ STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT),
+ STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED),
+ STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH),
+ STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT),
+ STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE),
+ STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR),
+ };
+
+ int i = sizeof(sNameTable)/sizeof(status_entry);
+
+ while(i>0)
+ {
+ i--;
+ if (sNameTable[i].code == PHNFCSTATUS(status))
+ {
+ return sNameTable[i].name;
+ }
+ }
+
+ return "UNKNOWN";
+}
+
+int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize,
+ int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) {
+ bool found = false;
+ for (int i = 0; i < listSize; i++) {
+ if (techList[i] == techToAdd) {
+ found = true;
+ break;
+ }
+ }
+ if (!found && listSize < maxListSize) {
+ techList[listSize] = techToAdd;
+ handleList[listSize] = handleToAdd;
+ typeList[listSize] = typeToAdd;
+ return listSize + 1;
+ }
+ else {
+ return listSize;
+ }
+}
+
+
+#define MAX_NUM_TECHNOLOGIES 32
+
+/*
+ * Utility to get a technology tree and a corresponding handle list from a detected tag.
+ */
+void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList,
+ uint8_t count, jintArray* techList, jintArray* handleList,
+ jintArray* libnfcTypeList)
+{
+ int technologies[MAX_NUM_TECHNOLOGIES];
+ int handles[MAX_NUM_TECHNOLOGIES];
+ int libnfctypes[MAX_NUM_TECHNOLOGIES];
+
+ int index = 0;
+ // TODO: This counts from up to down because on multi-protocols, the
+ // ISO handle is usually the second, and we prefer the ISO. Should implement
+ // a method to find the "preferred handle order" and use that instead,
+ // since we shouldn't have dependencies on the tech list ordering.
+ for (int target = count - 1; target >= 0; target--) {
+ int type = devList[target].psRemoteDevInfo->RemDevType;
+ int handle = devList[target].hTargetDev;
+ switch (type)
+ {
+ case phNfc_eISO14443_A_PICC:
+ case phNfc_eISO14443_4A_PICC:
+ {
+ index = addTechIfNeeded(technologies, handles, libnfctypes, index,
+ MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
+ break;
+ }
+ case phNfc_eISO14443_4B_PICC:
+ {
+ index = addTechIfNeeded(technologies, handles, libnfctypes, index,
+ MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
+ index = addTechIfNeeded(technologies, handles, libnfctypes, index,
+ MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
+ }break;
+ case phNfc_eISO14443_3A_PICC:
+ {
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
+ }break;
+ case phNfc_eISO14443_B_PICC:
+ {
+ // TODO a bug in libnfc will cause 14443-3B only cards
+ // to be returned as this type as well, but these cards
+ // are very rare. Hence assume it's -4B
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
+ }break;
+ case phNfc_eISO15693_PICC:
+ {
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type);
+ }break;
+ case phNfc_eMifare_PICC:
+ {
+ // We don't want to be too clever here; libnfc has already determined
+ // it's a Mifare, so we only check for UL, for all other tags
+ // we assume it's a mifare classic. This should make us more
+ // future-proof.
+ int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak;
+ switch(sak)
+ {
+ case 0x00:
+ // could be UL or UL-C
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type);
+ break;
+ default:
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type);
+ break;
+ }
+ }break;
+ case phNfc_eFelica_PICC:
+ {
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type);
+ }break;
+ case phNfc_eJewel_PICC:
+ {
+ // Jewel represented as NfcA
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
+ }break;
+ default:
+ {
+ index = addTechIfNeeded(technologies, handles, libnfctypes,
+ index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type);
+ }
+ }
+ }
+
+ // Build the Java arrays
+ if (techList != NULL) {
+ *techList = e->NewIntArray(index);
+ e->SetIntArrayRegion(*techList, 0, index, technologies);
+ }
+
+ if (handleList != NULL) {
+ *handleList = e->NewIntArray(index);
+ e->SetIntArrayRegion(*handleList, 0, index, handles);
+ }
+
+ if (libnfcTypeList != NULL) {
+ *libnfcTypeList = e->NewIntArray(index);
+ e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes);
+ }
+}
+
+} // namespace android
diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h
new file mode 100644
index 0000000..a44bcf0
--- /dev/null
+++ b/nxp/jni/com_android_nfc.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COM_ANDROID_NFC_JNI_H__
+#define __COM_ANDROID_NFC_JNI_H__
+
+#define LOG_TAG "NFCJNI"
+
+#include <JNIHelp.h>
+#include <jni.h>
+
+#include <pthread.h>
+#include <sys/queue.h>
+
+extern "C" {
+#include <phNfcStatus.h>
+#include <phNfcTypes.h>
+#include <phNfcIoctlCode.h>
+#include <phLibNfc.h>
+#include <phDal4Nfc_messageQueueLib.h>
+#include <phFriNfc_NdefMap.h>
+#include <cutils/log.h>
+#include <com_android_nfc_list.h>
+#include <semaphore.h>
+
+}
+#include <cutils/properties.h> // for property_get
+
+
+/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */
+#define DISCOVERY_MODE_TAG_READER 0
+#define DISCOVERY_MODE_NFCIP1 1
+#define DISCOVERY_MODE_CARD_EMULATION 2
+
+#define DISCOVERY_MODE_TABLE_SIZE 3
+
+#define DISCOVERY_MODE_DISABLED 0
+#define DISCOVERY_MODE_ENABLED 1
+
+#define MODE_P2P_TARGET 0
+#define MODE_P2P_INITIATOR 1
+
+/* Properties values */
+#define PROPERTY_LLCP_LTO 0
+#define PROPERTY_LLCP_MIU 1
+#define PROPERTY_LLCP_WKS 2
+#define PROPERTY_LLCP_OPT 3
+#define PROPERTY_NFC_DISCOVERY_A 4
+#define PROPERTY_NFC_DISCOVERY_B 5
+#define PROPERTY_NFC_DISCOVERY_F 6
+#define PROPERTY_NFC_DISCOVERY_15693 7
+#define PROPERTY_NFC_DISCOVERY_NCFIP 8
+
+/* Error codes */
+#define ERROR_BUFFER_TOO_SMALL -12
+#define ERROR_INSUFFICIENT_RESOURCES -9
+
+/* Pre-defined card read/write state values. These must match the values in
+ * Ndef.java in the framework.
+ */
+
+#define NDEF_UNKNOWN_TYPE -1
+#define NDEF_TYPE1_TAG 1
+#define NDEF_TYPE2_TAG 2
+#define NDEF_TYPE3_TAG 3
+#define NDEF_TYPE4_TAG 4
+#define NDEF_MIFARE_CLASSIC_TAG 101
+#define NDEF_ICODE_SLI_TAG 102
+
+/* Pre-defined tag type values. These must match the values in
+ * Ndef.java in the framework.
+ */
+
+#define NDEF_MODE_READ_ONLY 1
+#define NDEF_MODE_READ_WRITE 2
+#define NDEF_MODE_UNKNOWN 3
+
+
+/* Name strings for target types. These *must* match the values in TagTechnology.java */
+#define TARGET_TYPE_UNKNOWN -1
+#define TARGET_TYPE_ISO14443_3A 1
+#define TARGET_TYPE_ISO14443_3B 2
+#define TARGET_TYPE_ISO14443_4 3
+#define TARGET_TYPE_FELICA 4
+#define TARGET_TYPE_ISO15693 5
+#define TARGET_TYPE_NDEF 6
+#define TARGET_TYPE_NDEF_FORMATABLE 7
+#define TARGET_TYPE_MIFARE_CLASSIC 8
+#define TARGET_TYPE_MIFARE_UL 9
+
+#define SMX_SECURE_ELEMENT_ID 11259375
+
+/* Maximum byte length of an AID. */
+#define AID_MAXLEN 16
+
+/* Utility macros for logging */
+#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN
+
+#if 0
+ #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status));
+ #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#else
+ #define LOG_CALLBACK(...)
+ #define TRACE(...)
+#endif
+
+struct nfc_jni_native_data
+{
+ /* Thread handle */
+ pthread_t thread;
+ int running;
+
+ /* Our VM */
+ JavaVM *vm;
+ int env_version;
+
+ /* Reference to the NFCManager instance */
+ jobject manager;
+
+ /* Cached objects */
+ jobject cached_NfcTag;
+ jobject cached_P2pDevice;
+
+ /* Target discovery configuration */
+ int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE];
+ phLibNfc_sADD_Cfg_t discovery_cfg;
+ phLibNfc_Registry_Info_t registry_info;
+
+ /* Secure Element selected */
+ int seId;
+
+ /* LLCP params */
+ int lto;
+ int miu;
+ int wks;
+ int opt;
+
+ /* Tag detected */
+ jobject tag;
+
+ /* Lib Status */
+ NFCSTATUS status;
+
+ /* p2p modes */
+ int p2p_initiator_modes;
+ int p2p_target_modes;
+
+};
+
+typedef struct nfc_jni_native_monitor
+{
+ /* Mutex protecting native library against reentrance */
+ pthread_mutex_t reentrance_mutex;
+
+ /* Mutex protecting native library against concurrency */
+ pthread_mutex_t concurrency_mutex;
+
+ /* List used to track pending semaphores waiting for callback */
+ struct listHead sem_list;
+
+ /* List used to track incoming socket requests (and associated sync variables) */
+ LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head;
+ pthread_mutex_t incoming_socket_mutex;
+ pthread_cond_t incoming_socket_cond;
+
+} nfc_jni_native_monitor_t;
+
+typedef struct nfc_jni_callback_data
+{
+ /* Semaphore used to wait for callback */
+ sem_t sem;
+
+ /* Used to store the status sent by the callback */
+ NFCSTATUS status;
+
+ /* Used to provide a local context to the callback */
+ void* pContext;
+
+} nfc_jni_callback_data_t;
+
+typedef struct nfc_jni_listen_data
+{
+ /* LLCP server socket receiving the connection request */
+ phLibNfc_Handle pServerSocket;
+
+ /* LLCP socket created from the connection request */
+ phLibNfc_Handle pIncomingSocket;
+
+ /* List entries */
+ LIST_ENTRY(nfc_jni_listen_data) entries;
+
+} nfc_jni_listen_data_t;
+
+/* TODO: treat errors and add traces */
+#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex)
+#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex)
+#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex)
+#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex)
+
+namespace android {
+
+extern JavaVM *vm;
+
+JNIEnv *nfc_get_env();
+
+bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext);
+void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData);
+void nfc_cb_data_releaseAll();
+
+const char* nfc_jni_get_status_name(NFCSTATUS status);
+int nfc_jni_cache_object(JNIEnv *e, const char *clsname,
+ jobject *cached_obj);
+struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o);
+struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e);
+nfc_jni_native_monitor_t* nfc_jni_init_monitor(void);
+nfc_jni_native_monitor_t* nfc_jni_get_monitor(void);
+
+int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak);
+void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList,
+ uint8_t count, jintArray* techList, jintArray* handleList,
+ jintArray* typeList);
+
+/* P2P */
+phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o);
+jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o);
+
+/* TAG */
+jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o);
+jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o);
+phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o);
+jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o);
+
+/* LLCP */
+phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o);
+
+int register_com_android_nfc_NativeNfcManager(JNIEnv *e);
+int register_com_android_nfc_NativeNfcTag(JNIEnv *e);
+int register_com_android_nfc_NativeP2pDevice(JNIEnv *e);
+int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e);
+int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e);
+int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e);
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e);
+
+} // namespace android
+
+#endif
diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp
new file mode 100644
index 0000000..188edb4
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include "com_android_nfc.h"
+
+namespace android {
+
+/*
+ * Callbacks
+ */
+
+static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_receiveFrom_callback", status);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ pCallbackData->pContext = (void*)ssap;
+ TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap);
+ }
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_sendTo_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+/*
+* Methods
+*/
+static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data)
+{
+ NFCSTATUS ret;
+ struct timespec ts;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ phNfc_sData_t sSendBuffer = {NULL, 0};
+ struct nfc_jni_callback_data cb_data;
+ jboolean result = JNI_FALSE;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
+ sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
+
+ TRACE("phLibNfc_Llcp_SendTo()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_SendTo(hRemoteDevice,
+ hLlcpSocket,
+ nsap,
+ &sSendBuffer,
+ nfc_jni_send_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ if (sSendBuffer.buffer != NULL)
+ {
+ e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
+ }
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu)
+{
+ NFCSTATUS ret;
+ struct timespec ts;
+ uint8_t ssap;
+ jobject llcpPacket = NULL;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ phNfc_sData_t sReceiveBuffer;
+ jclass clsLlcpPacket;
+ jfieldID f;
+ jbyteArray receivedData = NULL;
+ struct nfc_jni_callback_data cb_data;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Create new LlcpPacket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1)
+ {
+ ALOGE("Find LlcpPacket class error");
+ goto clean_and_return;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsLlcpPacket = e->GetObjectClass(llcpPacket);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Get Object class error");
+ goto clean_and_return;
+ }
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+ TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu);
+
+ sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu);
+ sReceiveBuffer.length = linkMiu;
+
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice,
+ hLlcpSocket,
+ &sReceiveBuffer,
+ nfc_jni_receive_callback,
+ &cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ ssap = (uint32_t)cb_data.pContext;
+ TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length);
+
+ /* Set Llcp Packet remote SAP */
+ f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I");
+ e->SetIntField(llcpPacket, f,(jbyte)ssap);
+
+ /* Set Llcp Packet Buffer */
+ ALOGD("Set LlcpPacket Data Buffer\n");
+ f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B");
+ receivedData = e->NewByteArray(sReceiveBuffer.length);
+ e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer);
+ e->SetObjectField(llcpPacket, f, receivedData);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ return llcpPacket;
+}
+
+static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ TRACE("Close Connectionless socket");
+
+ /* Retrieve socket handle */
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ TRACE("phLibNfc_Llcp_Close()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return TRUE;
+ }
+ else
+ {
+ ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return FALSE;
+ }
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo},
+
+ {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom},
+
+ {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose},
+};
+
+
+int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/nxp/NativeLlcpConnectionlessSocket",
+ gMethods, NELEM(gMethods));
+}
+
+} // android namespace
diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp
new file mode 100644
index 0000000..92de3e4
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include "com_android_nfc.h"
+
+namespace android {
+
+extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext,
+ uint8_t nErrCode);
+/*
+ * Callbacks
+ */
+static void nfc_jni_llcp_accept_socket_callback(void* pContext,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+
+/*
+ * Utils
+ */
+
+static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor,
+ phLibNfc_Handle hServerSocket)
+{
+ nfc_jni_listen_data_t * pListenData;
+ phLibNfc_Handle pIncomingSocket = NULL;
+
+ /* Look for a pending incoming connection on the current server */
+ LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries)
+ {
+ if (pListenData->pServerSocket == hServerSocket)
+ {
+ pIncomingSocket = pListenData->pIncomingSocket;
+ LIST_REMOVE(pListenData, entries);
+ free(pListenData);
+ break;
+ }
+ }
+
+ return pIncomingSocket;
+}
+
+/*
+ * Methods
+ */
+static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
+{
+ NFCSTATUS ret = NFCSTATUS_SUCCESS;
+ struct timespec ts;
+ phLibNfc_Llcp_sSocketOptions_t sOptions;
+ phNfc_sData_t sWorkingBuffer;
+ jfieldID f;
+ jclass clsNativeLlcpSocket;
+ jobject clientSocket = NULL;
+ struct nfc_jni_callback_data cb_data;
+ phLibNfc_Handle hIncomingSocket, hServerSocket;
+ nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Get server socket */
+ hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Set socket options with the socket options of the service */
+ sOptions.miu = miu;
+ sOptions.rw = rw;
+
+ /* Allocate Working buffer length */
+ sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
+ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
+
+ while(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ /* Wait for tag Notification */
+ pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
+ while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) {
+ pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
+ }
+ pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
+
+ /* Accept the incomming socket */
+ TRACE("phLibNfc_Llcp_Accept()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Accept( hIncomingSocket,
+ &sOptions,
+ &sWorkingBuffer,
+ nfc_jni_llcp_transport_socket_err_callback,
+ nfc_jni_llcp_accept_socket_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ // NOTE: This may happen if link went down since incoming socket detected, then
+ // just drop it and start a new accept loop.
+ ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ continue;
+ }
+ TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
+ ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
+ }
+ }
+
+ /* Create new LlcpSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1)
+ {
+ ALOGD("LLCP Socket creation error");
+ goto clean_and_return;
+ }
+
+ /* Get NativeConnectionOriented class object */
+ clsNativeLlcpSocket = e->GetObjectClass(clientSocket);
+ if(e->ExceptionCheck())
+ {
+ ALOGD("LLCP Socket get class object error");
+ goto clean_and_return;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField(clientSocket, f,(jint)hIncomingSocket);
+
+ /* Set socket MIU */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField(clientSocket, f,(jint)miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField(clientSocket, f,(jint)rw);
+
+ TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ return clientSocket;
+}
+
+static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
+
+ TRACE("Close Service socket");
+
+ /* Retrieve socket handle */
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
+ /* TODO: implement accept abort */
+ pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
+ pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
+
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("Close Service socket OK");
+ return TRUE;
+ }
+ else
+ {
+ ALOGD("Close Service socket KO");
+ return FALSE;
+ }
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;",
+ (void *)com_NativeLlcpServiceSocket_doAccept},
+
+ {"doClose", "()Z",
+ (void *)com_NativeLlcpServiceSocket_doClose},
+};
+
+
+int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/nxp/NativeLlcpServiceSocket",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp
new file mode 100644
index 0000000..0c0b830
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include "com_android_nfc.h"
+
+namespace android {
+
+/*
+ * Callbacks
+ */
+
+static void nfc_jni_disconnect_callback(void* pContext,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_disconnect_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+
+static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcp_connect_callback", status);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ TRACE("Socket connected\n");
+ }
+ else
+ {
+ ALOGD("Socket not connected:");
+ switch(nErrCode)
+ {
+ case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE:
+ {
+ ALOGD("> SAP NOT ACTIVE\n");
+ }break;
+
+ case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND:
+ {
+ ALOGD("> SAP NOT FOUND\n");
+ }break;
+
+ case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED:
+ {
+ ALOGD("> CONNECT REJECTED\n");
+ }break;
+
+ case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED:
+ {
+ ALOGD("> CONNECT NOT ACCEPTED\n");
+ }break;
+
+ case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE:
+ {
+ ALOGD("> SOCKET NOT AVAILABLE\n");
+ }break;
+ }
+ }
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+
+
+
+static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcp_receive_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcp_send_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+/*
+ * Methods
+ */
+static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
+{
+ NFCSTATUS ret;
+ struct timespec ts;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ struct nfc_jni_callback_data cb_data;
+ jboolean result = JNI_FALSE;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Connect(hRemoteDevice,
+ hLlcpSocket,
+ nSap,
+ nfc_jni_connect_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("LLCP Connect request failed");
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
+{
+ NFCSTATUS ret;
+ struct timespec ts;
+ phNfc_sData_t serviceName = {0};
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ struct nfc_jni_callback_data cb_data;
+ jboolean result = JNI_FALSE;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Service socket */
+ serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
+ serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
+
+ TRACE("phLibNfc_Llcp_ConnectByUri()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice,
+ hLlcpSocket,
+ &serviceName,
+ nfc_jni_connect_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ if (serviceName.buffer != NULL) {
+ e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
+ }
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+
+ /* Retrieve socket handle */
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ TRACE("phLibNfc_Llcp_Close()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return FALSE;
+ }
+ TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return TRUE;
+}
+
+static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data)
+{
+ NFCSTATUS ret;
+ struct timespec ts;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ phNfc_sData_t sSendBuffer = {NULL, 0};
+ struct nfc_jni_callback_data cb_data;
+ jboolean result = JNI_FALSE;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
+ sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
+
+ TRACE("phLibNfc_Llcp_Send()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Send(hRemoteDevice,
+ hLlcpSocket,
+ &sSendBuffer,
+ nfc_jni_send_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ if (sSendBuffer.buffer != NULL)
+ {
+ e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
+ }
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer)
+{
+ NFCSTATUS ret;
+ struct timespec ts;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ phNfc_sData_t sReceiveBuffer = {NULL, 0};
+ struct nfc_jni_callback_data cb_data;
+ jint result = -1;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
+ sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
+
+ TRACE("phLibNfc_Llcp_Recv()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Recv(hRemoteDevice,
+ hLlcpSocket,
+ &sReceiveBuffer,
+ nfc_jni_receive_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_PENDING)
+ {
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = sReceiveBuffer.length;
+ }
+ }
+ else if (ret == NFCSTATUS_SUCCESS)
+ {
+ result = sReceiveBuffer.length;
+ }
+ else
+ {
+ /* Return status should be either SUCCESS or PENDING */
+ ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+clean_and_return:
+ if (sReceiveBuffer.buffer != NULL)
+ {
+ e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
+ }
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ phLibNfc_Llcp_sSocketOptions_t remoteSocketOption;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
+ hLlcpSocket,
+ &remoteSocketOption);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return remoteSocketOption.miu;
+ }
+ else
+ {
+ ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return 0;
+ }
+}
+
+static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hRemoteDevice;
+ phLibNfc_Handle hLlcpSocket;
+ phLibNfc_Llcp_sSocketOptions_t remoteSocketOption;
+
+ /* Retrieve handles */
+ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
+ hLlcpSocket,
+ &remoteSocketOption);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return remoteSocketOption.rw;
+ }
+ else
+ {
+ ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return 0;
+ }
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)Z",
+ (void *)com_android_nfc_NativeLlcpSocket_doConnect},
+
+ {"doConnectBy", "(Ljava/lang/String;)Z",
+ (void *)com_android_nfc_NativeLlcpSocket_doConnectBy},
+
+ {"doClose", "()Z",
+ (void *)com_android_nfc_NativeLlcpSocket_doClose},
+
+ {"doSend", "([B)Z",
+ (void *)com_android_nfc_NativeLlcpSocket_doSend},
+
+ {"doReceive", "([B)I",
+ (void *)com_android_nfc_NativeLlcpSocket_doReceive},
+
+ {"doGetRemoteSocketMiu", "()I",
+ (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU},
+
+ {"doGetRemoteSocketRw", "()I",
+ (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW},
+};
+
+
+int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp
new file mode 100644
index 0000000..704ee6a
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp
@@ -0,0 +1,2622 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <sys/queue.h>
+#include <hardware/hardware.h>
+#include <hardware/nfc.h>
+#include <cutils/properties.h>
+
+#include "com_android_nfc.h"
+
+#define ERROR_BUFFER_TOO_SMALL -12
+#define ERROR_INSUFFICIENT_RESOURCES -9
+
+extern uint32_t libnfc_llc_error_count;
+
+static phLibNfc_sConfig_t gDrvCfg;
+void *gHWRef;
+static phNfc_sData_t gInputParam;
+static phNfc_sData_t gOutputParam;
+
+uint8_t device_connected_flag;
+static bool driverConfigured = FALSE;
+
+static phLibNfc_Handle hLlcpHandle;
+static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED;
+static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault;
+
+static jmethodID cached_NfcManager_notifyNdefMessageListeners;
+static jmethodID cached_NfcManager_notifyTransactionListeners;
+static jmethodID cached_NfcManager_notifyLlcpLinkActivation;
+static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated;
+static jmethodID cached_NfcManager_notifyTargetDeselected;
+
+static jmethodID cached_NfcManager_notifySeFieldActivated;
+static jmethodID cached_NfcManager_notifySeFieldDeactivated;
+
+static jmethodID cached_NfcManager_notifySeApduReceived;
+static jmethodID cached_NfcManager_notifySeMifareAccess;
+static jmethodID cached_NfcManager_notifySeEmvCardRemoval;
+
+namespace android {
+
+phLibNfc_Handle storedHandle = 0;
+
+struct nfc_jni_native_data *exported_nat = NULL;
+
+/* Internal functions declaration */
+static void *nfc_jni_client_thread(void *arg);
+static void nfc_jni_init_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_se_set_mode_callback(void *context,
+ phLibNfc_Handle handle, NFCSTATUS status);
+static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status);
+static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume);
+static void nfc_jni_Discovery_notification_callback(void *pContext,
+ phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNofRemoteDev, NFCSTATUS status);
+static void nfc_jni_transaction_callback(void *context,
+ phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle,
+ phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status);
+static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock);
+
+/*
+ * Deferred callback called when client thread must be exited
+ */
+static void client_kill_deferred_call(void* arg)
+{
+ struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg;
+
+ nat->running = FALSE;
+}
+
+static void kill_client(nfc_jni_native_data *nat)
+{
+ phDal4Nfc_Message_Wrapper_t wrapper;
+ phLibNfc_DeferredCall_t *pMsg;
+
+ usleep(50000);
+
+ ALOGD("Terminating client thread...");
+
+ pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t));
+ pMsg->pCallback = client_kill_deferred_call;
+ pMsg->pParameter = (void*)nat;
+
+ wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
+ wrapper.msg.pMsgData = pMsg;
+ wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t);
+
+ phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0);
+}
+
+static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) {
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_ioctl_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_deinit_download_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update)
+{
+ uint8_t OutputBuffer[1];
+ uint8_t InputBuffer[1];
+ struct timespec ts;
+ NFCSTATUS status = NFCSTATUS_FAILED;
+ phLibNfc_StackCapabilities_t caps;
+ struct nfc_jni_callback_data cb_data;
+ bool result;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ if(update)
+ {
+ //deinit
+ TRACE("phLibNfc_Mgt_DeInitialize() (download)");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 5;
+
+ /* Wait for callback response */
+ if(sem_timedwait(&cb_data.sem, &ts))
+ {
+ ALOGW("Deinitialization timed out (download)");
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("Deinitialization FAILED (download)");
+ }
+ TRACE("Deinitialization SUCCESS (download)");
+ }
+
+ result = performDownload(nat, false);
+
+ if (!result) {
+ status = NFCSTATUS_FAILED;
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_Mgt_Initialize()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_FAILED;
+ goto clean_and_return;
+ }
+
+ /* Initialization Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ status = cb_data.status;
+ goto clean_and_return;
+ }
+
+ /* ====== CAPABILITIES ======= */
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+ else
+ {
+ ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d",
+ caps.psDevCapabilities.hal_version,
+ caps.psDevCapabilities.fw_version,
+ caps.psDevCapabilities.hw_version,
+ caps.psDevCapabilities.model_id,
+ caps.psDevCapabilities.hci_version,
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1],
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2],
+ caps.psDevCapabilities.firmware_update_info);
+ }
+
+ /*Download is successful*/
+ status = NFCSTATUS_SUCCESS;
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ return status;
+}
+
+static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat)
+{
+ char value[PROPERTY_VALUE_MAX];
+ int result = FALSE;
+ NFCSTATUS status;
+
+ /* ====== CONFIGURE DRIVER ======= */
+ /* Configure hardware link */
+ gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600);
+
+ TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId);
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef);
+ REENTRANCE_UNLOCK();
+ if(status == NFCSTATUS_ALREADY_INITIALISED) {
+ ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+ else if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0)
+ {
+ ALOGE("pthread_create failed");
+ goto clean_and_return;
+ }
+
+ driverConfigured = TRUE;
+
+clean_and_return:
+ return result;
+}
+
+static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat)
+{
+ int result = FALSE;
+ NFCSTATUS status;
+
+ /* Unconfigure driver */
+ TRACE("phLibNfc_Mgt_UnConfigureDriver()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_UnConfigureDriver(gHWRef);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status));
+ }
+ else
+ {
+ ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ result = TRUE;
+ }
+
+ driverConfigured = FALSE;
+
+ return result;
+}
+
+/* Initialization function */
+static int nfc_jni_initialize(struct nfc_jni_native_data *nat) {
+ struct timespec ts;
+ uint8_t resp[16];
+ NFCSTATUS status;
+ phLibNfc_StackCapabilities_t caps;
+ phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
+ uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0;
+ phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo;
+ struct nfc_jni_callback_data cb_data;
+ uint8_t firmware_status;
+ uint8_t update = TRUE;
+ int result = JNI_FALSE;
+ const hw_module_t* hw_module;
+ nfc_pn544_device_t* pn544_dev = NULL;
+ int ret = 0;
+ ALOGD("Start Initialization\n");
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+ /* Get EEPROM values and device port from product-specific settings */
+ ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module);
+ if (ret) {
+ ALOGE("hw_get_module() failed.");
+ goto clean_and_return;
+ }
+ ret = nfc_pn544_open(hw_module, &pn544_dev);
+ if (ret) {
+ ALOGE("Could not open pn544 hw_module.");
+ goto clean_and_return;
+ }
+ if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) {
+ ALOGE("Could not load EEPROM settings");
+ goto clean_and_return;
+ }
+
+ /* Reset device connected handle */
+ device_connected_flag = 0;
+
+ /* Reset stored handle */
+ storedHandle = 0;
+
+ /* Initialize Driver */
+ if(!driverConfigured)
+ {
+ nfc_jni_configure_driver(nat);
+ }
+
+ /* ====== INITIALIZE ======= */
+
+ TRACE("phLibNfc_Mgt_Initialize()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ update = FALSE;
+ goto force_download;
+ }
+ TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Initialization Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ update = FALSE;
+ goto force_download;
+ }
+
+ /* ====== CAPABILITIES ======= */
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ }
+ else
+ {
+ ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d",
+ caps.psDevCapabilities.hal_version,
+ caps.psDevCapabilities.fw_version,
+ caps.psDevCapabilities.hw_version,
+ caps.psDevCapabilities.model_id,
+ caps.psDevCapabilities.hci_version,
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1],
+ caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2],
+ caps.psDevCapabilities.firmware_update_info);
+ }
+
+ /* ====== FIRMWARE VERSION ======= */
+ if(caps.psDevCapabilities.firmware_update_info)
+ {
+force_download:
+ for (i=0; i<3; i++)
+ {
+ TRACE("Firmware version not UpToDate");
+ status = nfc_jni_download_locked(nat, update);
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ ALOGI("Firmware update SUCCESS");
+ break;
+ }
+ ALOGW("Firmware update FAILED");
+ update = FALSE;
+ }
+ if(i>=3)
+ {
+ ALOGE("Unable to update firmware, giving up");
+ goto clean_and_return;
+ }
+ }
+ else
+ {
+ TRACE("Firmware version UpToDate");
+ }
+ /* ====== EEPROM SETTINGS ======= */
+
+ // Update EEPROM settings
+ TRACE("****** START EEPROM SETTINGS UPDATE ******");
+ for (i = 0; i < pn544_dev->num_eeprom_settings; i++)
+ {
+ char eeprom_property[PROPERTY_KEY_MAX];
+ char eeprom_value[PROPERTY_VALUE_MAX];
+ uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]);
+ TRACE("> EEPROM SETTING: %d", i);
+
+ // Check for override of this EEPROM value in properties
+ snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X",
+ eeprom_base[1], eeprom_base[2]);
+ TRACE(">> Checking property: %s", eeprom_property);
+ if (property_get(eeprom_property, eeprom_value, "") == 2) {
+ int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16);
+ ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X",
+ eeprom_base[1], eeprom_base[2], eeprom_value_num);
+ eeprom_base[3] = eeprom_value_num;
+ }
+
+ TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2],
+ eeprom_base[3]);
+ gInputParam.buffer = eeprom_base;
+ gInputParam.length = 0x04;
+ gOutputParam.buffer = resp;
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_PENDING) {
+ ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Initialization Status */
+ if (cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+ }
+ TRACE("****** ALL EEPROM SETTINGS UPDATED ******");
+
+ /* ====== SECURE ELEMENTS ======= */
+
+ REENTRANCE_LOCK();
+ ALOGD("phLibNfc_SE_GetSecureElementList()");
+ status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): Error");
+ goto clean_and_return;
+ }
+
+ ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE);
+ /* Display Secure Element information */
+ for (i = 0; i < No_SE; i++)
+ {
+ if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement);
+ } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement);
+ }
+
+ /* Set SE mode - Off */
+ REENTRANCE_LOCK();
+ status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement,
+ phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+ }
+
+ /* ====== LLCP ======= */
+
+ /* LLCP Params */
+ TRACE("****** NFC Config Mode NFCIP1 - LLCP ******");
+ LlcpConfigInfo.miu = nat->miu;
+ LlcpConfigInfo.lto = nat->lto;
+ LlcpConfigInfo.wks = nat->wks;
+ LlcpConfigInfo.option = nat->opt;
+
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo,
+ nfc_jni_llcpcfg_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status,
+ nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* ===== DISCOVERY ==== */
+ nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator
+ nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target
+ nat->discovery_cfg.Duration = 300000; /* in ms */
+ nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE;
+
+ /* Register for the card emulation mode */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret);
+
+
+ /* ====== END ======= */
+
+ ALOGI("NFC Initialized");
+
+ result = TRUE;
+
+clean_and_return:
+ if (result != TRUE)
+ {
+ if(nat)
+ {
+ kill_client(nat);
+ }
+ }
+ if (pn544_dev != NULL) {
+ nfc_pn544_close(pn544_dev);
+ }
+ nfc_cb_data_deinit(&cb_data);
+
+ return result;
+}
+
+static int is_user_build() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.type", value, "");
+ return !strncmp("user", value, PROPERTY_VALUE_MAX);
+}
+
+/*
+ * Last-chance fallback when there is no clean way to recover
+ * Performs a software reset
+ */
+void emergency_recovery(struct nfc_jni_native_data *nat) {
+ if (!is_user_build()) {
+ ALOGE("emergency_recovery: force restart of NFC service");
+ } else {
+ // dont recover immediately, so we can debug
+ unsigned int t;
+ for (t=1; t < 1000000; t <<= 1) {
+ ALOGE("emergency_recovery: NFC stack dead-locked");
+ sleep(t);
+ }
+ }
+ phLibNfc_Mgt_Recovery();
+ abort(); // force a noisy crash
+}
+
+void nfc_jni_reset_timeout_values()
+{
+ REENTRANCE_LOCK();
+ phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT);
+ phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT);
+ phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT);
+ phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT);
+ REENTRANCE_UNLOCK();
+}
+
+/*
+ * Restart the polling loop when unable to perform disconnect
+ */
+void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat)
+{
+ nfc_jni_start_discovery_locked(nat, true);
+}
+
+ /*
+ * Utility to recover UID from target infos
+ */
+static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo)
+{
+ phNfc_sData_t uid;
+
+ switch(psRemoteDevInfo->RemDevType)
+ {
+ case phNfc_eISO14443_A_PICC:
+ case phNfc_eISO14443_4A_PICC:
+ case phNfc_eISO14443_3A_PICC:
+ case phNfc_eMifare_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength;
+ break;
+ case phNfc_eISO14443_B_PICC:
+ case phNfc_eISO14443_4B_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi;
+ uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi);
+ break;
+ case phNfc_eFelica_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength;
+ break;
+ case phNfc_eJewel_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength;
+ break;
+ case phNfc_eISO15693_PICC:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength;
+ break;
+ case phNfc_eNfcIP1_Target:
+ case phNfc_eNfcIP1_Initiator:
+ uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID;
+ uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length;
+ break;
+ default:
+ uid.buffer = NULL;
+ uid.length = 0;
+ break;
+ }
+
+ return uid;
+}
+
+/*
+ * NFC stack message processing
+ */
+static void *nfc_jni_client_thread(void *arg)
+{
+ struct nfc_jni_native_data *nat;
+ JNIEnv *e;
+ JavaVMAttachArgs thread_args;
+ phDal4Nfc_Message_Wrapper_t wrapper;
+
+ nat = (struct nfc_jni_native_data *)arg;
+
+ thread_args.name = "NFC Message Loop";
+ thread_args.version = nat->env_version;
+ thread_args.group = NULL;
+
+ nat->vm->AttachCurrentThread(&e, &thread_args);
+ pthread_setname_np(pthread_self(), "message");
+
+ TRACE("NFC client started");
+ nat->running = TRUE;
+ while(nat->running == TRUE)
+ {
+ /* Fetch next message from the NFC stack message queue */
+ if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper,
+ sizeof(phLibNfc_Message_t), 0, 0) == -1)
+ {
+ ALOGE("NFC client received bad message");
+ continue;
+ }
+
+ switch(wrapper.msg.eMsgType)
+ {
+ case PH_LIBNFC_DEFERREDCALL_MSG:
+ {
+ phLibNfc_DeferredCall_t *msg =
+ (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData);
+
+ REENTRANCE_LOCK();
+ msg->pCallback(msg->pParameter);
+ REENTRANCE_UNLOCK();
+
+ break;
+ }
+ }
+ }
+ TRACE("NFC client stopped");
+
+ nat->vm->DetachCurrentThread();
+
+ return NULL;
+}
+
+extern uint8_t nfc_jni_is_ndef;
+extern uint8_t *nfc_jni_ndef_buf;
+extern uint32_t nfc_jni_ndef_buf_len;
+
+static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg =
+{
+ 3,
+ { 0x46, 0x66, 0x6D }
+};
+
+/*
+ * Callbacks
+ */
+
+/* P2P - LLCP callbacks */
+static void nfc_jni_llcp_linkStatus_callback(void *pContext,
+ phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus)
+{
+ phFriNfc_Llcp_sLinkParameters_t sLinkParams;
+ JNIEnv *e;
+ NFCSTATUS status;
+
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext;
+
+ nfc_jni_listen_data_t * pListenData = NULL;
+ nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor();
+
+ TRACE("Callback: nfc_jni_llcp_linkStatus_callback()");
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ /* Update link status */
+ g_eLinkStatus = eLinkStatus;
+
+ if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated)
+ {
+ REENTRANCE_LOCK();
+ status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ ALOGW("GetRemote Info failded - Status = %02x",status);
+ }
+ else
+ {
+ ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto,
+ sLinkParams.miu,
+ sLinkParams.option,
+ sLinkParams.wks);
+ device_connected_flag = 1;
+ }
+ }
+ else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated)
+ {
+ ALOGI("LLCP Link deactivated");
+ free(pContextData);
+ /* Reset device connected flag */
+ device_connected_flag = 0;
+
+ /* Reset incoming socket list */
+ while (!LIST_EMPTY(&pMonitor->incoming_socket_head))
+ {
+ pListenData = LIST_FIRST(&pMonitor->incoming_socket_head);
+ LIST_REMOVE(pListenData, entries);
+ free(pListenData);
+ }
+
+ /* Notify manager that the LLCP is lost or deactivated */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+}
+
+static void nfc_jni_checkLlcp_callback(void *context,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context;
+
+ LOG_CALLBACK("nfc_jni_checkLlcp_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcpcfg_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext,
+ phLibNfc_Handle hIncomingSocket)
+{
+ phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext;
+ nfc_jni_listen_data_t * pListenData = NULL;
+ nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor();
+
+ TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket);
+
+ pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
+
+ /* Store the connection request */
+ pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t));
+ if (pListenData == NULL)
+ {
+ ALOGE("Failed to create structure to handle incoming LLCP connection request");
+ goto clean_and_return;
+ }
+ pListenData->pServerSocket = hServiceSocket;
+ pListenData->pIncomingSocket = hIncomingSocket;
+ LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries);
+
+ /* Signal pending accept operations that the list is updated */
+ pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
+
+clean_and_return:
+ pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
+}
+
+void nfc_jni_llcp_transport_socket_err_callback(void* pContext,
+ uint8_t nErrCode)
+{
+ PHNFC_UNUSED_VARIABLE(pContext);
+
+ TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()");
+
+ if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED)
+ {
+ ALOGW("Frame Rejected - Disconnected");
+ }
+ else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED)
+ {
+ ALOGD("Socket Disconnected");
+ }
+}
+
+
+static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_discover_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNoOfRemoteDev)
+{
+ // Always prefer p2p targets over other targets. Otherwise, select the first target
+ // reported.
+ uint8_t preferred_index = 0;
+ for (uint8_t i = 0; i < uNoOfRemoteDev; i++) {
+ if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) {
+ preferred_index = i;
+ }
+ }
+ return preferred_index;
+}
+
+static void nfc_jni_Discovery_notification_callback(void *pContext,
+ phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNofRemoteDev, NFCSTATUS status)
+{
+ JNIEnv *e;
+ NFCSTATUS ret;
+ jclass tag_cls = NULL;
+ jobject target_array;
+ jobject tag;
+ jmethodID ctor;
+ jfieldID f;
+ const char * typeName;
+ jbyteArray tagUid;
+ jbyteArray generalBytes = NULL;
+ struct nfc_jni_native_data *nat;
+ struct timespec ts;
+ phNfc_sData_t data;
+ int i;
+ int target_index = 0; // Target that will be reported (if multiple can be >0)
+
+ nat = (struct nfc_jni_native_data *)pContext;
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ if(status == NFCSTATUS_DESELECTED)
+ {
+ LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status);
+
+ /* Notify manager that a target was deselected */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+ else
+ {
+ LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status);
+ TRACE("Discovered %d tags", uNofRemoteDev);
+
+ target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev);
+
+ /* Reset device connected flag */
+ device_connected_flag = 1;
+ phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo;
+ phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev;
+ if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target))
+ {
+
+ tag_cls = e->GetObjectClass(nat->cached_P2pDevice);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Get Object Class Error");
+ kill_client(nat);
+ return;
+ }
+
+ /* New target instance */
+ ctor = e->GetMethodID(tag_cls, "<init>", "()V");
+ tag = e->NewObject(tag_cls, ctor);
+
+ /* Set P2P Target mode */
+ f = e->GetFieldID(tag_cls, "mMode", "I");
+
+ if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ {
+ ALOGD("Discovered P2P Initiator");
+ e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR);
+ }
+ else
+ {
+ ALOGD("Discovered P2P Target");
+ e->SetIntField(tag, f, (jint)MODE_P2P_TARGET);
+ }
+
+ if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ {
+ /* Set General Bytes */
+ f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B");
+
+ TRACE("General Bytes length =");
+ for(i=0;i<remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++)
+ {
+ ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]);
+ }
+
+ generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length);
+
+ e->SetByteArrayRegion(generalBytes, 0,
+ remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length,
+ (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo);
+
+ e->SetObjectField(tag, f, generalBytes);
+ }
+
+ /* Set tag handle */
+ f = e->GetFieldID(tag_cls, "mHandle", "I");
+ e->SetIntField(tag, f,(jint)remDevHandle);
+ TRACE("Target handle = 0x%08x",remDevHandle);
+ }
+ else
+ {
+ tag_cls = e->GetObjectClass(nat->cached_NfcTag);
+ if(e->ExceptionCheck())
+ {
+ kill_client(nat);
+ return;
+ }
+
+ /* New tag instance */
+ ctor = e->GetMethodID(tag_cls, "<init>", "()V");
+ tag = e->NewObject(tag_cls, ctor);
+
+ bool multi_protocol = false;
+
+ if(status == NFCSTATUS_MULTIPLE_PROTOCOLS)
+ {
+ TRACE("Multiple Protocol TAG detected\n");
+ multi_protocol = true;
+ }
+
+ /* Set tag UID */
+ f = e->GetFieldID(tag_cls, "mUid", "[B");
+ data = get_target_uid(remDevInfo);
+ tagUid = e->NewByteArray(data.length);
+ if(data.length > 0)
+ {
+ e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer);
+ }
+ e->SetObjectField(tag, f, tagUid);
+
+ /* Generate technology list */
+ jintArray techList;
+ jintArray handleList;
+ jintArray typeList;
+ nfc_jni_get_technology_tree(e, psRemoteDevList,
+ multi_protocol ? uNofRemoteDev : 1,
+ &techList, &handleList, &typeList);
+
+ /* Push the technology list into the java object */
+ f = e->GetFieldID(tag_cls, "mTechList", "[I");
+ e->SetObjectField(tag, f, techList);
+
+ f = e->GetFieldID(tag_cls, "mTechHandles", "[I");
+ e->SetObjectField(tag, f, handleList);
+
+ f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I");
+ e->SetObjectField(tag, f, typeList);
+
+ f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I");
+ e->SetIntField(tag, f,(jint)-1);
+
+ f = e->GetFieldID(tag_cls, "mConnectedHandle", "I");
+ e->SetIntField(tag, f,(jint)-1);
+ }
+
+ storedHandle = remDevHandle;
+ if (nat->tag != NULL) {
+ e->DeleteGlobalRef(nat->tag);
+ }
+ nat->tag = e->NewGlobalRef(tag);
+
+ /* Notify the service */
+ TRACE("Notify Nfc Service");
+ if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
+ || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target))
+ {
+ /* Store the hanlde of the P2P device */
+ hLlcpHandle = remDevHandle;
+
+ /* Notify manager that new a P2P device was found */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+ else
+ {
+ /* Notify manager that new a tag was found */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Exception occured");
+ kill_client(nat);
+ }
+ }
+ e->DeleteLocalRef(tag);
+ }
+}
+
+static void nfc_jni_init_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_init_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_deinit_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/* Set Secure Element mode callback*/
+static void nfc_jni_smartMX_setModeCb (void* pContext,
+ phLibNfc_Handle hSecureElement,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/* Card Emulation callback */
+static void nfc_jni_transaction_callback(void *context,
+ phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle,
+ phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status)
+{
+ JNIEnv *e;
+ jobject tmp_array = NULL;
+ jobject mifare_block = NULL;
+ struct nfc_jni_native_data *nat;
+ phNfc_sData_t *aid;
+ phNfc_sData_t *mifare_command;
+ struct nfc_jni_callback_data *pCallbackData;
+ int i=0;
+
+ LOG_CALLBACK("nfc_jni_transaction_callback", status);
+
+ nat = (struct nfc_jni_native_data *)context;
+
+ nat->vm->GetEnv( (void **)&e, nat->env_version);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ switch(evt_type)
+ {
+ case phLibNfc_eSE_EvtStartTransaction:
+ {
+ TRACE("> SE EVT_START_TRANSACTION");
+ if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN)
+ {
+ aid = &(evt_info->UiccEvtInfo.aid);
+
+ ALOGD("> AID DETECTED");
+
+ if(aid != NULL)
+ {
+ char aid_str[AID_MAXLEN * 2 + 1];
+ aid_str[0] = '\0';
+ for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) {
+ snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]);
+ }
+ ALOGD("> AID: %s", aid_str);
+
+ tmp_array = e->NewByteArray(aid->length);
+ if (tmp_array == NULL)
+ {
+ goto error;
+ }
+
+ e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ goto error;
+ }
+
+ TRACE("Notify Nfc Service");
+ /* Notify manager that a new event occurred on a SE */
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ ALOGD("> NO AID DETECTED");
+ }
+ }break;
+
+ case phLibNfc_eSE_EvtApduReceived:
+ {
+ phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid);
+ TRACE("> SE EVT_APDU_RECEIVED");
+
+ if (apdu != NULL) {
+ TRACE(" APDU length=%d", apdu->length);
+ tmp_array = e->NewByteArray(apdu->length);
+ if (tmp_array == NULL) {
+ goto error;
+ }
+ e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer);
+ if (e->ExceptionCheck()) {
+ goto error;
+ }
+ } else {
+ TRACE(" APDU EMPTY");
+ }
+
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array);
+ }break;
+
+ case phLibNfc_eSE_EvtCardRemoval:
+ {
+ TRACE("> SE EVT_EMV_CARD_REMOVAL");
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval);
+ }break;
+
+ case phLibNfc_eSE_EvtMifareAccess:
+ {
+ TRACE("> SE EVT_MIFARE_ACCESS");
+ mifare_command = &(evt_info->UiccEvtInfo.aid);
+ TRACE("> MIFARE Block: %d",mifare_command->buffer[1]);
+ tmp_array = e->NewByteArray(2);
+ if (tmp_array == NULL)
+ {
+ goto error;
+ }
+
+ e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block);
+ }break;
+
+ case phLibNfc_eSE_EvtFieldOn:
+ {
+ TRACE("> SE EVT_FIELD_ON");
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated);
+ }break;
+
+ case phLibNfc_eSE_EvtFieldOff:
+ {
+ TRACE("> SE EVT_FIELD_OFF");
+ TRACE("Notify Nfc Service");
+ e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated);
+ }break;
+
+ default:
+ {
+ TRACE("Unknown SE event");
+ }break;
+ }
+ }
+ else
+ {
+ ALOGE("SE transaction notification error");
+ goto error;
+ }
+
+ /* Function finished, now clean and return */
+ goto clean_and_return;
+
+ error:
+ /* In case of error, just discard the notification */
+ ALOGE("Failed to send SE transaction notification");
+ e->ExceptionClear();
+
+ clean_and_return:
+ if(tmp_array != NULL)
+ {
+ e->DeleteLocalRef(tmp_array);
+ }
+}
+
+static void nfc_jni_se_set_mode_callback(void *pContext,
+ phLibNfc_Handle handle, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("nfc_jni_se_set_mode_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/*
+ * NFCManager methods
+ */
+
+static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume)
+{
+ NFCSTATUS ret;
+ struct nfc_jni_callback_data cb_data;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+ /* Reset the PN544 ISO XCHG / sw watchdog timeouts */
+ nfc_jni_reset_timeout_values();
+
+ /* Reload the p2p modes */
+ nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator
+ nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target
+ nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE;
+
+ /* Reset device connected flag */
+ device_connected_flag = 0;
+
+ /* Start Polling loop */
+ TRACE("****** Start NFC Discovery ******");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG,
+ nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"",
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"",
+ nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret);
+
+ if(ret != NFCSTATUS_PENDING)
+ {
+ emergency_recovery(nat);
+ goto clean_and_return;
+ }
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+}
+
+static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat)
+{
+ phLibNfc_sADD_Cfg_t discovery_cfg;
+ NFCSTATUS ret;
+ struct nfc_jni_callback_data cb_data;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ discovery_cfg.PollDevInfo.PollEnabled = 0;
+ discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode;
+ discovery_cfg.NfcIP_Target_Mode = 0;
+ discovery_cfg.NfcIP_Tgt_Disable = TRUE;
+
+ /* Start Polling loop */
+ TRACE("****** Stop NFC Discovery ******");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"",
+ discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"",
+ discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret);
+
+ if(ret != NFCSTATUS_PENDING)
+ {
+ emergency_recovery(nat);
+ }
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+}
+
+
+static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ nfc_jni_stop_discovery_locked(nat);
+
+ CONCURRENCY_UNLOCK();
+
+}
+
+static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ struct nfc_jni_native_data *nat;
+
+ CONCURRENCY_LOCK();
+
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Register callback for remote device notifications.
+ * Must re-register every time we turn on discovery, since other operations
+ * (such as opening the Secure Element) can change the remote device
+ * notification callback*/
+ REENTRANCE_LOCK();
+ ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret);
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n",
+ nat->registry_info.Jewel==TRUE?"J":"",
+ nat->registry_info.MifareUL==TRUE?"UL":"",
+ nat->registry_info.MifareStd==TRUE?"Mi":"",
+ nat->registry_info.Felica==TRUE?"F":"",
+ nat->registry_info.ISO14443_4A==TRUE?"4A":"",
+ nat->registry_info.ISO14443_4B==TRUE?"4B":"",
+ nat->registry_info.NFC==TRUE?"P2P":"",
+ nat->registry_info.ISO15693==TRUE?"R":"", ret);
+
+ nfc_jni_start_discovery_locked(nat, false);
+clean_and_return:
+ CONCURRENCY_UNLOCK();
+}
+
+static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) {
+ CONCURRENCY_LOCK();
+ nfc_jni_reset_timeout_values();
+ CONCURRENCY_UNLOCK();
+}
+
+static void setFelicaTimeout(jint timeout) {
+ // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms.
+ // It can be set to 0 to disable the timeout altogether, in which case we
+ // use the sw watchdog as a fallback.
+ if (timeout <= 255) {
+ phLibNfc_SetFelicaTimeout(timeout);
+ } else {
+ // Disable hw timeout, use sw watchdog for timeout
+ phLibNfc_SetFelicaTimeout(0);
+ phLibNfc_SetHciTimeout(timeout);
+ }
+
+}
+// Calculates ceiling log2 of value
+static unsigned int log2(int value) {
+ unsigned int ret = 0;
+ bool isPowerOf2 = ((value & (value - 1)) == 0);
+ while ( (value >> ret) > 1 ) ret++;
+ if (!isPowerOf2) ret++;
+ return ret;
+}
+
+// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X
+// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X
+//
+// We keep the constant part of the formula in a static; note the factor
+// 1000 off, which is due to the fact that the formula calculates seconds,
+// but this method gets milliseconds as an argument.
+static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0;
+
+static int calcTimeout(int timeout_in_ms) {
+ // timeout = (256 * 16 / 13560000) * 2 ^ X
+ // First find the first X for which timeout > requested timeout
+ return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor)));
+}
+
+static void setIsoDepTimeout(jint timeout) {
+ if (timeout <= 4900) {
+ int value = calcTimeout(timeout);
+ // Then re-compute the actual timeout based on X
+ double actual_timeout = nxp_nfc_timeout_factor * (1 << value);
+ // Set the sw watchdog a bit longer (The PN544 timeout is very accurate,
+ // but it will take some time to get back through the sw layers.
+ // 500 ms should be enough).
+ phLibNfc_SetHciTimeout(ceil(actual_timeout + 500));
+ value |= 0x10; // bit 4 to enable timeout
+ phLibNfc_SetIsoXchgTimeout(value);
+ }
+ else {
+ // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout
+ // must be disabled completely, to prevent the PN544 from aborting
+ // the transaction. We reuse the HCI sw watchdog to catch the timeout
+ // in that case.
+ phLibNfc_SetIsoXchgTimeout(0x00);
+ phLibNfc_SetHciTimeout(timeout);
+ }
+}
+
+static void setNfcATimeout(jint timeout) {
+ if (timeout <= 4900) {
+ int value = calcTimeout(timeout);
+ phLibNfc_SetMifareRawTimeout(value);
+ }
+ else {
+ // Disable mifare raw timeout, use HCI sw watchdog instead
+ phLibNfc_SetMifareRawTimeout(0x00);
+ phLibNfc_SetHciTimeout(timeout);
+ }
+}
+
+static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o,
+ jint tech, jint timeout) {
+ bool success = false;
+ CONCURRENCY_LOCK();
+ if (timeout <= 0) {
+ ALOGE("Timeout must be positive.");
+ return false;
+ } else {
+ switch (tech) {
+ case TARGET_TYPE_MIFARE_CLASSIC:
+ case TARGET_TYPE_MIFARE_UL:
+ // Intentional fall-through, Mifare UL, Classic
+ // transceive just uses raw 3A frames
+ case TARGET_TYPE_ISO14443_3A:
+ setNfcATimeout(timeout);
+ success = true;
+ break;
+ case TARGET_TYPE_ISO14443_4:
+ setIsoDepTimeout(timeout);
+ success = true;
+ break;
+ case TARGET_TYPE_FELICA:
+ setFelicaTimeout(timeout);
+ success = true;
+ break;
+ default:
+ ALOGW("doSetTimeout: Timeout not supported for tech %d", tech);
+ success = false;
+ }
+ }
+ CONCURRENCY_UNLOCK();
+ return success;
+}
+
+static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o,
+ jint tech) {
+ int timeout = -1;
+ CONCURRENCY_LOCK();
+ switch (tech) {
+ case TARGET_TYPE_MIFARE_CLASSIC:
+ case TARGET_TYPE_MIFARE_UL:
+ // Intentional fall-through, Mifare UL, Classic
+ // transceive just uses raw 3A frames
+ case TARGET_TYPE_ISO14443_3A:
+ timeout = phLibNfc_GetMifareRawTimeout();
+ if (timeout == 0) {
+ timeout = phLibNfc_GetHciTimeout();
+ } else {
+ // Timeout returned from libnfc needs conversion to ms
+ timeout = (nxp_nfc_timeout_factor * (1 << timeout));
+ }
+ break;
+ case TARGET_TYPE_ISO14443_4:
+ timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only
+ if (timeout == 0) {
+ timeout = phLibNfc_GetHciTimeout();
+ } else {
+ // Timeout returned from libnfc needs conversion to ms
+ timeout = (nxp_nfc_timeout_factor * (1 << timeout));
+ }
+ break;
+ case TARGET_TYPE_FELICA:
+ timeout = phLibNfc_GetFelicaTimeout();
+ if (timeout == 0) {
+ timeout = phLibNfc_GetHciTimeout();
+ } else {
+ // Felica timeout already in ms
+ }
+ break;
+ default:
+ ALOGW("doGetTimeout: Timeout not supported for tech %d", tech);
+ break;
+ }
+ CONCURRENCY_UNLOCK();
+ return timeout;
+}
+
+
+static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o)
+{
+ NFCSTATUS status;
+ struct nfc_jni_native_data *nat = NULL;
+ jclass cls;
+ jobject obj;
+ jfieldID f;
+
+ TRACE("****** Init Native Structure ******");
+
+ /* Initialize native structure */
+ nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data));
+ if(nat == NULL)
+ {
+ ALOGD("malloc of nfc_jni_native_data failed");
+ return FALSE;
+ }
+ memset(nat, 0, sizeof(*nat));
+ e->GetJavaVM(&(nat->vm));
+ nat->env_version = e->GetVersion();
+ nat->manager = e->NewGlobalRef(o);
+
+ cls = e->GetObjectClass(o);
+ f = e->GetFieldID(cls, "mNative", "I");
+ e->SetIntField(o, f, (jint)nat);
+
+ /* Initialize native cached references */
+ cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls,
+ "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V");
+
+ cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls,
+ "notifyTransactionListeners", "([B)V");
+
+ cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls,
+ "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V");
+
+ cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls,
+ "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V");
+
+ cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls,
+ "notifyTargetDeselected","()V");
+
+ cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls,
+ "notifySeFieldActivated", "()V");
+
+ cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls,
+ "notifySeFieldDeactivated", "()V");
+
+ cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls,
+ "notifySeApduReceived", "([B)V");
+
+ cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls,
+ "notifySeMifareAccess", "([B)V");
+
+ cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls,
+ "notifySeEmvCardRemoval", "()V");
+
+ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1)
+ {
+ ALOGD("Native Structure initialization failed");
+ return FALSE;
+ }
+
+ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1)
+ {
+ ALOGD("Native Structure initialization failed");
+ return FALSE;
+ }
+ TRACE("****** Init Native Structure OK ******");
+ return TRUE;
+
+}
+
+/* Init/Deinit method */
+static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat = NULL;
+ int init_result = JNI_FALSE;
+#ifdef TNFC_EMULATOR_ONLY
+ char value[PROPERTY_VALUE_MAX];
+#endif
+ jboolean result;
+
+ CONCURRENCY_LOCK();
+
+#ifdef TNFC_EMULATOR_ONLY
+ if (!property_get("ro.kernel.qemu", value, 0))
+ {
+ ALOGE("NFC Initialization failed: not running in an emulator\n");
+ goto clean_and_return;
+ }
+#endif
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ nat->seId = SMX_SECURE_ELEMENT_ID;
+
+ nat->lto = 150; // LLCP_LTO
+ nat->miu = 128; // LLCP_MIU
+ // WKS indicates well-known services; 1 << sap for each supported SAP.
+ // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4)
+ nat->wks = 0x13; // LLCP_WKS
+ nat->opt = 0; // LLCP_OPT
+ nat->p2p_initiator_modes = phNfc_eP2P_ALL;
+ nat->p2p_target_modes = 0x0E; // All passive except 106, active
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE;
+ nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE;
+
+ nat->registry_info.MifareUL = TRUE;
+ nat->registry_info.MifareStd = TRUE;
+ nat->registry_info.ISO14443_4A = TRUE;
+ nat->registry_info.ISO14443_4B = TRUE;
+ nat->registry_info.Jewel = TRUE;
+ nat->registry_info.Felica = TRUE;
+ nat->registry_info.NFC = TRUE;
+ nat->registry_info.ISO15693 = TRUE;
+
+ exported_nat = nat;
+
+ /* Perform the initialization */
+ init_result = nfc_jni_initialize(nat);
+
+clean_and_return:
+ CONCURRENCY_UNLOCK();
+
+ /* Convert the result and return */
+ return (init_result==TRUE)?JNI_TRUE:JNI_FALSE;
+}
+
+static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o)
+{
+ struct timespec ts;
+ NFCSTATUS status;
+ int result = JNI_FALSE;
+ struct nfc_jni_native_data *nat;
+ int bStackReset = FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Clear previous configuration */
+ memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t));
+ memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t));
+
+ /* Create the local semaphore */
+ if (nfc_cb_data_init(&cb_data, NULL))
+ {
+ TRACE("phLibNfc_Mgt_DeInitialize()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (status == NFCSTATUS_PENDING)
+ {
+ TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 5;
+
+ /* Wait for callback response */
+ if(sem_timedwait(&cb_data.sem, &ts) == -1)
+ {
+ ALOGW("Operation timed out");
+ bStackReset = TRUE;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("Failed to deinit the stack");
+ bStackReset = TRUE;
+ }
+ }
+ else
+ {
+ TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ bStackReset = TRUE;
+ }
+ nfc_cb_data_deinit(&cb_data);
+ }
+ else
+ {
+ ALOGE("Failed to create semaphore (errno=0x%08x)", errno);
+ bStackReset = TRUE;
+ }
+
+ kill_client(nat);
+
+ if(bStackReset == TRUE)
+ {
+ /* Complete deinit. failed, try hard restart of NFC */
+ ALOGW("Reseting stack...");
+ emergency_recovery(nat);
+ }
+
+ result = nfc_jni_unconfigure_driver(nat);
+
+ TRACE("NFC Deinitialized");
+
+ CONCURRENCY_UNLOCK();
+
+ return TRUE;
+}
+
+/* Secure Element methods */
+static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ jintArray list= NULL;
+ phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE];
+ uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE;
+
+ TRACE("****** Get Secure Element List ******");
+
+ TRACE("phLibNfc_SE_GetSecureElementList()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count);
+ REENTRANCE_UNLOCK();
+ if (ret != NFCSTATUS_SUCCESS) {
+ ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret,
+ nfc_jni_get_status_name(ret));
+ return list;
+ }
+ TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret,
+ nfc_jni_get_status_name(ret));
+
+ TRACE("Nb SE: %d", se_count);
+ list =e->NewIntArray(se_count);
+ for (i = 0; i < se_count; i++) {
+ if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected");
+ ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement);
+ } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) {
+ ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected");
+ ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement);
+ }
+ e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement);
+ }
+
+ e->DeleteLocalRef(list);
+
+ return list;
+}
+
+static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ struct nfc_jni_native_data *nat;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL)) {
+ goto clean_and_return;
+ }
+
+ TRACE("****** Select Secure Element ******");
+
+ TRACE("phLibNfc_SE_SetMode()");
+ /* Set SE mode - Virtual */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if (ret != NFCSTATUS_PENDING) {
+ ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if (sem_wait(&cb_data.sem)) {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+}
+
+static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) {
+ NFCSTATUS ret;
+ struct nfc_jni_native_data *nat;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL)) {
+ goto clean_and_return;
+ }
+
+ TRACE("****** Deselect Secure Element ******");
+
+ TRACE("phLibNfc_SE_SetMode()");
+ /* Set SE mode - Default */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault,
+ nfc_jni_se_set_mode_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret);
+ if (ret != NFCSTATUS_PENDING) {
+ ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if (sem_wait(&cb_data.sem)) {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+}
+
+/* Llcp methods */
+
+static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ bool freeData = false;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_native_data *nat;
+ struct nfc_jni_callback_data *cb_data;
+
+
+ CONCURRENCY_LOCK();
+
+ /* Memory allocation for cb_data
+ * This is on the heap because it is used by libnfc
+ * even after this call has succesfully finished. It is only freed
+ * upon link closure in nfc_jni_llcp_linkStatus_callback.
+ */
+ cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data));
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(cb_data, (void*)nat))
+ {
+ goto clean_and_return;
+ }
+
+ /* Check LLCP compliancy */
+ TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle,
+ nfc_jni_checkLlcp_callback,
+ nfc_jni_llcp_linkStatus_callback,
+ (void*)cb_data);
+ REENTRANCE_UNLOCK();
+ /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol
+ * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */
+ if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ freeData = true;
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data->sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data->status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(cb_data);
+ if (freeData) {
+ free(cb_data);
+ }
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Activate(hLlcpHandle);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return JNI_TRUE;
+ }
+ else
+ {
+ ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ return JNI_FALSE;
+ }
+}
+
+
+
+static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o,
+ jint nSap, jstring sn)
+{
+ NFCSTATUS ret;
+ jobject connectionlessSocket = NULL;
+ phLibNfc_Handle hLlcpSocket;
+ struct nfc_jni_native_data *nat;
+ phNfc_sData_t sWorkingBuffer = {NULL, 0};
+ phNfc_sData_t serviceName = {NULL, 0};
+ phLibNfc_Llcp_sLinkParameters_t sParams;
+ jclass clsNativeConnectionlessSocket;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Allocate Working buffer length */
+ phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams);
+ sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP
+ sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length);
+
+ /* Create socket */
+ TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess,
+ NULL,
+ &sWorkingBuffer,
+ &hLlcpSocket,
+ nfc_jni_llcp_transport_socket_err_callback,
+ (void*)nat);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Service socket */
+ if (sn == NULL) {
+ serviceName.buffer = NULL;
+ serviceName.length = 0;
+ } else {
+ serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
+ serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
+ }
+
+ /* Bind socket */
+ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ /* Close socket created */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+
+ /* Create new NativeLlcpConnectionlessSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1)
+ {
+ goto error;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket);
+ if(e->ExceptionCheck())
+ {
+ goto error;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I");
+ e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket);
+ TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket);
+
+ /* Set the miu link of the connectionless socket */
+ f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I");
+ e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT);
+ TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT);
+
+ /* Set socket SAP */
+ f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I");
+ e->SetIntField(connectionlessSocket, f,(jint)nSap);
+ TRACE("Connectionless socket SAP = %d\n",nSap);
+
+ return connectionlessSocket;
+error:
+ if (serviceName.buffer != NULL) {
+ e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
+ }
+
+ if (sWorkingBuffer.buffer != NULL) {
+ free(sWorkingBuffer.buffer);
+ }
+
+ return NULL;
+}
+
+static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ phLibNfc_Llcp_sSocketOptions_t sOptions;
+ phNfc_sData_t sWorkingBuffer;
+ phNfc_sData_t serviceName;
+ struct nfc_jni_native_data *nat;
+ jobject serviceSocket = NULL;
+ jclass clsNativeLlcpServiceSocket;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Set Connection Oriented socket options */
+ sOptions.miu = miu;
+ sOptions.rw = rw;
+
+ /* Allocate Working buffer length */
+ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
+ sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length);
+
+
+ /* Create socket */
+ TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented,
+ &sOptions,
+ &sWorkingBuffer,
+ &hLlcpSocket,
+ nfc_jni_llcp_transport_socket_err_callback,
+ (void*)nat);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ lastErrorStatus = ret;
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Service socket */
+ if (sn == NULL) {
+ serviceName.buffer = NULL;
+ serviceName.length = 0;
+ } else {
+ serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
+ serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
+ }
+
+ /* Bind socket */
+ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ /* Close socket created */
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Listen( hLlcpSocket,
+ nfc_jni_llcp_transport_listen_socket_callback,
+ (void*)hLlcpSocket);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ lastErrorStatus = ret;
+ /* Close created socket */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ goto error;
+ }
+ TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Create new NativeLlcpServiceSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1)
+ {
+ ALOGE("Llcp Socket object creation error");
+ goto error;
+ }
+
+ /* Get NativeLlcpServiceSocket class object */
+ clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Llcp Socket get object class error");
+ goto error;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I");
+ e->SetIntField(serviceSocket, f,(jint)hLlcpSocket);
+ TRACE("Service socket Handle = %02x\n",hLlcpSocket);
+
+ /* Set socket linear buffer length */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I");
+ e->SetIntField(serviceSocket, f,(jint)linearBufferLength);
+ TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength);
+
+ /* Set socket MIU */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I");
+ e->SetIntField(serviceSocket, f,(jint)miu);
+ TRACE("Service socket MIU = %d\n",miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I");
+ e->SetIntField(serviceSocket, f,(jint)rw);
+ TRACE("Service socket RW = %d\n",rw);
+
+ return serviceSocket;
+error:
+ if (serviceName.buffer != NULL) {
+ e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
+ }
+ return NULL;
+}
+
+static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength)
+{
+ jobject clientSocket = NULL;
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ phLibNfc_Llcp_sSocketOptions_t sOptions;
+ phNfc_sData_t sWorkingBuffer;
+ struct nfc_jni_native_data *nat;
+ jclass clsNativeLlcpSocket;
+ jfieldID f;
+
+ /* Retrieve native structure address */
+ nat = nfc_jni_get_nat(e, o);
+
+ /* Set Connection Oriented socket options */
+ sOptions.miu = miu;
+ sOptions.rw = rw;
+
+ /* Allocate Working buffer length */
+ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
+ sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length);
+
+ /* Create socket */
+ TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented,
+ &sOptions,
+ &sWorkingBuffer,
+ &hLlcpSocket,
+ nfc_jni_llcp_transport_socket_err_callback,
+ (void*)nat);
+ REENTRANCE_UNLOCK();
+
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ lastErrorStatus = ret;
+ return NULL;
+ }
+ TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Create new NativeLlcpSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1)
+ {
+ ALOGE("Llcp socket object creation error");
+ return NULL;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsNativeLlcpSocket = e->GetObjectClass(clientSocket);
+ if(e->ExceptionCheck())
+ {
+ ALOGE("Get class object error");
+ return NULL;
+ }
+
+ /* Test if an SAP number is present */
+ if(nSap != 0)
+ {
+ /* Bind socket */
+ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap);
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ lastErrorStatus = ret;
+ ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ /* Close socket created */
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ return NULL;
+ }
+ TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Set socket SAP */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I");
+ e->SetIntField(clientSocket, f,(jint)nSap);
+ TRACE("socket SAP = %d\n",nSap);
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField(clientSocket, f,(jint)hLlcpSocket);
+ TRACE("socket Handle = %02x\n",hLlcpSocket);
+
+ /* Set socket MIU */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField(clientSocket, f,(jint)miu);
+ TRACE("socket MIU = %d\n",miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField(clientSocket, f,(jint)rw);
+ TRACE("socket RW = %d\n",rw);
+
+
+ return clientSocket;
+}
+
+static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o)
+{
+ TRACE("Last Error Status = 0x%02x",lastErrorStatus);
+
+ if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL)
+ {
+ return ERROR_BUFFER_TOO_SMALL;
+ }
+ else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES)
+ {
+ return ERROR_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ return lastErrorStatus;
+ }
+}
+
+static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o)
+{
+ emergency_recovery(NULL);
+}
+
+static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o,
+ jint modes)
+{
+ ALOGE("Setting init modes to %x", modes);
+ struct nfc_jni_native_data *nat = NULL;
+ nat = nfc_jni_get_nat(e, o);
+ nat->p2p_initiator_modes = modes;
+}
+
+static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o,
+ jint modes)
+{
+ ALOGE("Setting target modes to %x", modes);
+ struct nfc_jni_native_data *nat = NULL;
+ nat = nfc_jni_get_nat(e, o);
+ nat->p2p_target_modes = modes;
+}
+
+static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) {
+ bool result = FALSE;
+ int load_result;
+ bool wasDisabled = FALSE;
+ uint8_t OutputBuffer[1];
+ uint8_t InputBuffer[1];
+ NFCSTATUS status = NFCSTATUS_FAILED;
+ struct nfc_jni_callback_data cb_data;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ if (takeLock)
+ {
+ CONCURRENCY_LOCK();
+ }
+
+ /* Initialize Driver */
+ if(!driverConfigured)
+ {
+ result = nfc_jni_configure_driver(nat);
+ wasDisabled = TRUE;
+ }
+ TRACE("com_android_nfc_NfcManager_doDownload()");
+
+ TRACE("Go in Download Mode");
+ phLibNfc_Download_Mode();
+
+ TRACE("Load new Firmware Image");
+ load_result = phLibNfc_Load_Firmware_Image();
+ if(load_result != 0)
+ {
+ TRACE("Load new Firmware Image - status = %d",load_result);
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ // Download
+ gInputParam.buffer = InputBuffer;
+ gInputParam.length = 0x01;
+ gOutputParam.buffer = OutputBuffer;
+ gOutputParam.length = 0x01;
+
+ ALOGD("Download new Firmware");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ result = FALSE;
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we
+ try to download an old-style firmware on top of a new-style
+ firmware. Hence, this is expected behavior, and not an
+ error condition. */
+ if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED)
+ {
+ TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ result = FALSE;
+ goto clean_and_return;
+ }
+
+ if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED)
+ {
+ ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip.");
+ }
+
+ /*Download is successful*/
+ result = TRUE;
+clean_and_return:
+ TRACE("phLibNfc_HW_Reset()");
+ phLibNfc_HW_Reset();
+ /* Deinitialize Driver */
+ if(wasDisabled)
+ {
+ result = nfc_jni_unconfigure_driver(nat);
+ }
+ if (takeLock)
+ {
+ CONCURRENCY_UNLOCK();
+ }
+ nfc_cb_data_deinit(&cb_data);
+ return result;
+}
+
+static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o)
+{
+ struct nfc_jni_native_data *nat = NULL;
+ nat = nfc_jni_get_nat(e, o);
+ return performDownload(nat, true);
+}
+
+static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o)
+{
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count);
+ return e->NewStringUTF(buffer);
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doDownload", "()Z",
+ (void *)com_android_nfc_NfcManager_doDownload},
+
+ {"initializeNativeStructure", "()Z",
+ (void *)com_android_nfc_NfcManager_init_native_struc},
+
+ {"doInitialize", "()Z",
+ (void *)com_android_nfc_NfcManager_initialize},
+
+ {"doDeinitialize", "()Z",
+ (void *)com_android_nfc_NfcManager_deinitialize},
+
+ {"enableDiscovery", "()V",
+ (void *)com_android_nfc_NfcManager_enableDiscovery},
+
+ {"doGetSecureElementList", "()[I",
+ (void *)com_android_nfc_NfcManager_doGetSecureElementList},
+
+ {"doSelectSecureElement", "()V",
+ (void *)com_android_nfc_NfcManager_doSelectSecureElement},
+
+ {"doDeselectSecureElement", "()V",
+ (void *)com_android_nfc_NfcManager_doDeselectSecureElement},
+
+ {"doCheckLlcp", "()Z",
+ (void *)com_android_nfc_NfcManager_doCheckLlcp},
+
+ {"doActivateLlcp", "()Z",
+ (void *)com_android_nfc_NfcManager_doActivateLlcp},
+
+ {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;",
+ (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket},
+
+ {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;",
+ (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket},
+
+ {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;",
+ (void *)com_android_nfc_NfcManager_doCreateLlcpSocket},
+
+ {"doGetLastError", "()I",
+ (void *)com_android_nfc_NfcManager_doGetLastError},
+
+ {"disableDiscovery", "()V",
+ (void *)com_android_nfc_NfcManager_disableDiscovery},
+
+ {"doSetTimeout", "(II)Z",
+ (void *)com_android_nfc_NfcManager_doSetTimeout},
+
+ {"doGetTimeout", "(I)I",
+ (void *)com_android_nfc_NfcManager_doGetTimeout},
+
+ {"doResetTimeouts", "()V",
+ (void *)com_android_nfc_NfcManager_doResetTimeouts},
+
+ {"doAbort", "()V",
+ (void *)com_android_nfc_NfcManager_doAbort},
+
+ {"doSetP2pInitiatorModes","(I)V",
+ (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes},
+
+ {"doSetP2pTargetModes","(I)V",
+ (void *)com_android_nfc_NfcManager_doSetP2pTargetModes},
+
+ {"doDump", "()Ljava/lang/String;",
+ (void *)com_android_nfc_NfcManager_doDump},
+};
+
+
+int register_com_android_nfc_NativeNfcManager(JNIEnv *e)
+{
+ nfc_jni_native_monitor_t *nfc_jni_native_monitor;
+
+ nfc_jni_native_monitor = nfc_jni_init_monitor();
+ if(nfc_jni_native_monitor == NULL)
+ {
+ ALOGE("NFC Manager cannot recover native monitor %x\n", errno);
+ return -1;
+ }
+
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/nxp/NativeNfcManager",
+ gMethods, NELEM(gMethods));
+}
+
+} /* namespace android */
diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp
new file mode 100755
index 0000000..bf0bffc
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <semaphore.h>
+
+#include "com_android_nfc.h"
+
+static phNfc_sData_t *com_android_nfc_jni_transceive_buffer;
+static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer;
+static phNfc_sRemoteDevInformation_t* SecureElementInfo;
+static int secureElementHandle;
+extern void *gHWRef;
+static int SecureElementTech;
+extern uint8_t device_connected_flag;
+
+namespace android {
+
+static void com_android_nfc_jni_ioctl_callback ( void* pContext,
+ phNfc_sData_t* Outparam_Cb,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ if (status == NFCSTATUS_SUCCESS )
+ {
+ LOG_CALLBACK("> IOCTL successful",status);
+ }
+ else
+ {
+ LOG_CALLBACK("> IOCTL error",status);
+ }
+
+ com_android_nfc_jni_ioctl_buffer = Outparam_Cb;
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void com_android_nfc_jni_transceive_callback(void *pContext,
+ phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status);
+
+ com_android_nfc_jni_transceive_buffer = pResBuffer;
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+
+static void com_android_nfc_jni_connect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("com_android_nfc_jni_connect_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void com_android_nfc_jni_disconnect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status);
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+/* Set Secure Element mode callback*/
+static void com_android_nfc_jni_smartMX_setModeCb (void* pContext,
+ phLibNfc_Handle hSecureElement,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+
+ if(status==NFCSTATUS_SUCCESS)
+ {
+ LOG_CALLBACK("SE Set Mode is Successful",status);
+ TRACE("SE Handle: %lu", hSecureElement);
+ }
+ else
+ {
+ LOG_CALLBACK("SE Set Mode is failed\n ",status);
+ }
+
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext,
+ phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNofRemoteDev,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext;
+ NFCSTATUS ret;
+ int i;
+ JNIEnv *e = nfc_get_env();
+
+ if(status == NFCSTATUS_DESELECTED)
+ {
+ LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status);
+ }
+ else
+ {
+ LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status);
+ TRACE("Discovered %d secure elements", uNofRemoteDev);
+
+ if(status == NFCSTATUS_MULTIPLE_PROTOCOLS)
+ {
+ bool foundHandle = false;
+ TRACE("Multiple Protocol supported\n");
+ for (i=0; i<uNofRemoteDev; i++) {
+ // Always open the phNfc_eISO14443_A_PICC protocol
+ TRACE("Protocol %d handle=%x type=%d", i, psRemoteDevList[i].hTargetDev,
+ psRemoteDevList[i].psRemoteDevInfo->RemDevType);
+ if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) {
+ secureElementHandle = psRemoteDevList[i].hTargetDev;
+ foundHandle = true;
+ }
+ }
+ if (!foundHandle) {
+ ALOGE("Could not find ISO-DEP secure element");
+ status = NFCSTATUS_FAILED;
+ goto clean_and_return;
+ }
+ }
+ else
+ {
+ secureElementHandle = psRemoteDevList->hTargetDev;
+ }
+
+ TRACE("Secure Element Handle: 0x%08x", secureElementHandle);
+
+ /* Set type name */
+ jintArray techList;
+ nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL);
+
+ // TODO: Should use the "connected" technology, for now use the first
+ if ((techList != NULL) && e->GetArrayLength(techList) > 0) {
+ e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech);
+ TRACE("Store Secure Element Info\n");
+ SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
+
+ TRACE("Discovered secure element: tech=%d", SecureElementTech);
+ }
+ else {
+ ALOGE("Discovered secure element, but could not resolve tech");
+ status = NFCSTATUS_FAILED;
+ }
+
+ // This thread may not return to the virtual machine for a long time
+ // so make sure to delete the local refernce to the tech list.
+ e->DeleteLocalRef(techList);
+ }
+
+clean_and_return:
+ pContextData->status = status;
+ sem_post(&pContextData->sem);
+}
+
+
+static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ int semResult;
+
+ phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
+ uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
+ phLibNfc_sADD_Cfg_t discovery_cfg;
+ phLibNfc_Registry_Info_t registry_info;
+ phNfc_sData_t InParam;
+ phNfc_sData_t OutParam;
+ uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01};
+ uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B};
+ uint8_t GpioSetValue[4];
+ uint8_t gpioValue;
+ uint8_t Output_Buff[10];
+ uint8_t reg_value;
+ uint8_t mask_value;
+ struct nfc_jni_callback_data cb_data;
+ struct nfc_jni_callback_data cb_data_SE_Notification;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Registery */
+ registry_info.MifareUL = TRUE;
+ registry_info.MifareStd = TRUE;
+ registry_info.ISO14443_4A = TRUE;
+ registry_info.ISO14443_4B = TRUE;
+ registry_info.Jewel = TRUE;
+ registry_info.Felica = TRUE;
+ registry_info.NFC = FALSE;
+
+ CONCURRENCY_LOCK();
+
+ TRACE("Open Secure Element");
+
+ /* Check if NFC device is already connected to a tag or P2P peer */
+ if (device_connected_flag == 1)
+ {
+ ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag");
+ goto clean_and_return;
+ }
+
+ /* Test if External RF field is detected */
+ InParam.buffer = ExternalRFDetected;
+ InParam.length = 3;
+ OutParam.buffer = Output_Buff;
+ TRACE("phLibNfc_Mgt_IoCtl()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret!=NFCSTATUS_PENDING)
+ {
+ ALOGE("IOCTL status error");
+ goto clean_and_return;
+ }
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("IOCTL semaphore error");
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ ALOGE("READ MEM ERROR");
+ goto clean_and_return;
+ }
+
+ /* Check the value */
+ reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0];
+ mask_value = reg_value & 0x40;
+
+ if(mask_value == 0x40)
+ {
+ // There is an external RF field present, fail the open request
+ ALOGD("Unable to open SE connection, external RF Field detected");
+ goto clean_and_return;
+ }
+
+ /* Get Secure Element List */
+ TRACE("phLibNfc_SE_GetSecureElementList()");
+ ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE);
+ if (ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("\n> Number of Secure Element(s) : %d\n", No_SE);
+ /* Display Secure Element information */
+ for (i = 0; i<No_SE; i++)
+ {
+ if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX)
+ {
+ TRACE("> SMX detected");
+ TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement);
+ /* save SMARTMX index */
+ SmartMX_detected = 1;
+ SmartMX_index = i;
+ }
+ }
+
+ if(SmartMX_detected)
+ {
+ REENTRANCE_LOCK();
+ TRACE("phLibNfc_RemoteDev_NtfRegister()");
+ ret = phLibNfc_RemoteDev_NtfRegister(&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/nxp/NativeNfcSecureElement",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp
new file mode 100644
index 0000000..dbf8dc9
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include "com_android_nfc.h"
+#include "phNfcHalTypes.h"
+
+static phLibNfc_Data_t nfc_jni_ndef_rw;
+static phLibNfc_Handle handle;
+uint8_t *nfc_jni_ndef_buf = NULL;
+uint32_t nfc_jni_ndef_buf_len = 0;
+
+extern uint8_t device_connected_flag;
+
+namespace android {
+
+extern phLibNfc_Handle storedHandle;
+
+extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat);
+extern void nfc_jni_reset_timeout_values();
+
+/*
+ * Callbacks
+ */
+ static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_tag_rw_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_connect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_connect_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ if (pCallbackData->pContext != NULL) {
+ // Store the remote dev info ptr in the callback context
+ // Note that this ptr will remain valid, it is tied to a statically
+ // allocated buffer in libnfc.
+ phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo =
+ (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext;
+ *ppRemoteDevInfo = psRemoteDevInfo;
+ }
+
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_checkndef_callback(void *pContext,
+ phLibNfc_ChkNdef_Info_t info, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_checkndef_callback", status);
+ phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext);
+ if(status == NFCSTATUS_OK)
+ {
+ if(nfc_jni_ndef_buf)
+ {
+ free(nfc_jni_ndef_buf);
+ }
+ nfc_jni_ndef_buf_len = info.MaxNdefMsgLength;
+ nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len);
+ if (pNdefInfo != NULL) *pNdefInfo = info;
+ }
+ else {
+ if (pNdefInfo != NULL) {
+ memset(pNdefInfo, 0, sizeof(*pNdefInfo));
+ }
+ }
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_disconnect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_disconnect_callback", status);
+
+ if(nfc_jni_ndef_buf)
+ {
+ free(nfc_jni_ndef_buf);
+ }
+ nfc_jni_ndef_buf = NULL;
+ nfc_jni_ndef_buf_len = 0;
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_async_disconnect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev, NFCSTATUS status)
+{
+ LOG_CALLBACK("nfc_jni_async_disconnect_callback", status);
+
+ if(nfc_jni_ndef_buf)
+ {
+ free(nfc_jni_ndef_buf);
+ }
+ nfc_jni_ndef_buf = NULL;
+ nfc_jni_ndef_buf_len = 0;
+}
+
+static phNfc_sData_t *nfc_jni_transceive_buffer;
+
+static void nfc_jni_transceive_callback(void *pContext,
+ phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_transceive_callback", status);
+
+ nfc_jni_transceive_buffer = pResBuffer;
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_presencecheck_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_formatndef_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_readonly_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+/* Functions */
+static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e,
+ jobject o)
+{
+ NFCSTATUS status;
+ phLibNfc_Handle handle = 0;
+ jbyteArray buf = NULL;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ handle = nfc_jni_get_connected_handle(e, o);
+
+ nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len;
+ nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf;
+
+ TRACE("phLibNfc_Ndef_Read()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw,
+ phLibNfc_Ndef_EBegin,
+ nfc_jni_tag_rw_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ buf = e->NewByteArray(nfc_jni_ndef_rw.length);
+ e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length,
+ (jbyte *)nfc_jni_ndef_rw.buffer);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+
+ return buf;
+}
+
+
+static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e,
+ jobject o, jbyteArray buf)
+{
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o);
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf);
+ nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
+
+ TRACE("phLibNfc_Ndef_Write()");
+ TRACE("Ndef Handle :0x%x\n",handle);
+ TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length);
+ REENTRANCE_LOCK();
+ status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT);
+
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+/*
+ * Utility to recover poll bytes from target infos
+ */
+static void set_target_pollBytes(JNIEnv *e, jobject tag,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo)
+{
+ jclass tag_cls = e->GetObjectClass(tag);
+ jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B");
+
+ jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f);
+
+ if (existingPollBytes != NULL) {
+ return;
+ }
+
+ jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I");
+ jintArray techList = (jintArray) e->GetObjectField(tag, techListField);
+ jint *techId = e->GetIntArrayElements(techList, 0);
+ int techListLength = e->GetArrayLength(techList);
+
+ jbyteArray pollBytes = e->NewByteArray(0);
+ jobjectArray techPollBytes = e->NewObjectArray(techListLength,
+ e->GetObjectClass(pollBytes), 0);
+
+ for (int tech = 0; tech < techListLength; tech++) {
+ switch(techId[tech])
+ {
+ /* ISO14443-3A: ATQA/SENS_RES */
+ case TARGET_TYPE_ISO14443_3A:
+ if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) {
+ // Jewel ATQA is not read and stored by the PN544, but it is fixed
+ // at {0x00, 0x0C} in the spec. So eJewel can safely be
+ // translated to {0x00, 0x0C}.
+ const static jbyte JewelAtqA[2] = {0x00, 0x0C};
+ pollBytes = e->NewByteArray(2);
+ e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA);
+ }
+ else {
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA);
+ }
+ break;
+ /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */
+ case TARGET_TYPE_ISO14443_3B:
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData);
+ e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo);
+ break;
+ /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */
+ case TARGET_TYPE_FELICA:
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm);
+ e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode);
+ break;
+ /* ISO15693: response flags (1 byte), DSFID (1 byte) */
+ case TARGET_TYPE_ISO15693:
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags);
+ e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid);
+ break;
+ default:
+ pollBytes = e->NewByteArray(0);
+ break;
+ }
+ e->SetObjectArrayElement(techPollBytes, tech, pollBytes);
+ }
+
+ e->SetObjectField(tag, f, techPollBytes);
+
+ e->ReleaseIntArrayElements(techList, techId, 0);
+
+}
+
+/*
+ * Utility to recover activation bytes from target infos
+ */
+static void set_target_activationBytes(JNIEnv *e, jobject tag,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo)
+{
+ jclass tag_cls = e->GetObjectClass(tag);
+
+ jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B");
+ jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f);
+
+ if (existingActBytes != NULL) {
+ return;
+ }
+
+ jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I");
+ jintArray techList = (jintArray) e->GetObjectField(tag, techListField);
+ int techListLength = e->GetArrayLength(techList);
+ jint *techId = e->GetIntArrayElements(techList, 0);
+
+ jbyteArray actBytes = e->NewByteArray(0);
+ jobjectArray techActBytes = e->NewObjectArray(techListLength,
+ e->GetObjectClass(actBytes), 0);
+
+ for (int tech = 0; tech < techListLength; tech++) {
+ switch(techId[tech]) {
+
+ /* ISO14443-3A: SAK/SEL_RES */
+ case TARGET_TYPE_ISO14443_3A:
+ actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak));
+ e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);
+ break;
+ /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */
+ /* ISO14443-3B & ISO14443-4: HiLayerResp */
+ case TARGET_TYPE_ISO14443_4:
+ // Determine whether -A or -B
+ if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC ||
+ psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) {
+ actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength);
+ e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength,
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp);
+ }
+ else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC ||
+ psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) {
+ actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength);
+ e->SetByteArrayRegion(actBytes, 0,
+ psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength,
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData);
+ }
+ break;
+ /* ISO15693: response flags (1 byte), DSFID (1 byte) */
+ case TARGET_TYPE_ISO15693:
+ actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid));
+ e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags);
+ e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid);
+ break;
+ default:
+ actBytes = e->NewByteArray(0);
+ break;
+ }
+ e->SetObjectArrayElement(techActBytes, tech, actBytes);
+ }
+ e->SetObjectField(tag, f, techActBytes);
+
+ e->ReleaseIntArrayElements(techList, techId, 0);
+}
+
+static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,
+ jobject o, phLibNfc_Handle handle)
+{
+ jclass cls;
+ jfieldID f;
+ jint status;
+ struct nfc_jni_callback_data cb_data;
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
+ {
+ status = NFCSTATUS_NOT_ENOUGH_MEMORY;
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Connect(RW)");
+ REENTRANCE_LOCK();
+ storedHandle = handle;
+ status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_ABORTED;
+ goto clean_and_return;
+ }
+
+ status = cb_data.status;
+ TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status);
+
+ /* Connect Status */
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ // Success, set poll & act bytes
+ set_target_pollBytes(e, o, pRemDevInfo);
+ set_target_activationBytes(e, o, pRemDevInfo);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return status;
+}
+
+static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e,
+ jobject o, phLibNfc_Handle handle)
+{
+ jclass cls;
+ jfieldID f;
+ jint status;
+ struct nfc_jni_callback_data cb_data;
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
+ {
+ status = NFCSTATUS_NOT_ENOUGH_MEMORY;
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_ReConnect(RW)");
+ REENTRANCE_LOCK();
+ storedHandle = handle;
+ status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_ABORTED;
+ goto clean_and_return;
+ }
+
+ status = cb_data.status;
+
+ /* Connect Status */
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return status;
+}
+
+static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e,
+ jobject o)
+{
+ // Reconnect is provided by libnfc by just calling connect again
+ // on the same handle.
+ int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o);
+ if (libNfcType != -1) {
+ // Note that some tag types are stateless, hence we do not reconnect
+ // those. Currently those are the Jewel and Iso15693 technologies.
+ if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) {
+ phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o);
+ return com_android_nfc_NativeNfcTag_doConnect(e, o, handle);
+ }
+ else {
+ return NFCSTATUS_SUCCESS;
+ }
+ }
+ else {
+ return NFCSTATUS_REJECTED;
+ }
+}
+
+
+static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o)
+{
+ phLibNfc_Handle handle = 0;
+ jclass cls;
+ jfieldID f;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ handle = nfc_jni_get_connected_handle(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Reset the stored handle */
+ storedHandle = 0;
+
+ nfc_jni_reset_timeout_values();
+
+ /* Disconnect */
+ TRACE("Disconnecting from tag (%x)", handle);
+
+ if (handle == -1) {
+ // Was never connected to any tag, exit
+ result = JNI_TRUE;
+ ALOGE("doDisconnect() - Target already disconnected");
+ nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle);
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,
+ nfc_jni_disconnect_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
+ {
+ result = JNI_TRUE;
+ TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected");
+ goto clean_and_return;
+ }
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status));
+ nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Disconnect Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ /* Reset device connected flag */
+ device_connected_flag = 0;
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static uint16_t
+crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init )
+{
+ uint16_t b, crc = init;
+
+ do {
+ b = *msg++ ^ (crc & 0xFF);
+ b ^= (b << 4) & 0xFF;
+ crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4);
+ } while( --len );
+
+ return crc;
+}
+
+static void
+nfc_insert_crc_a( uint8_t* msg, size_t len )
+{
+ uint16_t crc;
+
+ crc = crc_16_ccitt1( msg, len, 0x6363 );
+ msg[len] = crc & 0xFF;
+ msg[len + 1] = (crc >> 8) & 0xFF;
+}
+
+static void
+nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2)
+{
+ uint16_t crc;
+
+ crc = crc_16_ccitt1( msg, len, 0x6363 );
+ *byte1 = crc & 0xFF;
+ *byte2 = (crc >> 8) & 0xFF;
+}
+
+static bool
+crc_valid( uint8_t* msg, size_t len)
+{
+ uint8_t crcByte1, crcByte2;
+
+ nfc_get_crc_a(nfc_jni_transceive_buffer->buffer,
+ len - 2, &crcByte1, &crcByte2);
+
+ if (msg[len - 2] == crcByte1 &&
+ msg[len - 1] == crcByte2) {
+ return true;
+ }
+ else {
+ return false;
+ }
+
+}
+
+static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e,
+ jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost)
+{
+ uint8_t offset = 0;
+ // buf is the pointer to the JNI array and never overwritten,
+ // outbuf is passed into the transceive - it may be pointed to new memory
+ // to be extended with CRC.
+ uint8_t *buf = NULL;
+ uint32_t buflen;
+
+ uint8_t *outbuf = NULL;
+ uint32_t outlen;
+ phLibNfc_sTransceiveInfo_t transceive_info;
+ jbyteArray result = NULL;
+ int res;
+ phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o);
+ NFCSTATUS status;
+ struct nfc_jni_callback_data cb_data;
+ int selectedTech = 0;
+ int selectedLibNfcType = 0;
+ jint* technologies = NULL;
+ bool checkResponseCrc = false;
+
+ jint *targetLost;
+ if (statusTargetLost != NULL) {
+ targetLost = e->GetIntArrayElements(statusTargetLost, 0);
+ if (targetLost != NULL) {
+ *targetLost = 0;
+ }
+ } else {
+ targetLost = NULL;
+ }
+
+ memset(&transceive_info, 0, sizeof(transceive_info));
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ selectedTech = nfc_jni_get_connected_technology(e, o);
+ selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o);
+
+ buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL);
+ buflen = outlen = (uint32_t)e->GetArrayLength(data);
+
+ switch (selectedTech) {
+ case TARGET_TYPE_FELICA:
+ transceive_info.cmd.FelCmd = phNfc_eFelica_Raw;
+ transceive_info.addr = 0;
+ break;
+ case TARGET_TYPE_MIFARE_CLASSIC:
+ case TARGET_TYPE_MIFARE_UL:
+ if (raw) {
+ transceive_info.cmd.MfCmd = phHal_eMifareRaw;
+ transceive_info.addr = 0;
+ // Need to add in the crc here
+ outbuf = (uint8_t*)malloc(buflen + 2);
+ outlen += 2;
+ memcpy(outbuf, buf, buflen);
+ nfc_insert_crc_a(outbuf, buflen);
+
+ checkResponseCrc = true;
+ } else {
+ offset = 2;
+ transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
+ transceive_info.addr = (uint8_t)buf[1];
+ }
+ break;
+ case TARGET_TYPE_ISO14443_3A:
+ // Check which libnfc type
+ if (selectedLibNfcType == phNfc_eJewel_PICC) {
+ // For the Jewel pipe, CRC is automatically computed
+ transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw;
+ transceive_info.addr = 0;
+ } else {
+ if (raw) {
+ // Use Mifare Raw to implement a standard
+ // ISO14443-3A transceive, with CRC added
+ transceive_info.cmd.MfCmd = phHal_eMifareRaw;
+ transceive_info.addr = 0;
+ // Need to add in the crc here
+ outbuf = (uint8_t*)malloc(buflen + 2);
+ outlen += 2;
+ memcpy(outbuf, buf, buflen);
+ nfc_insert_crc_a(outbuf, buflen);
+
+ checkResponseCrc = true;
+ } else {
+ // Use the mifare pipe
+ offset = 2;
+ transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
+ transceive_info.addr = (uint8_t)buf[1];
+ }
+
+ }
+ break;
+ case TARGET_TYPE_ISO14443_4:
+ transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw;
+ transceive_info.addr = 0;
+ break;
+ case TARGET_TYPE_ISO15693:
+ transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd;
+ transceive_info.addr = 0;
+ break;
+ case TARGET_TYPE_UNKNOWN:
+ case TARGET_TYPE_ISO14443_3B:
+ // Not supported
+ goto clean_and_return;
+ default:
+ break;
+ }
+
+ transceive_info.sSendData.buffer = outbuf + offset;
+ transceive_info.sSendData.length = outlen - offset;
+ transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
+ transceive_info.sRecvData.length = 1024;
+ if(transceive_info.sRecvData.buffer == NULL)
+ {
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Transceive()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info,
+ nfc_jni_transceive_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) {
+ *targetLost = 1;
+ }
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) {
+ *targetLost = 1;
+ }
+ goto clean_and_return;
+ }
+
+ /* Copy results back to Java *
+ * In case of NfcA and raw, also check the CRC in the response
+ * and cut it off in the returned data.
+ */
+ if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) {
+ if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) {
+ result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2);
+ if (result != NULL) {
+ e->SetByteArrayRegion(result, 0,
+ nfc_jni_transceive_buffer->length - 2,
+ (jbyte *)nfc_jni_transceive_buffer->buffer);
+ }
+ }
+ } else {
+ result = e->NewByteArray(nfc_jni_transceive_buffer->length);
+ if (result != NULL) {
+ e->SetByteArrayRegion(result, 0,
+ nfc_jni_transceive_buffer->length,
+ (jbyte *)nfc_jni_transceive_buffer->buffer);
+ }
+ }
+clean_and_return:
+ if(transceive_info.sRecvData.buffer != NULL)
+ {
+ free(transceive_info.sRecvData.buffer);
+ }
+
+ if ((outbuf != buf) && (outbuf != NULL)) {
+ // Buf was extended and re-alloced with crc bytes, free separately
+ free(outbuf);
+ }
+
+ e->ReleaseByteArrayElements(data,
+ (jbyte *)buf, JNI_ABORT);
+
+ if (targetLost != NULL) {
+ e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
+ }
+
+ nfc_cb_data_deinit(&cb_data);
+
+ CONCURRENCY_UNLOCK();
+
+ return result;
+}
+
+static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o,
+ jint libnfcType, jint javaType)
+{
+ jint ndefType = NDEF_UNKNOWN_TYPE;
+
+ switch (libnfcType) {
+ case phNfc_eJewel_PICC:
+ ndefType = NDEF_TYPE1_TAG;
+ break;
+ case phNfc_eISO14443_3A_PICC:
+ ndefType = NDEF_TYPE2_TAG;;
+ break;
+ case phNfc_eFelica_PICC:
+ ndefType = NDEF_TYPE3_TAG;
+ break;
+ case phNfc_eISO14443_A_PICC:
+ case phNfc_eISO14443_4A_PICC:
+ case phNfc_eISO14443_B_PICC:
+ case phNfc_eISO14443_4B_PICC:
+ ndefType = NDEF_TYPE4_TAG;
+ break;
+ case phNfc_eMifare_PICC:
+ if (javaType == TARGET_TYPE_MIFARE_UL) {
+ ndefType = NDEF_TYPE2_TAG;
+ } else {
+ ndefType = NDEF_MIFARE_CLASSIC_TAG;
+ }
+ break;
+ case phNfc_eISO15693_PICC:
+ ndefType = NDEF_ICODE_SLI_TAG;
+ break;
+ default:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ }
+ return ndefType;
+}
+
+static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo)
+{
+ phLibNfc_Handle handle = 0;
+ jint status;
+ phLibNfc_ChkNdef_Info_t sNdefInfo;
+ struct nfc_jni_callback_data cb_data;
+ jint *ndef = e->GetIntArrayElements(ndefinfo, 0);
+ int apiCardState = NDEF_MODE_UNKNOWN;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ status = NFCSTATUS_NOT_ENOUGH_MEMORY;
+ goto clean_and_return;
+ }
+ cb_data.pContext = &sNdefInfo;
+
+ handle = nfc_jni_get_connected_handle(e, o);
+
+ TRACE("phLibNfc_Ndef_CheckNdef()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_ABORTED;
+ goto clean_and_return;
+ }
+
+ status = cb_data.status;
+ TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status);
+
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ ndef[0] = sNdefInfo.MaxNdefMsgLength;
+ // Translate the card state to know values for the NFC API
+ switch (sNdefInfo.NdefCardState) {
+ case PHLIBNFC_NDEF_CARD_INITIALISED:
+ apiCardState = NDEF_MODE_READ_WRITE;
+ break;
+ case PHLIBNFC_NDEF_CARD_READ_ONLY:
+ apiCardState = NDEF_MODE_READ_ONLY;
+ break;
+ case PHLIBNFC_NDEF_CARD_READ_WRITE:
+ apiCardState = NDEF_MODE_READ_WRITE;
+ break;
+ case PHLIBNFC_NDEF_CARD_INVALID:
+ apiCardState = NDEF_MODE_UNKNOWN;
+ break;
+ }
+ ndef[1] = apiCardState;
+
+clean_and_return:
+ e->ReleaseIntArrayElements(ndefinfo, ndef, 0);
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return status;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ handle = nfc_jni_get_connected_handle(e, o);
+
+ TRACE("phLibNfc_RemoteDev_CheckPresence()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if (cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+
+ CONCURRENCY_UNLOCK();
+
+ return result;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e,
+ jobject o, jbyteArray pollBytes, jbyteArray actBytes)
+{
+ // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire
+ // is supported.
+ jboolean result = JNI_FALSE;
+
+ // DESfire has one sak byte and 2 ATQA bytes
+ if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) &&
+ actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) {
+ jbyte* poll = e->GetByteArrayElements(pollBytes, NULL);
+ jbyte* act = e->GetByteArrayElements(actBytes, NULL);
+ if (act[0] == 0x20 && poll[1] == 0x03) {
+ uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00};
+ // Identifies as DESfire, use get version cmd to be sure
+ jbyteArray versionCmd = e->NewByteArray(5);
+ e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd);
+ jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o,
+ versionCmd, JNI_TRUE, NULL);
+ if (respBytes != NULL) {
+ // Check whether the response matches a typical DESfire
+ // response.
+ // libNFC even does more advanced checking than we do
+ // here, and will only format DESfire's with a certain
+ // major/minor sw version and NXP as a manufacturer.
+ // We don't want to do such checking here, to avoid
+ // having to change code in multiple places.
+ // A succesful (wrapped) DESFire getVersion command returns
+ // 9 bytes, with byte 7 0x91 and byte 8 having status
+ // code 0xAF (these values are fixed and well-known).
+ int respLength = e->GetArrayLength(respBytes);
+ jbyte* resp = e->GetByteArrayElements(respBytes, NULL);
+ if (respLength == 9 && resp[7] == (jbyte)0x91 &&
+ resp[8] == (jbyte)0xAF) {
+ result = JNI_TRUE;
+ }
+ e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT);
+ }
+ }
+ e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT);
+ e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT);
+ }
+
+ return result;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ phNfc_sData_t keyBuffer;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ handle = nfc_jni_get_connected_handle(e, o);
+
+ keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL);
+ keyBuffer.length = e->GetArrayLength(key);
+ TRACE("phLibNfc_RemoteDev_FormatNdef()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if (cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT);
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+ phNfc_sData_t keyBuffer;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ handle = nfc_jni_get_connected_handle(e, o);
+ keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL);
+ keyBuffer.length = e->GetArrayLength(key);
+ TRACE("phLibNfc_ConvertToReadOnlyNdef()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if (cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT);
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)I",
+ (void *)com_android_nfc_NativeNfcTag_doConnect},
+ {"doDisconnect", "()Z",
+ (void *)com_android_nfc_NativeNfcTag_doDisconnect},
+ {"doReconnect", "()I",
+ (void *)com_android_nfc_NativeNfcTag_doReconnect},
+ {"doHandleReconnect", "(I)I",
+ (void *)com_android_nfc_NativeNfcTag_doHandleReconnect},
+ {"doTransceive", "([BZ[I)[B",
+ (void *)com_android_nfc_NativeNfcTag_doTransceive},
+ {"doGetNdefType", "(II)I",
+ (void *)com_android_nfc_NativeNfcTag_doGetNdefType},
+ {"doCheckNdef", "([I)I",
+ (void *)com_android_nfc_NativeNfcTag_doCheckNdef},
+ {"doRead", "()[B",
+ (void *)com_android_nfc_NativeNfcTag_doRead},
+ {"doWrite", "([B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doWrite},
+ {"doPresenceCheck", "()Z",
+ (void *)com_android_nfc_NativeNfcTag_doPresenceCheck},
+ {"doIsIsoDepNdefFormatable", "([B[B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable},
+ {"doNdefFormat", "([B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doNdefFormat},
+ {"doMakeReadonly", "([B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doMakeReadonly},
+};
+
+int register_com_android_nfc_NativeNfcTag(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/nxp/NativeNfcTag",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp
new file mode 100644
index 0000000..b3cc6e3
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp
@@ -0,0 +1,490 @@
+
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include "com_android_nfc.h"
+
+extern uint8_t device_connected_flag;
+
+namespace android {
+
+extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat);
+
+/*
+ * Callbacks
+ */
+static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_presence_check_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_connect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext;
+ LOG_CALLBACK("nfc_jni_connect_callback", status);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;
+ psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length);
+ psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo;
+ }
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_disconnect_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext;
+ LOG_CALLBACK("nfc_jni_receive_callback", status);
+
+ if(status == NFCSTATUS_SUCCESS)
+ {
+ *ptr = data;
+ }
+ else
+ {
+ *ptr = NULL;
+ }
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_send_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+/*
+ * Functions
+ */
+
+static void nfc_jni_transceive_callback(void *pContext,
+ phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_transceive_callback", status);
+
+ /* Report the callback data and wake up the caller */
+ pCallbackData->pContext = pResBuffer;
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ jclass target_cls = NULL;
+ jobject tag;
+ jmethodID ctor;
+ jfieldID f;
+ jbyteArray generalBytes = NULL;
+ phNfc_sData_t sGeneralBytes;
+ unsigned int i;
+
+ CONCURRENCY_LOCK();
+
+ handle = nfc_jni_get_p2p_device_handle(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes))
+ {
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Connect(P2P)");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ /* Set General Bytes */
+ target_cls = e->GetObjectClass(o);
+
+ f = e->GetFieldID(target_cls, "mGeneralBytes", "[B");
+
+ TRACE("General Bytes Length = %d", sGeneralBytes.length);
+ TRACE("General Bytes =");
+ for(i=0;i<sGeneralBytes.length;i++)
+ {
+ TRACE("0x%02x ", sGeneralBytes.buffer[i]);
+ }
+
+ generalBytes = e->NewByteArray(sGeneralBytes.length);
+
+ e->SetByteArrayRegion(generalBytes, 0,
+ sGeneralBytes.length,
+ (jbyte *)sGeneralBytes.buffer);
+
+ e->SetObjectField(o, f, generalBytes);
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ if (result != JNI_TRUE)
+ {
+ /* Restart the polling loop if the connection failed */
+ nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
+ }
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o)
+{
+ phLibNfc_Handle handle = 0;
+ jboolean result = JNI_FALSE;
+ NFCSTATUS status;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ handle = nfc_jni_get_p2p_device_handle(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Disconnect */
+ TRACE("Disconnecting from target (handle = 0x%x)", handle);
+
+ /* NativeNfcTag waits for tag to leave the field here with presence check.
+ * We do not in P2P path because presence check is not safe while transceive may be
+ * in progress.
+ */
+
+ TRACE("phLibNfc_RemoteDev_Disconnect()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
+ {
+ ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected");
+ }
+ else
+ {
+ ALOGE("phLibNfc_RemoteDev_Disconnect() failed");
+ nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
+ }
+
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Disconnect Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ /* Reset device connected flag */
+ device_connected_flag = 0;
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
+ jobject o, jbyteArray data)
+{
+ NFCSTATUS status;
+ uint8_t offset = 2;
+ uint8_t *buf;
+ uint32_t buflen;
+ phLibNfc_sTransceiveInfo_t transceive_info;
+ jbyteArray result = NULL;
+ phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
+ phNfc_sData_t * receive_buffer = NULL;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer))
+ {
+ goto clean_and_return;
+ }
+
+ /* Transceive*/
+ TRACE("Transceive data to target (handle = 0x%x)", handle);
+
+ buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
+ buflen = (uint32_t)e->GetArrayLength(data);
+
+ TRACE("Buffer Length = %d\n", buflen);
+
+ transceive_info.sSendData.buffer = buf; //+ offset;
+ transceive_info.sSendData.length = buflen; //- offset;
+ transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
+ transceive_info.sRecvData.length = 1024;
+
+ if(transceive_info.sRecvData.buffer == NULL)
+ {
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Transceive(P2P)");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ /* Copy results back to Java */
+ result = e->NewByteArray(receive_buffer->length);
+ if(result != NULL)
+ e->SetByteArrayRegion(result, 0,
+ receive_buffer->length,
+ (jbyte *)receive_buffer->buffer);
+
+clean_and_return:
+ if(transceive_info.sRecvData.buffer != NULL)
+ {
+ free(transceive_info.sRecvData.buffer);
+ }
+
+ e->ReleaseByteArrayElements(data,
+ (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
+
+ nfc_cb_data_deinit(&cb_data);
+
+ CONCURRENCY_UNLOCK();
+
+ return result;
+}
+
+
+static jbyteArray com_android_nfc_NativeP2pDevice_doReceive(
+ JNIEnv *e, jobject o)
+{
+ NFCSTATUS status;
+ struct timespec ts;
+ phLibNfc_Handle handle;
+ jbyteArray buf = NULL;
+ static phNfc_sData_t *data;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ handle = nfc_jni_get_p2p_device_handle(e, o);
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, (void*)data))
+ {
+ goto clean_and_return;
+ }
+
+ /* Receive */
+ TRACE("phLibNfc_RemoteDev_Receive()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(data == NULL)
+ {
+ goto clean_and_return;
+ }
+
+ buf = e->NewByteArray(data->length);
+ e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return buf;
+}
+
+static jboolean com_android_nfc_NativeP2pDevice_doSend(
+ JNIEnv *e, jobject o, jbyteArray buf)
+{
+ NFCSTATUS status;
+ phNfc_sData_t data;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Send */
+ TRACE("Send data to the Initiator (handle = 0x%x)", handle);
+
+ data.length = (uint32_t)e->GetArrayLength(buf);
+ data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
+
+ TRACE("phLibNfc_RemoteDev_Send()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ if (result != JNI_TRUE)
+ {
+ e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT);
+ }
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "()Z",
+ (void *)com_android_nfc_NativeP2pDevice_doConnect},
+ {"doDisconnect", "()Z",
+ (void *)com_android_nfc_NativeP2pDevice_doDisconnect},
+ {"doTransceive", "([B)[B",
+ (void *)com_android_nfc_NativeP2pDevice_doTransceive},
+ {"doReceive", "()[B",
+ (void *)com_android_nfc_NativeP2pDevice_doReceive},
+ {"doSend", "([B)Z",
+ (void *)com_android_nfc_NativeP2pDevice_doSend},
+};
+
+int register_com_android_nfc_NativeP2pDevice(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/nxp/NativeP2pDevice",
+ gMethods, NELEM(gMethods));
+}
+
+} // namepspace android
diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp
new file mode 100644
index 0000000..f0487d3
--- /dev/null
+++ b/nxp/jni/com_android_nfc_list.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <com_android_nfc_list.h>
+#include <com_android_nfc.h>
+#include <pthread.h>
+#include <errno.h>
+#include <cutils/log.h>
+
+#undef LOG_TAG
+#define LOG_TAG "NFC_LIST"
+
+bool listInit(listHead* pList)
+{
+ pList->pFirst = NULL;
+ if(pthread_mutex_init(&pList->mutex, NULL) == -1)
+ {
+ ALOGE("Mutex creation failed (errno=0x%08x)", errno);
+ return false;
+ }
+
+ return true;
+}
+
+bool listDestroy(listHead* pList)
+{
+ bool bListNotEmpty = true;
+ while (bListNotEmpty) {
+ bListNotEmpty = listGetAndRemoveNext(pList, NULL);
+ }
+
+ if(pthread_mutex_destroy(&pList->mutex) == -1)
+ {
+ ALOGE("Mutex destruction failed (errno=0x%08x)", errno);
+ return false;
+ }
+
+ return true;
+}
+
+bool listAdd(listHead* pList, void* pData)
+{
+ struct listNode* pNode;
+ struct listNode* pLastNode;
+ bool result;
+
+ /* Create node */
+ pNode = (struct listNode*)malloc(sizeof(listNode));
+ if (pNode == NULL)
+ {
+ result = false;
+ ALOGE("Failed to malloc");
+ goto clean_and_return;
+ }
+ TRACE("Allocated node: %8p (%8p)", pNode, pData);
+ pNode->pData = pData;
+ pNode->pNext = NULL;
+
+ pthread_mutex_lock(&pList->mutex);
+
+ /* Add the node to the list */
+ if (pList->pFirst == NULL)
+ {
+ /* Set the node as the head */
+ pList->pFirst = pNode;
+ }
+ else
+ {
+ /* Seek to the end of the list */
+ pLastNode = pList->pFirst;
+ while(pLastNode->pNext != NULL)
+ {
+ pLastNode = pLastNode->pNext;
+ }
+
+ /* Add the node to the current list */
+ pLastNode->pNext = pNode;
+ }
+
+ result = true;
+
+clean_and_return:
+ pthread_mutex_unlock(&pList->mutex);
+ return result;
+}
+
+bool listRemove(listHead* pList, void* pData)
+{
+ struct listNode* pNode;
+ struct listNode* pRemovedNode;
+ bool result;
+
+ pthread_mutex_lock(&pList->mutex);
+
+ if (pList->pFirst == NULL)
+ {
+ /* Empty list */
+ ALOGE("Failed to deallocate (list empty)");
+ result = false;
+ goto clean_and_return;
+ }
+
+ pNode = pList->pFirst;
+ if (pList->pFirst->pData == pData)
+ {
+ /* Get the removed node */
+ pRemovedNode = pNode;
+
+ /* Remove the first node */
+ pList->pFirst = pList->pFirst->pNext;
+ }
+ else
+ {
+ while (pNode->pNext != NULL)
+ {
+ if (pNode->pNext->pData == pData)
+ {
+ /* Node found ! */
+ break;
+ }
+ pNode = pNode->pNext;
+ }
+
+ if (pNode->pNext == NULL)
+ {
+ /* Node not found */
+ result = false;
+ ALOGE("Failed to deallocate (not found %8p)", pData);
+ goto clean_and_return;
+ }
+
+ /* Get the removed node */
+ pRemovedNode = pNode->pNext;
+
+ /* Remove the node from the list */
+ pNode->pNext = pNode->pNext->pNext;
+ }
+
+ /* Deallocate the node */
+ TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData);
+ free(pRemovedNode);
+
+ result = true;
+
+clean_and_return:
+ pthread_mutex_unlock(&pList->mutex);
+ return result;
+}
+
+bool listGetAndRemoveNext(listHead* pList, void** ppData)
+{
+ struct listNode* pNode;
+ bool result;
+
+ pthread_mutex_lock(&pList->mutex);
+
+ if (pList->pFirst)
+ {
+ /* Empty list */
+ ALOGE("Failed to deallocate (list empty)");
+ result = false;
+ goto clean_and_return;
+ }
+
+ /* Work on the first node */
+ pNode = pList->pFirst;
+
+ /* Return the data */
+ if (ppData != NULL)
+ {
+ *ppData = pNode->pData;
+ }
+
+ /* Remove and deallocate the node */
+ pList->pFirst = pNode->pNext;
+ TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData);
+ free(pNode);
+
+ result = true;
+
+clean_and_return:
+ listDump(pList);
+ pthread_mutex_unlock(&pList->mutex);
+ return result;
+}
+
+void listDump(listHead* pList)
+{
+ struct listNode* pNode = pList->pFirst;
+
+ TRACE("Node dump:");
+ while (pNode != NULL)
+ {
+ TRACE("- %8p (%8p)", pNode, pNode->pData);
+ pNode = pNode->pNext;
+ }
+}
diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h
new file mode 100644
index 0000000..22b4f09
--- /dev/null
+++ b/nxp/jni/com_android_nfc_list.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COM_ANDROID_NFC_LIST_H__
+#define __COM_ANDROID_NFC_LIST_H__
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct listNode
+{
+ void* pData;
+ struct listNode* pNext;
+};
+
+struct listHead
+{
+ listNode* pFirst;
+ pthread_mutex_t mutex;
+};
+
+bool listInit(listHead* pList);
+bool listDestroy(listHead* pList);
+bool listAdd(listHead* pList, void* pData);
+bool listRemove(listHead* pList, void* pData);
+bool listGetAndRemoveNext(listHead* pList, void** ppData);
+void listDump(listHead* pList);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __COM_ANDROID_NFC_LIST_H__ */
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java
new file mode 100755
index 0000000..db78496
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+import com.android.nfc.LlcpPacket;
+
+import java.io.IOException;
+
+/**
+ * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used
+ * in a connectionless communication
+ */
+public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket {
+
+ private int mHandle;
+ private int mSap;
+ private int mLinkMiu;
+
+ public NativeLlcpConnectionlessSocket() { }
+
+ public native boolean doSendTo(int sap, byte[] data);
+
+ public native LlcpPacket doReceiveFrom(int linkMiu);
+
+ public native boolean doClose();
+
+ @Override
+ public int getLinkMiu(){
+ return mLinkMiu;
+ }
+
+ @Override
+ public int getSap(){
+ return mSap;
+ }
+
+ @Override
+ public void send(int sap, byte[] data) throws IOException {
+ if (!doSendTo(sap, data)) {
+ throw new IOException();
+ }
+ }
+
+ @Override
+ public LlcpPacket receive() throws IOException {
+ LlcpPacket packet = doReceiveFrom(mLinkMiu);
+ if (packet == null) {
+ throw new IOException();
+ }
+ return packet;
+ }
+
+ public int getHandle(){
+ return mHandle;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (!doClose()) {
+ throw new IOException();
+ }
+ }
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java
new file mode 100755
index 0000000..3a7e57f
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+import com.android.nfc.DeviceHost.LlcpSocket;
+
+import java.io.IOException;
+
+/**
+ * LlcpServiceSocket represents a LLCP Service to be used in a
+ * Connection-oriented communication
+ */
+public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket {
+ private int mHandle;
+ private int mLocalMiu;
+ private int mLocalRw;
+ private int mLocalLinearBufferLength;
+ private int mSap;
+ private String mServiceName;
+
+ public NativeLlcpServiceSocket(){ }
+
+ private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength);
+ @Override
+ public LlcpSocket accept() throws IOException {
+ LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength);
+ if (socket == null) throw new IOException();
+ return socket;
+ }
+
+ private native boolean doClose();
+ @Override
+ public void close() throws IOException {
+ if (!doClose()) {
+ throw new IOException();
+ }
+ }
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java
new file mode 100755
index 0000000..69506c5
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+
+import java.io.IOException;
+
+/**
+ * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a
+ * connection-oriented communication
+ */
+public class NativeLlcpSocket implements DeviceHost.LlcpSocket {
+ private int mHandle;
+ private int mSap;
+ private int mLocalMiu;
+ private int mLocalRw;
+
+ public NativeLlcpSocket(){ }
+
+ private native boolean doConnect(int nSap);
+ @Override
+ public void connectToSap(int sap) throws IOException {
+ if (!doConnect(sap)) {
+ throw new IOException();
+ }
+ }
+
+ private native boolean doConnectBy(String sn);
+ @Override
+ public void connectToService(String serviceName) throws IOException {
+ if (!doConnectBy(serviceName)) {
+ throw new IOException();
+ }
+ }
+
+ private native boolean doClose();
+ @Override
+ public void close() throws IOException {
+ if (!doClose()) {
+ throw new IOException();
+ }
+ }
+
+ private native boolean doSend(byte[] data);
+ @Override
+ public void send(byte[] data) throws IOException {
+ if (!doSend(data)) {
+ throw new IOException();
+ }
+ }
+
+ private native int doReceive(byte[] recvBuff);
+ @Override
+ public int receive(byte[] recvBuff) throws IOException {
+ int receiveLength = doReceive(recvBuff);
+ if (receiveLength == -1) {
+ throw new IOException();
+ }
+ return receiveLength;
+ }
+
+ private native int doGetRemoteSocketMiu();
+ @Override
+ public int getRemoteMiu() { return doGetRemoteSocketMiu(); }
+
+ private native int doGetRemoteSocketRw();
+ @Override
+ public int getRemoteRw() { return doGetRemoteSocketRw(); }
+
+ @Override
+ public int getLocalSap(){
+ return mSap;
+ }
+
+ @Override
+ public int getLocalMiu(){
+ return mLocalMiu;
+ }
+
+ @Override
+ public int getLocalRw(){
+ return mLocalRw;
+ }
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
new file mode 100755
index 0000000..f969627
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+import com.android.nfc.LlcpException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.nfc.ErrorCodes;
+import android.nfc.tech.Ndef;
+import android.nfc.tech.TagTechnology;
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ * Native interface to the NFC Manager functions
+ */
+public class NativeNfcManager implements DeviceHost {
+ private static final String TAG = "NativeNfcManager";
+
+ private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
+
+ static final String PREF = "NxpDeviceHost";
+
+ private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
+ private static final long FIRMWARE_MODTIME_DEFAULT = -1;
+
+ static {
+ System.loadLibrary("nfc_jni");
+ }
+
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
+
+ /* Native structure */
+ private int mNative;
+
+ private final DeviceHostListener mListener;
+ private final Context mContext;
+
+ public NativeNfcManager(Context context, DeviceHostListener listener) {
+ mListener = listener;
+ initializeNativeStructure();
+ mContext = context;
+ }
+
+ public native boolean initializeNativeStructure();
+
+ private native boolean doDownload();
+
+ public native int doGetLastError();
+
+ @Override
+ public void checkFirmware() {
+ // Check that the NFC controller firmware is up to date. This
+ // ensures that firmware updates are applied in a timely fashion,
+ // and makes it much less likely that the user will have to wait
+ // for a firmware download when they enable NFC in the settings
+ // app. Firmware download can take some time, so this should be
+ // run in a separate thread.
+
+ // check the timestamp of the firmware file
+ File firmwareFile;
+ int nbRetry = 0;
+ try {
+ firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
+ } catch(NullPointerException npe) {
+ Log.e(TAG,"path to firmware file was null");
+ return;
+ }
+
+ long modtime = firmwareFile.lastModified();
+
+ SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
+ Log.d(TAG,"prev modtime: " + prev_fw_modtime);
+ Log.d(TAG,"new modtime: " + modtime);
+ if (prev_fw_modtime == modtime) {
+ return;
+ }
+
+ // FW download.
+ while(nbRetry < 5) {
+ Log.d(TAG,"Perform Download");
+ if(doDownload()) {
+ Log.d(TAG,"Download Success");
+ // Now that we've finished updating the firmware, save the new modtime.
+ prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
+ break;
+ } else {
+ Log.d(TAG,"Download Failed");
+ nbRetry++;
+ }
+ }
+ }
+
+ private native boolean doInitialize();
+
+ @Override
+ public boolean initialize() {
+ SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+
+ if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
+ try {
+ Thread.sleep (12000);
+ editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
+ editor.apply();
+ } catch (InterruptedException e) { }
+ }
+
+ return doInitialize();
+ }
+
+ private native boolean doDeinitialize();
+
+ @Override
+ public boolean deinitialize() {
+ SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+
+ editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
+ editor.apply();
+
+ return doDeinitialize();
+ }
+
+ @Override
+ public native void enableDiscovery();
+
+ @Override
+ public native void disableDiscovery();
+
+ @Override
+ public native int[] doGetSecureElementList();
+
+ @Override
+ public native void doSelectSecureElement();
+
+ @Override
+ public native void doDeselectSecureElement();
+
+
+ private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
+ String sn);
+
+ @Override
+ public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
+ throws LlcpException {
+ LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
+ if (socket != null) {
+ return socket;
+ } else {
+ /* Get Error Status */
+ int error = doGetLastError();
+
+ Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
+
+ switch (error) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ throw new LlcpException(error);
+ default:
+ throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
+ }
+ }
+ }
+
+ private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
+ int rw, int linearBufferLength);
+ @Override
+ public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
+ int rw, int linearBufferLength) throws LlcpException {
+ LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
+ if (socket != null) {
+ return socket;
+ } else {
+ /* Get Error Status */
+ int error = doGetLastError();
+
+ Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
+
+ switch (error) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ throw new LlcpException(error);
+ default:
+ throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
+ }
+ }
+ }
+
+ private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
+ int linearBufferLength);
+ @Override
+ public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
+ int linearBufferLength) throws LlcpException {
+ LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
+ if (socket != null) {
+ return socket;
+ } else {
+ /* Get Error Status */
+ int error = doGetLastError();
+
+ Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
+
+ switch (error) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ throw new LlcpException(error);
+ default:
+ throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
+ }
+ }
+ }
+
+ @Override
+ public native boolean doCheckLlcp();
+
+ @Override
+ public native boolean doActivateLlcp();
+
+ private native void doResetTimeouts();
+
+ @Override
+ public void resetTimeouts() {
+ doResetTimeouts();
+ }
+
+ @Override
+ public native void doAbort();
+
+ private native boolean doSetTimeout(int tech, int timeout);
+ @Override
+ public boolean setTimeout(int tech, int timeout) {
+ return doSetTimeout(tech, timeout);
+ }
+
+ private native int doGetTimeout(int tech);
+ @Override
+ public int getTimeout(int tech) {
+ return doGetTimeout(tech);
+ }
+
+
+ @Override
+ public boolean canMakeReadOnly(int ndefType) {
+ return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
+ ndefType == Ndef.TYPE_MIFARE_CLASSIC);
+ }
+
+ @Override
+ public int getMaxTransceiveLength(int technology) {
+ switch (technology) {
+ case (TagTechnology.NFC_A):
+ case (TagTechnology.MIFARE_CLASSIC):
+ case (TagTechnology.MIFARE_ULTRALIGHT):
+ return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
+ case (TagTechnology.NFC_B):
+ return 0; // PN544 does not support transceive of raw NfcB
+ case (TagTechnology.NFC_V):
+ return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
+ case (TagTechnology.ISO_DEP):
+ /* The maximum length of a normal IsoDep frame consists of:
+ * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
+ * such a frame is supported. Extended length frames however
+ * are not supported.
+ */
+ return 261; // Will be automatically split in two frames on the RF layer
+ case (TagTechnology.NFC_F):
+ return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
+ default:
+ return 0;
+ }
+
+ }
+
+ private native void doSetP2pInitiatorModes(int modes);
+ @Override
+ public void setP2pInitiatorModes(int modes) {
+ doSetP2pInitiatorModes(modes);
+ }
+
+ private native void doSetP2pTargetModes(int modes);
+ @Override
+ public void setP2pTargetModes(int modes) {
+ doSetP2pTargetModes(modes);
+ }
+
+ public boolean getExtendedLengthApdusSupported() {
+ // Not supported on the PN544
+ return false;
+ }
+
+ private native String doDump();
+ @Override
+ public String dump() {
+ return doDump();
+ }
+
+ /**
+ * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
+ */
+ private void notifyNdefMessageListeners(NativeNfcTag tag) {
+ mListener.onRemoteEndpointDiscovered(tag);
+ }
+
+ /**
+ * Notifies transaction
+ */
+ private void notifyTargetDeselected() {
+ mListener.onCardEmulationDeselected();
+ }
+
+ /**
+ * Notifies transaction
+ */
+ private void notifyTransactionListeners(byte[] aid) {
+ mListener.onCardEmulationAidSelected(aid);
+ }
+
+ /**
+ * Notifies P2P Device detected, to activate LLCP link
+ */
+ private void notifyLlcpLinkActivation(NativeP2pDevice device) {
+ mListener.onLlcpLinkActivated(device);
+ }
+
+ /**
+ * Notifies P2P Device detected, to activate LLCP link
+ */
+ private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
+ mListener.onLlcpLinkDeactivated(device);
+ }
+
+ private void notifySeFieldActivated() {
+ mListener.onRemoteFieldActivated();
+ }
+
+ private void notifySeFieldDeactivated() {
+ mListener.onRemoteFieldDeactivated();
+ }
+
+ private void notifySeApduReceived(byte[] apdu) {
+ mListener.onSeApduReceived(apdu);
+ }
+
+ private void notifySeEmvCardRemoval() {
+ mListener.onSeEmvCardRemoval();
+ }
+
+ private void notifySeMifareAccess(byte[] block) {
+ mListener.onSeMifareAccess(block);
+ }
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java
new file mode 100755
index 0000000..e2d91ec
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+
+/**
+ * Native interface to the NFC Secure Element functions
+ *
+ * {@hide}
+ */
+public class NativeNfcSecureElement {
+
+ static final String PREF_SE_WIRED = "se_wired";
+
+ private final Context mContext;
+
+ SharedPreferences mPrefs;
+ SharedPreferences.Editor mPrefsEditor;
+
+ public NativeNfcSecureElement(Context context) {
+ mContext = context;
+
+ mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE);
+ mPrefsEditor = mPrefs.edit();
+ }
+
+ private native int doNativeOpenSecureElementConnection();
+
+ public int doOpenSecureElementConnection() {
+ mPrefsEditor.putBoolean(PREF_SE_WIRED, true);
+ mPrefsEditor.apply();
+
+ return doNativeOpenSecureElementConnection();
+ }
+
+ private native boolean doNativeDisconnectSecureElementConnection(int handle);
+
+ public boolean doDisconnect(int handle) {
+ mPrefsEditor.putBoolean(PREF_SE_WIRED, false);
+ mPrefsEditor.apply();
+
+ return doNativeDisconnectSecureElementConnection(handle);
+ }
+
+ public native byte[] doTransceive(int handle, byte[] data);
+
+ public native int[] doGetTechList(int handle);
+
+ public native byte [] doGetUid(int handle);
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java
new file mode 100755
index 0000000..eddde94
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java
@@ -0,0 +1,803 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost.TagEndpoint;
+
+import android.nfc.FormatException;
+import android.nfc.NdefMessage;
+import android.nfc.tech.IsoDep;
+import android.nfc.tech.MifareClassic;
+import android.nfc.tech.MifareUltralight;
+import android.nfc.tech.Ndef;
+import android.nfc.tech.NfcA;
+import android.nfc.tech.NfcB;
+import android.nfc.tech.NfcF;
+import android.nfc.tech.NfcV;
+import android.nfc.tech.TagTechnology;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * Native interface to the NFC tag functions
+ */
+public class NativeNfcTag implements TagEndpoint {
+ static final boolean DBG = false;
+
+ static final int STATUS_CODE_TARGET_LOST = 146;
+
+ private int[] mTechList;
+ private int[] mTechHandles;
+ private int[] mTechLibNfcTypes;
+ private Bundle[] mTechExtras;
+ private byte[][] mTechPollBytes;
+ private byte[][] mTechActBytes;
+ private byte[] mUid;
+
+ // mConnectedHandle stores the *real* libnfc handle
+ // that we're connected to.
+ private int mConnectedHandle;
+
+ // mConnectedTechIndex stores to which technology
+ // the upper layer stack is connected. Note that
+ // we may be connected to a libnfchandle without being
+ // connected to a technology - technology changes
+ // may occur runtime, whereas the underlying handle
+ // could stay present. Usually all technologies are on the
+ // same handle, with the exception of multi-protocol
+ // tags.
+ private int mConnectedTechIndex; // Index in mTechHandles
+
+ private final String TAG = "NativeNfcTag";
+
+ private boolean mIsPresent; // Whether the tag is known to be still present
+
+ private PresenceCheckWatchdog mWatchdog;
+ class PresenceCheckWatchdog extends Thread {
+
+ private int watchdogTimeout = 125;
+
+ private boolean isPresent = true;
+ private boolean isStopped = false;
+ private boolean isPaused = false;
+ private boolean doCheck = true;
+
+ public synchronized void pause() {
+ isPaused = true;
+ doCheck = false;
+ this.notifyAll();
+ }
+
+ public synchronized void doResume() {
+ isPaused = false;
+ // We don't want to resume presence checking immediately,
+ // but go through at least one more wait period.
+ doCheck = false;
+ this.notifyAll();
+ }
+
+ public synchronized void end() {
+ isStopped = true;
+ doCheck = false;
+ this.notifyAll();
+ }
+
+ public synchronized void setTimeout(int timeout) {
+ watchdogTimeout = timeout;
+ doCheck = false; // Do it only after we have waited "timeout" ms again
+ this.notifyAll();
+ }
+
+ @Override
+ public synchronized void run() {
+ if (DBG) Log.d(TAG, "Starting background presence check");
+ while (isPresent && !isStopped) {
+ try {
+ if (!isPaused) {
+ doCheck = true;
+ }
+ this.wait(watchdogTimeout);
+ if (doCheck) {
+ isPresent = doPresenceCheck();
+ } else {
+ // 1) We are paused, waiting for unpause
+ // 2) We just unpaused, do pres check in next iteration
+ // (after watchdogTimeout ms sleep)
+ // 3) We just set the timeout, wait for this timeout
+ // to expire once first.
+ // 4) We just stopped, exit loop anyway
+ }
+ } catch (InterruptedException e) {
+ // Activity detected, loop
+ }
+ }
+ mIsPresent = false;
+ // Restart the polling loop
+
+ Log.d(TAG, "Tag lost, restarting polling loop");
+ doDisconnect();
+ if (DBG) Log.d(TAG, "Stopping background presence check");
+ }
+ }
+
+ private native int doConnect(int handle);
+ public synchronized int connectWithStatus(int technology) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = -1;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == technology) {
+ // Get the handle and connect, if not already connected
+ if (mConnectedHandle != mTechHandles[i]) {
+ // We're not yet connected to this handle, there are
+ // a few scenario's here:
+ // 1) We are not connected to anything yet - allow
+ // 2) We are connected to a technology which has
+ // a different handle (multi-protocol tag); we support
+ // switching to that.
+ if (mConnectedHandle == -1) {
+ // Not connected yet
+ status = doConnect(mTechHandles[i]);
+ } else {
+ // Connect to a tech with a different handle
+ status = reconnectWithStatus(mTechHandles[i]);
+ }
+ if (status == 0) {
+ mConnectedHandle = mTechHandles[i];
+ mConnectedTechIndex = i;
+ }
+ } else {
+ // 1) We are connected to a technology which has the same
+ // handle; we do not support connecting at a different
+ // level (libnfc auto-activates to the max level on
+ // any handle).
+ // 2) We are connecting to the ndef technology - always
+ // allowed.
+ if ((technology == TagTechnology.NDEF) ||
+ (technology == TagTechnology.NDEF_FORMATABLE)) {
+ status = 0;
+ } else {
+ if ((technology != TagTechnology.ISO_DEP) &&
+ (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) {
+ // Don't allow to connect a -4 tag at a different level
+ // than IsoDep, as this is not supported by
+ // libNFC.
+ status = -1;
+ } else {
+ status = 0;
+ }
+ }
+ if (status == 0) {
+ mConnectedTechIndex = i;
+ // Handle was already identical
+ }
+ }
+ break;
+ }
+ }
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+ @Override
+ public synchronized boolean connect(int technology) {
+ return connectWithStatus(technology) == 0;
+ }
+
+ @Override
+ public synchronized void startPresenceChecking() {
+ // Once we start presence checking, we allow the upper layers
+ // to know the tag is in the field.
+ mIsPresent = true;
+ if (mWatchdog == null) {
+ mWatchdog = new PresenceCheckWatchdog();
+ mWatchdog.start();
+ }
+ }
+
+ @Override
+ public synchronized boolean isPresent() {
+ // Returns whether the tag is still in the field to the best
+ // of our knowledge.
+ return mIsPresent;
+ }
+ native boolean doDisconnect();
+ @Override
+ public synchronized boolean disconnect() {
+ boolean result = false;
+
+ mIsPresent = false;
+ if (mWatchdog != null) {
+ // Watchdog has already disconnected or will do it
+ mWatchdog.end();
+ try {
+ mWatchdog.join();
+ } catch (InterruptedException e) {
+ // Should never happen.
+ }
+ mWatchdog = null;
+ result = true;
+ } else {
+ result = doDisconnect();
+ }
+
+ mConnectedTechIndex = -1;
+ mConnectedHandle = -1;
+ return result;
+ }
+
+ native int doReconnect();
+ public synchronized int reconnectWithStatus() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = doReconnect();
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+ @Override
+ public synchronized boolean reconnect() {
+ return reconnectWithStatus() == 0;
+ }
+
+ native int doHandleReconnect(int handle);
+ public synchronized int reconnectWithStatus(int handle) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = doHandleReconnect(handle);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+
+ private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode);
+ @Override
+ public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ byte[] result = doTransceive(data, raw, returnCode);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ private native int doCheckNdef(int[] ndefinfo);
+ private synchronized int checkNdefWithStatus(int[] ndefinfo) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = doCheckNdef(ndefinfo);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+ @Override
+ public synchronized boolean checkNdef(int[] ndefinfo) {
+ return checkNdefWithStatus(ndefinfo) == 0;
+ }
+
+ private native byte[] doRead();
+ @Override
+ public synchronized byte[] readNdef() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ byte[] result = doRead();
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ private native boolean doWrite(byte[] buf);
+ @Override
+ public synchronized boolean writeNdef(byte[] buf) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result = doWrite(buf);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doPresenceCheck();
+ @Override
+ public synchronized boolean presenceCheck() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result = doPresenceCheck();
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doNdefFormat(byte[] key);
+ @Override
+ public synchronized boolean formatNdef(byte[] key) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result = doNdefFormat(key);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doMakeReadonly(byte[] key);
+ @Override
+ public synchronized boolean makeReadOnly() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result;
+ if (hasTech(TagTechnology.MIFARE_CLASSIC)) {
+ result = doMakeReadonly(MifareClassic.KEY_DEFAULT);
+ } else {
+ // No key needed for other technologies
+ result = doMakeReadonly(new byte[] {});
+ }
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act);
+ @Override
+ public synchronized boolean isNdefFormatable() {
+ if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) {
+ // These are always formatable
+ return true;
+ }
+ if (hasTech(TagTechnology.NFC_V)) {
+ // Currently libnfc only formats NXP NFC-V tags
+ if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // For ISO-DEP, call native code to determine at lower level if format
+ // is possible. It will need NFC-A poll/activation time bytes for this.
+ if (hasTech(TagTechnology.ISO_DEP)) {
+ int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A);
+ if (nfcaTechIndex != -1) {
+ return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex],
+ mTechActBytes[nfcaTechIndex]);
+ } else {
+ return false;
+ }
+ } else {
+ // Formatting not supported by libNFC
+ return false;
+ }
+ }
+
+ @Override
+ public int getHandle() {
+ // This is just a handle for the clients; it can simply use the first
+ // technology handle we have.
+ if (mTechHandles.length > 0) {
+ return mTechHandles[0];
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public byte[] getUid() {
+ return mUid;
+ }
+
+ @Override
+ public int[] getTechList() {
+ return mTechList;
+ }
+
+ private int getConnectedHandle() {
+ return mConnectedHandle;
+ }
+
+ private int getConnectedLibNfcType() {
+ if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) {
+ return mTechLibNfcTypes[mConnectedTechIndex];
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int getConnectedTechnology() {
+ if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) {
+ return mTechList[mConnectedTechIndex];
+ } else {
+ return 0;
+ }
+ }
+ native int doGetNdefType(int libnfctype, int javatype);
+ private int getNdefType(int libnfctype, int javatype) {
+ return doGetNdefType(libnfctype, javatype);
+ }
+
+ private void addTechnology(int tech, int handle, int libnfctype) {
+ int[] mNewTechList = new int[mTechList.length + 1];
+ System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length);
+ mNewTechList[mTechList.length] = tech;
+ mTechList = mNewTechList;
+
+ int[] mNewHandleList = new int[mTechHandles.length + 1];
+ System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length);
+ mNewHandleList[mTechHandles.length] = handle;
+ mTechHandles = mNewHandleList;
+
+ int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1];
+ System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length);
+ mNewTypeList[mTechLibNfcTypes.length] = libnfctype;
+ mTechLibNfcTypes = mNewTypeList;
+ }
+
+ @Override
+ public void removeTechnology(int tech) {
+ synchronized (this) {
+ int techIndex = getTechIndex(tech);
+ if (techIndex != -1) {
+ int[] mNewTechList = new int[mTechList.length - 1];
+ System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex);
+ System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex,
+ mTechList.length - techIndex - 1);
+ mTechList = mNewTechList;
+
+ int[] mNewHandleList = new int[mTechHandles.length - 1];
+ System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex);
+ System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex,
+ mTechHandles.length - techIndex - 1);
+ mTechHandles = mNewHandleList;
+
+ int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1];
+ System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex);
+ System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex,
+ mTechLibNfcTypes.length - techIndex - 1);
+ mTechLibNfcTypes = mNewTypeList;
+ }
+ }
+ }
+
+ public void addNdefFormatableTechnology(int handle, int libnfcType) {
+ synchronized (this) {
+ addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType);
+ }
+ }
+
+ // This method exists to "patch in" the ndef technologies,
+ // which is done inside Java instead of the native JNI code.
+ // To not create some nasty dependencies on the order on which things
+ // are called (most notably getTechExtras()), it needs some additional
+ // checking.
+ public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType,
+ int javaType, int maxLength, int cardState) {
+ synchronized (this) {
+ addTechnology(TagTechnology.NDEF, handle, libnfcType);
+
+ Bundle extras = new Bundle();
+ extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg);
+ extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength);
+ extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState);
+ extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType));
+
+ if (mTechExtras == null) {
+ // This will build the tech extra's for the first time,
+ // including a NULL ref for the NDEF tech we generated above.
+ Bundle[] builtTechExtras = getTechExtras();
+ builtTechExtras[builtTechExtras.length - 1] = extras;
+ }
+ else {
+ // Tech extras were built before, patch the NDEF one in
+ Bundle[] oldTechExtras = getTechExtras();
+ Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1];
+ System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length);
+ newTechExtras[oldTechExtras.length] = extras;
+ mTechExtras = newTechExtras;
+ }
+
+
+ }
+ }
+
+ private int getTechIndex(int tech) {
+ int techIndex = -1;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == tech) {
+ techIndex = i;
+ break;
+ }
+ }
+ return techIndex;
+ }
+
+ private boolean hasTech(int tech) {
+ boolean hasTech = false;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == tech) {
+ hasTech = true;
+ break;
+ }
+ }
+ return hasTech;
+ }
+
+ private boolean hasTechOnHandle(int tech, int handle) {
+ boolean hasTech = false;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == tech && mTechHandles[i] == handle) {
+ hasTech = true;
+ break;
+ }
+ }
+ return hasTech;
+
+ }
+
+ private boolean isUltralightC() {
+ /* Make a best-effort attempt at classifying ULTRALIGHT
+ * vs ULTRALIGHT-C (based on NXP's public AN1303).
+ * The memory layout is as follows:
+ * Page # BYTE1 BYTE2 BYTE3 BYTE4
+ * 2 INT1 INT2 LOCK LOCK
+ * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted)
+ * 4 DATA DATA DATA DATA (version info if factory-state)
+ *
+ * Read four blocks from page 2, which will get us both
+ * the lock page, the OTP page and the version info.
+ */
+ boolean isUltralightC = false;
+ byte[] readCmd = { 0x30, 0x02 };
+ int[] retCode = new int[2];
+ byte[] respData = transceive(readCmd, false, retCode);
+ if (respData != null && respData.length == 16) {
+ // Check the lock bits (last 2 bytes in page2)
+ // and the OTP bytes (entire page 3)
+ if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 &&
+ respData[5] == 0 && respData[6] == 0 && respData[7] == 0) {
+ // Very likely to be a blank card, look at version info
+ // in page 4.
+ if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) {
+ // This is Ultralight-C
+ isUltralightC = true;
+ } else {
+ // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight
+ // as a fallback if it's anything else
+ isUltralightC = false;
+ }
+ } else {
+ // See if we can find the NDEF CC in the OTP page and if it's
+ // smaller than major version two
+ if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) {
+ // OK, got NDEF. Technically we'd have to search for the
+ // NDEF TLV as well. However, this would add too much
+ // time for discovery and we can make already make a good guess
+ // with the data we have here. Byte 2 of the OTP page
+ // indicates the size of the tag - 0x06 is UL, anything
+ // above indicates UL-C.
+ if ((respData[6] & 0xff) > 0x06) {
+ isUltralightC = true;
+ }
+ } else {
+ // Fall back to ultralight
+ isUltralightC = false;
+ }
+ }
+ }
+ return isUltralightC;
+ }
+
+ @Override
+ public Bundle[] getTechExtras() {
+ synchronized (this) {
+ if (mTechExtras != null) return mTechExtras;
+ mTechExtras = new Bundle[mTechList.length];
+ for (int i = 0; i < mTechList.length; i++) {
+ Bundle extras = new Bundle();
+ switch (mTechList[i]) {
+ case TagTechnology.NFC_A: {
+ byte[] actBytes = mTechActBytes[i];
+ if ((actBytes != null) && (actBytes.length > 0)) {
+ extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF));
+ } else {
+ // Unfortunately Jewel doesn't have act bytes,
+ // ignore this case.
+ }
+ extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]);
+ break;
+ }
+
+ case TagTechnology.NFC_B: {
+ // What's returned from the PN544 is actually:
+ // 4 bytes app data
+ // 3 bytes prot info
+ byte[] appData = new byte[4];
+ byte[] protInfo = new byte[3];
+ if (mTechPollBytes[i].length >= 7) {
+ System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4);
+ System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3);
+
+ extras.putByteArray(NfcB.EXTRA_APPDATA, appData);
+ extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo);
+ }
+ break;
+ }
+
+ case TagTechnology.NFC_F: {
+ byte[] pmm = new byte[8];
+ byte[] sc = new byte[2];
+ if (mTechPollBytes[i].length >= 8) {
+ // At least pmm is present
+ System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8);
+ extras.putByteArray(NfcF.EXTRA_PMM, pmm);
+ }
+ if (mTechPollBytes[i].length == 10) {
+ System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2);
+ extras.putByteArray(NfcF.EXTRA_SC, sc);
+ }
+ break;
+ }
+
+ case TagTechnology.ISO_DEP: {
+ if (hasTech(TagTechnology.NFC_A)) {
+ extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]);
+ }
+ else {
+ extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]);
+ }
+ break;
+ }
+
+ case TagTechnology.NFC_V: {
+ // First byte response flags, second byte DSFID
+ if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) {
+ extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]);
+ extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]);
+ }
+ break;
+ }
+
+ case TagTechnology.MIFARE_ULTRALIGHT: {
+ boolean isUlc = isUltralightC();
+ extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc);
+ break;
+ }
+
+ default: {
+ // Leave the entry in the array null
+ continue;
+ }
+ }
+ mTechExtras[i] = extras;
+ }
+ return mTechExtras;
+ }
+ }
+
+ @Override
+ public NdefMessage findAndReadNdef() {
+ // Try to find NDEF on any of the technologies.
+ int[] technologies = getTechList();
+ int[] handles = mTechHandles;
+ NdefMessage ndefMsg = null;
+ boolean foundFormattable = false;
+ int formattableHandle = 0;
+ int formattableLibNfcType = 0;
+ int status;
+
+ for (int techIndex = 0; techIndex < technologies.length; techIndex++) {
+ // have we seen this handle before?
+ for (int i = 0; i < techIndex; i++) {
+ if (handles[i] == handles[techIndex]) {
+ continue; // don't check duplicate handles
+ }
+ }
+
+ status = connectWithStatus(technologies[techIndex]);
+ if (status != 0) {
+ Log.d(TAG, "Connect Failed - status = "+ status);
+ if (status == STATUS_CODE_TARGET_LOST) {
+ break;
+ }
+ continue; // try next handle
+ }
+ // Check if this type is NDEF formatable
+ if (!foundFormattable) {
+ if (isNdefFormatable()) {
+ foundFormattable = true;
+ formattableHandle = getConnectedHandle();
+ formattableLibNfcType = getConnectedLibNfcType();
+ // We'll only add formattable tech if no ndef is
+ // found - this is because libNFC refuses to format
+ // an already NDEF formatted tag.
+ }
+ reconnect();
+ }
+
+ int[] ndefinfo = new int[2];
+ status = checkNdefWithStatus(ndefinfo);
+ if (status != 0) {
+ Log.d(TAG, "Check NDEF Failed - status = " + status);
+ if (status == STATUS_CODE_TARGET_LOST) {
+ break;
+ }
+ continue; // try next handle
+ }
+
+ // found our NDEF handle
+ boolean generateEmptyNdef = false;
+
+ int supportedNdefLength = ndefinfo[0];
+ int cardState = ndefinfo[1];
+ byte[] buff = readNdef();
+ if (buff != null) {
+ try {
+ ndefMsg = new NdefMessage(buff);
+ addNdefTechnology(ndefMsg,
+ getConnectedHandle(),
+ getConnectedLibNfcType(),
+ getConnectedTechnology(),
+ supportedNdefLength, cardState);
+ reconnect();
+ } catch (FormatException e) {
+ // Create an intent anyway, without NDEF messages
+ generateEmptyNdef = true;
+ }
+ } else {
+ generateEmptyNdef = true;
+ }
+
+ if (generateEmptyNdef) {
+ ndefMsg = null;
+ addNdefTechnology(null,
+ getConnectedHandle(),
+ getConnectedLibNfcType(),
+ getConnectedTechnology(),
+ supportedNdefLength, cardState);
+ reconnect();
+ }
+ break;
+ }
+
+ if (ndefMsg == null && foundFormattable) {
+ // Tag is not NDEF yet, and found a formattable target,
+ // so add formattable tech to tech list.
+ addNdefFormatableTechnology(
+ formattableHandle,
+ formattableLibNfcType);
+ }
+
+ return ndefMsg;
+ }
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java
new file mode 100755
index 0000000..094f46a
--- /dev/null
+++ b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost.NfcDepEndpoint;
+
+/**
+ * Native interface to the P2P Initiator functions
+ */
+public class NativeP2pDevice implements NfcDepEndpoint {
+
+ private int mHandle;
+
+ private int mMode;
+
+ private byte[] mGeneralBytes;
+
+ private native byte[] doReceive();
+ @Override
+ public byte[] receive() {
+ return doReceive();
+ }
+
+ private native boolean doSend(byte[] data);
+ @Override
+ public boolean send(byte[] data) {
+ return doSend(data);
+ }
+
+ private native boolean doConnect();
+ @Override
+ public boolean connect() {
+ return doConnect();
+ }
+
+ private native boolean doDisconnect();
+ @Override
+ public boolean disconnect() {
+ return doDisconnect();
+ }
+
+ public native byte[] doTransceive(byte[] data);
+ @Override
+ public byte[] transceive(byte[] data) {
+ return doTransceive(data);
+ }
+
+ @Override
+ public int getHandle() {
+ return mHandle;
+ }
+
+ @Override
+ public int getMode() {
+ return mMode;
+ }
+
+ @Override
+ public byte[] getGeneralBytes() {
+ return mGeneralBytes;
+ }
+
+}