[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 1/6] lib/devfs: Initial import from OSv
commit: c8395118cb580f2395cac6c53999feb217fd2c2f Signed-off-by: Vlad-Andrei Badoiu <vlad_andrei.badoiu@xxxxxxxxxxxxxxx> --- lib/Config.uk | 1 + lib/Makefile.uk | 1 + lib/devfs/Config.uk | 4 + lib/devfs/Makefile.uk | 4 + lib/devfs/devfs.h | 37 +++ lib/devfs/devfs_vnops.c | 284 +++++++++++++++++++++ lib/devfs/device.c | 537 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 868 insertions(+) create mode 100644 lib/devfs/Config.uk create mode 100644 lib/devfs/Makefile.uk create mode 100644 lib/devfs/devfs.h create mode 100644 lib/devfs/devfs_vnops.c create mode 100644 lib/devfs/device.c diff --git a/lib/Config.uk b/lib/Config.uk index 553d4c6b..ea8b06a3 100644 --- a/lib/Config.uk +++ b/lib/Config.uk @@ -40,6 +40,7 @@ source "lib/ukschedcoop/Config.uk" source "lib/fdt/Config.uk" source "lib/vfscore/Config.uk" source "lib/ramfs/Config.uk" +source "lib/devfs/Config.uk" source "lib/uklock/Config.uk" source "lib/ukmpi/Config.uk" source "lib/ukswrand/Config.uk" diff --git a/lib/Makefile.uk b/lib/Makefile.uk index 54a957de..97fdf7b2 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -18,6 +18,7 @@ $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukschedcoop)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/fdt)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/vfscore)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ramfs)) +$(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/devfs)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uklock)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukmpi)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukbus)) diff --git a/lib/devfs/Config.uk b/lib/devfs/Config.uk new file mode 100644 index 00000000..9ad502f7 --- /dev/null +++ b/lib/devfs/Config.uk @@ -0,0 +1,4 @@ +config LIBDEVFS + bool "devfs: devfs file system" + default n + depends on LIBVFSCORE diff --git a/lib/devfs/Makefile.uk b/lib/devfs/Makefile.uk new file mode 100644 index 00000000..f33187f3 --- /dev/null +++ b/lib/devfs/Makefile.uk @@ -0,0 +1,4 @@ +$(eval $(call addlib_s,libdevfs,$(CONFIG_LIBDEVFS))) + +LIBDEVFS_SRCS-y += $(LIBDEVFS_BASE)/device.c +LIBDEVFS_SRCS-y += $(LIBDEVFS_BASE)/devfs_vnops.c 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; +} -- 2.20.1 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |