[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH v4 1/5] lib/devfs: Initial import from OSv



From: Vlad-Andrei BĂDOIU (78692) <vlad_andrei.badoiu@xxxxxxxxxxxxxxx>

commit: c8395118cb580f2395cac6c53999feb217fd2c2f
Signed-off-by: Vlad-Andrei Badoiu <vlad_andrei.badoiu@xxxxxxxxxxxxxxx>
Reviewed-by: Yuri Volchkov <yuri.volchkov@xxxxxxxxx>
---
 lib/devfs/devfs.h                |  37 +++
 lib/devfs/devfs_vnops.c          | 284 ++++++++++++++++
 lib/devfs/device.c               | 537 +++++++++++++++++++++++++++++++
 lib/devfs/include/devfs/device.h | 213 ++++++++++++
 4 files changed, 1071 insertions(+)
 create mode 100644 lib/devfs/devfs.h
 create mode 100644 lib/devfs/devfs_vnops.c
 create mode 100644 lib/devfs/device.c
 create mode 100644 lib/devfs/include/devfs/device.h

diff --git a/lib/devfs/devfs.h b/lib/devfs/devfs.h
new file mode 100644
index 00000000..bdf50609
--- /dev/null
+++ b/lib/devfs/devfs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007, Kohsuke Ohtani
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEVFS_H
+#define _DEVFS_H
+
+#include <assert.h>
+
+/* #define DEBUG_DEVFS 1 */
+
+#endif /* !_DEVFS_H */
diff --git a/lib/devfs/devfs_vnops.c b/lib/devfs/devfs_vnops.c
new file mode 100644
index 00000000..1e69e4a6
--- /dev/null
+++ b/lib/devfs/devfs_vnops.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2005-2007, Kohsuke Ohtani
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * devfs - device file system.
+ */
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <osv/prex.h>
+#include <osv/device.h>
+#include <osv/vnode.h>
+#include <osv/mount.h>
+#include <osv/dentry.h>
+
+#include "devfs.h"
+
+#ifdef DEBUG_DEVFS
+#define DPRINTF(a)     dprintf a
+#else
+#define DPRINTF(a)     do {} while (0)
+#endif
+
+#define ASSERT(e)      assert(e)
+
+static uint64_t inode_count = 1; /* inode 0 is reserved to root */
+
+static int
+devfs_open(struct file *fp)
+{
+       struct vnode *vp = fp->f_dentry->d_vnode;
+       char *path = fp->f_dentry->d_path;
+       struct device *dev;
+       int error;
+
+       DPRINTF(("devfs_open: path=%s\n", path));
+
+       if (!strcmp(path, "/")) /* root ? */
+               return 0;
+
+       if (vp->v_flags & VPROTDEV) {
+               DPRINTF(("devfs_open: failed to open protected device.\n"));
+               return EPERM;
+       }
+       if (*path == '/')
+               path++;
+       error = device_open(path, fp->f_flags & DO_RWMASK, &dev);
+       if (error) {
+               DPRINTF(("devfs_open: can not open device = %s error=%d\n",
+                        path, error));
+               return error;
+       }
+       vp->v_data = (void *)dev;       /* Store private data */
+       return 0;
+}
+
+static int
+devfs_close(struct vnode *vp, struct file *fp)
+{
+
+       DPRINTF(("devfs_close: fp=%x\n", fp));
+
+       if (!strcmp(fp->f_dentry->d_path, "/")) /* root ? */
+               return 0;
+
+       return device_close((device*)vp->v_data);
+}
+
+static int
+devfs_read(struct vnode *vp, struct file *fp, struct uio *uio, int ioflags)
+{
+       return device_read((device*)vp->v_data, uio, ioflags);
+}
+
+static int
+devfs_write(struct vnode *vp, struct uio *uio, int ioflags)
+{
+       return device_write((device*)vp->v_data, uio, ioflags);
+}
+
+static int
+devfs_ioctl(struct vnode *vp, struct file *fp, u_long cmd, void *arg)
+{
+       int error;
+
+       error = device_ioctl((device*)vp->v_data, cmd, arg);
+       DPRINTF(("devfs_ioctl: cmd=%x\n", cmd));
+       return error;
+}
+
+static int
+devfs_lookup(struct vnode *dvp, char *name, struct vnode **vpp)
+{
+       struct devinfo info;
+       struct vnode *vp;
+       int error, i;
+
+       DPRINTF(("devfs_lookup:%s\n", name));
+
+       *vpp = NULL;
+
+       if (*name == '\0')
+               return ENOENT;
+
+       i = 0;
+       error = 0;
+       info.cookie = 0;
+       for (;;) {
+               error = device_info(&info);
+               if (error) {
+                       return ENOENT;
+               }
+               if (!strncmp(info.name, name, MAXDEVNAME))
+                       break;
+               i++;
+       }
+       if (vget(dvp->v_mount, inode_count++, &vp)) {
+               /* found in cache */
+               *vpp = vp;
+               return 0;
+       }
+       if (!vp)
+               return ENOMEM;
+       vp->v_type = (info.flags & D_CHR) ? VCHR : VBLK;
+       if (info.flags & D_TTY)
+               vp->v_flags |= VISTTY;
+
+       vp->v_mode = (mode_t)(S_IRUSR | S_IWUSR);
+
+       *vpp = vp;
+
+       return 0;
+}
+
+/*
+ * @vp: vnode of the directory.
+ */
+static int
+devfs_readdir(struct vnode *vp, struct file *fp, struct dirent *dir)
+{
+       struct devinfo info;
+       int error, i;
+
+       DPRINTF(("devfs_readdir offset=%d\n", fp->f_offset));
+
+       i = 0;
+       error = 0;
+       info.cookie = 0;
+       do {
+               error = device_info(&info);
+               if (error)
+                       return ENOENT;
+       } while (i++ != fp->f_offset);
+
+       dir->d_type = 0;
+       if (info.flags & D_CHR)
+               dir->d_type = DT_CHR;
+       else if (info.flags & D_BLK)
+               dir->d_type = DT_BLK;
+       strlcpy((char *)&dir->d_name, info.name, sizeof(dir->d_name));
+       dir->d_fileno = fp->f_offset;
+//     dir->d_namlen = strlen(dir->d_name);
+
+       DPRINTF(("devfs_readdir: %s\n", dir->d_name));
+       fp->f_offset++;
+       return 0;
+}
+
+static int
+devfs_unmount(struct mount *mp, int flags)
+{
+       release_mp_dentries(mp);
+       return 0;
+}
+
+int
+devfs_init(void)
+{
+       return 0;
+}
+
+static int
+devfs_getattr(struct vnode *vnode, struct vattr *attr)
+{
+       attr->va_nodeid = vnode->v_ino;
+       attr->va_size = vnode->v_size;
+       return 0;
+}
+
+#define devfs_mount    ((vfsop_mount_t)vfs_nullop)
+#define devfs_sync     ((vfsop_sync_t)vfs_nullop)
+#define devfs_vget     ((vfsop_vget_t)vfs_nullop)
+#define devfs_statfs   ((vfsop_statfs_t)vfs_nullop)
+
+#define devfs_seek     ((vnop_seek_t)vop_nullop)
+#define devfs_fsync    ((vnop_fsync_t)vop_nullop)
+#define devfs_create   ((vnop_create_t)vop_einval)
+#define devfs_remove   ((vnop_remove_t)vop_einval)
+#define devfs_rename   ((vnop_rename_t)vop_einval)
+#define devfs_mkdir    ((vnop_mkdir_t)vop_einval)
+#define devfs_rmdir    ((vnop_rmdir_t)vop_einval)
+#define devfs_setattr  ((vnop_setattr_t)vop_eperm)
+#define devfs_inactive ((vnop_inactive_t)vop_nullop)
+#define devfs_truncate ((vnop_truncate_t)vop_nullop)
+#define devfs_link     ((vnop_link_t)vop_eperm)
+#define devfs_fallocate ((vnop_fallocate_t)vop_nullop)
+#define devfs_readlink ((vnop_readlink_t)vop_nullop)
+#define devfs_symlink  ((vnop_symlink_t)vop_nullop)
+
+/*
+ * vnode operations
+ */
+struct vnops devfs_vnops = {
+       devfs_open,             /* open */
+       devfs_close,            /* close */
+       devfs_read,             /* read */
+       devfs_write,            /* write */
+       devfs_seek,             /* seek */
+       devfs_ioctl,            /* ioctl */
+       devfs_fsync,            /* fsync */
+       devfs_readdir,          /* readdir */
+       devfs_lookup,           /* lookup */
+       devfs_create,           /* create */
+       devfs_remove,           /* remove */
+       devfs_rename,           /* remame */
+       devfs_mkdir,            /* mkdir */
+       devfs_rmdir,            /* rmdir */
+       devfs_getattr,          /* getattr */
+       devfs_setattr,          /* setattr */
+       devfs_inactive,         /* inactive */
+       devfs_truncate,         /* truncate */
+       devfs_link,             /* link */
+       (vnop_cache_t) nullptr, /* arc */
+       devfs_fallocate,        /* fallocate */
+       devfs_readlink,         /* read link */
+       devfs_symlink,          /* symbolic link */
+};
+
+/*
+ * File system operations
+ */
+struct vfsops devfs_vfsops = {
+       devfs_mount,            /* mount */
+       devfs_unmount,          /* unmount */
+       devfs_sync,             /* sync */
+       devfs_vget,             /* vget */
+       devfs_statfs,           /* statfs */
+       &devfs_vnops,           /* vnops */
+};
diff --git a/lib/devfs/device.c b/lib/devfs/device.c
new file mode 100644
index 00000000..a0cd9768
--- /dev/null
+++ b/lib/devfs/device.c
@@ -0,0 +1,537 @@
+/*-
+ * Copyright (c) 2005-2009, Kohsuke Ohtani
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * device.c - device I/O support routines
+ */
+
+/**
+ * The device_* system calls are interfaces to access the specific
+ * device object which is handled by the related device driver.
+ *
+ * The routines in this moduile have the following role:
+ *  - Manage the name space for device objects.
+ *  - Forward user I/O requests to the drivers with minimum check.
+ *  - Provide the table for the Driver-Kernel Interface.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+
+#include <osv/prex.h>
+#include <osv/mutex.h>
+#include <osv/device.h>
+#include <osv/debug.h>
+#include <osv/buf.h>
+
+#include <geom/geom_disk.h>
+
+mutex sched_mutex;
+#define sched_lock()   sched_mutex.lock()
+#define sched_unlock() sched_mutex.unlock()
+
+
+/* list head of the devices */
+static struct device *device_list = NULL;
+
+/*
+ * Look up a device object by device name.
+ */
+static struct device *
+device_lookup(const char *name)
+{
+       struct device *dev;
+
+       for (dev = device_list; dev != NULL; dev = dev->next) {
+               if (!strncmp(dev->name, name, MAXDEVNAME))
+                       return dev;
+       }
+       return NULL;
+}
+
+struct partition_table_entry {
+       uint8_t  bootable;
+       uint8_t  starting_head;
+       uint16_t starting_sector:6;
+       uint16_t starting_cylinder:10;
+       uint8_t  system_id;
+       uint8_t  ending_head;
+       uint16_t ending_sector:6;
+       uint16_t ending_cylinder:10;
+       uint32_t rela_sector;
+       uint32_t total_sectors;
+} __attribute__((packed));
+
+/*
+ * read_partition_table - given a device @dev, create one subdevice per 
partition
+ * found in that device.
+ *
+ * This function will read a partition table from the canonical location of the
+ * device pointed by @dev. For each partition found, a new device will be
+ * created. The newly created device will have most of its data copied from
+ * @dev, except for its name, offset and size.
+ */
+void read_partition_table(struct device *dev)
+{
+       struct buf *bp;
+       unsigned long offset;
+       int index;
+
+       if (bread(dev, 0, &bp) != 0) {
+               debugf("read_partition_table failed for %s\n", dev->name);
+               return;
+       }
+
+       sched_lock();
+       // A real partition table (MBR) ends in the two bytes 0x55, 0xAA (see
+       // arch/x64/boot16.S on where we put those on the OSv image). If we
+       // don't find those, this is an unpartitioned disk.
+       if (((unsigned char*)bp->b_data)[510] == 0x55 &&
+           ((unsigned char*)bp->b_data)[511] == 0xAA)
+       for (offset = 0x1be, index = 0; offset < 0x1fe; offset += 0x10, 
index++) {
+               char dev_name[MAXDEVNAME];
+               struct device *new_dev;
+
+               auto* entry = static_cast<struct 
partition_table_entry*>(bp->b_data + offset);
+
+               if (entry->system_id == 0) {
+                       continue;
+               }
+
+               if (entry->starting_sector == 0) {
+                       continue;
+               }
+
+               snprintf(dev_name, MAXDEVNAME, "%s.%d", dev->name, index);
+               new_dev = device_create(dev->driver, dev_name, dev->flags);
+               free(new_dev->private_data);
+
+               new_dev->offset = (off_t)entry->rela_sector << 9;
+               new_dev->size = (off_t)entry->total_sectors << 9;
+               new_dev->max_io_size = dev->max_io_size;
+               new_dev->private_data = dev->private_data;
+               device_set_softc(new_dev, device_get_softc(dev));
+       }
+
+       sched_unlock();
+       brelse(bp);
+}
+
+void device_register(struct device *dev, const char *name, int flags)
+{
+       size_t len;
+       void *priv = NULL;
+
+       assert(dev->driver != NULL);
+
+       /* Check the length of name. */
+       len = strnlen(name, MAXDEVNAME);
+       if (len == 0 || len >= MAXDEVNAME)
+               return;
+
+       sched_lock();
+
+       /* Check if specified name is already used. */
+       if (device_lookup(name) != NULL)
+               sys_panic("duplicate device");
+
+       /*
+        * Allocate a device and device private data.
+        */
+       if (dev->driver->devsz != 0) {
+               if ((priv = malloc(dev->driver->devsz)) == NULL)
+                       sys_panic("devsz");
+               memset(priv, 0, dev->driver->devsz);
+       }
+
+       strlcpy(dev->name, name, len + 1);
+       dev->flags = flags;
+       dev->active = 1;
+       dev->refcnt = 1;
+       dev->offset = 0;
+       dev->private_data = priv;
+       dev->next = device_list;
+       dev->max_io_size = UINT_MAX;
+       device_list = dev;
+
+       sched_unlock();
+}
+
+
+/*
+ * device_create - create new device object.
+ *
+ * A device object is created by the device driver to provide
+ * I/O services to applications.  Returns device ID on
+ * success, or 0 on failure.
+ */
+struct device *
+device_create(struct driver *drv, const char *name, int flags)
+{
+       struct device *dev;
+       size_t len;
+
+       assert(drv != NULL);
+
+       /* Check the length of name. */
+       len = strnlen(name, MAXDEVNAME);
+       if (len == 0 || len >= MAXDEVNAME)
+               return NULL;
+
+       /*
+        * Allocate a device structure.
+        */
+       if ((dev = new device) == NULL)
+               sys_panic("device_create");
+
+    dev->driver = drv;
+    device_register(dev, name, flags);
+       return dev;
+}
+
+#if 0
+/*
+ * Return device's private data.
+ */
+static void *
+device_private(struct device *dev)
+{
+       assert(dev != NULL);
+       assert(dev->private_data != NULL);
+
+       return dev->private_data;
+}
+#endif
+
+/*
+ * Return true if specified device is valid.
+ */
+static int
+device_valid(struct device *dev)
+{
+       struct device *tmp;
+       int found = 0;
+
+       for (tmp = device_list; tmp != NULL; tmp = tmp->next) {
+               if (tmp == dev) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (found && dev->active)
+               return 1;
+       return 0;
+}
+
+/*
+ * Increment the reference count on an active device.
+ */
+static int
+device_reference(struct device *dev)
+{
+
+       sched_lock();
+       if (!device_valid(dev)) {
+               sched_unlock();
+               return ENODEV;
+       }
+       dev->refcnt++;
+       sched_unlock();
+       return 0;
+}
+
+/*
+ * Decrement the reference count on a device. If the reference
+ * count becomes zero, we can release the resource for the device.
+ */
+static void
+device_release(struct device *dev)
+{
+       struct device **tmp;
+
+       sched_lock();
+       if (--dev->refcnt > 0) {
+               sched_unlock();
+               return;
+       }
+       /*
+        * No more references - we can remove the device.
+        */
+       for (tmp = &device_list; *tmp; tmp = &(*tmp)->next) {
+               if (*tmp == dev) {
+                       *tmp = dev->next;
+                       break;
+               }
+       }
+       delete dev;
+       sched_unlock();
+}
+
+int
+device_destroy(struct device *dev)
+{
+
+       sched_lock();
+       if (!device_valid(dev)) {
+               sched_unlock();
+               return ENODEV;
+       }
+       dev->active = 0;
+       device_release(dev);
+       sched_unlock();
+       return 0;
+}
+
+/*
+ * device_open - open the specified device.
+ *
+ * Even if the target driver does not have an open
+ * routine, this function does not return an error. By
+ * using this mechanism, an application can check whether
+ * the specific device exists or not. The open mode
+ * should be handled by an each device driver if it is
+ * needed.
+ */
+int
+device_open(const char *name, int mode, struct device **devp)
+{
+       struct devops *ops;
+       struct device *dev;
+       int error;
+
+       sched_lock();
+       if ((dev = device_lookup(name)) == NULL) {
+               sched_unlock();
+               return ENXIO;
+       }
+       error = device_reference(dev);
+       if (error) {
+               sched_unlock();
+               return error;
+       }
+       sched_unlock();
+
+       ops = dev->driver->devops;
+       assert(ops->open != NULL);
+       error = (*ops->open)(dev, mode);
+       *devp = dev;
+
+       device_release(dev);
+       return error;
+}
+
+/*
+ * device_close - close a device.
+ *
+ * Even if the target driver does not have close routine,
+ * this function does not return any errors.
+ */
+int
+device_close(struct device *dev)
+{
+       struct devops *ops;
+       int error;
+
+       if ((error = device_reference(dev)) != 0)
+               return error;
+
+       ops = dev->driver->devops;
+       assert(ops->close != NULL);
+       error = (*ops->close)(dev);
+
+       device_release(dev);
+       return error;
+}
+
+int
+device_read(struct device *dev, struct uio *uio, int ioflags)
+{
+       struct devops *ops;
+       int error;
+
+       if ((error = device_reference(dev)) != 0)
+               return error;
+
+       ops = dev->driver->devops;
+       assert(ops->read != NULL);
+       error = (*ops->read)(dev, uio, ioflags);
+
+       device_release(dev);
+       return error;
+}
+
+int
+device_write(struct device *dev, struct uio *uio, int ioflags)
+{
+       struct devops *ops;
+       int error;
+
+       if ((error = device_reference(dev)) != 0)
+               return error;
+
+       ops = dev->driver->devops;
+       assert(ops->write != NULL);
+       error = (*ops->write)(dev, uio, ioflags);
+
+       device_release(dev);
+       return error;
+}
+
+/*
+ * device_ioctl - I/O control request.
+ *
+ * A command and its argument are completely device dependent.
+ * The ioctl routine of each driver must validate the user buffer
+ * pointed by the arg value.
+ */
+int
+device_ioctl(struct device *dev, u_long cmd, void *arg)
+{
+       struct devops *ops;
+       int error;
+
+       if ((error = device_reference(dev)) != 0)
+               return error;
+
+       ops = dev->driver->devops;
+       assert(ops->ioctl != NULL);
+       error = (*ops->ioctl)(dev, cmd, arg);
+
+       device_release(dev);
+       return error;
+}
+
+#if 0
+/*
+ * Device control - devctl is similar to ioctl, but is invoked from
+ * other device driver rather than from user application.
+ */
+static int
+device_control(struct device *dev, u_long cmd, void *arg)
+{
+       struct devops *ops;
+       int error;
+
+       assert(dev != NULL);
+
+       sched_lock();
+       ops = dev->driver->devops;
+       assert(ops->devctl != NULL);
+       error = (*ops->devctl)(dev, cmd, arg);
+       sched_unlock();
+       return error;
+}
+
+/*
+ * device_broadcast - broadcast devctl command to all device objects.
+ *
+ * If "force" argument is true, we will continue command
+ * notification even if some driver returns an error. In this
+ * case, this routine returns EIO error if at least one driver
+ * returns an error.
+ *
+ * If force argument is false, a kernel stops the command processing
+ * when at least one driver returns an error. In this case,
+ * device_broadcast will return the error code which is returned
+ * by the driver.
+ */
+static int
+device_broadcast(u_long cmd, void *arg, int force)
+{
+       struct device *dev;
+       struct devops *ops;
+       int error, retval = 0;
+
+       sched_lock();
+
+       for (dev = device_list; dev != NULL; dev = dev->next) {
+               /*
+                * Call driver's devctl() routine.
+                */
+               ops = dev->driver->devops;
+               if (ops == NULL)
+                       continue;
+
+               assert(ops->devctl != NULL);
+               error = (*ops->devctl)(dev, cmd, arg);
+               if (error) {
+                       if (force)
+                               retval = EIO;
+                       else {
+                               retval = error;
+                               break;
+                       }
+               }
+       }
+       sched_unlock();
+       return retval;
+}
+#endif
+
+/*
+ * Return device information.
+ */
+int
+device_info(struct devinfo *info)
+{
+       u_long target = info->cookie;
+       u_long i = 0;
+       struct device *dev;
+       int error = ESRCH;
+
+       sched_lock();
+       for (dev = device_list; dev != NULL; dev = dev->next) {
+               if (i++ == target) {
+                       info->cookie = i;
+                       info->id = dev;
+                       info->flags = dev->flags;
+                       strlcpy(info->name, dev->name, MAXDEVNAME);
+                       error = 0;
+                       break;
+               }
+       }
+       sched_unlock();
+       return error;
+}
+
+int
+enodev(void)
+{
+       return ENODEV;
+}
+
+int
+nullop(void)
+{
+       return 0;
+}
diff --git a/lib/devfs/include/devfs/device.h b/lib/devfs/include/devfs/device.h
new file mode 100644
index 00000000..16d2e470
--- /dev/null
+++ b/lib/devfs/include/devfs/device.h
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 2005-2008, Kohsuke Ohtani
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEVICE_H
+#define _DEVICE_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <osv/uio.h>
+
+__BEGIN_DECLS
+
+#define MAXDEVNAME     12
+#define DO_RWMASK      0x3
+
+struct bio;
+struct device;
+
+/*
+ * Device information
+ */
+struct devinfo {
+       u_long          cookie;         /* index cookie */
+       struct device   *id;            /* device id */
+       int             flags;          /* device characteristics flags */
+       char            name[MAXDEVNAME]; /* device name */
+};
+
+/*
+ * Device flags
+ */
+#define D_CHR          0x00000001      /* character device */
+#define D_BLK          0x00000002      /* block device */
+#define D_REM          0x00000004      /* removable device */
+#define D_TTY          0x00000010      /* tty device */
+
+typedef int (*devop_open_t)   (struct device *, int);
+typedef int (*devop_close_t)  (struct device *);
+typedef int (*devop_read_t)   (struct device *, struct uio *, int);
+typedef int (*devop_write_t)  (struct device *, struct uio *, int);
+typedef int (*devop_ioctl_t)  (struct device *, u_long, void *);
+typedef int (*devop_devctl_t) (struct device *, u_long, void *);
+typedef void (*devop_strategy_t)(struct bio *);
+
+/*
+ * Device operations
+ */
+struct devops {
+       devop_open_t    open;
+       devop_close_t   close;
+       devop_read_t    read;
+       devop_write_t   write;
+       devop_ioctl_t   ioctl;
+       devop_devctl_t  devctl;
+       devop_strategy_t strategy;
+};
+
+
+#define        no_open         ((devop_open_t)nullop)
+#define        no_close        ((devop_close_t)nullop)
+#define        no_read         ((devop_read_t)enodev)
+#define        no_write        ((devop_write_t)enodev)
+#define        no_ioctl        ((devop_ioctl_t)enodev)
+#define        no_devctl       ((devop_devctl_t)nullop)
+
+/*
+ * Driver object
+ */
+struct driver {
+       const char      *name;          /* name of device driver */
+       struct devops   *devops;        /* device operations */
+       size_t          devsz;          /* size of private data */
+       int             flags;          /* state of driver */
+};
+
+/*
+ * flags for the driver.
+ */
+
+typedef enum device_state {
+    DS_INACTIVE            = 0x00,             /* driver is inactive */
+    DS_ALIVE       = 0x01,             /* probe succeded */
+    DS_ACTIVE      = 0x02,             /* intialized */
+    DS_DEBUG       = 0x04,             /* debug */
+    DS_NOTPRESENT   = 0x08,     /* not probed or probe failed */
+    DS_ATTACHING    = 0x10,     /* currently attaching */
+    DS_ATTACHED     = 0x20,     /*attach method called */
+} device_state_t;
+
+/*
+ * Device object
+ */
+struct device {
+       struct device   *next;          /* linkage on list of all devices */
+       struct driver   *driver;        /* pointer to the driver object */
+       char            name[MAXDEVNAME]; /* name of device */
+       int             flags;          /* D_* flags defined above */
+       int             active;         /* device has not been destroyed */
+       int             refcnt;         /* reference count */
+       off_t           size;           /* device size */
+       off_t           offset; /* 0 for the main drive, if we have a 
partition, this is the start address */
+       size_t          max_io_size;
+       void            *private_data;  /* private storage */
+
+       void *softc;
+       void *ivars;
+       device_state_t state;
+       const char *desc;
+       int unit;
+       int irq;
+       int vector;
+};
+
+typedef struct device *device_t;
+
+static inline int
+device_set_unit(device_t dev, int unit)
+{
+       dev->unit = unit;
+       return 0;
+}
+
+static inline int
+device_get_unit(device_t dev)
+{
+       return dev->unit;
+}
+
+static inline const char *
+device_get_desc(device_t dev)
+{
+       return dev->desc;
+}
+
+static inline void
+device_set_desc(device_t dev, const char* desc)
+{
+       dev->desc = desc;
+}
+
+static inline void
+device_set_softc(device_t dev, void* softc)
+{
+       dev->softc = softc;
+}
+
+static inline void *
+device_get_softc(device_t dev)
+{
+       return dev->softc;
+}
+
+static inline void device_quiet(device_t dev)
+{
+}
+
+static inline const char *
+devtoname(struct device *dev)
+{
+    return dev->name;
+}
+
+int     device_open(const char *, int, struct device **);
+int     device_close(struct device *);
+int     device_read(struct device *, struct uio *, int);
+int     device_write(struct device *, struct uio *, int);
+int     device_ioctl(struct device *, u_long, void *);
+int     device_info(struct devinfo *);
+
+int     bdev_read(struct device *dev, struct uio *uio, int ioflags);
+int     bdev_write(struct device *dev, struct uio *uio, int ioflags);
+
+int    enodev(void);
+int    nullop(void);
+void multiplex_strategy(struct bio *);
+
+int    physio(struct device *dev, struct uio *uio, int ioflags);
+
+struct device *        device_create(struct driver *drv, const char *name, int 
flags);
+int device_destroy(struct device *dev);
+void device_register(struct device *device, const char *name, int flags);
+void read_partition_table(struct device *device);
+
+__END_DECLS
+
+#endif /* !_DEVICE_H */
-- 
2.21.0

_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.