blob: 7e17926ddd75d6792b698bc1101842f6b477986d [file] [log] [blame]
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "android.hardware.nfc@1.1-impl"
#include "NfcApiGet.h"
#include <log/log.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <cstring>
#include <dlfcn.h>
struct nqx_devinfo {
// Must be kept in sync with nqx_ UAPI
unsigned char chip_type;
unsigned char rom_version;
unsigned char fw_major;
unsigned char fw_minor;
};
union nqx_uinfo {
unsigned int i;
struct nqx_devinfo info;
};
bool nfc_debug_enabled = false;
static hal_api_struct_t *hal_api_s = nullptr;
static bool struct_initialized = false;
static void* hal_handle = nullptr;
/******************************************************************************
* Function chipInfo
*
* Description This function returns a success/fail integer, and populates
* nqx_info with chip information.
*
* Returns int return status (0/-1).
*
******************************************************************************/
static int chipInfo(union nqx_uinfo* nqx_info) {
int fp;
fp = open(DEV_NODE, O_RDONLY);
if (fp < 0) {
ALOGE("Not able to open dev node %s due to errno (%d) %s", DEV_NODE, errno, strerror(errno));
return STATUS_FAILURE;
}
nqx_info->i = ioctl(fp, NFCC_GET_INFO, 0);
int retval = static_cast<int> (nqx_info->i);
if (retval < 0) {
ALOGE("Failed to retrieve chip ID from hardware due to errno (%d), %s", errno, strerror(errno));
return STATUS_FAILURE;
}
ALOGD("NFC chip id = 0x%x\n", nqx_info->info.chip_type);
ALOGD("NFC FW Ver = %02x.%02x.%02x\n", nqx_info->info.rom_version, nqx_info->info.fw_major, nqx_info->info.fw_minor);
close(fp);
return STATUS_SUCCESS;
}
/******************************************************************************
* Function getHalFileName
*
* Description This function determines which library should be opened,
* based on the NFC chip ID from chipInfo().
*
* Returns char const* file_name
*
******************************************************************************/
static char const* getHalFileName() {
// get chip info from hardware, and return the correct HAL file name.
union nqx_uinfo nqx_info;
int ret = chipInfo(&nqx_info);
if (ret == 0) {
switch(nqx_info.info.chip_type) {
case PN553_ID_A0:
case NQ310_ID: // ALSO PN553 B0
case NQ210_ID:
case NQ440_ID: // ALSO NQ330
case NQ220_ID:
ALOGD("NFC HW chip-id matches with NQxxx");
return NQX_FILE_NAME;
case SN100X_ID_A:
case SN100X_ID_B:
// SN100 has chip id 0xa4 or 0xa3
ALOGD("NFC HW chip-id matches with SN100X");
return SN100X_FILE_NAME;
default:
// if chip id isn't matched, load the NQxxx HAL.
ALOGD("Chip does not match known ID - defaulting to NQX library.");
return NQX_FILE_NAME;
}
}
else {
ALOGD("Obtaining Chip ID failed, attempting loading of default shared library instead.");
return NQX_FILE_NAME;
}
}
/******************************************************************************
* Function unloadHalApiStruct
*
* Description This function is responsible for closing the dynamic library
* and unloading the HAL struct; in order to save memory on low
* memory targets.
*
* Returns void.
*
******************************************************************************/
void unloadHalApiStruct() {
hal_api_s = nullptr;
struct_initialized = false;
dlclose(hal_handle);
ALOGD("Unloaded HAL API Struct");
}
/******************************************************************************
* Function getHalApiStruct
*
* Description This function initializes a struct of pointers to functions
* within the NFC HAL implementation.
*
* Returns hal_api_s pointer or nullptr.
*
******************************************************************************/
hal_api_struct_t* getHalApiStruct() {
char const* linkerror = nullptr;
char const* file_name = nullptr;
/*
* If our HAL has been loaded successfully, we don't want to re-open it on every NFC function call.
* Conversely, if loading the HAL failed, we want to ensure we're not repeatedly trying to link.
*/
if (struct_initialized) {
return hal_api_s;
}
// Obtain the file name for the HAL library we wish to load
file_name = getHalFileName();
// Reset any errors
dlerror();
/*
* Attempt to load the library!
* /vendor/lib(64)/hw/nci_nfc.nqx.default.hw.so for NQx
* /vendor/lib(64)/hw/nci_nfc.sn100x.default.hw.so otherwise
*/
hal_handle = dlopen(file_name, RTLD_NOW);
linkerror = dlerror();
if (linkerror != nullptr) {
ALOGE("Error opening HAL file: %s with linking error: %s", file_name, linkerror);
/*
* Set struct as initialized even if loading fails, so that loading is only attempted
* once per NFC service initialization attempt.
*/
struct_initialized = true;
return nullptr;
}
ALOGD("Loading nfc HAL function table");
// Reset errors again
dlerror();
hal_api_s = (hal_api_struct_t*)dlsym(hal_handle, "api_funcs");
linkerror = dlerror();
if (linkerror != nullptr) {
ALOGE("Error loading HAL function API symbol table: %s", linkerror);
struct_initialized = true;
return nullptr;
}
//set the debug status and set the active status of the HIDL.
nfc_debug_enabled = hal_api_s->phNxpNciHal_get_debug_status();
struct_initialized = true;
return hal_api_s;
}