summaryrefslogtreecommitdiff
path: root/drivers/staging/comedi/comedi_fops.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/comedi_fops.c')
-rw-r--r--drivers/staging/comedi/comedi_fops.c1007
1 files changed, 477 insertions, 530 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 9b038e4..195d56d 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -49,10 +49,6 @@
#include "comedi_internal.h"
-MODULE_AUTHOR("http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi core module");
-MODULE_LICENSE("GPL");
-
#ifdef CONFIG_COMEDI_DEBUG
int comedi_debug;
EXPORT_SYMBOL(comedi_debug);
@@ -62,11 +58,6 @@ MODULE_PARM_DESC(comedi_debug,
);
#endif
-bool comedi_autoconfig = 1;
-module_param(comedi_autoconfig, bool, S_IRUGO);
-MODULE_PARM_DESC(comedi_autoconfig,
- "enable drivers to auto-configure comedi devices (default 1)");
-
static int comedi_num_legacy_minors;
module_param(comedi_num_legacy_minors, int, S_IRUGO);
MODULE_PARM_DESC(comedi_num_legacy_minors,
@@ -86,17 +77,58 @@ MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
"default maximum size of asynchronous buffer in KiB (default "
__MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
+struct comedi_file_info {
+ struct comedi_device *device;
+ struct comedi_subdevice *read_subdevice;
+ struct comedi_subdevice *write_subdevice;
+ struct device *hardware_device;
+};
+
static DEFINE_SPINLOCK(comedi_file_info_table_lock);
-static struct comedi_device_file_info
-*comedi_file_info_table[COMEDI_NUM_MINORS];
+static struct comedi_file_info *comedi_file_info_table[COMEDI_NUM_MINORS];
-static void do_become_nonbusy(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
+static struct comedi_file_info *comedi_file_info_from_minor(unsigned minor)
+{
+ struct comedi_file_info *info;
+
+ BUG_ON(minor >= COMEDI_NUM_MINORS);
+ spin_lock(&comedi_file_info_table_lock);
+ info = comedi_file_info_table[minor];
+ spin_unlock(&comedi_file_info_table_lock);
+ return info;
+}
+
+static struct comedi_device *
+comedi_dev_from_file_info(struct comedi_file_info *info)
+{
+ return info ? info->device : NULL;
+}
+
+struct comedi_device *comedi_dev_from_minor(unsigned minor)
+{
+ return comedi_dev_from_file_info(comedi_file_info_from_minor(minor));
+}
+EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
-static int comedi_fasync(int fd, struct file *file, int on);
+static struct comedi_subdevice *
+comedi_read_subdevice(const struct comedi_file_info *info)
+{
+ if (info->read_subdevice)
+ return info->read_subdevice;
+ if (info->device)
+ return info->device->read_subdev;
+ return NULL;
+}
-static int is_device_busy(struct comedi_device *dev);
+static struct comedi_subdevice *
+comedi_write_subdevice(const struct comedi_file_info *info)
+{
+ if (info->write_subdevice)
+ return info->write_subdevice;
+ if (info->device)
+ return info->device->write_subdev;
+ return NULL;
+}
static int resize_async_buffer(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -134,7 +166,7 @@ static int resize_async_buffer(struct comedi_device *dev,
}
DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
- dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
+ dev->minor, s->index, async->prealloc_bufsz);
return 0;
}
@@ -143,8 +175,8 @@ static int resize_async_buffer(struct comedi_device *dev,
static ssize_t show_max_read_buffer_kb(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_read_subdevice(info);
unsigned int size = 0;
mutex_lock(&info->device->mutex);
@@ -159,8 +191,8 @@ static ssize_t store_max_read_buffer_kb(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_read_subdevice(info);
unsigned int size;
int err;
@@ -184,8 +216,8 @@ static ssize_t store_max_read_buffer_kb(struct device *dev,
static ssize_t show_read_buffer_kb(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_read_subdevice(info);
unsigned int size = 0;
mutex_lock(&info->device->mutex);
@@ -200,8 +232,8 @@ static ssize_t store_read_buffer_kb(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_read_subdevice(info);
unsigned int size;
int err;
@@ -226,8 +258,8 @@ static ssize_t show_max_write_buffer_kb(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_write_subdevice(info);
unsigned int size = 0;
mutex_lock(&info->device->mutex);
@@ -242,8 +274,8 @@ static ssize_t store_max_write_buffer_kb(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_write_subdevice(info);
unsigned int size;
int err;
@@ -267,8 +299,8 @@ static ssize_t store_max_write_buffer_kb(struct device *dev,
static ssize_t show_write_buffer_kb(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_write_subdevice(info);
unsigned int size = 0;
mutex_lock(&info->device->mutex);
@@ -283,8 +315,8 @@ static ssize_t store_write_buffer_kb(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+ struct comedi_file_info *info = dev_get_drvdata(dev);
+ struct comedi_subdevice *s = comedi_write_subdevice(info);
unsigned int size;
int err;
@@ -317,6 +349,103 @@ static struct device_attribute comedi_dev_attrs[] = {
__ATTR_NULL
};
+static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
+ unsigned mask, unsigned bits)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->spin_lock, flags);
+ s->runflags &= ~mask;
+ s->runflags |= (bits & mask);
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+}
+
+static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
+{
+ unsigned long flags;
+ unsigned runflags;
+
+ spin_lock_irqsave(&s->spin_lock, flags);
+ runflags = s->runflags;
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+ return runflags;
+}
+
+bool comedi_is_subdevice_running(struct comedi_subdevice *s)
+{
+ unsigned runflags = comedi_get_subdevice_runflags(s);
+
+ return (runflags & SRF_RUNNING) ? true : false;
+}
+EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
+
+static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
+{
+ unsigned runflags = comedi_get_subdevice_runflags(s);
+
+ return (runflags & SRF_ERROR) ? true : false;
+}
+
+static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
+{
+ unsigned runflags = comedi_get_subdevice_runflags(s);
+
+ return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
+}
+
+/*
+ This function restores a subdevice to an idle state.
+ */
+static void do_become_nonbusy(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct comedi_async *async = s->async;
+
+ comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
+ if (async) {
+ comedi_buf_reset(async);
+ async->inttrig = NULL;
+ kfree(async->cmd.chanlist);
+ async->cmd.chanlist = NULL;
+ } else {
+ dev_err(dev->class_dev,
+ "BUG: (?) do_become_nonbusy called with async=NULL\n");
+ }
+
+ s->busy = NULL;
+}
+
+static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ int ret = 0;
+
+ if (comedi_is_subdevice_running(s) && s->cancel)
+ ret = s->cancel(dev, s);
+
+ do_become_nonbusy(dev, s);
+
+ return ret;
+}
+
+static int is_device_busy(struct comedi_device *dev)
+{
+ struct comedi_subdevice *s;
+ int i;
+
+ if (!dev->attached)
+ return 0;
+
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ if (s->busy)
+ return 1;
+ if (s->async && s->async->mmap_count)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
COMEDI_DEVCONFIG
device config ioctl
@@ -335,8 +464,6 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
{
struct comedi_devconfig it;
int ret;
- unsigned char *aux_data = NULL;
- int aux_len;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -352,36 +479,15 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
return 0;
}
- if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
+ if (copy_from_user(&it, arg, sizeof(it)))
return -EFAULT;
it.board_name[COMEDI_NAMELEN - 1] = 0;
- if (comedi_aux_data(it.options, 0) &&
- it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
- int bit_shift;
- aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
- if (aux_len < 0)
- return -EFAULT;
-
- aux_data = vmalloc(aux_len);
- if (!aux_data)
- return -ENOMEM;
-
- if (copy_from_user(aux_data,
- (unsigned char __user *
- )comedi_aux_data(it.options, 0), aux_len)) {
- vfree(aux_data);
- return -EFAULT;
- }
- it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
- (unsigned long)aux_data;
- if (sizeof(void *) > sizeof(int)) {
- bit_shift = sizeof(int) * 8;
- it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
- ((unsigned long)aux_data) >> bit_shift;
- } else
- it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
+ if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
+ dev_warn(dev->class_dev,
+ "comedi_config --init_data is deprecated\n");
+ return -EINVAL;
}
ret = comedi_device_attach(dev, &it);
@@ -392,9 +498,6 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
}
}
- if (aux_data)
- vfree(aux_data);
-
return ret;
}
@@ -420,7 +523,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev,
struct comedi_subdevice *s;
int retval = 0;
- if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
+ if (copy_from_user(&bc, arg, sizeof(bc)))
return -EFAULT;
if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
@@ -453,7 +556,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev,
bc.maximum_size = async->max_bufsize;
copyback:
- if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
+ if (copy_to_user(arg, &bc, sizeof(bc)))
return -EFAULT;
return 0;
@@ -477,14 +580,10 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
struct comedi_devinfo __user *arg,
struct file *file)
{
- struct comedi_devinfo devinfo;
const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_device_file_info *dev_file_info =
- comedi_get_device_file_info(minor);
- struct comedi_subdevice *read_subdev =
- comedi_get_read_subdevice(dev_file_info);
- struct comedi_subdevice *write_subdev =
- comedi_get_write_subdevice(dev_file_info);
+ struct comedi_file_info *info = comedi_file_info_from_minor(minor);
+ struct comedi_subdevice *s;
+ struct comedi_devinfo devinfo;
memset(&devinfo, 0, sizeof(devinfo));
@@ -494,17 +593,19 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
- if (read_subdev)
- devinfo.read_subdevice = read_subdev - dev->subdevices;
+ s = comedi_read_subdevice(info);
+ if (s)
+ devinfo.read_subdevice = s->index;
else
devinfo.read_subdevice = -1;
- if (write_subdev)
- devinfo.write_subdevice = write_subdev - dev->subdevices;
+ s = comedi_write_subdevice(info);
+ if (s)
+ devinfo.write_subdevice = s->index;
else
devinfo.write_subdevice = -1;
- if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
+ if (copy_to_user(arg, &devinfo, sizeof(devinfo)))
return -EFAULT;
return 0;
@@ -531,9 +632,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
struct comedi_subdinfo *tmp, *us;
struct comedi_subdevice *s;
- tmp =
- kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
- GFP_KERNEL);
+ tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
@@ -545,7 +644,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
us->type = s->type;
us->n_chan = s->n_chan;
us->subd_flags = s->subdev_flags;
- if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
+ if (comedi_is_subdevice_running(s))
us->subd_flags |= SDF_RUNNING;
#define TIMER_nanosec 5 /* backwards compatibility */
us->timer_type = TIMER_nanosec;
@@ -584,8 +683,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
us->settling_time_0 = s->settling_time_0;
}
- ret = copy_to_user(arg, tmp,
- dev->n_subdevices * sizeof(struct comedi_subdinfo));
+ ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp));
kfree(tmp);
@@ -612,7 +710,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
struct comedi_subdevice *s;
struct comedi_chaninfo it;
- if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
+ if (copy_from_user(&it, arg, sizeof(it)))
return -EFAULT;
if (it.subdev >= dev->n_subdevices)
@@ -679,7 +777,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
struct comedi_subdevice *s;
struct comedi_async *async;
- if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
+ if (copy_from_user(&bi, arg, sizeof(bi)))
return -EFAULT;
if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
@@ -714,9 +812,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
comedi_buf_read_free(async, bi.bytes_read);
- if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
- SRF_RUNNING))
- && async->buf_write_count == async->buf_read_count) {
+ if (comedi_is_subdevice_idle(s) &&
+ async->buf_write_count == async->buf_read_count) {
do_become_nonbusy(dev, s);
}
}
@@ -734,103 +831,12 @@ copyback_position:
bi.buf_read_ptr = async->buf_read_ptr;
copyback:
- if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
+ if (copy_to_user(arg, &bi, sizeof(bi)))
return -EFAULT;
return 0;
}
-static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
- unsigned int *data, void *file);
-/*
- * COMEDI_INSNLIST
- * synchronous instructions
- *
- * arg:
- * pointer to sync cmd structure
- *
- * reads:
- * sync cmd struct at arg
- * instruction list
- * data (for writes)
- *
- * writes:
- * data (for reads)
- */
-/* arbitrary limits */
-#define MAX_SAMPLES 256
-static int do_insnlist_ioctl(struct comedi_device *dev,
- struct comedi_insnlist __user *arg, void *file)
-{
- struct comedi_insnlist insnlist;
- struct comedi_insn *insns = NULL;
- unsigned int *data = NULL;
- int i = 0;
- int ret = 0;
-
- if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
- return -EFAULT;
-
- data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
- if (!data) {
- DPRINTK("kmalloc failed\n");
- ret = -ENOMEM;
- goto error;
- }
-
- insns =
- kcalloc(insnlist.n_insns, sizeof(struct comedi_insn), GFP_KERNEL);
- if (!insns) {
- DPRINTK("kmalloc failed\n");
- ret = -ENOMEM;
- goto error;
- }
-
- if (copy_from_user(insns, insnlist.insns,
- sizeof(struct comedi_insn) * insnlist.n_insns)) {
- DPRINTK("copy_from_user failed\n");
- ret = -EFAULT;
- goto error;
- }
-
- for (i = 0; i < insnlist.n_insns; i++) {
- if (insns[i].n > MAX_SAMPLES) {
- DPRINTK("number of samples too large\n");
- ret = -EINVAL;
- goto error;
- }
- if (insns[i].insn & INSN_MASK_WRITE) {
- if (copy_from_user(data, insns[i].data,
- insns[i].n * sizeof(unsigned int))) {
- DPRINTK("copy_from_user failed\n");
- ret = -EFAULT;
- goto error;
- }
- }
- ret = parse_insn(dev, insns + i, data, file);
- if (ret < 0)
- goto error;
- if (insns[i].insn & INSN_MASK_READ) {
- if (copy_to_user(insns[i].data, data,
- insns[i].n * sizeof(unsigned int))) {
- DPRINTK("copy_to_user failed\n");
- ret = -EFAULT;
- goto error;
- }
- }
- if (need_resched())
- schedule();
- }
-
-error:
- kfree(insns);
- kfree(data);
-
- if (ret < 0)
- return ret;
- return i;
-}
-
static int check_insn_config_length(struct comedi_insn *insn,
unsigned int *data)
{
@@ -1062,6 +1068,94 @@ out:
}
/*
+ * COMEDI_INSNLIST
+ * synchronous instructions
+ *
+ * arg:
+ * pointer to sync cmd structure
+ *
+ * reads:
+ * sync cmd struct at arg
+ * instruction list
+ * data (for writes)
+ *
+ * writes:
+ * data (for reads)
+ */
+/* arbitrary limits */
+#define MAX_SAMPLES 256
+static int do_insnlist_ioctl(struct comedi_device *dev,
+ struct comedi_insnlist __user *arg, void *file)
+{
+ struct comedi_insnlist insnlist;
+ struct comedi_insn *insns = NULL;
+ unsigned int *data = NULL;
+ int i = 0;
+ int ret = 0;
+
+ if (copy_from_user(&insnlist, arg, sizeof(insnlist)))
+ return -EFAULT;
+
+ data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
+ if (!data) {
+ DPRINTK("kmalloc failed\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
+ if (!insns) {
+ DPRINTK("kmalloc failed\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (copy_from_user(insns, insnlist.insns,
+ sizeof(*insns) * insnlist.n_insns)) {
+ DPRINTK("copy_from_user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+
+ for (i = 0; i < insnlist.n_insns; i++) {
+ if (insns[i].n > MAX_SAMPLES) {
+ DPRINTK("number of samples too large\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ if (insns[i].insn & INSN_MASK_WRITE) {
+ if (copy_from_user(data, insns[i].data,
+ insns[i].n * sizeof(unsigned int))) {
+ DPRINTK("copy_from_user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+ ret = parse_insn(dev, insns + i, data, file);
+ if (ret < 0)
+ goto error;
+ if (insns[i].insn & INSN_MASK_READ) {
+ if (copy_to_user(insns[i].data, data,
+ insns[i].n * sizeof(unsigned int))) {
+ DPRINTK("copy_to_user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+ if (need_resched())
+ schedule();
+ }
+
+error:
+ kfree(insns);
+ kfree(data);
+
+ if (ret < 0)
+ return ret;
+ return i;
+}
+
+/*
* COMEDI_INSN
* synchronous instructions
*
@@ -1088,7 +1182,7 @@ static int do_insn_ioctl(struct comedi_device *dev,
goto error;
}
- if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
+ if (copy_from_user(&insn, arg, sizeof(insn))) {
ret = -EFAULT;
goto error;
}
@@ -1123,17 +1217,6 @@ error:
return ret;
}
-static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
- unsigned mask, unsigned bits)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->spin_lock, flags);
- s->runflags &= ~mask;
- s->runflags |= (bits & mask);
- spin_unlock_irqrestore(&s->spin_lock, flags);
-}
-
static int do_cmd_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
@@ -1143,7 +1226,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
int ret = 0;
unsigned int __user *user_chanlist;
- if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
+ if (copy_from_user(&cmd, arg, sizeof(cmd))) {
DPRINTK("bad cmd address\n");
return -EFAULT;
}
@@ -1233,7 +1316,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
/* restore chanlist pointer before copying back */
cmd.chanlist = (unsigned int __force *)user_chanlist;
cmd.data = NULL;
- if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
+ if (copy_to_user(arg, &cmd, sizeof(cmd))) {
DPRINTK("fault writing cmd\n");
ret = -EFAULT;
goto cleanup;
@@ -1248,7 +1331,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
goto cleanup;
}
- comedi_reset_async_buf(async);
+ comedi_buf_reset(async);
async->cb_mask =
COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
@@ -1292,7 +1375,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
unsigned int *chanlist = NULL;
unsigned int __user *user_chanlist;
- if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
+ if (copy_from_user(&cmd, arg, sizeof(cmd))) {
DPRINTK("bad cmd address\n");
return -EFAULT;
}
@@ -1356,7 +1439,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
/* restore chanlist pointer before copying back */
cmd.chanlist = (unsigned int __force *)user_chanlist;
- if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
+ if (copy_to_user(arg, &cmd, sizeof(cmd))) {
DPRINTK("bad cmd address\n");
ret = -EFAULT;
goto cleanup;
@@ -1533,25 +1616,28 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_device_file_info *dev_file_info =
- comedi_get_device_file_info(minor);
- struct comedi_device *dev;
+ struct comedi_file_info *info = comedi_file_info_from_minor(minor);
+ struct comedi_device *dev = comedi_dev_from_file_info(info);
int rc;
- if (dev_file_info == NULL || dev_file_info->device == NULL)
+ if (!dev)
return -ENODEV;
- dev = dev_file_info->device;
mutex_lock(&dev->mutex);
/* Device config is special, because it must work on
* an unconfigured device. */
if (cmd == COMEDI_DEVCONFIG) {
+ if (minor >= COMEDI_NUM_BOARD_MINORS) {
+ /* Device config not appropriate on non-board minors. */
+ rc = -ENOTTY;
+ goto done;
+ }
rc = do_devconfig_ioctl(dev,
(struct comedi_devconfig __user *)arg);
if (rc == 0)
/* Evade comedi_auto_unconfig(). */
- dev_file_info->hardware_device = NULL;
+ info->hardware_device = NULL;
goto done;
}
@@ -1624,19 +1710,6 @@ done:
return rc;
}
-static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- int ret = 0;
-
- if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
- ret = s->cancel(dev, s);
-
- do_become_nonbusy(dev, s);
-
- return ret;
-}
-
-
static void comedi_vm_open(struct vm_area_struct *area)
{
struct comedi_async *async;
@@ -1671,40 +1744,38 @@ static struct vm_operations_struct comedi_vm_ops = {
static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
{
const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_async *async = NULL;
+ struct comedi_file_info *info = comedi_file_info_from_minor(minor);
+ struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_subdevice *s;
+ struct comedi_async *async;
unsigned long start = vma->vm_start;
unsigned long size;
int n_pages;
int i;
int retval;
- struct comedi_subdevice *s;
- struct comedi_device_file_info *dev_file_info;
- struct comedi_device *dev;
- dev_file_info = comedi_get_device_file_info(minor);
- if (dev_file_info == NULL)
- return -ENODEV;
- dev = dev_file_info->device;
- if (dev == NULL)
+ if (!dev)
return -ENODEV;
mutex_lock(&dev->mutex);
+
if (!dev->attached) {
DPRINTK("no driver configured on comedi%i\n", dev->minor);
retval = -ENODEV;
goto done;
}
+
if (vma->vm_flags & VM_WRITE)
- s = comedi_get_write_subdevice(dev_file_info);
+ s = comedi_write_subdevice(info);
else
- s = comedi_get_read_subdevice(dev_file_info);
-
- if (s == NULL) {
+ s = comedi_read_subdevice(info);
+ if (!s) {
retval = -EINVAL;
goto done;
}
+
async = s->async;
- if (async == NULL) {
+ if (!async) {
retval = -EINVAL;
goto done;
}
@@ -1727,11 +1798,11 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
n_pages = size >> PAGE_SHIFT;
for (i = 0; i < n_pages; ++i) {
+ struct comedi_buf_page *buf = &async->buf_page_list[i];
+
if (remap_pfn_range(vma, start,
- page_to_pfn(virt_to_page
- (async->buf_page_list
- [i].virt_addr)), PAGE_SIZE,
- PAGE_SHARED)) {
+ page_to_pfn(virt_to_page(buf->virt_addr)),
+ PAGE_SIZE, PAGE_SHARED)) {
retval = -EAGAIN;
goto done;
}
@@ -1753,50 +1824,40 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_subdevice *read_subdev;
- struct comedi_subdevice *write_subdev;
- struct comedi_device_file_info *dev_file_info;
- struct comedi_device *dev;
- dev_file_info = comedi_get_device_file_info(minor);
+ struct comedi_file_info *info = comedi_file_info_from_minor(minor);
+ struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_subdevice *s;
- if (dev_file_info == NULL)
- return -ENODEV;
- dev = dev_file_info->device;
- if (dev == NULL)
+ if (!dev)
return -ENODEV;
mutex_lock(&dev->mutex);
+
if (!dev->attached) {
DPRINTK("no driver configured on comedi%i\n", dev->minor);
- mutex_unlock(&dev->mutex);
- return 0;
+ goto done;
}
- mask = 0;
- read_subdev = comedi_get_read_subdevice(dev_file_info);
- if (read_subdev) {
- poll_wait(file, &read_subdev->async->wait_head, wait);
- if (!read_subdev->busy
- || comedi_buf_read_n_available(read_subdev->async) > 0
- || !(comedi_get_subdevice_runflags(read_subdev) &
- SRF_RUNNING)) {
+ s = comedi_read_subdevice(info);
+ if (s && s->async) {
+ poll_wait(file, &s->async->wait_head, wait);
+ if (!s->busy || !comedi_is_subdevice_running(s) ||
+ comedi_buf_read_n_available(s->async) > 0)
mask |= POLLIN | POLLRDNORM;
- }
}
- write_subdev = comedi_get_write_subdevice(dev_file_info);
- if (write_subdev) {
- poll_wait(file, &write_subdev->async->wait_head, wait);
- comedi_buf_write_alloc(write_subdev->async,
- write_subdev->async->prealloc_bufsz);
- if (!write_subdev->busy
- || !(comedi_get_subdevice_runflags(write_subdev) &
- SRF_RUNNING)
- || comedi_buf_write_n_allocated(write_subdev->async) >=
- bytes_per_sample(write_subdev->async->subdevice)) {
+
+ s = comedi_write_subdevice(info);
+ if (s && s->async) {
+ unsigned int bps = bytes_per_sample(s->async->subdevice);
+
+ poll_wait(file, &s->async->wait_head, wait);
+ comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
+ if (!s->busy || !comedi_is_subdevice_running(s) ||
+ comedi_buf_write_n_allocated(s->async) >= bps)
mask |= POLLOUT | POLLWRNORM;
- }
}
+done:
mutex_unlock(&dev->mutex);
return mask;
}
@@ -1809,53 +1870,38 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_device_file_info *dev_file_info;
- struct comedi_device *dev;
- dev_file_info = comedi_get_device_file_info(minor);
+ struct comedi_file_info *info = comedi_file_info_from_minor(minor);
+ struct comedi_device *dev = comedi_dev_from_file_info(info);
- if (dev_file_info == NULL)
- return -ENODEV;
- dev = dev_file_info->device;
- if (dev == NULL)
+ if (!dev)
return -ENODEV;
if (!dev->attached) {
DPRINTK("no driver configured on comedi%i\n", dev->minor);
- retval = -ENODEV;
- goto done;
+ return -ENODEV;
}
- s = comedi_get_write_subdevice(dev_file_info);
- if (s == NULL) {
- retval = -EIO;
- goto done;
- }
+ s = comedi_write_subdevice(info);
+ if (!s || !s->async)
+ return -EIO;
+
async = s->async;
- if (!nbytes) {
- retval = 0;
- goto done;
- }
- if (!s->busy) {
- retval = 0;
- goto done;
- }
- if (s->busy != file) {
- retval = -EACCES;
- goto done;
- }
+ if (!s->busy || !nbytes)
+ return 0;
+ if (s->busy != file)
+ return -EACCES;
+
add_wait_queue(&async->wait_head, &wait);
while (nbytes > 0 && !retval) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
+ if (!comedi_is_subdevice_running(s)) {
if (count == 0) {
- if (comedi_get_subdevice_runflags(s) &
- SRF_ERROR) {
+ if (comedi_is_subdevice_in_error(s))
retval = -EPIPE;
- } else {
+ else
retval = 0;
- }
do_become_nonbusy(dev, s);
}
break;
@@ -1908,7 +1954,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
set_current_state(TASK_RUNNING);
remove_wait_queue(&async->wait_head, &wait);
-done:
return count ? count : retval;
}
@@ -1920,40 +1965,26 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_device_file_info *dev_file_info;
- struct comedi_device *dev;
- dev_file_info = comedi_get_device_file_info(minor);
+ struct comedi_file_info *info = comedi_file_info_from_minor(minor);
+ struct comedi_device *dev = comedi_dev_from_file_info(info);
- if (dev_file_info == NULL)
- return -ENODEV;
- dev = dev_file_info->device;
- if (dev == NULL)
+ if (!dev)
return -ENODEV;
if (!dev->attached) {
DPRINTK("no driver configured on comedi%i\n", dev->minor);
- retval = -ENODEV;
- goto done;
+ return -ENODEV;
}
- s = comedi_get_read_subdevice(dev_file_info);
- if (s == NULL) {
- retval = -EIO;
- goto done;
- }
+ s = comedi_read_subdevice(info);
+ if (!s || !s->async)
+ return -EIO;
+
async = s->async;
- if (!nbytes) {
- retval = 0;
- goto done;
- }
- if (!s->busy) {
- retval = 0;
- goto done;
- }
- if (s->busy != file) {
- retval = -EACCES;
- goto done;
- }
+ if (!s->busy || !nbytes)
+ return 0;
+ if (s->busy != file)
+ return -EACCES;
add_wait_queue(&async->wait_head, &wait);
while (nbytes > 0 && !retval) {
@@ -1970,14 +2001,12 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
n = m;
if (n == 0) {
- if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
+ if (!comedi_is_subdevice_running(s)) {
do_become_nonbusy(dev, s);
- if (comedi_get_subdevice_runflags(s) &
- SRF_ERROR) {
+ if (comedi_is_subdevice_in_error(s))
retval = -EPIPE;
- } else {
+ else
retval = 0;
- }
break;
}
if (file->f_flags & O_NONBLOCK) {
@@ -2015,48 +2044,22 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
buf += n;
break; /* makes device work like a pipe */
}
- if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
+ if (comedi_is_subdevice_idle(s) &&
async->buf_read_count - async->buf_write_count == 0) {
do_become_nonbusy(dev, s);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&async->wait_head, &wait);
-done:
return count ? count : retval;
}
-/*
- This function restores a subdevice to an idle state.
- */
-static void do_become_nonbusy(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct comedi_async *async = s->async;
-
- comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
- if (async) {
- comedi_reset_async_buf(async);
- async->inttrig = NULL;
- kfree(async->cmd.chanlist);
- async->cmd.chanlist = NULL;
- } else {
- dev_err(dev->class_dev,
- "BUG: (?) do_become_nonbusy called with async=NULL\n");
- }
-
- s->busy = NULL;
-}
-
static int comedi_open(struct inode *inode, struct file *file)
{
const unsigned minor = iminor(inode);
- struct comedi_device_file_info *dev_file_info =
- comedi_get_device_file_info(minor);
- struct comedi_device *dev =
- dev_file_info ? dev_file_info->device : NULL;
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
- if (dev == NULL) {
+ if (!dev) {
DPRINTK("invalid minor number\n");
return -ENODEV;
}
@@ -2128,19 +2131,25 @@ ok:
return 0;
}
+static int comedi_fasync(int fd, struct file *file, int on)
+{
+ const unsigned minor = iminor(file->f_dentry->d_inode);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
+
+ if (!dev)
+ return -ENODEV;
+
+ return fasync_helper(fd, file, on, &dev->async_queue);
+}
+
static int comedi_close(struct inode *inode, struct file *file)
{
const unsigned minor = iminor(inode);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
struct comedi_subdevice *s = NULL;
int i;
- struct comedi_device_file_info *dev_file_info;
- struct comedi_device *dev;
- dev_file_info = comedi_get_device_file_info(minor);
- if (dev_file_info == NULL)
- return -ENODEV;
- dev = dev_file_info->device;
- if (dev == NULL)
+ if (!dev)
return -ENODEV;
mutex_lock(&dev->mutex);
@@ -2172,22 +2181,6 @@ static int comedi_close(struct inode *inode, struct file *file)
return 0;
}
-static int comedi_fasync(int fd, struct file *file, int on)
-{
- const unsigned minor = iminor(file->f_dentry->d_inode);
- struct comedi_device_file_info *dev_file_info;
- struct comedi_device *dev;
- dev_file_info = comedi_get_device_file_info(minor);
-
- if (dev_file_info == NULL)
- return -ENODEV;
- dev = dev_file_info->device;
- if (dev == NULL)
- return -ENODEV;
-
- return fasync_helper(fd, file, on, &dev->async_queue);
-}
-
static const struct file_operations comedi_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = comedi_unlocked_ioctl,
@@ -2205,99 +2198,6 @@ static const struct file_operations comedi_fops = {
static struct class *comedi_class;
static struct cdev comedi_cdev;
-static void comedi_cleanup_legacy_minors(void)
-{
- unsigned i;
-
- for (i = 0; i < comedi_num_legacy_minors; i++)
- comedi_free_board_minor(i);
-}
-
-static int __init comedi_init(void)
-{
- int i;
- int retval;
-
- pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
-
- if (comedi_num_legacy_minors < 0 ||
- comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
- pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n",
- COMEDI_NUM_BOARD_MINORS);
- return -EINVAL;
- }
-
- /*
- * comedi is unusable if both comedi_autoconfig and
- * comedi_num_legacy_minors are zero, so we might as well adjust the
- * defaults in that case
- */
- if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
- comedi_num_legacy_minors = 16;
-
- memset(comedi_file_info_table, 0,
- sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
-
- retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
- COMEDI_NUM_MINORS, "comedi");
- if (retval)
- return -EIO;
- cdev_init(&comedi_cdev, &comedi_fops);
- comedi_cdev.owner = THIS_MODULE;
- kobject_set_name(&comedi_cdev.kobj, "comedi");
- if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
- unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
- COMEDI_NUM_MINORS);
- return -EIO;
- }
- comedi_class = class_create(THIS_MODULE, "comedi");
- if (IS_ERR(comedi_class)) {
- pr_err("comedi: failed to create class\n");
- cdev_del(&comedi_cdev);
- unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
- COMEDI_NUM_MINORS);
- return PTR_ERR(comedi_class);
- }
-
- comedi_class->dev_attrs = comedi_dev_attrs;
-
- /* XXX requires /proc interface */
- comedi_proc_init();
-
- /* create devices files for legacy/manual use */
- for (i = 0; i < comedi_num_legacy_minors; i++) {
- int minor;
- minor = comedi_alloc_board_minor(NULL);
- if (minor < 0) {
- comedi_cleanup_legacy_minors();
- cdev_del(&comedi_cdev);
- unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
- COMEDI_NUM_MINORS);
- return minor;
- }
- }
-
- return 0;
-}
-
-static void __exit comedi_cleanup(void)
-{
- int i;
-
- comedi_cleanup_legacy_minors();
- for (i = 0; i < COMEDI_NUM_MINORS; ++i)
- BUG_ON(comedi_file_info_table[i]);
-
- class_destroy(comedi_class);
- cdev_del(&comedi_cdev);
- unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
-
- comedi_proc_cleanup();
-}
-
-module_init(comedi_init);
-module_exit(comedi_cleanup);
-
void comedi_error(const struct comedi_device *dev, const char *s)
{
dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
@@ -2312,7 +2212,7 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
/* DPRINTK("comedi_event 0x%x\n",mask); */
- if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
+ if (!comedi_is_subdevice_running(s))
return;
if (s->
@@ -2347,40 +2247,9 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
}
EXPORT_SYMBOL(comedi_event);
-unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
-{
- unsigned long flags;
- unsigned runflags;
-
- spin_lock_irqsave(&s->spin_lock, flags);
- runflags = s->runflags;
- spin_unlock_irqrestore(&s->spin_lock, flags);
- return runflags;
-}
-EXPORT_SYMBOL(comedi_get_subdevice_runflags);
-
-static int is_device_busy(struct comedi_device *dev)
-{
- struct comedi_subdevice *s;
- int i;
-
- if (!dev->attached)
- return 0;
-
- for (i = 0; i < dev->n_subdevices; i++) {
- s = &dev->subdevices[i];
- if (s->busy)
- return 1;
- if (s->async && s->async->mmap_count)
- return 1;
- }
-
- return 0;
-}
-
static void comedi_device_init(struct comedi_device *dev)
{
- memset(dev, 0, sizeof(struct comedi_device));
+ memset(dev, 0, sizeof(*dev));
spin_lock_init(&dev->spinlock);
mutex_init(&dev->mutex);
dev->minor = -1;
@@ -2398,11 +2267,11 @@ static void comedi_device_cleanup(struct comedi_device *dev)
int comedi_alloc_board_minor(struct device *hardware_device)
{
- struct comedi_device_file_info *info;
+ struct comedi_file_info *info;
struct device *csdev;
unsigned i;
- info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
@@ -2439,7 +2308,7 @@ int comedi_alloc_board_minor(struct device *hardware_device)
void comedi_free_board_minor(unsigned minor)
{
- struct comedi_device_file_info *info;
+ struct comedi_file_info *info;
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
spin_lock(&comedi_file_info_table_lock);
@@ -2464,7 +2333,7 @@ void comedi_free_board_minor(unsigned minor)
int comedi_find_board_minor(struct device *hardware_device)
{
int minor;
- struct comedi_device_file_info *info;
+ struct comedi_file_info *info;
for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
spin_lock(&comedi_file_info_table_lock);
@@ -2478,19 +2347,21 @@ int comedi_find_board_minor(struct device *hardware_device)
return -ENODEV;
}
-int comedi_alloc_subdevice_minor(struct comedi_device *dev,
- struct comedi_subdevice *s)
+int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
{
- struct comedi_device_file_info *info;
+ struct comedi_device *dev = s->device;
+ struct comedi_file_info *info;
struct device *csdev;
unsigned i;
- info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
- if (info == NULL)
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
return -ENOMEM;
info->device = dev;
- info->read_subdevice = s;
- info->write_subdevice = s;
+ if (s->subdev_flags & SDF_CMD_READ)
+ info->read_subdevice = s;
+ if (s->subdev_flags & SDF_CMD_WRITE)
+ info->write_subdevice = s;
spin_lock(&comedi_file_info_table_lock);
for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
@@ -2501,23 +2372,23 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev,
spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_MINORS) {
kfree(info);
- pr_err("comedi: error: ran out of minor numbers for board device files.\n");
+ pr_err("comedi: error: ran out of minor numbers for subdevice files.\n");
return -EBUSY;
}
s->minor = i;
csdev = device_create(comedi_class, dev->class_dev,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
- dev->minor, (int)(s - dev->subdevices));
+ dev->minor, s->index);
if (!IS_ERR(csdev))
s->class_dev = csdev;
dev_set_drvdata(csdev, info);
- return i;
+ return 0;
}
void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
- struct comedi_device_file_info *info;
+ struct comedi_file_info *info;
if (s == NULL)
return;
@@ -2539,14 +2410,90 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
kfree(info);
}
-struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
+static void comedi_cleanup_board_minors(void)
{
- struct comedi_device_file_info *info;
+ unsigned i;
- BUG_ON(minor >= COMEDI_NUM_MINORS);
- spin_lock(&comedi_file_info_table_lock);
- info = comedi_file_info_table[minor];
- spin_unlock(&comedi_file_info_table_lock);
- return info;
+ for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
+ comedi_free_board_minor(i);
+}
+
+static int __init comedi_init(void)
+{
+ int i;
+ int retval;
+
+ pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
+
+ if (comedi_num_legacy_minors < 0 ||
+ comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
+ pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n",
+ COMEDI_NUM_BOARD_MINORS);
+ return -EINVAL;
+ }
+
+ memset(comedi_file_info_table, 0,
+ sizeof(struct comedi_file_info *) * COMEDI_NUM_MINORS);
+
+ retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
+ COMEDI_NUM_MINORS, "comedi");
+ if (retval)
+ return -EIO;
+ cdev_init(&comedi_cdev, &comedi_fops);
+ comedi_cdev.owner = THIS_MODULE;
+ kobject_set_name(&comedi_cdev.kobj, "comedi");
+ if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
+ unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
+ COMEDI_NUM_MINORS);
+ return -EIO;
+ }
+ comedi_class = class_create(THIS_MODULE, "comedi");
+ if (IS_ERR(comedi_class)) {
+ pr_err("comedi: failed to create class\n");
+ cdev_del(&comedi_cdev);
+ unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
+ COMEDI_NUM_MINORS);
+ return PTR_ERR(comedi_class);
+ }
+
+ comedi_class->dev_attrs = comedi_dev_attrs;
+
+ /* XXX requires /proc interface */
+ comedi_proc_init();
+
+ /* create devices files for legacy/manual use */
+ for (i = 0; i < comedi_num_legacy_minors; i++) {
+ int minor;
+ minor = comedi_alloc_board_minor(NULL);
+ if (minor < 0) {
+ comedi_cleanup_board_minors();
+ cdev_del(&comedi_cdev);
+ unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
+ COMEDI_NUM_MINORS);
+ return minor;
+ }
+ }
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
+module_init(comedi_init);
+
+static void __exit comedi_cleanup(void)
+{
+ int i;
+
+ comedi_cleanup_board_minors();
+ for (i = 0; i < COMEDI_NUM_MINORS; ++i)
+ BUG_ON(comedi_file_info_table[i]);
+
+ class_destroy(comedi_class);
+ cdev_del(&comedi_cdev);
+ unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
+
+ comedi_proc_cleanup();
+}
+module_exit(comedi_cleanup);
+
+MODULE_AUTHOR("http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi core module");
+MODULE_LICENSE("GPL");