linux/drivers/mtd/parsers/tplink_safeloader.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright © 2022 Rafał Miłecki <[email protected]>
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/slab.h>

#define TPLINK_SAFELOADER_DATA_OFFSET
#define TPLINK_SAFELOADER_MAX_PARTS

struct safeloader_cmn_header {} __packed;

static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd)
{}

static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
					      const struct mtd_partition **pparts,
					      struct mtd_part_parser_data *data)
{
	struct mtd_partition *parts;
	char name[65];
	size_t offset;
	size_t bytes;
	char *buf;
	int idx;
	int err;

	parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL);
	if (!parts) {
		err = -ENOMEM;
		goto err_out;
	}

	buf = mtd_parser_tplink_safeloader_read_table(mtd);
	if (!buf) {
		err = -ENOENT;
		goto err_free_parts;
	}

	for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET;
	     idx < TPLINK_SAFELOADER_MAX_PARTS &&
	     sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%zn\n",
		    name, &parts[idx].offset, &parts[idx].size, &bytes) == 3;
	     idx++, offset += bytes + 1) {
		parts[idx].name = kstrdup(name, GFP_KERNEL);
		if (!parts[idx].name) {
			err = -ENOMEM;
			goto err_free;
		}
	}

	if (idx == TPLINK_SAFELOADER_MAX_PARTS)
		pr_warn("Reached maximum number of partitions!\n");

	kfree(buf);

	*pparts = parts;

	return idx;

err_free:
	for (idx -= 1; idx >= 0; idx--)
		kfree(parts[idx].name);
err_free_parts:
	kfree(parts);
err_out:
	return err;
};

static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts,
						 int nr_parts)
{}

static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] =;
MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table);

static struct mtd_part_parser mtd_parser_tplink_safeloader =;
module_mtd_part_parser();

MODULE_DESCRIPTION();
MODULE_LICENSE();