Merge branch 'for-next/mtd-partitions'
This commit is contained in:
commit
0e055c254c
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
global.bootm.image="/dev/nand0.kernel.bb"
|
||||
global.bootm.oftree="/dev/nand0.oftree.bb"
|
||||
|
||||
global.linux.bootargs.dyn.root="root=ubi0:rootfs ubi.mtd=rootfs rootfstype=ubifs noinitrd"
|
|
@ -1,42 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# use 'dhcp' to do dhcp in barebox and in kernel
|
||||
# use 'none' if you want to skip kernel ip autoconfiguration
|
||||
ip=dhcp
|
||||
|
||||
# or set your networking parameters here
|
||||
#eth0.ipaddr=a.b.c.d
|
||||
#eth0.netmask=a.b.c.d
|
||||
#eth0.gateway=a.b.c.d
|
||||
#eth0.serverip=a.b.c.d
|
||||
|
||||
# can be either 'nfs', 'tftp', 'nor' or 'nand'
|
||||
kernel_loc=nfs
|
||||
# can be either 'net', 'nor', 'nand' or 'initrd'
|
||||
rootfs_loc=net
|
||||
# can be either 'nfs', 'tftp', 'nand' or empty
|
||||
oftree_loc=nfs
|
||||
|
||||
# can be either 'jffs2' or 'ubifs'
|
||||
rootfs_type=ubifs
|
||||
rootfsimage=root.$rootfs_type
|
||||
ubiroot=rootfs
|
||||
|
||||
# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo
|
||||
kernelimage=zImage
|
||||
#kernelimage=uImage
|
||||
#kernelimage=Image
|
||||
#kernelimage=Image.lzo
|
||||
|
||||
nand_device=atmel_nand
|
||||
nand_parts="256k(at91bootstrap),512k(barebox)ro,256k(bareboxenv),256k(bareboxenv2),256k(spare),512k(oftree),6M(kernel),-(rootfs)"
|
||||
rootfs_mtdblock_nand=7
|
||||
|
||||
m25p80_parts="64k(bootstrap),384k(barebox),256k(bareboxenv),256k(bareboxenv2),128k(oftree),-(updater)"
|
||||
|
||||
autoboot_timeout=3
|
||||
|
||||
bootargs="console=ttyS0,115200"
|
||||
|
||||
# set a fancy prompt (if support is compiled in)
|
||||
PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m\n# "
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
mtdparts="256k(at91bootstrap),512k(barebox)ro,256k(bareboxenv),256k(bareboxenv2),256k(spare),512k(oftree),6M(kernel),-(rootfs)"
|
||||
kernelname="atmel_nand"
|
||||
|
||||
mtdparts-add -b -d nand0 -k ${kernelname} -p ${mtdparts}
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
mtdparts="64k(bootstrap),64k(bareboxenv),512k(barebox),384k(oftree),-(kernel)"
|
||||
kernelname="m25p800"
|
||||
|
||||
mtdparts-add -d m25p0 -k ${kernelname} -p ${mtdparts}
|
|
@ -1,10 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
PATH=/env/bin
|
||||
export PATH
|
||||
|
||||
. /env/config
|
||||
|
||||
splash=/env/splash.png
|
||||
|
||||
if [ -f ${splash} -a -e /dev/fb0 ]; then
|
|
@ -0,0 +1 @@
|
|||
nand net
|
|
@ -0,0 +1 @@
|
|||
sama5d4ek
|
|
@ -0,0 +1 @@
|
|||
console=ttyS0,115200
|
|
@ -9,13 +9,12 @@ CONFIG_MALLOC_SIZE=0xA00000
|
|||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_MALLOC_TLSF=y
|
||||
CONFIG_PROMPT="A5D4EK:"
|
||||
CONFIG_GLOB=y
|
||||
CONFIG_PROMPT_HUSH_PS2="y"
|
||||
CONFIG_HUSH_FANCY_PROMPT=y
|
||||
CONFIG_CMDLINE_EDITING=y
|
||||
CONFIG_AUTO_COMPLETE=y
|
||||
CONFIG_CONSOLE_ACTIVATE_ALL=y
|
||||
CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y
|
||||
CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
|
||||
CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/sama5d4ek/env"
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_CMD_ARM_CPUINFO is not set
|
||||
|
@ -35,6 +34,8 @@ CONFIG_CMD_PARTITION=y
|
|||
CONFIG_CMD_EXPORT=y
|
||||
CONFIG_CMD_LOADENV=y
|
||||
CONFIG_CMD_PRINTENV=y
|
||||
CONFIG_CMD_MAGICVAR=y
|
||||
CONFIG_CMD_MAGICVAR_HELP=y
|
||||
CONFIG_CMD_SAVEENV=y
|
||||
CONFIG_CMD_FILETYPE=y
|
||||
CONFIG_CMD_SLEEP=y
|
||||
|
|
|
@ -494,6 +494,7 @@ choice
|
|||
|
||||
config MACH_SAMA5D4EK
|
||||
bool "Atmel SAMA5D4 Evaluation Kit"
|
||||
select HAVE_DEFAULT_ENVIRONMENT_NEW
|
||||
help
|
||||
Select this if you are using Atmel's SAMA5D4-EK Evaluation Kit.
|
||||
|
||||
|
|
|
@ -35,96 +35,21 @@
|
|||
#include <linux/stat.h>
|
||||
#include <libgen.h>
|
||||
#include <getopt.h>
|
||||
#include <cmdlinepart.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define SIZE_REMAINING ((ulong)-1)
|
||||
|
||||
#define PART_ADD_DEVNAME (1 << 0)
|
||||
|
||||
static int mtd_part_do_parse_one(char *devname, const char *partstr,
|
||||
char **endp, loff_t *offset,
|
||||
loff_t devsize, size_t *retsize,
|
||||
unsigned int pflags)
|
||||
{
|
||||
loff_t size;
|
||||
char *end;
|
||||
char buf[PATH_MAX] = {};
|
||||
unsigned long flags = 0;
|
||||
int ret = 0;
|
||||
struct cdev *cdev;
|
||||
|
||||
memset(buf, 0, PATH_MAX);
|
||||
|
||||
if (*partstr == '-') {
|
||||
size = SIZE_REMAINING;
|
||||
end = (char *)partstr + 1;
|
||||
} else {
|
||||
size = strtoull_suffix(partstr, &end, 0);
|
||||
}
|
||||
|
||||
if (*end == '@')
|
||||
*offset = strtoull_suffix(end+1, &end, 0);
|
||||
|
||||
if (size == SIZE_REMAINING)
|
||||
size = devsize - *offset;
|
||||
|
||||
partstr = end;
|
||||
|
||||
if (*partstr == '(') {
|
||||
partstr++;
|
||||
end = strchr((char *) partstr, ')');
|
||||
if (!end) {
|
||||
printf("could not find matching ')'\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pflags & PART_ADD_DEVNAME)
|
||||
sprintf(buf, "%s.", devname);
|
||||
memcpy(buf + strlen(buf), partstr, end - partstr);
|
||||
|
||||
end++;
|
||||
}
|
||||
|
||||
if (size + *offset > devsize) {
|
||||
printf("%s: partition end is beyond device\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
partstr = end;
|
||||
|
||||
if (*partstr == 'r' && *(partstr + 1) == 'o') {
|
||||
flags |= DEVFS_PARTITION_READONLY;
|
||||
end = (char *)(partstr + 2);
|
||||
}
|
||||
|
||||
if (endp)
|
||||
*endp = end;
|
||||
|
||||
*retsize = size;
|
||||
|
||||
cdev = devfs_add_partition(devname, *offset, size, flags, buf);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
printf("cannot create %s: %s\n", buf, strerror(-ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_addpart(int argc, char *argv[])
|
||||
{
|
||||
char *devname;
|
||||
char *endp;
|
||||
loff_t offset = 0;
|
||||
loff_t devsize;
|
||||
struct stat s;
|
||||
int opt;
|
||||
unsigned int flags = PART_ADD_DEVNAME;
|
||||
unsigned int flags = CMDLINEPART_ADD_DEVNAME;
|
||||
|
||||
while ((opt = getopt(argc, argv, "n")) > 0) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
flags &= ~PART_ADD_DEVNAME;
|
||||
flags &= ~CMDLINEPART_ADD_DEVNAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -140,28 +65,7 @@ static int do_addpart(int argc, char *argv[])
|
|||
|
||||
devname = basename(argv[optind]);
|
||||
|
||||
endp = argv[optind + 1];
|
||||
|
||||
while (1) {
|
||||
size_t size = 0;
|
||||
|
||||
if (mtd_part_do_parse_one(devname, endp, &endp, &offset,
|
||||
devsize, &size, flags))
|
||||
return 1;
|
||||
|
||||
offset += size;
|
||||
|
||||
if (!*endp)
|
||||
break;
|
||||
|
||||
if (*endp != ',') {
|
||||
printf("parse error\n");
|
||||
return 1;
|
||||
}
|
||||
endp++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return cmdlinepart_do_parse(devname, argv[optind + 1], devsize, flags);
|
||||
}
|
||||
|
||||
BAREBOX_CMD_HELP_START(addpart)
|
||||
|
|
|
@ -5,7 +5,6 @@ mkdir -p /tmp/mtdparts
|
|||
parts=
|
||||
device=
|
||||
kernelname=
|
||||
bbdev=
|
||||
|
||||
while getopt "p:d:k:b" opt; do
|
||||
if [ ${opt} = p ]; then
|
||||
|
@ -14,8 +13,6 @@ while getopt "p:d:k:b" opt; do
|
|||
device=${OPTARG}
|
||||
elif [ ${opt} = k ]; then
|
||||
kernelname=${OPTARG}
|
||||
elif [ ${opt} = b ]; then
|
||||
bbdev=true
|
||||
fi
|
||||
done
|
||||
|
||||
|
@ -29,16 +26,12 @@ if [ -z "${parts}" ]; then
|
|||
exit
|
||||
fi
|
||||
|
||||
if [ -e /tmp/mtdparts/${device} ]; then
|
||||
if [ -n "/dev/${device}.*.bb" ]; then
|
||||
nand -d /dev/${device}.*.bb
|
||||
fi
|
||||
delpart /dev/${device}.*
|
||||
${device}.partitions="$parts"
|
||||
if [ $? != 0 ]; then
|
||||
echo "Failed to add partitions $parts to $device"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
addpart -n /dev/${device} "$parts" || exit
|
||||
mkdir -p /tmp/mtdparts/${device}
|
||||
|
||||
if [ -n ${kernelname} ]; then
|
||||
global linux.mtdparts.${device}
|
||||
global.linux.mtdparts.${device}="${kernelname}:${parts}"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <common.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <cmdlinepart.h>
|
||||
#include <init.h>
|
||||
#include <xfuncs.h>
|
||||
#include <driver.h>
|
||||
|
@ -377,9 +378,174 @@ static struct file_operations mtd_ops = {
|
|||
.lseek = dev_lseek_default,
|
||||
};
|
||||
|
||||
static int mtd_partition_set(struct device_d *dev, struct param_d *p, const char *val)
|
||||
{
|
||||
struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
|
||||
struct mtd_info *mtdpart, *tmp;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry_safe(mtdpart, tmp, &mtd->partitions, partitions_entry) {
|
||||
ret = mtd_del_partition(mtdpart);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return cmdlinepart_do_parse(mtd->cdev.name, val, mtd->size, CMDLINEPART_ADD_DEVNAME);
|
||||
}
|
||||
|
||||
static char *print_size(uint64_t s)
|
||||
{
|
||||
if (!(s & ((1 << 20) - 1)))
|
||||
return asprintf("%lldM", s >> 20);
|
||||
if (!(s & ((1 << 10) - 1)))
|
||||
return asprintf("%lldk", s >> 10);
|
||||
return asprintf("0x%lld", s);
|
||||
}
|
||||
|
||||
static int print_part(char *buf, int bufsize, struct mtd_info *mtd, uint64_t last_ofs,
|
||||
int is_last)
|
||||
{
|
||||
char *size = print_size(mtd->size);
|
||||
char *ofs = print_size(mtd->master_offset);
|
||||
int ret;
|
||||
|
||||
if (!size || !ofs) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mtd->master_offset == last_ofs)
|
||||
ret = snprintf(buf, bufsize, "%s(%s)%s", size,
|
||||
mtd->cdev.partname,
|
||||
is_last ? "" : ",");
|
||||
else
|
||||
ret = snprintf(buf, bufsize, "%s@%s(%s)%s", size,
|
||||
ofs,
|
||||
mtd->cdev.partname,
|
||||
is_last ? "" : ",");
|
||||
out:
|
||||
free(size);
|
||||
free(ofs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int print_parts(char *buf, int bufsize, struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *mtdpart;
|
||||
uint64_t last_ofs = 0;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(mtdpart, &mtd->partitions, partitions_entry) {
|
||||
int now;
|
||||
int is_last = list_is_last(&mtdpart->partitions_entry,
|
||||
&mtd->partitions);
|
||||
|
||||
now = print_part(buf, bufsize, mtdpart, last_ofs, is_last);
|
||||
if (now < 0)
|
||||
return now;
|
||||
|
||||
if (buf && bufsize) {
|
||||
buf += now;
|
||||
bufsize -= now;
|
||||
}
|
||||
ret += now;
|
||||
last_ofs = mtdpart->master_offset + mtdpart->size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *mtd_partition_get(struct device_d *dev, struct param_d *p)
|
||||
{
|
||||
struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
|
||||
int len = 0;
|
||||
|
||||
free(p->value);
|
||||
|
||||
len = print_parts(NULL, 0, mtd);
|
||||
p->value = xzalloc(len + 1);
|
||||
print_parts(p->value, len + 1, mtd);
|
||||
|
||||
return p->value;
|
||||
}
|
||||
|
||||
static int mtd_part_compare(struct list_head *a, struct list_head *b)
|
||||
{
|
||||
struct mtd_info *mtda = container_of(a, struct mtd_info, partitions_entry);
|
||||
struct mtd_info *mtdb = container_of(b, struct mtd_info, partitions_entry);
|
||||
|
||||
if (mtda->master_offset > mtdb->master_offset)
|
||||
return 1;
|
||||
if (mtda->master_offset < mtdb->master_offset)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int of_mtd_fixup(struct device_node *root, void *ctx)
|
||||
{
|
||||
struct mtd_info *mtd = ctx, *partmtd;
|
||||
struct device_node *np, *part, *tmp;
|
||||
int ret, i = 0;
|
||||
|
||||
np = of_find_node_by_path(mtd->of_path);
|
||||
if (!np) {
|
||||
dev_err(&mtd->class_dev, "Cannot find nodepath %s, cannot fixup\n",
|
||||
mtd->of_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_child_of_node_safe(np, tmp, part) {
|
||||
if (of_get_property(part, "compatible", NULL))
|
||||
continue;
|
||||
of_delete_node(part);
|
||||
}
|
||||
|
||||
list_for_each_entry(partmtd, &mtd->partitions, partitions_entry) {
|
||||
int na, ns, len = 0;
|
||||
char *name = asprintf("partition@%d", i++);
|
||||
void *p;
|
||||
u8 tmp[16 * 16]; /* Up to 64-bit address + 64-bit size */
|
||||
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
part = of_new_node(np, name);
|
||||
free(name);
|
||||
if (!part)
|
||||
return -ENOMEM;
|
||||
|
||||
p = of_new_property(part, "label", partmtd->cdev.partname,
|
||||
strlen(partmtd->cdev.partname) + 1);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
na = of_n_addr_cells(np);
|
||||
ns = of_n_size_cells(np);
|
||||
|
||||
of_write_number(tmp + len, partmtd->master_offset, na);
|
||||
len += na * 4;
|
||||
of_write_number(tmp + len, partmtd->size, ns);
|
||||
len += ns * 4;
|
||||
|
||||
ret = of_set_property(part, "reg", tmp, len, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (partmtd->cdev.flags & DEVFS_PARTITION_READONLY) {
|
||||
ret = of_set_property(part, "read-only", NULL, 0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id)
|
||||
{
|
||||
struct mtddev_hook *hook;
|
||||
int ret;
|
||||
|
||||
if (!devname)
|
||||
devname = "mtd";
|
||||
|
@ -387,7 +553,10 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id)
|
|||
mtd->class_dev.id = device_id;
|
||||
if (mtd->parent)
|
||||
mtd->class_dev.parent = mtd->parent;
|
||||
register_device(&mtd->class_dev);
|
||||
|
||||
ret = register_device(&mtd->class_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mtd->cdev.ops = &mtd_ops;
|
||||
mtd->cdev.size = mtd->size;
|
||||
|
@ -396,6 +565,8 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id)
|
|||
else
|
||||
mtd->cdev.name = asprintf("%s%d", devname, mtd->class_dev.id);
|
||||
|
||||
INIT_LIST_HEAD(&mtd->partitions);
|
||||
|
||||
mtd->cdev.priv = mtd;
|
||||
mtd->cdev.dev = &mtd->class_dev;
|
||||
mtd->cdev.mtd = mtd;
|
||||
|
@ -407,19 +578,50 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id)
|
|||
dev_add_param_int_ro(&mtd->class_dev, "oobsize", mtd->oobsize, "%u");
|
||||
}
|
||||
|
||||
devfs_create(&mtd->cdev);
|
||||
ret = devfs_create(&mtd->cdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (mtd->master && !(mtd->cdev.flags & DEVFS_PARTITION_FIXED)) {
|
||||
struct mtd_info *mtdpart;
|
||||
|
||||
list_for_each_entry(mtdpart, &mtd->master->partitions, partitions_entry) {
|
||||
if (mtdpart->master_offset + mtdpart->size <= mtd->master_offset)
|
||||
continue;
|
||||
if (mtd->master_offset + mtd->size <= mtdpart->master_offset)
|
||||
continue;
|
||||
dev_err(&mtd->class_dev, "New partition %s conflicts with %s\n",
|
||||
mtd->name, mtdpart->name);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
list_add_sort(&mtd->partitions_entry, &mtd->master->partitions, mtd_part_compare);
|
||||
}
|
||||
|
||||
if (mtd_can_have_bb(mtd))
|
||||
mtd->cdev_bb = mtd_add_bb(mtd, NULL);
|
||||
|
||||
if (mtd->parent && !mtd->master)
|
||||
if (mtd->parent && !mtd->master) {
|
||||
dev_add_param(&mtd->class_dev, "partitions", mtd_partition_set, mtd_partition_get, 0);
|
||||
of_parse_partitions(&mtd->cdev, mtd->parent->device_node);
|
||||
if (IS_ENABLED(CONFIG_OFDEVICE) && mtd->parent->device_node) {
|
||||
mtd->of_path = xstrdup(mtd->parent->device_node->full_name);
|
||||
of_register_fixup(of_mtd_fixup, mtd);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(hook, &mtd_register_hooks, hook)
|
||||
if (hook->add_mtd_device)
|
||||
hook->add_mtd_device(mtd, devname, &hook->priv);
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
devfs_remove(&mtd->cdev);
|
||||
err:
|
||||
free(mtd->cdev.name);
|
||||
unregister_device(&mtd->class_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int del_mtd_device (struct mtd_info *mtd)
|
||||
|
@ -431,9 +633,14 @@ int del_mtd_device (struct mtd_info *mtd)
|
|||
hook->del_mtd_device(mtd, &hook->priv);
|
||||
|
||||
devfs_remove(&mtd->cdev);
|
||||
if (mtd->cdev_bb)
|
||||
mtd_del_bb(mtd);
|
||||
unregister_device(&mtd->class_dev);
|
||||
free(mtd->param_size.value);
|
||||
free(mtd->cdev.name);
|
||||
if (mtd->master)
|
||||
list_del(&mtd->partitions_entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,17 @@ err:
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void mtd_del_bb(struct mtd_info *mtd)
|
||||
{
|
||||
struct cdev *cdev = mtd->cdev_bb;
|
||||
struct nand_bb *bb = container_of(cdev, struct nand_bb, cdev);
|
||||
|
||||
devfs_remove(&bb->cdev);
|
||||
list_del_init(&bb->list);
|
||||
free(bb->name);
|
||||
free(bb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bad block aware device ontop of another (NAND) device
|
||||
* @param[in] dev The device to add a partition on
|
||||
|
@ -335,10 +346,7 @@ int dev_remove_bb_dev(const char *name)
|
|||
|
||||
list_for_each_entry_safe(bb, tmp, &bb_list, list) {
|
||||
if (!strcmp(bb->cdev.name, name)) {
|
||||
devfs_remove(&bb->cdev);
|
||||
list_del_init(&bb->list);
|
||||
free(bb->name);
|
||||
free(bb);
|
||||
mtd_del_bb(bb->mtd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
|
|||
uint64_t size, unsigned long flags, const char *name)
|
||||
{
|
||||
struct mtd_info *part;
|
||||
int ret;
|
||||
|
||||
part = xzalloc(sizeof(*part));
|
||||
|
||||
|
@ -122,6 +123,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
|
|||
part->ecclayout = mtd->ecclayout;
|
||||
part->ecc_strength = mtd->ecc_strength;
|
||||
part->subpage_sft = mtd->subpage_sft;
|
||||
part->cdev.flags = flags;
|
||||
|
||||
if (mtd->numeraseregions > 1) {
|
||||
/* Deal with variable erase size stuff */
|
||||
|
@ -160,7 +162,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
|
|||
|
||||
part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL;
|
||||
part->size = size;
|
||||
part->name = strdup(name);
|
||||
part->name = xstrdup(name);
|
||||
|
||||
part->master_offset = offset;
|
||||
part->master = mtd;
|
||||
|
@ -168,9 +170,17 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
|
|||
if (!strncmp(mtd->cdev.name, name, strlen(mtd->cdev.name)))
|
||||
part->cdev.partname = xstrdup(name + strlen(mtd->cdev.name) + 1);
|
||||
|
||||
add_mtd_device(part, part->name, DEVICE_ID_SINGLE);
|
||||
ret = add_mtd_device(part, part->name, DEVICE_ID_SINGLE);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return part;
|
||||
err:
|
||||
free(part->cdev.partname);
|
||||
free(part->name);
|
||||
free(part);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int mtd_del_partition(struct mtd_info *part)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef __CMD_LINE_PART_H
|
||||
#define __CMD_LINE_PART_H
|
||||
|
||||
#define CMDLINEPART_ADD_DEVNAME (1 << 0)
|
||||
|
||||
int cmdlinepart_do_parse_one(const char *devname, const char *partstr,
|
||||
const char **endp, loff_t *offset,
|
||||
loff_t devsize, loff_t *retsize,
|
||||
unsigned int partition_flags);
|
||||
|
||||
int cmdlinepart_do_parse(const char *devname, const char *parts, loff_t devsize,
|
||||
unsigned partition_flags);
|
||||
|
||||
#endif /* __CMD_LINE_PART_H */
|
|
@ -220,6 +220,11 @@ struct mtd_info {
|
|||
|
||||
struct mtd_info *master;
|
||||
loff_t master_offset;
|
||||
|
||||
struct list_head partitions;
|
||||
struct list_head partitions_entry;
|
||||
|
||||
char *of_path;
|
||||
};
|
||||
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#ifndef __NAND_H__
|
||||
#define __NAND_H__
|
||||
|
||||
|
@ -8,6 +7,7 @@ struct nand_bb;
|
|||
int dev_add_bb_dev(const char *filename, const char *name);
|
||||
int dev_remove_bb_dev(const char *name);
|
||||
struct cdev *mtd_add_bb(struct mtd_info *mtd, const char *name);
|
||||
void mtd_del_bb(struct mtd_info *mtd);
|
||||
#else
|
||||
static inline int dev_add_bb_dev(const char *filename, const char *name) {
|
||||
return 0;
|
||||
|
@ -21,7 +21,10 @@ static inline struct cdev *mtd_add_bb(struct mtd_info *mtd, const char *name)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void mtd_del_bb(struct mtd_info *mtd)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NAND_H__ */
|
||||
|
||||
|
|
|
@ -623,6 +623,8 @@ static inline struct device_node *of_find_matching_node(
|
|||
for (dn = of_find_node_with_property(NULL, prop_name); dn; \
|
||||
dn = of_find_node_with_property(dn, prop_name))
|
||||
|
||||
#define for_each_child_of_node_safe(parent, tmp, child) \
|
||||
list_for_each_entry_safe(child, tmp, &parent->children, parent_list)
|
||||
#define for_each_child_of_node(parent, child) \
|
||||
list_for_each_entry(child, &parent->children, parent_list)
|
||||
#define for_each_available_child_of_node(parent, child) \
|
||||
|
|
|
@ -18,6 +18,7 @@ obj-y += kfifo.o
|
|||
obj-y += libbb.o
|
||||
obj-y += libgen.o
|
||||
obj-y += stringlist.o
|
||||
obj-y += cmdlinepart.o
|
||||
obj-y += recursive_action.o
|
||||
obj-y += make_directory.o
|
||||
obj-y += math.o
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* command line partition parsing code
|
||||
*
|
||||
* Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <driver.h>
|
||||
#include <fs.h>
|
||||
#include <linux/err.h>
|
||||
#include <cmdlinepart.h>
|
||||
|
||||
#define SIZE_REMAINING ((loff_t)-1)
|
||||
|
||||
int cmdlinepart_do_parse_one(const char *devname, const char *partstr,
|
||||
const char **endp, loff_t *offset,
|
||||
loff_t devsize, loff_t *retsize,
|
||||
unsigned int partition_flags)
|
||||
{
|
||||
loff_t size;
|
||||
char *end;
|
||||
char buf[PATH_MAX] = {};
|
||||
unsigned long flags = 0;
|
||||
int ret = 0;
|
||||
struct cdev *cdev;
|
||||
|
||||
memset(buf, 0, PATH_MAX);
|
||||
|
||||
if (*partstr == '-') {
|
||||
size = SIZE_REMAINING;
|
||||
end = (char *)partstr + 1;
|
||||
} else {
|
||||
size = strtoull_suffix(partstr, &end, 0);
|
||||
}
|
||||
|
||||
if (*end == '@')
|
||||
*offset = strtoull_suffix(end+1, &end, 0);
|
||||
|
||||
if (size == SIZE_REMAINING)
|
||||
size = devsize - *offset;
|
||||
|
||||
partstr = end;
|
||||
|
||||
if (*partstr == '(') {
|
||||
partstr++;
|
||||
end = strchr((char *) partstr, ')');
|
||||
if (!end) {
|
||||
printf("could not find matching ')'\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((partition_flags & CMDLINEPART_ADD_DEVNAME) &&
|
||||
strncmp(devname, partstr, strlen(devname)))
|
||||
sprintf(buf, "%s.", devname);
|
||||
memcpy(buf + strlen(buf), partstr, end - partstr);
|
||||
|
||||
end++;
|
||||
}
|
||||
|
||||
if (size + *offset > devsize) {
|
||||
printf("%s: partition end is beyond device\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
partstr = end;
|
||||
|
||||
if (*partstr == 'r' && *(partstr + 1) == 'o') {
|
||||
flags |= DEVFS_PARTITION_READONLY;
|
||||
end = (char *)(partstr + 2);
|
||||
}
|
||||
|
||||
if (endp)
|
||||
*endp = end;
|
||||
|
||||
*retsize = size;
|
||||
|
||||
cdev = devfs_add_partition(devname, *offset, size, flags, buf);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
printf("cannot create %s: %s\n", buf, strerror(-ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmdlinepart_do_parse(const char *devname, const char *parts, loff_t devsize,
|
||||
unsigned partition_flags)
|
||||
{
|
||||
loff_t offset = 0;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
loff_t size = 0;
|
||||
|
||||
ret = cmdlinepart_do_parse_one(devname, parts, &parts, &offset,
|
||||
devsize, &size, partition_flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
offset += size;
|
||||
if (!*parts)
|
||||
break;
|
||||
|
||||
if (*parts != ',') {
|
||||
printf("parse error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
parts++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue