[PATCH 06/16] devfs: factor out core devfs functionality
Sascha Hauer
s.hauer at pengutronix.de
Fri Apr 8 10:36:52 EDT 2011
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 <s.hauer at pengutronix.de>
---
fs/Makefile | 1 +
fs/devfs-core.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/devfs.c | 167 +-------------------------------------
include/driver.h | 5 +
4 files changed, 244 insertions(+), 165 deletions(-)
create mode 100644 fs/devfs-core.c
diff --git a/fs/Makefile b/fs/Makefile
index 228af6e..4aa92ef 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 0000000..519e18e
--- /dev/null
+++ b/fs/devfs-core.c
@@ -0,0 +1,236 @@
+/*
+ * devfs.c - a device file system for barebox
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer at pengutronix.de>, 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 <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ioctl.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+
+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 f82fddd..07ca16c 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -36,34 +36,7 @@
#include <linux/mtd/mtd-abi.h>
#include <partition.h>
-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;
-}
-
diff --git a/include/driver.h b/include/driver.h
index 14ccc6d..6a4d45e 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -315,8 +315,13 @@ struct cdev {
int devfs_create(struct cdev *);
int devfs_remove(struct cdev *);
struct cdev *cdev_by_name(const char *filename);
+struct cdev *cdev_open(const char *name, unsigned long flags);
+void cdev_close(struct cdev *cdev);
+int cdev_flush(struct cdev *cdev);
ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags);
ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags);
+int cdev_ioctl(struct cdev *cdev, int cmd, void *buf);
+int cdev_erase(struct cdev *cdev, size_t count, unsigned long offset);
#define DEVFS_PARTITION_FIXED (1 << 0)
#define DEVFS_PARTITION_READONLY (1 << 1)
--
1.7.2.3
More information about the barebox
mailing list