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

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



Reviewed-by: Yuri Volchkov <yuri.volchkov@xxxxxxxxx>

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

> commit: c8395118cb580f2395cac6c53999feb217fd2c2f
> Signed-off-by: Vlad-Andrei Badoiu <vlad_andrei.badoiu@xxxxxxxxxxxxxxx>
> ---
>  lib/devfs/devfs.h          |  37 +++
>  lib/devfs/devfs_vnops.c    | 284 ++++++++++++++++++++
>  lib/devfs/device.c         | 537 +++++++++++++++++++++++++++++++++++++
>  lib/devfs/include/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/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/device.h b/lib/devfs/include/device.h
> new file mode 100644
> index 00000000..16d2e470
> --- /dev/null
> +++ b/lib/devfs/include/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
>

-- 
Yuri Volchkov
Software Specialist

NEC Europe Ltd
Kurfürsten-Anlage 36
D-69115 Heidelberg

_______________________________________________
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®.