PATCH[1/3]: comedi : submissions of contec_fit.c driver to staging/comedi/drivers
Dan Naughton
daniel.naughton at gmail.com
Mon May 22 15:19:53 UTC 2017
Adding new driver to drivers/staging/comedi/drivers for contec_fit.c
for CONTEC F&eIT modules
Signed off by dan.naughton at dtx.com
----
diff -ruN linux.bak/drivers/staging/comedi/drivers/contec_fit.c
linux/drivers/staging/comedi/drivers/contec_fit.c
--- linux.bak/drivers/staging/comedi/drivers/contec_fit.c
1969-12-31 18:00:00.000000000 -0600
+++ linux/drivers/staging/comedi/drivers/contec_fit.c 2017-05-20
15:02:03.715167366 -0500
@@ -0,0 +1,908 @@
+/*
+ comedi/drivers/contec_fit.c
+
+ COMEDI - Linux Control and Measurement Device Interface
+ Copyright (C) 2000 David A. Schleef <ds at 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: contec_fit
+Description: Contec F&eIT series modules
+Devices: [Contec] DAI12-4(FIT)GY (contec_fit), ADI16-4(FIT)GY, DIO-8/8(FIT)GY
+Author: Contec Co., Ltd.
+Updated: Thu, 18 May 2017 14:30:00 +0900
+Status: works
+
+Configuration Options:
+ [0] - DeviceID of module (optional)
+ If DeviceID is not specified, DeviceID 0 will be used.
+*/
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include "../comedidev.h"
+#include <linux/delay.h>
+
+typedef struct {
+ struct task_struct *fit_kthread;
+} contec_fit_private;
+
+#define devpriv ((contec_fit_private *)dev->private)
+
+static int contec_attach(struct comedi_device * dev, struct
comedi_devconfig * it);
+static void contec_detach(struct comedi_device * dev);
+static struct comedi_driver driver_contec = {
+ .driver_name = "contec_fit",
+ .module = THIS_MODULE,
+ .attach = contec_attach,
+ .detach = contec_detach,
+};
+
+/* Classic digital IO */
+static int contec_ai_insn_read(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
+static int contec_ao_insn_write(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
+static int contec_di_insn_bits(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
+static int contec_do_insn_bits(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
+
+static int contec_ai_cmdtest(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_cmd * cmd);
+static int contec_ai_cmd(struct comedi_device * dev, struct
comedi_subdevice * s);
+static int contec_ai_sampling_thread(void * context_dev);
+static int contec_ai_cancel(struct comedi_device * dev, struct
comedi_subdevice * s);
+
+static int contec_ao_cmdtest(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_cmd * cmd);
+static int contec_ao_cmd(struct comedi_device * dev, struct
comedi_subdevice * s);
+static int contec_ao_sampling_thread(void * context_dev);
+static int contec_ao_cancel(struct comedi_device * dev, struct
comedi_subdevice * s);
+static int contec_ao_cmd_inttrig(struct comedi_device *dev, struct
comedi_subdevice *s, unsigned int trignum);
+
+static void contec_check_sampling_clock(unsigned int *sampling_clock,
unsigned int *channel_num, int flags);
+
+//START ADDRESS
+#define ADDRESS_BASE 0x0800
+#define ADDRESS_PER_ID 0x1000
+
+//CONTEC FIT SIZE
+#define CONTEC_FIT_SIZE 0x20
+
+//COMMON IO
+#define IO_PRODUCT_CATEGORY 0x00
+#define IO_PRODUCT_ID_NUMBER 0x01
+#define IO_COMMAND_DATA 0x18
+#define IO_SETUP_DATA0 0x1C
+#define IO_SETUP_DATA1 0x1D
+#define IO_SETUP_DATA2 0x1E
+#define IO_SETUP_DATA3 0x1F
+
+//DAI12-4(FIT)GY IO
+#define IO_DAI124_OUTPUTDATA_LOWER 0x10
+#define IO_DAI124_OUTPUTDATA_UPPER 0x11
+#define IO_DAI124_CHANNELDATA 0x12
+#define IO_DAI124_STATUS 0x16
+
+//ADI16-4(FIT)GY IO
+#define IO_ADI164_INPUTDATA_LOWER 0x10
+#define IO_ADI164_INPUTDATA_UPPER 0x11
+#define IO_ADI164_CHANNELDATA 0x12
+#define IO_ADI164_STATUS0 0x16
+#define IO_ADI164_STATUS1 0x17
+
+//DIO-8/8(FIT)GY IO
+#define IO_DIO88_INPUT0 0x10
+#define IO_DIO88_OUTPUT0 0x14
+
+//DAI12-4(FIT)GY COMMAND
+#define COMMAND_DAI124_INIT 0x00
+#define COMMAND_DAI124_DASETUP 0x02
+#define COMMAND_DAI124_OUTPUT_RANGE 0x03
+#define COMMAND_DAI124_PASERCLOCK 0x04
+#define COMMAND_DAI124_TIMER_START 0x05
+#define COMMAND_DAI124_TIMER_STOP 0x06
+
+//ADI16-4(FIT)GY COMMAND
+#define COMMAND_ADI164_INIT 0x00
+#define COMMAND_ADI164_SAMPLING_SETUP 0x02
+#define COMMAND_ADI164_INPUT_RANGE 0x03
+#define COMMAND_ADI164_SAMPLING_CLOCK 0x04
+#define COMMAND_ADI164_TIMER_START 0x05
+#define COMMAND_ADI164_TIMER_STOP 0x06
+#define COMMAND_ADI164_FIFO_FLAG 0x07
+
+//CATEGORY NUMBER
+#define CATEGORY_AIO 0x20
+#define CATEGORY_DIO 0x10
+
+//PRODUCT ID NUMBER
+#define PRODUCTID_DAI124 0x01
+#define PRODUCTID_ADI164 0x02
+#define PRODUCTID_DIO88 0x00
+
+//SUBDEVICE DAI12-4(FIT)GY
+#define SUBDEVICE_DAI124_AO 0x00
+
+//SUBDEVICE ADI16-4(FIT)GY
+#define SUBDEVICE_ADI164_AI 0x00
+
+//SUBDEVICE DIO-8/8(FIT)GY
+#define SUBDEVICE_DIO88_DI 0x00
+#define SUBDEVICE_DIO88_DO 0x01
+
+//RANGE
+#define RANGE_BIPOLAR_10 0x00
+
+//STATUS DAI12-4(FIT)GY
+#define STATUS_DAI124_DSB 0x01
+#define STATUS_DAI124_EOC 0x02
+#define STATUS_DAI124_PCI 0x10
+#define STATUS_DAI124_PCE 0x20
+
+//STATUS ADI16-4(FIT)GY
+#define STATUS_ADI164_DRE 0x01
+#define STATUS_ADI164_DOE 0x04
+#define STATUS_ADI164_SCE 0x20
+
+//SAMPLING SETUP ADI16-4(FIT)GY
+#define SAMPLING_SETUP_ADI164_CHANNELMODE_MULTI 0x04
+#define SAMPLING_SETUP_ADI164_SAMPLINGCLOCK_INTERNAL 0x00
+#define SAMPLING_SETUP_ADI164_SAMPLINGMODE_CLOCK 0x01
+
+//FIFO FLAG ADI16-4(FIT)GY
+#define FIFOFLAG_ADI164_DATACOUNT_1 0x01
+
+//DACONVERT SETUP DAI12-4(FIT)GY
+#define DACONVERT_SETUP_DAI124_SAMPLINGMODE_CLOCK 0x01
+#define DACONVERT_SETUP_DAI124_OUTPUTMODE_SYNCOUT 0x04
+
+//CHANNEL DATA DAI12-4(FIT)GY
+#define CHANNELDATA_DAI124_ENDCHANNEL 0x40
+
+static int contec_attach(struct comedi_device * dev, struct
comedi_devconfig * it)
+{
+ struct comedi_subdevice *s;
+ int deviceid, device_address;
+ int product_category, product_id_number;
+
+ printk(KERN_INFO "comedi%d: contec\n", dev->minor);
+ if (comedi_alloc_devpriv(dev, sizeof(contec_fit_private)) < 0){
+ return -ENOMEM;
+ }
+
+ deviceid = it->options[0];
+ if(deviceid < 0 || deviceid > 7){
+ printk(KERN_ERR "comedi%d: contec: ID %d out of range\n",
dev->minor, deviceid);
+ return -EINVAL;
+ }
+ device_address = ADDRESS_BASE + (ADDRESS_PER_ID * deviceid);
+ if(!request_region(device_address, CONTEC_FIT_SIZE, "contec_fit")){
+ printk(KERN_ERR "comedi%d: contec: 0x%04x I/O port
conflict\n", dev->minor, device_address);
+ return -EIO;
+ }
+ product_category = inb(device_address + IO_PRODUCT_CATEGORY);
+ product_id_number = inb(device_address + IO_PRODUCT_ID_NUMBER);
+ dev->iobase = device_address;
+ devpriv->fit_kthread = NULL;
+
+ switch(product_category & 0xf0){
+ case CATEGORY_AIO:
+ switch(product_id_number){
+ case PRODUCTID_DAI124:
+ if (comedi_alloc_subdevices(dev, 1) < 0){
+ return -ENOMEM;
+ }
+ dev->board_name = "DAI12-4(FIT)GY";
+
+ s = dev->subdevices + SUBDEVICE_DAI124_AO;
+ dev->write_subdev = s;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE | SDF_CMD_WRITE;
+ s->len_chanlist = 4;
+ s->n_chan = 4;
+ s->maxdata = 0xfff;
+ s->range_table = &range_bipolar10;
+ s->insn_write = contec_ao_insn_write;
+ s->do_cmdtest = contec_ao_cmdtest;
+ s->do_cmd = &contec_ao_cmd;
+ s->cancel = contec_ao_cancel;
+
+ return 1;
+ case PRODUCTID_ADI164:
+ if (comedi_alloc_subdevices(dev, 1) < 0){
+ return -ENOMEM;
+ }
+ dev->board_name = "ADI16-4(FIT)GY";
+
+ s = dev->subdevices + SUBDEVICE_ADI164_AI;
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
+ s->len_chanlist = 4;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->range_table = &range_bipolar10;
+ s->insn_read = contec_ai_insn_read;
+ s->do_cmdtest = contec_ai_cmdtest;
+ s->do_cmd = contec_ai_cmd;
+ s->cancel = contec_ai_cancel;
+
+ return 1;
+ }
+ break;
+ case CATEGORY_DIO:
+ switch(product_id_number){
+ case PRODUCTID_DIO88:
+ if (comedi_alloc_subdevices(dev, 2) < 0){
+ return -ENOMEM;
+ }
+ dev->board_name = "DIO-8/8(FIT)GY";
+
+ s = dev->subdevices + SUBDEVICE_DIO88_DI;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = contec_di_insn_bits;
+
+ s = dev->subdevices + SUBDEVICE_DIO88_DO;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = contec_do_insn_bits;
+ s->state = inb(dev->iobase + IO_DIO88_OUTPUT0);
+
+ return 1;
+ }
+ break;
+ }
+
+ return -EIO;
+}
+
+static void contec_detach(struct comedi_device * dev)
+{
+ printk(KERN_INFO "comedi%d: contec: remove\n", dev->minor);
+
+ if(dev->iobase){
+ release_region(dev->iobase, CONTEC_FIT_SIZE);
+ }
+}
+
+static int contec_ai_insn_read(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+ int lcount;
+ int i;
+ int channel;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ai_insn_read
called\n", dev->minor);
+
+ channel = CR_CHAN(insn->chanspec);
+
+ outb(COMMAND_ADI164_INIT, dev->iobase + IO_COMMAND_DATA);
+
+ for(i = 0; i < insn->n; i++){
+ outb(channel, dev->iobase + IO_ADI164_CHANNELDATA);
+ lcount = 0;
+ while(!(inb(dev->iobase + IO_ADI164_STATUS0) & STATUS_ADI164_DRE)){
+ lcount++;
+ if(lcount > 50000){
+ return -EIO;
+ }
+ udelay(1);
+ }
+ data[i] = inb(dev->iobase + IO_ADI164_INPUTDATA_LOWER) +
(inb(dev->iobase + IO_ADI164_INPUTDATA_UPPER) << 8);
+ }
+
+ return i;
+}
+
+static int contec_ao_insn_write(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+ int lcount;
+ int i;
+ int channel;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ao_insn_write
called\n", dev->minor);
+
+ channel = CR_CHAN(insn->chanspec);
+
+ outb(COMMAND_DAI124_INIT, dev->iobase + IO_COMMAND_DATA);
+
+ for(i = 0; i < insn->n; i++){
+ lcount = 0;
+ while((inb(dev->iobase + IO_DAI124_STATUS) & STATUS_DAI124_DSB)){
+ lcount++;
+ if(lcount > 50000){
+ return -EIO;
+ }
+ udelay(1);
+ }
+ outb(channel, dev->iobase + IO_DAI124_CHANNELDATA);
+ outb(data[i] & 0xff, dev->iobase + IO_DAI124_OUTPUTDATA_LOWER);
+ outb(((data[i] & 0xff00) >> 8), dev->iobase +
IO_DAI124_OUTPUTDATA_UPPER);
+ lcount = 0;
+ while(!(inb(dev->iobase + IO_DAI124_STATUS) & STATUS_DAI124_EOC)){
+ lcount++;
+ if(lcount > 50000){
+ return -EIO;
+ }
+ udelay(1);
+ }
+ outb(STATUS_DAI124_EOC, dev->iobase + IO_DAI124_STATUS);
+ }
+
+ return i;
+}
+
+static int contec_ai_cmdtest(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_cmd * cmd)
+{
+ int err = 0;
+ int tmp, i;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ai_cmdtest called\n",
dev->minor);
+
+ tmp = cmd->start_src;
+ cmd->start_src &= TRIG_NOW;
+ if(!cmd->start_src || tmp != cmd->start_src){
+ err++;
+ }
+
+ tmp = cmd->scan_begin_src;
+ cmd->scan_begin_src &= TRIG_TIMER;
+ if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src){
+ err++;
+ }
+
+ tmp = cmd->convert_src;
+ cmd->convert_src &= TRIG_NOW;
+ if(!cmd->convert_src || tmp != cmd->convert_src){
+ err++;
+ }
+
+ tmp = cmd->stop_src;
+ cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
+ if(!cmd->stop_src || tmp != cmd->stop_src){
+ err++;
+ }
+
+ tmp = cmd->scan_end_src;
+ cmd->scan_end_src &= TRIG_COUNT;
+ if(!cmd->scan_end_src || tmp != cmd->scan_end_src){
+ err++;
+ }
+
+ if(err){
+ return 1;
+ }
+
+ if(cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE){
+ err++;
+ }
+
+ if(err){
+ return 2;
+ }
+
+ if(cmd->start_arg != 0){
+ cmd->start_arg = 0;
+ err++;
+ }
+
+ if(!cmd->chanlist_len){
+ cmd->chanlist_len = 1;
+ err++;
+ }else if(cmd->chanlist_len > 4){
+ cmd->chanlist_len = 4;
+ err++;
+ }
+ if(cmd->scan_begin_arg < 10000 * cmd->chanlist_len + 20000){
+ cmd->scan_begin_arg = 10000 * cmd->chanlist_len + 20000;
+ err++;
+ }
+
+ if(cmd->convert_arg != 0){
+ cmd->convert_arg = 0;
+ err++;
+ }
+ if(cmd->stop_src == TRIG_COUNT)
+ {
+ if(!cmd->stop_arg){
+ cmd->stop_arg = 1;
+ err++;
+ }
+ }else{
+ if(cmd->stop_arg != 0){
+ cmd->stop_arg = 0;
+ err++;
+ }
+ }
+
+ if(cmd->scan_end_arg != cmd->chanlist_len){
+ cmd->scan_end_arg = cmd->chanlist_len;
+ err++;
+ }
+
+ if(err){
+ return 3;
+ }
+
+ tmp = cmd->scan_begin_arg;
+ contec_check_sampling_clock(&cmd->scan_begin_arg,
&cmd->chanlist_len, cmd->flags);
+ if(tmp != cmd->scan_begin_arg){
+ err++;
+ }
+
+ if(err){
+ return 4;
+ }
+
+ if(cmd->chanlist){
+ for(i = 0; i < cmd->chanlist_len; i++){
+ if(CR_CHAN(cmd->chanlist[i]) != i){
+ err++;
+ break;
+ }
+ }
+ }
+
+ if(err){
+ return 5;
+ }
+
+ return 0;
+}
+
+static int contec_ao_cmdtest(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_cmd * cmd)
+{
+ int err = 0;
+ int tmp, i;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ao_cmdtest called\n",
dev->minor);
+
+ tmp = cmd->start_src;
+ cmd->start_src &= TRIG_INT;
+ if(!cmd->start_src || tmp != cmd->start_src){
+ err++;
+ }
+
+ tmp = cmd->scan_begin_src;
+ cmd->scan_begin_src &= TRIG_TIMER;
+ if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src){
+ err++;
+ }
+
+ tmp = cmd->convert_src;
+ cmd->convert_src &= TRIG_NOW;
+ if(!cmd->convert_src || tmp != cmd->convert_src){
+ err++;
+ }
+
+ tmp = cmd->stop_src;
+ cmd->stop_src &= TRIG_COUNT;
+ if(!cmd->stop_src || tmp != cmd->stop_src){
+ err++;
+ }
+
+ tmp = cmd->scan_end_src;
+ cmd->scan_end_src &= TRIG_COUNT;
+ if(!cmd->scan_end_src || tmp != cmd->scan_end_src){
+ err++;
+ }
+
+ if(err){
+ return 1;
+ }
+
+ if(cmd->stop_src != TRIG_COUNT){
+ err++;
+ }
+
+ if(err){
+ return 2;
+ }
+ if(cmd->start_arg != 0){
+ cmd->start_arg = 0;
+ err++;
+ }
+
+ if(!cmd->chanlist_len){
+ cmd->chanlist_len = 1;
+ err++;
+ }else if(cmd->chanlist_len > 4){
+ cmd->chanlist_len = 4;
+ err++;
+ }
+ if(cmd->scan_begin_arg < 10000 * cmd->chanlist_len + 20000){
+ cmd->scan_begin_arg = 10000 * cmd->chanlist_len + 20000;
+ err++;
+ }
+
+ if(cmd->convert_arg != 0){
+ cmd->convert_arg = 0;
+ err++;
+ }
+ if(cmd->stop_src == TRIG_COUNT)
+ {
+ if(!cmd->stop_arg){
+ cmd->stop_arg = 1;
+ err++;
+ }
+ }else{
+ if(cmd->stop_arg != 0){
+ cmd->stop_arg = 0;
+ err++;
+ }
+ }
+
+ if(cmd->scan_end_arg != cmd->chanlist_len){
+ cmd->scan_end_arg = cmd->chanlist_len;
+ err++;
+ }
+
+ if(err){
+ return 3;
+ }
+
+ tmp = cmd->scan_begin_arg;
+ contec_check_sampling_clock(&cmd->scan_begin_arg,
&cmd->chanlist_len, cmd->flags);
+ if(tmp != cmd->scan_begin_arg){
+ err++;
+ }
+
+ if(err){
+ return 4;
+ }
+
+ if(cmd->chanlist){
+ for(i = 0; i < cmd->chanlist_len; i++){
+ if(CR_CHAN(cmd->chanlist[i]) != i){
+ err++;
+ break;
+ }
+ }
+ }
+
+ if(err){
+ return 5;
+ }
+
+ return 0;
+}
+
+static int contec_ai_cmd(struct comedi_device * dev, struct
comedi_subdevice * s)
+{
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ long clockdata;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ai_cmd called\n", dev->minor);
+
+ outb(COMMAND_ADI164_INIT, dev->iobase + IO_COMMAND_DATA);
+
+ outb(COMMAND_ADI164_SAMPLING_SETUP, dev->iobase + IO_COMMAND_DATA);
+ outb( SAMPLING_SETUP_ADI164_CHANNELMODE_MULTI |
+ SAMPLING_SETUP_ADI164_SAMPLINGCLOCK_INTERNAL |
+ SAMPLING_SETUP_ADI164_SAMPLINGMODE_CLOCK,
+ dev->iobase + IO_SETUP_DATA0);
+
+ outb(COMMAND_ADI164_FIFO_FLAG, dev->iobase + IO_COMMAND_DATA);
+ outb(FIFOFLAG_ADI164_DATACOUNT_1, dev->iobase + IO_SETUP_DATA0);
+
+ contec_check_sampling_clock(&cmd->scan_begin_arg,
&cmd->chanlist_len, cmd->flags);
+
+ clockdata = cmd->scan_begin_arg / 250 - 1;
+
+ outb(COMMAND_ADI164_SAMPLING_CLOCK, dev->iobase + IO_COMMAND_DATA);
+ outb(clockdata & 0xff, dev->iobase + IO_SETUP_DATA0);
+ outb((clockdata >> 8) & 0xff, dev->iobase + IO_SETUP_DATA1);
+ outb((clockdata >> 16) & 0xff, dev->iobase + IO_SETUP_DATA2);
+ outb((clockdata >> 24) & 0xff, dev->iobase + IO_SETUP_DATA3);
+
+ devpriv->fit_kthread = kthread_run(contec_ai_sampling_thread,
(void *)dev, "fit_ai");
+ if(IS_ERR(devpriv->fit_kthread)){
+ devpriv->fit_kthread = NULL;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int contec_ao_cmd(struct comedi_device * dev, struct
comedi_subdevice * s)
+{
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ long clockdata;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ao_cmd called\n", dev->minor);
+
+ outb(COMMAND_DAI124_INIT, dev->iobase + IO_COMMAND_DATA);
+
+ outb(COMMAND_DAI124_DASETUP, dev->iobase + IO_COMMAND_DATA);
+ outb(DACONVERT_SETUP_DAI124_SAMPLINGMODE_CLOCK |
DACONVERT_SETUP_DAI124_OUTPUTMODE_SYNCOUT, dev->iobase +
IO_SETUP_DATA0);
+
+ contec_check_sampling_clock(&cmd->scan_begin_arg,
&cmd->chanlist_len, cmd->flags);
+
+ clockdata = cmd->scan_begin_arg / 250 - 1;
+ outb(COMMAND_DAI124_PASERCLOCK, dev->iobase + IO_COMMAND_DATA);
+ outb(clockdata & 0xff, dev->iobase + IO_SETUP_DATA0);
+ outb((clockdata >> 8) & 0xff, dev->iobase + IO_SETUP_DATA1);
+ outb((clockdata >> 16) & 0xff, dev->iobase + IO_SETUP_DATA2);
+ outb((clockdata >> 24) & 0xff, dev->iobase + IO_SETUP_DATA3);
+
+ if(cmd->start_src == TRIG_INT){
+ s->async->inttrig = contec_ao_cmd_inttrig;
+ }
+
+ return 0;
+}
+
+static int contec_ao_cmd_inttrig(struct comedi_device *dev, struct
comedi_subdevice *s, unsigned int trignum)
+{
+ if(trignum != 0){
+ return -EINVAL;
+ }
+
+ s->async->inttrig = 0;
+ devpriv->fit_kthread = kthread_run(contec_ao_sampling_thread,
(void *)dev, "fit_ao");
+ if(IS_ERR(devpriv->fit_kthread)){
+ devpriv->fit_kthread = NULL;
+ return -EIO;
+ }
+
+ return 1;
+}
+
+static int contec_do_insn_bits(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+ printk(KERN_INFO "comedi%d: contec: contec_do_insn_bits
called\n", dev->minor);
+
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]){
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ outw(s->state, dev->iobase + IO_DIO88_OUTPUT0);
+ }
+ data[1] = s->state;
+
+ return 2;
+}
+
+static int contec_di_insn_bits(struct comedi_device * dev, struct
comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+ printk(KERN_INFO "comedi%d: contec: contec_di_insn_bits
called\n", dev->minor);
+
+ if (insn->n != 2)
+ return -EINVAL;
+
+ data[1] = inw(dev->iobase + IO_DIO88_INPUT0);
+
+ return 2;
+}
+
+static void contec_check_sampling_clock(unsigned int *sampling_clock,
unsigned int *channel_num, int flags)
+{
+ int clock_tmp;
+
+ if(*channel_num < 1){
+ *channel_num = 1;
+ }else if(*channel_num > 4){
+ *channel_num = 4;
+ }
+ if(*sampling_clock < ((10000 * *channel_num) + 20000)){
+ *sampling_clock = ((10000 * *channel_num) + 20000);
+ }
+
+ clock_tmp = *sampling_clock % 250;
+ if(clock_tmp != 0){
+ switch(flags & TRIG_ROUND_MASK){
+ case TRIG_ROUND_UP:
+ *sampling_clock += 250 - clock_tmp;
+ break;
+ case TRIG_ROUND_DOWN:
+ *sampling_clock -= clock_tmp;
+ break;
+ case TRIG_ROUND_NEAREST:
+ default:
+ if(clock_tmp < 126){
+ *sampling_clock -= clock_tmp;
+ }else{
+ *sampling_clock += 250 - clock_tmp;
+ }
+ break;
+ }
+ }
+}
+
+static int contec_ai_sampling_thread(void * context_dev)
+{
+ struct comedi_device *dev = (struct comedi_device *)context_dev;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ int sampling_count;
+ int status;
+ unsigned short aidata;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ai_sampling_thread
called\n", dev->minor);
+
+ outb((cmd->chanlist_len - 1), dev->iobase + IO_ADI164_CHANNELDATA);
+
+ outb(COMMAND_ADI164_TIMER_START, dev->iobase + IO_COMMAND_DATA);
+
+ sampling_count = 0;
+ while(!kthread_should_stop()){
+ schedule();
+ async->events = 0;
+ status = inb(dev->iobase + IO_ADI164_STATUS0);
+ if(status & STATUS_ADI164_DRE){
+ aidata = inb(dev->iobase + IO_ADI164_INPUTDATA_LOWER) +
(inb(dev->iobase + IO_ADI164_INPUTDATA_UPPER) << 8);
+ if(!comedi_buf_write_samples(s, &aidata, 1)){
+ async->events = COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ break;
+ }
+ sampling_count++;
+ if(cmd->stop_src == TRIG_COUNT){
+ if((cmd->stop_arg * cmd->chanlist_len) <= sampling_count){
+ async->events |= COMEDI_CB_EOA;
+ printk(KERN_INFO "comedi%d: contec:
contec_ai_sampling_thread TRIG_COUNT\n", dev->minor);
+ break;
+ }
+ }
+ if(!(sampling_count % cmd->chanlist_len)){
+ async->events = COMEDI_CB_BLOCK;
+ comedi_event(dev, s);
+ }
+ continue;
+ }
+ if(status & (STATUS_ADI164_DOE | STATUS_ADI164_SCE)){
+ async->events = COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ printk(KERN_ERR "comedi%d: contec:
contec_ai_sampling_thread ERROR = %d\n", dev->minor, status);
+ break;
+ }
+ }
+
+ outb(COMMAND_ADI164_TIMER_STOP, dev->iobase + IO_COMMAND_DATA);
+
+ comedi_event(dev, s);
+
+ return 0;
+}
+
+static int contec_ao_sampling_thread(void * context_dev)
+{
+ struct comedi_device *dev = (struct comedi_device *)context_dev;
+ struct comedi_subdevice *s = dev->write_subdev;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ int sampling_count;
+ int channel_num;
+ unsigned short data;
+ int status;
+ int i;
+ int count;
+
+ printk(KERN_INFO "comedi%d: contec: contec_ao_sampling_thread
called\n", dev->minor);
+
+ sampling_count = 0;
+ channel_num = 0;
+ count = 0;
+
+ status = inb(dev->iobase + IO_DAI124_STATUS);
+ while((status & STATUS_DAI124_DSB)){
+ count++;
+ if(count > 50000){
+ async->events |= COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ return 0;
+ }
+ }
+
+ for(i = 0; i < cmd->chanlist_len; i++){
+ if(!comedi_buf_read_samples(s, &data, 1)){
+ async->events = COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+
+ return 0;
+ }
+ if(i < (cmd->chanlist_len - 1)){
+ outb(i, dev->iobase + IO_DAI124_CHANNELDATA);
+ }else{
+ outb(i | CHANNELDATA_DAI124_ENDCHANNEL, dev->iobase +
IO_DAI124_CHANNELDATA);
+ }
+ outb(data & 0xff, dev->iobase + IO_DAI124_OUTPUTDATA_LOWER);
+ outb(((data & 0xf00) >> 8), dev->iobase + IO_DAI124_OUTPUTDATA_UPPER);
+ }
+
+ outb(COMMAND_DAI124_TIMER_START, dev->iobase + IO_COMMAND_DATA);
+
+ while(!kthread_should_stop()){
+ schedule();
+ async->events = 0;
+ status = inb(dev->iobase + IO_DAI124_STATUS);
+ if((status & STATUS_DAI124_EOC)){
+ sampling_count++;
+ if(cmd->stop_src == TRIG_COUNT){
+ if(cmd->stop_arg <= sampling_count){
+ async->events |= COMEDI_CB_EOA;
+ printk(KERN_INFO "comedi%d: contec:
contec_ao_sampling_thread TRIG_COUNT\n", dev->minor);
+ break;
+ }
+ }
+ for(i = 0; i < cmd->chanlist_len; i++){
+ if(!comedi_buf_read_samples(s, &data, 1)){
+ async->events = COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ break;
+ }
+ if(i < (cmd->chanlist_len - 1)){
+ outb(i, dev->iobase + IO_DAI124_CHANNELDATA);
+ }else{
+ outb(i | CHANNELDATA_DAI124_ENDCHANNEL,
dev->iobase + IO_DAI124_CHANNELDATA);
+ }
+ outb(data & 0xff, dev->iobase + IO_DAI124_OUTPUTDATA_LOWER);
+ outb(((data & 0xf00) >> 8), dev->iobase +
IO_DAI124_OUTPUTDATA_UPPER);
+ }
+ outb(status & (STATUS_DAI124_EOC | STATUS_DAI124_PCI),
dev->iobase + IO_DAI124_STATUS);
+ async->events = COMEDI_CB_BLOCK;
+ comedi_event(dev, s);
+
+ continue;
+ }
+ if(status & STATUS_DAI124_PCE){
+ async->events = COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ printk(KERN_ERR "comedi%d: contec:
contec_ai_sampling_thread ERROR = %d\n", dev->minor, status);
+ break;
+ }
+ }
+
+ outb(COMMAND_DAI124_TIMER_STOP, dev->iobase + IO_COMMAND_DATA);
+
+ comedi_event(dev, s);
+
+ return 0;
+}
+
+static int contec_ai_cancel(struct comedi_device * dev, struct
comedi_subdevice * s)
+{
+ printk(KERN_INFO "comedi%d: contec: contec_ai_cancel called\n",
dev->minor);
+
+ if(devpriv->fit_kthread != NULL){
+ kthread_stop(devpriv->fit_kthread);
+ devpriv->fit_kthread = NULL;
+ }
+
+ return 0;
+}
+
+static int contec_ao_cancel(struct comedi_device * dev, struct
comedi_subdevice * s)
+{
+ printk(KERN_INFO "comedi%d: contec: contec_ao_cancel called\n",
dev->minor);
+
+ if(devpriv->fit_kthread != NULL){
+ kthread_stop(devpriv->fit_kthread);
+ devpriv->fit_kthread = NULL;
+ }
+
+ return 0;
+}
+
+module_comedi_driver(driver_contec);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
More information about the devel
mailing list