summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2009-04-22 23:39:27 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2009-07-21 16:41:44 +0200
commita2b7cd183bad9c9e0888ce62f5ae0f83c070cc2a (patch)
tree556535cae729eac244edff816476cab281c6be7b /fs
parent6411c3b2be40bb295520db2e9f6f891873a48b1a (diff)
downloadbarebox-a2b7cd183bad9c9e0888ce62f5ae0f83c070cc2a.tar.gz
barebox-a2b7cd183bad9c9e0888ce62f5ae0f83c070cc2a.tar.xz
introduce cdev
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/devfs.c230
-rw-r--r--fs/fs.c27
2 files changed, 199 insertions, 58 deletions
diff --git a/fs/devfs.c b/fs/devfs.c
index cd9bed2676..1fa9b5c593 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -29,27 +29,53 @@
#include <errno.h>
#include <xfuncs.h>
#include <linux/stat.h>
+#include <ioctl.h>
+#include <nand.h>
+#include <linux/mtd/mtd-abi.h>
+#include <partition.h>
-static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
+static LIST_HEAD(cdev_list);
+
+struct cdev *cdev_by_name(const char *filename)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev;
- return dev_read(dev, buf, size, f->pos, f->flags);
+ list_for_each_entry(cdev, &cdev_list, list) {
+ if (!strcmp(cdev->name, filename))
+ return cdev;
+ }
+ return NULL;
}
-static int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t size)
+int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev = f->inode;
+
+ if (!cdev->ops->read)
+ return -ENOSYS;
- return dev_write(dev, buf, size, f->pos, f->flags);
+ return cdev->ops->read(cdev, buf, size,
+ f->pos + cdev->offset, f->flags);
}
-static off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
+int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t size)
{
- struct device_d *dev = f->inode;
- off_t ret;
+ struct cdev *cdev = f->inode;
- ret = dev_lseek(dev, pos);
+ if (!cdev->ops->write)
+ return -ENOSYS;
+
+ return cdev->ops->write(cdev, buf, size,
+ f->pos + cdev->offset, f->flags);
+}
+
+off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
+{
+ struct cdev *cdev = f->inode;
+ off_t ret = -1;
+
+ if (cdev->ops->lseek)
+ ret = cdev->ops->lseek(cdev, pos + cdev->offset);
if (ret != -1)
f->pos = pos;
@@ -57,51 +83,100 @@ static off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
return ret;
}
-static int devfs_erase(struct device_d *_dev, FILE *f, size_t count, unsigned long offset)
+int devfs_erase(struct device_d *_dev, FILE *f, size_t count, unsigned long offset)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev = f->inode;
+
+ if (!cdev->ops->erase)
+ return -ENOSYS;
- return dev_erase(dev, count, offset);
+ return cdev->ops->erase(cdev, count, offset + cdev->offset);
}
-static int devfs_protect(struct device_d *_dev, FILE *f, size_t count, unsigned long offset, int prot)
+int devfs_protect(struct device_d *_dev, FILE *f, size_t count, unsigned long offset, int prot)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev = f->inode;
- return dev_protect(dev, count, offset, prot);
+ if (!cdev->ops->protect)
+ return -ENOSYS;
+
+ return cdev->ops->protect(cdev, count, offset + cdev->offset, prot);
}
static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev = f->inode;
+ int ret = -ENOSYS;
+
+ if (!cdev->ops->memmap)
+ return -EINVAL;
- return dev_memmap(dev, map, flags);
+ ret = cdev->ops->memmap(cdev, map, flags);
+
+ if (!ret)
+ *map = (void *)((unsigned long)*map + cdev->offset);
+
+ return ret;
}
static int devfs_open(struct device_d *_dev, FILE *f, const char *filename)
{
- struct device_d *dev = get_device_by_id(filename + 1);
+ struct cdev *cdev;
- if (!dev)
+ cdev = cdev_by_name(filename + 1);
+
+ if (!cdev)
return -ENOENT;
- f->size = dev->size;
- f->inode = dev;
- return dev_open(dev, f);
+ f->size = cdev->size;
+ f->inode = cdev;
+
+ if (cdev->ops->open)
+ return cdev->ops->open(cdev, f);
+
+ return 0;
}
static int devfs_close(struct device_d *_dev, FILE *f)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev = f->inode;
+
+ if (cdev->ops->close)
+ return cdev->ops->close(cdev, f);
+ return 0;
+}
- return dev_close(dev, f);
+static int partition_ioctl(struct cdev *cdev, int request, void *buf)
+{
+ size_t offset;
+
+ switch (request) {
+ case MEMSETBADBLOCK:
+ case MEMGETBADBLOCK:
+ offset = (off_t)buf;
+ offset += cdev->offset;
+ return cdev->ops->ioctl(cdev, request, (void *)offset);
+ case MEMGETINFO:
+ return cdev->ops->ioctl(cdev, request, buf);
+ default:
+ return -EINVAL;
+ }
}
static int devfs_ioctl(struct device_d *_dev, FILE *f, int request, void *buf)
{
- struct device_d *dev = f->inode;
+ struct cdev *cdev = f->inode;
+ int ret = -EINVAL;
- return dev_ioctl(dev, request, buf);
+ if (!cdev->ops->ioctl)
+ goto out;
+
+ if (cdev->flags & DEVFS_IS_PARTITION)
+ ret = partition_ioctl(cdev, request, buf);
+ else
+ ret = cdev->ops->ioctl(cdev, request, buf);
+out:
+ return ret;
}
static int devfs_truncate(struct device_d *dev, FILE *f, ulong size)
@@ -117,26 +192,22 @@ static DIR* devfs_opendir(struct device_d *dev, const char *pathname)
dir = xzalloc(sizeof(DIR));
- if (!list_empty(&device_list))
- dir->priv = list_first_entry(&device_list, struct device_d, list);
+ if (!list_empty(&cdev_list))
+ dir->priv = list_first_entry(&cdev_list, struct cdev, list);
return dir;
}
static struct dirent* devfs_readdir(struct device_d *_dev, DIR *dir)
{
- struct device_d *dev = dir->priv;
+ struct cdev *cdev = dir->priv;
- if (!dev)
+ if (!cdev)
return NULL;
- list_for_each_entry_from(dev, &device_list, list) {
- if (!*dev->id)
- continue;
- if (!dev->driver)
- continue;
- strcpy(dir->d.d_name, dev->id);
- dir->priv = list_entry(dev->list.next, struct device_d, list);
+ list_for_each_entry_from(cdev, &cdev_list, list) {
+ strcpy(dir->d.d_name, cdev->name);
+ dir->priv = list_entry(cdev->list.next, struct cdev, list);
return &dir->d;
}
return NULL;
@@ -150,20 +221,17 @@ static int devfs_closedir(struct device_d *dev, DIR *dir)
static int devfs_stat(struct device_d *_dev, const char *filename, struct stat *s)
{
- struct device_d *dev;
+ struct cdev *cdev;
- dev = get_device_by_id(filename + 1);
- if (!dev)
+ cdev = cdev_by_name(filename + 1);
+ if (!cdev)
return -ENOENT;
- if (!dev->driver)
- return -ENXIO;
-
s->st_mode = S_IFCHR;
- s->st_size = dev->size;
- if (dev->driver->write)
+ s->st_size = cdev->size;
+ if (cdev->ops->write)
s->st_mode |= S_IWUSR;
- if (dev->driver->read)
+ if (cdev->ops->read)
s->st_mode |= S_IRUSR;
return 0;
@@ -206,3 +274,71 @@ static int devfs_init(void)
device_initcall(devfs_init);
+int devfs_create(struct cdev *new)
+{
+ struct cdev *cdev;
+
+ cdev = cdev_by_name(new->name);
+ if (cdev)
+ return -EEXIST;
+
+ list_add_tail(&new->list, &cdev_list);
+
+ return 0;
+}
+
+void devfs_remove(struct cdev *cdev)
+{
+ list_del(&cdev->list);
+}
+
+int devfs_add_partition(const char *devname, unsigned long offset, size_t size,
+ int flags, const char *name)
+{
+ struct cdev *cdev, *new;
+
+ cdev = cdev_by_name(name);
+ if (cdev)
+ return -EEXIST;
+
+ cdev = cdev_by_name(devname);
+ if (!cdev)
+ return -ENOENT;
+
+ if (offset + size > cdev->size)
+ return -EINVAL;
+
+ new = xzalloc(sizeof (*new));
+ new->name = strdup(name);
+ new->ops = cdev->ops;
+ new->priv = cdev->priv;
+ new->size = size;
+ new->offset = offset + cdev->offset;
+ new->dev = cdev->dev;
+ new->flags = flags | DEVFS_IS_PARTITION;
+
+ list_add_tail(&new->list, &cdev_list);
+
+ return 0;
+}
+
+int devfs_del_partition(const char *name)
+{
+ struct cdev *cdev;
+
+ cdev = cdev_by_name(name);
+ if (!cdev)
+ return -ENOENT;
+
+ if (!(cdev->flags & DEVFS_IS_PARTITION))
+ return -EINVAL;
+ if (cdev->flags & DEVFS_PARTITION_FIXED)
+ return -EPERM;
+
+ devfs_remove(cdev);
+ free(cdev->name);
+ free(cdev);
+
+ return 0;
+}
+
diff --git a/fs/fs.c b/fs/fs.c
index bc4e9f2c1a..6f278c0e1f 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -943,29 +943,34 @@ static void memcpy_sz(void *_dst, const void *_src, ulong count, ulong rwsize)
}
}
-ssize_t mem_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags)
+ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags)
{
ulong size;
- size = min(count, dev->size - offset);
+ struct device_d *dev;
+
+ if (!cdev->dev)
+ return -1;
+ dev = cdev->dev;
+
+ size = min((ulong)count, dev->size - offset);
debug("mem_read: dev->map_base: %p size: %d offset: %d\n",dev->map_base, size, offset);
memcpy_sz(buf, (void *)(dev->map_base + offset), size, flags & O_RWSIZE_MASK);
return size;
}
EXPORT_SYMBOL(mem_read);
-ssize_t mem_write(struct device_d *dev, const void *buf, size_t count, ulong offset, ulong flags)
+ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags)
{
ulong size;
- size = min(count, dev->size - offset);
+ struct device_d *dev;
+
+ if (!cdev->dev)
+ return -1;
+ dev = cdev->dev;
+
+ size = min((ulong)count, dev->size - offset);
memcpy_sz((void *)(dev->map_base + offset), buf, size, flags & O_RWSIZE_MASK);
return size;
}
EXPORT_SYMBOL(mem_write);
-int mem_memmap(struct device_d *dev, void **map, int flags)
-{
- *map = (void *)dev->map_base;
- return 0;
-}
-EXPORT_SYMBOL(mem_memmap);
-