Staging: add comedi core

This adds the Comedi core to the staging tree.
This is a data acquision infrastructure for Linux, providing a common
interface for these types of drivers.

Taken directly from the comedi git tree, with only minor tweaks
by Greg to get it to build properly within the kernel tree.

From: David Schleef <ds@schleef.org>
Cc: Ian Abbott <abbotti@mev.co.uk>
Cc: Shawn Bohrer <shawn.bohrer@gmail.com>
Signed-off-by: Frank Mori Hess <fmhess@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
David Schleef
2008-11-04 20:29:31 -08:00
committed by Greg Kroah-Hartman
parent 535deaa35e
commit ed9eccbe89
21 changed files with 6460 additions and 0 deletions

View File

@@ -71,5 +71,7 @@ source "drivers/staging/rt2860/Kconfig"
source "drivers/staging/benet/Kconfig"
source "drivers/staging/comedi/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING

View File

@@ -18,3 +18,4 @@ obj-$(CONFIG_AGNX) += agnx/
obj-$(CONFIG_OTUS) += otus/
obj-$(CONFIG_RT2860) += rt2860/
obj-$(CONFIG_BENET) += benet/
obj-$(CONFIG_COMEDI) += comedi/

View File

@@ -0,0 +1,13 @@
config COMEDI
tristate "Data Acquision support (comedi)"
default N
---help---
Enable support a wide range of data acquision devices
for Linux.
config COMEDI_RT
tristate "Comedi Real-time support"
depends on COMEDI && RT
default N
---help---
Enable Real time support for the Comedi core.

View File

@@ -0,0 +1,14 @@
obj-$(CONFIG_COMEDI) += comedi.o
obj-$(CONFIG_COMEDI_RT) += comedi_rt.o
comedi-objs := \
comedi_fops.o \
proc.o \
range.o \
drivers.o \
comedi_compat32.o \
comedi_ksyms.o \
comedi_rt-objs := \
rt_pend_tq.o \
rt.o

View File

@@ -0,0 +1,14 @@
TODO:
- checkpatch.pl cleanups
- Lindent
- remove all wrappers
- remove typedefs
- audit userspace interface
- reserve major number
- cleanup the individual comedi drivers as well
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
copy:
Ian Abbott <abbotti@mev.co.uk>
Frank Mori Hess <fmhess@users.sourceforge.net>
David Schleef <ds@schleef.org>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
/*
comedi/comedi_compat32.h
32-bit ioctl compatibility for 64-bit comedi kernel module.
Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1997-2007 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 _COMEDI_COMPAT32_H
#define _COMEDI_COMPAT32_H
#include <linux/compat.h>
#include <linux/fs.h> /* For HAVE_COMPAT_IOCTL and HAVE_UNLOCKED_IOCTL */
#ifdef CONFIG_COMPAT
#ifdef HAVE_COMPAT_IOCTL
extern long comedi_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
#define comedi_register_ioctl32() do{}while(0)
#define comedi_unregister_ioctl32() do{}while(0)
#else /* HAVE_COMPAT_IOCTL */
#define comedi_compat_ioctl 0 /* NULL */
extern void comedi_register_ioctl32(void);
extern void comedi_unregister_ioctl32(void);
#endif /* HAVE_COMPAT_IOCTL */
#else /* CONFIG_COMPAT */
#define comedi_compat_ioctl 0 /* NULL */
#define comedi_register_ioctl32() do{}while(0)
#define comedi_unregister_ioctl32() do{}while(0)
#endif /* CONFIG_COMPAT */
#endif /* _COMEDI_COMPAT32_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
#ifndef _COMEDI_FOPS_H
#define _COMEDI_FOPS_H
extern struct class *comedi_class;
extern const struct file_operations comedi_fops;
#endif //_COMEDI_FOPS_H

View File

@@ -0,0 +1,77 @@
/*
module/exp_ioctl.c
exported comedi functions
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1997-8 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__
#ifndef EXPORT_SYMTAB
#define EXPORT_SYMTAB
#endif
#include "comedidev.h"
/* for drivers */
EXPORT_SYMBOL(comedi_driver_register);
EXPORT_SYMBOL(comedi_driver_unregister);
//EXPORT_SYMBOL(comedi_bufcheck);
//EXPORT_SYMBOL(comedi_done);
//EXPORT_SYMBOL(comedi_error_done);
EXPORT_SYMBOL(comedi_error);
//EXPORT_SYMBOL(comedi_eobuf);
//EXPORT_SYMBOL(comedi_eos);
EXPORT_SYMBOL(comedi_event);
EXPORT_SYMBOL(comedi_get_subdevice_runflags);
EXPORT_SYMBOL(comedi_set_subdevice_runflags);
EXPORT_SYMBOL(range_bipolar10);
EXPORT_SYMBOL(range_bipolar5);
EXPORT_SYMBOL(range_bipolar2_5);
EXPORT_SYMBOL(range_unipolar10);
EXPORT_SYMBOL(range_unipolar5);
EXPORT_SYMBOL(range_unknown);
#ifdef CONFIG_COMEDI_RT
EXPORT_SYMBOL(comedi_free_irq);
EXPORT_SYMBOL(comedi_request_irq);
EXPORT_SYMBOL(comedi_switch_to_rt);
EXPORT_SYMBOL(comedi_switch_to_non_rt);
EXPORT_SYMBOL(rt_pend_call);
#endif
#ifdef CONFIG_COMEDI_DEBUG
EXPORT_SYMBOL(comedi_debug);
#endif
EXPORT_SYMBOL_GPL(comedi_alloc_board_minor);
EXPORT_SYMBOL_GPL(comedi_free_board_minor);
EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
/* for kcomedilib */
EXPORT_SYMBOL(check_chanlist);
EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
EXPORT_SYMBOL(comedi_buf_put);
EXPORT_SYMBOL(comedi_buf_get);
EXPORT_SYMBOL(comedi_buf_read_n_available);
EXPORT_SYMBOL(comedi_buf_write_free);
EXPORT_SYMBOL(comedi_buf_write_alloc);
EXPORT_SYMBOL(comedi_buf_read_free);
EXPORT_SYMBOL(comedi_buf_read_alloc);
EXPORT_SYMBOL(comedi_buf_memcpy_to);
EXPORT_SYMBOL(comedi_buf_memcpy_from);
EXPORT_SYMBOL(comedi_reset_async_buf);

View File

@@ -0,0 +1,150 @@
/*
module/comedi_rt.h
header file for real-time structures, variables, and constants
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.
*/
#ifndef _COMEDI_RT_H
#define _COMEDI_RT_H
#ifndef _COMEDIDEV_H
#error comedi_rt.h should only be included by comedidev.h
#endif
#include <linux/version.h>
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#ifdef CONFIG_COMEDI_RT
#ifdef CONFIG_COMEDI_RTAI
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_version.h>
#endif
#ifdef CONFIG_COMEDI_RTL
#include <rtl_core.h>
#include <rtl_time.h>
//#ifdef RTLINUX_VERSION_CODE
#include <rtl_sync.h>
//#endif
#define rt_printk rtl_printf
#endif
#ifdef CONFIG_COMEDI_FUSION
#define rt_printk(format, args...) printk(format , ## args )
#endif /* CONFIG_COMEDI_FUSION */
#ifdef CONFIG_PRIORITY_IRQ
#define rt_printk printk
#endif
int comedi_request_irq(unsigned int irq, irqreturn_t(*handler) (int,
void *PT_REGS_ARG), unsigned long flags, const char *device,
comedi_device * dev_id);
void comedi_free_irq(unsigned int irq, comedi_device * dev_id);
void comedi_rt_init(void);
void comedi_rt_cleanup(void);
int comedi_switch_to_rt(comedi_device * dev);
void comedi_switch_to_non_rt(comedi_device * dev);
void comedi_rt_pend_wakeup(wait_queue_head_t * q);
extern int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1,
void *arg2);
#else
#define comedi_request_irq(a,b,c,d,e) request_irq(a,b,c,d,e)
#define comedi_free_irq(a,b) free_irq(a,b)
#define comedi_rt_init() do{}while(0)
#define comedi_rt_cleanup() do{}while(0)
#define comedi_switch_to_rt(a) (-1)
#define comedi_switch_to_non_rt(a) do{}while(0)
#define comedi_rt_pend_wakeup(a) do{}while(0)
#define rt_printk(format,args...) printk(format,##args)
#endif
/* Define a spin_lock_irqsave function that will work with rt or without.
* Use inline functions instead of just macros to enforce some type checking.
*/
#define comedi_spin_lock_irqsave(lock_ptr, flags) \
(flags = __comedi_spin_lock_irqsave(lock_ptr))
static inline unsigned long __comedi_spin_lock_irqsave(spinlock_t * lock_ptr)
{
unsigned long flags;
#if defined(CONFIG_COMEDI_RTAI)
flags = rt_spin_lock_irqsave(lock_ptr);
#elif defined(CONFIG_COMEDI_RTL)
rtl_spin_lock_irqsave(lock_ptr, flags);
#elif defined(CONFIG_COMEDI_RTL_V1)
rtl_spin_lock_irqsave(lock_ptr, flags);
#elif defined(CONFIG_COMEDI_FUSION)
rthal_spin_lock_irqsave(lock_ptr, flags);
#else
spin_lock_irqsave(lock_ptr, flags);
#endif
return flags;
}
static inline void comedi_spin_unlock_irqrestore(spinlock_t * lock_ptr,
unsigned long flags)
{
#if defined(CONFIG_COMEDI_RTAI)
rt_spin_unlock_irqrestore(flags, lock_ptr);
#elif defined(CONFIG_COMEDI_RTL)
rtl_spin_unlock_irqrestore(lock_ptr, flags);
#elif defined(CONFIG_COMEDI_RTL_V1)
rtl_spin_unlock_irqrestore(lock_ptr, flags);
#elif defined(CONFIG_COMEDI_FUSION)
rthal_spin_unlock_irqrestore(lock_ptr, flags);
#else
spin_unlock_irqrestore(lock_ptr, flags);
#endif
}
/* define a RT safe udelay */
static inline void comedi_udelay(unsigned int usec)
{
#if defined(CONFIG_COMEDI_RTAI)
static const int nanosec_per_usec = 1000;
rt_busy_sleep(usec * nanosec_per_usec);
#elif defined(CONFIG_COMEDI_RTL)
static const int nanosec_per_usec = 1000;
rtl_delay(usec * nanosec_per_usec);
#else
udelay(usec);
#endif
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
/*
linux/include/comedilib.h
header file for kcomedilib
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1998-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 _LINUX_COMEDILIB_H
#define _LINUX_COMEDILIB_H
#include <linux/comedi.h>
/* Kernel internal stuff. Needed by real-time modules and such. */
#ifndef __KERNEL__
#error linux/comedilib.h should not be included by non-kernel-space code
#endif
/* exported functions */
#ifndef KCOMEDILIB_DEPRECATED
typedef void comedi_t;
/* these functions may not be called at real-time priority */
comedi_t *comedi_open(const char *path);
int comedi_close(comedi_t * dev);
/* these functions may be called at any priority, but may fail at
real-time priority */
int comedi_lock(comedi_t * dev, unsigned int subdev);
int comedi_unlock(comedi_t * dev, unsigned int subdev);
/* these functions may be called at any priority, but you must hold
the lock for the subdevice */
int comedi_loglevel(int loglevel);
void comedi_perror(const char *s);
char *comedi_strerror(int errnum);
int comedi_errno(void);
int comedi_fileno(comedi_t * dev);
int comedi_cancel(comedi_t * dev, unsigned int subdev);
int comedi_register_callback(comedi_t * dev, unsigned int subdev,
unsigned int mask, int (*cb) (unsigned int, void *), void *arg);
int comedi_command(comedi_t * dev, comedi_cmd * cmd);
int comedi_command_test(comedi_t * dev, comedi_cmd * cmd);
int comedi_trigger(comedi_t * dev, unsigned int subdev, comedi_trig * it);
int __comedi_trigger(comedi_t * dev, unsigned int subdev, comedi_trig * it);
int comedi_data_write(comedi_t * dev, unsigned int subdev, unsigned int chan,
unsigned int range, unsigned int aref, lsampl_t data);
int comedi_data_read(comedi_t * dev, unsigned int subdev, unsigned int chan,
unsigned int range, unsigned int aref, lsampl_t * data);
int comedi_data_read_hint(comedi_t * dev, unsigned int subdev,
unsigned int chan, unsigned int range, unsigned int aref);
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 comedi_dio_config(comedi_t * dev, unsigned int subdev, unsigned int chan,
unsigned int io);
int comedi_dio_read(comedi_t * dev, unsigned int subdev, unsigned int chan,
unsigned int *val);
int comedi_dio_write(comedi_t * dev, unsigned int subdev, unsigned int chan,
unsigned int val);
int comedi_dio_bitfield(comedi_t * dev, unsigned int subdev, unsigned int mask,
unsigned int *bits);
int comedi_get_n_subdevices(comedi_t * dev);
int comedi_get_version_code(comedi_t * dev);
const char *comedi_get_driver_name(comedi_t * dev);
const char *comedi_get_board_name(comedi_t * dev);
int comedi_get_subdevice_type(comedi_t * dev, unsigned int subdevice);
int comedi_find_subdevice_by_type(comedi_t * dev, int type, unsigned int subd);
int comedi_get_n_channels(comedi_t * dev, unsigned int subdevice);
lsampl_t comedi_get_maxdata(comedi_t * dev, unsigned int subdevice, unsigned
int chan);
int comedi_get_n_ranges(comedi_t * dev, unsigned int subdevice, unsigned int
chan);
int comedi_do_insn(comedi_t * dev, comedi_insn * insn);
int comedi_poll(comedi_t * dev, unsigned int subdev);
/* DEPRECATED functions */
int comedi_get_rangetype(comedi_t * dev, unsigned int subdevice,
unsigned int chan);
/* ALPHA functions */
unsigned int comedi_get_subdevice_flags(comedi_t * dev, unsigned int subdevice);
int comedi_get_len_chanlist(comedi_t * dev, unsigned int subdevice);
int comedi_get_krange(comedi_t * dev, unsigned int subdevice, unsigned int
chan, unsigned int range, comedi_krange * krange);
unsigned int comedi_get_buf_head_pos(comedi_t * dev, unsigned int subdevice);
int comedi_set_user_int_count(comedi_t * dev, unsigned int subdevice,
unsigned int buf_user_count);
int comedi_map(comedi_t * dev, unsigned int subdev, void *ptr);
int comedi_unmap(comedi_t * dev, unsigned int subdev);
int comedi_get_buffer_size(comedi_t * dev, unsigned int subdev);
int comedi_mark_buffer_read(comedi_t * dev, unsigned int subdevice,
unsigned int num_bytes);
int comedi_mark_buffer_written(comedi_t * d, unsigned int subdevice,
unsigned int num_bytes);
int comedi_get_buffer_contents(comedi_t * dev, unsigned int subdevice);
int comedi_get_buffer_offset(comedi_t * dev, unsigned int subdevice);
#else
/* these functions may not be called at real-time priority */
int comedi_open(unsigned int minor);
void comedi_close(unsigned int minor);
/* these functions may be called at any priority, but may fail at
real-time priority */
int comedi_lock(unsigned int minor, unsigned int subdev);
int comedi_unlock(unsigned int minor, unsigned int subdev);
/* these functions may be called at any priority, but you must hold
the lock for the subdevice */
int comedi_cancel(unsigned int minor, unsigned int subdev);
int comedi_register_callback(unsigned int minor, unsigned int subdev,
unsigned int mask, int (*cb) (unsigned int, void *), void *arg);
int comedi_command(unsigned int minor, comedi_cmd * cmd);
int comedi_command_test(unsigned int minor, comedi_cmd * cmd);
int comedi_trigger(unsigned int minor, unsigned int subdev, comedi_trig * it);
int __comedi_trigger(unsigned int minor, unsigned int subdev, comedi_trig * it);
int comedi_data_write(unsigned int dev, unsigned int subdev, unsigned int chan,
unsigned int range, unsigned int aref, lsampl_t data);
int comedi_data_read(unsigned int dev, unsigned int subdev, unsigned int chan,
unsigned int range, unsigned int aref, lsampl_t * data);
int comedi_dio_config(unsigned int dev, unsigned int subdev, unsigned int chan,
unsigned int io);
int comedi_dio_read(unsigned int dev, unsigned int subdev, unsigned int chan,
unsigned int *val);
int comedi_dio_write(unsigned int dev, unsigned int subdev, unsigned int chan,
unsigned int val);
int comedi_dio_bitfield(unsigned int dev, unsigned int subdev,
unsigned int mask, unsigned int *bits);
int comedi_get_n_subdevices(unsigned int dev);
int comedi_get_version_code(unsigned int dev);
char *comedi_get_driver_name(unsigned int dev);
char *comedi_get_board_name(unsigned int minor);
int comedi_get_subdevice_type(unsigned int minor, unsigned int subdevice);
int comedi_find_subdevice_by_type(unsigned int minor, int type,
unsigned int subd);
int comedi_get_n_channels(unsigned int minor, unsigned int subdevice);
lsampl_t comedi_get_maxdata(unsigned int minor, unsigned int subdevice, unsigned
int chan);
int comedi_get_n_ranges(unsigned int minor, unsigned int subdevice, unsigned int
chan);
int comedi_do_insn(unsigned int minor, comedi_insn * insn);
int comedi_poll(unsigned int minor, unsigned int subdev);
/* DEPRECATED functions */
int comedi_get_rangetype(unsigned int minor, unsigned int subdevice,
unsigned int chan);
/* ALPHA functions */
unsigned int comedi_get_subdevice_flags(unsigned int minor, unsigned int
subdevice);
int comedi_get_len_chanlist(unsigned int minor, unsigned int subdevice);
int comedi_get_krange(unsigned int minor, unsigned int subdevice, unsigned int
chan, unsigned int range, comedi_krange * krange);
unsigned int comedi_get_buf_head_pos(unsigned int minor, unsigned int
subdevice);
int comedi_set_user_int_count(unsigned int minor, unsigned int subdevice,
unsigned int buf_user_count);
int comedi_map(unsigned int minor, unsigned int subdev, void **ptr);
int comedi_unmap(unsigned int minor, unsigned int subdev);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
/*
module/proc.c
/proc interface for comedi
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1998 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.
*/
/*
This is some serious bloatware.
Taken from Dave A.'s PCL-711 driver, 'cuz I thought it
was cool.
*/
#define __NO_VERSION__
#include "comedidev.h"
#include <linux/proc_fs.h>
//#include <linux/string.h>
int comedi_read_procmem(char *buf, char **start, off_t offset, int len,
int *eof, void *data);
extern comedi_driver *comedi_drivers;
int comedi_read_procmem(char *buf, char **start, off_t offset, int len,
int *eof, void *data)
{
int i;
int devices_q = 0;
int l = 0;
comedi_driver *driv;
l += sprintf(buf + l,
"comedi version " COMEDI_RELEASE "\n"
"format string: %s\n",
"\"%2d: %-20s %-20s %4d\",i,driver_name,board_name,n_subdevices");
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(i);
comedi_device *dev;
if(dev_file_info == NULL) continue;
dev = dev_file_info->device;
if (dev->attached) {
devices_q = 1;
l += sprintf(buf + l, "%2d: %-20s %-20s %4d\n",
i,
dev->driver->driver_name,
dev->board_name, dev->n_subdevices);
}
}
if (!devices_q) {
l += sprintf(buf + l, "no devices\n");
}
for (driv = comedi_drivers; driv; driv = driv->next) {
l += sprintf(buf + l, "%s:\n", driv->driver_name);
for (i = 0; i < driv->num_names; i++) {
l += sprintf(buf + l, " %s\n",
*(char **)((char *)driv->board_name +
i * driv->offset));
}
if (!driv->num_names) {
l += sprintf(buf + l, " %s\n", driv->driver_name);
}
}
return l;
}
void comedi_proc_init(void)
{
struct proc_dir_entry *comedi_proc;
comedi_proc = create_proc_entry("comedi", S_IFREG | S_IRUGO, 0);
if (comedi_proc)
comedi_proc->read_proc = comedi_read_procmem;
}
void comedi_proc_cleanup(void)
{
remove_proc_entry("comedi", 0);
}

View File

@@ -0,0 +1,161 @@
/*
module/range.c
comedi routines for voltage ranges
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1997-8 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 "comedidev.h"
#include <asm/uaccess.h>
const comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} };
const comedi_lrange range_bipolar5 = { 1, {BIP_RANGE(5)} };
const comedi_lrange range_bipolar2_5 = { 1, {BIP_RANGE(2.5)} };
const comedi_lrange range_unipolar10 = { 1, {UNI_RANGE(10)} };
const comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} };
const comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none}} };
/*
COMEDI_RANGEINFO
range information ioctl
arg:
pointer to rangeinfo structure
reads:
range info structure
writes:
n comedi_krange structures to rangeinfo->range_ptr
*/
int do_rangeinfo_ioctl(comedi_device * dev, comedi_rangeinfo * arg)
{
comedi_rangeinfo it;
int subd, chan;
const comedi_lrange *lr;
comedi_subdevice *s;
if (copy_from_user(&it, arg, sizeof(comedi_rangeinfo)))
return -EFAULT;
subd = (it.range_type >> 24) & 0xf;
chan = (it.range_type >> 16) & 0xff;
if (!dev->attached)
return -EINVAL;
if (subd >= dev->n_subdevices)
return -EINVAL;
s = dev->subdevices + subd;
if (s->range_table) {
lr = s->range_table;
} else if (s->range_table_list) {
if (chan >= s->n_chan)
return -EINVAL;
lr = s->range_table_list[chan];
} else {
return -EINVAL;
}
if (RANGE_LENGTH(it.range_type) != lr->length) {
DPRINTK("wrong length %d should be %d (0x%08x)\n",
RANGE_LENGTH(it.range_type), lr->length, it.range_type);
return -EINVAL;
}
if (copy_to_user(it.range_ptr, lr->range,
sizeof(comedi_krange) * lr->length))
return -EFAULT;
return 0;
}
static int aref_invalid(comedi_subdevice * s, unsigned int chanspec)
{
unsigned int aref;
// disable reporting invalid arefs... maybe someday
return 0;
aref = CR_AREF(chanspec);
switch (aref) {
case AREF_DIFF:
if (s->subdev_flags & SDF_DIFF)
return 0;
break;
case AREF_COMMON:
if (s->subdev_flags & SDF_COMMON)
return 0;
break;
case AREF_GROUND:
if (s->subdev_flags & SDF_GROUND)
return 0;
break;
case AREF_OTHER:
if (s->subdev_flags & SDF_OTHER)
return 0;
break;
default:
break;
}
DPRINTK("subdevice does not support aref %i", aref);
return 1;
}
/*
This function checks each element in a channel/gain list to make
make sure it is valid.
*/
int check_chanlist(comedi_subdevice * s, int n, unsigned int *chanlist)
{
int i;
int chan;
if (s->range_table) {
for (i = 0; i < n; i++)
if (CR_CHAN(chanlist[i]) >= s->n_chan ||
CR_RANGE(chanlist[i]) >= s->range_table->length
|| aref_invalid(s, chanlist[i])) {
rt_printk
("bad chanlist[%d]=0x%08x n_chan=%d range length=%d\n",
i, chanlist[i], s->n_chan,
s->range_table->length);
#if 0
for (i = 0; i < n; i++) {
printk("[%d]=0x%08x\n", i, chanlist[i]);
}
#endif
return -EINVAL;
}
} else if (s->range_table_list) {
for (i = 0; i < n; i++) {
chan = CR_CHAN(chanlist[i]);
if (chan >= s->n_chan ||
CR_RANGE(chanlist[i]) >=
s->range_table_list[chan]->length
|| aref_invalid(s, chanlist[i])) {
rt_printk("bad chanlist[%d]=0x%08x\n", i,
chanlist[i]);
return -EINVAL;
}
}
} else {
rt_printk("comedi: (bug) no range type list!\n");
return -EINVAL;
}
return 0;
}

412
drivers/staging/comedi/rt.c Normal file
View File

@@ -0,0 +1,412 @@
/*
comedi/rt.c
comedi kernel module
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.
*/
#undef DEBUG
#define __NO_VERSION__
#include <linux/comedidev.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 "rt_pend_tq.h"
#ifdef CONFIG_COMEDI_RTAI
#include <rtai.h>
#endif
#ifdef CONFIG_COMEDI_FUSION
#include <nucleus/asm/hal.h>
#endif
#ifdef CONFIG_COMEDI_RTL
#include <rtl_core.h>
#include <rtl_sync.h>
#endif
struct comedi_irq_struct {
int rt;
int irq;
irqreturn_t(*handler) (int irq, void *dev_id PT_REGS_ARG);
unsigned long flags;
const char *device;
comedi_device *dev_id;
};
static int comedi_rt_get_irq(struct comedi_irq_struct *it);
static int comedi_rt_release_irq(struct comedi_irq_struct *it);
static struct comedi_irq_struct *comedi_irqs[NR_IRQS];
int comedi_request_irq(unsigned irq, irqreturn_t(*handler) (int,
void *PT_REGS_ARG), unsigned long flags, const char *device,
comedi_device * dev_id)
{
struct comedi_irq_struct *it;
int ret;
/* null shared interrupt flag, since rt interrupt handlers do not
* support it, and this version of comedi_request_irq() is only
* called for kernels with rt support */
unsigned long unshared_flags = flags & ~IRQF_SHARED;
ret = request_irq(irq, handler, unshared_flags, device, dev_id);
if (ret < 0) {
// we failed, so fall back on allowing shared interrupt (which we won't ever make RT)
if (flags & IRQF_SHARED) {
rt_printk
("comedi: cannot get unshared interrupt, will not use RT interrupts.\n");
ret = request_irq(irq, handler, flags, device, dev_id);
}
if (ret < 0) {
return ret;
}
} else {
it = kzalloc(sizeof(struct comedi_irq_struct), GFP_KERNEL);
if (!it)
return -ENOMEM;
it->handler = handler;
it->irq = irq;
it->dev_id = dev_id;
it->device = device;
it->flags = unshared_flags;
comedi_irqs[irq] = it;
}
return 0;
}
void comedi_free_irq(unsigned int irq, comedi_device * dev_id)
{
struct comedi_irq_struct *it;
free_irq(irq, dev_id);
it = comedi_irqs[irq];
if (it == NULL)
return;
if (it->rt) {
printk("real-time IRQ allocated at board removal (ignore)\n");
comedi_rt_release_irq(it);
}
kfree(it);
comedi_irqs[irq] = NULL;
}
int comedi_switch_to_rt(comedi_device * dev)
{
struct comedi_irq_struct *it;
unsigned long flags;
it = comedi_irqs[dev->irq];
/* drivers might not be using an interrupt for commands,
or we might not have been able to get an unshared irq */
if (it == NULL)
return -1;
comedi_spin_lock_irqsave(&dev->spinlock, flags);
if (!dev->rt)
comedi_rt_get_irq(it);
dev->rt++;
it->rt = 1;
comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
return 0;
}
void comedi_switch_to_non_rt(comedi_device * dev)
{
struct comedi_irq_struct *it;
unsigned long flags;
it = comedi_irqs[dev->irq];
if (it == NULL)
return;
comedi_spin_lock_irqsave(&dev->spinlock, flags);
dev->rt--;
if (!dev->rt)
comedi_rt_release_irq(it);
it->rt = 0;
comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
}
void wake_up_int_handler(int arg1, void *arg2)
{
wake_up_interruptible((wait_queue_head_t *) arg2);
}
void comedi_rt_pend_wakeup(wait_queue_head_t * q)
{
rt_pend_call(wake_up_int_handler, 0, q);
}
/* RTAI section */
#ifdef CONFIG_COMEDI_RTAI
#ifndef HAVE_RT_REQUEST_IRQ_WITH_ARG
#define DECLARE_VOID_IRQ(irq) \
static void handle_void_irq_ ## irq (void){ handle_void_irq(irq);}
static void handle_void_irq(int irq)
{
struct comedi_irq_struct *it;
it = comedi_irqs[irq];
if (it == NULL) {
rt_printk("comedi: null irq struct?\n");
return;
}
it->handler(irq, it->dev_id PT_REGS_NULL);
rt_enable_irq(irq); //needed by rtai-adeos, seems like it shouldn't hurt earlier versions
}
DECLARE_VOID_IRQ(0);
DECLARE_VOID_IRQ(1);
DECLARE_VOID_IRQ(2);
DECLARE_VOID_IRQ(3);
DECLARE_VOID_IRQ(4);
DECLARE_VOID_IRQ(5);
DECLARE_VOID_IRQ(6);
DECLARE_VOID_IRQ(7);
DECLARE_VOID_IRQ(8);
DECLARE_VOID_IRQ(9);
DECLARE_VOID_IRQ(10);
DECLARE_VOID_IRQ(11);
DECLARE_VOID_IRQ(12);
DECLARE_VOID_IRQ(13);
DECLARE_VOID_IRQ(14);
DECLARE_VOID_IRQ(15);
DECLARE_VOID_IRQ(16);
DECLARE_VOID_IRQ(17);
DECLARE_VOID_IRQ(18);
DECLARE_VOID_IRQ(19);
DECLARE_VOID_IRQ(20);
DECLARE_VOID_IRQ(21);
DECLARE_VOID_IRQ(22);
DECLARE_VOID_IRQ(23);
typedef void (*V_FP_V) (void);
static V_FP_V handle_void_irq_ptrs[] = {
handle_void_irq_0,
handle_void_irq_1,
handle_void_irq_2,
handle_void_irq_3,
handle_void_irq_4,
handle_void_irq_5,
handle_void_irq_6,
handle_void_irq_7,
handle_void_irq_8,
handle_void_irq_9,
handle_void_irq_10,
handle_void_irq_11,
handle_void_irq_12,
handle_void_irq_13,
handle_void_irq_14,
handle_void_irq_15,
handle_void_irq_16,
handle_void_irq_17,
handle_void_irq_18,
handle_void_irq_19,
handle_void_irq_20,
handle_void_irq_21,
handle_void_irq_22,
handle_void_irq_23,
};
static int comedi_rt_get_irq(struct comedi_irq_struct *it)
{
rt_request_global_irq(it->irq, handle_void_irq_ptrs[it->irq]);
rt_startup_irq(it->irq);
return 0;
}
static int comedi_rt_release_irq(struct comedi_irq_struct *it)
{
rt_shutdown_irq(it->irq);
rt_free_global_irq(it->irq);
return 0;
}
#else
static int comedi_rt_get_irq(struct comedi_irq_struct *it)
{
int ret;
ret = rt_request_global_irq_arg(it->irq, it->handler, it->flags,
it->device, it->dev_id);
if (ret < 0) {
rt_printk("rt_request_global_irq_arg() returned %d\n", ret);
return ret;
}
rt_startup_irq(it->irq);
return 0;
}
static int comedi_rt_release_irq(struct comedi_irq_struct *it)
{
rt_shutdown_irq(it->irq);
rt_free_global_irq(it->irq);
return 0;
}
#endif
void comedi_rt_init(void)
{
rt_mount_rtai();
rt_pend_tq_init();
}
void comedi_rt_cleanup(void)
{
rt_umount_rtai();
rt_pend_tq_cleanup();
}
#endif
/* Fusion section */
#ifdef CONFIG_COMEDI_FUSION
static void fusion_handle_irq(unsigned int irq, void *cookie)
{
struct comedi_irq_struct *it = cookie;
it->handler(irq, it->dev_id PT_REGS_NULL);
rthal_irq_enable(irq);
}
static int comedi_rt_get_irq(struct comedi_irq_struct *it)
{
rthal_irq_request(it->irq, fusion_handle_irq, it);
rthal_irq_enable(it->irq);
return 0;
}
static int comedi_rt_release_irq(struct comedi_irq_struct *it)
{
rthal_irq_disable(it->irq);
rthal_irq_release(it->irq);
return 0;
}
void comedi_rt_init(void)
{
rt_pend_tq_init();
}
void comedi_rt_cleanup(void)
{
rt_pend_tq_cleanup();
}
#endif /*CONFIG_COMEDI_FUSION */
/* RTLinux section */
#ifdef CONFIG_COMEDI_RTL
static unsigned int handle_rtl_irq(unsigned int irq PT_REGS_ARG)
{
struct comedi_irq_struct *it;
it = comedi_irqs[irq];
if (it == NULL)
return 0;
it->handler(irq, it->dev_id PT_REGS_NULL);
rtl_hard_enable_irq(irq);
return 0;
}
static int comedi_rt_get_irq(struct comedi_irq_struct *it)
{
rtl_request_global_irq(it->irq, handle_rtl_irq);
return 0;
}
static int comedi_rt_release_irq(struct comedi_irq_struct *it)
{
rtl_free_global_irq(it->irq);
return 0;
}
void comedi_rt_init(void)
{
rt_pend_tq_init();
}
void comedi_rt_cleanup(void)
{
rt_pend_tq_cleanup();
}
#endif
#ifdef CONFIG_COMEDI_PIRQ
static int comedi_rt_get_irq(struct comedi_irq_struct *it)
{
int ret;
free_irq(it->irq, it->dev_id);
ret = request_irq(it->irq, it->handler, it->flags | SA_PRIORITY,
it->device, it->dev_id);
return ret;
}
static int comedi_rt_release_irq(struct comedi_irq_struct *it)
{
int ret;
free_irq(it->irq, it->dev_id);
ret = request_irq(it->irq, it->handler, it->flags,
it->device, it->dev_id);
return ret;
}
void comedi_rt_init(void)
{
//rt_pend_tq_init();
}
void comedi_rt_cleanup(void)
{
//rt_pend_tq_cleanup();
}
#endif

View File

@@ -0,0 +1,113 @@
#define __NO_VERSION__
/* rt_pend_tq.c */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include "comedidev.h" // for rt spinlocks
#include "rt_pend_tq.h"
#ifdef CONFIG_COMEDI_RTAI
#include <rtai.h>
#endif
#ifdef CONFIG_COMEDI_FUSION
#include <nucleus/asm/hal.h>
#endif
#ifdef CONFIG_COMEDI_RTL
#include <rtl_core.h>
#endif
#ifdef standalone
#include <linux/module.h>
#define rt_pend_tq_init init_module
#define rt_pend_tq_cleanup cleanup_module
#endif
volatile static struct rt_pend_tq rt_pend_tq[RT_PEND_TQ_SIZE];
volatile static struct rt_pend_tq *volatile rt_pend_head = rt_pend_tq,
*volatile rt_pend_tail = rt_pend_tq;
int rt_pend_tq_irq = 0;
spinlock_t rt_pend_tq_lock = SPIN_LOCK_UNLOCKED;
// WARNING: following code not checked against race conditions yet.
#define INC_CIRCULAR_PTR(ptr,begin,size) do {if(++(ptr)>=(begin)+(size)) (ptr)=(begin); } while(0)
#define DEC_CIRCULAR_PTR(ptr,begin,size) do {if(--(ptr)<(begin)) (ptr)=(begin)+(size)-1; } while(0)
int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1, void *arg2)
{
unsigned long flags;
if (func == NULL)
return -EINVAL;
if (rt_pend_tq_irq <= 0)
return -ENODEV;
comedi_spin_lock_irqsave(&rt_pend_tq_lock, flags);
INC_CIRCULAR_PTR(rt_pend_head, rt_pend_tq, RT_PEND_TQ_SIZE);
if (rt_pend_head == rt_pend_tail) {
// overflow, we just refuse to take this request
DEC_CIRCULAR_PTR(rt_pend_head, rt_pend_tq, RT_PEND_TQ_SIZE);
comedi_spin_unlock_irqrestore(&rt_pend_tq_lock, flags);
return -EAGAIN;
}
rt_pend_head->func = func;
rt_pend_head->arg1 = arg1;
rt_pend_head->arg2 = arg2;
comedi_spin_unlock_irqrestore(&rt_pend_tq_lock, flags);
#ifdef CONFIG_COMEDI_RTAI
rt_pend_linux_srq(rt_pend_tq_irq);
#endif
#ifdef CONFIG_COMEDI_FUSION
rthal_apc_schedule(rt_pend_tq_irq);
#endif
#ifdef CONFIG_COMEDI_RTL
rtl_global_pend_irq(rt_pend_tq_irq);
#endif
return 0;
}
#ifdef CONFIG_COMEDI_RTAI
void rt_pend_irq_handler(void)
#elif defined(CONFIG_COMEDI_FUSION)
void rt_pend_irq_handler(void *cookie)
#elif defined(CONFIG_COMEDI_RTL)
void rt_pend_irq_handler(int irq, void *dev PT_REGS_ARG)
#endif
{
while (rt_pend_head != rt_pend_tail) {
INC_CIRCULAR_PTR(rt_pend_tail, rt_pend_tq, RT_PEND_TQ_SIZE);
rt_pend_tail->func(rt_pend_tail->arg1, rt_pend_tail->arg2);
}
}
int rt_pend_tq_init(void)
{
rt_pend_head = rt_pend_tail = rt_pend_tq;
#ifdef CONFIG_COMEDI_RTAI
rt_pend_tq_irq = rt_request_srq(0, rt_pend_irq_handler, NULL);
#endif
#ifdef CONFIG_COMEDI_FUSION
rt_pend_tq_irq =
rthal_apc_alloc("comedi APC", rt_pend_irq_handler, NULL);
#endif
#ifdef CONFIG_COMEDI_RTL
rt_pend_tq_irq = rtl_get_soft_irq(rt_pend_irq_handler, "rt_pend_irq");
#endif
if (rt_pend_tq_irq > 0)
printk("rt_pend_tq: RT bottom half scheduler initialized OK\n");
else
printk("rt_pend_tq: rtl_get_soft_irq failed\n");
return 0;
}
void rt_pend_tq_cleanup(void)
{
printk("rt_pend_tq: unloading\n");
#ifdef CONFIG_COMEDI_RTAI
rt_free_srq(rt_pend_tq_irq);
#endif
#ifdef CONFIG_COMEDI_FUSION
rthal_apc_free(rt_pend_tq_irq);
#endif
#ifdef CONFIG_COMEDI_RTL
free_irq(rt_pend_tq_irq, NULL);
#endif
}

View File

@@ -0,0 +1,10 @@
#define RT_PEND_TQ_SIZE 16
struct rt_pend_tq {
void (*func) (int arg1, void *arg2);
int arg1;
void *arg2;
};
extern int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1,
void *arg2);
extern int rt_pend_tq_init(void);
extern void rt_pend_tq_cleanup(void);

Some files were not shown because too many files have changed in this diff Show More