From 9224c881cf3f8575194823a6c779c0d65c42258a Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 30 Sep 2019 11:10:42 +0200 Subject: shinano-common: pn54x: Import from lineage-15.1 * https://github.com/LineageOS/android_system_nfc/tree/lineage-15.1/halimpl/pn54x/common * support for pn54x has been dropped in lineage-16.0 and above Change-Id: I19f2c3a6e3066bf9aaaaf4ddcd7d7ad867de0ed8 --- pn54x/utils/phNxpConfig.cpp | 865 ++++++++++++++++++++++++++++++++++++++++ pn54x/utils/phNxpConfig.h | 100 +++++ pn54x/utils/phNxpNciHal_utils.c | 477 ++++++++++++++++++++++ pn54x/utils/phNxpNciHal_utils.h | 106 +++++ pn54x/utils/sparse_crc32.c | 107 +++++ pn54x/utils/sparse_crc32.h | 32 ++ 6 files changed, 1687 insertions(+) create mode 100644 pn54x/utils/phNxpConfig.cpp create mode 100644 pn54x/utils/phNxpConfig.h create mode 100644 pn54x/utils/phNxpNciHal_utils.c create mode 100644 pn54x/utils/phNxpNciHal_utils.h create mode 100644 pn54x/utils/sparse_crc32.c create mode 100644 pn54x/utils/sparse_crc32.h (limited to 'pn54x/utils') diff --git a/pn54x/utils/phNxpConfig.cpp b/pn54x/utils/phNxpConfig.cpp new file mode 100644 index 0000000..9e8c7cb --- /dev/null +++ b/pn54x/utils/phNxpConfig.cpp @@ -0,0 +1,865 @@ +/****************************************************************************** + * + * Copyright (C) 2011-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. + * + ******************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include "sparse_crc32.h" + +#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-nxp.conf" +#define extra_config_base "libnfc-nxp-" +#define extra_config_ext ".conf" +#define IsStringValue 0x80000000 + +const char config_timestamp_path[] = + "/data/vendor/nfc/libnfc-nxpConfigState.bin"; + +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; + } + + 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 isModified(); + void resetModified(); + + 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; + 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; + uint32_t config_crc32_; + + 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') || 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; + + config_crc32_ = sparse_crc32(0, p_config, config_size); + 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 + + 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 +** +*******************************************************************************/ +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) { + NXPLOG_EXTNS_D("%s found %s=%s\n", __func__, p_name, + (*it)->str_value()); + } else { + NXPLOG_EXTNS_D("%s found %s=(0x%lx)\n", __func__, p_name, + (*it)->numValue()); + } + return *it; + } else + break; + } + return NULL; +} + +/******************************************************************************* +** +** 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(); +} + +bool CNfcConfig::isModified() { + FILE* fd = fopen(config_timestamp_path, "r+"); + if (fd == nullptr) { + ALOGE("%s Unable to open file '%s' - assuming modified", __func__, + config_timestamp_path); + return true; + } + + uint32_t stored_crc32 = 0; + fread(&stored_crc32, sizeof(uint32_t), 1, fd); + fclose(fd); + + return stored_crc32 != config_crc32_; +} + +void CNfcConfig::resetModified() { + FILE* fd = fopen(config_timestamp_path, "w+"); + if (fd == nullptr) { + ALOGE("%s Unable to open file '%s' for writing", __func__, + config_timestamp_path); + return; + } + + fwrite(&config_crc32_, sizeof(uint32_t), 1, fd); + fclose(fd); +} + +/******************************************************************************* +** +** 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 GetNxpStrValue(const char* name, char* pValue, + 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 GetNxpByteArrayValue(const char* name, char* pValue, + 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 GetNxpNumValue(const char* name, void* pValue, + 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; +} + +/******************************************************************************* +** +** Function: resetConfig +** +** Description: reset settings array +** +** Returns: none +** +*******************************************************************************/ +extern "C" void resetNxpConfig() + +{ + CNfcConfig& rConfig = CNfcConfig::GetInstance(); + + rConfig.clean(); +} + +/******************************************************************************* +** +** Function: readOptionalConfig() +** +** Description: read Config settings from an optional conf file +** +** Returns: none +** +*******************************************************************************/ +void readOptionalConfig(const char* extra) { + string strPath; + string configName(extra_config_base); + configName += extra; + configName += extra_config_ext; + + if (alternative_config_path[0] != '\0') { + strPath.assign(alternative_config_path); + strPath += configName; + } else { + findConfigFilePathFromTransportConfigPaths(configName, strPath); + } + + CNfcConfig::GetInstance().readConfig(strPath.c_str(), false); +} + +/******************************************************************************* +** +** Function: isNxpConfigModified() +** +** Description: check if config file has modified +** +** Returns: 0 if not modified, 1 otherwise. +** +*******************************************************************************/ +extern "C" int isNxpConfigModified() { + CNfcConfig& rConfig = CNfcConfig::GetInstance(); + return rConfig.isModified(); +} + +/******************************************************************************* +** +** Function: updateNxpConfigTimestamp() +** +** Description: update if config file has modified +** +** Returns: 0 if not modified, 1 otherwise. +** +*******************************************************************************/ +extern "C" int updateNxpConfigTimestamp() { + CNfcConfig& rConfig = CNfcConfig::GetInstance(); + rConfig.resetModified(); + return 0; +} diff --git a/pn54x/utils/phNxpConfig.h b/pn54x/utils/phNxpConfig.h new file mode 100644 index 0000000..9488ecc --- /dev/null +++ b/pn54x/utils/phNxpConfig.h @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +int GetNxpStrValue(const char* name, char* p_value, unsigned long len); +int GetNxpNumValue(const char* name, void* p_value, unsigned long len); +int GetNxpByteArrayValue(const char* name, char* pValue, long bufflen, + long* len); +void resetNxpConfig(void); +int isNxpConfigModified(); +int updateNxpConfigTimestamp(); + +#ifdef __cplusplus +}; +#endif + +#define NAME_NXPLOG_EXTNS_LOGLEVEL "NXPLOG_EXTNS_LOGLEVEL" +#define NAME_NXPLOG_NCIHAL_LOGLEVEL "NXPLOG_NCIHAL_LOGLEVEL" +#define NAME_NXPLOG_NCIX_LOGLEVEL "NXPLOG_NCIX_LOGLEVEL" +#define NAME_NXPLOG_NCIR_LOGLEVEL "NXPLOG_NCIR_LOGLEVEL" +#define NAME_NXPLOG_FWDNLD_LOGLEVEL "NXPLOG_FWDNLD_LOGLEVEL" +#define NAME_NXPLOG_TML_LOGLEVEL "NXPLOG_TML_LOGLEVEL" + +#define NAME_MIFARE_READER_ENABLE "MIFARE_READER_ENABLE" +#define NAME_FW_STORAGE "FW_STORAGE" +#define NAME_NXP_NFC_DEV_NODE "NXP_NFC_DEV_NODE" +#define NAME_NXP_FW_NAME "NXP_FW_NAME" +#define NAME_NXP_FW_PROTECION_OVERRIDE "NXP_FW_PROTECION_OVERRIDE" +#define NAME_NXP_SYS_CLK_SRC_SEL "NXP_SYS_CLK_SRC_SEL" +#define NAME_NXP_SYS_CLK_FREQ_SEL "NXP_SYS_CLK_FREQ_SEL" +#define NAME_NXP_SYS_CLOCK_TO_CFG "NXP_SYS_CLOCK_TO_CFG" +#define NAME_NXP_ACT_PROP_EXTN "NXP_ACT_PROP_EXTN" +#define NAME_NXP_EXT_TVDD_CFG "NXP_EXT_TVDD_CFG" +#define NAME_NXP_EXT_TVDD_CFG_1 "NXP_EXT_TVDD_CFG_1" +#define NAME_NXP_EXT_TVDD_CFG_2 "NXP_EXT_TVDD_CFG_2" +#define NAME_NXP_EXT_TVDD_CFG_3 "NXP_EXT_TVDD_CFG_3" +#define NAME_NXP_RF_CONF_BLK_1 "NXP_RF_CONF_BLK_1" +#define NAME_NXP_RF_CONF_BLK_2 "NXP_RF_CONF_BLK_2" +#define NAME_NXP_RF_CONF_BLK_3 "NXP_RF_CONF_BLK_3" +#define NAME_NXP_RF_CONF_BLK_4 "NXP_RF_CONF_BLK_4" +#define NAME_NXP_RF_CONF_BLK_5 "NXP_RF_CONF_BLK_5" +#define NAME_NXP_RF_CONF_BLK_6 "NXP_RF_CONF_BLK_6" +#define NAME_NXP_CORE_CONF_EXTN "NXP_CORE_CONF_EXTN" +#define NAME_NXP_CORE_CONF "NXP_CORE_CONF" +#define NAME_NXP_CORE_MFCKEY_SETTING "NXP_CORE_MFCKEY_SETTING" +#define NAME_NXP_CORE_STANDBY "NXP_CORE_STANDBY" +#define NAME_NXP_NFC_PROFILE_EXTN "NXP_NFC_PROFILE_EXTN" +#define NAME_NXP_CHINA_TIANJIN_RF_ENABLED "NXP_CHINA_TIANJIN_RF_ENABLED" +#define NAME_NXP_SWP_SWITCH_TIMEOUT "NXP_SWP_SWITCH_TIMEOUT" +#define NAME_NXP_SWP_FULL_PWR_ON "NXP_SWP_FULL_PWR_ON" +#define NAME_NXP_CORE_RF_FIELD "NXP_CORE_RF_FIELD" +#define NAME_NXP_NFC_MERGE_RF_PARAMS "NXP_NFC_MERGE_RF_PARAMS" +#define NAME_NXP_I2C_FRAGMENTATION_ENABLED "NXP_I2C_FRAGMENTATION_ENABLED" +#define NAME_AID_MATCHING_PLATFORM "AID_MATCHING_PLATFORM" + +/* default configuration */ +#define default_storage_location "/data/vendor/nfc" + +#endif diff --git a/pn54x/utils/phNxpNciHal_utils.c b/pn54x/utils/phNxpNciHal_utils.c new file mode 100644 index 0000000..46e4908 --- /dev/null +++ b/pn54x/utils/phNxpNciHal_utils.c @@ -0,0 +1,477 @@ +/* + * + * 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. + * + ******************************************************************************/ +#include +#include + +#include +#include +#include + +#if (NFC_NXP_CHIP_TYPE == PN548C2) +extern uint8_t discovery_cmd[50]; +extern uint8_t discovery_cmd_len; +extern uint8_t nfcdep_detected; +#endif + +/*********************** Link list functions **********************************/ + +/******************************************************************************* +** +** Function listInit +** +** Description List initialization +** +** Returns 1, if list initialized, 0 otherwise +** +*******************************************************************************/ +int listInit(struct listHead* pList) { + pList->pFirst = NULL; + if (pthread_mutex_init(&pList->mutex, NULL) == -1) { + NXPLOG_NCIHAL_E("Mutex creation failed (errno=0x%08x)", errno); + return 0; + } + + return 1; +} + +/******************************************************************************* +** +** Function listDestroy +** +** Description List destruction +** +** Returns 1, if list destroyed, 0 if failed +** +*******************************************************************************/ +int listDestroy(struct listHead* pList) { + int bListNotEmpty = 1; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if (pthread_mutex_destroy(&pList->mutex) == -1) { + NXPLOG_NCIHAL_E("Mutex destruction failed (errno=0x%08x)", errno); + return 0; + } + + return 1; +} + +/******************************************************************************* +** +** Function listAdd +** +** Description Add a node to the list +** +** Returns 1, if added, 0 if otherwise +** +*******************************************************************************/ +int listAdd(struct listHead* pList, void* pData) { + struct listNode* pNode; + struct listNode* pLastNode; + int result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(struct listNode)); + if (pNode == NULL) { + result = 0; + NXPLOG_NCIHAL_E("Failed to malloc"); + goto clean_and_return; + } + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) { + /* Set the node as the head */ + pList->pFirst = pNode; + } else { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while (pLastNode->pNext != NULL) { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = 1; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +/******************************************************************************* +** +** Function listRemove +** +** Description Remove node from the list +** +** Returns 1, if removed, 0 if otherwise +** +*******************************************************************************/ +int listRemove(struct listHead* pList, void* pData) { + struct listNode* pNode; + struct listNode* pRemovedNode; + int result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) { + /* Empty list */ + NXPLOG_NCIHAL_E("Failed to deallocate (list empty)"); + result = 0; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } else { + while (pNode->pNext != NULL) { + if (pNode->pNext->pData == pData) { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) { + /* Node not found */ + result = 0; + NXPLOG_NCIHAL_E("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + free(pRemovedNode); + + result = 1; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +/******************************************************************************* +** +** Function listGetAndRemoveNext +** +** Description Get next node on the list and remove it +** +** Returns 1, if successful, 0 if otherwise +** +*******************************************************************************/ +int listGetAndRemoveNext(struct listHead* pList, void** ppData) { + struct listNode* pNode; + int result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) { + /* Empty list */ + NXPLOG_NCIHAL_D("Failed to deallocate (list empty)"); + result = 0; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + free(pNode); + + result = 1; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +/******************************************************************************* +** +** Function listDump +** +** Description Dump list information +** +** Returns None +** +*******************************************************************************/ +void listDump(struct listHead* pList) { + struct listNode* pNode = pList->pFirst; + + NXPLOG_NCIHAL_D("Node dump:"); + while (pNode != NULL) { + NXPLOG_NCIHAL_D("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } + + return; +} + +/* END Linked list source code */ + +/****************** Semaphore and mutex helper functions **********************/ + +static phNxpNciHal_Monitor_t* nxpncihal_monitor = NULL; + +/******************************************************************************* +** +** Function phNxpNciHal_init_monitor +** +** Description Initialize the semaphore monitor +** +** Returns Pointer to monitor, otherwise NULL if failed +** +*******************************************************************************/ +phNxpNciHal_Monitor_t* phNxpNciHal_init_monitor(void) { + NXPLOG_NCIHAL_D("Entering phNxpNciHal_init_monitor"); + + if (nxpncihal_monitor == NULL) { + nxpncihal_monitor = + (phNxpNciHal_Monitor_t*)malloc(sizeof(phNxpNciHal_Monitor_t)); + } + + if (nxpncihal_monitor != NULL) { + memset(nxpncihal_monitor, 0x00, sizeof(phNxpNciHal_Monitor_t)); + + if (pthread_mutex_init(&nxpncihal_monitor->reentrance_mutex, NULL) == -1) { + NXPLOG_NCIHAL_E("reentrance_mutex creation returned 0x%08x", errno); + goto clean_and_return; + } + + if (pthread_mutex_init(&nxpncihal_monitor->concurrency_mutex, NULL) == -1) { + NXPLOG_NCIHAL_E("concurrency_mutex creation returned 0x%08x", errno); + pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex); + goto clean_and_return; + } + + if (listInit(&nxpncihal_monitor->sem_list) != 1) { + NXPLOG_NCIHAL_E("Semaphore List creation failed"); + pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex); + pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex); + goto clean_and_return; + } + } else { + NXPLOG_NCIHAL_E("nxphal_monitor creation failed"); + goto clean_and_return; + } + + NXPLOG_NCIHAL_D("Returning with SUCCESS"); + + return nxpncihal_monitor; + +clean_and_return: + NXPLOG_NCIHAL_D("Returning with FAILURE"); + + if (nxpncihal_monitor != NULL) { + free(nxpncihal_monitor); + nxpncihal_monitor = NULL; + } + + return NULL; +} + +/******************************************************************************* +** +** Function phNxpNciHal_cleanup_monitor +** +** Description Clean up semaphore monitor +** +** Returns None +** +*******************************************************************************/ +void phNxpNciHal_cleanup_monitor(void) { + if (nxpncihal_monitor != NULL) { + pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex); + REENTRANCE_UNLOCK(); + pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex); + phNxpNciHal_releaseall_cb_data(); + listDestroy(&nxpncihal_monitor->sem_list); + } + + free(nxpncihal_monitor); + nxpncihal_monitor = NULL; + + return; +} + +/******************************************************************************* +** +** Function phNxpNciHal_get_monitor +** +** Description Get monitor +** +** Returns Pointer to monitor +** +*******************************************************************************/ +phNxpNciHal_Monitor_t* phNxpNciHal_get_monitor(void) { + return nxpncihal_monitor; +} + +/* Initialize the callback data */ +NFCSTATUS phNxpNciHal_init_cb_data(phNxpNciHal_Sem_t* pCallbackData, + void* pContext) { + /* Create semaphore */ + if (sem_init(&pCallbackData->sem, 0, 0) == -1) { + NXPLOG_NCIHAL_E("Semaphore creation failed (errno=0x%08x)", errno); + return NFCSTATUS_FAILED; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (listAdd(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1) { + NXPLOG_NCIHAL_E("Failed to add the semaphore to the list"); + } + + return NFCSTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function phNxpNciHal_cleanup_cb_data +** +** Description Clean up callback data +** +** Returns None +** +*******************************************************************************/ +void phNxpNciHal_cleanup_cb_data(phNxpNciHal_Sem_t* pCallbackData) { + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) { + NXPLOG_NCIHAL_E( + "phNxpNciHal_cleanup_cb_data: Failed to destroy semaphore " + "(errno=0x%08x)", + errno); + } + + /* Remove from active semaphore list */ + if (listRemove(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1) { + NXPLOG_NCIHAL_E( + "phNxpNciHal_cleanup_cb_data: Failed to remove semaphore from the " + "list"); + } + + return; +} + +/******************************************************************************* +** +** Function phNxpNciHal_releaseall_cb_data +** +** Description Release all callback data +** +** Returns None +** +*******************************************************************************/ +void phNxpNciHal_releaseall_cb_data(void) { + phNxpNciHal_Sem_t* pCallbackData; + + while (listGetAndRemoveNext(&phNxpNciHal_get_monitor()->sem_list, + (void**)&pCallbackData)) { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } + + return; +} + +/* END Semaphore and mutex helper functions */ + +/**************************** Other functions *********************************/ + +/******************************************************************************* +** +** Function phNxpNciHal_print_packet +** +** Description Print packet +** +** Returns None +** +*******************************************************************************/ +void phNxpNciHal_print_packet(const char* pString, const uint8_t* p_data, + uint16_t len) { + uint32_t i, j; + char print_buffer[len * 3 + 1]; + + memset(print_buffer, 0, sizeof(print_buffer)); + for (i = 0; i < len; i++) { + snprintf(&print_buffer[i * 2], 3, "%02X", p_data[i]); + } + if (0 == memcmp(pString, "SEND", 0x04)) { + NXPLOG_NCIX_D("len = %3d > %s", len, print_buffer); + } else if (0 == memcmp(pString, "RECV", 0x04)) { + NXPLOG_NCIR_D("len = %3d > %s", len, print_buffer); + } + + return; +} + +/******************************************************************************* +** +** Function phNxpNciHal_emergency_recovery +** +** Description Emergency recovery in case of no other way out +** +** Returns None +** +*******************************************************************************/ + +void phNxpNciHal_emergency_recovery(void) { +#if (NFC_NXP_CHIP_TYPE == PN548C2) + if (nfcdep_detected && discovery_cmd_len != 0) { + pthread_t pthread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&pthread, &attr, (void*)phNxpNciHal_core_reset_recovery, + NULL) == 0) { + return; + } + } +#endif + NXPLOG_NCIHAL_E("%s: abort()", __func__); + abort(); +} diff --git a/pn54x/utils/phNxpNciHal_utils.h b/pn54x/utils/phNxpNciHal_utils.h new file mode 100644 index 0000000..3ea33e4 --- /dev/null +++ b/pn54x/utils/phNxpNciHal_utils.h @@ -0,0 +1,106 @@ +/* + * + * 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. + * + ******************************************************************************/ + +#ifndef _PHNXPNCIHAL_UTILS_H_ +#define _PHNXPNCIHAL_UTILS_H_ + +#include +#include +#include +#include + +/********************* Definitions and structures *****************************/ + +/* List structures */ +struct listNode { + void* pData; + struct listNode* pNext; +}; + +struct listHead { + struct listNode* pFirst; + pthread_mutex_t mutex; +}; + +/* Semaphore handling structure */ +typedef struct phNxpNciHal_Sem { + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} phNxpNciHal_Sem_t; + +/* Semaphore helper macros */ +#define SEM_WAIT(cb_data) sem_wait(&((cb_data).sem)) +#define SEM_POST(p_cb_data) sem_post(&((p_cb_data)->sem)) + +/* Semaphore and mutex monitor */ +typedef struct phNxpNciHal_Monitor { + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + +} phNxpNciHal_Monitor_t; + +/************************ Exposed functions ***********************************/ +/* List functions */ +int listInit(struct listHead* pList); +int listDestroy(struct listHead* pList); +int listAdd(struct listHead* pList, void* pData); +int listRemove(struct listHead* pList, void* pData); +int listGetAndRemoveNext(struct listHead* pList, void** ppData); +void listDump(struct listHead* pList); + +/* NXP NCI HAL utility functions */ +phNxpNciHal_Monitor_t* phNxpNciHal_init_monitor(void); +void phNxpNciHal_cleanup_monitor(void); +phNxpNciHal_Monitor_t* phNxpNciHal_get_monitor(void); +NFCSTATUS phNxpNciHal_init_cb_data(phNxpNciHal_Sem_t* pCallbackData, + void* pContext); +void phNxpNciHal_cleanup_cb_data(phNxpNciHal_Sem_t* pCallbackData); +void phNxpNciHal_releaseall_cb_data(void); +void phNxpNciHal_print_packet(const char* pString, const uint8_t* p_data, + uint16_t len); +void phNxpNciHal_emergency_recovery(void); + +/* Lock unlock helper macros */ +/* Lock unlock helper macros */ +#define REENTRANCE_LOCK() \ + if (phNxpNciHal_get_monitor()) \ + pthread_mutex_lock(&phNxpNciHal_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() \ + if (phNxpNciHal_get_monitor()) \ + pthread_mutex_unlock(&phNxpNciHal_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() \ + if (phNxpNciHal_get_monitor()) \ + pthread_mutex_lock(&phNxpNciHal_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() \ + if (phNxpNciHal_get_monitor()) \ + pthread_mutex_unlock(&phNxpNciHal_get_monitor()->concurrency_mutex) + +#endif /* _PHNXPNCIHAL_UTILS_H_ */ diff --git a/pn54x/utils/sparse_crc32.c b/pn54x/utils/sparse_crc32.c new file mode 100644 index 0000000..1ce4c63 --- /dev/null +++ b/pn54x/utils/sparse_crc32.c @@ -0,0 +1,107 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ + +/* Code taken from FreeBSD 8 */ +#include + +static uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +/* + * A function that calculates the CRC-32 based on the table above is + * given below for documentation purposes. An equivalent implementation + * of this function that's actually used in the kernel can be found + * in sys/libkern.h, where it can be inlined. + */ + +uint32_t sparse_crc32(uint32_t crc_in, const void* buf, int size) { + const uint8_t* p = buf; + uint32_t crc; + + crc = crc_in ^ ~0U; + while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return crc ^ ~0U; +} diff --git a/pn54x/utils/sparse_crc32.h b/pn54x/utils/sparse_crc32.h new file mode 100644 index 0000000..a776921 --- /dev/null +++ b/pn54x/utils/sparse_crc32.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBSPARSE_SPARSE_CRC32_H_ +#define _LIBSPARSE_SPARSE_CRC32_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t sparse_crc32(uint32_t crc, const void* buf, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3