Add proddata utility

Gives access to the OTP board information: serial number, MAC
addresses.

Imported from systems/proddata commit e4d57941645a42b7a711cbb52c104ff559e1bc9f

Change-Id: I79f4ee1ea4a524c1a3f52d7433a34738bb695751
diff --git a/BoardConfig.mk b/BoardConfig.mk
index 6155059..d9acbbd 100644
--- a/BoardConfig.mk
+++ b/BoardConfig.mk
@@ -38,6 +38,9 @@
     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_