C++程序  |  164行  |  3.7 KB

/*
 * Copyright (C) 2015 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.
 */
/* Handle read/write/erase of various devices used by the firmware */

#define LOG_TAG "fwtool"

#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "flash_device.h"
#include "fmap.h"
#include "update_log.h"
#include "vboot_interface.h"

static const struct flash_device_ops *devices[] = {
	&flash_mtd_ops,
	&flash_ec_ops,
	&flash_file_ops,
};

struct flash_device {
	const struct flash_device_ops *ops;
	void *priv_data;
	struct fmap *fmap;
	uint8_t *gbb;
	size_t gbb_size;
	size_t total_size;
	size_t write_size;
	size_t erase_size;
};

struct flash_device *flash_open(const char *name, const void *params)
{
	const struct flash_device_ops *ops = devices[0];
	struct flash_device *dev;

	if (name) {
		unsigned i;
		for (i = 0; i < sizeof(devices)/sizeof(devices[0]); i++)
			if (!strcmp(devices[i]->name, name)) {
				ops = devices[i];
				break;
			}
	}
	ALOGD("Using flash device '%s'\n", ops->name);

	dev = calloc(1, sizeof(struct flash_device));
	if (!dev)
		return NULL;

	dev->ops = ops;
	dev->priv_data = dev->ops->open(params);
	if (!dev->priv_data)
		goto out_free;

	dev->fmap = NULL;
	dev->gbb = NULL;
	dev->gbb_size = 0;
	dev->total_size = dev->ops->get_size(dev->priv_data);
	dev->write_size = dev->ops->get_write_size(dev->priv_data);
	dev->erase_size = dev->ops->get_erase_size(dev->priv_data);

	return dev;

out_free:
	free(dev);

	return NULL;
}

void flash_close(struct flash_device *dev)
{
	dev->ops->close(dev->priv_data);
	if (dev->gbb)
		free(dev->gbb);
	if (dev->fmap)
		free(dev->fmap);
	free(dev);
}

int flash_read(struct flash_device *dev, off_t off, void *buff, size_t len)
{
	return dev->ops->read(dev->priv_data, off, buff, len);
}

int flash_write(struct flash_device *dev, off_t off, void *buff, size_t len)
{
	if ((off % dev->write_size) || (len % dev->write_size)) {
		ALOGW("Bad write alignment offset %ld size %zd\n",
		      off, len);
		return -EINVAL;
	}
	return dev->ops->write(dev->priv_data, off, buff, len);
}

int flash_erase(struct flash_device *dev, off_t off, size_t len)
{
	if ((off % dev->erase_size) || (len % dev->erase_size)) {
		ALOGW("Bad erase alignment offset %ld size %zd\n",
		      off, len);
		return -EINVAL;
	}

	return dev->ops->erase(dev->priv_data, off, len);
}

size_t flash_get_size(struct flash_device *dev)
{
	return dev->ops->get_size(dev->priv_data);
}

struct fmap *flash_get_fmap(struct flash_device *dev)
{
	if (!dev->fmap) {
		off_t end = dev->ops->get_fmap_offset(dev->priv_data);
		off_t off = fmap_scan_offset(dev, end);
		dev->fmap = fmap_load(dev, off);
	}

	if (!dev->fmap)
		ALOGW("No FMAP found\n");

	return dev->fmap;
}

uint8_t *flash_get_gbb(struct flash_device *dev, size_t *size)
{
	if (!dev->gbb)
		dev->gbb = fmap_read_section(dev, "GBB", &dev->gbb_size, NULL);

	if (!dev->gbb)
		ALOGW("No GBB found\n");
	else if (size)
		*size = dev->gbb_size;

	return dev->gbb;
}

int flash_cmd(struct flash_device *dev, int cmd, int ver,
	      const void *odata, int osize, void *idata, int isize)
{
	if (!dev->ops->cmd)
		return -ENOENT;

	return dev->ops->cmd(dev->priv_data, cmd, ver,
			     odata, osize, idata, isize);
}