Commit f2db1135 authored by Federico Vaga's avatar Federico Vaga Committed by Alessandro Rubini

zio-buf.c and zio-dev.c merged in zio-cdev.c

Signed-off-by: 's avatarFederico Vaga <federico.vaga@gmail.com>
Acked-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 62d46235
LINUX ?= /lib/modules/$(shell uname -r)/build
zio-core-objs := zio-dev.o zio-sys.o zio-buf.o
zio-core-objs := zio-cdev.o zio-sys.o
obj-m = zio-core.o
obj-m += drivers/
obj-m += buffers/
......
/* Alessandro Rubini for CERN, 2011, GNU GPLv2 or later */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#define __ZIO_INTERNAL__
#include <linux/zio.h>
#include <linux/zio-buffer.h>
#include <linux/zio-trigger.h>
static DEFINE_MUTEX(zmutex);
struct zio_status zio_global_status;
static struct zio_status *zstat = &zio_global_status; /* Always use ptr */
static ssize_t zio_show_version(struct class *class,
struct class_attribute *attr,
char *buf)
{
return sprintf(buf, "%d.%d\n", ZIO_MAJOR_VERSION, ZIO_MINOR_VERSION);
}
static struct class_attribute zclass_attrs[] = {
__ATTR(version, S_IRUGO, zio_show_version, NULL),
__ATTR_NULL,
};
static char *zio_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "zio/%s", dev_name(dev));
}
/*
* zio_class: don't use class_create to create class because it doesn't permit
* to insert a set of class attributes. This structure is the exact
* reproduction of what class_create does but with some additional settings.
*/
static struct class zio_class = {
.name = "zio",
.owner = THIS_MODULE,
.class_attrs = zclass_attrs,
.devnode = zio_devnode,
};
/* retrieve a channel from one on its minors */
static struct zio_channel *__zio_minor_to_chan(dev_t mm)
{
struct zio_cset *zcset;
dev_t cset_base, chan_minor;
int found = 0;
chan_minor = mm & (ZIO_NMAX_CSET_MINORS-1);
cset_base = mm & (~(ZIO_NMAX_CSET_MINORS-1));
list_for_each_entry(zcset, &zstat->list_cset, list_cset) {
if (cset_base == zcset->basedev) {
found = 1;
break;
}
}
if (!found)
return NULL;
return &zcset->chan[chan_minor/2];
}
static int zio_f_open(struct inode *ino, struct file *f)
{
struct zio_f_priv *priv = NULL;
struct zio_channel *chan;
struct zio_buffer_type *zbuf;
const struct file_operations *old_fops, *new_fops;
int ret = -EINVAL, minor;
pr_debug("%s:%i\n", __func__, __LINE__);
if (f->f_flags & FMODE_WRITE)
goto out;
minor = iminor(ino);
chan = __zio_minor_to_chan(ino->i_rdev);
if (!chan) {
pr_err("ZIO: can't retrieve channel for minor %i\n", minor);
return -EBUSY;
}
zbuf = chan->cset->zbuf;
f->private_data = NULL;
priv = kzalloc(sizeof(struct zio_f_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* if there is no instance, then create a new one */
if (!chan->bi)
chan->bi = zbuf->b_op->create(zbuf, chan, FMODE_READ);
priv->chan = chan;
/* even number is control, odd number is data */
if (minor & 0x1)
priv->type = ZIO_CDEV_DATA;
else
priv->type = ZIO_CDEV_CTRL;
f->private_data = priv;
/* replace zio fops with buffer fops (FIXME: make it a lib function */
mutex_lock(&zmutex);
old_fops = f->f_op;
new_fops = fops_get(zbuf->f_op);
ret = 0;
if (new_fops->open)
ret = new_fops->open(ino, f);
if (ret) {
fops_put(zbuf->f_op);
mutex_unlock(&zmutex);
goto out;
}
fops_put(old_fops);
f->f_op = new_fops;
mutex_unlock(&zmutex);
return 0;
out:
kfree(priv);
return ret;
}
static const struct file_operations zfops = {
.owner = THIS_MODULE,
.open = zio_f_open,
};
int __zio_minorbase_get(struct zio_cset *zcset)
{
int i;
i = find_first_zero_bit(zstat->cset_minors_mask, ZIO_CSET_MAXNUM);
if (i >= ZIO_CSET_MAXNUM)
return 1;
set_bit(i, zstat->cset_minors_mask);
/* set the base minor for a cset*/
zcset->basedev = zstat->basedev + (i * ZIO_NMAX_CSET_MINORS);
pr_debug("%s:%i BASEMINOR 0x%x\n", __func__, __LINE__, zcset->basedev);
return 0;
}
void __zio_minorbase_put(struct zio_cset *zcset)
{
int i;
i = (zcset->basedev - zstat->basedev) / ZIO_NMAX_CSET_MINORS;
clear_bit(i, zstat->cset_minors_mask);
}
/*
* create control and data char devices for a channel. The even minor
* is for control, the odd one for data.
*/
int zio_create_chan_devices(struct zio_channel *chan)
{
int err;
dev_t devt_c, devt_d;
devt_c = chan->cset->basedev + chan->index * 2;
pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_c);
chan->ctrl_dev = device_create(&zio_class, NULL, devt_c, NULL,
"%s-%i-%i-ctrl",
chan->cset->zdev->head.name,
chan->cset->index,
chan->index);
if (IS_ERR(&chan->ctrl_dev)) {
err = PTR_ERR(&chan->ctrl_dev);
goto out;
}
devt_d = devt_c + 1;
pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_d);
chan->data_dev = device_create(&zio_class, NULL, devt_d, NULL,
"%s-%i-%i-data",
chan->cset->zdev->head.name,
chan->cset->index,
chan->index);
if (IS_ERR(&chan->data_dev)) {
err = PTR_ERR(&chan->data_dev);
goto out_data;
}
return 0;
out_data:
device_destroy(&zio_class, chan->ctrl_dev->devt);
out:
return err;
}
void zio_destroy_chan_devices(struct zio_channel *chan)
{
pr_debug("%s\n", __func__);
device_destroy(&zio_class, chan->data_dev->devt);
device_destroy(&zio_class, chan->ctrl_dev->devt);
}
int __zio_register_cdev()
{
int err;
err = class_register(&zio_class);
if (err) {
pr_err("%s: unable to register class\n", __func__);
goto out;
}
/* alloc to zio the maximum number of minors usable in ZIO */
err = alloc_chrdev_region(&zstat->basedev, 0,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS, "zio");
if (err) {
pr_err("%s: unable to allocate region for %i minors\n",
__func__, ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
goto out;
}
/* all ZIO's devices, buffers and triggers has zfops as f_op */
cdev_init(&zstat->chrdev, &zfops);
zstat->chrdev.owner = THIS_MODULE;
err = cdev_add(&zstat->chrdev, zstat->basedev,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
if (err)
goto out_cdev;
INIT_LIST_HEAD(&zstat->list_cset);
return 0;
out_cdev:
unregister_chrdev_region(zstat->basedev,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
out:
class_unregister(&zio_class);
return err;
}
void __zio_unregister_cdev()
{
cdev_del(&zstat->chrdev);
unregister_chrdev_region(zstat->basedev,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
class_unregister(&zio_class);
}
/*
* Helper functions to check whether read and write would block. The
* return value is a poll(2) mask, so the poll method just calls them.
......@@ -229,3 +458,4 @@ int zio_generic_release(struct inode *inode, struct file *f)
return 0;
}
EXPORT_SYMBOL(zio_generic_release);
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#define __ZIO_INTERNAL__
#include <linux/zio.h>
#include <linux/zio-buffer.h>
static DEFINE_MUTEX(zmutex);
struct zio_status zio_global_status;
static struct zio_status *zstat = &zio_global_status; /* Always use ptr */
static ssize_t zio_show_version(struct class *class,
struct class_attribute *attr,
char *buf)
{
return sprintf(buf, "%d.%d\n", ZIO_MAJOR_VERSION, ZIO_MINOR_VERSION);
}
static struct class_attribute zclass_attrs[] = {
__ATTR(version, S_IRUGO, zio_show_version, NULL),
__ATTR_NULL,
};
static char *zio_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "zio/%s", dev_name(dev));
}
/*
* zio_class: don't use class_create to create class because it doesn't permit
* to insert a set of class attributes. This structure is the exact
* reproduction of what class_create does but with some additional settings.
*/
static struct class zio_class = {
.name = "zio",
.owner = THIS_MODULE,
.class_attrs = zclass_attrs,
.devnode = zio_devnode,
};
/* retrieve a channel from one on its minors */
static struct zio_channel *__zio_minor_to_chan(dev_t mm)
{
struct zio_cset *zcset;
dev_t cset_base, chan_minor;
int found = 0;
chan_minor = mm & (ZIO_NMAX_CSET_MINORS-1);
cset_base = mm & (~(ZIO_NMAX_CSET_MINORS-1));
list_for_each_entry(zcset, &zstat->list_cset, list_cset) {
if (cset_base == zcset->basedev) {
found = 1;
break;
}
}
if (!found)
return NULL;
return &zcset->chan[chan_minor/2];
}
static int zio_f_open(struct inode *ino, struct file *f)
{
struct zio_f_priv *priv = NULL;
struct zio_channel *chan;
struct zio_buffer_type *zbuf;
const struct file_operations *old_fops, *new_fops;
int ret = -EINVAL, minor;
pr_debug("%s:%i\n", __func__, __LINE__);
if (f->f_flags & FMODE_WRITE)
goto out;
minor = iminor(ino);
chan = __zio_minor_to_chan(ino->i_rdev);
if (!chan) {
pr_err("ZIO: can't retrieve channel for minor %i\n", minor);
return -EBUSY;
}
zbuf = chan->cset->zbuf;
f->private_data = NULL;
priv = kzalloc(sizeof(struct zio_f_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* if there is no instance, then create a new one */
if (!chan->bi)
chan->bi = zbuf->b_op->create(zbuf, chan, FMODE_READ);
priv->chan = chan;
/* even number is control, odd number is data */
if (minor & 0x1)
priv->type = ZIO_CDEV_DATA;
else
priv->type = ZIO_CDEV_CTRL;
f->private_data = priv;
/* replace zio fops with buffer fops (FIXME: make it a lib function */
mutex_lock(&zmutex);
old_fops = f->f_op;
new_fops = fops_get(zbuf->f_op);
ret = 0;
if (new_fops->open)
ret = new_fops->open(ino, f);
if (ret) {
fops_put(zbuf->f_op);
mutex_unlock(&zmutex);
goto out;
}
fops_put(old_fops);
f->f_op = new_fops;
mutex_unlock(&zmutex);
return 0;
out:
kfree(priv);
return ret;
}
static const struct file_operations zfops = {
.owner = THIS_MODULE,
.open = zio_f_open,
};
int __zio_minorbase_get(struct zio_cset *zcset)
{
int i;
i = find_first_zero_bit(zstat->cset_minors_mask, ZIO_CSET_MAXNUM);
if (i >= ZIO_CSET_MAXNUM)
return 1;
set_bit(i, zstat->cset_minors_mask);
/* set the base minor for a cset*/
zcset->basedev = zstat->basedev + (i * ZIO_NMAX_CSET_MINORS);
pr_debug("%s:%i BASEMINOR 0x%x\n", __func__, __LINE__, zcset->basedev);
return 0;
}
void __zio_minorbase_put(struct zio_cset *zcset)
{
int i;
i = (zcset->basedev - zstat->basedev) / ZIO_NMAX_CSET_MINORS;
clear_bit(i, zstat->cset_minors_mask);
}
/*
* create control and data char devices for a channel. The even minor
* is for control, the odd one for data.
*/
int zio_create_chan_devices(struct zio_channel *chan)
{
int err;
dev_t devt_c, devt_d;
devt_c = chan->cset->basedev + chan->index * 2;
pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_c);
chan->ctrl_dev = device_create(&zio_class, NULL, devt_c, NULL,
"%s-%i-%i-ctrl",
chan->cset->zdev->head.name,
chan->cset->index,
chan->index);
if (IS_ERR(&chan->ctrl_dev)) {
err = PTR_ERR(&chan->ctrl_dev);
goto out;
}
devt_d = devt_c + 1;
pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_d);
chan->data_dev = device_create(&zio_class, NULL, devt_d, NULL,
"%s-%i-%i-data",
chan->cset->zdev->head.name,
chan->cset->index,
chan->index);
if (IS_ERR(&chan->data_dev)) {
err = PTR_ERR(&chan->data_dev);
goto out_data;
}
return 0;
out_data:
device_destroy(&zio_class, chan->ctrl_dev->devt);
out:
return err;
}
void zio_destroy_chan_devices(struct zio_channel *chan)
{
pr_debug("%s\n", __func__);
device_destroy(&zio_class, chan->data_dev->devt);
device_destroy(&zio_class, chan->ctrl_dev->devt);
}
int __zio_register_cdev()
{
int err;
err = class_register(&zio_class);
if (err) {
pr_err("%s: unable to register class\n", __func__);
goto out;
}
/* alloc to zio the maximum number of minors usable in ZIO */
err = alloc_chrdev_region(&zstat->basedev, 0,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS, "zio");
if (err) {
pr_err("%s: unable to allocate region for %i minors\n",
__func__, ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
goto out;
}
/* all ZIO's devices, buffers and triggers has zfops as f_op */
cdev_init(&zstat->chrdev, &zfops);
zstat->chrdev.owner = THIS_MODULE;
err = cdev_add(&zstat->chrdev, zstat->basedev,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
if (err)
goto out_cdev;
INIT_LIST_HEAD(&zstat->list_cset);
return 0;
out_cdev:
unregister_chrdev_region(zstat->basedev,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
out:
class_unregister(&zio_class);
return err;
}
void __zio_unregister_cdev()
{
cdev_del(&zstat->chrdev);
unregister_chrdev_region(zstat->basedev,
ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
class_unregister(&zio_class);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment