summaryrefslogtreecommitdiffstats
path: root/common/partition.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:01:53 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:01:53 +0200
commit50f42153cbd0f7a70e165a3644873d311d3ec3d7 (patch)
tree668b120806f60c4d69e902a3c0e9faee49c22390 /common/partition.c
parentb2a900da4c4cd63e66fe34b59f062c4471cc6845 (diff)
downloadbarebox-50f42153cbd0f7a70e165a3644873d311d3ec3d7.tar.gz
barebox-50f42153cbd0f7a70e165a3644873d311d3ec3d7.tar.xz
svn_rev_435
rename
Diffstat (limited to 'common/partition.c')
-rw-r--r--common/partition.c250
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);