9
0
Fork 0

- Implement tree structure for devices

- Use device tree structure to implement partitions
- Let devinfo print a nice tree
- Introduce 'fixed' partitions which are not removable
- Fix mount: It was not possible to mount on a relative path.
This commit is contained in:
sascha 2007-10-19 08:45:57 +02:00
parent 98839f8010
commit 3b6d6a45e7
13 changed files with 204 additions and 112 deletions

View File

@ -42,8 +42,8 @@ static int ipe337_devices_init(void) {
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;

View File

@ -75,11 +75,11 @@ static int netx_devices_init(void) {
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;
}

View File

@ -113,8 +113,8 @@ static int imx31_devices_init(void)
* 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);

View File

@ -90,8 +90,8 @@ static int devices_init (void)
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;
}

View File

@ -87,8 +87,8 @@ static int pcm038_devices_init(void)
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;

View File

@ -91,8 +91,8 @@ static int scb9328_devices_init(void) {
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;

View File

@ -29,25 +29,29 @@
#include <errno.h>
#include <xfuncs.h>
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 @@ static int mtd_part_do_parse_one(struct partition *part, const char *str,
str = end;
if (*str == 'r' && *(str + 1) == 'o') {
part->readonly = 1;
part->flags |= PARTITION_READONLY;
end = (char *)(str + 2);
}
@ -113,12 +117,12 @@ static int do_addpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
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 @@ static int do_addpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
offset = 0;
endp = argv[2];
while (1) {
part = xzalloc(sizeof(struct partition));
@ -138,28 +144,37 @@ static int do_addpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
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 @@ static __maybe_unused char cmd_addpart_help[] =
"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 @@ static int do_delpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
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;

View File

@ -7,7 +7,8 @@
#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 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 @@ struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset, s
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 @@ static ssize_t part_write(struct device_d *dev, const void *buf, size_t count, u
{
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);

39
fs/fs.c
View File

@ -202,6 +202,11 @@ struct mtab_entry *mtab_next_entry(struct mtab_entry *e)
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 @@ void put_file(FILE *f)
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 @@ int unlink(const char *pathname)
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 @@ int open(const char *pathname, int flags, ...)
goto out1;
}
dev = get_device_by_path(&path);
dev = get_fs_device_by_path(&path);
if (!dev)
goto out;
@ -599,7 +604,7 @@ EXPORT_SYMBOL(close);
* 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 @@ int mount(const char *device, const char *fsname, const char *path)
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 @@ int mount(const char *device, const char *fsname, const char *path)
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 @@ int mount(const char *device, const char *fsname, const char *path)
e->next = entry;
}
out:
free(path);
return errno;
}
EXPORT_SYMBOL(mount);
@ -710,7 +731,7 @@ int umount(const char *pathname)
unregister_device(entry->dev);
free(entry->dev->type_data);
free(entry);
return 0;
}
EXPORT_SYMBOL(umount);
@ -726,7 +747,7 @@ DIR *opendir(const char *pathname)
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 @@ int mkdir (const char *pathname, mode_t mode)
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 @@ int rmdir (const char *pathname)
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;

View File

@ -37,7 +37,11 @@ struct device_d {
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 @@ struct driver_d {
#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 @@ void unregister_device(struct device_d *);
*/
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 @@ struct device_d *get_first_device(void);
*/
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

View File

@ -76,11 +76,20 @@ struct fs_driver_d {
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 @@ char *mkmodestr(unsigned long mode, char *str);
*/
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

View File

@ -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 partition {
};
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 */

View File

@ -86,6 +86,7 @@ int register_device(struct device_d *new_device)
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 @@ int register_device(struct device_d *new_device)
}
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 @@ int register_driver(struct driver_d *drv)
{
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 @@ int register_driver(struct driver_d *drv)
}
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 @@ int dummy_probe(struct device_d *dev)
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 @@ static int do_devinfo ( cmd_tbl_t *cmdtp, int argc, char *argv[])
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);