#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(…) …;