From 2b9e604ec4c08566ec2c4271e047a2468783db21 Mon Sep 17 00:00:00 2001 From: Bongsu Jeon Date: Thu, 11 Mar 2021 17:16:21 +0900 Subject: Initial Samsung's NFC HAL This is the initial Samsung's AOSP HAL implementation. Change-Id: I9f2183242ef789c47cf278ac78159855c78ce92c --- 1.2/Android.bp | 26 + 1.2/HalSecNfc.h | 26 + 1.2/SecNfc.cpp | 157 +++++ 1.2/SecNfc.h | 93 +++ 1.2/SecNfcService.cpp | 33 + 1.2/android.hardware.nfc@1.2-service.samsung.rc | 4 + Android.bp | 58 ++ halimpl/include/config.h | 105 +++ halimpl/include/device.h | 31 + halimpl/include/hal.h | 213 ++++++ halimpl/include/hal_msg.h | 137 ++++ halimpl/include/sec_nfc.h | 26 + halimpl/include/util.h | 41 ++ halimpl/osi/osi.h | 348 ++++++++++ halimpl/osi/osi_common.h | 140 ++++ halimpl/osi/osi_main.cc | 107 +++ halimpl/osi/osi_memory.cc | 249 +++++++ halimpl/osi/osi_task.cc | 186 ++++++ halimpl/osi/osi_timer.cc | 263 ++++++++ halimpl/src/config.cpp | 833 ++++++++++++++++++++++++ halimpl/src/device.cc | 346 ++++++++++ halimpl/src/hal.cc | 452 +++++++++++++ halimpl/src/hal_nci.cc | 211 ++++++ halimpl/src/hal_task.cc | 447 +++++++++++++ halimpl/src/util.cc | 265 ++++++++ 25 files changed, 4797 insertions(+) create mode 100644 1.2/Android.bp create mode 100644 1.2/HalSecNfc.h create mode 100644 1.2/SecNfc.cpp create mode 100644 1.2/SecNfc.h create mode 100644 1.2/SecNfcService.cpp create mode 100644 1.2/android.hardware.nfc@1.2-service.samsung.rc create mode 100644 Android.bp create mode 100644 halimpl/include/config.h create mode 100644 halimpl/include/device.h create mode 100644 halimpl/include/hal.h create mode 100644 halimpl/include/hal_msg.h create mode 100644 halimpl/include/sec_nfc.h create mode 100644 halimpl/include/util.h create mode 100644 halimpl/osi/osi.h create mode 100644 halimpl/osi/osi_common.h create mode 100644 halimpl/osi/osi_main.cc create mode 100644 halimpl/osi/osi_memory.cc create mode 100644 halimpl/osi/osi_task.cc create mode 100644 halimpl/osi/osi_timer.cc create mode 100644 halimpl/src/config.cpp create mode 100644 halimpl/src/device.cc create mode 100644 halimpl/src/hal.cc create mode 100644 halimpl/src/hal_nci.cc create mode 100644 halimpl/src/hal_task.cc create mode 100644 halimpl/src/util.cc diff --git a/1.2/Android.bp b/1.2/Android.bp new file mode 100644 index 0000000..fbd21fe --- /dev/null +++ b/1.2/Android.bp @@ -0,0 +1,26 @@ +cc_binary { + name: "android.hardware.nfc@1.2-service.samsung", + defaults: ["hidl_defaults"], + proprietary: true, + init_rc: ["android.hardware.nfc@1.2-service.samsung.rc"], + relative_install_path: "hw", + srcs: [ + "SecNfcService.cpp", + "SecNfc.cpp", + ], + cflags: [ + ], + shared_libs: [ + "nfc_nci_samsung", + "android.hardware.nfc@1.0", + "android.hardware.nfc@1.1", + "android.hardware.nfc@1.2", + "libbase", + "libcutils", + "libhardware", + "liblog", + "libutils", + "libhidlbase", + "libcrypto", + ], +} diff --git a/1.2/HalSecNfc.h b/1.2/HalSecNfc.h new file mode 100644 index 0000000..33a9146 --- /dev/null +++ b/1.2/HalSecNfc.h @@ -0,0 +1,26 @@ +#ifndef __NFC_SEC_HAL__ +#define __NFC_SEC_HAL__ + +#include +#include +#include + +using ::android::hardware::nfc::V1_2::NfcConfig; + +int nfc_hal_init(void); +void nfc_hal_deinit(void); +int nfc_hal_open(nfc_stack_callback_t* p_cback, + nfc_stack_data_callback_t* p_data_cback); +int nfc_hal_write(uint16_t data_len, const uint8_t* p_data); +int nfc_hal_core_initialized(uint8_t* p_core_init_rsp_params); +int nfc_hal_pre_discover(); +int nfc_hal_close(); +int nfc_hal_control_granted(); +int nfc_hal_power_cycle(); + +int nfc_hal_factory_reset(void); +int nfc_hal_closeForPowerOffCase(void); +void nfc_hal_getVendorConfig(android::hardware::nfc::V1_1::NfcConfig& config); +void nfc_hal_getVendorConfig_1_2(NfcConfig& config); + +#endif // __NFC_SEC_HAL__ diff --git a/1.2/SecNfc.cpp b/1.2/SecNfc.cpp new file mode 100644 index 0000000..6eceaa5 --- /dev/null +++ b/1.2/SecNfc.cpp @@ -0,0 +1,157 @@ +/****************************************************************************** + * + * Copyright 2018 Samsung + * + * 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 "SecNfc.h" +#include +#include "HalSecNfc.h" + +typedef uint16_t NFCSTATUS; /* Return values */ +#define NFCSTATUS_SUCCESS (0x0000) +#define NFCSTATUS_OK (NFCSTATUS_SUCCESS) + +#define CHK_STATUS(x) \ + ((x) == NFCSTATUS_SUCCESS) \ + ? (android::hardware::nfc::V1_0::NfcStatus::OK) \ + : (android::hardware::nfc::V1_0::NfcStatus::FAILED) + +bool nfc_debug_enabled = true; + +namespace android { +namespace hardware { +namespace nfc { +namespace V1_2 { +namespace implementation { + +sp Nfc::mCallbackV1_1 = nullptr; +sp Nfc::mCallbackV1_0 = nullptr; + +Return Nfc::open_1_1( + const sp& clientCallback) { + ALOGD_IF(nfc_debug_enabled, "SecNfc::open Enter"); + if (clientCallback == nullptr) { + ALOGD_IF(nfc_debug_enabled, "Nfc::open null callback"); + return V1_0::NfcStatus::FAILED; + } else { + mCallbackV1_1 = clientCallback; + mCallbackV1_1->linkToDeath(this, 0 /*cookie*/); + } + ALOGD_IF(nfc_debug_enabled, "SecNfc::open Exit"); + return open(clientCallback); +} + +Return Nfc::open( + const sp& clientCallback) { + ALOGD_IF(nfc_debug_enabled, "SecNfc::open Enter"); + if (clientCallback == nullptr) { + ALOGD_IF(nfc_debug_enabled, "Nfc::open null callback"); + return V1_0::NfcStatus::FAILED; + } else { + mCallbackV1_0 = clientCallback; + mCallbackV1_0->linkToDeath(this, 0 /*cookie*/); + } + NFCSTATUS status = nfc_hal_open(eventCallback, dataCallback); + ALOGD_IF(nfc_debug_enabled, "SecNfc::open Exit"); + return CHK_STATUS(status); +} + +Return Nfc::write(const hidl_vec& data) { + hidl_vec copy = data; + return nfc_hal_write(copy.size(), ©[0]); +} + +Return Nfc::coreInitialized(const hidl_vec& data) { + hidl_vec copy = data; + NFCSTATUS status = nfc_hal_core_initialized((unsigned char*)©[0]); + return CHK_STATUS(status); +} + +Return<::android::hardware::nfc::V1_0::NfcStatus> Nfc::prediscover() { + NFCSTATUS status = nfc_hal_pre_discover(); + return CHK_STATUS(status); +} + +Return Nfc::close() { + if (mCallbackV1_1 == nullptr && mCallbackV1_0 == nullptr) { + return V1_0::NfcStatus::FAILED; + } + NFCSTATUS status = nfc_hal_close(); // To-do function Parameter + + if (mCallbackV1_1 != nullptr) { + mCallbackV1_1->unlinkToDeath(this); + mCallbackV1_1 = nullptr; + } + if (mCallbackV1_0 != nullptr) { + mCallbackV1_0->unlinkToDeath(this); + mCallbackV1_0 = nullptr; + } + return CHK_STATUS(status); +} + +Return Nfc::controlGranted() { + NFCSTATUS status = nfc_hal_control_granted(); + return CHK_STATUS(status); +} + +Return Nfc::powerCycle() { + NFCSTATUS status = nfc_hal_power_cycle(); + return CHK_STATUS(status); +} + +// Methods from ::android::hardware::nfc::V1_1::INfc follow. +Return Nfc::factoryReset() { + nfc_hal_factory_reset(); + return Void(); +} + +Return Nfc::closeForPowerOffCase() { + if (mCallbackV1_1 == nullptr && mCallbackV1_0 == nullptr) { + return V1_0::NfcStatus::FAILED; + } + + NFCSTATUS status = nfc_hal_closeForPowerOffCase(); + + if (mCallbackV1_1 != nullptr) { + mCallbackV1_1->unlinkToDeath(this); + mCallbackV1_1 = nullptr; + } + if (mCallbackV1_0 != nullptr) { + mCallbackV1_0->unlinkToDeath(this); + mCallbackV1_0 = nullptr; + } + return CHK_STATUS(status); +} + +Return Nfc::getConfig(getConfig_cb hidl_cb) { + android::hardware::nfc::V1_1::NfcConfig nfcVendorConfig; + nfc_hal_getVendorConfig(nfcVendorConfig); + hidl_cb(nfcVendorConfig); + return Void(); +} + +Return Nfc::getConfig_1_2(getConfig_1_2_cb hidl_cb) { + NfcConfig nfcVendorConfig; + nfc_hal_getVendorConfig_1_2(nfcVendorConfig); + hidl_cb(nfcVendorConfig); + return Void(); +} + +} // namespace implementation +} // namespace V1_2 +} // namespace nfc +} // namespace hardware +} // namespace android diff --git a/1.2/SecNfc.h b/1.2/SecNfc.h new file mode 100644 index 0000000..51bbd69 --- /dev/null +++ b/1.2/SecNfc.h @@ -0,0 +1,93 @@ +#ifndef ANDROID_HARDWARE_NFC_V1_2_NFC_H +#define ANDROID_HARDWARE_NFC_V1_2_NFC_H + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace nfc { +namespace V1_2 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::nfc::V1_2::INfc; +using ::android::hidl::base::V1_0::IBase; + +struct Nfc : public V1_2::INfc, public hidl_death_recipient { + public: + // Methods from ::android::hardware::nfc::V1_0::INfc follow. + Return open( + const sp& clientCallback) override; + Return open_1_1( + const sp& clientCallback) override; + Return write(const hidl_vec& data) override; + Return coreInitialized( + const hidl_vec& data) override; + Return prediscover() override; + Return close() override; + Return controlGranted() override; + Return powerCycle() override; + + // Methods from ::android::hardware::nfc::V1_1::INfc follow. + Return factoryReset() override; + Return closeForPowerOffCase() override; + Return getConfig(getConfig_cb config) override; + Return getConfig_1_2(getConfig_1_2_cb config) override; + + static void eventCallback(uint8_t event, uint8_t status) { + if (mCallbackV1_1 != nullptr) { + auto ret = mCallbackV1_1->sendEvent_1_1((V1_1::NfcEvent)event, + (V1_0::NfcStatus)status); + if (!ret.isOk()) { + ALOGW("failed to send event!!!"); + } + } else if (mCallbackV1_0 != nullptr) { + auto ret = mCallbackV1_0->sendEvent((V1_0::NfcEvent)event, + (V1_0::NfcStatus)status); + if (!ret.isOk()) { + ALOGE("failed to send event!!!"); + } + } + } + + static void dataCallback(uint16_t data_len, uint8_t* p_data) { + hidl_vec data; + data.setToExternal(p_data, data_len); + if (mCallbackV1_1 != nullptr) { + auto ret = mCallbackV1_1->sendData(data); + if (!ret.isOk()) { + ALOGW("failed to send data!!!"); + } + } else if (mCallbackV1_0 != nullptr) { + auto ret = mCallbackV1_0->sendData(data); + if (!ret.isOk()) { + ALOGE("failed to send data!!!"); + } + } + } + + virtual void serviceDied(uint64_t /*cookie*/, const wp& /*who*/) { + close(); + } + + private: + static sp mCallbackV1_1; + static sp mCallbackV1_0; +}; +} // namespace implementation +} // namespace V1_2 +} // namespace nfc +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NFC_V1_2_NFC_H diff --git a/1.2/SecNfcService.cpp b/1.2/SecNfcService.cpp new file mode 100644 index 0000000..fb11228 --- /dev/null +++ b/1.2/SecNfcService.cpp @@ -0,0 +1,33 @@ +#define LOG_TAG "secnfc@1.2-service" +#include +#include + +#include +#include "HalSecNfc.h" +#include "SecNfc.h" + +// Generated HIDL files +using android::OK; +using android::sp; +using android::status_t; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::nfc::V1_2::INfc; +using android::hardware::nfc::V1_2::implementation::Nfc; + +int main() { + ALOGD("SEC NFC HAL Service 1.2 is starting."); + sp nfc_service = new Nfc(); + + configureRpcThreadpool(1, true /*callerWillJoin*/); + status_t status = nfc_service->registerAsService(); + if (status != OK) { + LOG_ALWAYS_FATAL("Could not register service for NFC HAL Iface (%d).", + status); + return -1; + } + + ALOGD("NFC service is ready"); + joinRpcThreadpool(); + return 1; +} diff --git a/1.2/android.hardware.nfc@1.2-service.samsung.rc b/1.2/android.hardware.nfc@1.2-service.samsung.rc new file mode 100644 index 0000000..c026cde --- /dev/null +++ b/1.2/android.hardware.nfc@1.2-service.samsung.rc @@ -0,0 +1,4 @@ +service nfc_hal_service /vendor/bin/hw/android.hardware.nfc@1.2-service.sec + class hal + user nfc + group nfc diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..4bcd3b8 --- /dev/null +++ b/Android.bp @@ -0,0 +1,58 @@ +// +// Copyright (C) 2018 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. + +cc_library_shared { + name: "nfc_nci_samsung", + defaults: ["hidl_defaults"], + proprietary: true, + + cflags: [ + "-DBUILDCFG=1", + "-DANDROID", + "-DNFC_HAL_TARGET=TRUE", + "-DNFC_RW_ONLY=TRUE", + "-DNFC_SEC_NOT_OPEN_INCLUDED=TRUE", + "-DINFC_1_1", + ], + + srcs: [ + "halimpl/osi/*.cc", + "halimpl/src/*.cc", + "halimpl/src/*.cpp", + ], + + local_include_dirs: [ + "halimpl/include", + "halimpl/osi", + ], + export_include_dirs: [ + "halimpl/include", + "halimpl/osi", + ], + + shared_libs: [ + "android.hardware.nfc@1.0", + "android.hardware.nfc@1.1", + "android.hardware.nfc@1.2", + "libbase", + "libcutils", + "libhardware", + "libhardware_legacy", + "libhidlbase", + "liblog", + "libutils", + "libcrypto", + ], +} diff --git a/halimpl/include/config.h b/halimpl/include/config.h new file mode 100644 index 0000000..cafc4a4 --- /dev/null +++ b/halimpl/include/config.h @@ -0,0 +1,105 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * + * 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. + * + ******************************************************************************/ +/****************************************************************************** + * + * The original Work has been changed by Samsung Electronics. + + * + * Copyright (C) 2018 Samsung Electronics, System LSI Division + * + * 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 __CONFIG_H +#define __CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +int GetStrValue(const char* name, char* p_value, unsigned long len); // SLSI +int GetNumValue(const char* name, void* p_value, unsigned long len); // SLSI +int GetByteArrayValue(const char* name, char* pValue, long bufflen, + long* len); // SLSI +#if (NFC_SEC_NOT_OPEN_INCLUDED == TRUE) +void Set_user_prefix(char* field); +#endif + +void resetConfig(void); +int isConfigModified(); +int updateConfigTimestamp(); + +#ifdef __cplusplus +}; +#endif +#define NAME_MIFARE_READER_ENABLE "MIFARE_READER_ENABLE" +#define NAME_FW_STORAGE "FW_STORAGE" + +#define NAME_ISO_DEP_MAX_TRANSCEIVE "ISO_DEP_MAX_TRANSCEIVE" +#define NAME_AID_MATCHING_PLATFORM "AID_MATCHING_PLATFORM" +#define NAME_NFC_DEBUG_ENABLED "NFC_DEBUG_ENABLED" +#define NAME_RF_STATUS_UPDATE_ENABLE "RF_STATUS_UPDATE_ENABLE" +#define NAME_DEFAULT_ROUTE "DEFAULT_ROUTE" +#define NAME_DEFAULT_OFFHOST_ROUTE "DEFAULT_OFFHOST_ROUTE" +#define NAME_DEFAULT_NFCF_ROUTE "DEFAULT_NFCF_ROUTE" +#define NAME_DEFAULT_SYS_CODE_ROUTE "DEFAULT_SYS_CODE_ROUTE" +#define NAME_DEFAULT_SYS_CODE_PWR_STATE "DEFAULT_SYS_CODE_PWR_STATE" +#define NAME_DEVICE_HOST_WHITE_LIST "DEVICE_HOST_WHITE_LIST" +#define NAME_OFF_HOST_ESE_PIPE_ID "OFF_HOST_ESE_PIPE_ID" +#define NAME_OFF_HOST_SIM_PIPE_ID "OFF_HOST_SIM_PIPE_ID" +#define NAME_NFA_PROPRIETARY_CFG "NFA_PROPRIETARY_CFG" +#define NAME_PRESENCE_CHECK_ALGORITHM "PRESENCE_CHECK_ALGORITHM" + +#define NAME_OFFHOST_ROUTE_ESE "OFFHOST_ROUTE_ESE" +#define NAME_OFFHOST_ROUTE_UICC "OFFHOST_ROUTE_UICC" +#define NAME_DEFAULT_ISODEP_ROUTE "DEFAULT_ISODEP_ROUTE" + +/* default configuration */ +#define default_storage_location "/data/vendor/nfc" + +#endif diff --git a/halimpl/include/device.h b/halimpl/include/device.h new file mode 100644 index 0000000..99ec3b6 --- /dev/null +++ b/halimpl/include/device.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 "hal.h" +#include "osi.h" + +int device_init(int data_trace); +void device_deinit(void); +int device_open(); +void device_close(void); +int device_set_mode(eNFC_DEV_MODE mode); +int device_sleep(void); +int device_wakeup(void); +int device_write(uint8_t* data, size_t len); +int device_read(uint8_t* buffer, size_t len); +void data_trace(const char* head, int len, uint8_t* p_data); diff --git a/halimpl/include/hal.h b/halimpl/include/hal.h new file mode 100644 index 0000000..153cd99 --- /dev/null +++ b/halimpl/include/hal.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 __NFC_SEC_HAL__ +#define __NFC_SEC_HAL__ + +#include + +#include "hal_msg.h" +#include "osi.h" + +#include "android/hardware/nfc/1.2/INfc.h" +#include "android/hardware/nfc/1.2/types.h" + +using ::android::hardware::nfc::V1_1::NfcConfig; + +#ifndef __bool_true_false_are_defined +#define __bool_true_false_are_defined +typedef enum { false, true } bool; +#endif + +/*************************************** + * DEVICE + ***************************************/ +typedef enum { + NFC_DEV_MODE_OFF = 0, + NFC_DEV_MODE_ON, + NFC_DEV_MODE_BOOTLOADER, +} eNFC_DEV_MODE; + +/*************************************** + * States + ***************************************/ +typedef enum { + HAL_STATE_INIT, + HAL_STATE_DEINIT, + HAL_STATE_OPEN, + HAL_STATE_VS, + HAL_STATE_POSTINIT, + HAL_STATE_SERVICE, + HAL_STATE_GRANTED, + HAL_STATE_CLOSE, /* VTS */ + HAL_STATE_POWERCYCLE, /* VTS */ +} eHAL_STATE; + +/* FW sub-state */ +#define FW_DATA_PAYLOAD_MAX (256) + +/* VS sub-state */ +typedef enum { + VS_INIT, + VS_W4_COMPLETE, +} eNFC_HAL_VS_STATE; + +/*************************************** + * Structures + ***************************************/ +/* VS related */ + +typedef struct { + eNFC_HAL_VS_STATE state; +} tNFC_HAL_VS_INFO; +enum { + CFG_SLEEP_TIMEOUT = 0, + CFG_WAKEUP_DELAY, + CFG_NCI_PROP, + CFG_POWER_DRIVER, + CFG_TRANS_DRIVER, + CFG_TRACE_LEVEL, + CFG_DATA_TRACE, + CFG_FW_CLK_SPEED, +}; + +static const char* cfg_name_table[] = { + "SLEEP_TIMEOUT", "WAKEUP_DELAY", "NCI_PROP", "POWER_DRIVER", + "TRANS_DRIVER", "TRACE_LEVEL", "DATA_TRACE", "FW_CFG_CLK_SPEED", +}; + +typedef struct { + uint32_t sleep_timeout; + uint32_t override_timeout; +} tNFC_HAL_CONFIG; + +/* Granted related */ +#define HAL_GRANT_SEND_NEXT 0x00 +#define HAL_GRANT_WAIT_READ 0x01 +#define HAL_GRANT_FINISH 0x02 +typedef uint8_t(tNFC_HAL_GRANT_CALLBACK)(tNFC_NCI_PKT* pkt); + +/* FLAGS */ +#define HAL_FLAG_MASK_USING_TIMER 0x000F +#define HAL_FLAG_W4_CORE_RESET_RSP 0x0001 +#define HAL_FLAG_W4_CORE_INIT_RSP 0x0002 + +#define HAL_FLAG_PROP_RESET 0x0010 +#define HAL_FLAG_CLK_SET 0x0020 +#define HAL_FLAG_PROP_ONE_TIMER 0x0040 + +#define HAL_FLAG_MASK_ALREADY 0x0F00 +#define HAL_FLAG_ALREADY_RESET 0x0100 +#define HAL_FLAG_ALREADY_INIT 0x0200 + +#define HAL_FLAG_MASK_SYSTEM 0xF000 +#define HAL_FLAG_FORCE_FW_UPDATE 0x1000 +#define HAL_FLAG_NTF_TRNS_ERROR 0x2000 +#define HAL_FLAG_RETRY_TRNS 0x4000 + +/*************************************** + * Main information(context block) + ***************************************/ +typedef struct { + tNFC_HAL_CONFIG cfg; + eHAL_STATE state; /* HAL state */ + tNFC_HAL_VS_INFO vs_info; + + tOSI_TASK_HANDLER msg_task; /* HAL main task */ + tOSI_QUEUE_HANDLER msg_q; + nfc_stack_callback_t* stack_cback; /* Callback for HAL event */ + nfc_stack_data_callback_t* data_cback; /* Callback for data event */ + tNFC_NCI_PKT* nci_last_pkt; /* last sent package */ + tNFC_NCI_PKT* nci_fragment_pkt; /* Control msg flagmentation */ + tOSI_TIMER_HANDLER nci_timer; /* Timer for NCI message */ + tOSI_TIMER_HANDLER sleep_timer; /* Timer for NCI message */ + int trans_dev; /* transport device */ + int power_dev; /* power device */ + tOSI_QUEUE_HANDLER nci_q; + tNFC_HAL_GRANT_CALLBACK* grant_cback; + unsigned int flag; + /* START [H16031401] */ + uint8_t msg_event; /* receiving message event */ + /* END [H16031401] */ +} tNFC_HAL_CB; + +/************************************* + * Global + *************************************/ +extern tNFC_HAL_CB nfc_hal_info; + +/************************************* + * NFC HAL API prototype + *************************************/ +int nfc_hal_init(void); +void nfc_hal_deinit(void); +int nfc_hal_open(nfc_stack_callback_t* p_cback, + nfc_stack_data_callback_t* p_data_cback); +int nfc_hal_write(uint16_t data_len, const uint8_t* p_data); +int nfc_hal_core_initialized(uint8_t* p_core_init_rsp_params); +int nfc_hal_pre_discover(); +int nfc_hal_close(); +int nfc_hal_control_granted(); +int nfc_hal_power_cycle(); +// HIDL INfc 1.1 +int nfc_hal_factory_reset(void); +int nfc_hal_closeForPowerOffCase(void); +void nfc_hal_getVendorConfig(NfcConfig& config); // To-Do + +/************************************* + * NFC HAL functions. + *************************************/ +bool nfc_stack_cback(nfc_event_t event, nfc_status_t event_status); +bool nfc_data_callback(tNFC_NCI_PKT* pkt); + +void nfc_hal_task(void); + +/* START - VTS */ +void nfc_hal_power_sm(tNFC_HAL_MSG* msg); +/* END - VTS */ +void nfc_hal_grant_sm(tNFC_HAL_MSG* msg); +void nfc_hal_service_sm(tNFC_HAL_MSG* msg); +void nfc_hal_vs_sm(tNFC_HAL_MSG* msg); +void nfc_hal_postinit_sm(tNFC_HAL_MSG* msg); +void nfc_hal_open_sm(tNFC_HAL_MSG* msg); + +void setSleepTimeout(int option, uint32_t timeout); + +const char* event_to_string(uint8_t event); +const char* state_to_string(eHAL_STATE state); + +// SM +void hal_update_sleep_timer(void); +int __send_to_device(uint8_t* data, size_t len); + +// FW +void fw_force_update(void* param); +int nfc_fw_send_data(uint8_t* data, int len); +int fw_read_payload(tNFC_HAL_MSG* msg); + +// NCI +int hal_nci_send(tNFC_NCI_PKT* pkt); +void hal_nci_send_reset(void); +void hal_nci_send_prop_fw_cfg(void); +void hal_nci_send_clearLmrt(void); +void nci_init_timeout(void* param); +bool nfc_hal_prehandler(tNFC_NCI_PKT* pkt); +int nci_read_payload(tNFC_HAL_MSG* msg); + +// TRACE +void sec_nci_analyzer(tNFC_NCI_PKT* pkt); + +#endif // __NFC_SEC_HAL__ diff --git a/halimpl/include/hal_msg.h b/halimpl/include/hal_msg.h new file mode 100644 index 0000000..a886053 --- /dev/null +++ b/halimpl/include/hal_msg.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 __NFC_SEC_HALMSG__ +#define __NFC_SEC_HALMSG__ + +/*************************************** + * NCI + ***************************************/ +#define HAL_EVT_SIZE 1 +#define NCI_HDR_SIZE 3 +#define NCI_MAX_PAYLOAD 0xFF +#define NCI_CTRL_SIZE (NCI_HDR_SIZE + NCI_MAX_PAYLOAD) + +typedef struct { + uint8_t oct0; + uint8_t oid; + uint8_t len; + uint8_t payload[NCI_MAX_PAYLOAD]; +} tNFC_NCI_PKT; +/* START [181106] Patch for supporting NCI v2.0 */ +// [1. NCI Version Management] +#define NCI_VER_1_0 0x10 +#define NCI_VER_2_0 0x20 +/* END [181106] Patch for supporting NCI v2.0 */ +#define NCI_MT(x) ((x)->oct0 & 0xE0) +#define NCI_PBF(x) ((x)->oct0 & 0x10) +#define NCI_GID(x) ((x)->oct0 & 0x0F) +#define NCI_OID(x) ((x)->oid & 0x3F) +#define NCI_LEN(x) ((x)->len) +#define NCI_PAYLOAD(x) ((x)->payload) +#define NCI_STATUS(x) (((x)->payload)[0]) +#define NCI_MF_INFO_SIZE 4 +#define NCI_MF_INFO(x) (((x)->payload) + (x)->len - NCI_MF_INFO_SIZE) +#define NCI_PKT_LEN(x) (NCI_HDR_SIZE + NCI_LEN(x)) + +#define NCI_MT_DATA 0x00 +#define NCI_MT_CMD 0x20 +#define NCI_MT_RSP 0x40 +#define NCI_MT_NTF 0x60 + +#define NCI_PBF_LAST 0x00 +#define NCI_PBF_CONTINUE 0x10 + +#define NCI_GID_CORE 0x00 +#define NCI_GID_RF_MANAGE 0x01 +#define NCI_GID_EE_MANAGE 0x02 +#define NCI_GID_PROP 0x0F + +#define NCI_CORE_RESET 0x00 +#define NCI_CORE_INIT 0x01 + +#define NCI_PROP_AGAIN \ + 0x01 /* This prop oid is used only for N3 (sleep mode) \ \ + */ +#define NCI_PROP_FW_CFG 0x28 +#define NCI_PROP_WR_RESET 0x2F +#define NCI_PROP_SET_SLEEP_TIME 0x1A /* Last updated value: 20160530 */ + +#define SET_SLEEP_TIME_CFG 0 +#define SET_SLEEP_TIME_ONCE 1 +#define SET_SLEEP_TIME_FORCE 2 + +#define NCI_STATUS_OK 0x00 +#define NCI_STATUS_E_SYNTAX 0x05 + +/* START [S15012201] - block flip cover in RF field */ +#define HAL_NFC_STATUS_ERR_TRANSPORT 2 +/* END [S15012201] - block flip cover in RF field */ + +/* Response Value for Clock Setting. */ +#define NCI_CLOCK_STATUS_SYNTAX_ERROR 0x01 +#define NCI_CLOCK_STATUS_MISMATCHED 0x02 +#define NCI_CLOCK_STATUS_FULL 0x03 +/*************************************** + * BOOTLOADER + ***************************************/ +#define FW_HDR_SIZE 4 +typedef struct { + uint8_t type; + uint8_t code; + uint16_t len; + uint8_t payload[NCI_MAX_PAYLOAD + 1]; +} tNFC_FW_PKT; +#define FW_PAYLOAD(x) ((x)->payload) + +/* type */ +typedef enum { FW_MSG_CMD = 0, FW_MSG_RSP, FW_MSG_DATA } eNFC_FW_BLTYPE; + +/*************************************** + * HAL Message + ***************************************/ +#define MSG_EVENT_SIZE 1 +typedef struct { + uint8_t event; + union { + tNFC_NCI_PKT nci_packet; + tNFC_FW_PKT fw_packet; + uint8_t param[NCI_CTRL_SIZE]; + }; +} tNFC_HAL_MSG; + +#define HAL_EVT_OPEN 0x00 +#define HAL_EVT_CORE_INIT 0x01 +#define HAL_EVT_PRE_DISCOVER 0x02 +#define HAL_EVT_WRITE 0x03 +#define HAL_EVT_READ 0x04 +#define HAL_EVT_CONTROL_GRANTED 0x05 +#define HAL_EVT_TERMINATE 0x06 +/* START - VTS */ +#define HAL_EVT_POWER_CYCLE 0x07 +/* END - VTS */ +#define HAL_EVT_COMPLETE 0xF0 +#define HAL_EVT_COMPLETE_FAILED 0xF1 + +/*************************************** + * NFC Message + ***************************************/ +#define NFC_STATUS_OK 0x00 +#define NFC_STATUS_FAILED 0x01 + +#endif //__NFC_SEC_HALMSG__ diff --git a/halimpl/include/sec_nfc.h b/halimpl/include/sec_nfc.h new file mode 100644 index 0000000..8826bed --- /dev/null +++ b/halimpl/include/sec_nfc.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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. + * + * + */ + +#define SEC_NFC_DRIVER_NAME "sec-nfc" + +/* ioctl */ +#define SEC_NFC_MAGIC 'S' +#define SEC_NFC_GET_MODE _IOW(SEC_NFC_MAGIC, 0, unsigned int) +#define SEC_NFC_SET_MODE _IOW(SEC_NFC_MAGIC, 1, unsigned int) +#define SEC_NFC_SLEEP _IOW(SEC_NFC_MAGIC, 2, unsigned int) +#define SEC_NFC_WAKEUP _IOW(SEC_NFC_MAGIC, 3, unsigned int) diff --git a/halimpl/include/util.h b/halimpl/include/util.h new file mode 100644 index 0000000..5af4a29 --- /dev/null +++ b/halimpl/include/util.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 __NFC_SEC_HALUTIL__ +#define __NFC_SEC_HALUTIL__ + +#include "osi.h" + +#ifndef __bool_true_false_are_defined +#define __bool_true_false_are_defined +typedef enum { false, true } bool; +#endif + +#define HAL_UTIL_GET_INT_16 0x0001 + +bool get_config_int(const char* field, int* data); +int get_config_string(const char* field, char* strBuffer, size_t bufferSize); +int get_config_count(const char* field); +int get_hw_rev(); + +#ifdef NFC_HAL_NCI_TRACE +#define util_nci_analyzer(x) sec_nci_analyzer(x) +#else +#define util_nci_analyzer(x) +#endif + +#endif //__NFC_SEC_HALUTIL__ diff --git a/halimpl/osi/osi.h b/halimpl/osi/osi.h new file mode 100644 index 0000000..ac29c54 --- /dev/null +++ b/halimpl/osi/osi.h @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 OSI_H +#define OSI_H + +/************************************************************************ +** OS Interface +*************************************************************************/ +#include + +#include + +/************************************************************************ +** public functions +*************************************************************************/ +/* + * Function OSI_init + * + * Description This function is called to initialize OSI context. + * + * Return OSI_FAIL if any problem + * OSI_OK if initialization is succeeded. + */ +OSI_STATE OSI_init(void); + +/* + * Function OSI_deinit + * + * Description This function is called to deinitialize OSI context. + * + */ +void OSI_deinit(void); + +/* + * Function OSI_delay + * + * Description This function is called to delay. + * + * Parameter timeout(input): ms + * + * Return + * + */ +void OSI_delay(uint32_t timeout); + +/*************** + * OSI TASK + ***************/ +/* + * Function OSI_task_allocate + * + * Description This function is called to create a new task. + * + * Parameter task_name(input): + * task_entry(input): entry function. + * + * Return OSI_TASK_HANDLE if allocate is succeeded, + * NULL if any problem. + */ +tOSI_TASK_HANDLER OSI_task_allocate(const char* task_name, + tOSI_TASK_ENTRY task_entry); + +/* + * Function OSI_task_run + * + * Description This function is called to create a new task. + * + * Parameter OSI_TASK_HANDLE(input): target task + * + * Return OSI_OK if creadtion is succeeded, + * OSI_FAIL if any problem. + */ +OSI_STATE OSI_task_run(tOSI_TASK_HANDLER task_handler); + +/* + * Function OSI_task_isRun + * + * Description Check the task is running or not. + * + * Parameter task_handler(input): Target task handler to check running + * + * Return OSI_RUN, on run. + * OSI_FAIL, on error. + */ +OSI_STATE OSI_task_isRun(tOSI_TASK_HANDLER task_handler); + +/* + * Function OSI_task_kill + * + * Description This function is called to kill a task. + * + * Parameter task_handler(input): Target task handler to kill. + * + * Return OSI_OK, on success. + * other, on error. + */ +OSI_STATE OSI_task_kill(tOSI_TASK_HANDLER task_handler); + +/* + * Function OSI_task_stop + * + * Description This function is called to stop a task. + * + * Parameter task_handler(input): Target task handler to kill. + * + * Return OSI_OK, on success. + * other, on error. + */ +OSI_STATE OSI_task_stop(tOSI_TASK_HANDLER task_handler); + +/* + * Function OSI_task_free + * + * Description This function is called to free a task. + * + * Parameter task_handler(input): Target task handler to kill. + * + * Return OSI_OK, on success. + * other, on error. + */ +OSI_STATE OSI_task_free(tOSI_TASK_HANDLER task_handler); + +/* + * Function OSI_task_get_handler + * + * Description This function is called to get handler by task name. + * + * Parameter name(input): Target name to get handler. + * + * Return tOSI_TASK_HANDLER, on success. + * NULL, on error. + */ +tOSI_TASK_HANDLER OSI_task_get_handler(char* name); + +/*************** + * OSI MEMORY + ***************/ +/* + * Function OSI_mem_get + * + * Description This function is called to get memeory. + * + * Parameter size(input): it should be small than OSI_MEM_POLL_SIZE + * + * Return Memory address if getting is succeeded, + * NULL if any problem. + */ +tOSI_MEM_HANDLER OSI_mem_get(size_t size); + +/* + * Function OSI_mem_free + * + * Description This function is called to free memeory. + * + * Parameter target(input): + * + * Return + */ +void OSI_mem_free(tOSI_MEM_HANDLER target); + +/** queue **/ +/* + * Function OSI_queue_allocate + * + * Description This function is called to get a free queue. + * Anyone using OSI can access this message que. + * + * Parameter name(input): que_name + * + * Return tOSI_QUEUE_HANDLER if init is succeeded. + * NULL if any problem. + */ +tOSI_QUEUE_HANDLER OSI_queue_allocate(const char* que_name); + +/* + * Function OSI_queue_put + * + * Description This function is called to put data to the queue. + * + * Parameter que (input): queue handler. + * data (input): void * data to put the stack. + * + * Return number of element in target queue + * + */ +int OSI_queue_put(tOSI_QUEUE_HANDLER queue, void* p_data); + +/* + * Function OSI_queue_get + * + * Description This function is called to get data from the queue. + * + * Parameter que (input): queue handler. + * + * Return (void *) the first data in the queue. + * NULL if any problem. + */ +void* OSI_queue_get(tOSI_QUEUE_HANDLER queue); + +/* + * Function OSI_queue_get_wait + * + * Description This function is called to get data from the queue. + * If the queue is empty, this function is waiting for + * putting data. + * + * Parameter que (input): queue handler. + * + * Return (void *) the first data in the queue. + * NULL if any problem. + */ +void* OSI_queue_get_wait(tOSI_QUEUE_HANDLER target); + +/* + * Function OSI_queue_free + * + * Description This function is called to make que free. + * + * Parameter que (input): queue handler. + * + * Return void + */ +void OSI_queue_free(tOSI_QUEUE_HANDLER target); + +/* + * Function OSI_queue_get_handler + * + * Description This function is called to get handler by queue name. + * + * Parameter name(input): Target name to get handler. + * + * Return tOSI_QUEUE_HANDLER, on success. + * NULL, on error. + */ +tOSI_QUEUE_HANDLER OSI_queue_get_handler(const char* name); + +/*************** + * OSI TIMER + ***************/ +/* + * Function OSI_timer_allocate + * + * Description This function is called to get a timer. + * + * Parameter timer_name(input): + * + * Return 0 if any problem + * other if initialization is succeeded. + */ +tOSI_TIMER_HANDLER OSI_timer_allocate(const char* timer_name); + +/* + * Function OSI_timer_start + * + * Description This function is called to start a timer. + * + * Parameter timer_handler (input) + * timeout (input): time out value. it is millisecond. + * callback (input): callback function. + * + * Return 0 if any problem + * other if initialization is succeeded. + * + */ +int OSI_timer_start(tOSI_TIMER_HANDLER timer, uint32_t timeout, + tOSI_TIMER_CALLBACK callback, void* param); + +/* + * Function OSI_timer_stop + * + * Description This function is called to stop a timer. + * + * Parameter timer_handler (input) + * + * Return + * + */ +void OSI_timer_stop(tOSI_TIMER_HANDLER timer); + +/* + * Function OSI_timer_free + * + * Description This function is called to free a timer. + * + * Parameter timer_handler (input) + * + * Return + * + */ +void OSI_timer_free(tOSI_TIMER_HANDLER timer); + +/* + * Function OSI_timer_get_handler + * + * Description This function is called to get timer handler by name. + * + * Parameter name(input): Target name to get handler. + * + * Return tOSI_QUEUE_HANDLER, on success. + * NULL, on error. + */ +tOSI_TIMER_HANDLER OSI_timer_get_handler(char* name); + +/*************** + * OSI DEBUG + ***************/ +#define OSI_DEBUG +extern int osi_debug_level; +#define OSI_set_debug_level(xx) (osi_debug_level = xx) +#ifdef OSI_DEBUG +#define __osi_log(type, ...) (void)ALOG(type, "SecHAL", __VA_ARGS__) +#define OSI_logt(format, ...) \ + do { \ + if (osi_debug_level >= 2) \ + __osi_log(LOG_INFO, "%s: " format, __func__, ##__VA_ARGS__); \ + } while (0) +#define OSI_logd(format, ...) \ + do { \ + if (osi_debug_level >= 1) \ + __osi_log(LOG_DEBUG, "%s: " format, __func__, ##__VA_ARGS__); \ + } while (0) +#define OSI_loge(format, ...) \ + do { \ + if (osi_debug_level >= 0) \ + __osi_log(LOG_ERROR, "%s: " format, __func__, ##__VA_ARGS__); \ + } while (0) +#else +#define OSI_logt(...) +#define OSI_logd(...) +#define OSI_loge(...) +#endif + +#endif /* OSI_H */ diff --git a/halimpl/osi/osi_common.h b/halimpl/osi/osi_common.h new file mode 100644 index 0000000..582c669 --- /dev/null +++ b/halimpl/osi/osi_common.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 OSI_COMMON_H +#define OSI_COMMON_H + +/************************************************************************ +** OS Interface common component +*************************************************************************/ +#include +#ifdef ANDROID +#include +#endif + +/************************************************************************ +** Common definition and type +*************************************************************************/ +/* OSI common */ +// Maximum count of each obejct +#define OSI_MAX_TASK (3) // main task, read task +#define OSI_MAX_MEM_POOL (10) +#define OSI_MAX_QUEUE (2) // main queue, read queue +#define OSI_MAX_TIMER (2) // fw download timer, nci timer + +// Size of each object +#define OSI_MEM_POOL_SIZE \ + (259) // for NFC (NCI_MAX_CTRL_SIZE + NCI_MSG_HDR_SIZE + NFC_HAL_EVT_SIZE) +#define OSI_QUEUE_SIZE (10) + +// State +typedef uint8_t OSI_STATE; +#define OSI_FAIL 0 +#define OSI_OK 1 +#define OSI_FREE 2 +#define OSI_ALLOCATED 3 +#define OSI_RUN 4 +#define OSI_STOP 5 + +#define OSI_TIMER_THREAD_FLAG_DETACH 0x01 + +/************************************************************************ +** Common definition and type, union +*************************************************************************/ +/* OSI task */ +typedef void (*tOSI_TASK_ENTRY)(void); +typedef struct { + pthread_t task; + const char* name; + OSI_STATE state; + tOSI_TASK_ENTRY task_entry; +} sOSI_TASK; +typedef sOSI_TASK*(tOSI_TASK_HANDLER); + +/* OSI memory */ +typedef struct { + uint8_t buffer[OSI_MEM_POOL_SIZE]; + OSI_STATE state; +} sOSI_MEM; +typedef sOSI_MEM*(tOSI_MEM_HANDLER); + +/* OSI queue */ +typedef struct { + void* queue[OSI_QUEUE_SIZE]; + int head; + int tail; + const char* name; + OSI_STATE state; + pthread_cond_t cond; +} sOSI_QUEUE; +typedef sOSI_QUEUE*(tOSI_QUEUE_HANDLER); + +/* OSI timer */ +typedef void (*tOSI_TIMER_CALLBACK)(void* param); +typedef struct { + int32_t exact_time; + int32_t init_timeout; + int32_t timeout; + const char* name; + tOSI_TIMER_CALLBACK callback; + void* callback_param; + OSI_STATE state; +} sOSI_TIMER; +typedef sOSI_TIMER*(tOSI_TIMER_HANDLER); + +/* OSI Context */ +typedef struct { + /* main */ + pthread_mutex_t mutex; + + /* task */ + sOSI_TASK task[OSI_MAX_TASK]; + +/* memory */ +#ifndef OSI_USE_DYNAMIC_BUF + sOSI_MEM mem[OSI_MAX_MEM_POOL]; +#else + sOSI_MEM* mem[OSI_MAX_MEM_POOL]; +#endif + int32_t mem_max_cnt; /* Maximum number of allocated memory pool */ + + /* queue */ + sOSI_QUEUE queue[OSI_MAX_QUEUE]; + int32_t queue_max_cnt; /* Maximum number of allocated queue */ + + /* timer */ + sOSI_TIMER timer[OSI_MAX_TIMER]; + pthread_t timer_thread; + int32_t usingTimer; + unsigned char timer_thread_flag; + + /* log */ +} tOSI_INFO; + +/************************************************************************ +** Global variable +*************************************************************************/ +extern tOSI_INFO osi_info; + +/************************************************************************ +** Internal functions +*************************************************************************/ +void osi_lock(); +void osi_unlock(); +void OSI_timer_update(int32_t tick); +int32_t OSI_timer_get_current_time(); +#endif diff --git a/halimpl/osi/osi_main.cc b/halimpl/osi/osi_main.cc new file mode 100644 index 0000000..9b67265 --- /dev/null +++ b/halimpl/osi/osi_main.cc @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 +#include +#include +#include "hal.h" +#include "osi.h" + +#include +#include + +int osi_debug_level; +tOSI_INFO osi_info; + +OSI_STATE OSI_init(void) { + int32_t index; + + memset(&osi_info, 0, sizeof(osi_info)); + + /* Initialize lock */ + pthread_mutex_init(&osi_info.mutex, NULL); + + /* Initialize task information */ + for (index = 0; index < OSI_MAX_TASK; index++) { + osi_info.task[index].state = OSI_FREE; + } + + /* Initialize memory information */ + osi_info.mem_max_cnt = OSI_MAX_MEM_POOL; + for (index = 0; index < OSI_MAX_MEM_POOL; index++) { +#ifdef OSI_USE_DYNAMIC_BUF + osi_info.mem[index] = (tOSI_MEM_HANDLER)malloc(OSI_MEM_POOL_SIZE); + if (osi_info.mem[index] == NULL) { + OSI_loge("%s : maximum conut of buffer is set to %d, (expected: %d)", + index, OSI_MAX_MEM_POOL); + osi_info.mem_max_cnt = index; + break; + } + osi_info.mem[index]->state = OSI_FREE; +#else + osi_info.mem[index].state = OSI_FREE; +#endif + } + + /* Initialize queue information */ + osi_info.queue_max_cnt = OSI_MAX_QUEUE; + for (index = 0; index < OSI_MAX_QUEUE; index++) { + osi_info.queue[index].state = OSI_FREE; + osi_info.queue[index].tail = OSI_QUEUE_SIZE; + } + + /* Initialize timer information */ + for (index = 0; index < OSI_MAX_TIMER; index++) { + osi_info.timer[index].state = OSI_FREE; + osi_info.timer[index].name = NULL; + osi_info.timer[index].callback = NULL; + osi_info.timer[index].callback_param = NULL; + } + + return OSI_OK; +} + +void OSI_deinit() { + int index; +#ifdef OSI_USE_DYNAMIC_BUF + for (index = 0; index < osi_info.mem_max_cnt; index++) { + if (osi_info.mem[index]) free(osi_info.mem[index]); + } +#endif + + /* deinitialize timer */ + for (index = 0; index < OSI_MAX_TIMER; index++) { + OSI_timer_free(&osi_info.timer[index]); + } + osi_info.usingTimer = 0; +} + +void osi_lock() { pthread_mutex_lock(&osi_info.mutex); } + +void osi_unlock() { pthread_mutex_unlock(&osi_info.mutex); } + +void OSI_delay(uint32_t timeout) { + struct timespec delay; + int err; + + delay.tv_sec = timeout / 1000; + delay.tv_nsec = 1000 * 1000 * (timeout % 1000); + + do { + err = nanosleep(&delay, &delay); + } while (err < 0 && errno == EINTR); +} diff --git a/halimpl/osi/osi_memory.cc b/halimpl/osi/osi_memory.cc new file mode 100644 index 0000000..434afd7 --- /dev/null +++ b/halimpl/osi/osi_memory.cc @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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. + * + * + */ + +/************************************************************************ +** OS interface for task handling +*************************************************************************/ +#include +#include +#include +#include "osi.h" + +/************************************************************************ +** Internal function prototype +*************************************************************************/ + +/************************************************************************ +** Public functions +*************************************************************************/ +tOSI_MEM_HANDLER OSI_mem_get(size_t size) { + tOSI_MEM_HANDLER free_mem = NULL; + int index, err_cnt = 3; + + if (size > OSI_MEM_POOL_SIZE) { + OSI_loge("%s : memory getting failed. Max size=%d, Requested size=%d", + __func__, OSI_MEM_POOL_SIZE, (int)size); + return NULL; + } + +/* Try 3 times to get memory */ +retry_getting: + + osi_lock(); + for (index = 0; index < osi_info.mem_max_cnt; index++) { +#ifdef OSI_USE_DYNAMIC_BUF + if (osi_info.mem[index]->state == OSI_FREE) + free_mem = (tOSI_MEM_HANDLER)osi_info.mem[index]; +#else + if (osi_info.mem[index].state == OSI_FREE) + free_mem = (tOSI_MEM_HANDLER)&osi_info.mem[index]; +#endif + } + + if (free_mem == NULL) { + /* Not found free memory handler */ + OSI_loge("%s : Failed to find free memory pool(max: %d)", __func__, + osi_info.mem_max_cnt); +#ifdef OSI_USE_DYNAMIC_BUF + /* get a new buffer */ + free_mem = osi_info.mem[index] = + (tOSI_MEM_HANDLER)malloc(OSI_MEM_POOL_SIZE); + if (osi_info.mem[index] != NULL) { + osi_info.mem[index]->state = OSI_FREE; + osi_info.mem_max_cnt++; + OSI_loge("%s : get a new buffer (max: %d)", __func__, + osi_info.mem_max_cnt); + } else +#endif + if (--err_cnt > 0) { + OSI_loge("%s : try %d time(s) more!", __func__, err_cnt + 1); + osi_unlock(); + sched_yield(); + OSI_delay(20); + goto retry_getting; + } + } else { + free_mem->state = OSI_ALLOCATED; + memset(free_mem->buffer, 0, OSI_MEM_POOL_SIZE); + } + osi_unlock(); + + return free_mem; +} + +void OSI_mem_free(tOSI_MEM_HANDLER target) { + if (!target) return; + + osi_lock(); + target->state = OSI_FREE; + osi_unlock(); +} + +tOSI_QUEUE_HANDLER OSI_queue_allocate(const char* que_name) { + tOSI_QUEUE_HANDLER free_que = NULL; + int index; + + osi_lock(); + for (index = 0; index < osi_info.queue_max_cnt; index++) { + if (osi_info.queue[index].state == OSI_FREE) { + if (free_que == NULL) + free_que = (tOSI_QUEUE_HANDLER)&osi_info.queue[index]; + } else { + if (osi_info.queue[index].name == NULL) continue; + + if (strcmp((char const*)osi_info.queue[index].name, + (char const*)que_name) == 0) { + OSI_loge("%s : %s queue is already allocated [%d]", __func__, que_name, + index); + free_que = NULL; + break; + } + } + } + + if (free_que == NULL) { + OSI_loge("%s : Failed to find free queue(max: %d)", __func__, + OSI_MAX_QUEUE); + } else { + memset(free_que->queue, 0, OSI_QUEUE_SIZE); + free_que->name = que_name; + free_que->state = OSI_ALLOCATED; + free_que->head = 0; + free_que->tail = OSI_QUEUE_SIZE; + } + osi_unlock(); + + return free_que; +} + +int OSI_queue_put(tOSI_QUEUE_HANDLER queue, void* p_data) { + int ret; + + osi_lock(); + + if (!queue || queue->state != OSI_ALLOCATED) { + OSI_loge("%s : queue is not allocated", __func__); + return -1; + } + + if (queue->head == queue->tail) { + OSI_loge("%s : queue is overflower (max: %d)", __func__, OSI_QUEUE_SIZE); + } else { + queue->queue[queue->head++] = p_data; + if (queue->head >= OSI_QUEUE_SIZE) queue->head = 0; + + // pthread_cond_broadcast(&queue->cond); + pthread_cond_signal(&queue->cond); + } + + ret = (queue->head) - (queue->tail); + + osi_unlock(); + + if (ret < 0) ret += OSI_QUEUE_SIZE; + + return ret; +} + +void* queue_get(tOSI_QUEUE_HANDLER queue) { + void* data = NULL; + + if (!queue || queue->state != OSI_ALLOCATED) { + OSI_loge("%s : queue is not allocated", __func__); + return NULL; + } + + if (queue->tail + 1 >= OSI_QUEUE_SIZE) { + if (queue->head == 0) { + // empty + // OSI_loge("%s : queue is empty", __func__); + return NULL; + } + } else { + if (queue->tail + 1 == queue->head) { + // empty + // OSI_loge("%s : queue is empty", __func__); + return NULL; + } + } + + queue->tail++; + if (queue->tail >= OSI_QUEUE_SIZE) queue->tail = 0; + data = queue->queue[queue->tail]; + + return data; +} + +void* OSI_queue_get(tOSI_QUEUE_HANDLER queue) { + void* data = NULL; + + osi_lock(); + data = queue_get(queue); + osi_unlock(); + + return data; +} + +void* OSI_queue_get_wait(tOSI_QUEUE_HANDLER queue) { + void* ret; + + osi_lock(); + + if (!queue || queue->state != OSI_ALLOCATED) { + OSI_loge("%s : queue is not allocated", __func__); + return NULL; + } + + ret = queue_get(queue); + if (ret == NULL) { + pthread_cond_wait(&queue->cond, &osi_info.mutex); + ret = queue_get(queue); + } + + osi_unlock(); + + return ret; +} + +void OSI_queue_free(tOSI_QUEUE_HANDLER target) { + if (target) { + target->name = NULL; + target->state = OSI_FREE; + } +} + +tOSI_QUEUE_HANDLER OSI_queue_get_handler(const char* name) { + tOSI_QUEUE_HANDLER queue = NULL; + int index; + + if (name == NULL) return NULL; + + osi_lock(); + for (index = 0; index < OSI_MAX_QUEUE; index++) { + if (osi_info.queue[index].name == NULL) continue; + + if (strcmp((char const*)osi_info.queue[index].name, (char const*)name) == + 0) { + queue = (tOSI_QUEUE_HANDLER)&osi_info.queue[index]; + break; + } + } + osi_unlock(); + + return queue; +} diff --git a/halimpl/osi/osi_task.cc b/halimpl/osi/osi_task.cc new file mode 100644 index 0000000..9174b0e --- /dev/null +++ b/halimpl/osi/osi_task.cc @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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. + * + * + */ + +/************************************************************************ +** OS interface for task handling +*************************************************************************/ +#include +#include +#include +#include "osi.h" + +/************************************************************************ +** Internal function prototype +*************************************************************************/ + +/************************************************************************ +** Public functions +*************************************************************************/ +void osi_task_entry(void* arg) { + tOSI_TASK_ENTRY task_entry = (tOSI_TASK_ENTRY)arg; + + // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + task_entry(); + OSI_logt("%s : exit task", __func__); + + pthread_exit(NULL); +} + +tOSI_TASK_HANDLER OSI_task_allocate(const char* task_name, + tOSI_TASK_ENTRY task_entry) { + tOSI_TASK_HANDLER free_task = NULL; + int index; + + /* Find free task */ + osi_lock(); + for (index = 0; index < OSI_MAX_TASK; index++) { + if (osi_info.task[index].state == OSI_FREE) { + if (free_task == NULL) + free_task = (tOSI_TASK_HANDLER)&osi_info.task[index]; + } else { + if (osi_info.task[index].name == NULL) continue; + + /* User can't not make same name of task */ + if (strcmp((char const*)osi_info.task[index].name, + (char const*)task_name) == 0) { + OSI_loge("%s : %s task is already allocated [%d]", __func__, task_name, + index); + free_task = NULL; + break; + } + } + } + + if (free_task == NULL) { + OSI_loge("%s : Failed to find free task(max: %d)", __func__, OSI_MAX_TASK); + } else { + free_task->state = OSI_ALLOCATED; + free_task->name = task_name; + free_task->task_entry = task_entry; + } + + osi_unlock(); + return free_task; +} +OSI_STATE OSI_task_run(tOSI_TASK_HANDLER task_handler) { + pthread_attr_t attr; + int ret = OSI_FAIL; + + osi_lock(); + if (!task_handler) { + OSI_loge("%s : task handler is not exist!!", __func__); + } else if (task_handler->state != OSI_ALLOCATED) { + OSI_loge("%s : task state is not ALLOCATED!! (%d)", __func__, + task_handler->state); + } else { + /* Thread attr configuration */ + pthread_attr_init(&attr); + if (!pthread_create(&(task_handler->task), &attr, + (void* (*)(void*))osi_task_entry, + (void*)(task_handler->task_entry))) { // + task_handler->state = OSI_RUN; + ret = OSI_OK; + } else { + OSI_loge("%s : pthread_create failed(%d), %s", __func__, ret, + task_handler->name); + } + pthread_attr_destroy(&attr); + } + + osi_unlock(); + return ret; +} + +OSI_STATE OSI_task_isRun(tOSI_TASK_HANDLER task_handler) { + OSI_STATE ret = OSI_FAIL; + osi_lock(); + if (task_handler && task_handler->state == OSI_RUN) ret = OSI_RUN; + osi_unlock(); + return ret; +} + +OSI_STATE OSI_task_stop(tOSI_TASK_HANDLER task_handler) { + OSI_STATE ret = OSI_OK; + if (!task_handler) return OSI_OK; + + osi_lock(); + if (task_handler->state == OSI_RUN) { + osi_unlock(); + // ret = pthread_cancel(task_handler->task); + ret = (OSI_STATE)pthread_join(task_handler->task, NULL); + osi_lock(); + } + + task_handler->state = OSI_ALLOCATED; + osi_unlock(); + + return ret; +} + +OSI_STATE OSI_task_free(tOSI_TASK_HANDLER task_handler) { + OSI_STATE ret = OSI_OK; + + OSI_task_stop(task_handler); + osi_lock(); + task_handler->name = NULL; + task_handler->state = OSI_FREE; + osi_unlock(); + + return ret; +} + +OSI_STATE OSI_task_kill(tOSI_TASK_HANDLER task_handler) { + OSI_STATE ret = OSI_OK; + if (!task_handler) return OSI_OK; + + osi_lock(); + if (task_handler->state == OSI_RUN) { + osi_unlock(); + // ret = pthread_cancel(task_handler->task); + ret = (OSI_STATE)pthread_join(task_handler->task, NULL); + osi_lock(); + } + + task_handler->name = NULL; + task_handler->state = OSI_FREE; + osi_unlock(); + + return ret; +} + +tOSI_TASK_HANDLER OSI_task_get_handler(char* name) { + tOSI_TASK_HANDLER task = NULL; + int index; + + if (!name) return NULL; + + osi_lock(); + for (index = 0; index < OSI_MAX_TASK; index++) { + if ((char const*)osi_info.task[index].name == NULL) continue; + + if (strcmp((char const*)osi_info.task[index].name, (char const*)name) == + 0) { + task = &osi_info.task[index]; + break; + } + } + osi_unlock(); + + return task; +} diff --git a/halimpl/osi/osi_timer.cc b/halimpl/osi/osi_timer.cc new file mode 100644 index 0000000..6d65cab --- /dev/null +++ b/halimpl/osi/osi_timer.cc @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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. + * + * + */ + +/************************************************************************ +** OS interface for task handling +*************************************************************************/ +#include +#include +#include +#include +#include "osi.h" + +/************************************************************************ +** Internal function prototype +*************************************************************************/ +void timer_thread(void); + +/************************************************************************ +** Public functions +*************************************************************************/ +tOSI_TIMER_HANDLER OSI_timer_allocate(const char* timer_name) { + tOSI_TIMER_HANDLER free_timer = NULL; + int index; + + osi_lock(); + for (index = 0; index < OSI_MAX_TIMER; index++) { + if (osi_info.timer[index].state == OSI_FREE) { + if (free_timer == NULL) + free_timer = (tOSI_TIMER_HANDLER)&osi_info.timer[index]; + } else { + if ((char const*)osi_info.timer[index].name == NULL) continue; + + if (strcmp((char const*)osi_info.timer[index].name, + (char const*)timer_name) == 0) { + OSI_loge("%s : %s timer is already allocated [%d]", __func__, + timer_name, index); + free_timer = NULL; + break; + } + } + } + + if (free_timer == NULL) { + OSI_loge("%s : Failed to find free timer(max: %d)", __func__, + OSI_MAX_TIMER); + } else { + free_timer->timeout = 0; + free_timer->name = timer_name; + free_timer->callback = NULL; + free_timer->callback_param = NULL; + free_timer->state = OSI_ALLOCATED; + } + osi_unlock(); + + return free_timer; +} + +int OSI_timer_start(tOSI_TIMER_HANDLER timer, uint32_t timeout, + tOSI_TIMER_CALLBACK callback, void* param) { + pthread_attr_t attr; + int ret_th; + + if (timer == NULL) { + OSI_loge("%s : Invalid parameters", __func__); + return 0; + } else if (timer->state == OSI_FREE) { + OSI_loge("%s : The timer is not allocated", __func__); + return 0; + } else { + osi_lock(); + OSI_logt("enter,osi_lock"); + timer->timeout = timeout; + timer->exact_time = OSI_timer_get_current_time(); + timer->init_timeout = timeout - 10; + timer->callback = callback; + timer->callback_param = param; + + if (timer->state != OSI_RUN) { + timer->state = OSI_RUN; + + /* start timer thread */ + if (osi_info.usingTimer < 1) { + osi_info.timer_thread_flag |= OSI_TIMER_THREAD_FLAG_DETACH; + //[START] S.LSI - To increase usingTimer prior to timer_thread + osi_info.usingTimer++; + //[END] S.LSI - To increase usingTimer prior to timer_thread + ret_th = pthread_attr_init(&attr); + if (ret_th != 0) + OSI_loge("%s : Error pthread_attr_init! ,erron: %d", __func__, + ret_th); + + OSI_logt("before pthread_create for timer thread"); + ret_th = pthread_create(&osi_info.timer_thread, &attr, + (void* (*)(void*))timer_thread, NULL); + OSI_logt("after pthread_create for timer thread"); + if (ret_th != 0) + OSI_loge("%s : Error to create timer_thread! ,erron: %d", __func__, + ret_th); + + ret_th = pthread_attr_destroy(&attr); + if (ret_th != 0) + OSI_loge("%s : Error pthread_arrt_destroy ,erron: %d", __func__, + ret_th); + } else + osi_info.usingTimer++; + } + OSI_logt("before osi_unlock"); + osi_unlock(); + OSI_logt("exit"); + return timeout; + } +} + +void OSI_timer_stop(tOSI_TIMER_HANDLER timer) { + if (timer == NULL) { + OSI_loge("%s : Invalid parameters", __func__); + } else if (timer->state != OSI_RUN) { + OSI_logd("%s : This timer is not running", __func__); + } else { + osi_lock(); + timer->state = OSI_STOP; + osi_info.usingTimer--; + if (osi_info.usingTimer <= 0) { + /* Cancle pthread_detach */ + osi_info.timer_thread_flag &= ~OSI_TIMER_THREAD_FLAG_DETACH; + osi_unlock(); + pthread_join(osi_info.timer_thread, NULL); + } else + osi_unlock(); + } +} + +void OSI_timer_free(tOSI_TIMER_HANDLER timer) { + if (timer) { + osi_lock(); + + if (timer->state == OSI_RUN) osi_info.usingTimer--; + + timer->state = OSI_FREE; + timer->name = NULL; + timer->callback = NULL; + timer->callback_param = NULL; + + osi_unlock(); + } +} + +tOSI_TIMER_HANDLER OSI_timer_get_handler(char* name) { + tOSI_TIMER_HANDLER timer = NULL; + int index; + + if (name == NULL) return NULL; + + osi_lock(); + for (index = 0; index < OSI_MAX_TIMER; index++) { + if ((char const*)osi_info.timer[index].name == NULL) continue; + + if (strcmp((char const*)osi_info.timer[index].name, (char const*)name) == + 0) { + timer = &osi_info.timer[index]; + break; + } + } + osi_unlock(); + + return timer; +} + +int32_t OSI_timer_get_current_time() { + struct timeval sec; + struct tm* now; + time_t rawtime; + + gettimeofday(&sec, NULL); + time(&rawtime); + now = gmtime(&rawtime); + + return (((now->tm_hour * 3600) + (now->tm_min * 60) + (now->tm_sec)) * 1000) + + (sec.tv_usec / 1000); +} +/************************************************************************ +** Internal function +*************************************************************************/ +void OSI_timer_update(int32_t tick) { + int index; + + osi_lock(); + + /* timer is not using */ + if (osi_info.usingTimer <= 0) { + osi_unlock(); + return; + } + + for (index = 0; index < OSI_MAX_TIMER; index++) { + if (osi_info.timer[index].state == OSI_RUN) { + osi_info.timer[index].timeout -= tick; + + if (osi_info.timer[index].timeout <= 0) { + /* START [16051100] - RTCC Patch */ + if (((OSI_timer_get_current_time() - osi_info.timer[index].exact_time) > + osi_info.timer[index].init_timeout) || + (OSI_timer_get_current_time() < osi_info.timer[index].exact_time)) + /* END [16051100] - RTCC Patch */ + { + osi_info.timer[index].state = OSI_STOP; + osi_info.usingTimer--; + + if (osi_info.timer[index].callback != NULL) + osi_info.timer[index].callback( + osi_info.timer[index].callback_param); + } else { + osi_info.timer[index].timeout = + osi_info.timer[index].init_timeout - + (OSI_timer_get_current_time() - osi_info.timer[index].exact_time); + } + } + } + } + osi_unlock(); +} + +void timer_thread(void) { + struct timespec delay; + int err; + + while (osi_info.usingTimer > 0) { + /* delay */ + // OSI_delay(1); + { + /* 1ms sleep for nanosleep()*/ + delay.tv_sec = 0; + delay.tv_nsec = 1000 * 1000; + + do { + err = nanosleep(&delay, &delay); + if (err < 0) OSI_loge("%s:Fail nanosleep", __func__); + } while (err < 0 && errno == EINTR); + } + + OSI_timer_update(1); + } + + if (osi_info.timer_thread_flag & OSI_TIMER_THREAD_FLAG_DETACH) + pthread_detach(pthread_self()); + + pthread_exit(NULL); +} diff --git a/halimpl/src/config.cpp b/halimpl/src/config.cpp new file mode 100644 index 0000000..f488ed2 --- /dev/null +++ b/halimpl/src/config.cpp @@ -0,0 +1,833 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * + * 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. + * + ******************************************************************************/ +/****************************************************************************** + * + * The original Work has been changed by Samsung Electronics. + + * + * Copyright (C) 2018 Samsung Electronics, System LSI Division + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +#if GENERIC_TARGET +const char alternative_config_path[] = "/data/vendor/nfc/"; +#else +const char alternative_config_path[] = ""; +#endif + +#if 1 +const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"}; +#else +const char* transport_config_paths[] = {"res/"}; +#endif +const int transport_config_path_size = + (sizeof(transport_config_paths) / sizeof(transport_config_paths[0])); + +#define config_name "libnfc-sec-vendor.conf" +#define extra_config_base "libnfc-sec-vendor" +#define extra_config_ext ".conf" +#define IsStringValue 0x80000000 + +#if (NFC_SEC_NOT_OPEN_INCLUDED == TRUE) + +std::string UserPrefix; + +extern "C" void Set_user_prefix(char* field) { + UserPrefix.erase(); + + if (field != NULL) UserPrefix = field; +} +#endif + +namespace { + +size_t readConfigFile(const char* fileName, uint8_t** p_data) { + FILE* fd = fopen(fileName, "rb"); + if (fd == nullptr) return 0; + + fseek(fd, 0L, SEEK_END); + const size_t file_size = ftell(fd); + rewind(fd); + + uint8_t* buffer = new uint8_t[file_size]; + size_t read = fread(buffer, file_size, 1, fd); + fclose(fd); + + if (read == 1) { + *p_data = buffer; + return file_size; + } + + delete[] buffer; + return 0; +} + +} // namespace + +using namespace ::std; + +class CNfcParam : public string { + public: + CNfcParam(); + CNfcParam(const char* name, const string& value); + CNfcParam(const char* name, unsigned long value); + virtual ~CNfcParam(); + unsigned long numValue() const { return m_numValue; } + const char* str_value() const { return m_str_value.c_str(); } + size_t str_len() const { return m_str_value.length(); } + + private: + string m_str_value; + unsigned long m_numValue; +}; + +class CNfcConfig : public vector { + public: + virtual ~CNfcConfig(); + static CNfcConfig& GetInstance(); + friend void readOptionalConfig(const char* optional); + + bool getValue(const char* name, char* pValue, size_t len) const; + bool getValue(const char* name, unsigned long& rValue) const; + bool getValue(const char* name, unsigned short& rValue) const; + bool getValue(const char* name, char* pValue, long len, long* readlen) const; +#if (NFC_SEC_NOT_OPEN_INCLUDED == TRUE) + const CNfcParam* _find(const char* p_name) const; +#endif + const CNfcParam* find(const char* p_name) const; + void clean(); + + private: + CNfcConfig(); + bool readConfig(const char* name, bool bResetContent); + void moveFromList(); + void moveToList(); + void add(const CNfcParam* pParam); + list m_list; + bool mValidFile; + unsigned long state; + + inline bool Is(unsigned long f) { return (state & f) == f; } + inline void Set(unsigned long f) { state |= f; } + inline void Reset(unsigned long f) { state &= ~f; } +}; + +/******************************************************************************* +** +** Function: isPrintable() +** +** Description: determine if 'c' is printable +** +** Returns: 1, if printable, otherwise 0 +** +*******************************************************************************/ +inline bool isPrintable(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || +#if (NFC_SEC_NOT_OPEN_INCLUDED == TRUE) + (c == '+') || +#endif + c == '/' || c == '_' || c == '-' || c == '.'; +} + +/******************************************************************************* +** +** Function: isDigit() +** +** Description: determine if 'c' is numeral digit +** +** Returns: true, if numerical digit +** +*******************************************************************************/ +inline bool isDigit(char c, int base) { + if ('0' <= c && c <= '9') return true; + if (base == 16) { + if (('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) return true; + } + return false; +} + +/******************************************************************************* +** +** Function: getDigitValue() +** +** Description: return numerical value of a decimal or hex char +** +** Returns: numerical value if decimal or hex char, otherwise 0 +** +*******************************************************************************/ +inline int getDigitValue(char c, int base) { + if ('0' <= c && c <= '9') return c - '0'; + if (base == 16) { + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + else if ('a' <= c && c <= 'f') + return c - 'a' + 10; + } + return 0; +} + +/******************************************************************************* +** +** Function: findConfigFilePathFromTransportConfigPaths() +** +** Description: find a config file path with a given config name from transport +** config paths +** +** Returns: none +** +*******************************************************************************/ +void findConfigFilePathFromTransportConfigPaths(const string& configName, + string& filePath) { + for (int i = 0; i < transport_config_path_size - 1; i++) { + filePath.assign(transport_config_paths[i]); + filePath += configName; + struct stat file_stat; + if (stat(filePath.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode)) { + return; + } + } + filePath.assign(transport_config_paths[transport_config_path_size - 1]); + filePath += configName; +} + +/******************************************************************************* +** +** Function: CNfcConfig::readConfig() +** +** Description: read Config settings and parse them into a linked list +** move the element from linked list to a array at the end +** +** Returns: 1, if there are any config data, 0 otherwise +** +*******************************************************************************/ +bool CNfcConfig::readConfig(const char* name, bool bResetContent) { + enum { + BEGIN_LINE = 1, + TOKEN, + STR_VALUE, + NUM_VALUE, + BEGIN_HEX, + BEGIN_QUOTE, + END_LINE + }; + + uint8_t* p_config = nullptr; + size_t config_size = readConfigFile(name, &p_config); + if (p_config == nullptr) { + ALOGE("%s Cannot open config file %s\n", __func__, name); + if (bResetContent) { + ALOGE("%s Using default value for all settings\n", __func__); + mValidFile = false; + } + return false; + } + + string token; + string strValue; + unsigned long numValue = 0; + CNfcParam* pParam = NULL; + int i = 0; + int base = 0; + char c; + int bflag = 0; + state = BEGIN_LINE; + + mValidFile = true; + if (size() > 0) { + if (bResetContent) + clean(); + else + moveToList(); + } + + for (size_t offset = 0; offset != config_size; ++offset) { + c = p_config[offset]; + switch (state & 0xff) { + case BEGIN_LINE: + if (c == '#') + state = END_LINE; + else if (isPrintable(c)) { + i = 0; + token.erase(); + strValue.erase(); + state = TOKEN; + token.push_back(c); + } + break; + case TOKEN: + if (c == '=') { + token.push_back('\0'); + state = BEGIN_QUOTE; + } else if (isPrintable(c)) + token.push_back(c); + else + state = END_LINE; + break; + case BEGIN_QUOTE: + if (c == '"') { + state = STR_VALUE; + base = 0; + } else if (c == '0') + state = BEGIN_HEX; + else if (isDigit(c, 10)) { + state = NUM_VALUE; + base = 10; + numValue = getDigitValue(c, base); + i = 0; + } else if (c == '{') { + state = NUM_VALUE; + bflag = 1; + base = 16; + i = 0; + Set(IsStringValue); + } else + state = END_LINE; + break; + case BEGIN_HEX: + if (c == 'x' || c == 'X') { + state = NUM_VALUE; + base = 16; + numValue = 0; + i = 0; + break; + } else if (isDigit(c, 10)) { + state = NUM_VALUE; + base = 10; + numValue = getDigitValue(c, base); + break; + } else if (c != '\n' && c != '\r') { + state = END_LINE; + break; + } + // fall through to numValue to handle numValue + [[fallthrough]]; + + case NUM_VALUE: + if (isDigit(c, base)) { + numValue *= base; + numValue += getDigitValue(c, base); + ++i; + } else if (bflag == 1 && + (c == ' ' || c == '\r' || c == '\n' || c == '\t')) { + break; + } else if (base == 16 && + (c == ',' || c == ':' || c == '-' || c == ' ' || c == '}')) { + if (c == '}') { + bflag = 0; + } + if (i > 0) { + int n = (i + 1) / 2; + while (n-- > 0) { + numValue = numValue >> (n * 8); + unsigned char c = (numValue)&0xFF; + strValue.push_back(c); + } + } + + Set(IsStringValue); + numValue = 0; + i = 0; + } else { + if (c == '\n' || c == '\r') { + if (bflag == 0) { + state = BEGIN_LINE; + } + } else { + if (bflag == 0) { + state = END_LINE; + } + } + if (Is(IsStringValue) && base == 16 && i > 0) { + int n = (i + 1) / 2; + while (n-- > 0) strValue.push_back(((numValue >> (n * 8)) & 0xFF)); + } + if (strValue.length() > 0) + pParam = new CNfcParam(token.c_str(), strValue); + else + pParam = new CNfcParam(token.c_str(), numValue); + add(pParam); + strValue.erase(); + numValue = 0; + } + break; + case STR_VALUE: + if (c == '"') { + strValue.push_back('\0'); + state = END_LINE; + pParam = new CNfcParam(token.c_str(), strValue); + add(pParam); + } else if (isPrintable(c)) + strValue.push_back(c); + break; + case END_LINE: + if (c == '\n' || c == '\r') state = BEGIN_LINE; + break; + default: + break; + } + } + + delete[] p_config; + + moveFromList(); + return size() > 0; +} + +/******************************************************************************* +** +** Function: CNfcConfig::CNfcConfig() +** +** Description: class constructor +** +** Returns: none +** +*******************************************************************************/ +CNfcConfig::CNfcConfig() : mValidFile(true), state(0) {} + +/******************************************************************************* +** +** Function: CNfcConfig::~CNfcConfig() +** +** Description: class destructor +** +** Returns: none +** +*******************************************************************************/ +CNfcConfig::~CNfcConfig() {} + +/******************************************************************************* +** +** Function: CNfcConfig::GetInstance() +** +** Description: get class singleton object +** +** Returns: none +** +*******************************************************************************/ +CNfcConfig& CNfcConfig::GetInstance() { + static CNfcConfig theInstance; + if (theInstance.size() == 0 && theInstance.mValidFile) { + string strPath; + if (alternative_config_path[0] != '\0') { + strPath.assign(alternative_config_path); + strPath += config_name; + theInstance.readConfig(strPath.c_str(), true); + if (!theInstance.empty()) { + return theInstance; + } + } + findConfigFilePathFromTransportConfigPaths(config_name, strPath); + theInstance.readConfig(strPath.c_str(), true); + } + + return theInstance; +} + +/******************************************************************************* +** +** Function: CNfcConfig::getValue() +** +** Description: get a string value of a setting +** +** Returns: true if setting exists +** false if setting does not exist +** +*******************************************************************************/ +bool CNfcConfig::getValue(const char* name, char* pValue, size_t len) const { + const CNfcParam* pParam = find(name); + if (pParam == NULL) return false; + + if (pParam->str_len() > 0) { + memset(pValue, 0, len); + memcpy(pValue, pParam->str_value(), pParam->str_len()); + return true; + } + return false; +} + +bool CNfcConfig::getValue(const char* name, char* pValue, long len, + long* readlen) const { + const CNfcParam* pParam = find(name); + if (pParam == NULL) return false; + + if (pParam->str_len() > 0) { + if (pParam->str_len() <= (unsigned long)len) { + memset(pValue, 0, len); + memcpy(pValue, pParam->str_value(), pParam->str_len()); + *readlen = pParam->str_len(); + } else { + *readlen = -1; + } + + return true; + } + return false; +} + +/******************************************************************************* +** +** Function: CNfcConfig::getValue() +** +** Description: get a long numerical value of a setting +** +** Returns: true if setting exists +** false if setting does not exist +** +*******************************************************************************/ +bool CNfcConfig::getValue(const char* name, unsigned long& rValue) const { + const CNfcParam* pParam = find(name); + if (pParam == NULL) return false; + + if (pParam->str_len() == 0) { + rValue = static_cast(pParam->numValue()); + return true; + } + return false; +} + +/******************************************************************************* +** +** Function: CNfcConfig::getValue() +** +** Description: get a short numerical value of a setting +** +** Returns: true if setting exists +** false if setting does not exist +** +*******************************************************************************/ +bool CNfcConfig::getValue(const char* name, unsigned short& rValue) const { + const CNfcParam* pParam = find(name); + if (pParam == NULL) return false; + + if (pParam->str_len() == 0) { + rValue = static_cast(pParam->numValue()); + return true; + } + return false; +} + +/******************************************************************************* +** +** Function: CNfcConfig::find() +** +** Description: search if a setting exist in the setting array +** +** Returns: pointer to the setting object +** +*******************************************************************************/ +#if (NFC_SEC_NOT_OPEN_INCLUDED == TRUE) +const CNfcParam* CNfcConfig::find(const char* p_name) const { + if (size() == 0) return NULL; + + std::string firstField; + + if (UserPrefix.size() > 0) { + // Find first priority field + firstField.erase(); + firstField += "+"; + firstField += UserPrefix; + firstField += "_"; + firstField += p_name; + + const CNfcParam* ret = _find(firstField.c_str()); + if (ret != NULL) return ret; + } + + return _find(p_name); +} + +const CNfcParam* CNfcConfig::_find(const char* p_name) const { + for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it) { + if (**it < p_name) + continue; + else if (**it == p_name) { + if ((*it)->str_len() > 0) + ALOGD("%s found %s=%s\n", __func__, p_name, (*it)->str_value()); + else + ALOGD("%s found %s=(0x%lX)\n", __func__, p_name, (*it)->numValue()); + return *it; + } else + break; + } + + return NULL; +} +#else +const CNfcParam* CNfcConfig::find(const char* p_name) const { + if (size() == 0) return NULL; + + for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it) { + if (**it < p_name) { + continue; + } else if (**it == p_name) { + if ((*it)->str_len() > 0) { + ALOGD("%s found %s=%s\n", __func__, p_name, (*it)->str_value()); + + } else { + ALOGD("%s found %s=(0x%lx)\n", __func__, p_name, (*it)->numValue()); + } + return *it; + } else + break; + } + return NULL; +} +#endif +/******************************************************************************* +** +** Function: CNfcConfig::clean() +** +** Description: reset the setting array +** +** Returns: none +** +*******************************************************************************/ +void CNfcConfig::clean() { + if (size() == 0) return; + + for (iterator it = begin(), itEnd = end(); it != itEnd; ++it) delete *it; + clear(); +} + +/******************************************************************************* +** +** Function: CNfcConfig::Add() +** +** Description: add a setting object to the list +** +** Returns: none +** +*******************************************************************************/ +void CNfcConfig::add(const CNfcParam* pParam) { + if (m_list.size() == 0) { + m_list.push_back(pParam); + return; + } + for (list::iterator it = m_list.begin(), + itEnd = m_list.end(); + it != itEnd; ++it) { + if (**it < pParam->c_str()) continue; + m_list.insert(it, pParam); + return; + } + m_list.push_back(pParam); +} + +/******************************************************************************* +** +** Function: CNfcConfig::moveFromList() +** +** Description: move the setting object from list to array +** +** Returns: none +** +*******************************************************************************/ +void CNfcConfig::moveFromList() { + if (m_list.size() == 0) return; + + for (list::iterator it = m_list.begin(), + itEnd = m_list.end(); + it != itEnd; ++it) + push_back(*it); + m_list.clear(); +} + +/******************************************************************************* +** +** Function: CNfcConfig::moveToList() +** +** Description: move the setting object from array to list +** +** Returns: none +** +*******************************************************************************/ +void CNfcConfig::moveToList() { + if (m_list.size() != 0) m_list.clear(); + + for (iterator it = begin(), itEnd = end(); it != itEnd; ++it) + m_list.push_back(*it); + clear(); +} +/******************************************************************************* +** +** Function: CNfcParam::CNfcParam() +** +** Description: class constructor +** +** Returns: none +** +*******************************************************************************/ +CNfcParam::CNfcParam() : m_numValue(0) {} + +/******************************************************************************* +** +** Function: CNfcParam::~CNfcParam() +** +** Description: class destructor +** +** Returns: none +** +*******************************************************************************/ +CNfcParam::~CNfcParam() {} + +/******************************************************************************* +** +** Function: CNfcParam::CNfcParam() +** +** Description: class copy constructor +** +** Returns: none +** +*******************************************************************************/ +CNfcParam::CNfcParam(const char* name, const string& value) + : string(name), m_str_value(value), m_numValue(0) {} + +/******************************************************************************* +** +** Function: CNfcParam::CNfcParam() +** +** Description: class copy constructor +** +** Returns: none +** +*******************************************************************************/ +CNfcParam::CNfcParam(const char* name, unsigned long value) + : string(name), m_numValue(value) {} + +/******************************************************************************* +** +** Function: GetStrValue +** +** Description: API function for getting a string value of a setting +** +** Returns: True if found, otherwise False. +** +*/ +extern "C" int GetStrValue(const char* name, char* pValue, // SLSI + unsigned long len) { + CNfcConfig& rConfig = CNfcConfig::GetInstance(); + + return rConfig.getValue(name, pValue, len); +} +/******************************************************************************* +** +** Function: GetByteArrayValue() +** +** Description: Read byte array value from the config file. +** +** Parameters: +** name - name of the config param to read. +** pValue - pointer to input buffer. +** bufflen - input buffer length. +** len - out parameter to return the number of bytes read from +** config file, return -1 in case bufflen is not enough. +** +** Returns: TRUE[1] if config param name is found in the config file, else +** FALSE[0] +** +*******************************************************************************/ +extern "C" int GetByteArrayValue(const char* name, char* pValue, // SLSI + long bufflen, long* len) { + CNfcConfig& rConfig = CNfcConfig::GetInstance(); + + return rConfig.getValue(name, pValue, bufflen, len); +} +/******************************************************************************* +** +** Function: GetNumValue +** +** Description: API function for getting a numerical value of a setting +** +** Returns: true, if successful +** +*******************************************************************************/ +extern "C" int GetNumValue(const char* name, void* pValue, // SLSI + unsigned long len) { + if (!pValue) return false; + + CNfcConfig& rConfig = CNfcConfig::GetInstance(); + const CNfcParam* pParam = rConfig.find(name); + + if (pParam == NULL) return false; + unsigned long v = pParam->numValue(); + if (v == 0 && pParam->str_len() > 0 && pParam->str_len() < 4) { + const unsigned char* p = (const unsigned char*)pParam->str_value(); + for (unsigned int i = 0; i < pParam->str_len(); ++i) { + v *= 256; + v += *p++; + } + } + switch (len) { + case sizeof(unsigned long): + *(static_cast(pValue)) = (unsigned long)v; + break; + case sizeof(unsigned short): + *(static_cast(pValue)) = (unsigned short)v; + break; + case sizeof(unsigned char): + *(static_cast(pValue)) = (unsigned char)v; + break; + default: + return false; + } + return true; +} diff --git a/halimpl/src/device.cc b/halimpl/src/device.cc new file mode 100644 index 0000000..64c128f --- /dev/null +++ b/halimpl/src/device.cc @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "hal.h" +#include "osi.h" +#include "sec_nfc.h" +#include "util.h" + +int pw_driver, tr_driver; +pthread_mutex_t tr_lock; +int tr_closer; +bool isSleep; +int wakeup_delay; +bool log_ptr; +eNFC_DEV_MODE dev_state; +tOSI_TASK_HANDLER read_task; + +// [Start] Workaround - i2c write fail(self wakeup) +bool first_wakeup; +// [End] Workaround - i2c write fail(self wakeup) +void read_thread(void); +void data_trace(const char* head, int len, uint8_t* p_data); + +int device_init(int data_trace) { + dev_state = NFC_DEV_MODE_OFF; + log_ptr = data_trace; + + read_task = OSI_task_allocate("read_task", read_thread); + if (!read_task) { + OSI_loge("Failed to allocate task for read thread!!"); + return -1; + } + + pthread_mutex_init(&tr_lock, NULL); + + return 0; +} + +void device_deinit() { + device_close(); + pthread_mutex_destroy(&tr_lock); + OSI_task_free(read_task); +} + +int device_open() { + int ret; + char pw_driver_name[64]; + char tr_driver_name[64]; + + ret = get_config_string(cfg_name_table[CFG_POWER_DRIVER], pw_driver_name, + sizeof(pw_driver_name)); + if (ret == 0) return -EPERM; + + ret = get_config_string(cfg_name_table[CFG_TRANS_DRIVER], tr_driver_name, + sizeof(tr_driver_name)); + if (ret == 0) return -EPERM; + + pw_driver = open(pw_driver_name, O_RDWR | O_NOCTTY); + if (pw_driver < 0) { + OSI_loge("Failed to open device driver: %s, pw_driver : 0x%x, errno = %d", + pw_driver_name, pw_driver, errno); + return pw_driver; + } + + tr_driver = pw_driver; + + OSI_loge("pw_driver: %d, tr_driver: %d", pw_driver, tr_driver); + device_set_mode(NFC_DEV_MODE_BOOTLOADER); + + if (OSI_OK != OSI_task_run(read_task)) { + OSI_loge("Failed to run read task!!"); + OSI_task_stop(read_task); + close(tr_driver); + close(pw_driver); + return -1; + } + + if (!get_config_int(cfg_name_table[CFG_WAKEUP_DELAY], &wakeup_delay)) + wakeup_delay = 10; + + return 0; +} + +void device_close(void) { + close(tr_driver); + close(pw_driver); + + pthread_mutex_lock(&tr_lock); + tr_driver = -1; + pw_driver = -1; + pthread_mutex_unlock(&tr_lock); + + if (tr_closer != 0) write(tr_closer, "x", 1); + + OSI_task_stop(read_task); +} + +int device_set_mode(eNFC_DEV_MODE mode) { + int ret; + + OSI_logt("device mode chage: %d -> %d", dev_state, mode); + ret = ioctl(pw_driver, SEC_NFC_SET_MODE, (int)mode); + if (!ret) { + if (mode == NFC_DEV_MODE_ON) isSleep = true; + dev_state = mode; + } + + return ret; +} + +int device_sleep(void) { + if (isSleep) return 0; + + isSleep = true; + OSI_logt("NFC can be going to sleep"); + return ioctl(pw_driver, SEC_NFC_SLEEP, 0); +} + +int device_wakeup(void) { + int ret = 0; + if (!isSleep) return 0; + + isSleep = false; + // [Start] Workaround - i2c write fail(self wakeup) + first_wakeup = true; + // [End] Workaround - i2c write fail(self wakeup) + ret = ioctl(pw_driver, SEC_NFC_WAKEUP, 0); + + /* START [H16031401] */ + if (nfc_hal_info.state == HAL_STATE_SERVICE && + nfc_hal_info.msg_event == HAL_EVT_READ) + return ret; + /* END [H16031401] */ + OSI_logt("Wakeup! in %d ms", wakeup_delay); + /* wakeup delay */ + OSI_delay(wakeup_delay); + OSI_logt("exit"); + + return ret; +} + +int device_write(uint8_t* data, size_t len) { + OSI_logt("enter"); + int ret = 0; + int total = 0; + int retry = 1; + + while (len != 0) { + OSI_logt("before system call"); + ret = write(tr_driver, data + total, len); + OSI_logt("after system call"); + if (ret < 0) { + OSI_loge("write error ret = %d, errno = %d, retry = %d", ret, errno, + retry); + if (retry++ < 3 && (nfc_hal_info.flag & HAL_FLAG_RETRY_TRNS)) { + // [Start] Workaround - i2c write fail(self wakeup) + if ((retry == 2) && (first_wakeup == true)) { + ret = ioctl(pw_driver, SEC_NFC_SLEEP, 0); + OSI_delay(1); + ret = ioctl(pw_driver, SEC_NFC_WAKEUP, 0); + + OSI_delay(wakeup_delay); + first_wakeup = false; + continue; + } + // [End] Workaround - i2c write fail(self wakeup) + else { + OSI_delay(5); + continue; + } + } + break; + } + total += ret; + len -= ret; + } + + if (len == 0) data_trace("Send", total, data); + + OSI_logt("exit"); + return total; +} + +int device_read(uint8_t* buffer, size_t len) { + int ret = 0; + int total = 0; + int retry = 1; + + while (len != 0) { + ret = read(tr_driver, buffer + total, len); + if (ret <= 0) { + OSI_loge("Read error ret = %d, errno = %d", ret, errno); + if (retry++ < 3 && (nfc_hal_info.flag & HAL_FLAG_RETRY_TRNS)) continue; + break; + } + + total += ret; + len -= ret; + } + + return total; +} + +void read_thread(void) { + tOSI_QUEUE_HANDLER msg_que = NULL; + tNFC_HAL_MSG* msg = NULL; + fd_set rfds; + uint8_t header[NCI_HDR_SIZE]; + int close_pipe[2]; + int max_fd; + struct timeval tv; + struct timeval* ptv = NULL; + int ret; + + OSI_logt("enter"); + /* get msg que */ + msg_que = OSI_queue_get_handler("msg_q"); + if (!msg_que) { + OSI_loge("Not find %s queue!! exit read thread", "msg_q"); + return; + } + + /* closer */ + if (pipe(close_pipe) < 0) { + OSI_loge("pipe open error for closing read thread"); + close_pipe[0] = 0; + close_pipe[1] = 0; + ptv = &tv; + } + tr_closer = close_pipe[1]; + max_fd = (close_pipe[0] > tr_driver) ? close_pipe[0] : tr_driver; + + while (OSI_task_isRun(read_task) == OSI_RUN) { + pthread_mutex_lock(&tr_lock); + if (tr_driver < 0) { + pthread_mutex_unlock(&tr_lock); + break; + } + FD_ZERO(&rfds); + FD_SET(tr_driver, &rfds); + pthread_mutex_unlock(&tr_lock); + + if (close_pipe[0] > 0) { + FD_SET(close_pipe[0], &rfds); + } else { + tv.tv_sec = 0; + tv.tv_usec = 2000; + } + + ret = select(max_fd + 1, &rfds, NULL, NULL, ptv); + + pthread_mutex_lock(&tr_lock); + if (tr_driver < 0) { + pthread_mutex_unlock(&tr_lock); + break; + } + pthread_mutex_unlock(&tr_lock); + + if (ret == 0) /* timeout */ + continue; + else if (ret < 0 && errno == EINTR) /* signal received */ + continue; + else if (ret < 0) { + OSI_loge("Polling error"); + nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_OK); + break; + } + + /* read 3 bytes (header)*/ + ret = device_read(header, NCI_HDR_SIZE); + if (ret == 0) + continue; + else if (ret != NCI_HDR_SIZE) { + OSI_loge("Reading NCI header failed"); + continue; + } + + msg = (tNFC_HAL_MSG*)OSI_mem_get(NCI_CTRL_SIZE); + if (!msg) { + OSI_loge("Failed to allocate memory!1"); + nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_OK); + break; + } + + /* payload will read upper layer */ + + msg->event = HAL_EVT_READ; + memcpy((void*)msg->param, (void*)header, NCI_HDR_SIZE); + + ret = OSI_queue_put(msg_que, (void*)msg); + OSI_logd("Sent message to HAL message task, remind que: %d", ret); + } + + close(close_pipe[0]); + close(close_pipe[1]); + tr_closer = 0; + + osi_unlock(); // TODO: why? + + OSI_logt("end;"); +} + +#define TRACE_BUFFER_SIZE (NCI_CTRL_SIZE * 3 + 1) +void data_trace(const char* head, int len, uint8_t* p_data) { + int i = 0, header; + char trace_buffer[TRACE_BUFFER_SIZE + 2]; + + header = (dev_state == NFC_DEV_MODE_BOOTLOADER) ? 4 : 3; + while (len-- > 0 && i < NCI_CTRL_SIZE) { + if (i < header) + sprintf(trace_buffer + (i * 3), "%02x ", p_data[i]); + else + sprintf(trace_buffer + (i * 3 + 2), "%02x ", p_data[i]); + i++; + } + + if (log_ptr) OSI_logd(" %s(%3d) %s", head, i, trace_buffer); +} diff --git a/halimpl/src/hal.cc b/halimpl/src/hal.cc new file mode 100644 index 0000000..98bdd77 --- /dev/null +++ b/halimpl/src/hal.cc @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 +#include +#include + +#include "device.h" +#include "hal.h" +#include "osi.h" +#include "util.h" + +#include "config.h" + +using namespace android::hardware::nfc::V1_1; +using android::hardware::nfc::V1_1::NfcEvent; +tNFC_HAL_CB nfc_hal_info; + +/* START - VTS Replay */ +bool sending_nci_packet = false; +/* END - VTS Replay */ + +/************************************* + * Generic device handling. + *************************************/ +bool nfc_stack_cback(nfc_event_t event, nfc_status_t event_status) { + OSI_logt("!"); + if (!nfc_hal_info.stack_cback) return false; + + nfc_hal_info.stack_cback(event, event_status); + return true; +} + +bool nfc_data_callback(tNFC_NCI_PKT* pkt) { + uint8_t* data = (uint8_t*)pkt; + size_t len = NCI_LEN(pkt) + NCI_HDR_SIZE; + + OSI_logt("!"); + if (!nfc_hal_info.data_cback) return false; + + /* START - VTS Replay */ + if (((data[0] >> 4) == 4) && (sending_nci_packet == true)) { + OSI_logt("clear sendig_nci_packet"); + sending_nci_packet = false; + } + /* END - VTS Replay */ + + nfc_hal_info.data_cback(len, data); + return true; +} + +int nfc_hal_init(void) { + char valueStr[PROPERTY_VALUE_MAX] = {0}; + bool data_trace = false; + int trace_level = 0; + int ret; + + OSI_set_debug_level(2); + OSI_init(); + + OSI_logt("enter; ========================================"); + + /* START - VTS Replay */ + sending_nci_packet = false; + /* END - VTS Replay */ + + /* don't print log at user binary */ + ret = property_get("ro.build.type", valueStr, ""); + if (!strncmp("user", valueStr, PROPERTY_VALUE_MAX)) { + property_get("ro.debug_level", valueStr, ""); + if (strncmp("0x4f4c", valueStr, PROPERTY_VALUE_MAX)) { + trace_level = 2; + data_trace = true; + } + } else { + if (!get_config_int(cfg_name_table[CFG_TRACE_LEVEL], &trace_level)) + trace_level = 0; + + if (get_config_int(cfg_name_table[CFG_DATA_TRACE], &ret)) + if (ret > 0) data_trace = true; + } + + OSI_set_debug_level(trace_level); + + memset(&nfc_hal_info, 0, sizeof(nfc_hal_info)); + // contenxt init + nfc_hal_info.state = HAL_STATE_INIT; + nfc_hal_info.stack_cback = NULL; + nfc_hal_info.data_cback = NULL; + nfc_hal_info.nci_last_pkt = (tNFC_NCI_PKT*)OSI_mem_get(NCI_CTRL_SIZE); + nfc_hal_info.nci_fragment_pkt = NULL; + nfc_hal_info.msg_task = OSI_task_allocate("hal_task", nfc_hal_task); + nfc_hal_info.nci_timer = OSI_timer_allocate("nci_timer"); + nfc_hal_info.sleep_timer = OSI_timer_allocate("sleep_timer"); + nfc_hal_info.msg_q = OSI_queue_allocate("msg_q"); + nfc_hal_info.nci_q = OSI_queue_allocate("nci_q"); + + setSleepTimeout(SET_SLEEP_TIME_CFG, 5000); + + if (!nfc_hal_info.msg_task || !nfc_hal_info.nci_timer || + !nfc_hal_info.sleep_timer || !nfc_hal_info.msg_q || !nfc_hal_info.nci_q) { + nfc_hal_deinit(); + return -EPERM; + } + + if (device_init(data_trace)) { + nfc_hal_deinit(); + return -EPERM; + } + + OSI_logt("succeed;"); + return 0; +} + +void nfc_hal_deinit(void) { + OSI_logt("enter;"); + + device_close(); + + nfc_hal_info.state = HAL_STATE_DEINIT; + OSI_task_kill(nfc_hal_info.msg_task); + nfc_hal_info.stack_cback = NULL; + nfc_hal_info.data_cback = NULL; + OSI_mem_free((tOSI_MEM_HANDLER)nfc_hal_info.nci_last_pkt); + nfc_hal_info.nci_last_pkt = NULL; + OSI_mem_free((tOSI_MEM_HANDLER)nfc_hal_info.nci_fragment_pkt); + nfc_hal_info.nci_fragment_pkt = NULL; + OSI_timer_free(nfc_hal_info.nci_timer); + OSI_timer_free(nfc_hal_info.sleep_timer); + OSI_queue_free(nfc_hal_info.msg_q); + OSI_queue_free(nfc_hal_info.nci_q); + + OSI_deinit(); + OSI_logt("exit;"); +} + +int nfc_hal_open(nfc_stack_callback_t* p_cback, + nfc_stack_data_callback_t* p_data_cback) { + tNFC_HAL_MSG* msg; + + OSI_logt("enter;"); + + /* START - VTS */ + if (nfc_hal_info.state == HAL_STATE_POSTINIT) { + OSI_logt("SAMSUNG Hal already open"); + return 0; + } + /* END - VTS */ + + /* Initialize HAL */ + nfc_hal_init(); + + if (device_open()) return -EPERM; + + if (OSI_OK != OSI_task_run(nfc_hal_info.msg_task)) { + nfc_hal_deinit(); + return -EPERM; + } + + nfc_hal_info.stack_cback = p_cback; + nfc_hal_info.data_cback = p_data_cback; + nfc_hal_info.state = HAL_STATE_OPEN; + + msg = (tNFC_HAL_MSG*)OSI_mem_get(HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_OPEN; + OSI_queue_put(nfc_hal_info.msg_q, (void*)msg); + } + OSI_logt("exit;"); + return 0; +} + +int nfc_hal_close() { + tNFC_HAL_MSG* msg; + + OSI_logt("enter;"); + + /* START - VTS */ + if (nfc_hal_info.state == HAL_STATE_CLOSE) { + OSI_logt("SAMSUNG HAL already closed"); + return 1; // FAILED + } + /* END - VTS */ + + msg = (tNFC_HAL_MSG*)OSI_mem_get(HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_TERMINATE; + OSI_queue_put(nfc_hal_info.msg_q, (void*)msg); + } + OSI_task_stop(nfc_hal_info.msg_task); + + device_sleep(); + device_close(); + + nfc_hal_info.state = HAL_STATE_CLOSE; /* VTS */ + + nfc_stack_cback(HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK); + + /* START - For higher than Android-8.0 */ + OSI_deinit(); + /* END - For higher than Android-8.0 */ + + OSI_logt("exit;"); + return 0; +} + +int nfc_hal_write(uint16_t data_len, const uint8_t* p_data) { + tNFC_HAL_MSG* msg; + size_t size = (size_t)data_len; + + OSI_logt("enter;"); + /* START - VTS Replay */ + if ((sending_nci_packet == true) && ((p_data[0] >> 4) == 2)) { + OSI_logt("Don't send NCI"); + return size; + } + /* END - VTS Replay */ + + msg = (tNFC_HAL_MSG*)OSI_mem_get(size + HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_WRITE; + memcpy((uint8_t*)&msg->nci_packet, p_data, size); + + /* START - VTS Replay */ + if ((sending_nci_packet == false) && ((p_data[0] >> 4) == 2)) + sending_nci_packet = true; + /* END - VTS Replay */ + } + // changed OIS_queue_put() sequence to meet VTS Replay + if (OSI_queue_put(nfc_hal_info.msg_q, (void*)msg) == -1) + sending_nci_packet = false; + + OSI_logt("exit;"); + return size; /* VTS */ +} + +int nfc_hal_core_initialized(uint8_t* p_core_init_rsp_params) { + tNFC_HAL_MSG* msg; + size_t size = (size_t)p_core_init_rsp_params[2] + 3; + + OSI_logt("enter;"); + + msg = (tNFC_HAL_MSG*)OSI_mem_get(size + HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_CORE_INIT; + memcpy((uint8_t*)&msg->nci_packet, p_core_init_rsp_params, size); + + OSI_queue_put(nfc_hal_info.msg_q, (void*)msg); + } + OSI_logt("exit;"); + return 0; +} + +int nfc_hal_pre_discover() { + OSI_logt("enter;"); + /* START - VTS Replay */ + /* + tNFC_HAL_MSG *msg; + msg = (tNFC_HAL_MSG *)OSI_mem_get(HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_PRE_DISCOVER; + OSI_queue_put(nfc_hal_info.msg_q, (void *)msg); + } + */ + /* END - VTS Replay */ + OSI_logt("exit;"); + return 0; +} + +int nfc_hal_control_granted() { + tNFC_HAL_MSG* msg; + + OSI_logt("enter;"); + + msg = (tNFC_HAL_MSG*)OSI_mem_get(HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_CONTROL_GRANTED; + OSI_queue_put(nfc_hal_info.msg_q, (void*)msg); + } + OSI_logt("exit;"); + return 0; +} + +int nfc_hal_power_cycle() { + OSI_logt("enter;"); + + /* START - VTS */ + tNFC_HAL_MSG* msg; + if (nfc_hal_info.state == HAL_STATE_CLOSE) { + OSI_logt("SAMSUNG Hal already closed, ignoring power cycle"); + return NFC_STATUS_FAILED; + } + + msg = (tNFC_HAL_MSG*)OSI_mem_get(HAL_EVT_SIZE); + if (msg != NULL) { + msg->event = HAL_EVT_POWER_CYCLE; + OSI_queue_put(nfc_hal_info.msg_q, (void*)msg); + } + /* END - VTS */ + + OSI_logt("exit;"); + return 0; +} + +void setSleepTimeout(int option, uint32_t timeout) { + nfc_hal_info.flag &= ~HAL_FLAG_PROP_ONE_TIMER; + nfc_hal_info.cfg.override_timeout = 0; + + if (option == SET_SLEEP_TIME_CFG) { + if (!get_config_int(cfg_name_table[CFG_SLEEP_TIMEOUT], + (int*)&nfc_hal_info.cfg.sleep_timeout)) + nfc_hal_info.cfg.sleep_timeout = timeout; + } else if (option == SET_SLEEP_TIME_ONCE) { + nfc_hal_info.cfg.override_timeout = timeout; + nfc_hal_info.flag |= HAL_FLAG_PROP_ONE_TIMER; + } else if (option == SET_SLEEP_TIME_FORCE) + nfc_hal_info.cfg.sleep_timeout = timeout; + else + ALOGE("Unknown option: %d", option); + + if (nfc_hal_info.flag & HAL_FLAG_PROP_ONE_TIMER) + OSI_logd("Override timeout is %d ms", nfc_hal_info.cfg.override_timeout); + OSI_logd("Sleep timeout is %d ms", nfc_hal_info.cfg.sleep_timeout); +} + +#ifdef INFC_1_1 +int nfc_hal_factory_reset(void) { + OSI_logt("enter;"); + // TO DO impl + OSI_logt("exit;"); + + return 0; +} + +int nfc_hal_closeForPowerOffCase(void) { + OSI_logt("enter;"); + // TO DO impl + nfc_hal_close(); + OSI_logt("exit;"); + + return 0; +} + +void nfc_hal_getVendorConfig(android::hardware::nfc::V1_1::NfcConfig& config) { + OSI_logt("v1_1 enter;"); + const int MAX_CONFIG_STRING_LEN = 260; + unsigned long num = 0; + std::array buffer; + buffer.fill(0); + long retlen = 0; + memset(&config, 0x00, sizeof(NfcConfig)); + config.nfaPollBailOutMode = false; + if (GetNumValue(NAME_ISO_DEP_MAX_TRANSCEIVE, &num, sizeof(num))) { + config.maxIsoDepTransceiveLength = num; + } + if (GetNumValue(NAME_DEFAULT_OFFHOST_ROUTE, &num, sizeof(num))) { + config.defaultOffHostRoute = num; + } + if (GetNumValue(NAME_DEFAULT_NFCF_ROUTE, &num, sizeof(num))) { + config.defaultOffHostRouteFelica = num; + } + if (GetNumValue(NAME_DEFAULT_SYS_CODE_ROUTE, &num, sizeof(num))) { + config.defaultSystemCodeRoute = num; + } + if (GetNumValue(NAME_DEFAULT_SYS_CODE_PWR_STATE, &num, sizeof(num))) { + config.defaultSystemCodePowerState = num; + } + if (GetNumValue(NAME_DEFAULT_ROUTE, &num, sizeof(num))) { + config.defaultRoute = num; + OSI_logt("mDefaultRoute is %d ", (int)num); + } + if (GetByteArrayValue(NAME_DEVICE_HOST_WHITE_LIST, (char*)buffer.data(), + buffer.size(), &retlen)) { + config.hostWhitelist.resize(retlen); + for (int i = 0; i < retlen; i++) config.hostWhitelist[i] = buffer[i]; + } + if (GetNumValue(NAME_OFF_HOST_ESE_PIPE_ID, &num, sizeof(num))) { + config.offHostESEPipeId = num; + } + if (GetNumValue(NAME_OFF_HOST_SIM_PIPE_ID, &num, sizeof(num))) { + config.offHostSIMPipeId = num; + } + if (GetByteArrayValue(NAME_NFA_PROPRIETARY_CFG, (char*)buffer.data(), + buffer.size(), &retlen)) { + config.nfaProprietaryCfg.protocol18092Active = (uint8_t)buffer[0]; + config.nfaProprietaryCfg.protocolBPrime = (uint8_t)buffer[1]; + config.nfaProprietaryCfg.protocolDual = (uint8_t)buffer[2]; + config.nfaProprietaryCfg.protocol15693 = (uint8_t)buffer[3]; + config.nfaProprietaryCfg.protocolKovio = (uint8_t)buffer[4]; + config.nfaProprietaryCfg.protocolMifare = (uint8_t)buffer[5]; + config.nfaProprietaryCfg.discoveryPollKovio = (uint8_t)buffer[6]; + config.nfaProprietaryCfg.discoveryPollBPrime = (uint8_t)buffer[7]; + config.nfaProprietaryCfg.discoveryListenBPrime = (uint8_t)buffer[8]; + } else { + memset(&config.nfaProprietaryCfg, 0xFF, sizeof(ProtocolDiscoveryConfig)); + } + if ((GetNumValue(NAME_PRESENCE_CHECK_ALGORITHM, &num, sizeof(num))) && + (num <= 5)) { + config.presenceCheckAlgorithm = (PresenceCheckAlgorithm)num; + } + OSI_logt("exit;"); +} + +void nfc_hal_getVendorConfig_1_2( + android::hardware::nfc::V1_2::NfcConfig& config) { + OSI_logt("v1_2 enter;"); + const int MAX_CONFIG_STRING_LEN = 260; + unsigned long num = 0; + std::array buffer; + + buffer.fill(0); + long retlen = 0; + + memset(&config, 0x00, sizeof(android::hardware::nfc::V1_2::NfcConfig)); + + nfc_hal_getVendorConfig(config.v1_1); + + if (GetByteArrayValue(NAME_OFFHOST_ROUTE_UICC, (char*)buffer.data(), + buffer.size(), &retlen)) { + config.offHostRouteUicc.resize(retlen); + for (int i = 0; i < retlen; i++) { + config.offHostRouteUicc[i] = buffer[i]; + } + } + if (GetByteArrayValue(NAME_OFFHOST_ROUTE_ESE, (char*)buffer.data(), + buffer.size(), &retlen)) { + config.offHostRouteEse.resize(retlen); + for (int i = 0; i < retlen; i++) { + config.offHostRouteEse[i] = buffer[i]; + } + } + if (GetNumValue(NAME_DEFAULT_ISODEP_ROUTE, &num, sizeof(num))) { + config.defaultIsoDepRoute = num; + } + + OSI_logt("exit;"); +} + +#endif diff --git a/halimpl/src/hal_nci.cc b/halimpl/src/hal_nci.cc new file mode 100644 index 0000000..c16b51a --- /dev/null +++ b/halimpl/src/hal_nci.cc @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 +#include + +#include "device.h" +#include "hal.h" +#include "hal_msg.h" +#include "osi.h" +#include "util.h" + +int hal_nci_send(tNFC_NCI_PKT* pkt) { + size_t len = (size_t)(pkt->len + NCI_HDR_SIZE); + int ret; + + ret = __send_to_device((uint8_t*)pkt, len); + if (ret != (int)len + /* workaround for retry; F/W I2C issue */ + && (nfc_hal_info.flag & HAL_FLAG_NTF_TRNS_ERROR)) { + OSI_loge("NCI message send failed"); + OSI_logd("set flag to 0x%06X", nfc_hal_info.flag); + } else { + util_nci_analyzer(pkt); + } + + return ret; +} + +void hal_nci_send_reset(void) { + tNFC_NCI_PKT nci_pkt; + + memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT)); + nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_CORE; + nci_pkt.oid = NCI_CORE_RESET; + nci_pkt.len = 0x01; + nci_pkt.payload[0] = 0x01; // Reset config + + hal_nci_send(&nci_pkt); +} + +/* START [181106] Patch for supporting NCI v2.0 */ +// [3. CORE_INIT Changes] +void hal_nci_send_init(int version) { + /* END [181106] Patch for supporting NCI v2.0 */ + tNFC_NCI_PKT nci_pkt; + + /* START [181106] Patch for supporting NCI v2.0 */ + //[3. CORE_INIT Changes] + memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT)); + nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_CORE; + nci_pkt.oid = NCI_CORE_INIT; + nci_pkt.len = 0x00; + + if (version == NCI_VER_2_0) { + nci_pkt.len = 0x02; + nci_pkt.payload[0] = 0x00; + nci_pkt.payload[1] = 0x00; + } + /* END [181106] Patch for supporting NCI v2.0 */ + + hal_nci_send(&nci_pkt); +} + +/* Workaround: Initialization flash of LMRT */ +void hal_nci_send_clearLmrt(void) { + tNFC_NCI_PKT nci_pkt; + + memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT)); + nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_RF_MANAGE; + nci_pkt.oid = 0x01; // RF_SET_LMRT + nci_pkt.len = 0x02; + nci_pkt.payload[0] = 0x00; + nci_pkt.payload[1] = 0x00; + + hal_nci_send(&nci_pkt); +} +/* END WA */ + +void get_clock_info(int rev, int field_name, int* buffer) { + char rev_field[50] = { + '\0', + }; + int isRevField = 0; + + sprintf(rev_field, "%s_REV%d", cfg_name_table[field_name], rev); + isRevField = get_config_count(rev_field); + if (rev >= 0 && isRevField) { + if (!get_config_int(rev_field, buffer)) *buffer = 0; + } else if (!get_config_int(cfg_name_table[field_name], buffer)) + *buffer = 0; +} + +void hal_nci_send_prop_fw_cfg(void) { + tNFC_NCI_PKT nci_pkt; + int rev = get_hw_rev(); + + memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT)); + nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_PROP; + nci_pkt.oid = NCI_PROP_FW_CFG; + + nci_pkt.len = 0x01; + get_clock_info(rev, CFG_FW_CLK_SPEED, (int*)&nci_pkt.payload[0]); + if (nci_pkt.payload[0] == 0xff) { + OSI_loge("Set a different value! Current Clock Speed Value : 0x%x", + nci_pkt.payload[0]); + return; + } + hal_nci_send(&nci_pkt); +} + +int nci_read_payload(tNFC_HAL_MSG* msg) { + tNFC_NCI_PKT* pkt = &msg->nci_packet; + int ret; + + ret = device_read(NCI_PAYLOAD(pkt), NCI_LEN(pkt)); + if (ret != (int)NCI_LEN(pkt)) { + OSI_mem_free((tOSI_MEM_HANDLER)msg); + OSI_loge("Failed to read payload"); + return ret; + } + + data_trace("Recv", NCI_HDR_SIZE + ret, msg->param); + return ret; +} + +void fw_force_update(__attribute__((unused)) void* param) { + OSI_loge("need to F/W update!"); +} + +void nci_init_timeout(__attribute__((unused)) void* param) { + OSI_loge("need to retry!"); +} + +bool nfc_hal_prehandler(tNFC_NCI_PKT* pkt) { + if (NCI_MT(pkt) == NCI_MT_NTF) { + if (NCI_GID(pkt) == NCI_GID_PROP) { + /* Again procedure. only for N3 isN3group */ + if (NCI_OID(pkt) == NCI_PROP_AGAIN) { + if (nfc_hal_info.nci_last_pkt) { + OSI_logd("NFC requests sending last message again!"); + hal_update_sleep_timer(); + device_write((uint8_t*)nfc_hal_info.nci_last_pkt, + (size_t)(nfc_hal_info.nci_last_pkt->len + NCI_HDR_SIZE)); + return false; + } + } + } + } + + if (NCI_MT(pkt) == NCI_MT_CMD) { + if (NCI_GID(pkt) == NCI_GID_PROP) { + if (NCI_OID(pkt) == NCI_PROP_WR_RESET) { + hal_nci_send_reset(); + nfc_hal_info.flag |= HAL_FLAG_PROP_RESET; + return false; + } + + if (NCI_OID(pkt) == NCI_PROP_SET_SLEEP_TIME) { + tNFC_NCI_PKT dummy_rsp; + dummy_rsp.oct0 = NCI_MT_RSP | NCI_PBF_LAST | NCI_GID_PROP; + dummy_rsp.oid = NCI_OID(pkt); + dummy_rsp.len = 1; + dummy_rsp.payload[0] = NCI_STATUS_OK; + + if (NCI_LEN(pkt) == 0) { + setSleepTimeout(SET_SLEEP_TIME_CFG, 5000); + } else { + uint32_t timeout = NCI_PAYLOAD(pkt)[0] * 1000; // sec + int option = SET_SLEEP_TIME_ONCE; + + if (NCI_LEN(pkt) > 1) + timeout += NCI_PAYLOAD(pkt)[1] * 1000 * 60; // min + + if (NCI_LEN(pkt) > 2) option = NCI_PAYLOAD(pkt)[2]; + + setSleepTimeout(option, timeout); + } + + hal_update_sleep_timer(); + nfc_data_callback(&dummy_rsp); + return false; + } + } + } + + if (NCI_MT(pkt) == NCI_MT_RSP) { + if (NCI_GID(pkt) == NCI_GID_CORE) { + if (NCI_OID(pkt) == NCI_CORE_RESET) { + pkt->oct0 = NCI_MT_RSP | NCI_PBF_LAST | NCI_GID_PROP; + pkt->oid = NCI_PROP_WR_RESET; + } + } + } + return true; +} diff --git a/halimpl/src/hal_task.cc b/halimpl/src/hal_task.cc new file mode 100644 index 0000000..9528cc0 --- /dev/null +++ b/halimpl/src/hal_task.cc @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 +#include +#include + +#include "device.h" +#include "hal.h" +#include "hal_msg.h" +#include "osi.h" +#include "util.h" + +#include + +uint32_t fw_update_state = 0; +/* START [181106] Patch for supporting NCI v2.0 */ +// [1. NCI Version Management] +int gNciVersion = NCI_VER_1_0; // 0x10 : NCI 1.0, 0x20 : NCI2.0 +/* END [181106] Patch for supporting NCI v2.0 */ + +static void nfc_hal_state_switch(tNFC_HAL_MSG* msg, eHAL_STATE state) { + tNFC_HAL_MSG* new_msg; + + new_msg = (tNFC_HAL_MSG*)OSI_mem_get(HAL_EVT_SIZE); + if (!new_msg) { + OSI_loge("Failed to memory allocate!"); + nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_OK); + return; + } + + nfc_hal_info.state = state; + memcpy(new_msg, msg, sizeof(HAL_EVT_SIZE)); + OSI_queue_put(nfc_hal_info.msg_q, (void*)new_msg); +} + +void hal_sleep(__attribute__((unused)) void* param) { + nfc_hal_info.flag &= ~HAL_FLAG_PROP_ONE_TIMER; + nfc_hal_info.cfg.override_timeout = 0; + device_sleep(); +} + +void hal_update_sleep_timer(void) { + device_wakeup(); + + /* workaround for double timer */ + if (nfc_hal_info.flag & HAL_FLAG_MASK_USING_TIMER) return; + + if (nfc_hal_info.flag & HAL_FLAG_PROP_ONE_TIMER) + OSI_timer_start(nfc_hal_info.sleep_timer, nfc_hal_info.cfg.override_timeout, + (tOSI_TIMER_CALLBACK)hal_sleep, NULL); + else + OSI_timer_start(nfc_hal_info.sleep_timer, nfc_hal_info.cfg.sleep_timeout, + (tOSI_TIMER_CALLBACK)hal_sleep, NULL); +} + +int __send_to_device(uint8_t* data, size_t len) { + hal_update_sleep_timer(); + if (nfc_hal_info.nci_last_pkt) + memcpy((void*)nfc_hal_info.nci_last_pkt, (void*)data, len); + + return device_write(data, len); +} + +void nfc_hal_open_sm(tNFC_HAL_MSG* msg) { + tNFC_NCI_PKT* pkt = &msg->nci_packet; + + switch (msg->event) { + case HAL_EVT_OPEN: + device_set_mode(NFC_DEV_MODE_ON); + hal_nci_send_prop_fw_cfg(); + break; + case HAL_EVT_READ: + nci_read_payload(msg); + util_nci_analyzer(pkt); + if (NCI_MT(pkt) != NCI_MT_RSP || NCI_GID(pkt) != NCI_GID_PROP || + NCI_OID(pkt) != NCI_PROP_FW_CFG) { + OSI_logd("Not matched rsponse!! we expect NCI_PROP_FW_CFG_RSP"); + } else { + if (NCI_STATUS(pkt) != NCI_STATUS_OK && + NCI_STATUS(pkt) != NCI_STATUS_E_SYNTAX && + NCI_STATUS(pkt) != NCI_CLOCK_STATUS_SYNTAX_ERROR && + NCI_STATUS(pkt) != NCI_CLOCK_STATUS_MISMATCHED && + NCI_STATUS(pkt) != NCI_CLOCK_STATUS_FULL) { + OSI_loge("Failed to config FW, status: %d", NCI_STATUS(pkt)); + break; + } else { + if (NCI_STATUS(pkt) == NCI_STATUS_OK) { + nfc_hal_info.state = HAL_STATE_POSTINIT; + nfc_stack_cback(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_OK); + break; + } + OSI_loge("Failed to config FW, status: %d", NCI_STATUS(pkt)); + } + } + break; + case HAL_EVT_COMPLETE_FAILED: + device_set_mode(NFC_DEV_MODE_OFF); + nfc_stack_cback(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_FAILED); + break; + + case HAL_EVT_TERMINATE: + // TODO: terminate + break; + default: + break; + } +} + +void nfc_hal_postinit_sm(tNFC_HAL_MSG* msg) { + tNFC_NCI_PKT* pkt = &msg->nci_packet; + + switch (msg->event) { + case HAL_EVT_CORE_INIT: + nfc_hal_info.vs_info.state = VS_INIT; + nfc_hal_state_switch(msg, HAL_STATE_VS); + break; + + case HAL_EVT_WRITE: + if (NCI_GID(pkt) == NCI_GID_CORE) { + if (NCI_OID(pkt) == NCI_CORE_RESET && NCI_LEN(pkt) == 1) { + if (nfc_hal_info.flag & HAL_FLAG_ALREADY_RESET) goto complete; + + nfc_hal_info.flag |= HAL_FLAG_W4_CORE_RESET_RSP; + OSI_timer_start(nfc_hal_info.nci_timer, 1000, + (tOSI_TIMER_CALLBACK)fw_force_update, NULL); + OSI_logd("set flag to 0x%06X", nfc_hal_info.flag); + } else if (NCI_OID(pkt) == NCI_CORE_INIT && + (NCI_LEN(pkt) == 0 || NCI_LEN(pkt) == 2)) { + if (nfc_hal_info.flag & HAL_FLAG_ALREADY_INIT) goto complete; + + nfc_hal_info.flag |= HAL_FLAG_W4_CORE_INIT_RSP; + OSI_timer_start(nfc_hal_info.nci_timer, 1000, + (tOSI_TIMER_CALLBACK)nci_init_timeout, NULL); + OSI_logd("set flag to 0x%06X", nfc_hal_info.flag); + } + } + hal_nci_send(&msg->nci_packet); + break; + + case HAL_EVT_READ: + nci_read_payload(msg); + if (NCI_GID(pkt) == NCI_GID_CORE) { + if (NCI_OID(pkt) == NCI_CORE_RESET) { + OSI_logd("Respond CORE_RESET_RSP"); + nfc_hal_info.flag &= ~HAL_FLAG_W4_CORE_RESET_RSP; + nfc_hal_info.flag |= HAL_FLAG_ALREADY_RESET; + /* START [19082300] Patch for supporting NCI v2.0 */ + // [1. NCI Version Management] + // gNciVersion : 0x10 : NCI1.0, 0x20 : NCI2.0 + if ((NCI_LEN(pkt) == 0x03) && NCI_MT(pkt) == NCI_MT_RSP) + gNciVersion = NCI_VER_1_0; + else { + gNciVersion = NCI_VER_2_0; + } + /* END [19082300] Patch for supporting NCI v2.0 */ + } else if (NCI_OID(pkt) == NCI_CORE_INIT) { + OSI_logd("Respond CORE_INIT_RSP"); + nfc_hal_info.flag &= ~HAL_FLAG_W4_CORE_INIT_RSP; + nfc_hal_info.flag |= HAL_FLAG_ALREADY_INIT; + } + OSI_timer_stop(nfc_hal_info.nci_timer); + } + util_nci_analyzer(pkt); + nfc_data_callback(&msg->nci_packet); + break; + + case HAL_EVT_COMPLETE: + complete: + nfc_hal_info.flag |= HAL_FLAG_NTF_TRNS_ERROR | HAL_FLAG_RETRY_TRNS; + nfc_hal_info.state = HAL_STATE_SERVICE; + + OSI_logd("Complete postinit sm"); + + nfc_stack_cback(HAL_NFC_POST_INIT_CPLT_EVT, HAL_NFC_STATUS_OK); + break; + case HAL_EVT_COMPLETE_FAILED: + nfc_stack_cback(HAL_NFC_POST_INIT_CPLT_EVT, HAL_NFC_STATUS_FAILED); + break; + + /* START - VTS */ + case HAL_EVT_POWER_CYCLE: + OSI_logt("HAL_EVT_POWER_CYCLE"); + device_sleep(); + device_close(); + OSI_logt("HAL state change to POWERCYCLE"); + nfc_hal_state_switch(msg, HAL_STATE_POWERCYCLE); + break; + /* END - VTS */ + + case HAL_EVT_TERMINATE: + // TODO: terminate + break; + default: + break; + } +} + +void nfc_hal_vs_sm(tNFC_HAL_MSG* msg) { + tNFC_HAL_VS_INFO* vs = &nfc_hal_info.vs_info; + + if (msg->event != HAL_EVT_READ && msg->event != HAL_EVT_CORE_INIT) { + OSI_loge("Unexpected event [%d]", msg->event); + return; + } + + if (vs->state != VS_INIT) { + nci_read_payload(msg); + util_nci_analyzer(pkt); + } + + switch (vs->state) { + case VS_INIT: + hal_nci_send_clearLmrt(); + vs->state = VS_W4_COMPLETE; + break; + case VS_W4_COMPLETE: + OSI_logd("Vendor Specific is complete."); + msg->event = HAL_EVT_COMPLETE; + nfc_hal_state_switch(msg, HAL_STATE_POSTINIT); + break; + default: + OSI_loge("Unexpected event [%d]", msg->event); + break; + } +} + +void nfc_hal_service_sm(tNFC_HAL_MSG* msg) { + tNFC_NCI_PKT* pkt = &msg->nci_packet; + /* START [H16031401] */ + nfc_hal_info.msg_event = msg->event; + /* END [H16031401] */ + + switch (msg->event) { + /* START - VTS */ + case HAL_EVT_CORE_INIT: + nfc_hal_info.vs_info.state = VS_INIT; + nfc_hal_state_switch(msg, HAL_STATE_VS); + break; + /* END - VTS */ + case HAL_EVT_WRITE: + if (nfc_hal_prehandler(pkt)) hal_nci_send(pkt); + break; + case HAL_EVT_READ: + nci_read_payload(msg); + util_nci_analyzer(pkt); + hal_update_sleep_timer(); + if (nfc_hal_prehandler(pkt)) nfc_data_callback(pkt); + break; + case HAL_EVT_CONTROL_GRANTED: + nfc_hal_state_switch(msg, HAL_STATE_GRANTED); + break; + case HAL_EVT_TERMINATE: + // TODO: terminate + break; + default: + break; + } +} + +static void nfc_hal_grant_finish(void) { + nfc_stack_cback(HAL_NFC_RELEASE_CONTROL_EVT, HAL_NFC_STATUS_OK); + nfc_hal_info.state = HAL_STATE_SERVICE; + nfc_hal_info.grant_cback = NULL; +} + +void nfc_hal_grant_sm(tNFC_HAL_MSG* msg) { + tNFC_NCI_PKT* pkt = &msg->nci_packet; + uint8_t cback_ret = HAL_GRANT_FINISH; + + /* Granted mode is not need to SLEEP. + * hal should pend granted mode just few time */ + switch (msg->event) { + case HAL_EVT_READ: + nci_read_payload(msg); + util_nci_analyzer(pkt); + cback_ret = nfc_hal_info.grant_cback(pkt); + if (cback_ret == HAL_GRANT_FINISH) nfc_hal_grant_finish(); + + if (cback_ret != HAL_GRANT_SEND_NEXT) break; + [[fallthrough]]; + case HAL_EVT_CONTROL_GRANTED: + pkt = (tNFC_NCI_PKT*)OSI_queue_get(nfc_hal_info.nci_q); + if (pkt) { + // TODO: Should CLF respond? + hal_nci_send(pkt); + OSI_mem_free((tOSI_MEM_HANDLER)pkt); + } else + nfc_hal_grant_finish(); + + break; + + case HAL_EVT_WRITE: + OSI_loge("HAL is in granted mode!"); + break; + } +} +/* START - VTS */ +void nfc_hal_power_sm(tNFC_HAL_MSG* msg) { + switch (msg->event) { + case HAL_EVT_POWER_CYCLE: + // have to do is hal open + OSI_logt("HAL_EVT_POWER_CYCLE"); + // nfc_hal_init(); + + if (device_open()) return; + + msg->event = HAL_EVT_OPEN; + nfc_hal_state_switch(msg, HAL_STATE_OPEN); + break; + default: + break; + } +} +/* END - VTS */ + +/* TASK */ +void nfc_hal_task(void) { + tNFC_HAL_MSG* msg; + eHAL_STATE old_st; + + OSI_logt("enter!"); + + if (!nfc_hal_info.msg_task || !nfc_hal_info.nci_timer || + !nfc_hal_info.msg_q || !nfc_hal_info.nci_q) { + OSI_loge("msg_task = %p, nci_timer = %p, msg_q = %p, nci_q = %p", + nfc_hal_info.msg_task, nfc_hal_info.nci_timer, nfc_hal_info.msg_q, + nfc_hal_info.nci_q); + + nfc_hal_deinit(); + OSI_loge("nfc_hal initialization is not succeeded."); + nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_FAILED); + return; + } + + while (OSI_task_isRun(nfc_hal_info.msg_task) == OSI_RUN) { + msg = (tNFC_HAL_MSG*)OSI_queue_get_wait(nfc_hal_info.msg_q); + if (!msg) continue; + + OSI_logd("Got a event: %s(%d)", event_to_string(msg->event), msg->event); + if (msg->event == HAL_EVT_TERMINATE) break; + + OSI_logd("current state: %s", state_to_string(nfc_hal_info.state)); + old_st = nfc_hal_info.state; + switch (nfc_hal_info.state) { + case HAL_STATE_INIT: + case HAL_STATE_DEINIT: + case HAL_STATE_OPEN: + nfc_hal_open_sm(msg); + break; + case HAL_STATE_VS: + nfc_hal_vs_sm(msg); + break; + case HAL_STATE_POSTINIT: + nfc_hal_postinit_sm(msg); + break; + case HAL_STATE_SERVICE: + nfc_hal_service_sm(msg); + break; + case HAL_STATE_GRANTED: + nfc_hal_grant_sm(msg); + break; + /* START - VTS */ + case HAL_STATE_POWERCYCLE: + nfc_hal_power_sm(msg); + break; + /* END - VTS */ + default: + break; + } + OSI_mem_free((tOSI_MEM_HANDLER)msg); + + if (old_st != nfc_hal_info.state) { + OSI_logd("hal state is changed: %s -> %s", state_to_string(old_st), + state_to_string(nfc_hal_info.state)); + } + } + OSI_logt("exit!"); +} + +/* Print */ +const char* event_to_string(uint8_t event) { + switch (event) { + case HAL_EVT_OPEN: + return "HAL_EVT_OPEN"; + case HAL_EVT_CORE_INIT: + return "HAL_EVT_CORE_INIT"; + case HAL_EVT_WRITE: + return "HAL_EVT_WRITE"; + case HAL_EVT_READ: + return "HAL_EVT_READ"; + case HAL_EVT_CONTROL_GRANTED: + return "HAL_EVT_CONTROL_GRANTED"; + /* START - VTS */ + case HAL_EVT_POWER_CYCLE: + return "HAL_EVT_POWER_CYCLE"; + /* END - VTS */ + case HAL_EVT_TERMINATE: + return "NFC_HAL_TERMINATE"; + case HAL_EVT_COMPLETE: + return "NFC_HAL_COMPLETE"; + case HAL_EVT_COMPLETE_FAILED: + return "NFC_HAL_COMPLETE_FAILED"; + } + return "Unknown event."; +} + +const char* state_to_string(eHAL_STATE state) { + switch (state) { + case HAL_STATE_INIT: + return "INIT"; + case HAL_STATE_DEINIT: + return "DEINIT"; + case HAL_STATE_OPEN: + return "OPEN"; + case HAL_STATE_VS: + return "VENDOR_SPECIFIC"; + case HAL_STATE_POSTINIT: + return "POST_INIT"; + case HAL_STATE_SERVICE: + return "SERVICE"; + case HAL_STATE_GRANTED: + return "GRANT"; + /* START - VTS */ + case HAL_STATE_POWERCYCLE: + return "POWER_CYCLE"; + /* END - VTS */ + case HAL_STATE_CLOSE: + return "CLOSE"; + } + return "Unknown state."; +} diff --git a/halimpl/src/util.cc b/halimpl/src/util.cc new file mode 100644 index 0000000..fa75db0 --- /dev/null +++ b/halimpl/src/util.cc @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2013 SAMSUNG S.LSI + * + * 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 +#include +#include +#include +#include + +#include "util.h" + +/* START [H17080801] HAL config file path */ +#define CFG_FILE_1 "/vendor/etc/libnfc-sec-vendor.conf" +#define CFG_FILE_2 "/etc/libnfc-sec-vendor.conf" +/* END [H17080801] HAL config file path */ + +#define isToken(x) (x == ':' || x == '=' || x == ' ' || x == '\t') +#define skipToken(x) \ + while (isToken(*x)) x++ +#define skipSpace(x) \ + while (isspace(*x)) x++ + +bool willBeContinuous(char* buffer, size_t maxlen) { + char* p; + size_t len; + if (!buffer) return false; + + len = strnlen(buffer, maxlen); + if (len == maxlen && buffer[len - 2] != '\n') return true; + + p = buffer + len - 1; + while (isspace(*p) && p > buffer) p--; + if (*p == '\\') return true; + return false; +} + +bool find_by_name_from_current(FILE* file, const char* field) { + char *p, buffer[256] = { + '\0', + }; + size_t len; + int fp; + bool skip = false; + + if (!file || !field) return false; + + len = strlen(field); + while (!feof(file) && fgets(buffer, sizeof(buffer) - 1, file)) { + if (skip) { + skip = willBeContinuous(buffer, sizeof(buffer)); + continue; + } + skip = willBeContinuous(buffer, sizeof(buffer)); + + p = buffer; + skipSpace(p); + if (*p == '#') continue; + + if (!strncmp((char const*)field, (char const*)p, len)) { + fp = -strlen(p); + fp += len; + return (fseek(file, fp, SEEK_CUR) == 0) ? true : false; + } + } + return false; +} + +bool find_by_name(FILE* file, const char* field) { + fseek(file, 0x00, SEEK_SET); + return find_by_name_from_current(file, field); +} + +bool __get_config_int(__attribute__((unused)) char* file_path, + const char* field, int* data, int option) { + FILE* file; + char buffer[10], *p, *endp; + size_t len; + long int val; + + if (!field || !data) return false; + + /* START [H17080801] HAL config file path */ + if ((file = fopen(CFG_FILE_1, "rb")) == NULL) { + OSI_loge("Cannot open config file %s", CFG_FILE_1); + if ((file = fopen(CFG_FILE_2, "rb")) == NULL) { + OSI_loge("Cannot open config file %s", CFG_FILE_2); + return 0; + } + } + /* END [H17080801] HAL config file path */ + + if (!find_by_name(file, field)) { + OSI_loge("Cannot find the field name [%s]", field); + goto fail; + } + + if (!fgets(buffer, sizeof(buffer) - 1, file)) { + OSI_loge("Read failed"); + goto fail; + } + + if (willBeContinuous(buffer, sizeof(buffer))) // not supported multi line + goto fail; + + if ((len = strlen(buffer)) == sizeof(buffer) - 1) { + OSI_loge("It is too long data [%s~]; max", buffer); + goto fail; + } + + p = buffer; + skipToken(p); + if (*p == '\0') { + OSI_loge("It is empty data"); + goto fail; + } + + if (((*p == '0') && (*(p + 1) == 'x')) || option == HAL_UTIL_GET_INT_16) + val = strtol(p, &endp, 0x10); + else + val = strtol(p, &endp, 10); + + if (p == endp) { + OSI_loge("Read failed [%s]", buffer); + goto fail; + } + + OSI_logd("Get config %s: %ld(0x%lx)", field, val, val); + + fclose(file); + + *data = val; + return true; + +fail: + fclose(file); + return false; +} + +bool get_config_int(const char* field, int* data) { + /* START [17080801] HAL config file path */ + return __get_config_int((char*)CFG_FILE_1, field, data, 0); + /* END [17080801] HAL config file path */ +} + +int get_config_string(const char* field, char* strBuffer, size_t bufferSize) { + FILE* file; + char data[256], *buffer, *p; + bool readmore = true; + size_t count = 0; + + if (!field || !strBuffer || bufferSize < 1) return 0; + + /* START [H17080801] HAL config file path */ + if ((file = fopen(CFG_FILE_1, "rb")) == NULL) { + OSI_loge("Cannot open config file %s", CFG_FILE_1); + if ((file = fopen(CFG_FILE_2, "rb")) == NULL) { + OSI_loge("Cannot open config file %s", CFG_FILE_2); + return 0; + } + } + /* END [H17080801] HAL config file path */ + + if (!find_by_name(file, field)) { + OSI_logd("Cannot find the field name [%s]", field); + goto fail; + } + + if ((buffer = (char*)malloc(bufferSize)) == NULL) { + OSI_logd("Cannot allocate temporary buffer for [%s]", field); + goto fail; + } + + while (count < bufferSize - 1 && readmore) { + if (!fgets(data, sizeof(data) - 1, file)) { + OSI_loge("Read failed"); + goto fail_free; + } + + readmore = willBeContinuous(data, sizeof(data)); + p = data; + while ((p = strchr(p, '"')) != NULL) // start string + { + for (p++; *p != '"'; p++) // end string + { + if (*p == '\n' || *p == '\0' || *p == '\\') { + OSI_loge("Cannot find ending point of string"); + goto fail_free; + } + buffer[count++] = *p; + } + p++; + } + } + buffer[count] = '\0'; + + OSI_logd("Get config %s: %s", field, buffer); + if (count == bufferSize) { + if (p == NULL) + goto fail_free; + else if (*p != '\n') + OSI_loge("Overflower!, remained data is [%s]", p); + else if (readmore) + OSI_loge("Overflower!, data is remained! (multi line)"); + } + + count++; + memcpy(strBuffer, buffer, count); + free(buffer); + + fclose(file); + return count; + +fail_free: + free(buffer); +fail: + fclose(file); + return 0; +} + +int get_config_count(const char* field) { + FILE* file; + int count = 0; + + /* START [H17080801] HAL config file path */ + if ((file = fopen(CFG_FILE_1, "rb")) == NULL) { + OSI_loge("Cannot open config file %s", CFG_FILE_1); + if ((file = fopen(CFG_FILE_2, "rb")) == NULL) { + OSI_loge("Cannot open config file %s", CFG_FILE_2); + return 0; + } + } + /* END [H17080801] HAL config file path */ + + while (find_by_name_from_current(file, field)) count++; + + fclose(file); + return count; +} + +int get_hw_rev() { + char* info_file = (char*)"/proc/cpuinfo"; + char* field = (char*)"Revision"; + int rev = -1; + + OSI_logd("%s enter;", __func__); + __get_config_int(info_file, field, &rev, HAL_UTIL_GET_INT_16); + OSI_logd("%s exit; rev = %d", __func__, rev); + + return rev; +} -- cgit v1.2.3