blob: bc15719694a432f4f2b9159726ff89c944d1f495 [file] [log] [blame]
/*
* 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;
}