blob: 86db796788b4508dde7b3cda8b43b0a44c24891a [file] [log] [blame]
// Copyright 2021 Google LLC
//
// 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 <fcntl.h>
#include <mtd/mtd-user.h>
#include <sys/ioctl.h>
#include <flasher/device/mtd.hpp>
#include <flasher/util.hpp>
#include <stdplus/fd/create.hpp>
#include <stdplus/print.hpp>
#include <cstring>
#include <format>
#include <stdexcept>
#include <utility>
namespace flasher
{
namespace device
{
using stdplus::fd::Whence;
Mtd::Mtd(stdplus::ManagedFd&& fd) :
Device(buildDeviceInfo(fd)), fd(std::move(fd)),
offset(this->fd.lseek(0, Whence::Cur))
{}
std::span<std::byte> Mtd::readAt(std::span<std::byte> buf, size_t offset)
{
return opAt(&stdplus::Fd::read, fd, this->offset, buf, offset);
}
std::span<const std::byte> Mtd::writeAt(std::span<const std::byte> data,
size_t offset)
{
return opAt(&stdplus::Fd::write, fd, this->offset, data, offset);
}
void Mtd::eraseBlocks(size_t idx, size_t num)
{
struct erase_info_user erase;
memset(&erase, 0, sizeof(erase));
auto erase_size = getEraseSize();
erase.length = erase_size * num;
erase.start = erase_size * idx;
fd.ioctl(MEMERASE, &erase);
}
Device::DeviceInfo Mtd::buildDeviceInfo(stdplus::Fd& fd)
{
mtd_info_t info;
fd.ioctl(MEMGETINFO, &info);
DeviceInfo ret;
switch (info.type)
{
case MTD_NORFLASH:
ret.type = Type::Nor;
break;
default:
throw std::invalid_argument(
std::format("Unknown MTD type {:#x}", info.type));
}
ret.size = info.size;
ret.erase_size = info.erasesize;
return ret;
}
class MtdType : public DeviceType
{
public:
std::unique_ptr<Device> open(const ModArgs& args) override
{
if (args.arr.size() != 2)
{
throw std::invalid_argument("Requires a single file argument");
}
return std::make_unique<Mtd>(stdplus::fd::open(
args.arr[1].c_str(),
stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::ReadWrite)));
}
void printHelp() const override
{
stdplus::println(stderr, " `mtd` device");
stdplus::println(stderr,
" FILE required MTD device filename");
}
};
void registerMtd() __attribute__((constructor));
void registerMtd()
{
registerDeviceType("mtd", std::make_unique<MtdType>());
}
void unregisterMtd() __attribute__((destructor));
void unregisterMtd()
{
unregisterDeviceType("mtd");
}
} // namespace device
} // namespace flasher