diff options
author | David Schleef <ds@schleef.org> | 2008-11-14 15:58:23 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 13:52:17 -0800 |
commit | b79a7a2089294cba254f6972e4e224fea643b84a (patch) | |
tree | 827331fb39d61f55beb1d49e117d9aa0601ab228 | |
parent | 02ebd471ea5b9950d3c30d75ec2f579f9ff0e918 (diff) |
Staging: comedi: add kcomedilib to the tree
This adds the kcomedilib module
From: David Schleef <ds@schleef.org>
Cc: Frank Mori Hess <fmhess@users.sourceforge.net>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/comedi/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/comedi/kcomedilib/Makefile | 8 | ||||
-rw-r--r-- | drivers/staging/comedi/kcomedilib/data.c | 89 | ||||
-rw-r--r-- | drivers/staging/comedi/kcomedilib/dio.c | 95 | ||||
-rw-r--r-- | drivers/staging/comedi/kcomedilib/get.c | 294 | ||||
-rw-r--r-- | drivers/staging/comedi/kcomedilib/kcomedilib_main.c | 567 | ||||
-rw-r--r-- | drivers/staging/comedi/kcomedilib/ksyms.c | 144 |
7 files changed, 1199 insertions, 0 deletions
diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile index 831d931e6ab..e91e8c7f2a8 100644 --- a/drivers/staging/comedi/Makefile +++ b/drivers/staging/comedi/Makefile @@ -1,6 +1,8 @@ obj-$(CONFIG_COMEDI) += comedi.o obj-$(CONFIG_COMEDI_RT) += comedi_rt.o +obj-$(CONFIG_COMEDI) += kcomedilib/ + comedi-objs := \ comedi_fops.o \ proc.o \ diff --git a/drivers/staging/comedi/kcomedilib/Makefile b/drivers/staging/comedi/kcomedilib/Makefile new file mode 100644 index 00000000000..ffcc9ad32ad --- /dev/null +++ b/drivers/staging/comedi/kcomedilib/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_COMEDI) += kcomedilib.o + +kcomedilib-objs := \ + data.o \ + ksyms.o \ + dio.o \ + kcomedilib_main.o \ + get.o diff --git a/drivers/staging/comedi/kcomedilib/data.c b/drivers/staging/comedi/kcomedilib/data.c new file mode 100644 index 00000000000..79aec204115 --- /dev/null +++ b/drivers/staging/comedi/kcomedilib/data.c @@ -0,0 +1,89 @@ +/* + kcomedilib/data.c + implements comedi_data_*() functions + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 2000 David A. Schleef <ds@schleef.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "../comedi.h" +#include "../comedilib.h" +#include "../comedidev.h" /* for comedi_udelay() */ + +#include <linux/string.h> + +int comedi_data_write(comedi_t * dev, unsigned int subdev, unsigned int chan, + unsigned int range, unsigned int aref, lsampl_t data) +{ + comedi_insn insn; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_WRITE; + insn.n = 1; + insn.data = &data; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, range, aref); + + return comedi_do_insn(dev, &insn); +} + +int comedi_data_read(comedi_t * dev, unsigned int subdev, unsigned int chan, + unsigned int range, unsigned int aref, lsampl_t * data) +{ + comedi_insn insn; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_READ; + insn.n = 1; + insn.data = data; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, range, aref); + + return comedi_do_insn(dev, &insn); +} + +int comedi_data_read_hint(comedi_t * dev, unsigned int subdev, + unsigned int chan, unsigned int range, unsigned int aref) +{ + comedi_insn insn; + lsampl_t dummy_data; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_READ; + insn.n = 0; + insn.data = &dummy_data; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, range, aref); + + return comedi_do_insn(dev, &insn); +} + +int comedi_data_read_delayed(comedi_t * dev, unsigned int subdev, + unsigned int chan, unsigned int range, unsigned int aref, + lsampl_t * data, unsigned int nano_sec) +{ + int retval; + + retval = comedi_data_read_hint(dev, subdev, chan, range, aref); + if (retval < 0) + return retval; + + comedi_udelay((nano_sec + 999) / 1000); + + return comedi_data_read(dev, subdev, chan, range, aref, data); +} diff --git a/drivers/staging/comedi/kcomedilib/dio.c b/drivers/staging/comedi/kcomedilib/dio.c new file mode 100644 index 00000000000..a9f488aed36 --- /dev/null +++ b/drivers/staging/comedi/kcomedilib/dio.c @@ -0,0 +1,95 @@ +/* + kcomedilib/dio.c + implements comedi_dio_*() functions + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 2000 David A. Schleef <ds@schleef.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "../comedi.h" +#include "../comedilib.h" + +#include <linux/string.h> + +int comedi_dio_config(comedi_t * dev, unsigned int subdev, unsigned int chan, + unsigned int io) +{ + comedi_insn insn; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_CONFIG; + insn.n = 1; + insn.data = &io; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, 0, 0); + + return comedi_do_insn(dev, &insn); +} + +int comedi_dio_read(comedi_t * dev, unsigned int subdev, unsigned int chan, + unsigned int *val) +{ + comedi_insn insn; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_READ; + insn.n = 1; + insn.data = val; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, 0, 0); + + return comedi_do_insn(dev, &insn); +} + +int comedi_dio_write(comedi_t * dev, unsigned int subdev, unsigned int chan, + unsigned int val) +{ + comedi_insn insn; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_WRITE; + insn.n = 1; + insn.data = &val; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, 0, 0); + + return comedi_do_insn(dev, &insn); +} + +int comedi_dio_bitfield(comedi_t * dev, unsigned int subdev, unsigned int mask, + unsigned int *bits) +{ + comedi_insn insn; + lsampl_t data[2]; + int ret; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_BITS; + insn.n = 2; + insn.data = data; + insn.subdev = subdev; + + data[0] = mask; + data[1] = *bits; + + ret = comedi_do_insn(dev, &insn); + + *bits = data[1]; + + return ret; +} diff --git a/drivers/staging/comedi/kcomedilib/get.c b/drivers/staging/comedi/kcomedilib/get.c new file mode 100644 index 00000000000..2004ad4480c --- /dev/null +++ b/drivers/staging/comedi/kcomedilib/get.c @@ -0,0 +1,294 @@ +/* + kcomedilib/get.c + a comedlib interface for kernel modules + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#define __NO_VERSION__ +#include "../comedi.h" +#include "../comedilib.h" +#include "../comedidev.h" + +int comedi_get_n_subdevices(comedi_t * d) +{ + comedi_device *dev = (comedi_device *) d; + + return dev->n_subdevices; +} + +int comedi_get_version_code(comedi_t * d) +{ + return COMEDI_VERSION_CODE; +} + +const char *comedi_get_driver_name(comedi_t * d) +{ + comedi_device *dev = (comedi_device *) d; + + return dev->driver->driver_name; +} + +const char *comedi_get_board_name(comedi_t * d) +{ + comedi_device *dev = (comedi_device *) d; + + return dev->board_name; +} + +int comedi_get_subdevice_type(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + + return s->type; +} + +unsigned int comedi_get_subdevice_flags(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + + return s->subdev_flags; +} + +int comedi_find_subdevice_by_type(comedi_t * d, int type, unsigned int subd) +{ + comedi_device *dev = (comedi_device *) d; + + if (subd > dev->n_subdevices) + return -ENODEV; + + for (; subd < dev->n_subdevices; subd++) { + if (dev->subdevices[subd].type == type) + return subd; + } + return -1; +} + +int comedi_get_n_channels(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + + return s->n_chan; +} + +int comedi_get_len_chanlist(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + + return s->len_chanlist; +} + +lsampl_t comedi_get_maxdata(comedi_t * d, unsigned int subdevice, + unsigned int chan) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + + if (s->maxdata_list) + return s->maxdata_list[chan]; + + return s->maxdata; +} + +#ifdef KCOMEDILIB_DEPRECATED +int comedi_get_rangetype(comedi_t * d, unsigned int subdevice, + unsigned int chan) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + int ret; + + if (s->range_table_list) { + ret = s->range_table_list[chan]->length; + } else { + ret = s->range_table->length; + } + + ret = ret | (dev->minor << 28) | (subdevice << 24) | (chan << 16); + + return ret; +} +#endif + +int comedi_get_n_ranges(comedi_t * d, unsigned int subdevice, unsigned int chan) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + int ret; + + if (s->range_table_list) { + ret = s->range_table_list[chan]->length; + } else { + ret = s->range_table->length; + } + + return ret; +} + +/* + * ALPHA (non-portable) +*/ +int comedi_get_krange(comedi_t * d, unsigned int subdevice, unsigned int chan, + unsigned int range, comedi_krange * krange) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + const comedi_lrange *lr; + + if (s->range_table_list) { + lr = s->range_table_list[chan]; + } else { + lr = s->range_table; + } + if (range >= lr->length) { + return -EINVAL; + } + memcpy(krange, lr->range + range, sizeof(comedi_krange)); + + return 0; +} + +/* + * ALPHA (may be renamed) +*/ +unsigned int comedi_get_buf_head_pos(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + comedi_async *async; + + async = s->async; + if (async == NULL) + return 0; + + return async->buf_write_count; +} + +int comedi_get_buffer_contents(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + comedi_async *async; + unsigned int num_bytes; + + if (subdevice >= dev->n_subdevices) + return -1; + async = s->async; + if (async == NULL) + return 0; + num_bytes = comedi_buf_read_n_available(s->async); + return num_bytes; +} + +/* + * ALPHA +*/ +int comedi_set_user_int_count(comedi_t * d, unsigned int subdevice, + unsigned int buf_user_count) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + comedi_async *async; + int num_bytes; + + async = s->async; + if (async == NULL) + return -1; + + num_bytes = buf_user_count - async->buf_read_count; + if (num_bytes < 0) + return -1; + comedi_buf_read_alloc(async, num_bytes); + comedi_buf_read_free(async, num_bytes); + + return 0; +} + +int comedi_mark_buffer_read(comedi_t * d, unsigned int subdevice, + unsigned int num_bytes) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + comedi_async *async; + + if (subdevice >= dev->n_subdevices) + return -1; + async = s->async; + if (async == NULL) + return -1; + + comedi_buf_read_alloc(async, num_bytes); + comedi_buf_read_free(async, num_bytes); + + return 0; +} + +int comedi_mark_buffer_written(comedi_t * d, unsigned int subdevice, + unsigned int num_bytes) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + comedi_async *async; + int bytes_written; + + if (subdevice >= dev->n_subdevices) + return -1; + async = s->async; + if (async == NULL) + return -1; + bytes_written = comedi_buf_write_alloc(async, num_bytes); + comedi_buf_write_free(async, bytes_written); + if (bytes_written != num_bytes) + return -1; + return 0; +} + +int comedi_get_buffer_size(comedi_t * d, unsigned int subdev) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdev; + comedi_async *async; + + if (subdev >= dev->n_subdevices) + return -1; + async = s->async; + if (async == NULL) + return 0; + + return async->prealloc_bufsz; +} + +int comedi_get_buffer_offset(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices + subdevice; + comedi_async *async; + + if (subdevice >= dev->n_subdevices) + return -1; + async = s->async; + if (async == NULL) + return 0; + + return async->buf_read_ptr; +} diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c new file mode 100644 index 00000000000..510fbdcec49 --- /dev/null +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -0,0 +1,567 @@ +/* + kcomedilib/kcomedilib.c + a comedlib interface for kernel modules + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#define __NO_VERSION__ +#include <linux/module.h> + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/fcntl.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/io.h> + +#include "../comedi.h" +#include "../comedilib.h" +#include "../comedidev.h" + +MODULE_AUTHOR("David Schleef <ds@schleef.org>"); +MODULE_DESCRIPTION("Comedi kernel library"); +MODULE_LICENSE("GPL"); + +comedi_t *comedi_open(const char *filename) +{ + struct comedi_device_file_info *dev_file_info; + comedi_device *dev; + unsigned int minor; + + if (strncmp(filename, "/dev/comedi", 11) != 0) + return NULL; + + minor = simple_strtoul(filename + 11, NULL, 0); + + if (minor >= COMEDI_NUM_BOARD_MINORS) + return NULL; + + dev_file_info = comedi_get_device_file_info(minor); + if(dev_file_info == NULL) + return NULL; + dev = dev_file_info->device; + + if(dev == NULL || !dev->attached) + return NULL; + + if (!try_module_get(dev->driver->module)) + return NULL; + + return (comedi_t *) dev; +} + +comedi_t *comedi_open_old(unsigned int minor) +{ + struct comedi_device_file_info *dev_file_info; + comedi_device *dev; + + if (minor >= COMEDI_NUM_MINORS) + return NULL; + + dev_file_info = comedi_get_device_file_info(minor); + if(dev_file_info == NULL) + return NULL; + dev = dev_file_info->device; + + if(dev == NULL || !dev->attached) + return NULL; + + return (comedi_t *) dev; +} + +int comedi_close(comedi_t * d) +{ + comedi_device *dev = (comedi_device *) d; + + module_put(dev->driver->module); + + return 0; +} + +int comedi_loglevel(int newlevel) +{ + return 0; +} + +void comedi_perror(const char *message) +{ + rt_printk("%s: unknown error\n", message); +} + +char *comedi_strerror(int err) +{ + return "unknown error"; +} + +int comedi_fileno(comedi_t * d) +{ + comedi_device *dev = (comedi_device *) d; + + /* return something random */ + return dev->minor; +} + +int comedi_command(comedi_t * d, comedi_cmd * cmd) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + comedi_async *async; + unsigned runflags; + + if (cmd->subdev >= dev->n_subdevices) + return -ENODEV; + + s = dev->subdevices + cmd->subdev; + if (s->type == COMEDI_SUBD_UNUSED) + return -EIO; + + async = s->async; + if (async == NULL) + return -ENODEV; + + if (s->busy) + return -EBUSY; + s->busy = d; + + if (async->cb_mask & COMEDI_CB_EOS) + cmd->flags |= TRIG_WAKE_EOS; + + async->cmd = *cmd; + + runflags = SRF_RUNNING; + +#ifdef CONFIG_COMEDI_RT + if (comedi_switch_to_rt(dev) == 0) + runflags |= SRF_RT; +#endif + comedi_set_subdevice_runflags(s, ~0, runflags); + + comedi_reset_async_buf(async); + + return s->do_cmd(dev, s); +} + +int comedi_command_test(comedi_t * d, comedi_cmd * cmd) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + + if (cmd->subdev >= dev->n_subdevices) + return -ENODEV; + + s = dev->subdevices + cmd->subdev; + if (s->type == COMEDI_SUBD_UNUSED) + return -EIO; + + if (s->async == NULL) + return -ENODEV; + + return s->do_cmdtest(dev, s, cmd); +} + +/* + * COMEDI_INSN + * perform an instruction + */ +int comedi_do_insn(comedi_t * d, comedi_insn * insn) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + int ret = 0; + + if (insn->insn & INSN_MASK_SPECIAL) { + switch (insn->insn) { + case INSN_GTOD: + { + struct timeval tv; + + do_gettimeofday(&tv); + insn->data[0] = tv.tv_sec; + insn->data[1] = tv.tv_usec; + ret = 2; + + break; + } + case INSN_WAIT: + /* XXX isn't the value supposed to be nanosecs? */ + if (insn->n != 1 || insn->data[0] >= 100) { + ret = -EINVAL; + break; + } + comedi_udelay(insn->data[0]); + ret = 1; + break; + case INSN_INTTRIG: + if (insn->n != 1) { + ret = -EINVAL; + break; + } + if (insn->subdev >= dev->n_subdevices) { + rt_printk("%d not usable subdevice\n", + insn->subdev); + ret = -EINVAL; + break; + } + s = dev->subdevices + insn->subdev; + if (!s->async) { + rt_printk("no async\n"); + ret = -EINVAL; + break; + } + if (!s->async->inttrig) { + rt_printk("no inttrig\n"); + ret = -EAGAIN; + break; + } + ret = s->async->inttrig(dev, s, insn->data[0]); + if (ret >= 0) + ret = 1; + break; + default: + ret = -EINVAL; + } + } else { + /* a subdevice instruction */ + if (insn->subdev >= dev->n_subdevices) { + ret = -EINVAL; + goto error; + } + s = dev->subdevices + insn->subdev; + + if (s->type == COMEDI_SUBD_UNUSED) { + rt_printk("%d not useable subdevice\n", insn->subdev); + ret = -EIO; + goto error; + } + + /* XXX check lock */ + + if ((ret = check_chanlist(s, 1, &insn->chanspec)) < 0) { + rt_printk("bad chanspec\n"); + ret = -EINVAL; + goto error; + } + + if (s->busy) { + ret = -EBUSY; + goto error; + } + s->busy = d; + + switch (insn->insn) { + case INSN_READ: + ret = s->insn_read(dev, s, insn, insn->data); + break; + case INSN_WRITE: + ret = s->insn_write(dev, s, insn, insn->data); + break; + case INSN_BITS: + ret = s->insn_bits(dev, s, insn, insn->data); + break; + case INSN_CONFIG: + /* XXX should check instruction length */ + ret = s->insn_config(dev, s, insn, insn->data); + break; + default: + ret = -EINVAL; + break; + } + + s->busy = NULL; + } + if (ret < 0) + goto error; +#if 0 + /* XXX do we want this? -- abbotti #if'ed it out for now. */ + if (ret != insn->n) { + rt_printk("BUG: result of insn != insn.n\n"); + ret = -EINVAL; + goto error; + } +#endif + error: + + return ret; +} + +/* + COMEDI_LOCK + lock subdevice + + arg: + subdevice number + + reads: + none + + writes: + none + + necessary locking: + - ioctl/rt lock (this type) + - lock while subdevice busy + - lock while subdevice being programmed + +*/ +int comedi_lock(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + unsigned long flags; + int ret = 0; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + comedi_spin_lock_irqsave(&s->spin_lock, flags); + + if (s->busy) { + ret = -EBUSY; + } else { + if (s->lock) { + ret = -EBUSY; + } else { + s->lock = d; + } + } + + comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + + return ret; +} + +/* + COMEDI_UNLOCK + unlock subdevice + + arg: + subdevice number + + reads: + none + + writes: + none + +*/ +int comedi_unlock(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + unsigned long flags; + comedi_async *async; + int ret; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + async = s->async; + + comedi_spin_lock_irqsave(&s->spin_lock, flags); + + if (s->busy) { + ret = -EBUSY; + } else if (s->lock && s->lock != (void *)d) { + ret = -EACCES; + } else { + s->lock = NULL; + + if (async) { + async->cb_mask = 0; + async->cb_func = NULL; + async->cb_arg = NULL; + } + + ret = 0; + } + + comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + + return ret; +} + +/* + COMEDI_CANCEL + cancel acquisition ioctl + + arg: + subdevice number + + reads: + nothing + + writes: + nothing + +*/ +int comedi_cancel(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + int ret = 0; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + if (s->lock && s->lock != d) + return -EACCES; + +#if 0 + if (!s->busy) + return 0; + + if (s->busy != d) + return -EBUSY; +#endif + + if (!s->cancel || !s->async) + return -EINVAL; + + if ((ret = s->cancel(dev, s))) + return ret; + +#ifdef CONFIG_COMEDI_RT + if (comedi_get_subdevice_runflags(s) & SRF_RT) { + comedi_switch_to_non_rt(dev); + } +#endif + comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0); + s->async->inttrig = NULL; + s->busy = NULL; + + return 0; +} + +/* + registration of callback functions + */ +int comedi_register_callback(comedi_t * d, unsigned int subdevice, + unsigned int mask, int (*cb) (unsigned int, void *), void *arg) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + comedi_async *async; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + async = s->async; + if (s->type == COMEDI_SUBD_UNUSED || !async) + return -EIO; + + /* are we locked? (ioctl lock) */ + if (s->lock && s->lock != d) + return -EACCES; + + /* are we busy? */ + if (s->busy) + return -EBUSY; + + if (!mask) { + async->cb_mask = 0; + async->cb_func = NULL; + async->cb_arg = NULL; + } else { + async->cb_mask = mask; + async->cb_func = cb; + async->cb_arg = arg; + } + + return 0; +} + +int comedi_poll(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s = dev->subdevices; + comedi_async *async; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + async = s->async; + if (s->type == COMEDI_SUBD_UNUSED || !async) + return -EIO; + + /* are we locked? (ioctl lock) */ + if (s->lock && s->lock != d) + return -EACCES; + + /* are we running? XXX wrong? */ + if (!s->busy) + return -EIO; + + return s->poll(dev, s); +} + +/* WARNING: not portable */ +int comedi_map(comedi_t * d, unsigned int subdevice, void *ptr) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + if (!s->async) + return -EINVAL; + + if (ptr) { + *((void **)ptr) = s->async->prealloc_buf; + } + + /* XXX no reference counting */ + + return 0; +} + +/* WARNING: not portable */ +int comedi_unmap(comedi_t * d, unsigned int subdevice) +{ + comedi_device *dev = (comedi_device *) d; + comedi_subdevice *s; + + if (subdevice >= dev->n_subdevices) { + return -EINVAL; + } + s = dev->subdevices + subdevice; + + if (!s->async) + return -EINVAL; + + /* XXX no reference counting */ + + return 0; +} diff --git a/drivers/staging/comedi/kcomedilib/ksyms.c b/drivers/staging/comedi/kcomedilib/ksyms.c new file mode 100644 index 00000000000..76b45063a9f --- /dev/null +++ b/drivers/staging/comedi/kcomedilib/ksyms.c @@ -0,0 +1,144 @@ +/* + comedi/kcomedilib/ksyms.c + a comedlib interface for kernel modules + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include "../comedi.h" +#include "../comedilib.h" +#include "../comedidev.h" + +#include <linux/module.h> + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/fcntl.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> + +#if LINUX_VERSION_CODE >= 0x020200 + +/* functions specific to kcomedilib */ + +EXPORT_SYMBOL(comedi_register_callback); +EXPORT_SYMBOL(comedi_get_krange); +EXPORT_SYMBOL(comedi_get_buf_head_pos); +EXPORT_SYMBOL(comedi_set_user_int_count); +EXPORT_SYMBOL(comedi_map); +EXPORT_SYMBOL(comedi_unmap); + +/* This list comes from user-space comedilib, to show which + * functions are not ported yet. */ + +EXPORT_SYMBOL(comedi_open); +EXPORT_SYMBOL(comedi_close); + +/* logging */ +EXPORT_SYMBOL(comedi_loglevel); +EXPORT_SYMBOL(comedi_perror); +EXPORT_SYMBOL(comedi_strerror); +//EXPORT_SYMBOL(comedi_errno); +EXPORT_SYMBOL(comedi_fileno); + +/* device queries */ +EXPORT_SYMBOL(comedi_get_n_subdevices); +EXPORT_SYMBOL(comedi_get_version_code); +EXPORT_SYMBOL(comedi_get_driver_name); +EXPORT_SYMBOL(comedi_get_board_name); + +/* subdevice queries */ +EXPORT_SYMBOL(comedi_get_subdevice_type); +EXPORT_SYMBOL(comedi_find_subdevice_by_type); +EXPORT_SYMBOL(comedi_get_subdevice_flags); +EXPORT_SYMBOL(comedi_get_n_channels); +//EXPORT_SYMBOL(comedi_range_is_chan_specific); +//EXPORT_SYMBOL(comedi_maxdata_is_chan_specific); + +/* channel queries */ +EXPORT_SYMBOL(comedi_get_maxdata); +#ifdef KCOMEDILIB_DEPRECATED +EXPORT_SYMBOL(comedi_get_rangetype); +#endif +EXPORT_SYMBOL(comedi_get_n_ranges); +//EXPORT_SYMBOL(comedi_find_range); + +/* buffer queries */ +EXPORT_SYMBOL(comedi_get_buffer_size); +//EXPORT_SYMBOL(comedi_get_max_buffer_size); +//EXPORT_SYMBOL(comedi_set_buffer_size); +EXPORT_SYMBOL(comedi_get_buffer_contents); +EXPORT_SYMBOL(comedi_get_buffer_offset); + +/* low-level stuff */ +//EXPORT_SYMBOL(comedi_trigger); +//EXPORT_SYMBOL(comedi_do_insnlist); +EXPORT_SYMBOL(comedi_do_insn); +EXPORT_SYMBOL(comedi_lock); +EXPORT_SYMBOL(comedi_unlock); + +/* physical units */ +//EXPORT_SYMBOL(comedi_to_phys); +//EXPORT_SYMBOL(comedi_from_phys); + +/* synchronous stuff */ +EXPORT_SYMBOL(comedi_data_read); +EXPORT_SYMBOL(comedi_data_read_hint); +EXPORT_SYMBOL(comedi_data_read_delayed); +EXPORT_SYMBOL(comedi_data_write); +EXPORT_SYMBOL(comedi_dio_config); +EXPORT_SYMBOL(comedi_dio_read); +EXPORT_SYMBOL(comedi_dio_write); +EXPORT_SYMBOL(comedi_dio_bitfield); + +/* slowly varying stuff */ +//EXPORT_SYMBOL(comedi_sv_init); +//EXPORT_SYMBOL(comedi_sv_update); +//EXPORT_SYMBOL(comedi_sv_measure); + +/* commands */ +//EXPORT_SYMBOL(comedi_get_cmd_src_mask); +//EXPORT_SYMBOL(comedi_get_cmd_generic_timed); +EXPORT_SYMBOL(comedi_cancel); +EXPORT_SYMBOL(comedi_command); +EXPORT_SYMBOL(comedi_command_test); +EXPORT_SYMBOL(comedi_poll); + +/* buffer configuration */ +EXPORT_SYMBOL(comedi_mark_buffer_read); +EXPORT_SYMBOL(comedi_mark_buffer_written); + +//EXPORT_SYMBOL(comedi_get_range); +EXPORT_SYMBOL(comedi_get_len_chanlist); + +/* deprecated */ +//EXPORT_SYMBOL(comedi_get_timer); +//EXPORT_SYMBOL(comedi_timed_1chan); + +/* alpha */ +//EXPORT_SYMBOL(comedi_set_global_oor_behavior); + +#endif |