[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |