diff --git a/board/ipe337/ipe337.c b/board/ipe337/ipe337.c index 3bcba6f..50723b8 100644 --- a/board/ipe337/ipe337.c +++ b/board/ipe337/ipe337.c @@ -42,8 +42,8 @@ register_device(&smc911x_dev); - dev_add_partition(&cfi_dev, 0x00000, 0x20000, "self"); - dev_add_partition(&cfi_dev, 0x20000, 0x20000, "env"); + dev_add_partition(&cfi_dev, 0x00000, 0x20000, PARTITION_FIXED, "self"); + dev_add_partition(&cfi_dev, 0x20000, 0x20000, PARTITION_FIXED, "env"); dev_protect(&cfi_dev, 0x20000, 0, 1); return 0; diff --git a/board/netx/netx.c b/board/netx/netx.c index 63a33f0..fa7d964 100644 --- a/board/netx/netx.c +++ b/board/netx/netx.c @@ -75,11 +75,11 @@ register_device(&netx_eth_dev0); // register_device(&netx_eth_dev1); - dev_add_partition(&cfi_dev, 0x00000, 0x40000, "self"); + dev_add_partition(&cfi_dev, 0x00000, 0x40000, PARTITION_FIXED, "self"); dev_protect(&cfi_dev, 0x40000, 0, 1); /* Do not overwrite primary env for now */ - dev_add_partition(&cfi_dev, 0xc0000, 0x80000, "env"); + dev_add_partition(&cfi_dev, 0xc0000, 0x80000, PARTITION_FIXED, "env"); return 0; } diff --git a/board/phycore_imx31/phycore_imx31.c b/board/phycore_imx31/phycore_imx31.c index 68ac644..8f39e42 100644 --- a/board/phycore_imx31/phycore_imx31.c +++ b/board/phycore_imx31/phycore_imx31.c @@ -113,8 +113,8 @@ * Create partitions that should be * not touched by any regular user */ - dev_add_partition(&cfi_dev, 0x00000, 0x20000, "self"); /* ourself */ - dev_add_partition(&cfi_dev, 0x20000, 0x20000, "env"); /* environment */ + dev_add_partition(&cfi_dev, 0x00000, 0x20000, PARTITION_FIXED, "self"); /* ourself */ + dev_add_partition(&cfi_dev, 0x20000, 0x20000, PARTITION_FIXED, "env"); /* environment */ dev_protect(&cfi_dev, 0x20000, 0, 1); register_device(&sram_dev); diff --git a/board/phycore_mpc5200b_tiny/phycore_mpc5200b_tiny.c b/board/phycore_mpc5200b_tiny/phycore_mpc5200b_tiny.c index e3fd9c8..39c3b76 100644 --- a/board/phycore_mpc5200b_tiny/phycore_mpc5200b_tiny.c +++ b/board/phycore_mpc5200b_tiny/phycore_mpc5200b_tiny.c @@ -90,8 +90,8 @@ scratch_dev.size = SCRATCHMEM_SIZE; register_device(&scratch_dev); - dev_add_partition(&cfi_dev, 0x00f00000, 0x40000, "self"); - dev_add_partition(&cfi_dev, 0x00f60000, 0x20000, "env"); + dev_add_partition(&cfi_dev, 0x00f00000, 0x40000, PARTITION_FIXED, "self"); + dev_add_partition(&cfi_dev, 0x00f60000, 0x20000, PARTITION_FIXED, "env"); return 0; } diff --git a/board/phycore_pcm038/pcm038.c b/board/phycore_pcm038/pcm038.c index 60c4d89..092abd1 100644 --- a/board/phycore_pcm038/pcm038.c +++ b/board/phycore_pcm038/pcm038.c @@ -87,8 +87,8 @@ register_device(&sdram_dev); register_device(&fec_dev); - dev_add_partition(&cfi_dev, 0x00000, 0x20000, "self"); - dev_add_partition(&cfi_dev, 0x40000, 0x20000, "env"); + dev_add_partition(&cfi_dev, 0x00000, 0x20000, PARTITION_FIXED, "self"); + dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env"); dev_protect(&cfi_dev, 0x20000, 0, 1); return 0; diff --git a/board/scb9328/scb9328.c b/board/scb9328/scb9328.c index 5446fc3..022e476 100644 --- a/board/scb9328/scb9328.c +++ b/board/scb9328/scb9328.c @@ -91,8 +91,8 @@ register_device(&sdram_dev); register_device(&dm9000_dev); - dev_add_partition(&cfi_dev, 0x00000, 0x20000, "self"); - dev_add_partition(&cfi_dev, 0x40000, 0x20000, "env"); + dev_add_partition(&cfi_dev, 0x00000, 0x20000, PARTITION_FIXED, "self"); + dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env"); dev_protect(&cfi_dev, 0x20000, 0, 1); return 0; diff --git a/commands/partition.c b/commands/partition.c index c613033..421f01f 100644 --- a/commands/partition.c +++ b/commands/partition.c @@ -29,25 +29,29 @@ #include #include -static void dev_del_partitions(struct device_d *physdev) +static int dev_del_partitions(struct device_d *physdev) { - struct device_d *dev; - char buf[MAX_DRIVER_NAME]; - int i = 0; + struct device_d *child, *tmp; + int ret; - /* This is lame. Devices should to able to have children */ - while (1) { - sprintf(buf, "%s.%d", physdev->id, i); - dev = device_from_spec_str(buf, NULL); - if (dev) { - struct partition *part = dev->type_data; - printf("unregister %s %s\n", dev->name, dev->id); - unregister_device(dev); - free(part); - } else - break; - i++; + device_for_each_child_safe(physdev, tmp, child) { + struct partition *part = child->type_data; + + debug("delete partition: %s\n", child->id); + + if (part->flags & PARTITION_FIXED) + continue; + + ret = unregister_device(child); + if (ret) { + printf("delete partition `%s' failed: %s\n", child->id, errno_str()); + return errno; + } + + free(part); } + + return 0; } static int mtd_part_do_parse_one(struct partition *part, const char *str, @@ -92,7 +96,7 @@ str = end; if (*str == 'r' && *(str + 1) == 'o') { - part->readonly = 1; + part->flags |= PARTITION_READONLY; end = (char *)(str + 2); } @@ -113,12 +117,12 @@ int num = 0; unsigned long offset; - if (argc != 2) { + if (argc != 3) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } - dev = device_from_spec_str(argv[1], &endp); + dev = get_device_by_path(argv[1]); if (!dev) { printf("no such device: %s\n", argv[1]); return 1; @@ -128,6 +132,8 @@ offset = 0; + endp = argv[2]; + while (1) { part = xzalloc(sizeof(struct partition)); @@ -138,28 +144,37 @@ if (mtd_part_do_parse_one(part, endp, &endp)) { dev_del_partitions(dev); - free(part); - return 1; + goto free_out; } offset += part->device.size; part->device.type_data = part; - sprintf(part->device.id, "%s.%d", dev->id, num); - register_device(&part->device); + sprintf(part->device.id, "%s.%s", dev->id, part->name); + if (register_device(&part->device)) + goto free_out; + + dev_add_child(dev, &part->device); + num++; if (!*endp) break; + if (*endp != ',') { printf("parse error\n"); - return 1; + goto err_out; } endp++; } return 0; + +free_out: + free(part); +err_out: + return 1; } static __maybe_unused char cmd_addpart_help[] = @@ -175,7 +190,7 @@ "Note That this command has to be reworked and will probably change it's API."; U_BOOT_CMD_START(addpart) - .maxargs = 2, + .maxargs = 3, .cmd = do_addpart, .usage = "add a partition table to a device", U_BOOT_CMD_HELP(cmd_addpart_help) @@ -190,7 +205,7 @@ return 1; } - dev = device_from_spec_str(argv[1], NULL); + dev = get_device_by_path(argv[1]); if (!dev) { printf("no such device: %s\n", argv[1]); return 1; diff --git a/common/partition.c b/common/partition.c index a37177c..98bae39 100644 --- a/common/partition.c +++ b/common/partition.c @@ -7,7 +7,8 @@ #include #include -struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset, size_t size, char *name) +struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset, + size_t size, int flags, const char *name) { struct partition *part; @@ -24,8 +25,10 @@ part->offset = offset; part->physdev = dev; + part->flags = flags; register_device(&part->device); + dev_add_child(dev, &part->device); if (part->device.driver) return &part->device; @@ -81,15 +84,17 @@ { struct partition *part = dev->type_data; - if (part->readonly) - return -EROFS; + if (part->flags & PARTITION_READONLY) + return -EROFS; else return dev_write(part->physdev, buf, count, offset + part->offset, flags); } static int part_probe(struct device_d *dev) { +#ifdef DEBUG struct partition *part = dev->type_data; +#endif debug("registering partition %s on device %s (size=0x%08x, name=%s)\n", dev->id, part->physdev->id, dev->size, part->name); diff --git a/fs/fs.c b/fs/fs.c index a613b1a..3aabb17 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -202,6 +202,11 @@ return e->next; } +const char *fsdev_get_mountpoint(struct fs_device_d *fsdev) +{ + return fsdev->mtab.path; +} + FILE files[MAX_FILES]; FILE *get_file(void) @@ -224,7 +229,7 @@ files[f->no].in_use = 0; } -static struct device_d *get_device_by_path(char **path) +static struct device_d *get_fs_device_by_path(char **path) { struct device_d *dev; struct mtab_entry *e; @@ -346,7 +351,7 @@ if (path_check_prereq(pathname, S_IFREG)) goto out; - dev = get_device_by_path(&p); + dev = get_fs_device_by_path(&p); if (!dev) goto out; fsdrv = (struct fs_driver_d *)dev->driver->type_data; @@ -386,7 +391,7 @@ goto out1; } - dev = get_device_by_path(&path); + dev = get_fs_device_by_path(&path); if (!dev) goto out; @@ -599,7 +604,7 @@ * driver will match. The filesystem driver then grabs the infomation * it needs from the new devices type_data. */ -int mount(const char *device, const char *fsname, const char *path) +int mount(const char *device, const char *fsname, const char *_path) { struct driver_d *drv; struct fs_driver_d *fs_drv; @@ -607,11 +612,23 @@ struct fs_device_d *fsdev; struct device_d *dev, *parent_device = 0; int ret; + char *path = normalise_path(_path); errno = 0; debug("mount: %s on %s type %s\n", device, path, fsname); + if (get_mtab_entry_by_path(path) != mtab) { + errno = -EBUSY; + goto out; + } + + if (strchr(path + 1, '/')) { + printf("mounting allowed on first directory level only\n"); + errno = -EBUSY; + goto out; + } + drv = get_driver_by_name(fsname); if (!drv) { errno = -ENODEV; @@ -663,10 +680,13 @@ goto out; } + if (parent_device) + dev_add_child(parent_device, &fsdev->dev); + dev = &fsdev->dev; /* add mtab entry */ - entry = malloc(sizeof(struct mtab_entry)); + entry = &fsdev->mtab; sprintf(entry->path, "%s", path); entry->dev = dev; entry->parent_device = parent_device; @@ -681,6 +701,7 @@ e->next = entry; } out: + free(path); return errno; } EXPORT_SYMBOL(mount); @@ -710,7 +731,7 @@ unregister_device(entry->dev); free(entry->dev->type_data); - free(entry); + return 0; } EXPORT_SYMBOL(umount); @@ -726,7 +747,7 @@ if (path_check_prereq(pathname, S_IFDIR)) goto out; - dev = get_device_by_path(&p); + dev = get_fs_device_by_path(&p); if (!dev) goto out; fsdrv = (struct fs_driver_d *)dev->driver->type_data; @@ -809,7 +830,7 @@ if (path_check_prereq(pathname, S_UB_DOES_NOT_EXIST)) goto out; - dev = get_device_by_path(&p); + dev = get_fs_device_by_path(&p); if (!dev) goto out; fsdrv = (struct fs_driver_d *)dev->driver->type_data; @@ -836,7 +857,7 @@ if (path_check_prereq(pathname, S_IFDIR | S_UB_IS_EMPTY)) goto out; - dev = get_device_by_path(&p); + dev = get_fs_device_by_path(&p); if (!dev) goto out; fsdrv = (struct fs_driver_d *)dev->driver->type_data; diff --git a/include/driver.h b/include/driver.h index 018bbac..1b92759 100644 --- a/include/driver.h +++ b/include/driver.h @@ -37,7 +37,11 @@ struct driver_d *driver; /* The driver for this device */ - struct list_head list; + struct list_head list; /* The list of all devices */ + struct list_head children; /* our children */ + struct list_head sibling; + + struct device_d *parent; /* our parent, NULL if not present */ unsigned long type; @@ -70,12 +74,30 @@ #define RW_SIZE(x) (x) #define RW_SIZE_MASK 0x7 -/* Register/unregister devices and drivers. Since we don't have modules - * we do not need a driver_unregister function. +/* Register devices and drivers. */ int register_driver(struct driver_d *); int register_device(struct device_d *); -void unregister_device(struct device_d *); + +/* Unregister a device. This function can fail, e.g. when the device + * has children. + */ +int unregister_device(struct device_d *); + +/* Organize devices in a tree. These functions do _not_ register or + * unregister a device. Only registered devices are allowed here. + */ +int dev_add_child(struct device_d *dev, struct device_d *child); + +/* Iterate over a devices children + */ +#define device_for_each_child(dev, child) \ + list_for_each_entry(child, &dev->children, sibling) + +/* Iterate over a devices children - Safe against removal version + */ +#define device_for_each_child_safe(dev, tmpdev, child) \ + list_for_each_entry_safe(child, tmpdev, &dev->children, sibling) /* Iterate through the devices of a given type. if last is NULL, the * first device of this type is returned. Put this pointer in as @@ -84,7 +106,7 @@ */ struct device_d *get_device_by_type(ulong type, struct device_d *last); struct device_d *get_device_by_id(const char *id); -struct device_d *get_first_device(void); +struct device_d *get_device_by_path(const char *path); /* Find a free device id from the given template. This is archieved by * appending a number to the template. Dynamically created devices should @@ -92,13 +114,22 @@ */ int get_free_deviceid(char *id, char *id_template); -struct device_d *device_from_spec_str(const char *str, char **endp); char *deviceid_from_spec_str(const char *str, char **endp); +/* linear list over all available devices + */ extern struct list_head device_list; + +/* linear list over all available drivers + */ +extern struct list_head driver_list; + +/* Iterate over all devices + */ #define for_each_device(dev) list_for_each_entry(dev, &device_list, list) -extern struct list_head driver_list; +/* Iterate over all drivers + */ #define for_each_driver(drv) list_for_each_entry(drv, &driver_list, list) /* Find a driver with the given name. Currently the filesystem implementation diff --git a/include/fs.h b/include/fs.h index fcc04f4..b77279a 100644 --- a/include/fs.h +++ b/include/fs.h @@ -76,11 +76,20 @@ unsigned long flags; }; +struct mtab_entry { + char path[PATH_MAX]; + struct mtab_entry *next; + struct device_d *dev; + struct device_d *parent_device; +}; + struct fs_device_d { struct device_d *parent; /* the device we are associated with */ struct device_d dev; /* our own device */ struct fs_driver_d *driver; + + struct mtab_entry mtab; }; /* @@ -136,13 +145,7 @@ */ struct mtab_entry *get_mtab_entry_by_path(const char *path); struct mtab_entry *mtab_next_entry(struct mtab_entry *entry); - -struct mtab_entry { - char path[PATH_MAX]; - struct mtab_entry *next; - struct device_d *dev; - struct device_d *parent_device; -}; +const char *fsdev_get_mountpoint(struct fs_device_d *fsdev); /* * Read a file into memory. Memory is allocated with malloc and must diff --git a/include/partition.h b/include/partition.h index 151235c..08504dd 100644 --- a/include/partition.h +++ b/include/partition.h @@ -3,10 +3,13 @@ struct device_d; +#define PARTITION_FIXED (1 << 0) +#define PARTITION_READONLY (1 << 1) + struct partition { int num; - int readonly; + int flags; unsigned long offset; @@ -17,7 +20,7 @@ }; struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset, - size_t size, char *name); + size_t size, int flags, const char *name); /* FIXME: counterpart missing */ #endif /* __PARTITION_H */ diff --git a/lib/driver.c b/lib/driver.c index 1d1e59b..27b6075 100644 --- a/lib/driver.c +++ b/lib/driver.c @@ -86,6 +86,7 @@ debug ("register_device: %s\n",new_device->name); list_add_tail(&new_device->list, &device_list); + INIT_LIST_HEAD(&new_device->children); for_each_driver(drv) { if (!match(drv, new_device)) @@ -96,17 +97,37 @@ } EXPORT_SYMBOL(register_device); -void unregister_device(struct device_d *old_dev) +int unregister_device(struct device_d *old_dev) { debug("unregister_device: %s:%s\n",old_dev->name, old_dev->id); + if (!list_empty(&old_dev->children)) { + errno = -EBUSY; + return errno; + } + if (old_dev->driver) old_dev->driver->remove(old_dev); list_del(&old_dev->list); + + /* remove device from parents child list */ + if (old_dev->parent) + list_del(&old_dev->sibling); + + return 0; } EXPORT_SYMBOL(unregister_device); +int dev_add_child(struct device_d *dev, struct device_d *child) +{ + child->parent = dev; + + list_add_tail(&child->sibling, &dev->children); + + return 0; +} + struct driver_d *get_driver_by_name(const char *name) { struct driver_d *drv; @@ -132,7 +153,7 @@ { struct device_d *dev = NULL; - debug("register_driver: %s\n",new_driver->name); + debug("register_driver: %s\n", drv->name); list_add_tail(&drv->list, &driver_list); @@ -148,51 +169,17 @@ } EXPORT_SYMBOL(register_driver); -static char devicename_from_spec_str_buf[PATH_MAX]; - -char *deviceid_from_spec_str(const char *str, char **endp) -{ - char *buf = devicename_from_spec_str_buf; - const char *end; - int i = 0; - - if (isdigit(*str)) { - /* No device name given, use default driver mem */ - sprintf(buf, "mem"); - end = str; - } else { - /* OK, we have a device name, parse it */ - while (*str) { - if (*str == ':') { - str++; - buf[i] = 0; - break; - } - - buf[i++] = *str++; - buf[i] = 0; - if (i == MAX_DRIVER_NAME) - return NULL; - } - end = str; - } - - if (endp) - *endp = (char *)end; - - return buf; -} - /* Get a device struct from the beginning of the string. Default to mem if no * device is given, return NULL if a unknown device is given. * If endp is not NULL, this function stores a pointer to the first character * after the device name in *endp. */ -struct device_d *device_from_spec_str(const char *str, char **endp) +struct device_d *get_device_by_path(const char *path) { - char *name; - name = deviceid_from_spec_str(str, endp); - return get_device_by_id(name); + if (strncmp(path, "/dev/", 5)) + return NULL; + + return get_device_by_id(path + 5); } ssize_t dev_read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags) @@ -254,6 +241,30 @@ return 0; } +static int do_devinfo_subtree(struct device_d *dev, int depth, char edge) +{ + struct device_d *child; + int i; + + for (i = 0; i < depth; i++) + printf("| "); + + if (*dev->id) + printf("%c----%s\n", edge, dev->id); + else if (dev->type == DEVICE_TYPE_FS) + printf("%c----filesystem: %s\n", edge, fsdev_get_mountpoint((struct fs_device_d *)dev->type_data)); + + if (!list_empty(&dev->children)) { + device_for_each_child(dev, child) { + do_dev_subtree(child, depth + 1, + list_is_last(&child->sibling, + &dev->children) ? '`' : '|'); + } + } + + return 0; +} + static int do_devinfo ( cmd_tbl_t *cmdtp, int argc, char *argv[]) { struct device_d *dev; @@ -264,23 +275,26 @@ printf("devices:\n"); for_each_device(dev) { - printf("%10s: base=0x%08x size=0x%08x (driver %s)\n", - dev->id, dev->map_base, dev->size, - dev->driver ? - dev->driver->name : "none"); + if (!dev->parent) + do_devinfo_subtree(dev, 0, '|'); } printf("\ndrivers:\n"); for_each_driver(drv) printf("%10s\n",drv->name); } else { - struct device_d *dev = get_device_by_id(argv[1]); + struct device_d *dev = get_device_by_path(argv[1]); if (!dev) { printf("no such device: %s\n",argv[1]); return -1; } + printf("base : 0x%08x\nsize : 0x%08x\ndriver: %s\n\n", + dev->map_base, dev->size, + dev->driver ? + dev->driver->name : "none"); + if (dev->driver) dev->driver->info(dev);