Newer
Older
barebox / common / mtdpart.c
@Sascha Hauer Sascha Hauer on 5 Jul 2007 5 KB svn_rev_118

#include <common.h>
#include <command.h>
#include <driver.h>
#include <malloc.h>

struct partition {
        int num;

        unsigned long offset;

        struct device_d *parent;
        struct device_d device;
};

#if 0
static void dev_del_partitions(struct device_d *dev)
{
        struct partition *part = dev->part;
        struct partition *oldpart;

        while (part) {
                unregister_device(&part->device);
                oldpart = part;
                part = part->next;
                free(oldpart);
        }

        dev->part = NULL;
}
#endif

int mtd_part_do_parse_one (struct partition *part, const char *str, char **endp)
{
        ulong size;
        char *end;
        char buf[MAX_DRIVER_NAME];
        int ro = 0;

	memset(buf, 0, MAX_DRIVER_NAME);

        if (*str == '-') {
                /* FIXME: The rest of the device */
                return -1;
        }

        size = strtoul_suffix(str, &end, 0);

        str = end;

        if (*str == '(') {
		str++;
                end = strchr(str, ')');
                if (!end) {
                        printf("could not find matching ')'\n");
                        return -1;
                }
                if (end - str >= MAX_DRIVER_NAME) {
                        printf("device name too long\n");
                        return -1;
                }

                memcpy(buf, str, end - str);
                end++;
        }

        str = end;

        if (*str == 'r' && *(str + 1) == 'o') {
                ro = 1;
                end = (char *)(str + 2);
        }

        if (endp)
                *endp = end;

        strcpy(part->device.name, "partition");
        part->device.size = size;

//        printf("part: name=%10s size=0x%08x %s\n", part->device.name, size, ro ? "ro":"");
        return 0;
}

int do_addpart ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
        struct partition *part;
        struct device_d *dev;
        char *endp;
        int num = 0;
        unsigned long offset;

        if (argc != 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

        dev = device_from_spec_str(argv[1], &endp);
        if (!dev) {
                printf("no such device: %s\n",argv[1]);
                return 1;
        }

//        dev_del_partitions(dev);

        offset = 0;

        while (1) {
                part = malloc(sizeof(struct partition));
                if(!part) {
                        printf("-ENOMEM\n");
                        return 1;
                }

                part->offset = offset;
                part->parent = dev;
                part->num = num;
                part->device.map_base = dev->map_base + offset;

                if(mtd_part_do_parse_one(part, endp, &endp)) {
//                        dev_del_partitions(dev);
                        free(part);
                        return 1;
                }

                offset += part->device.size;

                part->device.platform_data = part;

                sprintf(part->device.id, "%s.%d", dev->id, num);
                register_device(&part->device);
                num++;

                if(!*endp)
                        break;
                if(*endp != ',') {
                        printf("parse error\n");
                        return 1;
                }
                endp++;
        }

        return 0;
}

int do_delpart ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
        struct device_d *dev, *p;
        int i = 0;
        char buf[MAX_DRIVER_NAME];

        if (argc != 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

        dev = device_from_spec_str(argv[1], NULL);
        if (!dev) {
                printf("no such device: %s\n",argv[1]);
                return 1;
        }

        /* This is lame. Devices should to able to have children */
        while(1) {
                sprintf(buf, "%s.%d", dev->id, i);
                p = device_from_spec_str(buf, NULL);
                if (p)
                        unregister_device(p);
                else
                        break;
                i++;
        }

        return 0;
}

U_BOOT_CMD(
	addpart,     2,     0,      do_addpart,
	"addpart     - add a partition table to a device\n",
	""
);

U_BOOT_CMD(
	delpart,     2,     0,      do_delpart,
	"delpart     - delete a partition table from a device\n",
	""
);

int part_probe (struct device_d *dev)
{
//        printf("%s: devname: %s devid: %s drvname: %s\n",__FUNCTION__, dev->name, dev->id, dev->driver->name);
        return 0;
}

int part_erase(struct device_d *dev, size_t count, unsigned long offset)
{
        struct partition *part = dev->platform_data;

        if (part->parent->driver->erase)
                return part->parent->driver->erase(part->parent, count, offset + part->offset);

        return -1;
}

ssize_t part_read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
{
        struct partition *part = dev->platform_data;

        return read(part->parent, buf, count, offset + part->offset, flags);
}

ssize_t part_write(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
{
        struct partition *part = dev->platform_data;

        return write(part->parent, buf, count, offset + part->offset, flags);
}

static struct driver_d part_driver = {
        .name  = "partition",
        .probe = part_probe,
        .read  = part_read,
        .write = part_write,
        .erase = part_erase,
};

int partition_init(void)
{
        return register_driver(&part_driver);
}