[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH 1/6] lib/devfs: Initial import from OSv
Hi Vlad, thanks for the series. Modifications in (Config|Makefile).uk files do not belong to this patch. It breaks bisectability. It is better to include the library into the build system only when it compiles and works. More logical place for these modifications would be patch "Adapt imported devfs to Unikraft" or a separate one. Cheers, Yuri. "Vlad-Andrei BĂDOIU (78692)" <vlad_andrei.badoiu@xxxxxxxxxxxxxxx> writes: > 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 > -- 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |