1124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/*
2124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    comedi/drivers/ni_labpc.c
3124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    Driver for National Instruments Lab-PC series boards and compatibles
4124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    Copyright (C) 2001, 2002, 2003 Frank Mori Hess <fmhess@users.sourceforge.net>
5124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
6124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    This program is free software; you can redistribute it and/or modify
7124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    it under the terms of the GNU General Public License as published by
8124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    the Free Software Foundation; either version 2 of the License, or
9124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    (at your option) any later version.
10124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
11124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    This program is distributed in the hope that it will be useful,
12124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    but WITHOUT ANY WARRANTY; without even the implied warranty of
13124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    GNU General Public License for more details.
15124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
16124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    You should have received a copy of the GNU General Public License
17124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    along with this program; if not, write to the Free Software
18124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
20124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess************************************************************************
21124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess*/
22124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/*
23124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessDriver: ni_labpc
24124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessDescription: National Instruments Lab-PC (& compatibles)
25124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessAuthor: Frank Mori Hess <fmhess@users.sourceforge.net>
26124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessDevices: [National Instruments] Lab-PC-1200 (labpc-1200),
27124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess  Lab-PC-1200AI (labpc-1200ai), Lab-PC+ (lab-pc+), PCI-1200 (ni_labpc)
28124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessStatus: works
29124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
30124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessTested with lab-pc-1200.  For the older Lab-PC+, not all input ranges
31124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessand analog references will work, the available ranges/arefs will
32124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessdepend on how you have configured the jumpers on your board
33124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess(see your owner's manual).
34124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
35124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessKernel-level ISA plug-and-play support for the lab-pc-1200
36124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessboards has not
37124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessyet been added to the driver, mainly due to the fact that
38124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessI don't know the device id numbers.  If you have one
39124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessof these boards,
40631dd1a885b6d7e9f6f51b4e5b311c2bb04c323cJustin P. Mattockplease file a bug report at http://comedi.org/
41124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessso I can get the necessary information from you.
42124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
43124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessThe 1200 series boards have onboard calibration dacs for correcting
44124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessanalog input/output offsets and gains.  The proper settings for these
45124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hesscaldacs are stored on the board's eeprom.  To read the caldac values
46124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessfrom the eeprom and store them into a file that can be then be used by
47124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hesscomedilib, use the comedi_calibrate program.
48124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
49124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessConfiguration options - ISA boards:
50124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess  [0] - I/O port base address
51124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess  [1] - IRQ (optional, required for timed or externally triggered conversions)
52124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess  [2] - DMA channel (optional)
53124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
54124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessConfiguration options - PCI boards:
55124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess  [0] - bus (optional)
56124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess  [1] - slot (optional)
57124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
58124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessThe Lab-pc+ has quirky chanlist requirements
59124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hesswhen scanning multiple channels.  Multiple channel scan
60124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hesssequence must start at highest channel, then decrement down to
61124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hesschannel 0.  The rest of the cards can scan down like lab-pc+ or scan
62124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessup from channel zero.  Chanlists consisting of all one channel
63124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessare also legal, and allow you to pace conversions in bursts.
64124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
65124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess*/
66124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
67124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/*
68124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
69124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessNI manuals:
70124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess341309a (labpc-1200 register manual)
71124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess340914a (pci-1200)
72124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess320502b (lab-pc+)
73124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
74124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess*/
75124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
76124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#undef LABPC_DEBUG
77f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* #define LABPC_DEBUG    enable debugging messages */
78124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
7925436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
805a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
81845d131e2b363717d8ac8db2c6b4417de8cf10b5Greg Kroah-Hartman#include <linux/io.h>
82124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include "../comedidev.h"
83124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
84124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include <linux/delay.h>
85124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include <asm/dma.h>
86124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
87124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include "8253.h"
88124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include "8255.h"
89124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include "mite.h"
90124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include "comedi_fc.h"
91124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#include "ni_labpc.h"
92124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
93124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define DRV_NAME "ni_labpc"
94124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
95e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* size of io region used by board */
96e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define LABPC_SIZE           32
97e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* 2 MHz master clock */
98e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define LABPC_TIMER_BASE            500
99124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
100124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/* Registers for the lab-pc+ */
101124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
102f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* write-only registers */
103124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COMMAND1_REG	0x0
104124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define   ADC_GAIN_MASK	(0x7 << 4)
105124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define   ADC_CHAN_BITS(x)	((x) & 0x7)
106e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enables multi channel scans */
107e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_SCAN_EN_BIT	0x80
108124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COMMAND2_REG	0x1
109e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable pretriggering (used in conjunction with SWTRIG) */
110e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   PRETRIG_BIT	0x1
111e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable paced conversions on external trigger */
112e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   HWTRIG_BIT	0x2
113e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable paced conversions */
114e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   SWTRIG_BIT	0x4
115e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* use two cascaded counters for pacing */
116e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   CASCADE_BIT	0x8
117124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define   DAC_PACED_BIT(channel)	(0x40 << ((channel) & 0x1))
118124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COMMAND3_REG	0x2
119e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable dma transfers */
120e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DMA_EN_BIT	0x1
121e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable interrupts for 8255 */
122e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DIO_INTR_EN_BIT	0x2
123e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable dma terminal count interrupt */
124e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DMATC_INTR_EN_BIT	0x4
125e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable timer interrupt */
126e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   TIMER_INTR_EN_BIT	0x8
127e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable error interrupt */
128e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ERR_INTR_EN_BIT	0x10
129e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable fifo not empty interrupt */
130e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_FNE_INTR_EN_BIT	0x20
131124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define ADC_CONVERT_REG	0x3
132124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define DAC_LSB_REG(channel)	(0x4 + 2 * ((channel) & 0x1))
133124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define DAC_MSB_REG(channel)	(0x5 + 2 * ((channel) & 0x1))
134124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define ADC_CLEAR_REG	0x8
135124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define DMATC_CLEAR_REG	0xa
136124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define TIMER_CLEAR_REG	0xc
137e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* 1200 boards only */
138e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define COMMAND6_REG	0xe
139e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* select ground or common-mode reference */
140e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_COMMON_BIT	0x1
141e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/*  adc unipolar */
142e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_UNIP_BIT	0x2
143e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/*  dac unipolar */
144e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DAC_UNIP_BIT(channel)	(0x4 << ((channel) & 0x1))
145e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable fifo half full interrupt */
146e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_FHF_INTR_EN_BIT	0x20
147e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable interrupt on end of hardware count */
148e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   A1_INTR_EN_BIT	0x40
149e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* scan up from channel zero instead of down to zero */
150e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_SCAN_UP_BIT 0x80
151124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COMMAND4_REG	0xf
152e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enables 'interval' scanning */
153e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   INTERVAL_SCAN_EN_BIT	0x1
154e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enables external signal on counter b1 output to trigger scan */
155e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   EXT_SCAN_EN_BIT	0x2
156e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* chooses direction (output or input) for EXTCONV* line */
157e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   EXT_CONVERT_OUT_BIT	0x4
158e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* chooses differential inputs for adc (in conjunction with board jumper) */
159e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   ADC_DIFF_BIT	0x8
160124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define   EXT_CONVERT_DISABLE_BIT	0x10
161e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* 1200 boards only, calibration stuff */
162e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define COMMAND5_REG	0x1c
163e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable eeprom for write */
164e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   EEPROM_WRITE_UNPROTECT_BIT	0x4
165e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable dithering */
166e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DITHER_EN_BIT	0x8
167e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* load calibration dac */
168e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   CALDAC_LOAD_BIT	0x10
169e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* serial clock - rising edge writes, falling edge reads */
170e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   SCLOCK_BIT	0x20
171e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* serial data bit for writing to eeprom or calibration dacs */
172e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   SDATA_BIT	0x40
173e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* enable eeprom for read/write */
174e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   EEPROM_EN_BIT	0x80
175124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define INTERVAL_COUNT_REG	0x1e
176124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define INTERVAL_LOAD_REG	0x1f
177124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define   INTERVAL_LOAD_BITS	0x1
178124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
179f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* read-only registers */
180124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define STATUS1_REG	0x0
181e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* data is available in fifo */
182e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DATA_AVAIL_BIT	0x1
183e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* overrun has occurred */
184e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   OVERRUN_BIT	0x2
185e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* fifo overflow */
186e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   OVERFLOW_BIT	0x4
18725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* timer interrupt has occurred */
188e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   TIMER_BIT	0x8
18925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* dma terminal count has occurred */
190e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   DMATC_BIT	0x10
19125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* external trigger has occurred */
192e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   EXT_TRIG_BIT	0x40
193e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* 1200 boards only */
194e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define STATUS2_REG	0x1d
195e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* programmable eeprom serial output */
196e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   EEPROM_OUT_BIT	0x1
197e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* counter A1 terminal count */
198e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   A1_TC_BIT	0x2
199e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* fifo not half full */
200e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   FNHF_BIT	0x4
201124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define ADC_FIFO_REG	0xa
202124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
203124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define DIO_BASE_REG	0x10
204124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COUNTER_A_BASE_REG	0x14
205124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COUNTER_A_CONTROL_REG	(COUNTER_A_BASE_REG + 0x3)
206e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* check modes put conversion pacer output in harmless state (a0 mode 2) */
207e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   INIT_A0_BITS	0x14
208e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* put hardware conversion counter output in harmless state (a1 mode 0) */
209e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson#define   INIT_A1_BITS	0x70
210124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define COUNTER_B_BASE_REG	0x18
211124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
212814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
213814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
21470265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t labpc_interrupt(int irq, void *d);
215814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_drain_fifo(struct comedi_device *dev);
2163297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
217814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void labpc_drain_dma(struct comedi_device *dev);
218814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void handle_isa_dma(struct comedi_device *dev);
2193297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
220814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void labpc_drain_dregs(struct comedi_device *dev);
2210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_ai_cmdtest(struct comedi_device *dev,
2220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s, struct comedi_cmd *cmd);
223814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
224814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
2250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data);
226814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
2270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data);
228814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
2290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data);
2300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_calib_read_insn(struct comedi_device *dev,
2310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 struct comedi_subdevice *s,
2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 struct comedi_insn *insn, unsigned int *data);
2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_calib_write_insn(struct comedi_device *dev,
2340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data);
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_eeprom_read_insn(struct comedi_device *dev,
2370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
2380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data);
2390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_eeprom_write_insn(struct comedi_device *dev,
2400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   struct comedi_subdevice *s,
2410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   struct comedi_insn *insn,
2420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   unsigned int *data);
243814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
244d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_ISA_DMA_API
2453297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlapstatic unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd);
246d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#endif
247d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
24871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int labpc_find_device(struct comedi_device *dev, int bus, int slot);
249124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
250124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic int labpc_dio_mem_callback(int dir, int port, int data,
2510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  unsigned long arg);
252814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void labpc_serial_out(struct comedi_device *dev, unsigned int value,
2530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     unsigned int num_bits);
254814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic unsigned int labpc_serial_in(struct comedi_device *dev);
255814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic unsigned int labpc_eeprom_read(struct comedi_device *dev,
2560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				      unsigned int address);
257814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic unsigned int labpc_eeprom_read_status(struct comedi_device *dev);
258d6269644e1f8fc7931c4d6b86d58de7af63a5fc9Julia Lawallstatic int labpc_eeprom_write(struct comedi_device *dev,
2590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				       unsigned int address,
2600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				       unsigned int value);
261814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void write_caldac(struct comedi_device *dev, unsigned int channel,
2620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 unsigned int value);
263124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
264124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessenum scan_mode {
265124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	MODE_SINGLE_CHAN,
266124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	MODE_SINGLE_CHAN_INTERVAL,
267124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	MODE_MULT_CHAN_UP,
268124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	MODE_MULT_CHAN_DOWN,
269124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
270124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
271f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* analog input ranges */
272124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define NUM_LABPC_PLUS_AI_RANGES 16
273f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* indicates unipolar ranges */
274124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic const int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] = {
275124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
276124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
277124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
278124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
279124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
280124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
281124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
282124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
283124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
284124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
285124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
286124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
287124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
288124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
289124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
290124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
291124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
292124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
293f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* map range index to gain bits */
294124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic const int labpc_plus_ai_gain_bits[NUM_LABPC_PLUS_AI_RANGES] = {
295124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x00,
296124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x10,
297124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x20,
298124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x30,
299124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x40,
300124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x50,
301124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x60,
302124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x70,
303124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x00,
304124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x10,
305124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x20,
306124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x30,
307124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x40,
308124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x50,
309124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x60,
310124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x70,
311124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
3120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
3139ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_labpc_plus_ai = {
314124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	NUM_LABPC_PLUS_AI_RANGES,
315124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
3160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(5),
3170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(4),
3180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(2.5),
3190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(1),
3200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.5),
3210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.25),
3220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.1),
3230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.05),
3240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(10),
3250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(8),
3260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(5),
3270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(2),
3280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(1),
3290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(0.5),
3300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(0.2),
3310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(0.1),
3320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 }
333124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
334124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
335124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define NUM_LABPC_1200_AI_RANGES 14
336f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* indicates unipolar ranges */
337124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessconst int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] = {
338124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
339124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
340124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
341124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
342124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
343124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
344124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0,
345124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
346124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
347124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
348124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
349124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
350124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
351124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	1,
352124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
3530656bb352080982f960bfff2b78602a5071c909fMaurice DawsonEXPORT_SYMBOL_GPL(labpc_1200_is_unipolar);
354124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
355f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* map range index to gain bits */
356124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessconst int labpc_1200_ai_gain_bits[NUM_LABPC_1200_AI_RANGES] = {
357124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x00,
358124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x20,
359124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x30,
360124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x40,
361124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x50,
362124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x60,
363124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x70,
364124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x00,
365124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x20,
366124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x30,
367124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x40,
368124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x50,
369124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x60,
370124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	0x70,
371124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
3720656bb352080982f960bfff2b78602a5071c909fMaurice DawsonEXPORT_SYMBOL_GPL(labpc_1200_ai_gain_bits);
3730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
3749ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonconst struct comedi_lrange range_labpc_1200_ai = {
375124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	NUM_LABPC_1200_AI_RANGES,
376124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
3770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(5),
3780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(2.5),
3790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(1),
3800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.5),
3810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.25),
3820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.1),
3830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(0.05),
3840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(10),
3850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(5),
3860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(2),
3870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(1),
3880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(0.5),
3890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(0.2),
3900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(0.1),
3910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 }
392124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
3930656bb352080982f960bfff2b78602a5071c909fMaurice DawsonEXPORT_SYMBOL_GPL(range_labpc_1200_ai);
394124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
395f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* analog output ranges */
396124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#define AO_RANGE_IS_UNIPOLAR 0x1
3979ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_labpc_ao = {
398124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	2,
399124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
4000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(5),
4010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(10),
4020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 }
403124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
404124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
405124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/* functions that do inb/outb and readb/writeb so we can use
406124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess * function pointers to decide which to use */
407124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic inline unsigned int labpc_inb(unsigned long address)
408124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
409124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return inb(address);
410124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
4110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
412124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic inline void labpc_outb(unsigned int byte, unsigned long address)
413124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
414124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	outb(byte, address);
415124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
4160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
417124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic inline unsigned int labpc_readb(unsigned long address)
418124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
419124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return readb((void *)address);
420124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
4210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
422124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic inline void labpc_writeb(unsigned int byte, unsigned long address)
423124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
424124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	writeb(byte, (void *)address);
425124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
426124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
4279ad007403fa4326586060e443ee344697daa60ecBill Pembertonstatic const struct labpc_board_struct labpc_boards[] = {
428124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
4290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "lab-pc-1200",
4300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_speed = 10000,
4310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .bustype = isa_bustype,
4320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .register_layout = labpc_1200_layout,
4330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .has_ao = 1,
4340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_table = &range_labpc_1200_ai,
4350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_code = labpc_1200_ai_gain_bits,
4360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_is_unipolar = labpc_1200_is_unipolar,
4370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_scan_up = 1,
4380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .memory_mapped_io = 0,
4390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
440124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
4410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "lab-pc-1200ai",
4420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_speed = 10000,
4430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .bustype = isa_bustype,
4440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .register_layout = labpc_1200_layout,
4450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .has_ao = 0,
4460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_table = &range_labpc_1200_ai,
4470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_code = labpc_1200_ai_gain_bits,
4480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_is_unipolar = labpc_1200_is_unipolar,
4490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_scan_up = 1,
4500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .memory_mapped_io = 0,
4510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
452124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
4530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "lab-pc+",
4540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_speed = 12000,
4550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .bustype = isa_bustype,
4560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .register_layout = labpc_plus_layout,
4570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .has_ao = 1,
4580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_table = &range_labpc_plus_ai,
4590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_code = labpc_plus_ai_gain_bits,
4600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_is_unipolar = labpc_plus_is_unipolar,
4610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_scan_up = 0,
4620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .memory_mapped_io = 0,
4630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
464d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
465124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
4660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "pci-1200",
4670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .device_id = 0x161,
4680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_speed = 10000,
4690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .bustype = pci_bustype,
4700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .register_layout = labpc_1200_layout,
4710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .has_ao = 1,
4720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_table = &range_labpc_1200_ai,
4730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_code = labpc_1200_ai_gain_bits,
4740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_is_unipolar = labpc_1200_is_unipolar,
4750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_scan_up = 1,
4760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .memory_mapped_io = 1,
4770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
478e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* dummy entry so pci board works when comedi_config is passed driver name */
479124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	{
4800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = DRV_NAME,
4810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .bustype = pci_bustype,
4820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
483124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
484124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
485124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
486124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/*
487124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess * Useful for shorthand access to the particular board structure
488124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess */
4899ad007403fa4326586060e443ee344697daa60ecBill Pemberton#define thisboard ((struct labpc_board_struct *)dev->board_ptr)
490124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
491e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* size in bytes of dma buffer */
492e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertsonstatic const int dma_buffer_size = 0xff00;
493e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* 2 bytes per sample */
494e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertsonstatic const int sample_size = 2;
495124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
4960a4eb4b6c7c12730254be53d93a67ed2955d5c66Bill Pemberton#define devpriv ((struct labpc_private *)dev->private)
497124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
498139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_labpc = {
499124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	.driver_name = DRV_NAME,
500124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	.module = THIS_MODULE,
501124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	.attach = labpc_attach,
502124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	.detach = labpc_common_detach,
5038629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton	.num_names = ARRAY_SIZE(labpc_boards),
504124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	.board_name = &labpc_boards[0].name,
5059ad007403fa4326586060e443ee344697daa60ecBill Pemberton	.offset = sizeof(struct labpc_board_struct),
506124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
507124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
508d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
509124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
5104e40cee9c8a46d4231d28ae7ae6d9938cf0526d5Greg Kroah-Hartman	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)},
5114e40cee9c8a46d4231d28ae7ae6d9938cf0526d5Greg Kroah-Hartman	{0}
512124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
513124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
514124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori HessMODULE_DEVICE_TABLE(pci, labpc_pci_table);
515d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#endif /* CONFIG_COMEDI_PCI_DRIVERS */
516124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
517da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic inline int labpc_counter_load(struct comedi_device *dev,
5180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     unsigned long base_address,
5190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     unsigned int counter_number,
5200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     unsigned int count, unsigned int mode)
521124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
522124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->memory_mapped_io)
523124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return i8254_mm_load((void *)base_address, 0, counter_number,
5240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     count, mode);
525124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	else
526124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return i8254_load(base_address, 0, counter_number, count, mode);
527124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
528124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
529da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonint labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
5300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			unsigned int irq, unsigned int dma_chan)
531124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
53234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
533124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i;
5343297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap	unsigned long isr_flags;
5353297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
5363297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap	unsigned long dma_flags;
5373297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
538124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	short lsb, msb;
539124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
54088d8ed4b643d2064a663b2f07426963289def676Maurice Dawson	printk(KERN_ERR "comedi%d: ni_labpc: %s, io 0x%lx", dev->minor,
54188d8ed4b643d2064a663b2f07426963289def676Maurice Dawson								thisboard->name,
5420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       iobase);
543412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	if (irq)
544124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		printk(", irq %u", irq);
545412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	if (dma_chan)
546124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		printk(", dma %u", dma_chan);
547124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	printk("\n");
548124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
549124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (iobase == 0) {
550177d42821e2d662fda5bb57d31d33d215fb74fd0Aseem Sethi		printk(KERN_ERR "io base address is zero!\n");
551124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -EINVAL;
552124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
553f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  request io regions for isa boards */
554124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->bustype == isa_bustype) {
555124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		/* check if io addresses are available */
556124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (!request_region(iobase, LABPC_SIZE,
5570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    driver_labpc.driver_name)) {
55888d8ed4b643d2064a663b2f07426963289def676Maurice Dawson			printk(KERN_ERR "I/O port conflict\n");
559124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -EIO;
560124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
561124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
562124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	dev->iobase = iobase;
563124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
564124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->memory_mapped_io) {
565124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->read_byte = labpc_readb;
566124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte = labpc_writeb;
567124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else {
568124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->read_byte = labpc_inb;
569124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte = labpc_outb;
570124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
571e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* initialize board's command registers */
572124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
573124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
574124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
575124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
576124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout) {
577124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command5_bits,
5780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND5_REG);
579124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command6_bits,
5800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND6_REG);
581124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
582124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
583124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* grab our IRQ */
584124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (irq) {
585124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		isr_flags = 0;
586d1ce318496f5943d2cc5e20171fc383a59a1421fIan Abbott		if (thisboard->bustype == pci_bustype
587d1ce318496f5943d2cc5e20171fc383a59a1421fIan Abbott		    || thisboard->bustype == pcmcia_bustype)
588124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			isr_flags |= IRQF_SHARED;
5895f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		if (request_irq(irq, labpc_interrupt, isr_flags,
590124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				driver_labpc.driver_name, dev)) {
59188d8ed4b643d2064a663b2f07426963289def676Maurice Dawson			printk(KERN_ERR "unable to allocate irq %u\n", irq);
592124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -EINVAL;
593124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
594124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
595124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	dev->irq = irq;
596124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
5973297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
598e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* grab dma channel */
599124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (dma_chan > 3) {
60088d8ed4b643d2064a663b2f07426963289def676Maurice Dawson		printk(KERN_ERR " invalid dma channel %u\n", dma_chan);
601124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -EINVAL;
602124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else if (dma_chan) {
603e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* allocate dma buffer */
604124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->dma_buffer =
6050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
606124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->dma_buffer == NULL) {
60788d8ed4b643d2064a663b2f07426963289def676Maurice Dawson			printk(KERN_ERR " failed to allocate dma buffer\n");
608124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -ENOMEM;
609124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
610124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (request_dma(dma_chan, driver_labpc.driver_name)) {
61188d8ed4b643d2064a663b2f07426963289def676Maurice Dawson			printk(KERN_ERR " failed to allocate dma channel %u\n",
6120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       dma_chan);
613124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -EINVAL;
614124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
615124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->dma_chan = dma_chan;
616124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		dma_flags = claim_dma_lock();
617124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		disable_dma(devpriv->dma_chan);
618124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
619124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		release_dma_lock(dma_flags);
620124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
6213297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
622124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
623124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	dev->board_name = thisboard->name;
624124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
625124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (alloc_subdevices(dev, 5) < 0)
626124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -ENOMEM;
627124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
628124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* analog input subdevice */
629124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s = dev->subdevices + 0;
630124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	dev->read_subdev = s;
631124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->type = COMEDI_SUBD_AI;
632124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->subdev_flags =
6330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
634124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->n_chan = 8;
635124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->len_chanlist = 8;
636e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	s->maxdata = (1 << 12) - 1;	/* 12 bit resolution */
637124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->range_table = thisboard->ai_range_table;
638124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->do_cmd = labpc_ai_cmd;
639124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->do_cmdtest = labpc_ai_cmdtest;
640124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->insn_read = labpc_ai_rinsn;
641124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s->cancel = labpc_cancel;
642124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
643124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* analog output */
644124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s = dev->subdevices + 1;
645124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->has_ao) {
646639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		/*
647639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		 * Could provide command support, except it only has a
648412bd046b0a1726f8b168d5056d21213932f9d84tony burrows		 * one sample hardware buffer for analog output and no
649639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		 * underrun flag.
650639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		 */
651124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->type = COMEDI_SUBD_AO;
652124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
653124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->n_chan = NUM_AO_CHAN;
654f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		s->maxdata = (1 << 12) - 1;	/*  12 bit resolution */
655124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->range_table = &range_labpc_ao;
656124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->insn_read = labpc_ao_rinsn;
657124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->insn_write = labpc_ao_winsn;
658124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		/* initialize analog outputs to a known value */
659124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		for (i = 0; i < s->n_chan; i++) {
660124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->ao_value[i] = s->maxdata / 2;
661124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			lsb = devpriv->ao_value[i] & 0xff;
662124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			msb = (devpriv->ao_value[i] >> 8) & 0xff;
663124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
664124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
665124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
666124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else {
667124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->type = COMEDI_SUBD_UNUSED;
668124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
669124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
670124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* 8255 dio */
671124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s = dev->subdevices + 2;
672412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	/*  if board uses io memory we have to give a custom callback
673412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	 * function to the 8255 driver */
674124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->memory_mapped_io)
675124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		subdev_8255_init(dev, s, labpc_dio_mem_callback,
6760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 (unsigned long)(dev->iobase + DIO_BASE_REG));
677124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	else
678124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);
679124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
680f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  calibration subdevices for boards that have one */
681124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s = dev->subdevices + 3;
682124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout) {
683124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->type = COMEDI_SUBD_CALIB;
684124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
685124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->n_chan = 16;
686124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->maxdata = 0xff;
687124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->insn_read = labpc_calib_read_insn;
688124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->insn_write = labpc_calib_write_insn;
689124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
690124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		for (i = 0; i < s->n_chan; i++)
691124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			write_caldac(dev, i, s->maxdata / 2);
692124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
693124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->type = COMEDI_SUBD_UNUSED;
694124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
695124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* EEPROM */
696124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	s = dev->subdevices + 4;
697124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout) {
698124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->type = COMEDI_SUBD_MEMORY;
699124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
700124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->n_chan = EEPROM_SIZE;
701124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->maxdata = 0xff;
702124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->insn_read = labpc_eeprom_read_insn;
703124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->insn_write = labpc_eeprom_write_insn;
704124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
705412bd046b0a1726f8b168d5056d21213932f9d84tony burrows		for (i = 0; i < EEPROM_SIZE; i++)
706124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
707124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#ifdef LABPC_DEBUG
70888d8ed4b643d2064a663b2f07426963289def676Maurice Dawson		printk(KERN_ERR " eeprom:");
709412bd046b0a1726f8b168d5056d21213932f9d84tony burrows		for (i = 0; i < EEPROM_SIZE; i++)
710124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			printk(" %i:0x%x ", i, devpriv->eeprom_data[i]);
711124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		printk("\n");
712124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
713124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
714124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		s->type = COMEDI_SUBD_UNUSED;
715124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
716124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
717124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
7180656bb352080982f960bfff2b78602a5071c909fMaurice DawsonEXPORT_SYMBOL_GPL(labpc_common_attach);
719124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
720da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
721124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
722124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long iobase = 0;
723124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int irq = 0;
724124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int dma_chan = 0;
725d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
726124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int retval;
727124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
728124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
729124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* allocate and initialize dev->private */
7300a4eb4b6c7c12730254be53d93a67ed2955d5c66Bill Pemberton	if (alloc_private(dev, sizeof(struct labpc_private)) < 0)
731124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -ENOMEM;
732124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
733e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* get base address, irq etc. based on bustype */
734124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	switch (thisboard->bustype) {
735124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case isa_bustype:
7363297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
737124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		iobase = it->options[0];
738124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		irq = it->options[1];
739124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		dma_chan = it->options[2];
7403297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#else
7413297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap		printk(KERN_ERR " this driver has not been built with ISA DMA "
7423297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap								"support.\n");
7433297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap		return -EINVAL;
7443297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
745124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
746124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case pci_bustype:
747d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
748124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		retval = labpc_find_device(dev, it->options[0], it->options[1]);
749412bd046b0a1726f8b168d5056d21213932f9d84tony burrows		if (retval < 0)
750124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return retval;
751124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		retval = mite_setup(devpriv->mite);
752124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (retval < 0)
753124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return retval;
754124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		iobase = (unsigned long)devpriv->mite->daq_io_addr;
755124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		irq = mite_irq(devpriv->mite);
756124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#else
75788d8ed4b643d2064a663b2f07426963289def676Maurice Dawson		printk(KERN_ERR " this driver has not been built with PCI "
75888d8ed4b643d2064a663b2f07426963289def676Maurice Dawson								"support.\n");
759124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -EINVAL;
760124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
761124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
762124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case pcmcia_bustype:
7630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk
7640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (" this driver does not support pcmcia cards, use ni_labpc_cs.o\n");
765124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -EINVAL;
766124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
767124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	default:
76888d8ed4b643d2064a663b2f07426963289def676Maurice Dawson		printk(KERN_ERR "bug! couldn't determine board type\n");
769124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -EINVAL;
770124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
771124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
772124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
773124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return labpc_common_attach(dev, iobase, irq, dma_chan);
774124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
775124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
776f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* adapted from ni_pcimio for finding mite based boards (pc-1200) */
777d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
77871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int labpc_find_device(struct comedi_device *dev, int bus, int slot)
779124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
780124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	struct mite_struct *mite;
781124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i;
782124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (mite = mite_devices; mite; mite = mite->next) {
783124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (mite->used)
784124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			continue;
785e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* if bus/slot are specified then make sure we have the right bus/slot */
786124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (bus || slot) {
787124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (bus != mite->pcidev->bus->number
7880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    || slot != PCI_SLOT(mite->pcidev->devfn))
789124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				continue;
790124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
791124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		for (i = 0; i < driver_labpc.num_names; i++) {
792124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (labpc_boards[i].bustype != pci_bustype)
793124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				continue;
794124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (mite_device_id(mite) == labpc_boards[i].device_id) {
795124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				devpriv->mite = mite;
796e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson/* fixup board pointer, in case we were using the dummy "ni_labpc" entry */
797124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				dev->board_ptr = &labpc_boards[i];
798124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				return 0;
799124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			}
800124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
801124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
80288d8ed4b643d2064a663b2f07426963289def676Maurice Dawson	printk(KERN_ERR "no device found\n");
803124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	mite_list_devices();
804124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return -EIO;
805124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
806124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
807124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
808da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonint labpc_common_detach(struct comedi_device *dev)
809124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
81088d8ed4b643d2064a663b2f07426963289def676Maurice Dawson	printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor);
811124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
812124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (dev->subdevices)
813124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		subdev_8255_cleanup(dev, dev->subdevices + 2);
814124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
8153297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
816124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* only free stuff if it has been allocated by _attach */
817e4e1f289be88a75dc8b63d50ade1f9a2e6168021Ilia Mirkin	kfree(devpriv->dma_buffer);
818124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->dma_chan)
819124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		free_dma(devpriv->dma_chan);
8203297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
821124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (dev->irq)
8225f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		free_irq(dev->irq, dev);
823124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->bustype == isa_bustype && dev->iobase)
824124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		release_region(dev->iobase, LABPC_SIZE);
825d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
826124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->mite)
827124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		mite_unsetup(devpriv->mite);
828124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
829124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
830124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
831124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess};
8320656bb352080982f960bfff2b78602a5071c909fMaurice DawsonEXPORT_SYMBOL_GPL(labpc_common_detach);
833124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
834da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_clear_adc_fifo(const struct comedi_device *dev)
835124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
836124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
837124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
838124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
839124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
840124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
841da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
842124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
843124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long flags;
844124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
8455f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&dev->spinlock, flags);
846124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
847124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
8485f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&dev->spinlock, flags);
849124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
850124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command3_bits = 0;
851124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
852124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
853124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
854124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
855124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
856da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
857124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
858124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->chanlist_len == 1)
859124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return MODE_SINGLE_CHAN;
860124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
861124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* chanlist may be NULL during cmdtest. */
862124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->chanlist == NULL)
863124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return MODE_MULT_CHAN_UP;
864124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
865124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1]))
866124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return MODE_SINGLE_CHAN_INTERVAL;
867124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
868124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1]))
869124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return MODE_MULT_CHAN_UP;
870124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
871124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1]))
872124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return MODE_MULT_CHAN_DOWN;
873124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
87488d8ed4b643d2064a663b2f07426963289def676Maurice Dawson	printk(KERN_ERR "ni_labpc: bug! this should never happen\n");
875124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
876124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
877124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
878124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
879da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
8800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     const struct comedi_cmd *cmd)
881124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
882124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int mode, channel, range, aref, i;
883124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
884124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->chanlist == NULL)
885124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 0;
886124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
887124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	mode = labpc_ai_scan_mode(cmd);
888124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
889124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (mode == MODE_SINGLE_CHAN)
890124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 0;
891124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
892124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (mode == MODE_SINGLE_CHAN_INTERVAL) {
893124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->chanlist_len > 0xff) {
894124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev,
8950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     "ni_labpc: chanlist too long for single channel interval mode\n");
896124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return 1;
897124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
898124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
899124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
900124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	channel = CR_CHAN(cmd->chanlist[0]);
901124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	range = CR_RANGE(cmd->chanlist[0]);
902124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	aref = CR_AREF(cmd->chanlist[0]);
903124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
904124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (i = 0; i < cmd->chanlist_len; i++) {
905124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
906124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		switch (mode) {
907124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		case MODE_SINGLE_CHAN_INTERVAL:
908124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (CR_CHAN(cmd->chanlist[i]) != channel) {
909124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				comedi_error(dev,
9100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     "channel scanning order specified in chanlist is not supported by hardware.\n");
911124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				return 1;
912124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			}
913124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
914124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		case MODE_MULT_CHAN_UP:
915124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (CR_CHAN(cmd->chanlist[i]) != i) {
916124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				comedi_error(dev,
9170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     "channel scanning order specified in chanlist is not supported by hardware.\n");
918124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				return 1;
919124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			}
920124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
921124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		case MODE_MULT_CHAN_DOWN:
922124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (CR_CHAN(cmd->chanlist[i]) !=
9230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    cmd->chanlist_len - i - 1) {
924124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				comedi_error(dev,
9250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     "channel scanning order specified in chanlist is not supported by hardware.\n");
926124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				return 1;
927124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			}
928124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
929124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		default:
93088d8ed4b643d2064a663b2f07426963289def676Maurice Dawson			printk(KERN_ERR "ni_labpc: bug! in chanlist check\n");
931124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return 1;
932124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
933124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
934124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
935124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (CR_RANGE(cmd->chanlist[i]) != range) {
936124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev,
9370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     "entries in chanlist must all have the same range\n");
938124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return 1;
939124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
940124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
941124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (CR_AREF(cmd->chanlist[i]) != aref) {
942124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev,
9430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     "entries in chanlist must all have the same reference\n");
944124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return 1;
945124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
946124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
947124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
948124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
949124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
950124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
951da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_use_continuous_mode(const struct comedi_cmd *cmd)
952124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
953124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN)
954124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 1;
955124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
956124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->scan_begin_src == TRIG_FOLLOW)
957124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 1;
958124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
959124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
960124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
961124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
962da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd)
963124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
964124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->convert_src != TRIG_TIMER)
965124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 0;
966124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
967124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
9680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src == TRIG_TIMER)
969124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return cmd->scan_begin_arg;
970124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
971124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return cmd->convert_arg;
972124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
973124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
974da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns)
975124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
976124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->convert_src != TRIG_TIMER)
977124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return;
978124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
979124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
9800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src == TRIG_TIMER) {
981124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		cmd->scan_begin_arg = ns;
982124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->convert_arg > cmd->scan_begin_arg)
983124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			cmd->convert_arg = cmd->scan_begin_arg;
984124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
985124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		cmd->convert_arg = ns;
986124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
987124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
988da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd)
989124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
990124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->scan_begin_src != TRIG_TIMER)
991124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 0;
992124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
993124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
9940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->convert_src == TRIG_TIMER)
995124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 0;
996124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
997124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return cmd->scan_begin_arg;
998124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
999124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1000da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_set_ai_scan_period(struct comedi_cmd *cmd, unsigned int ns)
1001124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1002124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->scan_begin_src != TRIG_TIMER)
1003124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return;
1004124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1005124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
10060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->convert_src == TRIG_TIMER)
1007124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return;
1008124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1009124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd->scan_begin_arg = ns;
1010124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1011124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
10120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_ai_cmdtest(struct comedi_device *dev,
10130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s, struct comedi_cmd *cmd)
1014124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1015124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int err = 0;
1016124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int tmp, tmp2;
1017124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int stop_mask;
1018124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1019124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* step 1: make sure trigger sources are trivially valid */
1020124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1021124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp = cmd->start_src;
1022124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd->start_src &= TRIG_NOW | TRIG_EXT;
1023124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (!cmd->start_src || tmp != cmd->start_src)
1024124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1025124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1026124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp = cmd->scan_begin_src;
1027124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
1028124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1029124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1030124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1031124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp = cmd->convert_src;
1032124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1033124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (!cmd->convert_src || tmp != cmd->convert_src)
1034124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1035124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1036124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp = cmd->scan_end_src;
1037124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd->scan_end_src &= TRIG_COUNT;
1038124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1039124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1040124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1041124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp = cmd->stop_src;
1042124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	stop_mask = TRIG_COUNT | TRIG_NONE;
1043124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout)
1044124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		stop_mask |= TRIG_EXT;
1045124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd->stop_src &= stop_mask;
1046124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (!cmd->stop_src || tmp != cmd->stop_src)
1047124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1048124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1049124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (err)
1050124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 1;
1051124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1052124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* step 2: make sure trigger sources are unique and mutually compatible */
1053124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1054124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
1055124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1056124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->scan_begin_src != TRIG_TIMER &&
10570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_FOLLOW &&
10580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_EXT)
1059124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1060124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1061124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1062124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->stop_src != TRIG_COUNT &&
10630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
1064124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1065124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1066e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* can't have external stop and start triggers at once */
1067124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
1068124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1069124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1070124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (err)
1071124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 2;
1072124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1073124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* step 3: make sure arguments are trivially compatible */
1074124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1075124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->start_arg == TRIG_NOW && cmd->start_arg != 0) {
1076124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		cmd->start_arg = 0;
1077124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1078124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1079124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1080412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	if (!cmd->chanlist_len)
1081124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1082412bd046b0a1726f8b168d5056d21213932f9d84tony burrows
1083124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->scan_end_arg != cmd->chanlist_len) {
1084124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		cmd->scan_end_arg = cmd->chanlist_len;
1085124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1086124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1087124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1088124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->convert_src == TRIG_TIMER) {
1089124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->convert_arg < thisboard->ai_speed) {
1090124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			cmd->convert_arg = thisboard->ai_speed;
1091124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			err++;
1092124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1093124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1094e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* make sure scan timing is not too fast */
1095124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->scan_begin_src == TRIG_TIMER) {
1096124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->convert_src == TRIG_TIMER &&
10970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    cmd->scan_begin_arg <
10980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    cmd->convert_arg * cmd->chanlist_len) {
1099124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			cmd->scan_begin_arg =
11000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    cmd->convert_arg * cmd->chanlist_len;
1101124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			err++;
1102124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1103124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->scan_begin_arg <
11040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    thisboard->ai_speed * cmd->chanlist_len) {
1105124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			cmd->scan_begin_arg =
11060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    thisboard->ai_speed * cmd->chanlist_len;
1107124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			err++;
1108124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1109124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1110e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* stop source */
1111124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	switch (cmd->stop_src) {
1112124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_COUNT:
1113124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (!cmd->stop_arg) {
1114124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			cmd->stop_arg = 1;
1115124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			err++;
1116124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1117124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1118124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_NONE:
1119124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->stop_arg != 0) {
1120124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			cmd->stop_arg = 0;
1121124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			err++;
1122124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1123124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
11241309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		/*
11251309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * TRIG_EXT doesn't care since it doesn't
11261309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * trigger off a numbered channel
11271309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 */
1128124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	default:
1129124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1130124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1131124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1132124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (err)
1133124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 3;
1134124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1135124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* step 4: fix up any arguments */
1136124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1137124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp = cmd->convert_arg;
1138124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	tmp2 = cmd->scan_begin_arg;
1139124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_adc_timing(dev, cmd);
1140124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg)
1141124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		err++;
1142124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1143124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (err)
1144124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 4;
1145124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1146124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_chanlist_invalid(dev, cmd))
1147124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 5;
1148124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1149124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
1150124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1151124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1152da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1153124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1154124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int channel, range, aref;
11553297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1156124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long irq_flags;
11573297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
1158124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int ret;
1159d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1160ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &async->cmd;
1161124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	enum transfer_type xfer;
1162124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long flags;
1163124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1164124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (!dev->irq) {
1165124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "no irq assigned, cannot perform command");
1166124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -1;
1167124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1168124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1169124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	range = CR_RANGE(cmd->chanlist[0]);
1170124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	aref = CR_AREF(cmd->chanlist[0]);
1171124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
117225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* make sure board is disabled before setting up acquisition */
11735f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&dev->spinlock, flags);
1174124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
1175124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
11765f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&dev->spinlock, flags);
1177124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1178124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command3_bits = 0;
1179124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
1180124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1181f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  initialize software conversion count */
1182412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	if (cmd->stop_src == TRIG_COUNT)
1183124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->count = cmd->stop_arg * cmd->chanlist_len;
118465d6d26c6bcd802ebe2b22a29d9b6bbebfd8d7f8Maurice Dawson
1185f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  setup hardware conversion counter */
1186124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->stop_src == TRIG_EXT) {
11871309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		/*
11881309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * load counter a1 with count of 3
11891309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * (pc+ manual says this is minimum allowed) using mode 0
11901309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 */
1191124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
11920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 1, 3, 0);
1193124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (ret < 0) {
1194124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev, "error loading counter a1");
1195124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -1;
1196124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
11971309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson	} else			/*
11981309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson				 * otherwise, just put a1 in mode 0
11991309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson				 * with no count to set its output low
12001309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson				 */
1201124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(INIT_A1_BITS,
12020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COUNTER_A_CONTROL_REG);
1203124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
12043297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1205f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  figure out what method we will use to transfer data */
1206f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	if (devpriv->dma_chan &&	/*  need a dma channel allocated */
12071309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		/*
12081309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * dma unsafe at RT priority,
12091309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * and too much setup time for TRIG_WAKE_EOS for
12101309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 */
12110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 &&
12120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    /*  only available on the isa boards */
12130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    thisboard->bustype == isa_bustype) {
1214124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		xfer = isa_dma_transfer;
12151309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		/* pc-plus has no fifo-half full interrupt */
12163297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap	} else
12173297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
12183297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap	if (thisboard->register_layout == labpc_1200_layout &&
12190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		   /*  wake-end-of-scan should interrupt on fifo not empty */
12200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		   (cmd->flags & TRIG_WAKE_EOS) == 0 &&
12210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		   /*  make sure we are taking more than just a few points */
12220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		   (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) {
1223124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		xfer = fifo_half_full_transfer;
1224124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
1225124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		xfer = fifo_not_empty_transfer;
1226124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->current_transfer = xfer;
1227124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1228f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  setup command6 register for 1200 boards */
1229124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout) {
1230f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  reference inputs to ground or common? */
1231124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (aref != AREF_GROUND)
1232124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= ADC_COMMON_BIT;
1233124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1234124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~ADC_COMMON_BIT;
1235f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  bipolar or unipolar range? */
1236124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (thisboard->ai_range_is_unipolar[range])
1237124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= ADC_UNIP_BIT;
1238124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1239124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~ADC_UNIP_BIT;
1240f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  interrupt on fifo half full? */
1241124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (xfer == fifo_half_full_transfer)
1242124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= ADC_FHF_INTR_EN_BIT;
1243124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1244124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
1245f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  enable interrupt on counter a1 terminal count? */
1246124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->stop_src == TRIG_EXT)
1247124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= A1_INTR_EN_BIT;
1248124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1249124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~A1_INTR_EN_BIT;
1250f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  are we scanning up or down through channels? */
1251124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP)
1252124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= ADC_SCAN_UP_BIT;
1253124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1254124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~ADC_SCAN_UP_BIT;
1255f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  write to register */
1256124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command6_bits,
12570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND6_REG);
1258124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1259124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1260124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* setup channel list, etc (command1 register) */
1261124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command1_bits = 0;
1262124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP)
1263124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
1264124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	else
1265124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		channel = CR_CHAN(cmd->chanlist[0]);
1266e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* munge channel bits for differential / scan disabled mode */
1267124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF)
1268124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		channel *= 2;
1269124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command1_bits |= ADC_CHAN_BITS(channel);
1270124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command1_bits |= thisboard->ai_range_code[range];
1271124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
1272e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* manual says to set scan enable bit on second pass */
1273124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP ||
12740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) {
1275124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command1_bits |= ADC_SCAN_EN_BIT;
1276e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* need a brief delay before enabling scan, or scan
1277e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 * list will get screwed when you switch
1278124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		 * between scan up to scan down mode - dunno why */
12795f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
1280124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command1_bits,
12810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND1_REG);
1282124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1283f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  setup any external triggering/pacing (command4 register) */
1284124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command4_bits = 0;
1285124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->convert_src != TRIG_EXT)
1286124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
1287124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* XXX should discard first scan when using interval scanning
1288124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	 * since manual says it is not synced with scan clock */
1289124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_use_continuous_mode(cmd) == 0) {
1290124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT;
1291124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->scan_begin_src == TRIG_EXT)
1292124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command4_bits |= EXT_SCAN_EN_BIT;
1293124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1294f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  single-ended/differential */
1295124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (aref == AREF_DIFF)
1296124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command4_bits |= ADC_DIFF_BIT;
1297124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
1298124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1299124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(cmd->chanlist_len,
13000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    dev->iobase + INTERVAL_COUNT_REG);
1301f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  load count */
1302124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(INTERVAL_LOAD_BITS,
13030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    dev->iobase + INTERVAL_LOAD_REG);
1304124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1305124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) {
1306f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  set up pacing */
1307124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_adc_timing(dev, cmd);
1308f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  load counter b0 in mode 3 */
1309124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
13100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 0, devpriv->divisor_b0, 3);
1311124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (ret < 0) {
1312124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev, "error loading counter b0");
1313124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -1;
1314124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1315124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1316f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  set up conversion pacing */
1317124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_convert_period(cmd)) {
1318f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  load counter a0 in mode 2 */
1319124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
13200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 0, devpriv->divisor_a0, 2);
1321124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (ret < 0) {
1322124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev, "error loading counter a0");
1323124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -1;
1324124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1325124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
1326124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(INIT_A0_BITS,
13270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COUNTER_A_CONTROL_REG);
1328124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1329f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  set up scan pacing */
1330124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_scan_period(cmd)) {
1331f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  load counter b1 in mode 2 */
1332124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
13330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 1, devpriv->divisor_b1, 2);
1334124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (ret < 0) {
1335124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev, "error loading counter b1");
1336124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -1;
1337124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1338124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1339124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1340124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_clear_adc_fifo(dev);
1341124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
13423297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1343f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  set up dma transfer */
1344124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (xfer == isa_dma_transfer) {
1345124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		irq_flags = claim_dma_lock();
1346124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		disable_dma(devpriv->dma_chan);
1347124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		/* clear flip-flop to make sure 2-byte registers for
1348124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		 * count and address get set correctly */
1349124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		clear_dma_ff(devpriv->dma_chan);
1350124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		set_dma_addr(devpriv->dma_chan,
13510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     virt_to_bus(devpriv->dma_buffer));
1352f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  set appropriate size of transfer */
1353124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd);
1354124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (cmd->stop_src == TRIG_COUNT &&
13550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    devpriv->count * sample_size < devpriv->dma_transfer_size) {
1356124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->dma_transfer_size =
13570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    devpriv->count * sample_size;
1358124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1359124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
1360124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		enable_dma(devpriv->dma_chan);
1361124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		release_dma_lock(irq_flags);
1362f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  enable board's dma */
1363124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command3_bits |= DMA_EN_BIT | DMATC_INTR_EN_BIT;
1364124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
1365124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command3_bits &= ~DMA_EN_BIT & ~DMATC_INTR_EN_BIT;
13663297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
1367124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1368f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  enable error interrupts */
1369124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command3_bits |= ERR_INTR_EN_BIT;
1370f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  enable fifo not empty interrupt? */
1371124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (xfer == fifo_not_empty_transfer)
1372124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command3_bits |= ADC_FNE_INTR_EN_BIT;
1373124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	else
1374124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT;
1375124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
1376124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
137725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/*  startup acquisition */
1378124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1379f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  command2 reg */
1380f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  use 2 cascaded counters for pacing */
13815f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&dev->spinlock, flags);
1382124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command2_bits |= CASCADE_BIT;
1383124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	switch (cmd->start_src) {
1384124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_EXT:
1385124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command2_bits |= HWTRIG_BIT;
1386124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command2_bits &= ~PRETRIG_BIT & ~SWTRIG_BIT;
1387124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1388124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_NOW:
1389124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command2_bits |= SWTRIG_BIT;
1390124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command2_bits &= ~PRETRIG_BIT & ~HWTRIG_BIT;
1391124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1392124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	default:
1393124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "bug with start_src");
1394124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -1;
1395124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1396124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1397124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	switch (cmd->stop_src) {
1398124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_EXT:
1399124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command2_bits |= HWTRIG_BIT | PRETRIG_BIT;
1400124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1401124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_COUNT:
1402124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	case TRIG_NONE:
1403124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		break;
1404124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	default:
1405124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "bug with stop_src");
1406124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -1;
1407124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1408124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
14095f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&dev->spinlock, flags);
1410124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1411124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
1412124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1413124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1414124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess/* interrupt service routine */
141570265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t labpc_interrupt(int irq, void *d)
1416124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
141771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = d;
141834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = dev->read_subdev;
1419d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1420ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd;
1421124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1422124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (dev->attached == 0) {
1423124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "premature interrupt");
1424124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return IRQ_HANDLED;
1425124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1426124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1427124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	async = s->async;
1428124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	cmd = &async->cmd;
1429124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	async->events = 0;
1430124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1431e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* read board status */
1432124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
1433124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout)
1434124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->status2_bits =
14350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    devpriv->read_byte(dev->iobase + STATUS2_REG);
1436124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1437124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if ((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT |
14380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				      OVERRUN_BIT | DATA_AVAIL_BIT)) == 0
14390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    && (devpriv->status2_bits & A1_TC_BIT) == 0
14400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    && (devpriv->status2_bits & FNHF_BIT)) {
1441124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return IRQ_NONE;
1442124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1443124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1444124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->status1_bits & OVERRUN_BIT) {
1445e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* clear error interrupt */
1446124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
1447124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1448124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_event(dev, s);
1449124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "overrun");
1450124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return IRQ_HANDLED;
1451124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1452124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
14533297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1454124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->current_transfer == isa_dma_transfer) {
1455639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		/*
1456639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		 * if a dma terminal count of external stop trigger
1457639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		 * has occurred
1458639b9f1ee5987270be2bca4bf8b7e6110d3b47ecStewart Robertson		 */
1459124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->status1_bits & DMATC_BIT ||
14600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (thisboard->register_layout == labpc_1200_layout
14610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     && devpriv->status2_bits & A1_TC_BIT)) {
1462124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			handle_isa_dma(dev);
1463124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1464124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else
14653297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
1466124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_drain_fifo(dev);
1467124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1468124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->status1_bits & TIMER_BIT) {
1469124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "handled timer interrupt?");
1470f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  clear it */
1471124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
1472124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1473124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1474124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->status1_bits & OVERFLOW_BIT) {
1475f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  clear error interrupt */
1476124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
1477124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1478124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_event(dev, s);
1479124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "overflow");
1480124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return IRQ_HANDLED;
1481124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1482f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  handle external stop trigger */
1483124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->stop_src == TRIG_EXT) {
1484124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->status2_bits & A1_TC_BIT) {
1485124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			labpc_drain_dregs(dev);
1486124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			labpc_cancel(dev, s);
1487124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			async->events |= COMEDI_CB_EOA;
1488124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1489124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1490124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1491124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* TRIG_COUNT end of acquisition */
1492124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd->stop_src == TRIG_COUNT) {
1493124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->count == 0) {
1494124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			labpc_cancel(dev, s);
1495124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			async->events |= COMEDI_CB_EOA;
1496124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1497124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1498124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1499124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	comedi_event(dev, s);
1500124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return IRQ_HANDLED;
1501124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1502124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1503f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* read all available samples from ai fifo */
1504da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_drain_fifo(struct comedi_device *dev)
1505124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1506124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int lsb, msb;
1507790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	short data;
1508d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = dev->read_subdev->async;
1509124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	const int timeout = 10000;
1510124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int i;
1511124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1512124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
1513124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1514124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (i = 0; (devpriv->status1_bits & DATA_AVAIL_BIT) && i < timeout;
15150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     i++) {
1516f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  quit if we have all the data we want */
1517124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (async->cmd.stop_src == TRIG_COUNT) {
1518124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (devpriv->count == 0)
1519124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				break;
1520124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->count--;
1521124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1522124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
1523124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
1524124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		data = (msb << 8) | lsb;
1525124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		cfc_write_to_buffer(dev->read_subdev, data);
1526124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->status1_bits =
15270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    devpriv->read_byte(dev->iobase + STATUS1_REG);
1528124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1529124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (i == timeout) {
1530124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "ai timeout, fifo never empties");
1531124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1532124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -1;
1533124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1534124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1535124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
1536124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1537124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
15383297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1539da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_drain_dma(struct comedi_device *dev)
1540124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
154134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = dev->read_subdev;
1542d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1543124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int status;
1544124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long flags;
1545124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int max_points, num_points, residue, leftover;
1546124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i;
1547124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1548124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	status = devpriv->status1_bits;
1549124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1550124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	flags = claim_dma_lock();
1551124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	disable_dma(devpriv->dma_chan);
1552124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* clear flip-flop to make sure 2-byte registers for
1553124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	 * count and address get set correctly */
1554124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	clear_dma_ff(devpriv->dma_chan);
1555124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1556f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  figure out how many points to read */
1557124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	max_points = devpriv->dma_transfer_size / sample_size;
1558124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* residue is the number of points left to be done on the dma
1559124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	 * transfer.  It should always be zero at this point unless
1560124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	 * the stop_src is set to external triggering.
1561124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	 */
1562124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	residue = get_dma_residue(devpriv->dma_chan) / sample_size;
1563124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	num_points = max_points - residue;
1564124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
1565124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		num_points = devpriv->count;
1566124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1567f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  figure out how many points will be stored next time */
1568124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	leftover = 0;
1569124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (async->cmd.stop_src != TRIG_COUNT) {
1570124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		leftover = devpriv->dma_transfer_size / sample_size;
1571124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else if (devpriv->count > num_points) {
1572124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		leftover = devpriv->count - num_points;
1573124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (leftover > max_points)
1574124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			leftover = max_points;
1575124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1576124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1577124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* write data to comedi buffer */
1578412bd046b0a1726f8b168d5056d21213932f9d84tony burrows	for (i = 0; i < num_points; i++)
1579124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
158065d6d26c6bcd802ebe2b22a29d9b6bbebfd8d7f8Maurice Dawson
1581124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (async->cmd.stop_src == TRIG_COUNT)
1582124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->count -= num_points;
1583124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1584f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  set address and count for next transfer */
1585124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer));
1586124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	set_dma_count(devpriv->dma_chan, leftover * sample_size);
1587124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	release_dma_lock(flags);
1588124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1589124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	async->events |= COMEDI_CB_BLOCK;
1590124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1591124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1592da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void handle_isa_dma(struct comedi_device *dev)
1593124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1594124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_drain_dma(dev);
1595124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1596124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	enable_dma(devpriv->dma_chan);
1597124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1598f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  clear dma tc interrupt */
1599124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
1600124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
16013297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
1602124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
160325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* makes sure all data acquired by board is transferred to comedi (used
160425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * when acquisition is terminated by stop_src == TRIG_EXT). */
1605da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_drain_dregs(struct comedi_device *dev)
1606124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
16073297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1608124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (devpriv->current_transfer == isa_dma_transfer)
1609124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_drain_dma(dev);
16103297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
1611124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1612124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_drain_fifo(dev);
1613124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1614124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1615da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
16160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data)
1617124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1618124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i, n;
1619124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int chan, range;
1620124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int lsb, msb;
1621124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int timeout = 1000;
1622124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long flags;
1623124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1624f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  disable timed conversions */
16255f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&dev->spinlock, flags);
1626124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
1627124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
16285f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&dev->spinlock, flags);
1629124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1630f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  disable interrupt generation and dma */
1631124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command3_bits = 0;
1632124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
1633124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1634124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* set gain and channel */
1635124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command1_bits = 0;
1636124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	chan = CR_CHAN(insn->chanspec);
1637124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	range = CR_RANGE(insn->chanspec);
1638124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command1_bits |= thisboard->ai_range_code[range];
1639e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* munge channel bits for differential/scan disabled mode */
1640124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (CR_AREF(insn->chanspec) == AREF_DIFF)
1641124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		chan *= 2;
1642124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command1_bits |= ADC_CHAN_BITS(chan);
1643124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
1644124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1645e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* setup command6 register for 1200 boards */
1646124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout) {
1647f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  reference inputs to ground or common? */
1648124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (CR_AREF(insn->chanspec) != AREF_GROUND)
1649124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= ADC_COMMON_BIT;
1650124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1651124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~ADC_COMMON_BIT;
1652e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* bipolar or unipolar range? */
1653124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (thisboard->ai_range_is_unipolar[range])
1654124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= ADC_UNIP_BIT;
1655124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1656124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~ADC_UNIP_BIT;
1657e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* don't interrupt on fifo half full */
1658124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
1659e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* don't enable interrupt on counter a1 terminal count? */
1660124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command6_bits &= ~A1_INTR_EN_BIT;
1661e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/* write to register */
1662124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command6_bits,
16630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND6_REG);
1664124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1665e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* setup command4 register */
1666124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command4_bits = 0;
1667124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
1668e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* single-ended/differential */
1669124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (CR_AREF(insn->chanspec) == AREF_DIFF)
1670124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command4_bits |= ADC_DIFF_BIT;
1671124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
1672124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
16731309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson	/*
16741309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson	 * initialize pacer counter output to make sure it doesn't
16751309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson	 * cause any problems
16761309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson	 */
1677124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
1678124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1679124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_clear_adc_fifo(dev);
1680124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1681124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (n = 0; n < insn->n; n++) {
1682124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		/* trigger conversion */
1683124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(0x1, dev->iobase + ADC_CONVERT_REG);
1684124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1685124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		for (i = 0; i < timeout; i++) {
1686124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			if (devpriv->read_byte(dev->iobase +
16870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       STATUS1_REG) & DATA_AVAIL_BIT)
1688124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess				break;
16895f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman			udelay(1);
1690124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1691124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (i == timeout) {
1692124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			comedi_error(dev, "timeout");
1693124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			return -ETIME;
1694124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1695124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
1696124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
1697124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		data[n] = (msb << 8) | lsb;
1698124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1699124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1700124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return n;
1701124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1702124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1703f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* analog output insn */
1704da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
17050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data)
1706124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1707124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int channel, range;
1708124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned long flags;
1709124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int lsb, msb;
1710124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1711124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	channel = CR_CHAN(insn->chanspec);
1712124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1713e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* turn off pacing of analog output channel */
1714124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	/* note: hardware bug in daqcard-1200 means pacing cannot
1715124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	 * be independently enabled/disabled for its the two channels */
17165f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&dev->spinlock, flags);
1717124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command2_bits &= ~DAC_PACED_BIT(channel);
1718124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
17195f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&dev->spinlock, flags);
1720124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1721e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* set range */
1722124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (thisboard->register_layout == labpc_1200_layout) {
1723124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		range = CR_RANGE(insn->chanspec);
1724124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (range & AO_RANGE_IS_UNIPOLAR)
1725124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits |= DAC_UNIP_BIT(channel);
1726124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1727124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command6_bits &= ~DAC_UNIP_BIT(channel);
1728f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  write to register */
1729124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command6_bits,
17300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND6_REG);
1731124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1732e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* send data */
1733124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	lsb = data[0] & 0xff;
1734124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	msb = (data[0] >> 8) & 0xff;
1735124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(channel));
1736124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(channel));
1737124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1738e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* remember value for readback */
1739124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->ao_value[channel] = data[0];
1740124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1741124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 1;
1742124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1743124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1744f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* analog output readback insn */
1745da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
17460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data)
1747124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1748124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
1749124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1750124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 1;
1751124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1752124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
17530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_calib_read_insn(struct comedi_device *dev,
17540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 struct comedi_subdevice *s,
17550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 struct comedi_insn *insn, unsigned int *data)
1756124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1757124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)];
1758124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1759124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 1;
1760124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1761124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
17620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_calib_write_insn(struct comedi_device *dev,
17630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
17640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
1765124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1766124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int channel = CR_CHAN(insn->chanspec);
1767124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1768124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	write_caldac(dev, channel, data[0]);
1769124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 1;
1770124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1771124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
17720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_eeprom_read_insn(struct comedi_device *dev,
17730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
17740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
1775124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1776124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)];
1777124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1778124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 1;
1779124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1780124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
17810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int labpc_eeprom_write_insn(struct comedi_device *dev,
17820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   struct comedi_subdevice *s,
17830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   struct comedi_insn *insn, unsigned int *data)
1784124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1785124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int channel = CR_CHAN(insn->chanspec);
1786124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int ret;
1787124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1788f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  only allow writes to user area of eeprom */
1789124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (channel < 16 || channel > 127) {
17900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk
17910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    ("eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)");
1792124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -EINVAL;
1793124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1794124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1795124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	ret = labpc_eeprom_write(dev, channel, data[0]);
1796124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (ret < 0)
1797124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return ret;
1798124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1799124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 1;
1800124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1801124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
18023297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#ifdef CONFIG_ISA_DMA_API
1803f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* utility function that suggests a dma transfer size in bytes */
1804ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pembertonstatic unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd)
1805124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1806124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int size;
1807124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int freq;
1808124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1809124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (cmd.convert_src == TRIG_TIMER)
1810124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		freq = 1000000000 / cmd.convert_arg;
1811e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* return some default value */
1812124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	else
1813124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		freq = 0xffffffff;
1814124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1815e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* make buffer fill in no more than 1/3 second */
1816124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	size = (freq / 3) * sample_size;
1817124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1818e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* set a minimum and maximum size allowed */
1819124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (size > dma_buffer_size)
1820124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		size = dma_buffer_size - dma_buffer_size % sample_size;
1821124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	else if (size < sample_size)
1822124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		size = sample_size;
1823124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1824124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return size;
1825124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
18263297d6c7c84a2a3f62b41b703a2963759e822e96Randy Dunlap#endif
1827124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1828f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* figures out what counter values to use based on command */
1829da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
1830124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1831e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* max value for 16 bit counter in mode 2 */
1832e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	const int max_counter_value = 0x10000;
1833e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/* min value for 16 bit counter in mode 2 */
1834e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	const int min_counter_value = 2;
1835124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int base_period;
1836124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1837e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/*
1838e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	 * if both convert and scan triggers are TRIG_TIMER, then they
1839e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	 * both rely on counter b0
1840e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	 */
1841124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) {
1842e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/*
1843e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 * pick the lowest b0 divisor value we can (for maximum input
1844e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 * clock speed on convert and scan counters)
1845e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 */
1846124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) /
18470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (LABPC_TIMER_BASE * max_counter_value) + 1;
1848124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->divisor_b0 < min_counter_value)
1849124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b0 = min_counter_value;
1850124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->divisor_b0 > max_counter_value)
1851124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b0 = max_counter_value;
1852124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1853124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
1854124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1855f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  set a0 for conversion frequency and b1 for scan frequency */
1856124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		switch (cmd->flags & TRIG_ROUND_MASK) {
1857124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		default:
1858124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		case TRIG_ROUND_NEAREST:
1859124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_a0 =
18600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (labpc_ai_convert_period(cmd) +
18610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     (base_period / 2)) / base_period;
1862124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b1 =
18630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (labpc_ai_scan_period(cmd) +
18640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     (base_period / 2)) / base_period;
1865124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
1866124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		case TRIG_ROUND_UP:
1867124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_a0 =
18680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (labpc_ai_convert_period(cmd) + (base_period -
18690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     1)) / base_period;
1870124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b1 =
18710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (labpc_ai_scan_period(cmd) + (base_period -
18720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							  1)) / base_period;
1873124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
1874124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		case TRIG_ROUND_DOWN:
1875124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_a0 =
18760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    labpc_ai_convert_period(cmd) / base_period;
1877124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b1 =
18780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    labpc_ai_scan_period(cmd) / base_period;
1879124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
1880124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		}
1881f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  make sure a0 and b1 values are acceptable */
1882124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->divisor_a0 < min_counter_value)
1883124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_a0 = min_counter_value;
1884124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->divisor_a0 > max_counter_value)
1885124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_a0 = max_counter_value;
1886124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->divisor_b1 < min_counter_value)
1887124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b1 = min_counter_value;
1888124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (devpriv->divisor_b1 > max_counter_value)
1889124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->divisor_b1 = max_counter_value;
1890f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  write corrected timings to command */
1891124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_set_ai_convert_period(cmd,
18920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    base_period * devpriv->divisor_a0);
1893124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_set_ai_scan_period(cmd,
18940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 base_period * devpriv->divisor_b1);
1895e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		/*
1896e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 * if only one TRIG_TIMER is used, we can employ the generic
1897e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 * cascaded timing functions
1898e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson		 */
1899124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else if (labpc_ai_scan_period(cmd)) {
1900124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		unsigned int scan_period;
1901124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1902124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		scan_period = labpc_ai_scan_period(cmd);
19031309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		/*
19041309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * calculate cascaded counter values
19051309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * that give desired scan timing
19061309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 */
1907124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
19080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &(devpriv->divisor_b1),
19090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &(devpriv->divisor_b0),
19100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &scan_period,
19110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       cmd->flags & TRIG_ROUND_MASK);
1912124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_set_ai_scan_period(cmd, scan_period);
1913124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else if (labpc_ai_convert_period(cmd)) {
1914124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		unsigned int convert_period;
1915124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1916124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		convert_period = labpc_ai_convert_period(cmd);
19171309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		/*
19181309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * calculate cascaded counter values
19191309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 * that give desired conversion timing
19201309e617bc56f2f8af9a9c5aab1224a45539002aMaurice Dawson		 */
1921124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
19220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &(devpriv->divisor_a0),
19230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &(devpriv->divisor_b0),
19240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &convert_period,
19250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       cmd->flags & TRIG_ROUND_MASK);
1926124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		labpc_set_ai_convert_period(cmd, convert_period);
1927124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1928124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1929124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1930124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hessstatic int labpc_dio_mem_callback(int dir, int port, int data,
19310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  unsigned long iobase)
1932124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1933124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (dir) {
1934124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		writeb(data, (void *)(iobase + port));
1935124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return 0;
1936124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	} else {
1937124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return readb((void *)(iobase + port));
1938124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1939124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1940124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1941f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* lowlevel write to eeprom/dac */
1942da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void labpc_serial_out(struct comedi_device *dev, unsigned int value,
19430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     unsigned int value_width)
1944124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1945124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i;
1946124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1947124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (i = 1; i <= value_width; i++) {
1948f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  clear serial clock */
1949124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command5_bits &= ~SCLOCK_BIT;
1950f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  send bits most significant bit first */
1951124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if (value & (1 << (value_width - i)))
1952124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command5_bits |= SDATA_BIT;
1953124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		else
1954124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			devpriv->command5_bits &= ~SDATA_BIT;
19555f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
1956124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command5_bits,
19570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND5_REG);
1958f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  set clock to load bit */
1959124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command5_bits |= SCLOCK_BIT;
19605f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
1961124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command5_bits,
19620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND5_REG);
1963124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1964124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1965124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1966f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* lowlevel read from eeprom */
1967da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic unsigned int labpc_serial_in(struct comedi_device *dev)
1968124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1969124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int value = 0;
1970124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i;
1971f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	const int value_width = 8;	/*  number of bits wide values are */
1972124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1973124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (i = 1; i <= value_width; i++) {
1974f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  set serial clock */
1975124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command5_bits |= SCLOCK_BIT;
19765f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
1977124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command5_bits,
19780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND5_REG);
1979f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  clear clock bit */
1980124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->command5_bits &= ~SCLOCK_BIT;
19815f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
1982124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->write_byte(devpriv->command5_bits,
19830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    dev->iobase + COMMAND5_REG);
1984f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton		/*  read bits most significant bit first */
19855f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
1986124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		devpriv->status2_bits =
19870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    devpriv->read_byte(dev->iobase + STATUS2_REG);
1988412bd046b0a1726f8b168d5056d21213932f9d84tony burrows		if (devpriv->status2_bits & EEPROM_OUT_BIT)
1989124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			value |= 1 << (value_width - i);
1990124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
1991124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
1992124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return value;
1993124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
1994124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
19950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int labpc_eeprom_read(struct comedi_device *dev,
19960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				      unsigned int address)
1997124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
1998124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int value;
1999e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/*  bits to tell eeprom to expect a read */
2000e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	const int read_instruction = 0x3;
2001e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	/*  8 bit write lengths to eeprom */
2002e41a6f6d9cb7404420d596f27609a3f4f55dcaf5Stewart Robertson	const int write_length = 8;
2003124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2004f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  enable read/write to eeprom */
2005124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT;
20065f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2007124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2008124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
20095f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2010124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2011124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2012f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  send read instruction */
2013124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, read_instruction, write_length);
2014f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  send 8 bit address to read from */
2015124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, address, write_length);
2016f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  read result */
2017124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	value = labpc_serial_in(dev);
2018124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2019f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  disable read/write to eeprom */
2020124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
20215f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2022124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2023124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2024124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return value;
2025124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
2026124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2027d6269644e1f8fc7931c4d6b86d58de7af63a5fc9Julia Lawallstatic int labpc_eeprom_write(struct comedi_device *dev,
2028d6269644e1f8fc7931c4d6b86d58de7af63a5fc9Julia Lawall				unsigned int address, unsigned int value)
2029124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
2030124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	const int write_enable_instruction = 0x6;
2031124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	const int write_instruction = 0x2;
2032f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	const int write_length = 8;	/*  8 bit write lengths to eeprom */
2033124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	const int write_in_progress_bit = 0x1;
2034124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	const int timeout = 10000;
2035124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	int i;
2036124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2037f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  make sure there isn't already a write in progress */
2038124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	for (i = 0; i < timeout; i++) {
2039124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) ==
20400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    0)
2041124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess			break;
2042124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
2043124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (i == timeout) {
2044124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		comedi_error(dev, "eeprom write timed out");
2045124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return -ETIME;
2046124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	}
2047f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  update software copy of eeprom */
2048124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->eeprom_data[address] = value;
2049124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2050f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  enable read/write to eeprom */
2051124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT;
20525f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2053124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2054124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
20555f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2056124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2057124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2058f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  send write_enable instruction */
2059124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, write_enable_instruction, write_length);
2060124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT;
20615f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2062124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2063124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2064f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  send write instruction */
2065124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits |= EEPROM_EN_BIT;
20665f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2067124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2068124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, write_instruction, write_length);
2069f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  send 8 bit address to write to */
2070124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, address, write_length);
2071f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  write value */
2072124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, value, write_length);
2073124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT;
20745f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2075124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2076124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2077f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  disable read/write to eeprom */
2078124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
20795f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2080124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2081124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2082124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return 0;
2083124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
2084124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2085da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
2086124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
2087124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	unsigned int value;
2088124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	const int read_status_instruction = 0x5;
2089f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	const int write_length = 8;	/*  8 bit write lengths to eeprom */
2090124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2091f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  enable read/write to eeprom */
2092124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT;
20935f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2094124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2095124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
20965f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2097124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2098124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2099f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  send read status instruction */
2100124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, read_status_instruction, write_length);
2101f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  read result */
2102124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	value = labpc_serial_in(dev);
2103124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2104f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  disable read/write to eeprom */
2105124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
21065f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2107124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2108124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2109124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	return value;
2110124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
2111124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2112f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton/* writes to 8 bit calibration dacs */
2113da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void write_caldac(struct comedi_device *dev, unsigned int channel,
21140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 unsigned int value)
2115124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess{
2116124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	if (value == devpriv->caldac[channel])
2117124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess		return;
2118124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->caldac[channel] = value;
2119124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2120f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  clear caldac load bit and make sure we don't write to eeprom */
2121124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &=
21220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
21235f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2124124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2125124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2126f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  write 4 bit channel */
2127124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, channel, 4);
2128f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  write 8 bit caldac value */
2129124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	labpc_serial_out(dev, value, 8);
2130124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2131f6b49620a43ca661246d209009b849d7d3030caeBill Pemberton	/*  set and clear caldac bit to load caldac value */
2132124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits |= CALDAC_LOAD_BIT;
21335f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2134124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2135124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->command5_bits &= ~CALDAC_LOAD_BIT;
21365f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(1);
2137124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
2138124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess}
2139124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
2140d6aa8366dde1656f859b6ebf5face1718793a467Randy Dunlap#ifdef CONFIG_COMEDI_PCI_DRIVERS
2141727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __devinit driver_labpc_pci_probe(struct pci_dev *dev,
2142727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas					    const struct pci_device_id *ent)
2143727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
2144727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return comedi_pci_auto_config(dev, driver_labpc.driver_name);
2145727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
2146727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2147727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __devexit driver_labpc_pci_remove(struct pci_dev *dev)
2148727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
2149727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_pci_auto_unconfig(dev);
2150727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
2151727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2152727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic struct pci_driver driver_labpc_pci_driver = {
2153727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.id_table = labpc_pci_table,
2154727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.probe = &driver_labpc_pci_probe,
2155727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.remove = __devexit_p(&driver_labpc_pci_remove)
2156727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas};
2157727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2158727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __init driver_labpc_init_module(void)
2159727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
2160727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	int retval;
2161727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2162727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	retval = comedi_driver_register(&driver_labpc);
2163727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	if (retval < 0)
2164727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas		return retval;
2165727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2166727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	driver_labpc_pci_driver.name = (char *)driver_labpc.driver_name;
2167727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return pci_register_driver(&driver_labpc_pci_driver);
2168727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
2169727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2170727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __exit driver_labpc_cleanup_module(void)
2171727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
2172727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	pci_unregister_driver(&driver_labpc_pci_driver);
2173727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_driver_unregister(&driver_labpc);
2174727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
2175727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
2176727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_init(driver_labpc_init_module);
2177727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_exit(driver_labpc_cleanup_module);
2178124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#else
21797114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_labpc_init_module(void)
21807114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
21817114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_labpc);
21827114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
21837114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
21847114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_labpc_cleanup_module(void)
21857114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
21867114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_labpc);
21877114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
21887114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
21897114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_labpc_init_module);
21907114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_labpc_cleanup_module);
2191124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess#endif
2192124b13b26df5dab0236520de95e1cc1dea06e3c3Frank Mori Hess
219390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
219490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
219590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
219690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
2197