Moved real-time timer code from comedi/realtime/vd_timer.c
authorDavid Schleef <ds@schleef.org>
Wed, 21 Mar 2001 23:59:46 +0000 (23:59 +0000)
committerDavid Schleef <ds@schleef.org>
Wed, 21 Mar 2001 23:59:46 +0000 (23:59 +0000)
comedi/drivers/Makefile
comedi/drivers/comedi_rt_timer.c [new file with mode: 0644]

index 010c5a6ee53de88918e2d3059071ec91727e31f2..d6b1e48a2bc4a79f74f2537b4b8c5b80f4246f22 100644 (file)
@@ -75,6 +75,8 @@ obj-$(CONFIG_COMEDI_RTI802)           += rti802.o
 
 obj-$(CONFIG_COMEDI_SKEL)              += skel.o
 
+obj-$(CONFIG_COMEDI_RT_TIMER)          += comedi_rt_timer.o
+
 #obj-m += $(obj-y)
 
 O_OBJS         := $(sort $(filter-out $(export-objs), $(obj-y)))
diff --git a/comedi/drivers/comedi_rt_timer.c b/comedi/drivers/comedi_rt_timer.c
new file mode 100644 (file)
index 0000000..a041ed0
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+    module/vd_timer.c
+    virtual driver for using RTL timing sources
+
+    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.
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <linux/comedidev.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>
+#endif
+#ifdef CONFIG_COMEDI_RTAI
+#include <rtai.h>
+#include <rtai_sched.h>
+#endif
+
+static int timer_attach(comedi_device *dev,comedi_devconfig *it);
+static int timer_detach(comedi_device *dev);
+comedi_driver driver_timer={
+       driver_name:    "timer",
+       attach:         timer_attach,
+       detach:         timer_detach,
+};
+COMEDI_INITCLEANUP(driver_timer);
+
+
+static void timer_interrupt(int irq,void *dev,struct pt_regs * regs);
+
+typedef struct{
+       int device;
+       int subd;
+       comedi_device *dev;
+       comedi_subdevice *s;
+       RT_TASK rt_task;
+       sampl_t *data;
+       comedi_trig trig;
+       int soft_irq;
+}timer_private;
+#define devpriv ((timer_private *)dev->private)
+
+
+static comedi_device *broken_rtl_dev;
+
+static void timer_interrupt(int irq,void *d,struct pt_regs * regs)
+{
+       comedi_device *dev=broken_rtl_dev;
+
+       comedi_done(dev,dev->subdevices+0);
+
+       comedi_unlock_ioctl(devpriv->device,devpriv->subd);
+}
+
+static inline void buf_add(comedi_device *dev,comedi_subdevice *s,sampl_t x)
+{
+       *(sampl_t *)(((void *)(s->cur_trig.data))+s->buf_int_ptr)=x&0xfff;
+       s->buf_int_ptr+=sizeof(sampl_t);
+       if(s->buf_int_ptr>=s->cur_trig.data_len){
+               s->buf_int_ptr=0;
+               comedi_eobuf(dev,s);
+       }
+       s->buf_int_count+=sizeof(sampl_t);
+}
+
+
+static void timer_ai_task_func(int d)
+{
+       comedi_device *dev=(comedi_device *)d;
+       comedi_subdevice *s=dev->subdevices+0;
+       comedi_trig *it=&devpriv->trig;
+       comedi_trig *my_trig=&s->cur_trig;
+       int i,n,ret;
+       int n_chan;
+
+       n_chan=s->cur_trig.n_chan;
+
+       for(n=0;n<my_trig->n;n++){
+               for(i=0;i<n_chan;i++){
+                       it->n_chan=1;
+                       it->data=devpriv->data+i;
+                       it->chanlist=my_trig->chanlist+i;
+
+                       ret=comedi_trig_ioctl(devpriv->device,devpriv->subd,it);
+
+                       if(ret<0){
+                               /* eek! */
+                       }
+               }
+               for(i=0;i<n_chan;i++){
+                       buf_add(dev,s,devpriv->data[i]);
+               }
+#ifdef CONFIG_COMEDI_RTL
+               rt_task_wait();
+#endif
+#ifdef CONFIG_COMEDI_RTAI
+               //rt_task_wait();
+#endif
+       }
+#ifdef CONFIG_COMEDI_RTL
+       rtl_global_pend_irq(devpriv->soft_irq);
+#endif
+#ifdef CONFIG_COMEDI_RTAI
+       //rtl_global_pend_irq(devpriv->soft_irq);
+#endif
+
+       rt_task_delete(&devpriv->rt_task);
+
+       /* eek! */
+}
+
+static int timer_ai_mode0(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
+{
+       return comedi_trig_ioctl(devpriv->device,devpriv->subd,it);
+}
+
+static int timer_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
+{
+       if(cmd->scan_begin_arg<100000)  /* 10 khz */
+               cmd->scan_begin_arg=100000;
+       if(cmd->scan_begin_arg>1e9)     /* 1 hz */
+               cmd->scan_begin_arg=1e9;
+
+       return 0;
+}
+
+static int timer_cmd(comedi_device *dev,comedi_subdevice *s)
+{
+       int ret;
+       RTIME now,period;
+       struct timespec ts;
+       comedi_cmd *cmd = &s->cmd;
+
+       ret=comedi_lock_ioctl(devpriv->device,devpriv->subd);
+       if(ret<0)return ret;
+
+       /* XXX this does not get freed */
+       devpriv->data=kmalloc(sizeof(sampl_t)*cmd->chanlist_len,GFP_KERNEL);
+       if(!devpriv->data){
+               ret=-ENOMEM;
+               goto unlock;
+       }
+
+       devpriv->trig.subdev=devpriv->subd;
+       devpriv->trig.mode=0;
+       devpriv->trig.flags=0;
+       devpriv->trig.n=1;
+
+       ts.tv_sec=0;
+       ts.tv_nsec=cmd->scan_begin_arg;
+
+#ifdef CONFIG_COMEDI_RTL
+       period=timespec_to_RTIME(ts);
+       rt_task_init(&devpriv->rt_task,timer_ai_task_func,(int)dev,3000,4);
+#endif
+#ifdef CONFIG_COMEDI_RTAI
+       period = 0;
+       //period=timespec_to_RTIME(ts);
+       //rt_task_init(&devpriv->rt_task,timer_ai_task_func,(int)dev,3000,4);
+#endif
+
+       now=rt_get_time();
+       rt_task_make_periodic(&devpriv->rt_task,now+period,period);
+
+       return 0;
+
+unlock:
+       comedi_unlock_ioctl(devpriv->device,devpriv->subd);
+       return ret;
+}
+
+static int timer_ai_mode2(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
+{
+       int ret;
+       RTIME now,period;
+       struct timespec ts;
+
+       //if(it->trigvar1!=0)return -EINVAL;
+       if(it->trigvar<100000)return -EINVAL;   /* 10 khz */
+       
+       ret=comedi_lock_ioctl(devpriv->device,devpriv->subd);
+       if(ret<0)goto out;
+
+#if 0
+       struct timespec ts;
+
+       ts.tv_sec=0;
+       ts.tv_nsec=it->trigvar;
+#endif
+
+       /* XXX this does not get freed */
+       devpriv->data=kmalloc(sizeof(sampl_t)*it->n_chan,GFP_KERNEL);
+       if(!devpriv->data){
+               ret=-ENOMEM;
+               goto unlock;
+       }
+
+       devpriv->trig.subdev=devpriv->subd;
+       devpriv->trig.mode=0;
+       devpriv->trig.flags=0;
+       devpriv->trig.n=1;
+
+       ts.tv_sec=0;
+       ts.tv_nsec=it->trigvar;
+#ifdef CONFIG_COMEDI_RTL
+       period=timespec_to_RTIME(ts);
+       rt_task_init(&devpriv->rt_task,timer_ai_task_func,(int)dev,3000,4);
+#endif
+#ifdef CONFIG_COMEDI_RTAI
+       period = 0;
+       //period=timespec_to_RTIME(ts);
+       //rt_task_init(&devpriv->rt_task,timer_ai_task_func,(int)dev,3000,4);
+#endif
+
+       now=rt_get_time();
+       rt_task_make_periodic(&devpriv->rt_task,now+period,period);
+
+       return 0;
+
+unlock:
+       comedi_unlock_ioctl(devpriv->device,devpriv->subd);
+out:
+       return ret;
+}
+
+int timer_cancel(comedi_device *dev,comedi_subdevice *s)
+{
+       rt_task_delete(&devpriv->rt_task);
+
+       comedi_unlock_ioctl(devpriv->device,devpriv->subd);
+
+       return 0;
+}
+
+static int timer_attach(comedi_device *dev,comedi_devconfig *it)
+{
+       int ret;
+       comedi_subdevice *s;
+
+       printk("comedi%d: timer: ",dev->minor);
+       dev->board_name="timer";
+
+       dev->n_subdevices=1;
+       if((ret=alloc_subdevices(dev))<0)
+               return ret;
+       if((ret=alloc_private(dev,sizeof(timer_private)))<0)
+               return ret;
+
+       devpriv->device=it->options[0];
+       devpriv->subd=it->options[1];
+
+       devpriv->dev=comedi_get_device_by_minor(devpriv->device);
+       devpriv->s=devpriv->dev->subdevices+devpriv->subd;
+
+       s=dev->subdevices+0;
+       s->type=COMEDI_SUBD_AI;
+       s->subdev_flags=SDF_READABLE;
+       s->n_chan=devpriv->s->n_chan;
+       s->len_chanlist=1024;
+       s->trig[0]=timer_ai_mode0;
+       s->trig[2]=timer_ai_mode2;
+       s->do_cmd=timer_cmd;
+       s->do_cmdtest=timer_cmdtest;
+       s->cancel=timer_cancel;
+       s->maxdata=devpriv->s->maxdata;
+       s->range_table=devpriv->s->range_table;
+       s->range_table_list=devpriv->s->range_table_list;
+
+#ifdef CONFIG_COMEDI_RTL
+       devpriv->soft_irq=rtl_get_soft_irq(timer_interrupt,"timer");
+       broken_rtl_dev=dev;
+#endif
+#ifdef CONFIG_COMEDI_RTAI
+       //devpriv->soft_irq=rtl_get_soft_irq(timer_interrupt,"timer");
+#endif
+
+       printk("\n");
+
+       return 1;
+}
+
+
+static int timer_detach(comedi_device *dev)
+{
+       printk("comedi%d: timer: remove\n",dev->minor);
+       
+       free_irq(devpriv->soft_irq,NULL);
+
+       return 0;
+}
+
+