From 30be97aff25f618f3925d1733a39996d50fc2213 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 4 Apr 2011 13:13:30 +0200 Subject: devfs: factor out core devfs functionality This makes it possible to compile without devfs. devfs_create/devfs_remove is used by drivers and thus must still be present even without devfs support. Also, this patch adds cdev_open/cdev_close/cdev_flush/cdev_ioctl calls to work with devices without using the file api. Signed-off-by: Sascha Hauer --- fs/Makefile | 1 + fs/devfs-core.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/devfs.c | 167 +-------------------------------------- 3 files changed, 239 insertions(+), 165 deletions(-) create mode 100644 fs/devfs-core.c (limited to 'fs') diff --git a/fs/Makefile b/fs/Makefile index 228af6eb2d..4aa92ef0d6 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_FS_CRAMFS) += cramfs/ obj-$(CONFIG_FS_RAMFS) += ramfs.o +obj-y += devfs-core.o obj-$(CONFIG_FS_DEVFS) += devfs.o obj-y += fs.o diff --git a/fs/devfs-core.c b/fs/devfs-core.c new file mode 100644 index 0000000000..519e18e6b7 --- /dev/null +++ b/fs/devfs-core.c @@ -0,0 +1,236 @@ +/* + * devfs.c - a device file system for barebox + * + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +LIST_HEAD(cdev_list); + +struct cdev *cdev_by_name(const char *filename) +{ + struct cdev *cdev; + + list_for_each_entry(cdev, &cdev_list, list) { + if (!strcmp(cdev->name, filename)) + return cdev; + } + return NULL; +} + +struct cdev *cdev_open(const char *name, unsigned long flags) +{ + struct cdev *cdev = cdev_by_name(name); + int ret; + + if (!cdev) + return NULL; + + if (cdev->ops->open) { + ret = cdev->ops->open(cdev); + if (ret) + return NULL; + } + + return cdev; +} + +void cdev_close(struct cdev *cdev) +{ + if (cdev->ops->close) + cdev->ops->close(cdev); +} + +ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags) +{ + if (!cdev->ops->read) + return -ENOSYS; + + return cdev->ops->read(cdev, buf, count, cdev->offset +offset, flags); +} + +ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags) +{ + if (!cdev->ops->write) + return -ENOSYS; + + return cdev->ops->write(cdev, buf, count, cdev->offset + offset, flags); +} + +int cdev_flush(struct cdev *cdev) +{ + if (!cdev->ops->flush) + return 0; + + return cdev->ops->flush(cdev); +} + +static int partition_ioctl(struct cdev *cdev, int request, void *buf) +{ + size_t offset; + struct mtd_info_user *user = buf; + + switch (request) { + case MEMSETBADBLOCK: + case MEMGETBADBLOCK: + offset = (off_t)buf; + offset += cdev->offset; + return cdev->ops->ioctl(cdev, request, (void *)offset); + case MEMGETINFO: + if (cdev->mtd) { + user->type = cdev->mtd->type; + user->flags = cdev->mtd->flags; + user->size = cdev->mtd->size; + user->erasesize = cdev->mtd->erasesize; + user->oobsize = cdev->mtd->oobsize; + user->mtd = cdev->mtd; + /* The below fields are obsolete */ + user->ecctype = -1; + user->eccsize = 0; + return 0; + } + if (!cdev->ops->ioctl) + return -EINVAL; + return cdev->ops->ioctl(cdev, request, buf); + default: + return -EINVAL; + } +} + +int cdev_ioctl(struct cdev *cdev, int request, void *buf) +{ + if (cdev->flags & DEVFS_IS_PARTITION) + return partition_ioctl(cdev, request, buf); + + if (!cdev->ops->ioctl) + return -EINVAL; + + return cdev->ops->ioctl(cdev, request, buf); +} + +int cdev_erase(struct cdev *cdev, size_t count, unsigned long offset) +{ + if (!cdev->ops->erase) + return -ENOSYS; + + return cdev->ops->erase(cdev, count, cdev->offset + offset); +} + +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); + if (new->dev) + list_add_tail(&new->devices_list, &new->dev->cdevs); + + return 0; +} + +int devfs_remove(struct cdev *cdev) +{ + if (cdev->open) + return -EBUSY; + + list_del(&cdev->list); + if (cdev->dev) + list_del(&cdev->devices_list); + + return 0; +} + +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; + +#ifdef CONFIG_PARTITION_NEED_MTD + if (cdev->mtd) { + new->mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name); + if (IS_ERR(new->mtd)) { + int ret = PTR_ERR(new->mtd); + free(new); + return ret; + } + } +#endif + + devfs_create(new); + + return 0; +} + +int devfs_del_partition(const char *name) +{ + struct cdev *cdev; + int ret; + + 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; + +#ifdef CONFIG_PARTITION_NEED_MTD + if (cdev->mtd) + mtd_del_partition(cdev->mtd); +#endif + + ret = devfs_remove(cdev); + if (ret) + return ret; + + free(cdev->name); + free(cdev); + + return 0; +} diff --git a/fs/devfs.c b/fs/devfs.c index f82fdddbc2..07ca16c553 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -36,34 +36,7 @@ #include #include -static LIST_HEAD(cdev_list); - -struct cdev *cdev_by_name(const char *filename) -{ - struct cdev *cdev; - - list_for_each_entry(cdev, &cdev_list, list) { - if (!strcmp(cdev->name, filename)) - return cdev; - } - return NULL; -} - -ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags) -{ - if (!cdev->ops->read) - return -ENOSYS; - - return cdev->ops->read(cdev, buf, count, cdev->offset +offset, flags); -} - -ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags) -{ - if (!cdev->ops->write) - return -ENOSYS; - - return cdev->ops->write(cdev, buf, count, cdev->offset + offset, flags); -} +extern struct list_head cdev_list; static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size) { @@ -179,49 +152,11 @@ static int devfs_flush(struct device_d *_dev, FILE *f) return 0; } -static int partition_ioctl(struct cdev *cdev, int request, void *buf) -{ - size_t offset; - struct mtd_info_user *user = buf; - - switch (request) { - case MEMSETBADBLOCK: - case MEMGETBADBLOCK: - offset = (off_t)buf; - offset += cdev->offset; - return cdev->ops->ioctl(cdev, request, (void *)offset); - case MEMGETINFO: - if (cdev->mtd) { - user->type = cdev->mtd->type; - user->flags = cdev->mtd->flags; - user->size = cdev->mtd->size; - user->erasesize = cdev->mtd->erasesize; - user->oobsize = cdev->mtd->oobsize; - user->mtd = cdev->mtd; - /* The below fields are obsolete */ - user->ecctype = -1; - user->eccsize = 0; - return 0; - } - if (!cdev->ops->ioctl) - return -EINVAL; - 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 cdev *cdev = f->inode; - if (cdev->flags & DEVFS_IS_PARTITION) - return partition_ioctl(cdev, request, buf); - - if (!cdev->ops->ioctl) - return -EINVAL; - - return cdev->ops->ioctl(cdev, request, buf); + return cdev_ioctl(cdev, request, buf); } static int devfs_truncate(struct device_d *dev, FILE *f, ulong size) @@ -322,101 +257,3 @@ static int devfs_init(void) } coredevice_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); - if (new->dev) - list_add_tail(&new->devices_list, &new->dev->cdevs); - - return 0; -} - -int devfs_remove(struct cdev *cdev) -{ - if (cdev->open) - return -EBUSY; - - list_del(&cdev->list); - if (cdev->dev) - list_del(&cdev->devices_list); - - return 0; -} - -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; - -#ifdef CONFIG_PARTITION_NEED_MTD - if (cdev->mtd) { - new->mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name); - if (IS_ERR(new->mtd)) { - int ret = PTR_ERR(new->mtd); - free(new); - return ret; - } - } -#endif - - devfs_create(new); - - return 0; -} - -int devfs_del_partition(const char *name) -{ - struct cdev *cdev; - int ret; - - 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; - -#ifdef CONFIG_PARTITION_NEED_MTD - if (cdev->mtd) - mtd_del_partition(cdev->mtd); -#endif - - ret = devfs_remove(cdev); - if (ret) - return ret; - - free(cdev->name); - free(cdev); - - return 0; -} - -- cgit v1.2.3