summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Dearman <chris.dearman@imgtec.com>2016-03-17 15:01:57 -0700
committerChris Dearman <chris.dearman@imgtec.com>2016-03-17 15:20:45 -0700
commit4234d175b750d5c27a40007ad8ce21172bc9a9c3 (patch)
tree23d87acba94720b0cb3e31d4f1172ca6785bf323
parent5d63509477036224df9481867871e446a59acfe4 (diff)
downloadcreatorci41-4234d175b750d5c27a40007ad8ce21172bc9a9c3.tar.gz
Add proddata utility
Gives access to the OTP board information: serial number, MAC addresses. Imported from systems/proddata commit e4d57941645a42b7a711cbb52c104ff559e1bc9f Change-Id: I79f4ee1ea4a524c1a3f52d7433a34738bb695751
-rw-r--r--BoardConfig.mk3
-rw-r--r--proddata/Android.mk39
-rw-r--r--proddata/device_data.cpp286
-rw-r--r--proddata/device_data.h157
-rw-r--r--proddata/flash_access.cpp88
-rw-r--r--proddata/flash_access.h69
-rw-r--r--proddata/main.cpp131
-rw-r--r--proddata/mtd_access.cpp143
-rw-r--r--proddata/mtd_access.h55
-rw-r--r--proddata/proddata.cpp87
-rw-r--r--proddata/proddata.h74
-rw-r--r--proddata/userotp_access.cpp105
-rw-r--r--proddata/userotp_access.h54
13 files changed, 1291 insertions, 0 deletions
diff --git a/BoardConfig.mk b/BoardConfig.mk
index 6155059..d9acbbd 100644
--- a/BoardConfig.mk
+++ b/BoardConfig.mk
@@ -38,6 +38,9 @@ PRODUCT_COPY_FILES += \
device/imagination/creatorci41/fstab.device:root/fstab.${soc_name} \
device/imagination/creatorci41/provision-device:provision-device
+DEVICE_PACKAGES += \
+ proddata
+
BOARD_SEPOLICY_DIRS += \
device/imagination/creatorci41/sepolicy
diff --git a/proddata/Android.mk b/proddata/Android.mk
new file mode 100644
index 0000000..0c4e4c8
--- /dev/null
+++ b/proddata/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# proddata
+# ==============================================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ device_data.cpp \
+ flash_access.cpp \
+ main.cpp \
+ mtd_access.cpp \
+ proddata.cpp \
+ userotp_access.cpp
+
+LOCAL_MODULE := proddata
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ liblog \
+ libutils
+LOCAL_C_INCLUDES := \
+ $(TOP)/system/core/base/include
+include $(BUILD_EXECUTABLE)
diff --git a/proddata/device_data.cpp b/proddata/device_data.cpp
new file mode 100644
index 0000000..82b05ad
--- /dev/null
+++ b/proddata/device_data.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * DeviceData class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#include "device_data.h"
+#ifdef __ANDROID__
+#include <android-base/logging.h>
+#define DLOG(x) LOG(x)
+#else
+#include <glog/logging.h>
+#endif
+
+
+static const int kCRCSize = 2;
+
+/* CRC-16 lookup table */
+static const uint16_t crctab16[] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+ 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+ 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+ 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+ 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+ 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+ 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+ 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+ 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+ 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+ 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+ 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+ 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+ 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+ 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+ 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+ 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+ 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+ 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+ 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+ 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+ 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+ 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+ 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+ 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+ 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+ 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+ 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
+};
+
+uint16_t update_crc16(uint16_t crc, uint8_t c) {
+
+ crc = (crc >> 8) ^ crctab16[(crc ^ c) & 0xff];
+
+ return crc;
+}
+
+static std::vector<uint8_t> CalculateDataCRC(const std::vector<uint8_t> &data) {
+ uint16_t crc16 = 0;
+ const uint8_t *ptr = data.data();
+ int size = data.size();
+ while (size) {
+ crc16 = update_crc16(crc16, *ptr);
+ ptr++;
+ size--;
+ }
+ /* convert uint16_t crc to crc vector */
+ uint8_t crc_0 = (crc16 >> 8) & 0xff;
+ uint8_t crc_1 = crc16 & 0xff;
+
+ std::vector<uint8_t> crc;
+
+ crc.push_back(crc_0);
+ crc.push_back(crc_1);
+
+ return crc;
+}
+
+static void AddDataCRC(std::vector<uint8_t> *data) {
+ std::vector<uint8_t> crc = CalculateDataCRC(*data);
+ data->insert(data->begin(), crc.begin(), crc.end());
+}
+
+static void CheckDataCRC(const std::vector<uint8_t> &data) {
+ /* ignore first 2 bytes which stores crc */
+ std::vector<uint8_t> data_without_crc(data.begin() + kCRCSize, data.end());
+ std::vector<uint8_t> crc = CalculateDataCRC(data_without_crc);
+
+ if ((crc[0] != data[0]) || (crc[1] != data[1])) {
+ LOG(ERROR) << "Data corrupted:CRC failed";
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("Data corrupted:CRC failed");
+#endif
+ }
+}
+
+/* TODO: Scenario of version check will be different when more than one version is actually
+ supported, need to select register map according to version read and proceed for reading
+ content. */
+
+static void CheckDataLayoutVersion(std::vector<uint8_t> &data) {
+ uint8_t version = data[2];
+
+ /* TODO: Change hardcoded version, when support for more than one version is added */
+ if (version != 0x01) {
+#ifdef __ANDROID__
+ LOG(ERROR) << "Invalid data layout version";
+ exit(-1);
+#else
+ throw std::runtime_error("Invalid data layout version");
+#endif
+ }
+}
+
+DeviceData::DeviceData(std::unique_ptr<FlashAccess> flash_access) :
+ flash_access_(std::move(flash_access)) {
+ DLOG(INFO) << "Initialising DeviceData";
+}
+
+DeviceData::~DeviceData() {
+ DLOG(INFO) << "Deinitialising DeviceData";
+}
+
+int DeviceData::GetRegisterSize(RegisterName register_name) {
+ std::map<std::string, struct DataField> register_data_fields;
+
+ if (register_name == register0) {
+ register_data_fields = register0_data_fields_;
+ } else if (register_name == register1) {
+ register_data_fields = register1_data_fields_;
+ }
+
+ int size = 0;
+ for (const auto &field : register_data_fields) {
+ size = size + field.second.size;
+ }
+
+ return size;
+}
+
+int DeviceData::GetCRCOffset(RegisterName register_name) {
+ const DataField field = GetDataField(register_name, "CRC");
+
+ return field.offset;
+}
+
+const DeviceData::DataField DeviceData::GetDataField(RegisterName register_name,
+ const std::string &name) {
+ std::map<std::string, struct DataField> register_data_fields;
+
+ if (register_name == register0) {
+ register_data_fields = register0_data_fields_;
+ } else if (register_name == register1) {
+ register_data_fields = register1_data_fields_;
+ }
+
+ for (const auto &field : register_data_fields) {
+ if (field.first == name) {
+ return field.second;
+ }
+ }
+
+ std::string error = "Invalid data field: " + name;
+#ifdef __ANDROID__
+ LOG(ERROR) << error;
+ exit(-1);
+#else
+ throw std::runtime_error(error);
+#endif
+}
+
+void DeviceData::ParseData(const std::vector<uint8_t> &data, std::vector<uint8_t> *mac_data,
+ std::vector<uint8_t> *wifi_data) {
+ int mac_data_size = GetRegisterSize(register0) - kCRCSize;
+ int wifi_data_size = GetRegisterSize(register1) - kCRCSize;
+ int size = data.size();
+ if (size != (mac_data_size + wifi_data_size)) {
+ LOG(ERROR) << "Data size error";
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("Data size error");
+#endif
+ }
+
+ mac_data->assign(data.begin(), data.begin() + mac_data_size);
+ wifi_data->assign(data.begin() + mac_data_size, data.end());
+
+ /* Add CRC */
+ AddDataCRC(mac_data);
+ AddDataCRC(wifi_data);
+}
+
+void DeviceData::Write(const std::vector<uint8_t> &data) {
+ std::vector<uint8_t> mac_data;
+ std::vector<uint8_t> wifi_data;
+
+ ParseData(data, &mac_data, &wifi_data);
+
+ flash_access_->Write(mac_data, GetCRCOffset(register0));
+ flash_access_->Write(wifi_data, GetCRCOffset(register1));
+}
+
+std::vector<uint8_t> DeviceData::Read() {
+ std::vector<uint8_t> data[2];
+
+ /* read data from 2 registers */
+ for (int i = 0; i < 2; i++) {
+ DeviceData::RegisterName register_name = static_cast<DeviceData::RegisterName>(i);
+ data[i] = flash_access_->Read(GetRegisterSize(register_name), GetCRCOffset(register_name));
+
+ /* check crc */
+ CheckDataCRC(data[i]);
+
+ /* Check version */
+ CheckDataLayoutVersion(data[i]);
+
+ /* remove crc from data */
+ data[i].erase(data[i].begin(), data[i].begin() + kCRCSize);
+ }
+
+ std::vector<uint8_t> buf = data[0];
+ buf.insert(buf.end(), data[1].begin(), data[1].end());
+
+ return buf;
+}
+
+std::vector<uint8_t> DeviceData::ReadValue(const std::string &name) {
+ DeviceData::RegisterName register_name;
+ DataField field;
+ if (register0_data_fields_.end() != register0_data_fields_.find(name)) {
+ field = GetDataField(register0, name);
+ register_name = register0;
+ } else if (register1_data_fields_.end() != register1_data_fields_.find(name)) {
+ field = GetDataField(register1, name);
+ register_name = register1;
+ } else if (key_serial == name) {
+ return flash_access_->ReadSerial();
+ } else {
+ LOG(ERROR) << "Invalid data field: " << name;
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("Invalid data field: " + name);
+#endif
+ }
+
+ std::vector<uint8_t> buf;
+
+ /* read complete register into buf to check for crc and version */
+ buf = flash_access_->Read(GetRegisterSize(register_name), GetCRCOffset(register_name));
+ CheckDataCRC(buf);
+ CheckDataLayoutVersion(buf);
+
+ int data_field_position = field.offset - GetCRCOffset(register_name);
+
+ /* Get data field from buf */
+ std::vector<uint8_t> data(buf.begin() + data_field_position,
+ buf.begin() + data_field_position + field.size);
+
+ return data;
+}
diff --git a/proddata/device_data.h b/proddata/device_data.h
new file mode 100644
index 0000000..791e525
--- /dev/null
+++ b/proddata/device_data.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * DeviceData class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+
+#ifndef DEVICEDATA_H_
+#define DEVICEDATA_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include "flash_access.h"
+
+/**
+ * @brief class for maintaining device data layout and performing read/write operations
+ */
+class DeviceData {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * Creates an instance of DeviceData
+ * @param[in] flash_access unique pointer to FlashAccess implementation
+ *
+ */
+ explicit DeviceData(std::unique_ptr<FlashAccess> flash_access);
+ ~DeviceData();
+
+ /**
+ * @brief Parse the data into wifi calibration data and MAC and write appropriately
+ *
+ * @param[in] data chunk of data to be written
+ */
+ void Write(const std::vector<uint8_t> &data);
+
+ /**
+ * @brief Read device data from memory
+ *
+ * returns vector containing raw data
+ */
+ std::vector<uint8_t> Read();
+
+ /**
+ * @brief Read device data value e.g MAC_0
+ *
+ * @param[in] name name of data field
+ * returns vector containing raw data
+ */
+ std::vector<uint8_t> ReadValue(const std::string &name);
+
+ /**
+ * @brief struct for storing size and offset for each field
+ */
+ struct DataField {
+ int size;
+ int offset;
+ };
+
+ private:
+ const std::string key_serial{"SERIAL"};
+ const std::map<std::string, struct DataField> register0_data_fields_ {
+ {"CRC", {2, 0}},
+ {"VERSION", {1, 2}},
+ {"MAC_0", {6, 3}},
+ {"MAC_1", {6, 9}},
+ {"MAC_2", {6, 15}},
+ {"MAC_3", {6, 21}},
+ {"MAC_4", {6, 27}},
+ {"MAC_5", {6, 33}},
+ };
+ const std::map<std::string, struct DataField> register1_data_fields_ {
+ {"CRC", {2, 256}},
+ {"VERSION", {1, 258}},
+ {"DCXO", {1, 259}},
+ {"DSSS_TX_POWER_2.4", {1, 260}},
+ {"OFDM_TX_POWER_2.4_MCS7", {1, 261}},
+ {"OFDM_TX_POWER_5B1_MCS5", {1, 262}},
+ {"OFDM_TX_POWER_5B2_MCS5", {1, 263}},
+ {"OFDM_TX_POWER_5B3_MCS5", {1, 264}},
+ {"OFDM_TX_POWER_5B4_MCS5", {1, 265}},
+ {"OFDM_TX_POWER_5B1_MCS7", {1, 266}},
+ {"OFDM_TX_POWER_5B2_MCS7", {1, 267}},
+ {"OFDM_TX_POWER_5B3_MCS7", {1, 268}},
+ {"OFDM_TX_POWER_5B4_MCS7", {1, 269}},
+ {"OFDM_TX_POWER_5B1_MCS8", {1, 270}},
+ {"OFDM_TX_POWER_5B2_MCS8", {1, 271}},
+ {"OFDM_TX_POWER_5B3_MCS8", {1, 272}},
+ {"OFDM_TX_POWER_5B4_MCS8", {1, 273}},
+ {"OFDM_TX_POWER_5B1_MCS9", {1, 274}},
+ {"OFDM_TX_POWER_5B2_MCS9", {1, 275}},
+ {"OFDM_TX_POWER_5B3_MCS9", {1, 276}},
+ {"OFDM_TX_POWER_5B4_MCS9", {1, 277}},
+ };
+
+ enum RegisterName {
+ register0,
+ register1,
+ };
+
+ std::unique_ptr<FlashAccess> flash_access_;
+
+ /**
+ * @brief Parse data vector to mac data and wifi data and validate CRC
+ *
+ * @param[in] data vector containing raw data
+ * @param[out] mac_str pointer to vector storing mac data
+ * @param[out] wifi_str pointer to vector storing wifi data
+ */
+ void ParseData(const std::vector<uint8_t> &data, std::vector<uint8_t> *mac_data,
+ std::vector<uint8_t> *wifi_data);
+
+ /**
+ * @brief Get Sum of size of all data fields in map
+ *
+ * @param[in] register_name enum specifying which register map to use
+ */
+ int GetRegisterSize(RegisterName register_name);
+
+ /**
+ * @brief Get offset of CRC field from register map
+ *
+ * @param[in] register_name enum specifying which register map to use
+ */
+ int GetCRCOffset(RegisterName register_name);
+
+ /**
+ * @brief Get DataField structure(size, offset) from corresponding name(key)
+ *
+ * @param[in] register_name enum specifying which register map to use
+ * @param[in] name name of data field
+ */
+ const DeviceData::DataField GetDataField(RegisterName register_name, const std::string &name);
+};
+
+#endif // DEVICEDATA_H_
diff --git a/proddata/flash_access.cpp b/proddata/flash_access.cpp
new file mode 100644
index 0000000..c549c85
--- /dev/null
+++ b/proddata/flash_access.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * Abstract class for flash access
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#include "flash_access.h"
+#ifdef __ANDROID__
+#include <android-base/logging.h>
+#define DLOG(x) LOG(x)
+#else
+#include <glog/logging.h>
+#endif
+#include <mtd/mtd-user.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdexcept>
+
+FlashAccess::FlashAccess(const std::string &device_name) {
+ fd_ = open(device_name.c_str(), O_RDWR);
+ if (fd_ < 0) {
+ DLOG(ERROR) << "Can't open device: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("FlashAccess Initialization failed");
+#endif
+ }
+}
+
+FlashAccess::~FlashAccess() {
+ close(fd_);
+}
+
+std::vector<uint8_t> FlashAccess::ReadSerial() {
+ DLOG(INFO) << "Reading serial number";
+ const int size = 8;
+ std::vector<uint8_t> buf(size);
+ int val = MTD_OTP_FACTORY;
+ if (ioctl(fd_, OTPSELECT, &val) < 0) {
+ DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("Factory OTP access failed");
+#endif
+ }
+
+ if (lseek(fd_, 0, SEEK_SET) < 0) {
+ DLOG(ERROR) << "read serial: lseek failed: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("read serial: lseek failed");
+#endif
+ }
+
+ int ret = read(fd_, buf.data(), buf.size());
+ if (ret < 0) {
+ DLOG(ERROR) << "read serial num failed:" << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("read serial num failed");
+#endif
+ }
+ return buf;
+}
+
diff --git a/proddata/flash_access.h b/proddata/flash_access.h
new file mode 100644
index 0000000..7f2ea4d
--- /dev/null
+++ b/proddata/flash_access.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * Abstract class for flash access
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#ifndef FLASHACCESS_H_
+#define FLASHACCESS_H_
+
+#include <string>
+#include <vector>
+
+/**
+ * @brief Abstract class for flash access
+ */
+class FlashAccess {
+ public:
+ explicit FlashAccess(const std::string &device_name);
+ virtual ~FlashAccess();
+
+ /**
+ * @brief Write data to flash
+ *
+ * @param[in] buf chunk of data to be written
+ * @param[in] offset device offset
+ */
+ virtual void Write(const std::vector<uint8_t> &buf, const int offset) = 0;
+
+ /**
+ * @brief Read data from flash storage
+
+ * @param[in] size size of data to be read
+ * @param[in] offset device offset
+ * @returns vector containing read data
+ *
+ */
+ virtual std::vector<uint8_t> Read(const int size, const int offset) = 0;
+
+ /**
+ * @brief Read serial number
+ *
+ * returns vector containing serial number
+ */
+ virtual std::vector<uint8_t> ReadSerial();
+
+ protected:
+ int fd_;
+};
+
+#endif // FLASHACCESS_H_
diff --git a/proddata/main.cpp b/proddata/main.cpp
new file mode 100644
index 0000000..d764083
--- /dev/null
+++ b/proddata/main.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * Proddata tool main entry point
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#ifdef __ANDROID__
+#include <android-base/logging.h>
+#define DLOG(x) LOG(x)
+#else
+#include <glog/logging.h>
+#endif
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include "proddata.h"
+#include "flash_access.h"
+#include "userotp_access.h"
+
+static void PrintData(std::vector<uint8_t> &data) {
+ int size = data.size();
+ for (int i = 0; i < size; i++) {
+ std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(data[i]);
+ }
+ std::cout << std::endl;
+}
+
+static void usage() {
+ std::string mesg = "Usage: proddata write <data> Write calibration data \n"
+ " proddata read Read calibration data \n"
+ " proddata read <name e.g DCXO> Read data field \n";
+ std::cerr << mesg;
+}
+
+#ifdef __ANDROID__
+int main(int argc, char* argv[]) {
+
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
+ // TODO(Sagar): Make FlashAccess implemetation and hardcoded device name configurable
+ std::unique_ptr<FlashAccess> flash_access(new UserOTPAccess("/dev/mtd/mtd0"));
+ Proddata proddata(std::move(flash_access));
+
+ if (!strcmp(argv[1], "write")) {
+ if (argv[2] == NULL) {
+ std::cerr << "Specify data to be written to OTP" << std::endl;
+ return -1;
+ } else {
+ proddata.Write(argv[2]);
+ }
+ } else if (!strcmp(argv[1], "read")) {
+ std::vector<uint8_t> data;
+ if (argv[2] == NULL) {
+ data = proddata.Read();
+ } else {
+ data = proddata.ReadValue(argv[2]);
+ }
+ PrintData(data);
+ } else {
+ std::cerr << "Invalid command" << std::endl;
+ usage();
+ return -1;
+ }
+
+ return 0;
+}
+#else
+int main(int argc, char* argv[]) {
+ google::InitGoogleLogging(argv[0]);
+
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
+ try {
+ // TODO(Sagar): Make FlashAccess implemetation and harcoded device name configurable
+ std::unique_ptr<FlashAccess> flash_access(new UserOTPAccess("/dev/mtd1"));
+ Proddata proddata(std::move(flash_access));
+
+ if (!strcmp(argv[1], "write")) {
+ if (argv[2] == NULL) {
+ std::cerr << "Specify data to be written to OTP" << std::endl;
+ return -1;
+ } else {
+ proddata.Write(argv[2]);
+ }
+ } else if (!strcmp(argv[1], "read")) {
+ std::vector<uint8_t> data;
+ if (argv[2] == NULL) {
+ data = proddata.Read();
+ } else {
+ data = proddata.ReadValue(argv[2]);
+ }
+ PrintData(data);
+ } else {
+ std::cerr << "Invalid command" << std::endl;
+ usage();
+ return -1;
+ }
+ } catch (std::runtime_error &e) {
+ google::ShutdownGoogleLogging();
+ return -1;
+ }
+
+ google::ShutdownGoogleLogging();
+ return 0;
+}
+#endif
diff --git a/proddata/mtd_access.cpp b/proddata/mtd_access.cpp
new file mode 100644
index 0000000..bc15719
--- /dev/null
+++ b/proddata/mtd_access.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * MTDAccess class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#include "mtd_access.h"
+#ifdef __ANDROID__
+#include <android-base/logging.h>
+#define DLOG(x) LOG(x)
+#else
+#include <glog/logging.h>
+#endif
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdexcept>
+
+MTDAccess::MTDAccess(const std::string &device_name) : FlashAccess(device_name) {
+ DLOG(INFO) << "Initialising MTDAccess";
+ if (ioctl(fd_, MEMGETINFO, &mtd_info_) < 0) {
+ DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno);
+ close(fd_);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("MTDAccess Initialization failed");
+#endif
+ }
+}
+
+MTDAccess::~MTDAccess() {
+ DLOG(INFO) << "Deinitialising MTDAccess";
+}
+
+/**
+ * Replace vector content with replacement vector from specified position
+ *
+ * @param[out] data vector whose content is to be replaced
+ * @param[in] replacement_vector replacement vector
+ * @param[in] position position in the vector from where content is to be replaced
+ */
+
+static void replace(std::vector<uint8_t> *data, const std::vector<uint8_t> &replacement_vector,
+ int position) {
+ auto erase_end = data->begin() + position + replacement_vector.size();
+
+ if (erase_end > data->end()) { /* data should fit in 1st sector of mtd device */
+#ifdef __ANDROID__
+ LOG(ERROR) << "Cannot replace content of vector with replacement vector";
+ exit(-1);
+#else
+ throw std::runtime_error("Cannot replace content of vector with replacement vector");
+#endif
+ }
+
+ data->erase(data->begin() + position, erase_end);
+ data->insert(data->begin() + position, replacement_vector.begin(), replacement_vector.end());
+}
+
+void MTDAccess::Write(const std::vector<uint8_t> &buf, const int offset) {
+ int sector_size = mtd_info_.erasesize;
+
+ /* read sector (note : it is assumed that all the device data will be on 1st sector) */
+ std::vector<uint8_t> read_buf = this->Read(sector_size, 0);
+
+ /* erase sector */
+ erase_info_t ei;
+ ei.length = mtd_info_.erasesize;
+ ei.start = 0;
+ if (ioctl(fd_, MEMERASE, &ei) < 0) {
+ DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("mtd write: ioctl failed");
+#endif
+ }
+ /* modify sector */
+ replace(&read_buf, buf, offset);
+
+ /* write sector */
+ if (lseek(fd_, 0, SEEK_SET) < 0) {
+ DLOG(ERROR) << "mtd write: lseek failed:" << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("mtd write: lseek failed");
+#endif
+ }
+
+ int ret = write(fd_, read_buf.data(), sector_size);
+ if (ret < 0) {
+ DLOG(ERROR) << "mtd write failed:" << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("mtd write failed");
+#endif
+ }
+}
+
+std::vector<uint8_t> MTDAccess::Read(const int size, const int offset) {
+ std::vector<uint8_t> buf(size);
+ if (lseek(fd_, offset, SEEK_SET) < 0) {
+ DLOG(ERROR) << "mtd read: lseek failed:" << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("mtd read: lseek failed");
+#endif
+ }
+
+ int ret = read(fd_, buf.data(), buf.size());
+ if (ret < 0) {
+ DLOG(ERROR) << "mtd read failed:" << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("mtd read failed");
+#endif
+ }
+ return buf;
+}
+
diff --git a/proddata/mtd_access.h b/proddata/mtd_access.h
new file mode 100644
index 0000000..2fab793
--- /dev/null
+++ b/proddata/mtd_access.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * MTDAccess class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#ifndef MTDACCESS__H_
+#define MTDACCESS__H_
+
+#include <mtd/mtd-user.h>
+#include <string>
+#include <vector>
+#include "flash_access.h"
+
+/**
+ * @brief MTDAccess class to perfrom read/write on mtd device
+ */
+class MTDAccess final: public FlashAccess {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * Creates an instance of MTDAccess
+ *
+ */
+ explicit MTDAccess(const std::string &device_name);
+ ~MTDAccess();
+
+ void Write(const std::vector<uint8_t> &buf, const int offset);
+ std::vector<uint8_t> Read(const int size, const int offset);
+
+ private:
+ mtd_info_t mtd_info_;
+};
+
+#endif // MTDACCESS_H_
diff --git a/proddata/proddata.cpp b/proddata/proddata.cpp
new file mode 100644
index 0000000..e5ee18c
--- /dev/null
+++ b/proddata/proddata.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * Proddata class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#include "proddata.h"
+#ifdef __ANDROID__
+#include <android-base/logging.h>
+#define DLOG(x) LOG(x)
+#else
+#include <glog/logging.h>
+#endif
+#include "device_data.h"
+#include "flash_access.h"
+
+/**
+ * Format string containing hexadecimal symbols
+ * @note string should only have symbols 0-9 A-F
+ * @return vector containing raw data
+ *
+ */
+
+std::vector<uint8_t> FormatString(const std::string &data) {
+ int size = data.size();
+ std::vector<uint8_t> buf(size/2);
+ const char *src = data.c_str();
+ int j = 0;
+ for (int i = 0; i < size; i += 2) {
+ sscanf(src + i, "%02hhx", &buf[j++]);
+ }
+
+ return buf;
+}
+
+Proddata::Proddata(std::unique_ptr<FlashAccess> flash_access) {
+ DLOG(INFO) << "Initialising Proddata";
+ device_data_ = std::unique_ptr<DeviceData>(new DeviceData(std::move(flash_access)));
+}
+
+Proddata::~Proddata() {
+ LOG(INFO) << "Deinitialising Proddata";
+}
+
+void Proddata::Write(const std::string &data) {
+ LOG(INFO) << "Writing wifi calibration and MAC data";
+ if (data.size() % 2 != 0) {
+ LOG(ERROR) << "Invalid data given";
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("Invalid data given");
+#endif
+ }
+
+ std::vector<uint8_t> buf = FormatString(data);
+ device_data_->Write(buf);
+}
+
+std::vector<uint8_t> Proddata::Read() {
+ DLOG(INFO) << "Reading wifi calibration and MAC data";
+ return device_data_->Read();
+}
+
+std::vector<uint8_t> Proddata::ReadValue(const std::string &name) {
+ DLOG(INFO) << "Reading data";
+ return device_data_->ReadValue(name);
+}
diff --git a/proddata/proddata.h b/proddata/proddata.h
new file mode 100644
index 0000000..2b0089e
--- /dev/null
+++ b/proddata/proddata.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * Proddata class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#ifndef PRODDATA_H_
+#define PRODDATA_H_
+
+#include <string>
+#include <vector>
+#include "device_data.h"
+
+/**
+ * @brief Class to perform read/write of production data.
+ */
+class Proddata {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * Creates an instance of Proddata
+ *
+ * @param[in] flash_access unique pointer to FlashAccess implementation
+ */
+ explicit Proddata(std::unique_ptr<FlashAccess> flash_access);
+ ~Proddata();
+
+ /**
+ * @brief Write production data
+ *
+ * @param[in] data chunk of data to be written
+ */
+ void Write(const std::string &data);
+
+ /**
+ * @brief Read production data
+ *
+ * returns vector containing raw data
+ */
+ std::vector<uint8_t> Read();
+
+ /**
+ * @brief Read production data value e.g mac
+ *
+ * @param[in] value to be read
+ * returns vector containing raw data
+ */
+ std::vector<uint8_t> ReadValue(const std::string& name);
+
+ private:
+ std::unique_ptr<DeviceData> device_data_;
+};
+
+#endif // PRODDATA_H_
diff --git a/proddata/userotp_access.cpp b/proddata/userotp_access.cpp
new file mode 100644
index 0000000..6397465
--- /dev/null
+++ b/proddata/userotp_access.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * UserOTPAccess class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#include "userotp_access.h"
+#ifdef __ANDROID__
+#include <android-base/logging.h>
+#define DLOG(x) LOG(x)
+#else
+#include <glog/logging.h>
+#endif
+#include <mtd/mtd-user.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdexcept>
+
+UserOTPAccess::UserOTPAccess(const std::string &device_name) : FlashAccess(device_name) {
+ DLOG(INFO) << "Initialising UserOTPAccess";
+}
+
+UserOTPAccess::~UserOTPAccess() {
+ DLOG(INFO) << "Deinitialising UserOTPAccess";
+}
+
+void UserOTPAccess::Write(const std::vector<uint8_t> &buf, const int offset) {
+ SelectUserOTP();
+
+ if (lseek(fd_, offset, SEEK_SET) < 0) {
+ DLOG(ERROR) << "user otp write: lseek failed: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("user otp write: lseek failed");
+#endif
+ }
+
+ int ret = write(fd_, buf.data(), buf.size());
+ if (ret < 0) {
+ DLOG(ERROR) << "user otp write failed: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("user otp write failed");
+#endif
+ }
+}
+
+std::vector<uint8_t> UserOTPAccess::Read(const int size, const int offset) {
+ std::vector<uint8_t> buf(size);
+ SelectUserOTP();
+
+ if (lseek(fd_, offset, SEEK_SET) < 0) {
+ DLOG(ERROR) << "user otp read: lseek failed: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("user otp read: lseek failed");
+#endif
+ }
+
+ int ret = read(fd_, buf.data(), buf.size());
+ if (ret < 0) {
+ DLOG(ERROR) << "user otp read failed:" << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("user otp read failed");
+#endif
+ }
+ return buf;
+}
+
+void UserOTPAccess::SelectUserOTP() {
+ int val = MTD_OTP_USER;
+ if (ioctl(fd_, OTPSELECT, &val) < 0) {
+ DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno);
+#ifdef __ANDROID__
+ exit(-1);
+#else
+ throw std::runtime_error("UserOTPAccess: ioctl failed");
+#endif
+ }
+}
+
diff --git a/proddata/userotp_access.h b/proddata/userotp_access.h
new file mode 100644
index 0000000..54f5a37
--- /dev/null
+++ b/proddata/userotp_access.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * @file
+ * UserOTPAccess class
+ *
+ * @author Imagination Technologies
+ *
+ * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b>
+ */
+
+#ifndef USEROTPACCESS__H_
+#define USEROTPACCESS__H_
+
+#include <string>
+#include <vector>
+#include "flash_access.h"
+
+/**
+ * @brief UserOTPAccess class to perform read/write on user OTP memory
+ */
+class UserOTPAccess final: public FlashAccess {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * Creates an instance of UserOTPAccess
+ *
+ */
+ explicit UserOTPAccess(const std::string &device_name);
+ ~UserOTPAccess();
+
+ void Write(const std::vector<uint8_t> &buf, const int offset);
+ std::vector<uint8_t> Read(const int size, const int offset);
+
+ private:
+ void SelectUserOTP();
+};
+
+#endif // USEROTPACCESS_H_