Staging: comedi: remove RT code
This removes the unused RT code from the comedi subsystem. A lot of drivers needed to then include interrupt.h on their own, as they were picking it up through the comedi_rt.h inclusion. Cc: Ian Abbott <abbotti@mev.co.uk> Cc: Frank Mori Hess <fmhess@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
5f74ea14c0
commit
25436dc9d8
|
@ -13,13 +13,6 @@ config COMEDI_DEBUG
|
||||||
This is an option for use by developers; most people should
|
This is an option for use by developers; most people should
|
||||||
say N here. This enables comedi core and driver debugging.
|
say N here. This enables comedi core and driver debugging.
|
||||||
|
|
||||||
config COMEDI_RT
|
|
||||||
tristate "Comedi Real-time support"
|
|
||||||
depends on COMEDI && RT
|
|
||||||
default N
|
|
||||||
---help---
|
|
||||||
Enable Real time support for the Comedi core.
|
|
||||||
|
|
||||||
config COMEDI_PCI_DRIVERS
|
config COMEDI_PCI_DRIVERS
|
||||||
tristate "Comedi PCI drivers"
|
tristate "Comedi PCI drivers"
|
||||||
depends on COMEDI && PCI
|
depends on COMEDI && PCI
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
obj-$(CONFIG_COMEDI) += comedi.o
|
obj-$(CONFIG_COMEDI) += comedi.o
|
||||||
obj-$(CONFIG_COMEDI_RT) += comedi_rt.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_COMEDI) += kcomedilib/
|
obj-$(CONFIG_COMEDI) += kcomedilib/
|
||||||
obj-$(CONFIG_COMEDI) += drivers/
|
obj-$(CONFIG_COMEDI) += drivers/
|
||||||
|
@ -11,7 +10,3 @@ comedi-objs := \
|
||||||
drivers.o \
|
drivers.o \
|
||||||
comedi_compat32.o \
|
comedi_compat32.o \
|
||||||
comedi_ksyms.o \
|
comedi_ksyms.o \
|
||||||
|
|
||||||
comedi_rt-objs := \
|
|
||||||
rt_pend_tq.o \
|
|
||||||
rt.o
|
|
||||||
|
|
|
@ -1079,13 +1079,6 @@ static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
|
||||||
|
|
||||||
comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
|
comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
|
||||||
|
|
||||||
#ifdef CONFIG_COMEDI_RT
|
|
||||||
if (async->cmd.flags & TRIG_RT) {
|
|
||||||
if (comedi_switch_to_rt(dev) == 0)
|
|
||||||
comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = s->do_cmd(dev, s);
|
ret = s->do_cmd(dev, s);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1720,12 +1713,6 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||||
struct comedi_async *async = s->async;
|
struct comedi_async *async = s->async;
|
||||||
|
|
||||||
comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
|
comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
|
||||||
#ifdef CONFIG_COMEDI_RT
|
|
||||||
if (comedi_get_subdevice_runflags(s) & SRF_RT) {
|
|
||||||
comedi_switch_to_non_rt(dev);
|
|
||||||
comedi_set_subdevice_runflags(s, SRF_RT, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (async) {
|
if (async) {
|
||||||
comedi_reset_async_buf(async);
|
comedi_reset_async_buf(async);
|
||||||
async->inttrig = NULL;
|
async->inttrig = NULL;
|
||||||
|
@ -1952,8 +1939,6 @@ static int __init comedi_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
comedi_rt_init();
|
|
||||||
|
|
||||||
comedi_register_ioctl32();
|
comedi_register_ioctl32();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1974,8 +1959,6 @@ static void __exit comedi_cleanup(void)
|
||||||
|
|
||||||
comedi_proc_cleanup();
|
comedi_proc_cleanup();
|
||||||
|
|
||||||
comedi_rt_cleanup();
|
|
||||||
|
|
||||||
comedi_unregister_ioctl32();
|
comedi_unregister_ioctl32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2015,15 +1998,8 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||||
|
|
||||||
if (async->cb_mask & s->async->events) {
|
if (async->cb_mask & s->async->events) {
|
||||||
if (comedi_get_subdevice_runflags(s) & SRF_USER) {
|
if (comedi_get_subdevice_runflags(s) & SRF_USER) {
|
||||||
|
|
||||||
if (dev->rt) {
|
if (dev->rt) {
|
||||||
#ifdef CONFIG_COMEDI_RT
|
printk("BUG: comedi_event() code unreachable\n");
|
||||||
/* pend wake up */
|
|
||||||
comedi_rt_pend_wakeup(&async->wait_head);
|
|
||||||
#else
|
|
||||||
printk
|
|
||||||
("BUG: comedi_event() code unreachable\n");
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
wake_up_interruptible(&async->wait_head);
|
wake_up_interruptible(&async->wait_head);
|
||||||
if (s->subdev_flags & SDF_CMD_READ) {
|
if (s->subdev_flags & SDF_CMD_READ) {
|
||||||
|
|
|
@ -46,13 +46,6 @@ EXPORT_SYMBOL(range_bipolar2_5);
|
||||||
EXPORT_SYMBOL(range_unipolar10);
|
EXPORT_SYMBOL(range_unipolar10);
|
||||||
EXPORT_SYMBOL(range_unipolar5);
|
EXPORT_SYMBOL(range_unipolar5);
|
||||||
EXPORT_SYMBOL(range_unknown);
|
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
|
#ifdef CONFIG_COMEDI_DEBUG
|
||||||
EXPORT_SYMBOL(comedi_debug);
|
EXPORT_SYMBOL(comedi_debug);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
/*
|
|
||||||
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/kdev_t.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/interrupt.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, irq_handler_t handler,
|
|
||||||
unsigned long flags, const char *device,
|
|
||||||
struct comedi_device *dev_id);
|
|
||||||
void comedi_free_irq(unsigned int irq, struct comedi_device *dev_id);
|
|
||||||
void comedi_rt_init(void);
|
|
||||||
void comedi_rt_cleanup(void);
|
|
||||||
int comedi_switch_to_rt(struct comedi_device *dev);
|
|
||||||
void comedi_switch_to_non_rt(struct 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
|
|
|
@ -523,8 +523,6 @@ struct usb_device; /* forward declaration */
|
||||||
int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name);
|
int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name);
|
||||||
void comedi_usb_auto_unconfig(struct usb_device *usbdev);
|
void comedi_usb_auto_unconfig(struct usb_device *usbdev);
|
||||||
|
|
||||||
#include "comedi_rt.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_COMEDI_PCI_DRIVERS
|
#ifdef CONFIG_COMEDI_PCI_DRIVERS
|
||||||
#define CONFIG_COMEDI_PCI
|
#define CONFIG_COMEDI_PCI
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,6 +31,7 @@ Status: experimental
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
|
@ -43,6 +43,7 @@ See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
#include "comedi_pci.h"
|
#include "comedi_pci.h"
|
||||||
#include "plx9052.h"
|
#include "plx9052.h"
|
||||||
|
|
|
@ -1,756 +0,0 @@
|
||||||
/*
|
|
||||||
comedi/drivers/comedi_rt_timer.c
|
|
||||||
virtual driver for using RTL timing sources
|
|
||||||
|
|
||||||
Authors: David A. Schleef, Frank M. Hess
|
|
||||||
|
|
||||||
COMEDI - Linux Control and Measurement Device Interface
|
|
||||||
Copyright (C) 1999,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.
|
|
||||||
|
|
||||||
**************************************************************************
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Driver: comedi_rt_timer
|
|
||||||
Description: Command emulator using real-time tasks
|
|
||||||
Author: ds, fmhess
|
|
||||||
Devices:
|
|
||||||
Status: works
|
|
||||||
|
|
||||||
This driver requires RTAI or RTLinux to work correctly. It doesn't
|
|
||||||
actually drive hardware directly, but calls other drivers and uses
|
|
||||||
a real-time task to emulate commands for drivers and devices that
|
|
||||||
are incapable of native commands. Thus, you can get accurately
|
|
||||||
timed I/O on any device.
|
|
||||||
|
|
||||||
Since the timing is all done in software, sampling jitter is much
|
|
||||||
higher than with a device that has an on-board timer, and maximum
|
|
||||||
sample rate is much lower.
|
|
||||||
|
|
||||||
Configuration options:
|
|
||||||
[0] - minor number of device you wish to emulate commands for
|
|
||||||
[1] - subdevice number you wish to emulate commands for
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
TODO:
|
|
||||||
Support for digital io commands could be added, except I can't see why
|
|
||||||
anyone would want to use them
|
|
||||||
What happens if device we are emulating for is de-configured?
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../comedidev.h"
|
|
||||||
#include "../comedilib.h"
|
|
||||||
|
|
||||||
#include "comedi_fc.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_COMEDI_RTL_V1
|
|
||||||
#include <rtl_sched.h>
|
|
||||||
#include <asm/rt_irq.h>
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_COMEDI_RTL
|
|
||||||
#include <rtl.h>
|
|
||||||
#include <rtl_sched.h>
|
|
||||||
#include <rtl_compat.h>
|
|
||||||
#include <asm/div64.h>
|
|
||||||
|
|
||||||
#ifndef RTLINUX_VERSION_CODE
|
|
||||||
#define RTLINUX_VERSION_CODE 0
|
|
||||||
#endif
|
|
||||||
#ifndef RTLINUX_VERSION
|
|
||||||
#define RTLINUX_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* begin hack to workaround broken HRT_TO_8254() function on rtlinux */
|
|
||||||
#if RTLINUX_VERSION_CODE <= RTLINUX_VERSION(3, 0, 100)
|
|
||||||
/* this function sole purpose is to divide a long long by 838 */
|
|
||||||
static inline RTIME nano2count(long long ns)
|
|
||||||
{
|
|
||||||
do_div(ns, 838);
|
|
||||||
return ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef rt_get_time()
|
|
||||||
#undef rt_get_time()
|
|
||||||
#endif
|
|
||||||
#define rt_get_time() nano2count(gethrtime())
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define nano2count(x) HRT_TO_8254(x)
|
|
||||||
#endif
|
|
||||||
/* end hack */
|
|
||||||
|
|
||||||
/* rtl-rtai compatibility */
|
|
||||||
#define rt_task_wait_period() rt_task_wait()
|
|
||||||
#define rt_pend_linux_srq(irq) rtl_global_pend_irq(irq)
|
|
||||||
#define rt_free_srq(irq) rtl_free_soft_irq(irq)
|
|
||||||
#define rt_request_srq(x, y, z) rtl_get_soft_irq(y, "timer")
|
|
||||||
#define rt_task_init(a, b, c, d, e, f, g) rt_task_init(a, b, c, d, (e)+1)
|
|
||||||
#define rt_task_resume(x) rt_task_wakeup(x)
|
|
||||||
#define rt_set_oneshot_mode()
|
|
||||||
#define start_rt_timer(x)
|
|
||||||
#define stop_rt_timer()
|
|
||||||
|
|
||||||
#define comedi_rt_task_context_t int
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_COMEDI_RTAI
|
|
||||||
#include <rtai.h>
|
|
||||||
#include <rtai_sched.h>
|
|
||||||
#include <rtai_version.h>
|
|
||||||
|
|
||||||
/* RTAI_VERSION_CODE doesn't work for rtai-3.6-cv and other strange versions.
|
|
||||||
* These are characterized by CONFIG_RTAI_REVISION_LEVEL being defined as an
|
|
||||||
* empty macro and CONFIG_RTAI_VERSION_MINOR being defined as something like
|
|
||||||
* '6-cv' or '7-test1'. The problem has been noted by the RTAI folks and they
|
|
||||||
* promise not to do it again. :-) Try and work around it here. */
|
|
||||||
#if !(CONFIG_RTAI_REVISION_LEVEL + 0)
|
|
||||||
#undef CONFIG_RTAI_REVISION_LEVEL
|
|
||||||
#define CONFIG_RTAI_REVISION_LEVEL 0
|
|
||||||
#define cv 0
|
|
||||||
#define test1 0
|
|
||||||
#define test2 0
|
|
||||||
#define test3 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if RTAI_VERSION_CODE < RTAI_MANGLE_VERSION(3, 3, 0)
|
|
||||||
#define comedi_rt_task_context_t int
|
|
||||||
#else
|
|
||||||
#define comedi_rt_task_context_t long
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Finished checking RTAI_VERSION_CODE. */
|
|
||||||
#undef cv
|
|
||||||
#undef test1
|
|
||||||
#undef test2
|
|
||||||
#undef test3
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This defines the fastest speed we will emulate. Note that
|
|
||||||
* without a watchdog (like in RTAI), we could easily overrun our
|
|
||||||
* task period because analog input tends to be slow. */
|
|
||||||
#define SPEED_LIMIT 100000 /* in nanoseconds */
|
|
||||||
|
|
||||||
static int timer_attach(struct comedi_device *dev, struct comedi_devconfig *it);
|
|
||||||
static int timer_detach(struct comedi_device *dev);
|
|
||||||
static int timer_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
|
|
||||||
unsigned int trig_num);
|
|
||||||
static int timer_start_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
|
|
||||||
|
|
||||||
static struct comedi_driver driver_timer = {
|
|
||||||
.module = THIS_MODULE,
|
|
||||||
.driver_name = "comedi_rt_timer",
|
|
||||||
.attach = timer_attach,
|
|
||||||
.detach = timer_detach,
|
|
||||||
/* .open = timer_open, */
|
|
||||||
};
|
|
||||||
|
|
||||||
COMEDI_INITCLEANUP(driver_timer);
|
|
||||||
|
|
||||||
struct timer_private {
|
|
||||||
comedi_t *device; /* device we are emulating commands for */
|
|
||||||
int subd; /* subdevice we are emulating commands for */
|
|
||||||
RT_TASK *rt_task; /* rt task that starts scans */
|
|
||||||
RT_TASK *scan_task; /* rt task that controls conversion timing in a scan */
|
|
||||||
/* io_function can point to either an input or output function
|
|
||||||
* depending on what kind of subdevice we are emulating for */
|
|
||||||
int (*io_function) (struct comedi_device *dev, struct comedi_cmd *cmd,
|
|
||||||
unsigned int index);
|
|
||||||
/*
|
|
||||||
* RTIME has units of 1 = 838 nanoseconds time at which first scan
|
|
||||||
* started, used to check scan timing
|
|
||||||
*/
|
|
||||||
RTIME start;
|
|
||||||
/* time between scans */
|
|
||||||
RTIME scan_period;
|
|
||||||
/* time between conversions in a scan */
|
|
||||||
RTIME convert_period;
|
|
||||||
/* flags */
|
|
||||||
volatile int stop; /* indicates we should stop */
|
|
||||||
volatile int rt_task_active; /* indicates rt_task is servicing a struct comedi_cmd */
|
|
||||||
volatile int scan_task_active; /* indicates scan_task is servicing a struct comedi_cmd */
|
|
||||||
unsigned timer_running:1;
|
|
||||||
};
|
|
||||||
#define devpriv ((struct timer_private *)dev->private)
|
|
||||||
|
|
||||||
static int timer_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
|
|
||||||
{
|
|
||||||
devpriv->stop = 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* checks for scan timing error */
|
|
||||||
inline static int check_scan_timing(struct comedi_device *dev,
|
|
||||||
unsigned long long scan)
|
|
||||||
{
|
|
||||||
RTIME now, timing_error;
|
|
||||||
|
|
||||||
now = rt_get_time();
|
|
||||||
timing_error = now - (devpriv->start + scan * devpriv->scan_period);
|
|
||||||
if (timing_error > devpriv->scan_period) {
|
|
||||||
comedi_error(dev, "timing error");
|
|
||||||
printk("scan started %i ns late\n", timing_error * 838);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* checks for conversion timing error */
|
|
||||||
inline static int check_conversion_timing(struct comedi_device *dev,
|
|
||||||
RTIME scan_start, unsigned int conversion)
|
|
||||||
{
|
|
||||||
RTIME now, timing_error;
|
|
||||||
|
|
||||||
now = rt_get_time();
|
|
||||||
timing_error =
|
|
||||||
now - (scan_start + conversion * devpriv->convert_period);
|
|
||||||
if (timing_error > devpriv->convert_period) {
|
|
||||||
comedi_error(dev, "timing error");
|
|
||||||
printk("conversion started %i ns late\n",
|
|
||||||
timing_error * 838);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* devpriv->io_function for an input subdevice */
|
|
||||||
static int timer_data_read(struct comedi_device *dev, struct comedi_cmd *cmd,
|
|
||||||
unsigned int index)
|
|
||||||
{
|
|
||||||
struct comedi_subdevice *s = dev->read_subdev;
|
|
||||||
int ret;
|
|
||||||
unsigned int data;
|
|
||||||
|
|
||||||
ret = comedi_data_read(devpriv->device, devpriv->subd,
|
|
||||||
CR_CHAN(cmd->chanlist[index]),
|
|
||||||
CR_RANGE(cmd->chanlist[index]),
|
|
||||||
CR_AREF(cmd->chanlist[index]), &data);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "read error");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
if (s->flags & SDF_LSAMPL) {
|
|
||||||
cfc_write_long_to_buffer(s, data);
|
|
||||||
} else {
|
|
||||||
comedi_buf_put(s->async, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* devpriv->io_function for an output subdevice */
|
|
||||||
static int timer_data_write(struct comedi_device *dev, struct comedi_cmd *cmd,
|
|
||||||
unsigned int index)
|
|
||||||
{
|
|
||||||
struct comedi_subdevice *s = dev->write_subdev;
|
|
||||||
unsigned int num_bytes;
|
|
||||||
short data;
|
|
||||||
unsigned int long_data;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (s->flags & SDF_LSAMPL) {
|
|
||||||
num_bytes =
|
|
||||||
cfc_read_array_from_buffer(s, &long_data,
|
|
||||||
sizeof(long_data));
|
|
||||||
} else {
|
|
||||||
num_bytes = cfc_read_array_from_buffer(s, &data, sizeof(data));
|
|
||||||
long_data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_bytes == 0) {
|
|
||||||
comedi_error(dev, "buffer underrun");
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
ret = comedi_data_write(devpriv->device, devpriv->subd,
|
|
||||||
CR_CHAN(cmd->chanlist[index]),
|
|
||||||
CR_RANGE(cmd->chanlist[index]),
|
|
||||||
CR_AREF(cmd->chanlist[index]), long_data);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "write error");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* devpriv->io_function for DIO subdevices */
|
|
||||||
static int timer_dio_read(struct comedi_device *dev, struct comedi_cmd *cmd,
|
|
||||||
unsigned int index)
|
|
||||||
{
|
|
||||||
struct comedi_subdevice *s = dev->read_subdev;
|
|
||||||
int ret;
|
|
||||||
unsigned int data;
|
|
||||||
|
|
||||||
ret = comedi_dio_bitfield(devpriv->device, devpriv->subd, 0, &data);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "read error");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->flags & SDF_LSAMPL)
|
|
||||||
cfc_write_long_to_buffer(s, data);
|
|
||||||
else
|
|
||||||
cfc_write_to_buffer(s, data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* performs scans */
|
|
||||||
static void scan_task_func(comedi_rt_task_context_t d)
|
|
||||||
{
|
|
||||||
struct comedi_device *dev = (struct comedi_device *) d;
|
|
||||||
struct comedi_subdevice *s = dev->subdevices + 0;
|
|
||||||
struct comedi_async *async = s->async;
|
|
||||||
struct comedi_cmd *cmd = &async->cmd;
|
|
||||||
int i, ret;
|
|
||||||
unsigned long long n;
|
|
||||||
RTIME scan_start;
|
|
||||||
|
|
||||||
/* every struct comedi_cmd causes one execution of while loop */
|
|
||||||
while (1) {
|
|
||||||
devpriv->scan_task_active = 1;
|
|
||||||
/* each for loop completes one scan */
|
|
||||||
for (n = 0; n < cmd->stop_arg || cmd->stop_src == TRIG_NONE;
|
|
||||||
n++) {
|
|
||||||
if (n) {
|
|
||||||
/* suspend task until next scan */
|
|
||||||
ret = rt_task_suspend(devpriv->scan_task);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev,
|
|
||||||
"error suspending scan task");
|
|
||||||
async->events |= COMEDI_CB_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* check if stop flag was set (by timer_cancel()) */
|
|
||||||
if (devpriv->stop)
|
|
||||||
goto cleanup;
|
|
||||||
ret = check_scan_timing(dev, n);
|
|
||||||
if (ret < 0) {
|
|
||||||
async->events |= COMEDI_CB_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
scan_start = rt_get_time();
|
|
||||||
for (i = 0; i < cmd->scan_end_arg; i++) {
|
|
||||||
/* conversion timing */
|
|
||||||
if (cmd->convert_src == TRIG_TIMER && i) {
|
|
||||||
rt_task_wait_period();
|
|
||||||
ret = check_conversion_timing(dev,
|
|
||||||
scan_start, i);
|
|
||||||
if (ret < 0) {
|
|
||||||
async->events |=
|
|
||||||
COMEDI_CB_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = devpriv->io_function(dev, cmd, i);
|
|
||||||
if (ret < 0) {
|
|
||||||
async->events |= COMEDI_CB_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s->async->events |= COMEDI_CB_BLOCK;
|
|
||||||
comedi_event(dev, s);
|
|
||||||
s->async->events = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
|
|
||||||
comedi_unlock(devpriv->device, devpriv->subd);
|
|
||||||
async->events |= COMEDI_CB_EOA;
|
|
||||||
comedi_event(dev, s);
|
|
||||||
async->events = 0;
|
|
||||||
devpriv->scan_task_active = 0;
|
|
||||||
/* suspend task until next struct comedi_cmd */
|
|
||||||
rt_task_suspend(devpriv->scan_task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_task_func(comedi_rt_task_context_t d)
|
|
||||||
{
|
|
||||||
struct comedi_device *dev = (struct comedi_device *) d;
|
|
||||||
struct comedi_subdevice *s = dev->subdevices + 0;
|
|
||||||
struct comedi_cmd *cmd = &s->async->cmd;
|
|
||||||
int ret;
|
|
||||||
unsigned long long n;
|
|
||||||
|
|
||||||
/* every struct comedi_cmd causes one execution of while loop */
|
|
||||||
while (1) {
|
|
||||||
devpriv->rt_task_active = 1;
|
|
||||||
devpriv->scan_task_active = 1;
|
|
||||||
devpriv->start = rt_get_time();
|
|
||||||
|
|
||||||
for (n = 0; n < cmd->stop_arg || cmd->stop_src == TRIG_NONE;
|
|
||||||
n++) {
|
|
||||||
/* scan timing */
|
|
||||||
if (n)
|
|
||||||
rt_task_wait_period();
|
|
||||||
if (devpriv->scan_task_active == 0) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
ret = rt_task_make_periodic(devpriv->scan_task,
|
|
||||||
devpriv->start + devpriv->scan_period * n,
|
|
||||||
devpriv->convert_period);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "bug!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
|
|
||||||
devpriv->rt_task_active = 0;
|
|
||||||
/* suspend until next struct comedi_cmd */
|
|
||||||
rt_task_suspend(devpriv->rt_task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_insn(struct comedi_device *dev, struct comedi_subdevice *s,
|
|
||||||
struct comedi_insn *insn, unsigned int *data)
|
|
||||||
{
|
|
||||||
struct comedi_insn xinsn = *insn;
|
|
||||||
|
|
||||||
xinsn.data = data;
|
|
||||||
xinsn.subdev = devpriv->subd;
|
|
||||||
|
|
||||||
return comedi_do_insn(devpriv->device, &xinsn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmdtest_helper(struct comedi_cmd *cmd,
|
|
||||||
unsigned int start_src,
|
|
||||||
unsigned int scan_begin_src,
|
|
||||||
unsigned int convert_src,
|
|
||||||
unsigned int scan_end_src, unsigned int stop_src)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
int tmp;
|
|
||||||
|
|
||||||
tmp = cmd->start_src;
|
|
||||||
cmd->start_src &= start_src;
|
|
||||||
if (!cmd->start_src || tmp != cmd->start_src)
|
|
||||||
err++;
|
|
||||||
|
|
||||||
tmp = cmd->scan_begin_src;
|
|
||||||
cmd->scan_begin_src &= scan_begin_src;
|
|
||||||
if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
|
|
||||||
err++;
|
|
||||||
|
|
||||||
tmp = cmd->convert_src;
|
|
||||||
cmd->convert_src &= convert_src;
|
|
||||||
if (!cmd->convert_src || tmp != cmd->convert_src)
|
|
||||||
err++;
|
|
||||||
|
|
||||||
tmp = cmd->scan_end_src;
|
|
||||||
cmd->scan_end_src &= scan_end_src;
|
|
||||||
if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
|
|
||||||
err++;
|
|
||||||
|
|
||||||
tmp = cmd->stop_src;
|
|
||||||
cmd->stop_src &= stop_src;
|
|
||||||
if (!cmd->stop_src || tmp != cmd->stop_src)
|
|
||||||
err++;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
|
|
||||||
struct comedi_cmd *cmd)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
unsigned int start_src = 0;
|
|
||||||
|
|
||||||
if (s->type == COMEDI_SUBD_AO)
|
|
||||||
start_src = TRIG_INT;
|
|
||||||
else
|
|
||||||
start_src = TRIG_NOW;
|
|
||||||
|
|
||||||
err = cmdtest_helper(cmd, start_src, /* start_src */
|
|
||||||
TRIG_TIMER | TRIG_FOLLOW, /* scan_begin_src */
|
|
||||||
TRIG_NOW | TRIG_TIMER, /* convert_src */
|
|
||||||
TRIG_COUNT, /* scan_end_src */
|
|
||||||
TRIG_COUNT | TRIG_NONE); /* stop_src */
|
|
||||||
if (err)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* step 2: make sure trigger sources are unique and mutually
|
|
||||||
* compatible */
|
|
||||||
|
|
||||||
if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT)
|
|
||||||
err++;
|
|
||||||
if (cmd->scan_begin_src != TRIG_TIMER &&
|
|
||||||
cmd->scan_begin_src != TRIG_FOLLOW)
|
|
||||||
err++;
|
|
||||||
if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_NOW)
|
|
||||||
err++;
|
|
||||||
if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
|
|
||||||
err++;
|
|
||||||
if (cmd->scan_begin_src == TRIG_FOLLOW
|
|
||||||
&& cmd->convert_src != TRIG_TIMER)
|
|
||||||
err++;
|
|
||||||
if (cmd->convert_src == TRIG_NOW && cmd->scan_begin_src != TRIG_TIMER)
|
|
||||||
err++;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
/* step 3: make sure arguments are trivially compatible */
|
|
||||||
/* limit frequency, this is fairly arbitrary */
|
|
||||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
|
||||||
if (cmd->scan_begin_arg < SPEED_LIMIT) {
|
|
||||||
cmd->scan_begin_arg = SPEED_LIMIT;
|
|
||||||
err++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd->convert_src == TRIG_TIMER) {
|
|
||||||
if (cmd->convert_arg < SPEED_LIMIT) {
|
|
||||||
cmd->convert_arg = SPEED_LIMIT;
|
|
||||||
err++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* make sure conversion and scan frequencies are compatible */
|
|
||||||
if (cmd->convert_src == TRIG_TIMER && cmd->scan_begin_src == TRIG_TIMER) {
|
|
||||||
if (cmd->convert_arg * cmd->scan_end_arg > cmd->scan_begin_arg) {
|
|
||||||
cmd->scan_begin_arg =
|
|
||||||
cmd->convert_arg * cmd->scan_end_arg;
|
|
||||||
err++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (err)
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
/* step 4: fix up and arguments */
|
|
||||||
if (err)
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct comedi_cmd *cmd = &s->async->cmd;
|
|
||||||
|
|
||||||
/* hack attack: drivers are not supposed to do this: */
|
|
||||||
dev->rt = 1;
|
|
||||||
|
|
||||||
/* make sure tasks have finished cleanup of last struct comedi_cmd */
|
|
||||||
if (devpriv->rt_task_active || devpriv->scan_task_active)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
ret = comedi_lock(devpriv->device, devpriv->subd);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "failed to obtain lock");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
switch (cmd->scan_begin_src) {
|
|
||||||
case TRIG_TIMER:
|
|
||||||
devpriv->scan_period = nano2count(cmd->scan_begin_arg);
|
|
||||||
break;
|
|
||||||
case TRIG_FOLLOW:
|
|
||||||
devpriv->scan_period =
|
|
||||||
nano2count(cmd->convert_arg * cmd->scan_end_arg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
comedi_error(dev, "bug setting scan period!");
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (cmd->convert_src) {
|
|
||||||
case TRIG_TIMER:
|
|
||||||
devpriv->convert_period = nano2count(cmd->convert_arg);
|
|
||||||
break;
|
|
||||||
case TRIG_NOW:
|
|
||||||
devpriv->convert_period = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
comedi_error(dev, "bug setting conversion period!");
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd->start_src == TRIG_NOW)
|
|
||||||
return timer_start_cmd(dev, s);
|
|
||||||
|
|
||||||
s->async->inttrig = timer_inttrig;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
|
|
||||||
unsigned int trig_num)
|
|
||||||
{
|
|
||||||
if (trig_num != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
s->async->inttrig = NULL;
|
|
||||||
|
|
||||||
return timer_start_cmd(dev, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_start_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
|
||||||
{
|
|
||||||
struct comedi_async *async = s->async;
|
|
||||||
struct comedi_cmd *cmd = &async->cmd;
|
|
||||||
RTIME now, delay, period;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
devpriv->stop = 0;
|
|
||||||
s->async->events = 0;
|
|
||||||
|
|
||||||
if (cmd->start_src == TRIG_NOW)
|
|
||||||
delay = nano2count(cmd->start_arg);
|
|
||||||
else
|
|
||||||
delay = 0;
|
|
||||||
|
|
||||||
now = rt_get_time();
|
|
||||||
/* Using 'period' this way gets around some weird bug in gcc-2.95.2
|
|
||||||
* that generates the compile error 'internal error--unrecognizable insn'
|
|
||||||
* when rt_task_make_period() is called (observed with rtlinux-3.1, linux-2.2.19).
|
|
||||||
* - fmhess */
|
|
||||||
period = devpriv->scan_period;
|
|
||||||
ret = rt_task_make_periodic(devpriv->rt_task, now + delay, period);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "error starting rt_task");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_attach(struct comedi_device *dev, struct comedi_devconfig *it)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct comedi_subdevice *s, *emul_s;
|
|
||||||
struct comedi_device *emul_dev;
|
|
||||||
/* These should probably be devconfig options[] */
|
|
||||||
const int timer_priority = 4;
|
|
||||||
const int scan_priority = timer_priority + 1;
|
|
||||||
char path[20];
|
|
||||||
|
|
||||||
printk("comedi%d: timer: ", dev->minor);
|
|
||||||
|
|
||||||
dev->board_name = "timer";
|
|
||||||
|
|
||||||
ret = alloc_subdevices(dev, 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = alloc_private(dev, sizeof(struct timer_private));
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
sprintf(path, "/dev/comedi%d", it->options[0]);
|
|
||||||
devpriv->device = comedi_open(path);
|
|
||||||
devpriv->subd = it->options[1];
|
|
||||||
|
|
||||||
printk("emulating commands for minor %i, subdevice %d\n",
|
|
||||||
it->options[0], devpriv->subd);
|
|
||||||
|
|
||||||
emul_dev = devpriv->device;
|
|
||||||
emul_s = emul_dev->subdevices + devpriv->subd;
|
|
||||||
|
|
||||||
/* input or output subdevice */
|
|
||||||
s = dev->subdevices + 0;
|
|
||||||
s->type = emul_s->type;
|
|
||||||
s->subdev_flags = emul_s->subdev_flags; /* SDF_GROUND (to fool check_driver) */
|
|
||||||
s->n_chan = emul_s->n_chan;
|
|
||||||
s->len_chanlist = 1024;
|
|
||||||
s->do_cmd = timer_cmd;
|
|
||||||
s->do_cmdtest = timer_cmdtest;
|
|
||||||
s->cancel = timer_cancel;
|
|
||||||
s->maxdata = emul_s->maxdata;
|
|
||||||
s->range_table = emul_s->range_table;
|
|
||||||
s->range_table_list = emul_s->range_table_list;
|
|
||||||
switch (emul_s->type) {
|
|
||||||
case COMEDI_SUBD_AI:
|
|
||||||
s->insn_read = timer_insn;
|
|
||||||
dev->read_subdev = s;
|
|
||||||
s->subdev_flags |= SDF_CMD_READ;
|
|
||||||
devpriv->io_function = timer_data_read;
|
|
||||||
break;
|
|
||||||
case COMEDI_SUBD_AO:
|
|
||||||
s->insn_write = timer_insn;
|
|
||||||
s->insn_read = timer_insn;
|
|
||||||
dev->write_subdev = s;
|
|
||||||
s->subdev_flags |= SDF_CMD_WRITE;
|
|
||||||
devpriv->io_function = timer_data_write;
|
|
||||||
break;
|
|
||||||
case COMEDI_SUBD_DIO:
|
|
||||||
s->insn_write = timer_insn;
|
|
||||||
s->insn_read = timer_insn;
|
|
||||||
s->insn_bits = timer_insn;
|
|
||||||
dev->read_subdev = s;
|
|
||||||
s->subdev_flags |= SDF_CMD_READ;
|
|
||||||
devpriv->io_function = timer_dio_read;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
comedi_error(dev, "failed to determine subdevice type!");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
rt_set_oneshot_mode();
|
|
||||||
start_rt_timer(1);
|
|
||||||
devpriv->timer_running = 1;
|
|
||||||
|
|
||||||
devpriv->rt_task = kzalloc(sizeof(RT_TASK), GFP_KERNEL);
|
|
||||||
|
|
||||||
/* initialize real-time tasks */
|
|
||||||
ret = rt_task_init(devpriv->rt_task, timer_task_func,
|
|
||||||
(comedi_rt_task_context_t) dev, 3000, timer_priority, 0, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "error initalizing rt_task");
|
|
||||||
kfree(devpriv->rt_task);
|
|
||||||
devpriv->rt_task = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
devpriv->scan_task = kzalloc(sizeof(RT_TASK), GFP_KERNEL);
|
|
||||||
|
|
||||||
ret = rt_task_init(devpriv->scan_task, scan_task_func,
|
|
||||||
(comedi_rt_task_context_t) dev, 3000, scan_priority, 0, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
comedi_error(dev, "error initalizing scan_task");
|
|
||||||
kfree(devpriv->scan_task);
|
|
||||||
devpriv->scan_task = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free allocated resources */
|
|
||||||
static int timer_detach(struct comedi_device *dev)
|
|
||||||
{
|
|
||||||
printk("comedi%d: timer: remove\n", dev->minor);
|
|
||||||
|
|
||||||
if (devpriv) {
|
|
||||||
if (devpriv->rt_task) {
|
|
||||||
rt_task_delete(devpriv->rt_task);
|
|
||||||
kfree(devpriv->rt_task);
|
|
||||||
}
|
|
||||||
if (devpriv->scan_task) {
|
|
||||||
rt_task_delete(devpriv->scan_task);
|
|
||||||
kfree(devpriv->scan_task);
|
|
||||||
}
|
|
||||||
if (devpriv->timer_running)
|
|
||||||
stop_rt_timer();
|
|
||||||
if (devpriv->device)
|
|
||||||
comedi_close(devpriv->device);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -119,6 +119,7 @@ Configuration options:
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
#include "comedi_pci.h"
|
#include "comedi_pci.h"
|
||||||
#include "8255.h"
|
#include "8255.h"
|
||||||
|
|
|
@ -79,6 +79,7 @@ Computer boards manuals also available from their website www.measurementcomputi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <asm/dma.h>
|
#include <asm/dma.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ irq can be omitted, although the cmd interface will not work without it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include "8255.h"
|
#include "8255.h"
|
||||||
|
|
|
@ -100,6 +100,7 @@ TODO:
|
||||||
read insn for analog out
|
read insn for analog out
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -38,6 +38,7 @@ Devices: [Keithley Metrabyte] DAS6402 (das6402)
|
||||||
This driver has suffered bitrot.
|
This driver has suffered bitrot.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -62,6 +62,7 @@ cmd triggers supported:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -74,6 +74,7 @@ Configuration Options:
|
||||||
* options that are used with comedi_config.
|
* options that are used with comedi_config.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ Configuration options:
|
||||||
[4] - D/A 1 range (same choices)
|
[4] - D/A 1 range (same choices)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -39,6 +39,7 @@ a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In
|
||||||
addition, the clock does not seem to be very accurate.
|
addition, the clock does not seem to be very accurate.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -59,6 +59,7 @@ AO commands are not supported.
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ support could be added to this driver.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ Options:
|
||||||
[1] - PCI slot number
|
[1] - PCI slot number
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -51,6 +51,7 @@ broken.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -50,6 +50,7 @@ from http://www.comedi.org
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include "comedi_pci.h"
|
#include "comedi_pci.h"
|
||||||
|
|
|
@ -29,6 +29,7 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -41,6 +41,7 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
#define DEBUG_FLAGS
|
#define DEBUG_FLAGS
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include "mite.h"
|
#include "mite.h"
|
||||||
|
|
|
@ -50,6 +50,7 @@ except maybe the 6514.
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
#define DEBUG_FLAGS
|
#define DEBUG_FLAGS
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include "mite.h"
|
#include "mite.h"
|
||||||
|
|
|
@ -40,6 +40,7 @@ DAQ 6601/6602 User Manual (NI 322137B-01)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
#include "mite.h"
|
#include "mite.h"
|
||||||
#include "ni_tio.h"
|
#include "ni_tio.h"
|
||||||
|
|
|
@ -41,6 +41,7 @@ Commands are not supported.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include "mite.h"
|
#include "mite.h"
|
||||||
|
|
|
@ -64,6 +64,7 @@ TRIG_WAKE_EOS
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -93,6 +93,7 @@ are not supported.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -35,6 +35,7 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -41,6 +41,7 @@ emu as port A output, port B input, port C N/A).
|
||||||
IRQ is assigned but not used.
|
IRQ is assigned but not used.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -40,6 +40,7 @@ the PCMCIA interface.
|
||||||
/* #define LABPC_DEBUG */ /* enable debugging messages */
|
/* #define LABPC_DEBUG */ /* enable debugging messages */
|
||||||
#undef LABPC_DEBUG
|
#undef LABPC_DEBUG
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -76,6 +76,7 @@ NI manuals:
|
||||||
#undef LABPC_DEBUG
|
#undef LABPC_DEBUG
|
||||||
/* #define LABPC_DEBUG enable debugging messages */
|
/* #define LABPC_DEBUG enable debugging messages */
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
/* #define DEBUG_STATUS_A */
|
/* #define DEBUG_STATUS_A */
|
||||||
/* #define DEBUG_STATUS_B */
|
/* #define DEBUG_STATUS_B */
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "8255.h"
|
#include "8255.h"
|
||||||
#include "mite.h"
|
#include "mite.h"
|
||||||
#include "comedi_fc.h"
|
#include "comedi_fc.h"
|
||||||
|
|
|
@ -69,6 +69,7 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org
|
||||||
/* #define DEBUG 1 */
|
/* #define DEBUG 1 */
|
||||||
/* #define DEBUG_FLAGS */
|
/* #define DEBUG_FLAGS */
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include "mite.h"
|
#include "mite.h"
|
||||||
|
|
|
@ -58,6 +58,7 @@ supported.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -107,6 +107,7 @@ Options for ACL-8113, ISO-813:
|
||||||
3= 20V unipolar inputs
|
3= 20V unipolar inputs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -41,6 +41,7 @@ Configuration options:
|
||||||
1 = two's complement
|
1 = two's complement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -73,6 +73,7 @@ Configuration Options:
|
||||||
[1] - IRQ (optional -- for edge-detect interrupt support only, leave out if you don't need this feature)
|
[1] - IRQ (optional -- for edge-detect interrupt support only, leave out if you don't need this feature)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
#include <linux/pci.h> /* for PCI devices */
|
#include <linux/pci.h> /* for PCI devices */
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ Configuration Options:
|
||||||
[2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
|
[2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/pci.h> /* for PCI devices */
|
#include <linux/pci.h> /* for PCI devices */
|
||||||
|
|
|
@ -101,6 +101,7 @@ Configuration options:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
|
@ -52,6 +52,7 @@ Configuration options:
|
||||||
[8] - DAC 1 encoding (same as DAC 0)
|
[8] - DAC 1 encoding (same as DAC 0)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include "../comedidev.h"
|
#include "../comedidev.h"
|
||||||
|
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
|
@ -68,6 +68,7 @@ INSN_CONFIG instructions:
|
||||||
comedi_do_insn(cf,&insn); //executing configuration
|
comedi_do_insn(cf,&insn); //executing configuration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
|
|
@ -150,10 +150,6 @@ int comedi_command(void *d, struct comedi_cmd *cmd)
|
||||||
|
|
||||||
runflags = SRF_RUNNING;
|
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_set_subdevice_runflags(s, ~0, runflags);
|
||||||
|
|
||||||
comedi_reset_async_buf(async);
|
comedi_reset_async_buf(async);
|
||||||
|
@ -449,11 +445,6 @@ int comedi_cancel(void *d, unsigned int subdevice)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
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);
|
comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0);
|
||||||
s->async->inttrig = NULL;
|
s->async->inttrig = NULL;
|
||||||
s->busy = NULL;
|
s->busy = NULL;
|
||||||
|
|
|
@ -1,411 +0,0 @@
|
||||||
/*
|
|
||||||
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/interrupt.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;
|
|
||||||
irq_handler_t handler;
|
|
||||||
unsigned long flags;
|
|
||||||
const char *device;
|
|
||||||
struct 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, irq_handler_t handler, unsigned long flags,
|
|
||||||
const char *device, struct 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, struct 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(struct 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(struct 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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
static void 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);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
struct comedi_irq_struct *it;
|
|
||||||
|
|
||||||
it = comedi_irqs[irq];
|
|
||||||
if (it == NULL)
|
|
||||||
return 0;
|
|
||||||
it->handler(irq, it->dev_id);
|
|
||||||
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
|
|
|
@ -1,113 +0,0 @@
|
||||||
#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;
|
|
||||||
DEFINE_SPINLOCK(rt_pend_tq_lock);
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
#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
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
#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);
|
|
Loading…
Reference in New Issue