Add subdevice 1 as an analog input (AI) subdevice. It currently only supports basic, software-triggered acquisitions. This is mostly the work of Fred Brooks (MODULE_AUTHOR), but he based his update on an older version of the driver. I applied the relevant changes with a few tweaks: adding an explicit `udelay(1)` in a timeout loop, replacing binary constants with hex, renaming functions, replacing `printk()` calls, removing exported symbols, removing (very) incomplete comedi "command" support, and making some coding-style changes. Signed-off-by: Ian Abbott <abbotti@xxxxxxxxx> --- drivers/staging/comedi/drivers/ni_daq_700.c | 136 ++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 10 deletions(-) diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 2318463..2ba0ade 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -1,6 +1,6 @@ /* * comedi/drivers/ni_daq_700.c - * Driver for DAQCard-700 DIO only + * Driver for DAQCard-700 DIO/AI * copied from 8255 * * COMEDI - Linux Control and Measurement Device Interface @@ -29,14 +29,25 @@ Author: Fred Brooks <nsaspook@xxxxxxxxxxxx>, based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@xxxxxxx> Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700) Status: works -Updated: Thu, 21 Feb 2008 12:07:20 +0000 +Updated: Wed, 19 Sep 2012 12:07:20 +0000 -The daqcard-700 appears in Comedi as a single digital I/O subdevice with -16 channels. The channel 0 corresponds to the daqcard-700's output +The daqcard-700 appears in Comedi as a digital I/O subdevice (0) with +16 channels and a analog input subdevice (1) with 16 single-ended channels. + +Digital: The channel 0 corresponds to the daqcard-700's output port, bit 0; channel 8 corresponds to the input port, bit 0. -Direction configuration: channels 0-7 output, 8-15 input (8225 device +Digital direction configuration: channels 0-7 output, 8-15 input (8225 device emu as port A output, port B input, port C N/A). + +Analog: The input range is 0 to 4095 for -10 to +10 volts +IRQ is assigned but not used. + +Version 0.1 Original DIO only driver +Version 0.2 DIO and basic AI analog input support on 16 se channels + +Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf + User Manual: http://www.ni.com/pdf/manuals/320676d.pdf */ #include <linux/interrupt.h> @@ -55,8 +66,21 @@ struct daq700_board { const char *name; }; -#define DIO_W 0x04 -#define DIO_R 0x05 +/* daqcard700 registers */ +#define DIO_W 0x04 /* WO 8bit */ +#define DIO_R 0x05 /* RO 8bit */ +#define CMD_R1 0x00 /* WO 8bit */ +#define CMD_R2 0x07 /* RW 8bit */ +#define CMD_R3 0x05 /* W0 8bit */ +#define STA_R1 0x00 /* RO 8bit */ +#define STA_R2 0x01 /* RO 8bit */ +#define ADFIFO_R 0x02 /* RO 16bit */ +#define ADCLEAR_R 0x01 /* WO 8bit */ +#define CDA_R0 0x08 /* RW 8bit */ +#define CDA_R1 0x09 /* RW 8bit */ +#define CDA_R2 0x0A /* RW 8bit */ +#define CMO_R 0x0B /* RO 8bit */ +#define TIC_R 0x06 /* WO 8bit */ static int daq700_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, @@ -97,6 +121,87 @@ static int daq700_dio_insn_config(struct comedi_device *dev, return insn->n; } +static int daq700_ai_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int n, i, chan; + int d; + unsigned int status; + enum { TIMEOUT = 100 }; + + chan = CR_CHAN(insn->chanspec); + /* write channel to multiplexer */ + /* set mask scan bit high to disable scanning */ + outb(chan | 0x80, dev->iobase + CMD_R1); + + /* convert n samples */ + for (n = 0; n < insn->n; n++) { + /* trigger conversion with out0 L to H */ + outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */ + outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ + /* mode 1 out0 H, L to H, start conversion */ + outb(0x32, dev->iobase + CMO_R); + /* wait for conversion to end */ + for (i = 0; i < TIMEOUT; i++) { + status = inb(dev->iobase + STA_R2); + if ((status & 0x03) != 0) { + dev_info(dev->class_dev, + "Overflow/run Error\n"); + return -EOVERFLOW; + } + status = inb(dev->iobase + STA_R1); + if ((status & 0x02) != 0) { + dev_info(dev->class_dev, "Data Error\n"); + return -ENODATA; + } + if ((status & 0x11) == 0x01) { + /* ADC conversion complete */ + break; + } + udelay(1); + } + if (i == TIMEOUT) { + dev_info(dev->class_dev, + "timeout during ADC conversion\n"); + return -ETIMEDOUT; + } + /* read data */ + d = inw(dev->iobase + ADFIFO_R); + /* mangle the data as necessary */ + /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */ + d &= 0x0fff; + d ^= 0x0800; + data[n] = d; + } + return n; +} + +/* + * Data acquisition is enabled. + * The counter 0 output is high. + * The I/O connector pin CLK1 drives counter 1 source. + * Multiple-channel scanning is disabled. + * All interrupts are disabled. + * The analog input range is set to +-10 V + * The analog input mode is single-ended. + * The analog input circuitry is initialized to channel 0. + * The A/D FIFO is cleared. + */ +static void daq700_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned long iobase = dev->iobase; + + outb(0x80, iobase + CMD_R1); /* disable scanning, ADC to chan 0 */ + outb(0x00, iobase + CMD_R2); /* clear all bits */ + outb(0x00, iobase + CMD_R3); /* set +-10 range */ + outb(0x32, iobase + CMO_R); /* config counter mode1, out0 to H */ + outb(0x00, iobase + TIC_R); /* clear counter interrupt */ + outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */ + inw(iobase + ADFIFO_R); /* read 16bit junk from FIFO to clear */ +} + static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct daq700_board *thisboard = comedi_board(dev); @@ -116,7 +221,7 @@ static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = thisboard->name; - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; @@ -129,10 +234,20 @@ static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->insn_bits = daq700_dio_insn_bits; s->insn_config = daq700_dio_insn_config; - s->state = 0; s->io_bits = 0x00ff; + /* DAQCard-700 ai */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AI; + /* we support single-ended (ground) */ + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = (1 << 12) - 1; + s->range_table = &range_bipolar10; + s->insn_read = daq700_ai_rinsn; + daq700_ai_config(dev, s); + dev_info(dev->class_dev, "%s: %s, io 0x%lx\n", dev->driver->driver_name, dev->board_name, @@ -246,5 +361,6 @@ module_exit(daq700_cs_exit); MODULE_AUTHOR("Fred Brooks <nsaspook@xxxxxxxxxxxx>"); MODULE_DESCRIPTION( - "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO"); + "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI"); +MODULE_VERSION("0.2.00"); MODULE_LICENSE("GPL"); -- 1.7.12 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel