diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:01:53 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:01:53 +0200 |
commit | 50f42153cbd0f7a70e165a3644873d311d3ec3d7 (patch) | |
tree | 668b120806f60c4d69e902a3c0e9faee49c22390 /common/partition.c | |
parent | b2a900da4c4cd63e66fe34b59f062c4471cc6845 (diff) | |
download | barebox-50f42153cbd0f7a70e165a3644873d311d3ec3d7.tar.gz barebox-50f42153cbd0f7a70e165a3644873d311d3ec3d7.tar.xz |
svn_rev_435
rename
Diffstat (limited to 'common/partition.c')
-rw-r--r-- | common/partition.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/common/partition.c b/common/partition.c new file mode 100644 index 0000000000..6c91a54ac5 --- /dev/null +++ b/common/partition.c @@ -0,0 +1,250 @@ + +#include <common.h> +#include <command.h> +#include <init.h> +#include <driver.h> +#include <malloc.h> +#include <errno.h> +#include <partition.h> +#include <xfuncs.h> + +struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset, size_t size, char *name) +{ + struct partition *part; + + if (offset + size > dev->size) + return NULL; + + part = xzalloc(sizeof(struct partition)); + + strcpy(part->device.name, "partition"); + part->device.map_base = dev->map_base + offset; + part->device.size = size; + part->device.type_data = part; + get_free_deviceid(part->device.id, name); + + part->offset = offset; + part->physdev = dev; + + register_device(&part->device); + + if (part->device.driver) + return &part->device; + + free(part); + return 0; +} + +static void dev_del_partitions(struct device_d *dev) +{ + struct device_d *p; + char buf[MAX_DRIVER_NAME]; + int i = 0; + + /* 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++; + } +} + +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 == '-') { + size = part->physdev->size - part->offset; + end = (char *)str + 1; + } else { + size = strtoul_suffix(str, &end, 0); + } + + if (size + part->offset > part->physdev->size) { + printf("partition end is beyond device\n"); + return -EINVAL; + } + + str = end; + + if (*str == '(') { + str++; + end = strchr(str, ')'); + if (!end) { + printf("could not find matching ')'\n"); + return -EINVAL; + } + if (end - str >= MAX_DRIVER_NAME) { + printf("device name too long\n"); + return -EINVAL; + } + + memcpy(part->name, 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; + + 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->physdev = 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.type_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; + + 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; + } + + dev_del_partitions(dev); + + return 0; +} + +U_BOOT_CMD_START(addpart) + .maxargs = 2, + .cmd = do_addpart, + .usage = "addpart - add a partition table to a device\n", +U_BOOT_CMD_END + +U_BOOT_CMD_START(delpart) + .maxargs = 2, + .cmd = do_delpart, + .usage = "delpart - delete a partition table from a device\n", +U_BOOT_CMD_END + +static int part_probe(struct device_d *dev) +{ + struct partition *part = dev->type_data; + + printf("registering partition %s on device %s (size=0x%08x, name=%s)\n", + dev->id, part->physdev->id, dev->size, part->name); + return 0; +} + +static int part_erase(struct device_d *dev, size_t count, unsigned long offset) +{ + struct partition *part = dev->type_data; + + if (part->physdev->driver->erase) + return part->physdev->driver->erase(part->physdev, count, offset + part->offset); + + return -1; +} + +static ssize_t part_read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags) +{ + struct partition *part = dev->type_data; + + return dev_read(part->physdev, buf, count, offset + part->offset, flags); +} + +static ssize_t part_write(struct device_d *dev, const void *buf, size_t count, unsigned long offset, ulong flags) +{ + struct partition *part = dev->type_data; + + return dev_write(part->physdev, buf, count, offset + part->offset, flags); +} + +struct driver_d part_driver = { + .name = "partition", + .probe = part_probe, + .read = part_read, + .write = part_write, + .erase = part_erase, +}; + +static int partition_init(void) +{ + return register_driver(&part_driver); +} + +device_initcall(partition_init); |