cb_pcidas.c revision 790c55415aa31f4c732729f94d2c3a54f7d3bfc2
159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    comedi/drivers/cb_pcidas.c
359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    Developed by Ivan Martinez and Frank Mori Hess, with valuable help from
559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    David Schleef and the rest of the Comedi developers comunity.
659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    Copyright (C) 2001-2003 Ivan Martinez <imr@oersted.dtu.dk>
859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
1059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    COMEDI - Linux Control and Measurement Device Interface
1159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
1259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
1359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    This program is free software; you can redistribute it and/or modify
1459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    it under the terms of the GNU General Public License as published by
1559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    the Free Software Foundation; either version 2 of the License, or
1659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    (at your option) any later version.
1759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
1859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    This program is distributed in the hope that it will be useful,
1959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    but WITHOUT ANY WARRANTY; without even the implied warranty of
2059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    GNU General Public License for more details.
2259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
2359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    You should have received a copy of the GNU General Public License
2459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    along with this program; if not, write to the Free Software
2559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
2759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez************************************************************************
2859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez*/
2959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
3059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezDriver: cb_pcidas
3159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezDescription: MeasurementComputing PCI-DAS series with the AMCC S5933 PCI controller
3259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezAuthor: Ivan Martinez <imr@oersted.dtu.dk>,
3359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  Frank Mori Hess <fmhess@users.sourceforge.net>
3459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezUpdated: 2003-3-11
3559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezDevices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas),
3659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr,
3759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  PCI-DAS1000, PCI-DAS1001, PCI_DAS1002
3859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
3959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezStatus:
4059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  There are many reports of the driver being used with most of the
4159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  supported cards. Despite no detailed log is maintained, it can
4259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  be said that the driver is quite tested and stable.
4359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
4459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  The boards may be autocalibrated using the comedi_calibrate
4559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  utility.
4659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
4759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezConfiguration options:
4859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  [0] - PCI bus of device (optional)
4959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  [1] - PCI slot of device (optional)
5059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  If bus/slot is not specified, the first supported
5159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez  PCI device found will be used.
5259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
5359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezFor commands, the scanned channels must be consecutive
5459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez(i.e. 4-5-6-7, 2-3-4,...), and must all have the same
5559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezrange and aref.
5659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez*/
5759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
5859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
5959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezTODO:
6059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
6159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezanalog triggering on 1602 series
6259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez*/
6359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
6459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include "../comedidev.h"
6559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include <linux/delay.h>
6659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
6759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include "8253.h"
6859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include "8255.h"
6959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include "amcc_s5933.h"
7059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include "comedi_pci.h"
7159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#include "comedi_fc.h"
7259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
7359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#undef CB_PCIDAS_DEBUG		// disable debugging code
7459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez//#define CB_PCIDAS_DEBUG       // enable debugging code
7559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
7659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// PCI vendor number of ComputerBoards/MeasurementComputing
7759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define PCI_VENDOR_ID_CB	0x1307
7859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define TIMER_BASE 100		// 10MHz master clock
7959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define AI_BUFFER_SIZE 1024	// maximum fifo size of any supported board
8059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define AO_BUFFER_SIZE 1024	// maximum fifo size of any supported board
8159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define NUM_CHANNELS_8800 8
8259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define NUM_CHANNELS_7376 1
8359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define NUM_CHANNELS_8402 2
8459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define NUM_CHANNELS_DAC08 1
8559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
8659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* PCI-DAS base addresses */
8759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
8859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// indices of base address regions
8959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define S5933_BADRINDEX 0
9059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define CONT_STAT_BADRINDEX 1
9159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define ADC_FIFO_BADRINDEX 2
9259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define PACER_BADRINDEX 3
9359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define AO_BADRINDEX 4
9459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// sizes of io regions
9559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define CONT_STAT_SIZE 10
9659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define ADC_FIFO_SIZE 4
9759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define PACER_SIZE 12
9859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define AO_SIZE 4
9959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
10059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* Control/Status registers */
10159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define INT_ADCFIFO	0	// INTERRUPT / ADC FIFO register
10259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   INT_EOS 0x1		// interrupt end of scan
10359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   INT_FHF 0x2		// interrupt fifo half full
10459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   INT_FNE 0x3		// interrupt fifo not empty
10559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   INT_MASK 0x3		// mask of interrupt select bits
10659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   INTE 0x4		// interrupt enable
10759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   DAHFIE 0x8		// dac half full interrupt enable
10859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   EOAIE	0x10		// end of aquisition interrupt enable
10959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   DAHFI	0x20		// dac half full read status / write interrupt clear
11059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   EOAI 0x40		// read end of acq. interrupt status / write clear
11159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   INT 0x80		// read interrupt status / write clear
11259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   EOBI 0x200		// read end of burst interrupt status
11359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   ADHFI 0x400		// read half-full interrupt status
11459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   ADNEI 0x800		// read fifo not empty interrupt latch status
11559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   ADNE 0x1000		// read, fifo not empty (realtime, not latched) status
11659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   DAEMIE	0x1000	// write, dac empty interrupt enable
11759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   LADFUL 0x2000		// read fifo overflow / write clear
11859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   DAEMI 0x4000		// dac fifo empty interrupt status / write clear
11959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
12059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define ADCMUX_CONT	2	// ADC CHANNEL MUX AND CONTROL register
12159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   BEGIN_SCAN(x)	((x) & 0xf)
12259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   END_SCAN(x)	(((x) & 0xf) << 4)
12359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   GAIN_BITS(x)	(((x) & 0x3) << 8)
12459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   UNIP	0x800		// Analog front-end unipolar for range
12559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   SE	0x400		// Inputs in single-ended mode
12659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   PACER_MASK	0x3000	// pacer source bits
12759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   PACER_INT 0x1000	// internal pacer
12859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   PACER_EXT_FALL	0x2000	// external falling edge
12959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   PACER_EXT_RISE	0x3000	// external rising edge
13059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   EOC	0x4000		// adc not busy
13159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
13259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define TRIG_CONTSTAT 4		// TRIGGER CONTROL/STATUS register
13359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   SW_TRIGGER 0x1	// software start trigger
13459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   EXT_TRIGGER 0x2	// external start trigger
13559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   ANALOG_TRIGGER 0x3	// external analog trigger
13659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   TRIGGER_MASK	0x3	// mask of bits that determine start trigger
13759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   TGEN	0x10		// enable external start trigger
13859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   BURSTE 0x20		// burst mode enable
13959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   XTRCL	0x80		// clear external trigger
14059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
14159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define CALIBRATION_REG	6	// CALIBRATION register
14259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   SELECT_8800_BIT	0x100	// select 8800 caldac
14359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   SELECT_TRIMPOT_BIT	0x200	// select ad7376 trim pot
14459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   SELECT_DAC08_BIT	0x400	// select dac08 caldac
14559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   CAL_SRC_BITS(x)	(((x) & 0x7) << 11)
14659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   CAL_EN_BIT	0x4000	// read calibration source instead of analog input channel 0
14759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define   SERIAL_DATA_IN_BIT	0x8000	// serial data stream going to 8800 and 7376
14859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
14959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define DAC_CSR	0x8		// dac control and status register
15059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezenum dac_csr_bits {
15159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DACEN = 0x2,		// dac enable
15259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_MODE_UPDATE_BOTH = 0x80,	// update both dacs when dac0 is written
15359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
15459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range)
15559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
15659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return (range & 0x3) << (8 + 2 * (channel & 0x1));
15759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
15859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic inline unsigned int DAC_RANGE_MASK(unsigned int channel)
15959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
16059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0x3 << (8 + 2 * (channel & 0x1));
16159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
16259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
16359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// bits for 1602 series only
16459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezenum dac_csr_bits_1602 {
16559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_EMPTY = 0x1,	// dac fifo empty, read, write clear
16659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_START = 0x4,	// start/arm dac fifo operations
16759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_PACER_MASK = 0x18,	// bits that set dac pacer source
16859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_PACER_INT = 0x8,	// dac internal pacing
16959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_PACER_EXT_FALL = 0x10,	// dac external pacing, falling edge
17059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	DAC_PACER_EXT_RISE = 0x18,	// dac external pacing, rising edge
17159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
17259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic inline unsigned int DAC_CHAN_EN(unsigned int channel)
17359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
17459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1 << (5 + (channel & 0x1));	// enable channel 0 or 1
17559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
17659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
17759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* analog input fifo */
17859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define ADCDATA	0		// ADC DATA register
17959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define ADCFIFOCLR	2	// ADC FIFO CLEAR
18059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
18159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// pacer, counter, dio registers
18259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define ADC8254 0
18359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define DIO_8255 4
18459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define DAC8254 8
18559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
18659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// analog output registers for 100x, 1200 series
18759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic inline unsigned int DAC_DATA_REG(unsigned int channel)
18859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
18959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 2 * (channel & 0x1);
19059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
19159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
19259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* analog output registers for 1602 series*/
19359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define DACDATA	0		// DAC DATA register
19459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define DACFIFOCLR	2	// DAC FIFO CLEAR
19559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
19659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// bit in hexadecimal representation of range index that indicates unipolar input range
19759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define IS_UNIPOLAR 0x4
19859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// analog input ranges for most boards
19959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic const comedi_lrange cb_pcidas_ranges = {
20059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	8,
20159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
20259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(10),
20359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(5),
20459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(2.5),
20559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(1.25),
20659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(10),
20759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(5),
20859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(2.5),
20959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(1.25)
21059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
21159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
21259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
21359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// pci-das1001 input ranges
21459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic const comedi_lrange cb_pcidas_alt_ranges = {
21559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	8,
21659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
21759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(10),
21859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(1),
21959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(0.1),
22059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(0.01),
22159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(10),
22259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(1),
22359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(0.1),
22459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(0.01)
22559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
22659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
22759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
22859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// analog output ranges
22959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic const comedi_lrange cb_pcidas_ao_ranges = {
23059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	4,
23159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
23259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(5),
23359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			BIP_RANGE(10),
23459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(5),
23559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			UNI_RANGE(10),
23659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
23759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
23859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
23959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezenum trimpot_model {
24059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	AD7376,
24159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	AD8402,
24259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
24359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
24459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martineztypedef struct cb_pcidas_board_struct {
24559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	const char *name;
24659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned short device_id;
24759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ai_se_chans;	// Inputs in single-ended mode
24859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ai_diff_chans;	// Inputs in differential mode
24959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ai_bits;		// analog input resolution
25059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ai_speed;		// fastest conversion period in ns
25159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ao_nchan;		// number of analog out channels
25259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int has_ao_fifo;	// analog output has fifo
25359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ao_scan_speed;	// analog output speed for 1602 series (for a scan, not conversion)
25459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int fifo_size;		// number of samples fifo can hold
25559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	const comedi_lrange *ranges;
25659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	enum trimpot_model trimpot;
25759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned has_dac08:1;
25859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez} cb_pcidas_board;
25959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
26059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic const cb_pcidas_board cb_pcidas_boards[] = {
26159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
26259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1602/16",
26359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x1,
26459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
26559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
26659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	16,
26759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:5000,
26859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:2,
26959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:1,
27059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_scan_speed:10000,
27159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:512,
27259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
27359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD8402,
27459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:1,
27559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
27659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
27759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1200",
27859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0xF,
27959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
28059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
28159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	12,
28259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:3200,
28359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:2,
28459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:0,
28559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:1024,
28659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
28759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD7376,
28859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:0,
28959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
29059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
29159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1602/12",
29259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x10,
29359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
29459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
29559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	12,
29659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:3200,
29759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:2,
29859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:1,
29959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_scan_speed:4000,
30059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:1024,
30159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
30259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD7376,
30359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:0,
30459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
30559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
30659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1200/jr",
30759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x19,
30859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
30959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
31059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	12,
31159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:3200,
31259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:0,
31359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:0,
31459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:1024,
31559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
31659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD7376,
31759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:0,
31859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
31959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
32059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1602/16/jr",
32159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x1C,
32259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
32359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
32459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	16,
32559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:5000,
32659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:0,
32759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:0,
32859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:512,
32959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
33059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD8402,
33159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:1,
33259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
33359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
33459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1000",
33559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x4C,
33659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
33759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
33859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	12,
33959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:4000,
34059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:0,
34159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:0,
34259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:1024,
34359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
34459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD7376,
34559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:0,
34659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
34759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
34859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1001",
34959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x1a,
35059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
35159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
35259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	12,
35359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:6800,
35459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:2,
35559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:0,
35659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:1024,
35759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_alt_ranges,
35859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD7376,
35959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:0,
36059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
36159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{
36259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      name:	"pci-das1002",
36359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      device_id:0x1b,
36459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_se_chans:16,
36559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_diff_chans:8,
36659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_bits:	12,
36759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ai_speed:6800,
36859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ao_nchan:2,
36959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_ao_fifo:0,
37059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      fifo_size:1024,
37159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      ranges:	&cb_pcidas_ranges,
37259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      trimpot:	AD7376,
37359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	      has_dac08:0,
37459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		},
37559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
37659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
37759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// Number of boards in cb_pcidas_boards
37859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define N_BOARDS	(sizeof(cb_pcidas_boards) / sizeof(cb_pcidas_board))
37959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
38059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
38159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x000f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x0010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x001c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x004c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x001a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{PCI_VENDOR_ID_CB, 0x001b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
38959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	{0}
39059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
39159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
39259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezMODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
39359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
39459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
39559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * Useful for shorthand access to the particular board structure
39659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
39759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define thisboard ((const cb_pcidas_board *)dev->board_ptr)
39859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
39959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* this structure is for data unique to this hardware driver.  If
40059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez   several hardware drivers keep similar information in this structure,
40159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez   feel free to suggest moving the variable to the comedi_device struct.  */
40259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martineztypedef struct {
40359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* would be useful for a PCI device */
40459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	struct pci_dev *pci_dev;
40559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// base addresses
40659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long s5933_config;
40759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long control_status;
40859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long adc_fifo;
40959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long pacer_counter_dio;
41059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long ao_registers;
41159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// divisors of master clock for analog input pacing
41259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int divisor1;
41359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int divisor2;
41459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	volatile unsigned int count;	// number of analog input samples remaining
41559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	volatile unsigned int adc_fifo_bits;	// bits to write to interupt/adcfifo register
41659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	volatile unsigned int s5933_intcsr_bits;	// bits to write to amcc s5933 interrupt control/status register
41759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	volatile unsigned int ao_control_bits;	// bits to write to ao control and status register
418790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	short ai_buffer[AI_BUFFER_SIZE];
419790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	short ao_buffer[AO_BUFFER_SIZE];
42059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// divisors of master clock for analog output pacing
42159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int ao_divisor1;
42259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int ao_divisor2;
42359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	volatile unsigned int ao_count;	// number of analog output samples remaining
42459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int ao_value[2];	// remember what the analog outputs are set to, to allow readback
42559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int caldac_value[NUM_CHANNELS_8800];	// for readback of caldac
42659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int trimpot_value[NUM_CHANNELS_8402];	// for readback of trimpot
42759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int dac08_value;
42859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int calibration_source;
42959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez} cb_pcidas_private;
43059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
43159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
43259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * most drivers define the following macro to make it easy to
43359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * access the private structure.
43459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
43559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#define devpriv ((cb_pcidas_private *)dev->private)
43659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
43759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
43859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * The comedi_driver structure tells the Comedi core module
43959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * which functions to call to configure/deconfigure (attach/detach)
44059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * the board, and also about the kernel module that contains
44159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * the device code.
44259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
44359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_attach(comedi_device * dev, comedi_devconfig * it);
44459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_detach(comedi_device * dev);
44559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic comedi_driver driver_cb_pcidas = {
44659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez      driver_name:"cb_pcidas",
44759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez      module:THIS_MODULE,
44859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez      attach:cb_pcidas_attach,
44959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez      detach:cb_pcidas_detach,
45059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez};
45159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
45259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
453790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
45459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int ai_config_insn(comedi_device * dev, comedi_subdevice * s,
455790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
45659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_nofifo_winsn(comedi_device * dev, comedi_subdevice * s,
457790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
45859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_fifo_winsn(comedi_device * dev, comedi_subdevice * s,
459790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
46059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_readback_insn(comedi_device * dev, comedi_subdevice * s,
461790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
46259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ai_cmd(comedi_device * dev, comedi_subdevice * s);
46359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
46459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd * cmd);
46559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_cmd(comedi_device * dev, comedi_subdevice * s);
46659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_inttrig(comedi_device * dev, comedi_subdevice * subdev,
46759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int trig_num);
46859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_cmdtest(comedi_device * dev, comedi_subdevice * s,
46959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd * cmd);
47059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG);
47159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic void handle_ao_interrupt(comedi_device * dev, unsigned int status);
47259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_cancel(comedi_device * dev, comedi_subdevice * s);
47359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_cancel(comedi_device * dev, comedi_subdevice * s);
47459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic void cb_pcidas_load_counters(comedi_device * dev, unsigned int *ns,
47559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int round_flags);
47659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int eeprom_read_insn(comedi_device * dev, comedi_subdevice * s,
477790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
47859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int caldac_read_insn(comedi_device * dev, comedi_subdevice * s,
479790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
48059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int caldac_write_insn(comedi_device * dev, comedi_subdevice * s,
481790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
48259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_read_insn(comedi_device * dev, comedi_subdevice * s,
483790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
48459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_trimpot_write(comedi_device * dev, unsigned int channel,
485790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int value);
48659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_write_insn(comedi_device * dev, comedi_subdevice * s,
487790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
48859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int dac08_read_insn(comedi_device * dev, comedi_subdevice * s,
489790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
490790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pembertonstatic int dac08_write(comedi_device * dev, unsigned int value);
49159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int dac08_write_insn(comedi_device * dev, comedi_subdevice * s,
492790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data);
49359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int caldac_8800_write(comedi_device * dev, unsigned int address,
49459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	uint8_t value);
49559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_7376_write(comedi_device * dev, uint8_t value);
49659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_8402_write(comedi_device * dev, unsigned int channel,
49759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	uint8_t value);
49859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int nvram_read(comedi_device * dev, unsigned int address,
49959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	uint8_t * data);
50059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
50159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic inline unsigned int cal_enable_bits(comedi_device * dev)
50259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
50359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
50459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
50559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
50659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
50759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * Attach is called by the Comedi core to configure the driver
50859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * for a particular board.
50959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
51059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_attach(comedi_device * dev, comedi_devconfig * it)
51159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
51259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_subdevice *s;
51359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	struct pci_dev *pcidev;
51459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int index;
51559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int i;
51659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
51759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	printk("comedi%d: cb_pcidas: ", dev->minor);
51859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
51959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
52059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * Allocate the private structure area.
52159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
52259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (alloc_private(dev, sizeof(cb_pcidas_private)) < 0)
52359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -ENOMEM;
52459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
52559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
52659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * Probe the device to determine what device in the series it is.
52759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
52859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	printk("\n");
52959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
53059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
53159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pcidev != NULL;
53259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
53359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// is it not a computer boards card?
53459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (pcidev->vendor != PCI_VENDOR_ID_CB)
53559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			continue;
53659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// loop through cards supported by this driver
53759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		for (index = 0; index < N_BOARDS; index++) {
53859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (cb_pcidas_boards[index].device_id != pcidev->device)
53959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				continue;
54059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			// was a particular bus/slot requested?
54159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (it->options[0] || it->options[1]) {
54259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				// are we on the wrong bus/slot?
54359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				if (pcidev->bus->number != it->options[0] ||
54459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					PCI_SLOT(pcidev->devfn) !=
54559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					it->options[1]) {
54659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					continue;
54759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				}
54859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			}
54959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->pci_dev = pcidev;
55059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			dev->board_ptr = cb_pcidas_boards + index;
55159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			goto found;
55259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
55359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
55459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
55559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	printk("No supported ComputerBoards/MeasurementComputing card found on "
55659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		"requested position\n");
55759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return -EIO;
55859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
55959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez      found:
56059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
56159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	printk("Found %s on bus %i, slot %i\n", cb_pcidas_boards[index].name,
56259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pcidev->bus->number, PCI_SLOT(pcidev->devfn));
56359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
56459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/*
56559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * Enable PCI device and reserve I/O ports.
56659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 */
56759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (comedi_pci_enable(pcidev, "cb_pcidas")) {
56859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		printk(" Failed to enable PCI device and request regions\n");
56959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -EIO;
57059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
57159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/*
57259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * Initialize devpriv->control_status and devpriv->adc_fifo to point to
57359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * their base address.
57459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 */
57559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->s5933_config =
57659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pci_resource_start(devpriv->pci_dev, S5933_BADRINDEX);
57759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->control_status =
57859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pci_resource_start(devpriv->pci_dev, CONT_STAT_BADRINDEX);
57959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->adc_fifo =
58059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pci_resource_start(devpriv->pci_dev, ADC_FIFO_BADRINDEX);
58159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->pacer_counter_dio =
58259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pci_resource_start(devpriv->pci_dev, PACER_BADRINDEX);
58359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (thisboard->ao_nchan) {
58459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_registers =
58559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			pci_resource_start(devpriv->pci_dev, AO_BADRINDEX);
58659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
58759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// disable and clear interrupts on amcc s5933
58859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outl(INTCSR_INBOX_INTR_STATUS,
58959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
59159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// get irq
59259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (comedi_request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt,
59359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			IRQF_SHARED, "cb_pcidas", dev)) {
59459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq);
59559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -EINVAL;
59659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
59759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	dev->irq = devpriv->pci_dev->irq;
59859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
59959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	//Initialize dev->board_name
60059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	dev->board_name = thisboard->name;
60159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
60259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
60359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * Allocate the subdevice structures.
60459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
60559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (alloc_subdevices(dev, 7) < 0)
60659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -ENOMEM;
60759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
60859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 0;
60959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* analog input subdevice */
61059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	dev->read_subdev = s;
61159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->type = COMEDI_SUBD_AI;
61259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
61359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* WARNING: Number of inputs in differential mode is ignored */
61459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->n_chan = thisboard->ai_se_chans;
61559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->len_chanlist = thisboard->ai_se_chans;
61659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->maxdata = (1 << thisboard->ai_bits) - 1;
61759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->range_table = thisboard->ranges;
61859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_read = cb_pcidas_ai_rinsn;
61959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_config = ai_config_insn;
62059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->do_cmd = cb_pcidas_ai_cmd;
62159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->do_cmdtest = cb_pcidas_ai_cmdtest;
62259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->cancel = cb_pcidas_cancel;
62359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
62459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* analog output subdevice */
62559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 1;
62659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (thisboard->ao_nchan) {
62759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->type = COMEDI_SUBD_AO;
62859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
62959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->n_chan = thisboard->ao_nchan;
63059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// analog out resolution is the same as analog input resolution, so use ai_bits
63159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->maxdata = (1 << thisboard->ai_bits) - 1;
63259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->range_table = &cb_pcidas_ao_ranges;
63359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->insn_read = cb_pcidas_ao_readback_insn;
63459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (thisboard->has_ao_fifo) {
63559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			dev->write_subdev = s;
63659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			s->subdev_flags |= SDF_CMD_WRITE;
63759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			s->insn_write = cb_pcidas_ao_fifo_winsn;
63859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			s->do_cmdtest = cb_pcidas_ao_cmdtest;
63959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			s->do_cmd = cb_pcidas_ao_cmd;
64059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			s->cancel = cb_pcidas_ao_cancel;
64159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		} else {
64259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			s->insn_write = cb_pcidas_ao_nofifo_winsn;
64359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
64459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else {
64559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->type = COMEDI_SUBD_UNUSED;
64659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
64759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
64859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* 8255 */
64959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 2;
65059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	subdev_8255_init(dev, s, NULL, devpriv->pacer_counter_dio + DIO_8255);
65159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
65259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// serial EEPROM,
65359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 3;
65459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->type = COMEDI_SUBD_MEMORY;
65559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
65659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->n_chan = 256;
65759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->maxdata = 0xff;
65859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_read = eeprom_read_insn;
65959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
66059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// 8800 caldac
66159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 4;
66259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->type = COMEDI_SUBD_CALIB;
66359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
66459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->n_chan = NUM_CHANNELS_8800;
66559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->maxdata = 0xff;
66659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_read = caldac_read_insn;
66759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_write = caldac_write_insn;
66859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (i = 0; i < s->n_chan; i++)
66959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		caldac_8800_write(dev, i, s->maxdata / 2);
67059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
67159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// trim potentiometer
67259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 5;
67359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->type = COMEDI_SUBD_CALIB;
67459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
67559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (thisboard->trimpot == AD7376) {
67659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->n_chan = NUM_CHANNELS_7376;
67759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->maxdata = 0x7f;
67859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else {
67959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->n_chan = NUM_CHANNELS_8402;
68059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->maxdata = 0xff;
68159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
68259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_read = trimpot_read_insn;
68359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s->insn_write = trimpot_write_insn;
68459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (i = 0; i < s->n_chan; i++)
68559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
68659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
68759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// dac08 caldac
68859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s = dev->subdevices + 6;
68959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (thisboard->has_dac08) {
69059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->type = COMEDI_SUBD_CALIB;
69159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
69259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->n_chan = NUM_CHANNELS_DAC08;
69359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->insn_read = dac08_read_insn;
69459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->insn_write = dac08_write_insn;
69559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->maxdata = 0xff;
69659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		dac08_write(dev, s->maxdata / 2);
69759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else
69859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		s->type = COMEDI_SUBD_UNUSED;
69959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
70059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// make sure mailbox 4 is empty
70159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
70259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* Set bits to enable incoming mailbox interrupts on amcc s5933. */
70359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->s5933_intcsr_bits =
70459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
70559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		INTCSR_INBOX_FULL_INT;
70659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// clear and enable interrupt on amcc s5933
70759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
70859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->s5933_config + AMCC_OP_REG_INTCSR);
70959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
71059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
71159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
71259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
71359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
71459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * cb_pcidas_detach is called to deconfigure a device.  It should deallocate
71559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * resources.
71659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * This function is also called when _attach() fails, so it should be
71759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * careful not to release resources that were not necessarily
71859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * allocated by _attach().  dev->private and dev->subdevices are
71959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * deallocated automatically by the core.
72059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
72159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_detach(comedi_device * dev)
72259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
72359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	printk("comedi%d: cb_pcidas: remove\n", dev->minor);
72459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
72559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (devpriv) {
72659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (devpriv->s5933_config) {
72759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			// disable and clear interrupts on amcc s5933
72859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			outl(INTCSR_INBOX_INTR_STATUS,
72959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				devpriv->s5933_config + AMCC_OP_REG_INTCSR);
73059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
73159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			rt_printk("detaching, incsr is 0x%x\n",
73259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				inl(devpriv->s5933_config +
73359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					AMCC_OP_REG_INTCSR));
73459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
73559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
73659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
73759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (dev->irq)
73859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_free_irq(dev->irq, dev);
73959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (dev->subdevices)
74059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		subdev_8255_cleanup(dev, dev->subdevices + 2);
74159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (devpriv && devpriv->pci_dev) {
74259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (devpriv->s5933_config) {
74359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			comedi_pci_disable(devpriv->pci_dev);
74459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
74559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		pci_dev_put(devpriv->pci_dev);
74659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
74759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
74859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
74959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
75059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
75159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
75259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * "instructions" read/write data in "one-shot" or "software-triggered"
75359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * mode.
75459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
75559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
756790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
75759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
75859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int n, i;
75959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bits;
76059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int timeout = 10000;
76159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int channel;
76259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// enable calibration input if appropriate
76359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (insn->chanspec & CR_ALT_SOURCE) {
76459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(cal_enable_bits(dev),
76559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + CALIBRATION_REG);
76659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		channel = 0;
76759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else {
76859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(0, devpriv->control_status + CALIBRATION_REG);
76959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		channel = CR_CHAN(insn->chanspec);
77059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
77159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set mux limits and gain
77259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	bits = BEGIN_SCAN(channel) |
77359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		END_SCAN(channel) | GAIN_BITS(CR_RANGE(insn->chanspec));
77459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set unipolar/bipolar
77559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (CR_RANGE(insn->chanspec) & IS_UNIPOLAR)
77659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= UNIP;
77759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set singleended/differential
77859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (CR_AREF(insn->chanspec) != AREF_DIFF)
77959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= SE;
78059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(bits, devpriv->control_status + ADCMUX_CONT);
78159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
78259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* clear fifo */
78359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->adc_fifo + ADCFIFOCLR);
78459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
78559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* convert n samples */
78659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (n = 0; n < insn->n; n++) {
78759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* trigger conversion */
78859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(0, devpriv->adc_fifo + ADCDATA);
78959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
79059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* wait for conversion to end */
79159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* return -ETIMEDOUT if there is a timeout */
79259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		for (i = 0; i < timeout; i++) {
79359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (inw(devpriv->control_status + ADCMUX_CONT) & EOC)
79459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				break;
79559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
79659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (i == timeout)
79759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			return -ETIMEDOUT;
79859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
79959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* read data */
80059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		data[n] = inw(devpriv->adc_fifo + ADCDATA);
80159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
80259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
80359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* return the number of samples read/written */
80459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return n;
80559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
80659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
807790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pembertonstatic int ai_config_calibration_source(comedi_device * dev, unsigned int * data)
80859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
80959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int num_calibration_sources = 8;
810790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int source = data[1];
81159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
81259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (source >= num_calibration_sources) {
81359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		printk("invalid calibration source: %i\n", source);
81459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -EINVAL;
81559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
81659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
81759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->calibration_source = source;
81859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
81959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 2;
82059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
82159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
82259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int ai_config_insn(comedi_device * dev, comedi_subdevice * s,
823790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
82459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
82559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int id = data[0];
82659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
82759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	switch (id) {
82859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	case INSN_CONFIG_ALT_SOURCE:
82959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return ai_config_calibration_source(dev, data);
83059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
83159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	default:
83259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -EINVAL;
83359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
83459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
83559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return -EINVAL;
83659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
83759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
83859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// analog output insn for pcidas-1000 and 1200 series
83959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_nofifo_winsn(comedi_device * dev, comedi_subdevice * s,
840790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
84159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
84259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int channel;
84359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
84459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
84559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set channel and range
84659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	channel = CR_CHAN(insn->chanspec);
84759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
84859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_control_bits &=
84959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		~DAC_MODE_UPDATE_BOTH & ~DAC_RANGE_MASK(channel);
85059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_control_bits |=
85159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		DACEN | DAC_RANGE(channel, CR_RANGE(insn->chanspec));
85259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
85359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
85459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
85559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// remember value for readback
85659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_value[channel] = data[0];
85759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// send data
85859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(data[0], devpriv->ao_registers + DAC_DATA_REG(channel));
85959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
86059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
86159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
86259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
86359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// analog output insn for pcidas-1602 series
86459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_fifo_winsn(comedi_device * dev, comedi_subdevice * s,
865790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
86659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
86759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int channel;
86859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
86959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
87059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// clear dac fifo
87159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->ao_registers + DACFIFOCLR);
87259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
87359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set channel and range
87459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	channel = CR_CHAN(insn->chanspec);
87559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
87659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_control_bits &=
87759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) & ~DAC_RANGE_MASK(channel) &
87859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		~DAC_PACER_MASK;
87959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_control_bits |=
88059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		DACEN | DAC_RANGE(channel,
88159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		CR_RANGE(insn->chanspec)) | DAC_CHAN_EN(channel) | DAC_START;
88259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
88359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
88459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
88559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// remember value for readback
88659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_value[channel] = data[0];
88759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// send data
88859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(data[0], devpriv->ao_registers + DACDATA);
88959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
89059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
89159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
89259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
89359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// analog output readback insn
89459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// XXX loses track of analog output value back after an analog ouput command is executed
89559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_readback_insn(comedi_device * dev, comedi_subdevice * s,
896790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
89759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
89859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
89959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
90059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
90159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
90259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
90359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int eeprom_read_insn(comedi_device * dev, comedi_subdevice * s,
904790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
90559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
90659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	uint8_t nvram_data;
90759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int retval;
90859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
90959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data);
91059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (retval < 0)
91159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return retval;
91259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
91359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	data[0] = nvram_data;
91459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
91559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
91659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
91759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
91859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int caldac_write_insn(comedi_device * dev, comedi_subdevice * s,
919790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
92059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
92159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	const unsigned int channel = CR_CHAN(insn->chanspec);
92259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
92359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return caldac_8800_write(dev, channel, data[0]);
92459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
92559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
92659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int caldac_read_insn(comedi_device * dev, comedi_subdevice * s,
927790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
92859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
92959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	data[0] = devpriv->caldac_value[CR_CHAN(insn->chanspec)];
93059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
93159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
93259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
93359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
93459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* 1602/16 pregain offset */
935790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pembertonstatic int dac08_write(comedi_device * dev, unsigned int value)
93659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
93759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (devpriv->dac08_value == value)
93859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 1;
93959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
94059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->dac08_value = value;
94159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
94259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev) | (value & 0xff),
94359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->control_status + CALIBRATION_REG);
94459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(1);
94559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev) | SELECT_DAC08_BIT | (value & 0xff),
94659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->control_status + CALIBRATION_REG);
94759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(1);
94859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev) | (value & 0xff),
94959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->control_status + CALIBRATION_REG);
95059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(1);
95159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
95259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
95359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
95459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
95559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int dac08_write_insn(comedi_device * dev, comedi_subdevice * s,
956790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
95759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
95859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return dac08_write(dev, data[0]);
95959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
96059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
96159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int dac08_read_insn(comedi_device * dev, comedi_subdevice * s,
962790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
96359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
96459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	data[0] = devpriv->dac08_value;
96559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
96659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
96759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
96859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
96959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_trimpot_write(comedi_device * dev,
970790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int channel, unsigned int value)
97159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
97259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (devpriv->trimpot_value[channel] == value)
97359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 1;
97459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
97559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->trimpot_value[channel] = value;
97659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	switch (thisboard->trimpot) {
97759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	case AD7376:
97859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		trimpot_7376_write(dev, value);
97959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
98059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	case AD8402:
98159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		trimpot_8402_write(dev, channel, value);
98259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
98359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	default:
98459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev, "driver bug?");
98559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -1;
98659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
98759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
98859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
98959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
99059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
99159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
99259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_write_insn(comedi_device * dev, comedi_subdevice * s,
993790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
99459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
99559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int channel = CR_CHAN(insn->chanspec);
99659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
99759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return cb_pcidas_trimpot_write(dev, channel, data[0]);
99859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
99959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
100059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_read_insn(comedi_device * dev, comedi_subdevice * s,
1001790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	comedi_insn * insn, unsigned int * data)
100259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
100359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int channel = CR_CHAN(insn->chanspec);
100459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
100559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	data[0] = devpriv->trimpot_value[channel];
100659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
100759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
100859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
100959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
101059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
101159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd * cmd)
101259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
101359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int err = 0;
101459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int tmp;
101559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int i, gain, start_chan;
101659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
101759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* cmdtest tests a particular command to see if it is valid.
101859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * Using the cmdtest ioctl, a user can create a valid cmd
101959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * and then have it executes by the cmd ioctl.
102059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 *
102159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
102259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * the command passes. */
102359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
102459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 1: make sure trigger sources are trivially valid */
102559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
102659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->start_src;
102759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->start_src &= TRIG_NOW | TRIG_EXT;
102859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->start_src || tmp != cmd->start_src)
102959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
103059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
103159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->scan_begin_src;
103259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
103359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
103459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
103559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
103659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->convert_src;
103759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->convert_src &= TRIG_TIMER | TRIG_NOW | TRIG_EXT;
103859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->convert_src || tmp != cmd->convert_src)
103959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
104059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
104159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->scan_end_src;
104259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->scan_end_src &= TRIG_COUNT;
104359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
104459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
104559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
104659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->stop_src;
104759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
104859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->stop_src || tmp != cmd->stop_src)
104959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
105059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
105159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
105259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 1;
105359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
105459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 2: make sure trigger sources are unique and mutually compatible */
105559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
105659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
105759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
105859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src != TRIG_FOLLOW &&
105959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->scan_begin_src != TRIG_TIMER &&
106059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->scan_begin_src != TRIG_EXT)
106159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
106259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->convert_src != TRIG_TIMER &&
106359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
106459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
106559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
106659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
106759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
106859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// make sure trigger sources are compatible with each other
106959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
107059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
107159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
107259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
107359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->start_src == TRIG_EXT &&
107459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		(cmd->convert_src == TRIG_EXT
107559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			|| cmd->scan_begin_src == TRIG_EXT))
107659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
107759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
107859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
107959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 2;
108059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
108159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 3: make sure arguments are trivially compatible */
108259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
108359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->start_arg != 0) {
108459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->start_arg = 0;
108559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
108659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
108759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
108859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
108959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->scan_begin_arg <
109059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			thisboard->ai_speed * cmd->chanlist_len) {
109159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->scan_begin_arg =
109259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				thisboard->ai_speed * cmd->chanlist_len;
109359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
109459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
109559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
109659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->convert_src == TRIG_TIMER) {
109759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->convert_arg < thisboard->ai_speed) {
109859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->convert_arg = thisboard->ai_speed;
109959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
110059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
110159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
110259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
110359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_end_arg != cmd->chanlist_len) {
110459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->scan_end_arg = cmd->chanlist_len;
110559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
110659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
110759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src == TRIG_NONE) {
110859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* TRIG_NONE */
110959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->stop_arg != 0) {
111059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->stop_arg = 0;
111159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
111259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
111359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
111459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
111559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
111659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 3;
111759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
111859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 4: fix up any arguments */
111959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
112059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
112159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		tmp = cmd->scan_begin_arg;
112259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		i8253_cascade_ns_to_timer_2div(TIMER_BASE,
112359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(devpriv->divisor1), &(devpriv->divisor2),
112459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK);
112559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (tmp != cmd->scan_begin_arg)
112659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
112759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
112859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->convert_src == TRIG_TIMER) {
112959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		tmp = cmd->convert_arg;
113059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		i8253_cascade_ns_to_timer_2div(TIMER_BASE,
113159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(devpriv->divisor1), &(devpriv->divisor2),
113259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);
113359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (tmp != cmd->convert_arg)
113459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
113559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
113659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
113759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
113859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 4;
113959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
114059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// check channel/gain list against card's limitations
114159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->chanlist) {
114259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		gain = CR_RANGE(cmd->chanlist[0]);
114359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		start_chan = CR_CHAN(cmd->chanlist[0]);
114459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		for (i = 1; i < cmd->chanlist_len; i++) {
114559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (CR_CHAN(cmd->chanlist[i]) !=
114659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				(start_chan + i) % s->n_chan) {
114759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				comedi_error(dev,
114859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					"entries in chanlist must be consecutive channels, counting upwards\n");
114959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				err++;
115059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			}
115159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (CR_RANGE(cmd->chanlist[i]) != gain) {
115259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				comedi_error(dev,
115359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					"entries in chanlist must all have the same gain\n");
115459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				err++;
115559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			}
115659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
115759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
115859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
115959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
116059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 5;
116159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
116259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
116359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
116459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
116559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ai_cmd(comedi_device * dev, comedi_subdevice * s)
116659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
116759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_async *async = s->async;
116859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd *cmd = &async->cmd;
116959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bits;
117059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
117159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
117259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// make sure CAL_EN_BIT is disabled
117359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->control_status + CALIBRATION_REG);
117459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// initialize before settings pacer source and count values
117559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->control_status + TRIG_CONTSTAT);
117659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// clear fifo
117759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->adc_fifo + ADCFIFOCLR);
117859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
117959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set mux limits, gain and pacer source
118059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) |
118159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
118259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		GAIN_BITS(CR_RANGE(cmd->chanlist[0]));
118359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set unipolar/bipolar
118459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR)
118559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= UNIP;
118659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set singleended/differential
118759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
118859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= SE;
118959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set pacer source
119059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
119159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= PACER_EXT_RISE;
119259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	else
119359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= PACER_INT;
119459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(bits, devpriv->control_status + ADCMUX_CONT);
119559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
119659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
119759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("comedi: sent 0x%x to adcmux control\n", bits);
119859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
119959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
120059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// load counters
120159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->convert_src == TRIG_TIMER)
120259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cb_pcidas_load_counters(dev, &cmd->convert_arg,
120359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->flags & TRIG_ROUND_MASK);
120459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	else if (cmd->scan_begin_src == TRIG_TIMER)
120559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cb_pcidas_load_counters(dev, &cmd->scan_begin_arg,
120659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->flags & TRIG_ROUND_MASK);
120759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
120859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set number of conversions
120959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src == TRIG_COUNT) {
121059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->count = cmd->chanlist_len * cmd->stop_arg;
121159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
121259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// enable interrupts
121359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
121459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->adc_fifo_bits |= INTE;
121559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->adc_fifo_bits &= ~INT_MASK;
121659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->flags & TRIG_WAKE_EOS) {
121759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
121859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->adc_fifo_bits |= INT_EOS;	// interrupt end of burst
121959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		else
122059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->adc_fifo_bits |= INT_FNE;	// interrupt fifo not empty
122159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else {
122259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->adc_fifo_bits |= INT_FHF;	//interrupt fifo half full
122359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
122459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
122559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits);
122659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
122759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// enable (and clear) interrupts
122859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL,
122959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->control_status + INT_ADCFIFO);
123059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
123159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
123259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set start trigger and burst mode
123359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	bits = 0;
123459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->start_src == TRIG_NOW)
123559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= SW_TRIGGER;
123659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	else if (cmd->start_src == TRIG_EXT)
123759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= EXT_TRIGGER | TGEN | XTRCL;
123859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	else {
123959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev, "bug!");
124059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -1;
124159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
124259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
124359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bits |= BURSTE;
124459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(bits, devpriv->control_status + TRIG_CONTSTAT);
124559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
124659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("comedi: sent 0x%x to trig control\n", bits);
124759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
124859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
124959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
125059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
125159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
125259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_cmdtest(comedi_device * dev, comedi_subdevice * s,
125359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd * cmd)
125459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
125559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int err = 0;
125659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int tmp;
125759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
125859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* cmdtest tests a particular command to see if it is valid.
125959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * Using the cmdtest ioctl, a user can create a valid cmd
126059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * and then have it executes by the cmd ioctl.
126159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 *
126259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
126359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	 * the command passes. */
126459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
126559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 1: make sure trigger sources are trivially valid */
126659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
126759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->start_src;
126859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->start_src &= TRIG_INT;
126959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->start_src || tmp != cmd->start_src)
127059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
127159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
127259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->scan_begin_src;
127359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
127459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
127559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
127659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
127759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->convert_src;
127859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->convert_src &= TRIG_NOW;
127959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->convert_src || tmp != cmd->convert_src)
128059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
128159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
128259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->scan_end_src;
128359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->scan_end_src &= TRIG_COUNT;
128459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
128559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
128659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
128759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	tmp = cmd->stop_src;
128859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
128959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (!cmd->stop_src || tmp != cmd->stop_src)
129059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
129159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
129259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
129359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 1;
129459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
129559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 2: make sure trigger sources are unique and mutually compatible */
129659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
129759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src != TRIG_TIMER &&
129859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->scan_begin_src != TRIG_EXT)
129959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
130059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
130159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
130259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
130359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
130459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 2;
130559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
130659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 3: make sure arguments are trivially compatible */
130759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
130859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->start_arg != 0) {
130959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->start_arg = 0;
131059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
131159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
131259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
131359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
131459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->scan_begin_arg < thisboard->ao_scan_speed) {
131559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->scan_begin_arg = thisboard->ao_scan_speed;
131659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
131759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
131859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
131959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
132059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_end_arg != cmd->chanlist_len) {
132159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cmd->scan_end_arg = cmd->chanlist_len;
132259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		err++;
132359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
132459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src == TRIG_NONE) {
132559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* TRIG_NONE */
132659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->stop_arg != 0) {
132759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cmd->stop_arg = 0;
132859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
132959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
133059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
133159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
133259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
133359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 3;
133459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
133559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* step 4: fix up any arguments */
133659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
133759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
133859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		tmp = cmd->scan_begin_arg;
133959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		i8253_cascade_ns_to_timer_2div(TIMER_BASE,
134059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(devpriv->ao_divisor1), &(devpriv->ao_divisor2),
134159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK);
134259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (tmp != cmd->scan_begin_arg)
134359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
134459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
134559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
134659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
134759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 4;
134859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
134959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// check channel/gain list against card's limitations
135059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->chanlist && cmd->chanlist_len > 1) {
135159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (CR_CHAN(cmd->chanlist[0]) != 0 ||
135259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			CR_CHAN(cmd->chanlist[1]) != 1) {
135359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			comedi_error(dev,
135459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				"channels must be ordered channel 0, channel 1 in chanlist\n");
135559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			err++;
135659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
135759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
135859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
135959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (err)
136059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 5;
136159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
136259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
136359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
136459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
136559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_cmd(comedi_device * dev, comedi_subdevice * s)
136659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
136759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_async *async = s->async;
136859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd *cmd = &async->cmd;
136959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int i;
137059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
137159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
137259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set channel limits, gain
137359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
137459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (i = 0; i < cmd->chanlist_len; i++) {
137559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// enable channel
137659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_control_bits |=
137759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
137859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// set range
137959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
138059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			CR_RANGE(cmd->chanlist[i]));
138159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
138259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
138359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// disable analog out before settings pacer source and count values
138459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
138559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
138659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
138759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// clear fifo
138859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->ao_registers + DACFIFOCLR);
138959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
139059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// load counters
139159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
139259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		i8253_cascade_ns_to_timer_2div(TIMER_BASE,
139359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(devpriv->ao_divisor1), &(devpriv->ao_divisor2),
139459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			&(cmd->scan_begin_arg), cmd->flags);
139559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
139659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
139759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1,
139859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->ao_divisor1, 2);
139959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2,
140059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->ao_divisor2, 2);
140159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
140259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set number of conversions
140359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src == TRIG_COUNT) {
140459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
140559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
140659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// set pacer source
140759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
140859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	switch (cmd->scan_begin_src) {
140959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	case TRIG_TIMER:
141059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_control_bits |= DAC_PACER_INT;
141159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
141259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	case TRIG_EXT:
141359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
141459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
141559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	default:
141659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
141759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev, "error setting dac pacer source");
141859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -1;
141959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		break;
142059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
142159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
142259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
142359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	async->inttrig = cb_pcidas_ao_inttrig;
142459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
142559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
142659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
142759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
142859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_inttrig(comedi_device * dev, comedi_subdevice * s,
142959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int trig_num)
143059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
143159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int num_bytes, num_points = thisboard->fifo_size;
143259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_async *async = s->async;
143359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd *cmd = &s->async->cmd;
143459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
143559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
143659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (trig_num != 0)
143759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -EINVAL;
143859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
143959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// load up fifo
144059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points)
144159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		num_points = devpriv->ao_count;
144259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
144359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1444790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		num_points * sizeof(short));
1445790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	num_points = num_bytes / sizeof(short);
144659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
144759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (cmd->stop_src == TRIG_COUNT) {
144859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_count -= num_points;
144959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
145059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// write data to board's fifo
145159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes);
145259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
145359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// enable dac half-full and empty interrupts
145459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
145559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
145659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
145759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits);
145859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
145959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// enable and clear interrupts
146059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
146159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->control_status + INT_ADCFIFO);
146259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
146359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// start dac
146459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
146559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
146659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
146759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("comedi: sent 0x%x to dac control\n",
146859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->ao_control_bits);
146959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
147059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
147159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
147259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	async->inttrig = NULL;
147359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
147459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
147559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
147659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
147759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG)
147859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
147959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_device *dev = (comedi_device *) d;
148059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_subdevice *s = dev->read_subdev;
148159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_async *async;
148259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int status, s5933_status;
148359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int half_fifo = thisboard->fifo_size / 2;
148459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int num_samples, i;
148559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int timeout = 10000;
148659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
148759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
148859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (dev->attached == 0) {
148959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return IRQ_NONE;
149059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
149159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
149259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	async = s->async;
149359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	async->events = 0;
149459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
149559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
149659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
149759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("intcsr 0x%x\n", s5933_status);
149859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	rt_printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF));
149959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
150059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
150159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
150259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return IRQ_NONE;
150359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
150459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// make sure mailbox 4 is empty
150559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
150659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// clear interrupt on amcc s5933
150759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
150859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->s5933_config + AMCC_OP_REG_INTCSR);
150959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
151059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	status = inw(devpriv->control_status + INT_ADCFIFO);
151159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#ifdef CB_PCIDAS_DEBUG
151259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if ((status & (INT | EOAI | LADFUL | DAHFI | DAEMI)) == 0) {
151359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev, "spurious interrupt");
151459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
151559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez#endif
151659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
151759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// check for analog output interrupt
151859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (status & (DAHFI | DAEMI)) {
151959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		handle_ao_interrupt(dev, status);
152059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
152159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// check for analog input interrupts
152259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// if fifo half-full
152359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (status & ADHFI) {
152459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// read data
152559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		num_samples = half_fifo;
152659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (async->cmd.stop_src == TRIG_COUNT &&
152759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			num_samples > devpriv->count) {
152859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			num_samples = devpriv->count;
152959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
153059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
153159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			num_samples);
153259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cfc_write_array_to_buffer(s, devpriv->ai_buffer,
1533790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton			num_samples * sizeof(short));
153459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->count -= num_samples;
153559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) {
153659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			async->events |= COMEDI_CB_EOA;
153759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cb_pcidas_cancel(dev, s);
153859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
153959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// clear half-full interrupt latch
154059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_lock_irqsave(&dev->spinlock, flags);
154159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(devpriv->adc_fifo_bits | INT,
154259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + INT_ADCFIFO);
154359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
154459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// else if fifo not empty
154559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else if (status & (ADNEI | EOBI)) {
154659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		for (i = 0; i < timeout; i++) {
154759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			// break if fifo is empty
154859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if ((ADNE & inw(devpriv->control_status +
154959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez						INT_ADCFIFO)) == 0)
155059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				break;
155159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cfc_write_to_buffer(s, inw(devpriv->adc_fifo));
155259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (async->cmd.stop_src == TRIG_COUNT && --devpriv->count == 0) {	/* end of acquisition */
155359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				cb_pcidas_cancel(dev, s);
155459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				async->events |= COMEDI_CB_EOA;
155559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				break;
155659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			}
155759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
155859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// clear not-empty interrupt latch
155959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_lock_irqsave(&dev->spinlock, flags);
156059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(devpriv->adc_fifo_bits | INT,
156159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + INT_ADCFIFO);
156259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
156359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else if (status & EOAI) {
156459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev,
156559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			"bug! encountered end of aquisition interrupt?");
156659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// clear EOA interrupt latch
156759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_lock_irqsave(&dev->spinlock, flags);
156859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(devpriv->adc_fifo_bits | EOAI,
156959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + INT_ADCFIFO);
157059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
157159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
157259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	//check for fifo overflow
157359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (status & LADFUL) {
157459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev, "fifo overflow");
157559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// clear overflow interrupt latch
157659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_lock_irqsave(&dev->spinlock, flags);
157759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(devpriv->adc_fifo_bits | LADFUL,
157859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + INT_ADCFIFO);
157959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
158059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		cb_pcidas_cancel(dev, s);
158159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
158259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
158359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
158459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_event(dev, s);
158559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
158659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return IRQ_HANDLED;
158759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
158859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
158959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic void handle_ao_interrupt(comedi_device * dev, unsigned int status)
159059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
159159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_subdevice *s = dev->write_subdev;
159259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_async *async = s->async;
159359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_cmd *cmd = &async->cmd;
159459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int half_fifo = thisboard->fifo_size / 2;
159559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int num_points;
159659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int flags;
159759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
159859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	async->events = 0;
159959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
160059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (status & DAEMI) {
160159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// clear dac empty interrupt latch
160259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_lock_irqsave(&dev->spinlock, flags);
160359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(devpriv->adc_fifo_bits | DAEMI,
160459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + INT_ADCFIFO);
160559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
160659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
160759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			if (cmd->stop_src == TRIG_NONE ||
160859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				(cmd->stop_src == TRIG_COUNT
160959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					&& devpriv->ao_count)) {
161059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				comedi_error(dev, "dac fifo underflow");
161159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				cb_pcidas_ao_cancel(dev, s);
161259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez				async->events |= COMEDI_CB_ERROR;
161359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			}
161459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			async->events |= COMEDI_CB_EOA;
161559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
161659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	} else if (status & DAHFI) {
161759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		unsigned int num_bytes;
161859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
161959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// figure out how many points we are writing to fifo
162059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		num_points = half_fifo;
162159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (cmd->stop_src == TRIG_COUNT &&
162259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->ao_count < num_points)
162359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			num_points = devpriv->ao_count;
162459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		num_bytes =
162559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1626790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton			num_points * sizeof(short));
1627790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		num_points = num_bytes / sizeof(short);
162859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
162959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (async->cmd.stop_src == TRIG_COUNT) {
163059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->ao_count -= num_points;
163159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		}
163259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// write data to board's fifo
163359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
163459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			num_points);
163559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		// clear half-full interrupt latch
163659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_lock_irqsave(&dev->spinlock, flags);
163759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(devpriv->adc_fifo_bits | DAHFI,
163859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			devpriv->control_status + INT_ADCFIFO);
163959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
164059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
164159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
164259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_event(dev, s);
164359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
164459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
164559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// cancel analog input command
164659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_cancel(comedi_device * dev, comedi_subdevice * s)
164759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
164859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
164959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
165059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
165159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// disable interrupts
165259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
165359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
165459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
165559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
165659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// disable start trigger source and burst mode
165759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->control_status + TRIG_CONTSTAT);
165859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// software pacer source
165959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(0, devpriv->control_status + ADCMUX_CONT);
166059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
166159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
166259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
166359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
166459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez// cancel analog output command
166559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int cb_pcidas_ao_cancel(comedi_device * dev, comedi_subdevice * s)
166659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
166759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long flags;
166859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
166959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_lock_irqsave(&dev->spinlock, flags);
167059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// disable interrupts
167159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
167259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
167359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
167459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	// disable output
167559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
167659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
167759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
167859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
167959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
168059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
168159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
168259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic void cb_pcidas_load_counters(comedi_device * dev, unsigned int *ns,
168359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	int rounding_flags)
168459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
168559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
168659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		&(devpriv->divisor2), ns, rounding_flags & TRIG_ROUND_MASK);
168759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
168859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
168959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1,
169059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->divisor1, 2);
169159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2,
169259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->divisor2, 2);
169359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
169459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
169559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic void write_calibration_bitstream(comedi_device * dev,
169659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int register_bits, unsigned int bitstream,
169759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bitstream_length)
169859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
169959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int write_delay = 1;
170059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bit;
170159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
170259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
170359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if (bitstream & bit)
170459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			register_bits |= SERIAL_DATA_IN_BIT;
170559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		else
170659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			register_bits &= ~SERIAL_DATA_IN_BIT;
170759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_udelay(write_delay);
170859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		outw(register_bits, devpriv->control_status + CALIBRATION_REG);
170959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
171059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
171159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
171259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int caldac_8800_write(comedi_device * dev, unsigned int address,
171359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	uint8_t value)
171459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
171559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int num_caldac_channels = 8;
171659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int bitstream_length = 11;
171759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bitstream = ((address & 0x7) << 8) | value;
171859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int caldac_8800_comedi_udelay = 1;
171959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
172059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (address >= num_caldac_channels) {
172159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_error(dev, "illegal caldac channel");
172259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -1;
172359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
172459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
172559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (value == devpriv->caldac_value[address])
172659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return 1;
172759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
172859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	devpriv->caldac_value[address] = value;
172959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
173059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream,
173159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bitstream_length);
173259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
173359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(caldac_8800_comedi_udelay);
173459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev) | SELECT_8800_BIT,
173559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		devpriv->control_status + CALIBRATION_REG);
173659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(caldac_8800_comedi_udelay);
173759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
173859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
173959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 1;
174059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
174159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
174259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_7376_write(comedi_device * dev, uint8_t value)
174359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
174459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int bitstream_length = 7;
174559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bitstream = value & 0x7f;
174659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int register_bits;
174759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int ad7376_comedi_udelay = 1;
174859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
174959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
175059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(ad7376_comedi_udelay);
175159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(register_bits, devpriv->control_status + CALIBRATION_REG);
175259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
175359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	write_calibration_bitstream(dev, register_bits, bitstream,
175459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bitstream_length);
175559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
175659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(ad7376_comedi_udelay);
175759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
175859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
175959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
176059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
176159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
176259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/* For 1602/16 only
176359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * ch 0 : adc gain
176459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * ch 1 : adc postgain offset */
176559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int trimpot_8402_write(comedi_device * dev, unsigned int channel,
176659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	uint8_t value)
176759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
176859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int bitstream_length = 10;
176959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
177059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int register_bits;
177159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int ad8402_comedi_udelay = 1;
177259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
177359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
177459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(ad8402_comedi_udelay);
177559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(register_bits, devpriv->control_status + CALIBRATION_REG);
177659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
177759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	write_calibration_bitstream(dev, register_bits, bitstream,
177859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		bitstream_length);
177959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
178059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	comedi_udelay(ad8402_comedi_udelay);
178159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
178259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
178359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
178459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
178559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
178659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int wait_for_nvram_ready(unsigned long s5933_base_addr)
178759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
178859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	static const int timeout = 1000;
178959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned int i;
179059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
179159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	for (i = 0; i < timeout; i++) {
179259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		if ((inb(s5933_base_addr +
179359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez					AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY)
179459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			== 0)
179559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez			return 0;
179659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		comedi_udelay(1);
179759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	}
179859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return -1;
179959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
180059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
180159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinezstatic int nvram_read(comedi_device * dev, unsigned int address, uint8_t * data)
180259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez{
180359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	unsigned long iobase = devpriv->s5933_config;
180459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
180559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (wait_for_nvram_ready(iobase) < 0)
180659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -ETIMEDOUT;
180759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
180859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR,
180959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		iobase + AMCC_OP_REG_MCSR_NVCMD);
181059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
181159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR,
181259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		iobase + AMCC_OP_REG_MCSR_NVCMD);
181359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
181459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
181559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
181659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	if (wait_for_nvram_ready(iobase) < 0)
181759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez		return -ETIMEDOUT;
181859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
181959c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	*data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
182059c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
182159c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez	return 0;
182259c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez}
182359c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez
182459c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez/*
182559c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * A convenient macro that defines init_module() and cleanup_module(),
182659c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez * as necessary.
182759c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan Martinez */
182859c7dd3dc37dc42339406d08f1cde4d6194a4ccfIvan MartinezCOMEDI_PCI_INITCLEANUP(driver_cb_pcidas, cb_pcidas_pci_table);
1829