GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / amplc_pci230.c
blob683e2437a5b6fa6b67fd393931b9a7b6df7ecb90
1 /*
2 comedi/drivers/amplc_pci230.c
3 Driver for Amplicon PCI230 and PCI260 Multifunction I/O boards.
5 Copyright (C) 2001 Allan Willcox <allanwillcox@ozemail.com.au>
7 COMEDI - Linux Control and Measurement Device Interface
8 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Driver: amplc_pci230
26 Description: Amplicon PCI230, PCI260 Multifunction I/O boards
27 Author: Allan Willcox <allanwillcox@ozemail.com.au>,
28 Steve D Sharples <steve.sharples@nottingham.ac.uk>,
29 Ian Abbott <abbotti@mev.co.uk>
30 Updated: Wed, 22 Oct 2008 12:34:49 +0100
31 Devices: [Amplicon] PCI230 (pci230 or amplc_pci230),
32 PCI230+ (pci230+ or amplc_pci230),
33 PCI260 (pci260 or amplc_pci230), PCI260+ (pci260+ or amplc_pci230)
34 Status: works
36 Configuration options:
37 [0] - PCI bus of device (optional).
38 [1] - PCI slot of device (optional).
39 If bus/slot is not specified, the first available PCI device
40 will be used.
42 Configuring a "amplc_pci230" will match any supported card and it will
43 choose the best match, picking the "+" models if possible. Configuring
44 a "pci230" will match a PCI230 or PCI230+ card and it will be treated as
45 a PCI230. Configuring a "pci260" will match a PCI260 or PCI260+ card
46 and it will be treated as a PCI260. Configuring a "pci230+" will match
47 a PCI230+ card. Configuring a "pci260+" will match a PCI260+ card.
49 Subdevices:
51 PCI230(+) PCI260(+)
52 --------- ---------
53 Subdevices 3 1
54 0 AI AI
55 1 AO
56 2 DIO
58 AI Subdevice:
60 The AI subdevice has 16 single-ended channels or 8 differential
61 channels.
63 The PCI230 and PCI260 cards have 12-bit resolution. The PCI230+ and
64 PCI260+ cards have 16-bit resolution.
66 For differential mode, use inputs 2N and 2N+1 for channel N (e.g. use
67 inputs 14 and 15 for channel 7). If the card is physically a PCI230
68 or PCI260 then it actually uses a "pseudo-differential" mode where the
69 inputs are sampled a few microseconds apart. The PCI230+ and PCI260+
70 use true differential sampling. Another difference is that if the
71 card is physically a PCI230 or PCI260, the inverting input is 2N,
72 whereas for a PCI230+ or PCI260+ the inverting input is 2N+1. So if a
73 PCI230 is physically replaced by a PCI230+ (or a PCI260 with a
74 PCI260+) and differential mode is used, the differential inputs need
75 to be physically swapped on the connector.
77 The following input ranges are supported:
79 0 => [-10, +10] V
80 1 => [-5, +5] V
81 2 => [-2.5, +2.5] V
82 3 => [-1.25, +1.25] V
83 4 => [0, 10] V
84 5 => [0, 5] V
85 6 => [0, 2.5] V
87 AI Commands:
89 +=========+==============+===========+============+==========+
90 |start_src|scan_begin_src|convert_src|scan_end_src| stop_src |
91 +=========+==============+===========+============+==========+
92 |TRIG_NOW | TRIG_FOLLOW |TRIG_TIMER | TRIG_COUNT |TRIG_NONE |
93 |TRIG_INT | |TRIG_EXT(3)| |TRIG_COUNT|
94 | | |TRIG_INT | | |
95 | |--------------|-----------| | |
96 | | TRIG_TIMER(1)|TRIG_TIMER | | |
97 | | TRIG_EXT(2) | | | |
98 | | TRIG_INT | | | |
99 +---------+--------------+-----------+------------+----------+
101 Note 1: If AI command and AO command are used simultaneously, only
102 one may have scan_begin_src == TRIG_TIMER.
104 Note 2: For PCI230 and PCI230+, scan_begin_src == TRIG_EXT uses
105 DIO channel 16 (pin 49) which will need to be configured as
106 a digital input. For PCI260+, the EXTTRIG/EXTCONVCLK input
107 (pin 17) is used instead. For PCI230, scan_begin_src ==
108 TRIG_EXT is not supported. The trigger is a rising edge
109 on the input.
111 Note 3: For convert_src == TRIG_EXT, the EXTTRIG/EXTCONVCLK input
112 (pin 25 on PCI230(+), pin 17 on PCI260(+)) is used. The
113 convert_arg value is interpreted as follows:
115 convert_arg == (CR_EDGE | 0) => rising edge
116 convert_arg == (CR_EDGE | CR_INVERT | 0) => falling edge
117 convert_arg == 0 => falling edge (backwards compatibility)
118 convert_arg == 1 => rising edge (backwards compatibility)
120 All entries in the channel list must use the same analogue reference.
121 If the analogue reference is not AREF_DIFF (not differential) each
122 pair of channel numbers (0 and 1, 2 and 3, etc.) must use the same
123 input range. The input ranges used in the sequence must be all
124 bipolar (ranges 0 to 3) or all unipolar (ranges 4 to 6). The channel
125 sequence must consist of 1 or more identical subsequences. Within the
126 subsequence, channels must be in ascending order with no repeated
127 channels. For example, the following sequences are valid: 0 1 2 3
128 (single valid subsequence), 0 2 3 5 0 2 3 5 (repeated valid
129 subsequence), 1 1 1 1 (repeated valid subsequence). The following
130 sequences are invalid: 0 3 2 1 (invalid subsequence), 0 2 3 5 0 2 3
131 (incompletely repeated subsequence). Some versions of the PCI230+ and
132 PCI260+ have a bug that requires a subsequence longer than one entry
133 long to include channel 0.
135 AO Subdevice:
137 The AO subdevice has 2 channels with 12-bit resolution.
139 The following output ranges are supported:
141 0 => [0, 10] V
142 1 => [-10, +10] V
144 AO Commands:
146 +=========+==============+===========+============+==========+
147 |start_src|scan_begin_src|convert_src|scan_end_src| stop_src |
148 +=========+==============+===========+============+==========+
149 |TRIG_INT | TRIG_TIMER(1)| TRIG_NOW | TRIG_COUNT |TRIG_NONE |
150 | | TRIG_EXT(2) | | |TRIG_COUNT|
151 | | TRIG_INT | | | |
152 +---------+--------------+-----------+------------+----------+
154 Note 1: If AI command and AO command are used simultaneously, only
155 one may have scan_begin_src == TRIG_TIMER.
157 Note 2: scan_begin_src == TRIG_EXT is only supported if the card is
158 configured as a PCI230+ and is only supported on later
159 versions of the card. As a card configured as a PCI230+ is
160 not guaranteed to support external triggering, please consider
161 this support to be a bonus. It uses the EXTTRIG/ EXTCONVCLK
162 input (PCI230+ pin 25). Triggering will be on the rising edge
163 unless the CR_INVERT flag is set in scan_begin_arg.
165 The channels in the channel sequence must be in ascending order with
166 no repeats. All entries in the channel sequence must use the same
167 output range.
169 DIO Subdevice:
171 The DIO subdevice is a 8255 chip providing 24 DIO channels. The DIO
172 channels are configurable as inputs or outputs in four groups:
174 Port A - channels 0 to 7
175 Port B - channels 8 to 15
176 Port CL - channels 16 to 19
177 Port CH - channels 20 to 23
179 Only mode 0 of the 8255 chip is supported.
181 Bit 0 of port C (DIO channel 16) is also used as an external scan
182 trigger input for AI commands on PCI230 and PCI230+, so would need to
183 be configured as an input to use it for that purpose.
186 Extra triggered scan functionality, interrupt bug-fix added by Steve Sharples.
187 Support for PCI230+/260+, more triggered scan functionality, and workarounds
188 for (or detection of) various hardware problems added by Ian Abbott.
191 #include "../comedidev.h"
193 #include <linux/delay.h>
194 #include <linux/interrupt.h>
196 #include "comedi_pci.h"
197 #include "8253.h"
198 #include "8255.h"
200 /* PCI230 PCI configuration register information */
201 #define PCI_VENDOR_ID_AMPLICON 0x14dc
202 #define PCI_DEVICE_ID_PCI230 0x0000
203 #define PCI_DEVICE_ID_PCI260 0x0006
204 #define PCI_DEVICE_ID_INVALID 0xffff
206 #define PCI230_IO1_SIZE 32 /* Size of I/O space 1 */
207 #define PCI230_IO2_SIZE 16 /* Size of I/O space 2 */
209 /* PCI230 i/o space 1 registers. */
210 #define PCI230_PPI_X_BASE 0x00 /* User PPI (82C55) base */
211 #define PCI230_PPI_X_A 0x00 /* User PPI (82C55) port A */
212 #define PCI230_PPI_X_B 0x01 /* User PPI (82C55) port B */
213 #define PCI230_PPI_X_C 0x02 /* User PPI (82C55) port C */
214 #define PCI230_PPI_X_CMD 0x03 /* User PPI (82C55) control word */
215 #define PCI230_Z2_CT_BASE 0x14 /* 82C54 counter/timer base */
216 #define PCI230_Z2_CT0 0x14 /* 82C54 counter/timer 0 */
217 #define PCI230_Z2_CT1 0x15 /* 82C54 counter/timer 1 */
218 #define PCI230_Z2_CT2 0x16 /* 82C54 counter/timer 2 */
219 #define PCI230_Z2_CTC 0x17 /* 82C54 counter/timer control word */
220 #define PCI230_ZCLK_SCE 0x1A /* Group Z Clock Configuration */
221 #define PCI230_ZGAT_SCE 0x1D /* Group Z Gate Configuration */
222 #define PCI230_INT_SCE 0x1E /* Interrupt source mask (w) */
223 #define PCI230_INT_STAT 0x1E /* Interrupt status (r) */
225 /* PCI230 i/o space 2 registers. */
226 #define PCI230_DACCON 0x00 /* DAC control */
227 #define PCI230_DACOUT1 0x02 /* DAC channel 0 (w) */
228 #define PCI230_DACOUT2 0x04 /* DAC channel 1 (w) (not FIFO mode) */
229 #define PCI230_ADCDATA 0x08 /* ADC data (r) */
230 #define PCI230_ADCSWTRIG 0x08 /* ADC software trigger (w) */
231 #define PCI230_ADCCON 0x0A /* ADC control */
232 #define PCI230_ADCEN 0x0C /* ADC channel enable bits */
233 #define PCI230_ADCG 0x0E /* ADC gain control bits */
234 /* PCI230+ i/o space 2 additional registers. */
235 #define PCI230P_ADCTRIG 0x10 /* ADC start acquisition trigger */
236 #define PCI230P_ADCTH 0x12 /* ADC analog trigger threshold */
237 #define PCI230P_ADCFFTH 0x14 /* ADC FIFO interrupt threshold */
238 #define PCI230P_ADCFFLEV 0x16 /* ADC FIFO level (r) */
239 #define PCI230P_ADCPTSC 0x18 /* ADC pre-trigger sample count (r) */
240 #define PCI230P_ADCHYST 0x1A /* ADC analog trigger hysteresys */
241 #define PCI230P_EXTFUNC 0x1C /* Extended functions */
242 #define PCI230P_HWVER 0x1E /* Hardware version (r) */
243 /* PCI230+ hardware version 2 onwards. */
244 #define PCI230P2_DACDATA 0x02 /* DAC data (FIFO mode) (w) */
245 #define PCI230P2_DACSWTRIG 0x02 /* DAC soft trigger (FIFO mode) (r) */
246 #define PCI230P2_DACEN 0x06 /* DAC channel enable (FIFO mode) */
248 /* Convertor related constants. */
249 #define PCI230_DAC_SETTLE 5 /* Analogue output settling time in µs */
250 /* (DAC itself is 1µs nominally). */
251 #define PCI230_ADC_SETTLE 1 /* Analogue input settling time in µs */
252 /* (ADC itself is 1.6µs nominally but we poll
253 * anyway). */
254 #define PCI230_MUX_SETTLE 10 /* ADC MUX settling time in µS */
255 /* - 10µs for se, 20µs de. */
257 /* DACCON read-write values. */
258 #define PCI230_DAC_OR_UNI (0<<0) /* Output range unipolar */
259 #define PCI230_DAC_OR_BIP (1<<0) /* Output range bipolar */
260 #define PCI230_DAC_OR_MASK (1<<0)
261 /* The following applies only if DAC FIFO support is enabled in the EXTFUNC
262 * register (and only for PCI230+ hardware version 2 onwards). */
263 #define PCI230P2_DAC_FIFO_EN (1<<8) /* FIFO enable */
264 /* The following apply only if the DAC FIFO is enabled (and only for PCI230+
265 * hardware version 2 onwards). */
266 #define PCI230P2_DAC_TRIG_NONE (0<<2) /* No trigger */
267 #define PCI230P2_DAC_TRIG_SW (1<<2) /* Software trigger trigger */
268 #define PCI230P2_DAC_TRIG_EXTP (2<<2) /* EXTTRIG +ve edge trigger */
269 #define PCI230P2_DAC_TRIG_EXTN (3<<2) /* EXTTRIG -ve edge trigger */
270 #define PCI230P2_DAC_TRIG_Z2CT0 (4<<2) /* CT0-OUT +ve edge trigger */
271 #define PCI230P2_DAC_TRIG_Z2CT1 (5<<2) /* CT1-OUT +ve edge trigger */
272 #define PCI230P2_DAC_TRIG_Z2CT2 (6<<2) /* CT2-OUT +ve edge trigger */
273 #define PCI230P2_DAC_TRIG_MASK (7<<2)
274 #define PCI230P2_DAC_FIFO_WRAP (1<<7) /* FIFO wraparound mode */
275 #define PCI230P2_DAC_INT_FIFO_EMPTY (0<<9) /* FIFO interrupt empty */
276 #define PCI230P2_DAC_INT_FIFO_NEMPTY (1<<9)
277 #define PCI230P2_DAC_INT_FIFO_NHALF (2<<9) /* FIFO intr not half full */
278 #define PCI230P2_DAC_INT_FIFO_HALF (3<<9)
279 #define PCI230P2_DAC_INT_FIFO_NFULL (4<<9) /* FIFO interrupt not full */
280 #define PCI230P2_DAC_INT_FIFO_FULL (5<<9)
281 #define PCI230P2_DAC_INT_FIFO_MASK (7<<9)
283 /* DACCON read-only values. */
284 #define PCI230_DAC_BUSY (1<<1) /* DAC busy. */
285 /* The following apply only if the DAC FIFO is enabled (and only for PCI230+
286 * hardware version 2 onwards). */
287 #define PCI230P2_DAC_FIFO_UNDERRUN_LATCHED (1<<5) /* Underrun error */
288 #define PCI230P2_DAC_FIFO_EMPTY (1<<13) /* FIFO empty */
289 #define PCI230P2_DAC_FIFO_FULL (1<<14) /* FIFO full */
290 #define PCI230P2_DAC_FIFO_HALF (1<<15) /* FIFO half full */
292 /* DACCON write-only, transient values. */
293 /* The following apply only if the DAC FIFO is enabled (and only for PCI230+
294 * hardware version 2 onwards). */
295 #define PCI230P2_DAC_FIFO_UNDERRUN_CLEAR (1<<5) /* Clear underrun */
296 #define PCI230P2_DAC_FIFO_RESET (1<<12) /* FIFO reset */
298 /* PCI230+ hardware version 2 DAC FIFO levels. */
299 #define PCI230P2_DAC_FIFOLEVEL_HALF 512
300 #define PCI230P2_DAC_FIFOLEVEL_FULL 1024
301 /* Free space in DAC FIFO. */
302 #define PCI230P2_DAC_FIFOROOM_EMPTY PCI230P2_DAC_FIFOLEVEL_FULL
303 #define PCI230P2_DAC_FIFOROOM_ONETOHALF \
304 (PCI230P2_DAC_FIFOLEVEL_FULL - PCI230P2_DAC_FIFOLEVEL_HALF)
305 #define PCI230P2_DAC_FIFOROOM_HALFTOFULL 1
306 #define PCI230P2_DAC_FIFOROOM_FULL 0
308 /* ADCCON read/write values. */
309 #define PCI230_ADC_TRIG_NONE (0<<0) /* No trigger */
310 #define PCI230_ADC_TRIG_SW (1<<0) /* Software trigger trigger */
311 #define PCI230_ADC_TRIG_EXTP (2<<0) /* EXTTRIG +ve edge trigger */
312 #define PCI230_ADC_TRIG_EXTN (3<<0) /* EXTTRIG -ve edge trigger */
313 #define PCI230_ADC_TRIG_Z2CT0 (4<<0) /* CT0-OUT +ve edge trigger */
314 #define PCI230_ADC_TRIG_Z2CT1 (5<<0) /* CT1-OUT +ve edge trigger */
315 #define PCI230_ADC_TRIG_Z2CT2 (6<<0) /* CT2-OUT +ve edge trigger */
316 #define PCI230_ADC_TRIG_MASK (7<<0)
317 #define PCI230_ADC_IR_UNI (0<<3) /* Input range unipolar */
318 #define PCI230_ADC_IR_BIP (1<<3) /* Input range bipolar */
319 #define PCI230_ADC_IR_MASK (1<<3)
320 #define PCI230_ADC_IM_SE (0<<4) /* Input mode single ended */
321 #define PCI230_ADC_IM_DIF (1<<4) /* Input mode differential */
322 #define PCI230_ADC_IM_MASK (1<<4)
323 #define PCI230_ADC_FIFO_EN (1<<8) /* FIFO enable */
324 #define PCI230_ADC_INT_FIFO_EMPTY (0<<9)
325 #define PCI230_ADC_INT_FIFO_NEMPTY (1<<9) /* FIFO interrupt not empty */
326 #define PCI230_ADC_INT_FIFO_NHALF (2<<9)
327 #define PCI230_ADC_INT_FIFO_HALF (3<<9) /* FIFO interrupt half full */
328 #define PCI230_ADC_INT_FIFO_NFULL (4<<9)
329 #define PCI230_ADC_INT_FIFO_FULL (5<<9) /* FIFO interrupt full */
330 #define PCI230P_ADC_INT_FIFO_THRESH (7<<9) /* FIFO interrupt threshold */
331 #define PCI230_ADC_INT_FIFO_MASK (7<<9)
333 /* ADCCON write-only, transient values. */
334 #define PCI230_ADC_FIFO_RESET (1<<12) /* FIFO reset */
335 #define PCI230_ADC_GLOB_RESET (1<<13) /* Global reset */
337 /* ADCCON read-only values. */
338 #define PCI230_ADC_BUSY (1<<15) /* ADC busy */
339 #define PCI230_ADC_FIFO_EMPTY (1<<12) /* FIFO empty */
340 #define PCI230_ADC_FIFO_FULL (1<<13) /* FIFO full */
341 #define PCI230_ADC_FIFO_HALF (1<<14) /* FIFO half full */
342 #define PCI230_ADC_FIFO_FULL_LATCHED (1<<5) /* Indicates overrun occurred */
344 /* PCI230 ADC FIFO levels. */
345 #define PCI230_ADC_FIFOLEVEL_HALFFULL 2049 /* Value for FIFO half full */
346 #define PCI230_ADC_FIFOLEVEL_FULL 4096 /* FIFO size */
348 /* Value to write to ADCSWTRIG to trigger ADC conversion in software trigger
349 * mode. Can be anything. */
350 #define PCI230_ADC_CONV 0xffff
352 /* PCI230+ EXTFUNC values. */
353 #define PCI230P_EXTFUNC_GAT_EXTTRIG (1<<0)
354 /* Route EXTTRIG pin to external gate inputs. */
355 /* PCI230+ hardware version 2 values. */
356 #define PCI230P2_EXTFUNC_DACFIFO (1<<1)
357 /* Allow DAC FIFO to be enabled. */
360 * Counter/timer clock input configuration sources.
362 #define CLK_CLK 0 /* reserved (channel-specific clock) */
363 #define CLK_10MHZ 1 /* internal 10 MHz clock */
364 #define CLK_1MHZ 2 /* internal 1 MHz clock */
365 #define CLK_100KHZ 3 /* internal 100 kHz clock */
366 #define CLK_10KHZ 4 /* internal 10 kHz clock */
367 #define CLK_1KHZ 5 /* internal 1 kHz clock */
368 #define CLK_OUTNM1 6 /* output of channel-1 modulo total */
369 #define CLK_EXT 7 /* external clock */
370 /* Macro to construct clock input configuration register value. */
371 #define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
372 /* Timebases in ns. */
373 #define TIMEBASE_10MHZ 100
374 #define TIMEBASE_1MHZ 1000
375 #define TIMEBASE_100KHZ 10000
376 #define TIMEBASE_10KHZ 100000
377 #define TIMEBASE_1KHZ 1000000
380 * Counter/timer gate input configuration sources.
382 #define GAT_VCC 0 /* VCC (i.e. enabled) */
383 #define GAT_GND 1 /* GND (i.e. disabled) */
384 #define GAT_EXT 2 /* external gate input (PPCn on PCI230) */
385 #define GAT_NOUTNM2 3 /* inverted output of channel-2 modulo total */
386 /* Macro to construct gate input configuration register value. */
387 #define GAT_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
390 * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI230 and PCI260:
392 * Channel's Channel's
393 * clock input gate input
394 * Channel CLK_OUTNM1 GAT_NOUTNM2
395 * ------- ---------- -----------
396 * Z2-CT0 Z2-CT2-OUT /Z2-CT1-OUT
397 * Z2-CT1 Z2-CT0-OUT /Z2-CT2-OUT
398 * Z2-CT2 Z2-CT1-OUT /Z2-CT0-OUT
401 /* Interrupt enables/status register values. */
402 #define PCI230_INT_DISABLE 0
403 #define PCI230_INT_PPI_C0 (1<<0)
404 #define PCI230_INT_PPI_C3 (1<<1)
405 #define PCI230_INT_ADC (1<<2)
406 #define PCI230_INT_ZCLK_CT1 (1<<5)
407 /* For PCI230+ hardware version 2 when DAC FIFO enabled. */
408 #define PCI230P2_INT_DAC (1<<4)
410 #define PCI230_TEST_BIT(val, n) ((val>>n)&1)
411 /* Assumes bits numbered with zero offset, ie. 0-15 */
413 /* (Potentially) shared resources and their owners */
414 enum {
415 RES_Z2CT0, /* Z2-CT0 */
416 RES_Z2CT1, /* Z2-CT1 */
417 RES_Z2CT2, /* Z2-CT2 */
418 NUM_RESOURCES /* Number of (potentially) shared resources. */
421 enum {
422 OWNER_NONE, /* Not owned */
423 OWNER_AICMD, /* Owned by AI command */
424 OWNER_AOCMD /* Owned by AO command */
428 * Handy macros.
431 /* Combine old and new bits. */
432 #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
434 /* A generic null function pointer value. */
435 #define NULLFUNC 0
437 #define THISCPU smp_processor_id()
439 /* State flags for atomic bit operations */
440 #define AI_CMD_STARTED 0
441 #define AO_CMD_STARTED 1
444 * Board descriptions for the two boards supported.
447 struct pci230_board {
448 const char *name;
449 unsigned short id;
450 int ai_chans;
451 int ai_bits;
452 int ao_chans;
453 int ao_bits;
454 int have_dio;
455 unsigned int min_hwver; /* Minimum hardware version supported. */
457 static const struct pci230_board pci230_boards[] = {
459 .name = "pci230+",
460 .id = PCI_DEVICE_ID_PCI230,
461 .ai_chans = 16,
462 .ai_bits = 16,
463 .ao_chans = 2,
464 .ao_bits = 12,
465 .have_dio = 1,
466 .min_hwver = 1,
469 .name = "pci260+",
470 .id = PCI_DEVICE_ID_PCI260,
471 .ai_chans = 16,
472 .ai_bits = 16,
473 .ao_chans = 0,
474 .ao_bits = 0,
475 .have_dio = 0,
476 .min_hwver = 1,
479 .name = "pci230",
480 .id = PCI_DEVICE_ID_PCI230,
481 .ai_chans = 16,
482 .ai_bits = 12,
483 .ao_chans = 2,
484 .ao_bits = 12,
485 .have_dio = 1,
488 .name = "pci260",
489 .id = PCI_DEVICE_ID_PCI260,
490 .ai_chans = 16,
491 .ai_bits = 12,
492 .ao_chans = 0,
493 .ao_bits = 0,
494 .have_dio = 0,
497 .name = "amplc_pci230", /* Wildcard matches any above */
498 .id = PCI_DEVICE_ID_INVALID,
502 static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = {
504 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230, PCI_ANY_ID,
505 PCI_ANY_ID, 0, 0, 0}, {
506 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260, PCI_ANY_ID,
507 PCI_ANY_ID, 0, 0, 0}, {
511 MODULE_DEVICE_TABLE(pci, pci230_pci_table);
513 * Useful for shorthand access to the particular board structure
515 #define n_pci230_boards ARRAY_SIZE(pci230_boards)
516 #define thisboard ((const struct pci230_board *)dev->board_ptr)
518 /* this structure is for data unique to this hardware driver. If
519 several hardware drivers keep similar information in this structure,
520 feel free to suggest moving the variable to the struct comedi_device struct. */
521 struct pci230_private {
522 struct pci_dev *pci_dev;
523 spinlock_t isr_spinlock; /* Interrupt spin lock */
524 spinlock_t res_spinlock; /* Shared resources spin lock */
525 spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */
526 spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */
527 unsigned long state; /* State flags */
528 unsigned long iobase1; /* PCI230's I/O space 1 */
529 unsigned int ao_readback[2]; /* Used for AO readback */
530 unsigned int ai_scan_count; /* Number of analogue input scans
531 * remaining. */
532 unsigned int ai_scan_pos; /* Current position within analogue
533 * input scan */
534 unsigned int ao_scan_count; /* Number of analogue output scans
535 * remaining. */
536 int intr_cpuid; /* ID of CPU running interrupt routine. */
537 unsigned short hwver; /* Hardware version (for '+' models). */
538 unsigned short adccon; /* ADCCON register value. */
539 unsigned short daccon; /* DACCON register value. */
540 unsigned short adcfifothresh; /* ADC FIFO programmable interrupt
541 * level threshold (PCI230+/260+). */
542 unsigned short adcg; /* ADCG register value. */
543 unsigned char int_en; /* Interrupt enables bits. */
544 unsigned char ai_continuous; /* Flag set when cmd->stop_src ==
545 * TRIG_NONE - user chooses to stop
546 * continuous conversion by
547 * cancelation. */
548 unsigned char ao_continuous; /* Flag set when cmd->stop_src ==
549 * TRIG_NONE - user chooses to stop
550 * continuous conversion by
551 * cancelation. */
552 unsigned char ai_bipolar; /* Set if bipolar input range so we
553 * know to mangle it. */
554 unsigned char ao_bipolar; /* Set if bipolar output range so we
555 * know to mangle it. */
556 unsigned char ier; /* Copy of interrupt enables/status register. */
557 unsigned char intr_running; /* Flag set in interrupt routine. */
558 unsigned char res_owner[NUM_RESOURCES]; /* Shared resource owners. */
561 #define devpriv ((struct pci230_private *)dev->private)
563 /* PCI230 clock source periods in ns */
564 static const unsigned int pci230_timebase[8] = {
565 [CLK_10MHZ] = TIMEBASE_10MHZ,
566 [CLK_1MHZ] = TIMEBASE_1MHZ,
567 [CLK_100KHZ] = TIMEBASE_100KHZ,
568 [CLK_10KHZ] = TIMEBASE_10KHZ,
569 [CLK_1KHZ] = TIMEBASE_1KHZ,
572 /* PCI230 analogue input range table */
573 static const struct comedi_lrange pci230_ai_range = { 7, {
574 BIP_RANGE(10),
575 BIP_RANGE(5),
576 BIP_RANGE(2.5),
577 BIP_RANGE(1.25),
578 UNI_RANGE(10),
579 UNI_RANGE(5),
580 UNI_RANGE(2.5)
584 /* PCI230 analogue gain bits for each input range. */
585 static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 };
587 /* PCI230 adccon bipolar flag for each analogue input range. */
588 static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 };
590 /* PCI230 analogue output range table */
591 static const struct comedi_lrange pci230_ao_range = { 2, {
592 UNI_RANGE(10),
593 BIP_RANGE(10)
597 /* PCI230 daccon bipolar flag for each analogue output range. */
598 static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
601 * The struct comedi_driver structure tells the Comedi core module
602 * which functions to call to configure/deconfigure (attach/detach)
603 * the board, and also about the kernel module that contains
604 * the device code.
606 static int pci230_attach(struct comedi_device *dev,
607 struct comedi_devconfig *it);
608 static int pci230_detach(struct comedi_device *dev);
609 static struct comedi_driver driver_amplc_pci230 = {
610 .driver_name = "amplc_pci230",
611 .module = THIS_MODULE,
612 .attach = pci230_attach,
613 .detach = pci230_detach,
614 .board_name = &pci230_boards[0].name,
615 .offset = sizeof(pci230_boards[0]),
616 .num_names = ARRAY_SIZE(pci230_boards),
619 static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev,
620 const struct pci_device_id
621 *ent)
623 return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name);
626 static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev)
628 comedi_pci_auto_unconfig(dev);
631 static struct pci_driver driver_amplc_pci230_pci_driver = {
632 .id_table = pci230_pci_table,
633 .probe = &driver_amplc_pci230_pci_probe,
634 .remove = __devexit_p(&driver_amplc_pci230_pci_remove)
637 static int __init driver_amplc_pci230_init_module(void)
639 int retval;
641 retval = comedi_driver_register(&driver_amplc_pci230);
642 if (retval < 0)
643 return retval;
645 driver_amplc_pci230_pci_driver.name =
646 (char *)driver_amplc_pci230.driver_name;
647 return pci_register_driver(&driver_amplc_pci230_pci_driver);
650 static void __exit driver_amplc_pci230_cleanup_module(void)
652 pci_unregister_driver(&driver_amplc_pci230_pci_driver);
653 comedi_driver_unregister(&driver_amplc_pci230);
656 module_init(driver_amplc_pci230_init_module);
657 module_exit(driver_amplc_pci230_cleanup_module);
659 static int pci230_ai_rinsn(struct comedi_device *dev,
660 struct comedi_subdevice *s, struct comedi_insn *insn,
661 unsigned int *data);
662 static int pci230_ao_winsn(struct comedi_device *dev,
663 struct comedi_subdevice *s, struct comedi_insn *insn,
664 unsigned int *data);
665 static int pci230_ao_rinsn(struct comedi_device *dev,
666 struct comedi_subdevice *s, struct comedi_insn *insn,
667 unsigned int *data);
668 static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
669 unsigned int mode, uint64_t ns,
670 unsigned int round);
671 static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round);
672 static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct);
673 static irqreturn_t pci230_interrupt(int irq, void *d);
674 static int pci230_ao_cmdtest(struct comedi_device *dev,
675 struct comedi_subdevice *s,
676 struct comedi_cmd *cmd);
677 static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
678 static int pci230_ao_cancel(struct comedi_device *dev,
679 struct comedi_subdevice *s);
680 static void pci230_ao_stop(struct comedi_device *dev,
681 struct comedi_subdevice *s);
682 static void pci230_handle_ao_nofifo(struct comedi_device *dev,
683 struct comedi_subdevice *s);
684 static int pci230_handle_ao_fifo(struct comedi_device *dev,
685 struct comedi_subdevice *s);
686 static int pci230_ai_cmdtest(struct comedi_device *dev,
687 struct comedi_subdevice *s,
688 struct comedi_cmd *cmd);
689 static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
690 static int pci230_ai_cancel(struct comedi_device *dev,
691 struct comedi_subdevice *s);
692 static void pci230_ai_stop(struct comedi_device *dev,
693 struct comedi_subdevice *s);
694 static void pci230_handle_ai(struct comedi_device *dev,
695 struct comedi_subdevice *s);
697 static short pci230_ai_read(struct comedi_device *dev)
699 /* Read sample. */
700 short data = (short)inw(dev->iobase + PCI230_ADCDATA);
702 /* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
703 * four bits reserved for expansion). */
704 /* PCI230+ is 16 bit AI. */
705 data = data >> (16 - thisboard->ai_bits);
707 /* If a bipolar range was specified, mangle it (twos
708 * complement->straight binary). */
709 if (devpriv->ai_bipolar)
710 data ^= 1 << (thisboard->ai_bits - 1);
712 return data;
715 static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
716 short datum)
718 /* If a bipolar range was specified, mangle it (straight binary->twos
719 * complement). */
720 if (devpriv->ao_bipolar)
721 datum ^= 1 << (thisboard->ao_bits - 1);
724 /* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
725 * four bits reserved for expansion). */
726 /* PCI230+ is also 12 bit AO. */
727 datum <<= (16 - thisboard->ao_bits);
728 return (unsigned short)datum;
731 static inline void pci230_ao_write_nofifo(struct comedi_device *dev,
732 short datum, unsigned int chan)
734 /* Store unmangled datum to be read back later. */
735 devpriv->ao_readback[chan] = datum;
737 /* Write mangled datum to appropriate DACOUT register. */
738 outw(pci230_ao_mangle_datum(dev, datum), dev->iobase + (((chan) == 0)
739 ? PCI230_DACOUT1
741 PCI230_DACOUT2));
744 static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum,
745 unsigned int chan)
747 /* Store unmangled datum to be read back later. */
748 devpriv->ao_readback[chan] = datum;
750 /* Write mangled datum to appropriate DACDATA register. */
751 outw(pci230_ao_mangle_datum(dev, datum),
752 dev->iobase + PCI230P2_DACDATA);
756 * Attach is called by the Comedi core to configure the driver
757 * for a particular board. If you specified a board_name array
758 * in the driver structure, dev->board_ptr contains that
759 * address.
761 static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
763 struct comedi_subdevice *s;
764 unsigned long iobase1, iobase2;
765 /* PCI230's I/O spaces 1 and 2 respectively. */
766 struct pci_dev *pci_dev = NULL;
767 int i = 0, irq_hdl, rc;
769 printk("comedi%d: amplc_pci230: attach %s %d,%d\n", dev->minor,
770 thisboard->name, it->options[0], it->options[1]);
772 /* Allocate the private structure area using alloc_private().
773 * Macro defined in comedidev.h - memsets struct fields to 0. */
774 if ((alloc_private(dev, sizeof(struct pci230_private))) < 0)
775 return -ENOMEM;
777 spin_lock_init(&devpriv->isr_spinlock);
778 spin_lock_init(&devpriv->res_spinlock);
779 spin_lock_init(&devpriv->ai_stop_spinlock);
780 spin_lock_init(&devpriv->ao_stop_spinlock);
781 /* Find card */
782 for_each_pci_dev(pci_dev) {
783 if (it->options[0] || it->options[1]) {
784 /* Match against bus/slot options. */
785 if (it->options[0] != pci_dev->bus->number ||
786 it->options[1] != PCI_SLOT(pci_dev->devfn))
787 continue;
789 if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
790 continue;
791 if (thisboard->id == PCI_DEVICE_ID_INVALID) {
792 /* The name was specified as "amplc_pci230" which is
793 * used to match any supported device. Replace the
794 * current dev->board_ptr with one that matches the
795 * PCI device ID. */
796 for (i = 0; i < n_pci230_boards; i++) {
797 if (pci_dev->device == pci230_boards[i].id) {
798 if (pci230_boards[i].min_hwver > 0) {
799 /* Check for a '+' model.
800 * First check length of
801 * registers. */
802 if (pci_resource_len(pci_dev, 3)
803 < 32) {
804 /* Not a '+' model. */
805 continue;
807 /* TODO: temporarily enable the
808 * PCI device and read the
809 * hardware version register.
810 * For now assume it's okay. */
812 /* Change board_ptr to matched board */
813 dev->board_ptr = &pci230_boards[i];
814 break;
817 if (i < n_pci230_boards)
818 break;
819 } else {
820 /* The name was specified as a specific device name.
821 * The current dev->board_ptr is correct. Check
822 * whether it matches the PCI device ID. */
823 if (thisboard->id == pci_dev->device) {
824 /* Check minimum hardware version. */
825 if (thisboard->min_hwver > 0) {
826 /* Looking for a '+' model. First
827 * check length of registers. */
828 if (pci_resource_len(pci_dev, 3) < 32) {
829 /* Not a '+' model. */
830 continue;
832 /* TODO: temporarily enable the PCI
833 * device and read the hardware version
834 * register. For now, assume it's
835 * okay. */
836 break;
837 } else {
838 break;
843 if (!pci_dev) {
844 printk("comedi%d: No %s card found\n", dev->minor,
845 thisboard->name);
846 return -EIO;
848 devpriv->pci_dev = pci_dev;
851 * Initialize dev->board_name.
853 dev->board_name = thisboard->name;
855 /* Enable PCI device and reserve I/O spaces. */
856 if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) {
857 printk("comedi%d: failed to enable PCI device "
858 "and request regions\n", dev->minor);
859 return -EIO;
862 /* Read base addresses of the PCI230's two I/O regions from PCI
863 * configuration register. */
864 iobase1 = pci_resource_start(pci_dev, 2);
865 iobase2 = pci_resource_start(pci_dev, 3);
867 printk("comedi%d: %s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
868 dev->minor, dev->board_name, iobase1, iobase2);
870 devpriv->iobase1 = iobase1;
871 dev->iobase = iobase2;
873 /* Read bits of DACCON register - only the output range. */
874 devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK;
876 /* Read hardware version register and set extended function register
877 * if they exist. */
878 if (pci_resource_len(pci_dev, 3) >= 32) {
879 unsigned short extfunc = 0;
881 devpriv->hwver = inw(dev->iobase + PCI230P_HWVER);
882 if (devpriv->hwver < thisboard->min_hwver) {
883 printk("comedi%d: %s - bad hardware version "
884 "- got %u, need %u\n", dev->minor,
885 dev->board_name, devpriv->hwver,
886 thisboard->min_hwver);
887 return -EIO;
889 if (devpriv->hwver > 0) {
890 if (!thisboard->have_dio) {
891 /* No DIO ports. Route counters' external gates
892 * to the EXTTRIG signal (PCI260+ pin 17).
893 * (Otherwise, they would be routed to DIO
894 * inputs PC0, PC1 and PC2 which don't exist
895 * on PCI260[+].) */
896 extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
898 if ((thisboard->ao_chans > 0)
899 && (devpriv->hwver >= 2)) {
900 /* Enable DAC FIFO functionality. */
901 extfunc |= PCI230P2_EXTFUNC_DACFIFO;
904 outw(extfunc, dev->iobase + PCI230P_EXTFUNC);
905 if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) {
906 /* Temporarily enable DAC FIFO, reset it and disable
907 * FIFO wraparound. */
908 outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN
909 | PCI230P2_DAC_FIFO_RESET,
910 dev->iobase + PCI230_DACCON);
911 /* Clear DAC FIFO channel enable register. */
912 outw(0, dev->iobase + PCI230P2_DACEN);
913 /* Disable DAC FIFO. */
914 outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
918 /* Disable board's interrupts. */
919 outb(0, devpriv->iobase1 + PCI230_INT_SCE);
921 /* Set ADC to a reasonable state. */
922 devpriv->adcg = 0;
923 devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE
924 | PCI230_ADC_IR_BIP;
925 outw(1 << 0, dev->iobase + PCI230_ADCEN);
926 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
927 outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
928 dev->iobase + PCI230_ADCCON);
930 /* Register the interrupt handler. */
931 irq_hdl = request_irq(devpriv->pci_dev->irq, pci230_interrupt,
932 IRQF_SHARED, "amplc_pci230", dev);
933 if (irq_hdl < 0) {
934 printk("comedi%d: unable to register irq, "
935 "commands will not be available %d\n", dev->minor,
936 devpriv->pci_dev->irq);
937 } else {
938 dev->irq = devpriv->pci_dev->irq;
939 printk("comedi%d: registered irq %u\n", dev->minor,
940 devpriv->pci_dev->irq);
944 * Allocate the subdevice structures. alloc_subdevice() is a
945 * convenient macro defined in comedidev.h.
947 if (alloc_subdevices(dev, 3) < 0)
948 return -ENOMEM;
950 s = dev->subdevices + 0;
951 /* analog input subdevice */
952 s->type = COMEDI_SUBD_AI;
953 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
954 s->n_chan = thisboard->ai_chans;
955 s->maxdata = (1 << thisboard->ai_bits) - 1;
956 s->range_table = &pci230_ai_range;
957 s->insn_read = &pci230_ai_rinsn;
958 s->len_chanlist = 256; /* but there are restrictions. */
959 /* Only register commands if the interrupt handler is installed. */
960 if (irq_hdl == 0) {
961 dev->read_subdev = s;
962 s->subdev_flags |= SDF_CMD_READ;
963 s->do_cmd = &pci230_ai_cmd;
964 s->do_cmdtest = &pci230_ai_cmdtest;
965 s->cancel = pci230_ai_cancel;
968 s = dev->subdevices + 1;
969 /* analog output subdevice */
970 if (thisboard->ao_chans > 0) {
971 s->type = COMEDI_SUBD_AO;
972 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
973 s->n_chan = thisboard->ao_chans;;
974 s->maxdata = (1 << thisboard->ao_bits) - 1;
975 s->range_table = &pci230_ao_range;
976 s->insn_write = &pci230_ao_winsn;
977 s->insn_read = &pci230_ao_rinsn;
978 s->len_chanlist = thisboard->ao_chans;
979 /* Only register commands if the interrupt handler is
980 * installed. */
981 if (irq_hdl == 0) {
982 dev->write_subdev = s;
983 s->subdev_flags |= SDF_CMD_WRITE;
984 s->do_cmd = &pci230_ao_cmd;
985 s->do_cmdtest = &pci230_ao_cmdtest;
986 s->cancel = pci230_ao_cancel;
988 } else {
989 s->type = COMEDI_SUBD_UNUSED;
992 s = dev->subdevices + 2;
993 /* digital i/o subdevice */
994 if (thisboard->have_dio) {
995 rc = subdev_8255_init(dev, s, NULL,
996 (devpriv->iobase1 + PCI230_PPI_X_BASE));
997 if (rc < 0)
998 return rc;
999 } else {
1000 s->type = COMEDI_SUBD_UNUSED;
1003 printk("comedi%d: attached\n", dev->minor);
1005 return 1;
1009 * _detach is called to deconfigure a device. It should deallocate
1010 * resources.
1011 * This function is also called when _attach() fails, so it should be
1012 * careful not to release resources that were not necessarily
1013 * allocated by _attach(). dev->private and dev->subdevices are
1014 * deallocated automatically by the core.
1016 static int pci230_detach(struct comedi_device *dev)
1018 printk("comedi%d: amplc_pci230: remove\n", dev->minor);
1020 if (dev->subdevices && thisboard->have_dio)
1021 /* Clean up dio subdevice. */
1022 subdev_8255_cleanup(dev, dev->subdevices + 2);
1024 if (dev->irq)
1025 free_irq(dev->irq, dev);
1027 if (devpriv) {
1028 if (devpriv->pci_dev) {
1029 if (dev->iobase)
1030 comedi_pci_disable(devpriv->pci_dev);
1032 pci_dev_put(devpriv->pci_dev);
1036 return 0;
1039 static int get_resources(struct comedi_device *dev, unsigned int res_mask,
1040 unsigned char owner)
1042 int ok;
1043 unsigned int i;
1044 unsigned int b;
1045 unsigned int claimed;
1046 unsigned long irqflags;
1048 ok = 1;
1049 claimed = 0;
1050 spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
1051 for (b = 1, i = 0; (i < NUM_RESOURCES)
1052 && (res_mask != 0); b <<= 1, i++) {
1053 if ((res_mask & b) != 0) {
1054 res_mask &= ~b;
1055 if (devpriv->res_owner[i] == OWNER_NONE) {
1056 devpriv->res_owner[i] = owner;
1057 claimed |= b;
1058 } else if (devpriv->res_owner[i] != owner) {
1059 for (b = 1, i = 0; claimed != 0; b <<= 1, i++) {
1060 if ((claimed & b) != 0) {
1061 devpriv->res_owner[i]
1062 = OWNER_NONE;
1063 claimed &= ~b;
1066 ok = 0;
1067 break;
1071 spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
1072 return ok;
1075 static inline int get_one_resource(struct comedi_device *dev,
1076 unsigned int resource, unsigned char owner)
1078 return get_resources(dev, (1U << resource), owner);
1081 static void put_resources(struct comedi_device *dev, unsigned int res_mask,
1082 unsigned char owner)
1084 unsigned int i;
1085 unsigned int b;
1086 unsigned long irqflags;
1088 spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
1089 for (b = 1, i = 0; (i < NUM_RESOURCES)
1090 && (res_mask != 0); b <<= 1, i++) {
1091 if ((res_mask & b) != 0) {
1092 res_mask &= ~b;
1093 if (devpriv->res_owner[i] == owner)
1094 devpriv->res_owner[i] = OWNER_NONE;
1098 spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
1101 static inline void put_one_resource(struct comedi_device *dev,
1102 unsigned int resource, unsigned char owner)
1104 put_resources(dev, (1U << resource), owner);
1107 static inline void put_all_resources(struct comedi_device *dev,
1108 unsigned char owner)
1110 put_resources(dev, (1U << NUM_RESOURCES) - 1, owner);
1114 * COMEDI_SUBD_AI instruction;
1116 static int pci230_ai_rinsn(struct comedi_device *dev,
1117 struct comedi_subdevice *s, struct comedi_insn *insn,
1118 unsigned int *data)
1120 unsigned int n, i;
1121 unsigned int chan, range, aref;
1122 unsigned int gainshift;
1123 unsigned int status;
1124 unsigned short adccon, adcen;
1126 /* Unpack channel and range. */
1127 chan = CR_CHAN(insn->chanspec);
1128 range = CR_RANGE(insn->chanspec);
1129 aref = CR_AREF(insn->chanspec);
1130 if (aref == AREF_DIFF) {
1131 /* Differential. */
1132 if (chan >= s->n_chan / 2) {
1133 DPRINTK("comedi%d: amplc_pci230: ai_rinsn: "
1134 "differential channel number out of range "
1135 "0 to %u\n", dev->minor, (s->n_chan / 2) - 1);
1136 return -EINVAL;
1140 /* Use Z2-CT2 as a conversion trigger instead of the built-in
1141 * software trigger, as otherwise triggering of differential channels
1142 * doesn't work properly for some versions of PCI230/260. Also set
1143 * FIFO mode because the ADC busy bit only works for software triggers.
1145 adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
1146 /* Set Z2-CT2 output low to avoid any false triggers. */
1147 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
1148 devpriv->ai_bipolar = pci230_ai_bipolar[range];
1149 if (aref == AREF_DIFF) {
1150 /* Differential. */
1151 gainshift = chan * 2;
1152 if (devpriv->hwver == 0) {
1153 /* Original PCI230/260 expects both inputs of the
1154 * differential channel to be enabled. */
1155 adcen = 3 << gainshift;
1156 } else {
1157 /* PCI230+/260+ expects only one input of the
1158 * differential channel to be enabled. */
1159 adcen = 1 << gainshift;
1161 adccon |= PCI230_ADC_IM_DIF;
1162 } else {
1163 /* Single ended. */
1164 adcen = 1 << chan;
1165 gainshift = chan & ~1;
1166 adccon |= PCI230_ADC_IM_SE;
1168 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift))
1169 | (pci230_ai_gain[range] << gainshift);
1170 if (devpriv->ai_bipolar)
1171 adccon |= PCI230_ADC_IR_BIP;
1172 else
1173 adccon |= PCI230_ADC_IR_UNI;
1176 /* Enable only this channel in the scan list - otherwise by default
1177 * we'll get one sample from each channel. */
1178 outw(adcen, dev->iobase + PCI230_ADCEN);
1180 /* Set gain for channel. */
1181 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
1183 /* Specify uni/bip, se/diff, conversion source, and reset FIFO. */
1184 devpriv->adccon = adccon;
1185 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
1187 /* Convert n samples */
1188 for (n = 0; n < insn->n; n++) {
1189 /* Trigger conversion by toggling Z2-CT2 output (finish with
1190 * output high). */
1191 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
1192 I8254_MODE0);
1193 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
1194 I8254_MODE1);
1196 #define TIMEOUT 100
1197 /* wait for conversion to end */
1198 for (i = 0; i < TIMEOUT; i++) {
1199 status = inw(dev->iobase + PCI230_ADCCON);
1200 if (!(status & PCI230_ADC_FIFO_EMPTY))
1201 break;
1202 udelay(1);
1204 if (i == TIMEOUT) {
1205 /* printk() should be used instead of printk()
1206 * whenever the code can be called from real-time. */
1207 printk("timeout\n");
1208 return -ETIMEDOUT;
1211 /* read data */
1212 data[n] = pci230_ai_read(dev);
1215 /* return the number of samples read/written */
1216 return n;
1220 * COMEDI_SUBD_AO instructions;
1222 static int pci230_ao_winsn(struct comedi_device *dev,
1223 struct comedi_subdevice *s, struct comedi_insn *insn,
1224 unsigned int *data)
1226 int i;
1227 int chan, range;
1229 /* Unpack channel and range. */
1230 chan = CR_CHAN(insn->chanspec);
1231 range = CR_RANGE(insn->chanspec);
1233 /* Set range - see analogue output range table; 0 => unipolar 10V,
1234 * 1 => bipolar +/-10V range scale */
1235 devpriv->ao_bipolar = pci230_ao_bipolar[range];
1236 outw(range, dev->iobase + PCI230_DACCON);
1238 /* Writing a list of values to an AO channel is probably not
1239 * very useful, but that's how the interface is defined. */
1240 for (i = 0; i < insn->n; i++) {
1241 /* Write value to DAC and store it. */
1242 pci230_ao_write_nofifo(dev, data[i], chan);
1245 /* return the number of samples read/written */
1246 return i;
1249 /* AO subdevices should have a read insn as well as a write insn.
1250 * Usually this means copying a value stored in devpriv. */
1251 static int pci230_ao_rinsn(struct comedi_device *dev,
1252 struct comedi_subdevice *s, struct comedi_insn *insn,
1253 unsigned int *data)
1255 int i;
1256 int chan = CR_CHAN(insn->chanspec);
1258 for (i = 0; i < insn->n; i++)
1259 data[i] = devpriv->ao_readback[chan];
1261 return i;
1264 static int pci230_ao_cmdtest(struct comedi_device *dev,
1265 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1267 int err = 0;
1268 unsigned int tmp;
1270 /* cmdtest tests a particular command to see if it is valid.
1271 * Using the cmdtest ioctl, a user can create a valid cmd
1272 * and then have it executes by the cmd ioctl.
1274 * cmdtest returns 1,2,3,4 or 0, depending on which tests
1275 * the command passes. */
1277 /* Step 1: make sure trigger sources are trivially valid.
1278 * "invalid source" returned by comedilib to user mode process
1279 * if this fails. */
1281 tmp = cmd->start_src;
1282 cmd->start_src &= TRIG_INT;
1283 if (!cmd->start_src || tmp != cmd->start_src)
1284 err++;
1286 tmp = cmd->scan_begin_src;
1287 if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) {
1288 cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT;
1289 } else {
1290 cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT;
1292 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1293 err++;
1295 tmp = cmd->convert_src;
1296 cmd->convert_src &= TRIG_NOW;
1297 if (!cmd->convert_src || tmp != cmd->convert_src)
1298 err++;
1300 tmp = cmd->scan_end_src;
1301 cmd->scan_end_src &= TRIG_COUNT;
1302 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1303 err++;
1305 tmp = cmd->stop_src;
1306 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1307 if (!cmd->stop_src || tmp != cmd->stop_src)
1308 err++;
1310 if (err)
1311 return 1;
1313 /* Step 2: make sure trigger sources are unique and mutually compatible
1314 * "source conflict" returned by comedilib to user mode process
1315 * if this fails. */
1317 /* these tests are true if more than one _src bit is set */
1318 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1319 err++;
1320 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1321 err++;
1322 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1323 err++;
1324 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1325 err++;
1326 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1327 err++;
1329 if (err)
1330 return 2;
1332 /* Step 3: make sure arguments are trivially compatible.
1333 * "invalid argument" returned by comedilib to user mode process
1334 * if this fails. */
1336 if (cmd->start_arg != 0) {
1337 cmd->start_arg = 0;
1338 err++;
1340 #define MAX_SPEED_AO 8000 /* 8000 ns => 125 kHz */
1341 #define MIN_SPEED_AO 4294967295u /* 4294967295ns = 4.29s */
1342 /*- Comedi limit due to unsigned int cmd. Driver limit
1343 * = 2^16 (16bit * counter) * 1000000ns (1kHz onboard
1344 * clock) = 65.536s */
1346 switch (cmd->scan_begin_src) {
1347 case TRIG_TIMER:
1348 if (cmd->scan_begin_arg < MAX_SPEED_AO) {
1349 cmd->scan_begin_arg = MAX_SPEED_AO;
1350 err++;
1352 if (cmd->scan_begin_arg > MIN_SPEED_AO) {
1353 cmd->scan_begin_arg = MIN_SPEED_AO;
1354 err++;
1356 break;
1357 case TRIG_EXT:
1358 /* External trigger - for PCI230+ hardware version 2 onwards. */
1359 /* Trigger number must be 0. */
1360 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
1361 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1362 ~CR_FLAGS_MASK);
1363 err++;
1365 /* The only flags allowed are CR_EDGE and CR_INVERT. The
1366 * CR_EDGE flag is ignored. */
1367 if ((cmd->scan_begin_arg
1368 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
1369 cmd->scan_begin_arg =
1370 COMBINE(cmd->scan_begin_arg, 0,
1371 CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
1372 err++;
1374 break;
1375 default:
1376 if (cmd->scan_begin_arg != 0) {
1377 cmd->scan_begin_arg = 0;
1378 err++;
1380 break;
1383 if (cmd->scan_end_arg != cmd->chanlist_len) {
1384 cmd->scan_end_arg = cmd->chanlist_len;
1385 err++;
1387 if (cmd->stop_src == TRIG_NONE) {
1388 /* TRIG_NONE */
1389 if (cmd->stop_arg != 0) {
1390 cmd->stop_arg = 0;
1391 err++;
1395 if (err)
1396 return 3;
1398 /* Step 4: fix up any arguments.
1399 * "argument conflict" returned by comedilib to user mode process
1400 * if this fails. */
1402 if (cmd->scan_begin_src == TRIG_TIMER) {
1403 tmp = cmd->scan_begin_arg;
1404 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1405 cmd->flags & TRIG_ROUND_MASK);
1406 if (tmp != cmd->scan_begin_arg)
1407 err++;
1410 if (err)
1411 return 4;
1413 /* Step 5: check channel list if it exists. */
1415 if (cmd->chanlist && cmd->chanlist_len > 0) {
1416 enum {
1417 seq_err = (1 << 0),
1418 range_err = (1 << 1)
1420 unsigned int errors;
1421 unsigned int n;
1422 unsigned int chan, prev_chan;
1423 unsigned int range, first_range;
1425 prev_chan = CR_CHAN(cmd->chanlist[0]);
1426 first_range = CR_RANGE(cmd->chanlist[0]);
1427 errors = 0;
1428 for (n = 1; n < cmd->chanlist_len; n++) {
1429 chan = CR_CHAN(cmd->chanlist[n]);
1430 range = CR_RANGE(cmd->chanlist[n]);
1431 /* Channel numbers must strictly increase. */
1432 if (chan < prev_chan)
1433 errors |= seq_err;
1435 /* Ranges must be the same. */
1436 if (range != first_range)
1437 errors |= range_err;
1439 prev_chan = chan;
1441 if (errors != 0) {
1442 err++;
1443 if ((errors & seq_err) != 0) {
1444 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1445 "channel numbers must increase\n",
1446 dev->minor);
1448 if ((errors & range_err) != 0) {
1449 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1450 "channels must have the same range\n",
1451 dev->minor);
1456 if (err)
1457 return 5;
1459 return 0;
1462 static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
1463 struct comedi_subdevice *s,
1464 unsigned int trig_num)
1466 unsigned long irqflags;
1468 if (trig_num != 0)
1469 return -EINVAL;
1471 spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
1472 if (test_bit(AO_CMD_STARTED, &devpriv->state)) {
1473 /* Perform scan. */
1474 if (devpriv->hwver < 2) {
1475 /* Not using DAC FIFO. */
1476 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
1477 irqflags);
1478 pci230_handle_ao_nofifo(dev, s);
1479 comedi_event(dev, s);
1480 } else {
1481 /* Using DAC FIFO. */
1482 /* Read DACSWTRIG register to trigger conversion. */
1483 inw(dev->iobase + PCI230P2_DACSWTRIG);
1484 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
1485 irqflags);
1487 /* Delay. Should driver be responsible for this? */
1488 udelay(8);
1491 return 1;
1494 static void pci230_ao_start(struct comedi_device *dev,
1495 struct comedi_subdevice *s)
1497 struct comedi_async *async = s->async;
1498 struct comedi_cmd *cmd = &async->cmd;
1499 unsigned long irqflags;
1501 set_bit(AO_CMD_STARTED, &devpriv->state);
1502 if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
1503 /* An empty acquisition! */
1504 async->events |= COMEDI_CB_EOA;
1505 pci230_ao_stop(dev, s);
1506 comedi_event(dev, s);
1507 } else {
1508 if (devpriv->hwver >= 2) {
1509 /* Using DAC FIFO. */
1510 unsigned short scantrig;
1511 int run;
1513 /* Preload FIFO data. */
1514 run = pci230_handle_ao_fifo(dev, s);
1515 comedi_event(dev, s);
1516 if (!run) {
1517 /* Stopped. */
1518 return;
1520 /* Set scan trigger source. */
1521 switch (cmd->scan_begin_src) {
1522 case TRIG_TIMER:
1523 scantrig = PCI230P2_DAC_TRIG_Z2CT1;
1524 break;
1525 case TRIG_EXT:
1526 /* Trigger on EXTTRIG/EXTCONVCLK pin. */
1527 if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
1528 /* +ve edge */
1529 scantrig = PCI230P2_DAC_TRIG_EXTP;
1530 } else {
1531 /* -ve edge */
1532 scantrig = PCI230P2_DAC_TRIG_EXTN;
1534 break;
1535 case TRIG_INT:
1536 scantrig = PCI230P2_DAC_TRIG_SW;
1537 break;
1538 default:
1539 /* Shouldn't get here. */
1540 scantrig = PCI230P2_DAC_TRIG_NONE;
1541 break;
1543 devpriv->daccon = (devpriv->daccon
1544 & ~PCI230P2_DAC_TRIG_MASK) |
1545 scantrig;
1546 outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
1549 switch (cmd->scan_begin_src) {
1550 case TRIG_TIMER:
1551 if (devpriv->hwver < 2) {
1552 /* Not using DAC FIFO. */
1553 /* Enable CT1 timer interrupt. */
1554 spin_lock_irqsave(&devpriv->isr_spinlock,
1555 irqflags);
1556 devpriv->int_en |= PCI230_INT_ZCLK_CT1;
1557 devpriv->ier |= PCI230_INT_ZCLK_CT1;
1558 outb(devpriv->ier,
1559 devpriv->iobase1 + PCI230_INT_SCE);
1560 spin_unlock_irqrestore(&devpriv->isr_spinlock,
1561 irqflags);
1563 /* Set CT1 gate high to start counting. */
1564 outb(GAT_CONFIG(1, GAT_VCC),
1565 devpriv->iobase1 + PCI230_ZGAT_SCE);
1566 break;
1567 case TRIG_INT:
1568 async->inttrig = pci230_ao_inttrig_scan_begin;
1569 break;
1571 if (devpriv->hwver >= 2) {
1572 /* Using DAC FIFO. Enable DAC FIFO interrupt. */
1573 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1574 devpriv->int_en |= PCI230P2_INT_DAC;
1575 devpriv->ier |= PCI230P2_INT_DAC;
1576 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
1577 spin_unlock_irqrestore(&devpriv->isr_spinlock,
1578 irqflags);
1583 static int pci230_ao_inttrig_start(struct comedi_device *dev,
1584 struct comedi_subdevice *s,
1585 unsigned int trig_num)
1587 if (trig_num != 0)
1588 return -EINVAL;
1590 s->async->inttrig = NULLFUNC;
1591 pci230_ao_start(dev, s);
1593 return 1;
1596 static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1598 unsigned short daccon;
1599 unsigned int range;
1601 /* Get the command. */
1602 struct comedi_cmd *cmd = &s->async->cmd;
1604 if (cmd->scan_begin_src == TRIG_TIMER) {
1605 /* Claim Z2-CT1. */
1606 if (!get_one_resource(dev, RES_Z2CT1, OWNER_AOCMD))
1607 return -EBUSY;
1611 /* Get number of scans required. */
1612 if (cmd->stop_src == TRIG_COUNT) {
1613 devpriv->ao_scan_count = cmd->stop_arg;
1614 devpriv->ao_continuous = 0;
1615 } else {
1616 /* TRIG_NONE, user calls cancel. */
1617 devpriv->ao_scan_count = 0;
1618 devpriv->ao_continuous = 1;
1621 /* Set range - see analogue output range table; 0 => unipolar 10V,
1622 * 1 => bipolar +/-10V range scale */
1623 range = CR_RANGE(cmd->chanlist[0]);
1624 devpriv->ao_bipolar = pci230_ao_bipolar[range];
1625 daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI;
1626 /* Use DAC FIFO for hardware version 2 onwards. */
1627 if (devpriv->hwver >= 2) {
1628 unsigned short dacen;
1629 unsigned int i;
1631 dacen = 0;
1632 for (i = 0; i < cmd->chanlist_len; i++)
1633 dacen |= 1 << CR_CHAN(cmd->chanlist[i]);
1635 /* Set channel scan list. */
1636 outw(dacen, dev->iobase + PCI230P2_DACEN);
1638 * Enable DAC FIFO.
1639 * Set DAC scan source to 'none'.
1640 * Set DAC FIFO interrupt trigger level to 'not half full'.
1641 * Reset DAC FIFO and clear underrun.
1643 * N.B. DAC FIFO interrupts are currently disabled.
1645 daccon |= PCI230P2_DAC_FIFO_EN | PCI230P2_DAC_FIFO_RESET
1646 | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR
1647 | PCI230P2_DAC_TRIG_NONE | PCI230P2_DAC_INT_FIFO_NHALF;
1650 /* Set DACCON. */
1651 outw(daccon, dev->iobase + PCI230_DACCON);
1652 /* Preserve most of DACCON apart from write-only, transient bits. */
1653 devpriv->daccon = daccon
1654 & ~(PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR);
1656 if (cmd->scan_begin_src == TRIG_TIMER) {
1657 /* Set the counter timer 1 to the specified scan frequency. */
1658 /* cmd->scan_begin_arg is sampling period in ns */
1659 /* gate it off for now. */
1660 outb(GAT_CONFIG(1, GAT_GND),
1661 devpriv->iobase1 + PCI230_ZGAT_SCE);
1662 pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
1663 cmd->scan_begin_arg,
1664 cmd->flags & TRIG_ROUND_MASK);
1667 /* N.B. cmd->start_src == TRIG_INT */
1668 s->async->inttrig = pci230_ao_inttrig_start;
1670 return 0;
1673 static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
1675 unsigned int min_scan_period, chanlist_len;
1676 int err = 0;
1678 chanlist_len = cmd->chanlist_len;
1679 if (cmd->chanlist_len == 0)
1680 chanlist_len = 1;
1682 min_scan_period = chanlist_len * cmd->convert_arg;
1683 if ((min_scan_period < chanlist_len)
1684 || (min_scan_period < cmd->convert_arg)) {
1685 /* Arithmetic overflow. */
1686 min_scan_period = UINT_MAX;
1687 err++;
1689 if (cmd->scan_begin_arg < min_scan_period) {
1690 cmd->scan_begin_arg = min_scan_period;
1691 err++;
1694 return !err;
1697 static int pci230_ai_cmdtest(struct comedi_device *dev,
1698 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1700 int err = 0;
1701 unsigned int tmp;
1703 /* cmdtest tests a particular command to see if it is valid.
1704 * Using the cmdtest ioctl, a user can create a valid cmd
1705 * and then have it executes by the cmd ioctl.
1707 * cmdtest returns 1,2,3,4,5 or 0, depending on which tests
1708 * the command passes. */
1710 /* Step 1: make sure trigger sources are trivially valid.
1711 * "invalid source" returned by comedilib to user mode process
1712 * if this fails. */
1714 tmp = cmd->start_src;
1715 cmd->start_src &= TRIG_NOW | TRIG_INT;
1716 if (!cmd->start_src || tmp != cmd->start_src)
1717 err++;
1719 tmp = cmd->scan_begin_src;
1720 /* Unfortunately, we cannot trigger a scan off an external source
1721 * on the PCI260 board, since it uses the PPIC0 (DIO) input, which
1722 * isn't present on the PCI260. For PCI260+ we can use the
1723 * EXTTRIG/EXTCONVCLK input on pin 17 instead. */
1724 if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) {
1725 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT
1726 | TRIG_EXT;
1727 } else {
1728 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
1730 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1731 err++;
1733 tmp = cmd->convert_src;
1734 cmd->convert_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT;
1735 if (!cmd->convert_src || tmp != cmd->convert_src)
1736 err++;
1738 tmp = cmd->scan_end_src;
1739 cmd->scan_end_src &= TRIG_COUNT;
1740 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1741 err++;
1743 tmp = cmd->stop_src;
1744 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1745 if (!cmd->stop_src || tmp != cmd->stop_src)
1746 err++;
1748 if (err)
1749 return 1;
1751 /* Step 2: make sure trigger sources are unique and mutually compatible
1752 * "source conflict" returned by comedilib to user mode process
1753 * if this fails. */
1755 /* these tests are true if more than one _src bit is set */
1756 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1757 err++;
1758 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1759 err++;
1760 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1761 err++;
1762 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1763 err++;
1764 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1765 err++;
1767 /* If scan_begin_src is not TRIG_FOLLOW, then a monostable will be
1768 * set up to generate a fixed number of timed conversion pulses. */
1769 if ((cmd->scan_begin_src != TRIG_FOLLOW)
1770 && (cmd->convert_src != TRIG_TIMER))
1771 err++;
1773 if (err)
1774 return 2;
1776 /* Step 3: make sure arguments are trivially compatible.
1777 * "invalid argument" returned by comedilib to user mode process
1778 * if this fails. */
1780 if (cmd->start_arg != 0) {
1781 cmd->start_arg = 0;
1782 err++;
1784 #define MAX_SPEED_AI_SE 3200 /* PCI230 SE: 3200 ns => 312.5 kHz */
1785 #define MAX_SPEED_AI_DIFF 8000 /* PCI230 DIFF: 8000 ns => 125 kHz */
1786 #define MAX_SPEED_AI_PLUS 4000 /* PCI230+: 4000 ns => 250 kHz */
1787 #define MIN_SPEED_AI 4294967295u /* 4294967295ns = 4.29s */
1788 /*- Comedi limit due to unsigned int cmd. Driver limit
1789 * = 2^16 (16bit * counter) * 1000000ns (1kHz onboard
1790 * clock) = 65.536s */
1792 if (cmd->convert_src == TRIG_TIMER) {
1793 unsigned int max_speed_ai;
1795 if (devpriv->hwver == 0) {
1796 /* PCI230 or PCI260. Max speed depends whether
1797 * single-ended or pseudo-differential. */
1798 if (cmd->chanlist && (cmd->chanlist_len > 0)) {
1799 /* Peek analogue reference of first channel. */
1800 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF)
1801 max_speed_ai = MAX_SPEED_AI_DIFF;
1802 else
1803 max_speed_ai = MAX_SPEED_AI_SE;
1805 } else {
1806 /* No channel list. Assume single-ended. */
1807 max_speed_ai = MAX_SPEED_AI_SE;
1809 } else {
1810 /* PCI230+ or PCI260+. */
1811 max_speed_ai = MAX_SPEED_AI_PLUS;
1814 if (cmd->convert_arg < max_speed_ai) {
1815 cmd->convert_arg = max_speed_ai;
1816 err++;
1818 if (cmd->convert_arg > MIN_SPEED_AI) {
1819 cmd->convert_arg = MIN_SPEED_AI;
1820 err++;
1822 } else if (cmd->convert_src == TRIG_EXT) {
1824 * external trigger
1826 * convert_arg == (CR_EDGE | 0)
1827 * => trigger on +ve edge.
1828 * convert_arg == (CR_EDGE | CR_INVERT | 0)
1829 * => trigger on -ve edge.
1831 if ((cmd->convert_arg & CR_FLAGS_MASK) != 0) {
1832 /* Trigger number must be 0. */
1833 if ((cmd->convert_arg & ~CR_FLAGS_MASK) != 0) {
1834 cmd->convert_arg = COMBINE(cmd->convert_arg, 0,
1835 ~CR_FLAGS_MASK);
1836 err++;
1838 /* The only flags allowed are CR_INVERT and CR_EDGE.
1839 * CR_EDGE is required. */
1840 if ((cmd->convert_arg & (CR_FLAGS_MASK & ~CR_INVERT))
1841 != CR_EDGE) {
1842 /* Set CR_EDGE, preserve CR_INVERT. */
1843 cmd->convert_arg =
1844 COMBINE(cmd->start_arg, (CR_EDGE | 0),
1845 CR_FLAGS_MASK & ~CR_INVERT);
1846 err++;
1848 } else {
1849 /* Backwards compatibility with previous versions. */
1850 /* convert_arg == 0 => trigger on -ve edge. */
1851 /* convert_arg == 1 => trigger on +ve edge. */
1852 if (cmd->convert_arg > 1) {
1853 /* Default to trigger on +ve edge. */
1854 cmd->convert_arg = 1;
1855 err++;
1858 } else {
1859 if (cmd->convert_arg != 0) {
1860 cmd->convert_arg = 0;
1861 err++;
1865 if (cmd->scan_end_arg != cmd->chanlist_len) {
1866 cmd->scan_end_arg = cmd->chanlist_len;
1867 err++;
1870 if (cmd->stop_src == TRIG_NONE) {
1871 if (cmd->stop_arg != 0) {
1872 cmd->stop_arg = 0;
1873 err++;
1877 if (cmd->scan_begin_src == TRIG_EXT) {
1878 /* external "trigger" to begin each scan
1879 * scan_begin_arg==0 => use PPC0 input -> gate of CT0 -> gate
1880 * of CT2 (sample convert trigger is CT2) */
1881 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
1882 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1883 ~CR_FLAGS_MASK);
1884 err++;
1886 /* The only flag allowed is CR_EDGE, which is ignored. */
1887 if ((cmd->scan_begin_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
1888 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1889 CR_FLAGS_MASK & ~CR_EDGE);
1890 err++;
1892 } else if (cmd->scan_begin_src == TRIG_TIMER) {
1893 /* N.B. cmd->convert_arg is also TRIG_TIMER */
1894 if (!pci230_ai_check_scan_period(cmd))
1895 err++;
1897 } else {
1898 if (cmd->scan_begin_arg != 0) {
1899 cmd->scan_begin_arg = 0;
1900 err++;
1904 if (err)
1905 return 3;
1907 /* Step 4: fix up any arguments.
1908 * "argument conflict" returned by comedilib to user mode process
1909 * if this fails. */
1911 if (cmd->convert_src == TRIG_TIMER) {
1912 tmp = cmd->convert_arg;
1913 pci230_ns_to_single_timer(&cmd->convert_arg,
1914 cmd->flags & TRIG_ROUND_MASK);
1915 if (tmp != cmd->convert_arg)
1916 err++;
1919 if (cmd->scan_begin_src == TRIG_TIMER) {
1920 /* N.B. cmd->convert_arg is also TRIG_TIMER */
1921 tmp = cmd->scan_begin_arg;
1922 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1923 cmd->flags & TRIG_ROUND_MASK);
1924 if (!pci230_ai_check_scan_period(cmd)) {
1925 /* Was below minimum required. Round up. */
1926 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1927 TRIG_ROUND_UP);
1928 pci230_ai_check_scan_period(cmd);
1930 if (tmp != cmd->scan_begin_arg)
1931 err++;
1934 if (err)
1935 return 4;
1937 /* Step 5: check channel list if it exists. */
1939 if (cmd->chanlist && cmd->chanlist_len > 0) {
1940 enum {
1941 seq_err = 1 << 0,
1942 rangepair_err = 1 << 1,
1943 polarity_err = 1 << 2,
1944 aref_err = 1 << 3,
1945 diffchan_err = 1 << 4,
1946 buggy_chan0_err = 1 << 5
1948 unsigned int errors;
1949 unsigned int chan, prev_chan;
1950 unsigned int range, prev_range;
1951 unsigned int polarity, prev_polarity;
1952 unsigned int aref, prev_aref;
1953 unsigned int subseq_len;
1954 unsigned int n;
1956 subseq_len = 0;
1957 errors = 0;
1958 prev_chan = prev_aref = prev_range = prev_polarity = 0;
1959 for (n = 0; n < cmd->chanlist_len; n++) {
1960 chan = CR_CHAN(cmd->chanlist[n]);
1961 range = CR_RANGE(cmd->chanlist[n]);
1962 aref = CR_AREF(cmd->chanlist[n]);
1963 polarity = pci230_ai_bipolar[range];
1964 /* Only the first half of the channels are available if
1965 * differential. (These are remapped in software. In
1966 * hardware, only the even channels are available.) */
1967 if ((aref == AREF_DIFF)
1968 && (chan >= (s->n_chan / 2))) {
1969 errors |= diffchan_err;
1971 if (n > 0) {
1972 /* Channel numbers must strictly increase or
1973 * subsequence must repeat exactly. */
1974 if ((chan <= prev_chan)
1975 && (subseq_len == 0)) {
1976 subseq_len = n;
1978 if ((subseq_len > 0)
1979 && (cmd->chanlist[n] !=
1980 cmd->chanlist[n % subseq_len])) {
1981 errors |= seq_err;
1983 /* Channels must have same AREF. */
1984 if (aref != prev_aref)
1985 errors |= aref_err;
1987 /* Channel ranges must have same polarity. */
1988 if (polarity != prev_polarity)
1989 errors |= polarity_err;
1991 /* Single-ended channel pairs must have same
1992 * range. */
1993 if ((aref != AREF_DIFF)
1994 && (((chan ^ prev_chan) & ~1) == 0)
1995 && (range != prev_range)) {
1996 errors |= rangepair_err;
1999 prev_chan = chan;
2000 prev_range = range;
2001 prev_aref = aref;
2002 prev_polarity = polarity;
2004 if (subseq_len == 0) {
2005 /* Subsequence is whole sequence. */
2006 subseq_len = n;
2008 /* If channel list is a repeating subsequence, need a whole
2009 * number of repeats. */
2010 if ((n % subseq_len) != 0)
2011 errors |= seq_err;
2013 if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) {
2015 * Buggy PCI230+ or PCI260+ requires channel 0 to be
2016 * (first) in the sequence if the sequence contains
2017 * more than one channel. Hardware versions 1 and 2
2018 * have the bug. There is no hardware version 3.
2020 * Actually, there are two firmwares that report
2021 * themselves as hardware version 1 (the boards
2022 * have different ADC chips with slightly different
2023 * timing requirements, which was supposed to be
2024 * invisible to software). The first one doesn't
2025 * seem to have the bug, but the second one
2026 * does, and we can't tell them apart!
2028 if ((subseq_len > 1)
2029 && (CR_CHAN(cmd->chanlist[0]) != 0)) {
2030 errors |= buggy_chan0_err;
2033 if (errors != 0) {
2034 err++;
2035 if ((errors & seq_err) != 0) {
2036 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2037 "channel numbers must increase or "
2038 "sequence must repeat exactly\n",
2039 dev->minor);
2041 if ((errors & rangepair_err) != 0) {
2042 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2043 "single-ended channel pairs must "
2044 "have the same range\n", dev->minor);
2046 if ((errors & polarity_err) != 0) {
2047 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2048 "channel sequence ranges must be all "
2049 "bipolar or all unipolar\n",
2050 dev->minor);
2052 if ((errors & aref_err) != 0) {
2053 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2054 "channel sequence analogue references "
2055 "must be all the same (single-ended "
2056 "or differential)\n", dev->minor);
2058 if ((errors & diffchan_err) != 0) {
2059 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2060 "differential channel number out of "
2061 "range 0 to %u\n", dev->minor,
2062 (s->n_chan / 2) - 1);
2064 if ((errors & buggy_chan0_err) != 0) {
2065 /* Use printk instead of DPRINTK here. */
2066 printk("comedi: comedi%d: amplc_pci230: "
2067 "ai_cmdtest: Buggy PCI230+/260+ "
2068 "h/w version %u requires first channel "
2069 "of multi-channel sequence to be 0 "
2070 "(corrected in h/w version 4)\n",
2071 dev->minor, devpriv->hwver);
2076 if (err)
2077 return 5;
2079 return 0;
2082 static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
2083 struct comedi_subdevice *s)
2085 struct comedi_cmd *cmd = &s->async->cmd;
2086 unsigned int scanlen = cmd->scan_end_arg;
2087 unsigned int wake;
2088 unsigned short triglev;
2089 unsigned short adccon;
2091 if ((cmd->flags & TRIG_WAKE_EOS) != 0) {
2092 /* Wake at end of scan. */
2093 wake = scanlen - devpriv->ai_scan_pos;
2094 } else {
2095 if (devpriv->ai_continuous
2096 || (devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL)
2097 || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) {
2098 wake = PCI230_ADC_FIFOLEVEL_HALFFULL;
2099 } else {
2100 wake = (devpriv->ai_scan_count * scanlen)
2101 - devpriv->ai_scan_pos;
2104 if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) {
2105 triglev = PCI230_ADC_INT_FIFO_HALF;
2106 } else {
2107 if ((wake > 1) && (devpriv->hwver > 0)) {
2108 /* PCI230+/260+ programmable FIFO interrupt level. */
2109 if (devpriv->adcfifothresh != wake) {
2110 devpriv->adcfifothresh = wake;
2111 outw(wake, dev->iobase + PCI230P_ADCFFTH);
2113 triglev = PCI230P_ADC_INT_FIFO_THRESH;
2114 } else {
2115 triglev = PCI230_ADC_INT_FIFO_NEMPTY;
2118 adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev;
2119 if (adccon != devpriv->adccon) {
2120 devpriv->adccon = adccon;
2121 outw(adccon, dev->iobase + PCI230_ADCCON);
2125 static int pci230_ai_inttrig_convert(struct comedi_device *dev,
2126 struct comedi_subdevice *s,
2127 unsigned int trig_num)
2129 unsigned long irqflags;
2131 if (trig_num != 0)
2132 return -EINVAL;
2134 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2135 if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
2136 unsigned int delayus;
2138 /* Trigger conversion by toggling Z2-CT2 output. Finish
2139 * with output high. */
2140 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
2141 I8254_MODE0);
2142 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
2143 I8254_MODE1);
2144 /* Delay. Should driver be responsible for this? An
2145 * alternative would be to wait until conversion is complete,
2146 * but we can't tell when it's complete because the ADC busy
2147 * bit has a different meaning when FIFO enabled (and when
2148 * FIFO not enabled, it only works for software triggers). */
2149 if (((devpriv->adccon & PCI230_ADC_IM_MASK)
2150 == PCI230_ADC_IM_DIF)
2151 && (devpriv->hwver == 0)) {
2152 /* PCI230/260 in differential mode */
2153 delayus = 8;
2154 } else {
2155 /* single-ended or PCI230+/260+ */
2156 delayus = 4;
2158 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2159 udelay(delayus);
2160 } else {
2161 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2164 return 1;
2167 static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
2168 struct comedi_subdevice *s,
2169 unsigned int trig_num)
2171 unsigned long irqflags;
2172 unsigned char zgat;
2174 if (trig_num != 0)
2175 return -EINVAL;
2177 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2178 if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
2179 /* Trigger scan by waggling CT0 gate source. */
2180 zgat = GAT_CONFIG(0, GAT_GND);
2181 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2182 zgat = GAT_CONFIG(0, GAT_VCC);
2183 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2185 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2187 return 1;
2190 static void pci230_ai_start(struct comedi_device *dev,
2191 struct comedi_subdevice *s)
2193 unsigned long irqflags;
2194 unsigned short conv;
2195 struct comedi_async *async = s->async;
2196 struct comedi_cmd *cmd = &async->cmd;
2198 set_bit(AI_CMD_STARTED, &devpriv->state);
2199 if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
2200 /* An empty acquisition! */
2201 async->events |= COMEDI_CB_EOA;
2202 pci230_ai_stop(dev, s);
2203 comedi_event(dev, s);
2204 } else {
2205 /* Enable ADC FIFO trigger level interrupt. */
2206 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2207 devpriv->int_en |= PCI230_INT_ADC;
2208 devpriv->ier |= PCI230_INT_ADC;
2209 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2210 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2212 /* Update conversion trigger source which is currently set
2213 * to CT2 output, which is currently stuck high. */
2214 switch (cmd->convert_src) {
2215 default:
2216 conv = PCI230_ADC_TRIG_NONE;
2217 break;
2218 case TRIG_TIMER:
2219 /* Using CT2 output. */
2220 conv = PCI230_ADC_TRIG_Z2CT2;
2221 break;
2222 case TRIG_EXT:
2223 if ((cmd->convert_arg & CR_EDGE) != 0) {
2224 if ((cmd->convert_arg & CR_INVERT) == 0) {
2225 /* Trigger on +ve edge. */
2226 conv = PCI230_ADC_TRIG_EXTP;
2227 } else {
2228 /* Trigger on -ve edge. */
2229 conv = PCI230_ADC_TRIG_EXTN;
2231 } else {
2232 /* Backwards compatibility. */
2233 if (cmd->convert_arg != 0) {
2234 /* Trigger on +ve edge. */
2235 conv = PCI230_ADC_TRIG_EXTP;
2236 } else {
2237 /* Trigger on -ve edge. */
2238 conv = PCI230_ADC_TRIG_EXTN;
2241 break;
2242 case TRIG_INT:
2243 /* Use CT2 output for software trigger due to problems
2244 * in differential mode on PCI230/260. */
2245 conv = PCI230_ADC_TRIG_Z2CT2;
2246 break;
2248 devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK)
2249 | conv;
2250 outw(devpriv->adccon, dev->iobase + PCI230_ADCCON);
2251 if (cmd->convert_src == TRIG_INT)
2252 async->inttrig = pci230_ai_inttrig_convert;
2254 /* Update FIFO interrupt trigger level, which is currently
2255 * set to "full". */
2256 pci230_ai_update_fifo_trigger_level(dev, s);
2257 if (cmd->convert_src == TRIG_TIMER) {
2258 /* Update timer gates. */
2259 unsigned char zgat;
2261 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2262 /* Conversion timer CT2 needs to be gated by
2263 * inverted output of monostable CT2. */
2264 zgat = GAT_CONFIG(2, GAT_NOUTNM2);
2265 } else {
2266 /* Conversion timer CT2 needs to be gated on
2267 * continuously. */
2268 zgat = GAT_CONFIG(2, GAT_VCC);
2270 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2271 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2272 /* Set monostable CT0 trigger source. */
2273 switch (cmd->scan_begin_src) {
2274 default:
2275 zgat = GAT_CONFIG(0, GAT_VCC);
2276 break;
2277 case TRIG_EXT:
2279 * For CT0 on PCI230, the external
2280 * trigger (gate) signal comes from
2281 * PPC0, which is channel 16 of the DIO
2282 * subdevice. The application needs to
2283 * configure this as an input in order
2284 * to use it as an external scan
2285 * trigger.
2287 zgat = GAT_CONFIG(0, GAT_EXT);
2288 break;
2289 case TRIG_TIMER:
2291 * Monostable CT0 triggered by rising
2292 * edge on inverted output of CT1
2293 * (falling edge on CT1).
2295 zgat = GAT_CONFIG(0, GAT_NOUTNM2);
2296 break;
2297 case TRIG_INT:
2299 * Monostable CT0 is triggered by
2300 * inttrig function waggling the CT0
2301 * gate source.
2303 zgat = GAT_CONFIG(0, GAT_VCC);
2304 break;
2306 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2307 switch (cmd->scan_begin_src) {
2308 case TRIG_TIMER:
2309 /* Scan period timer CT1 needs to be
2310 * gated on to start counting. */
2311 zgat = GAT_CONFIG(1, GAT_VCC);
2312 outb(zgat, devpriv->iobase1
2313 + PCI230_ZGAT_SCE);
2314 break;
2315 case TRIG_INT:
2316 async->inttrig =
2317 pci230_ai_inttrig_scan_begin;
2318 break;
2321 } else if (cmd->convert_src != TRIG_INT) {
2322 /* No longer need Z2-CT2. */
2323 put_one_resource(dev, RES_Z2CT2, OWNER_AICMD);
2328 static int pci230_ai_inttrig_start(struct comedi_device *dev,
2329 struct comedi_subdevice *s,
2330 unsigned int trig_num)
2332 if (trig_num != 0)
2333 return -EINVAL;
2335 s->async->inttrig = NULLFUNC;
2336 pci230_ai_start(dev, s);
2338 return 1;
2341 static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
2343 unsigned int i, chan, range, diff;
2344 unsigned int res_mask;
2345 unsigned short adccon, adcen;
2346 unsigned char zgat;
2348 /* Get the command. */
2349 struct comedi_async *async = s->async;
2350 struct comedi_cmd *cmd = &async->cmd;
2353 * Determine which shared resources are needed.
2355 res_mask = 0;
2356 /* Need Z2-CT2 to supply a conversion trigger source at a high
2357 * logic level, even if not doing timed conversions. */
2358 res_mask |= (1U << RES_Z2CT2);
2359 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2360 /* Using Z2-CT0 monostable to gate Z2-CT2 conversion timer */
2361 res_mask |= (1U << RES_Z2CT0);
2362 if (cmd->scan_begin_src == TRIG_TIMER) {
2363 /* Using Z2-CT1 for scan frequency */
2364 res_mask |= (1U << RES_Z2CT1);
2367 /* Claim resources. */
2368 if (!get_resources(dev, res_mask, OWNER_AICMD))
2369 return -EBUSY;
2372 /* Get number of scans required. */
2373 if (cmd->stop_src == TRIG_COUNT) {
2374 devpriv->ai_scan_count = cmd->stop_arg;
2375 devpriv->ai_continuous = 0;
2376 } else {
2377 /* TRIG_NONE, user calls cancel. */
2378 devpriv->ai_scan_count = 0;
2379 devpriv->ai_continuous = 1;
2381 devpriv->ai_scan_pos = 0; /* Position within scan. */
2383 /* Steps;
2384 * - Set channel scan list.
2385 * - Set channel gains.
2386 * - Enable and reset FIFO, specify uni/bip, se/diff, and set
2387 * start conversion source to point to something at a high logic
2388 * level (we use the output of counter/timer 2 for this purpose.
2389 * - PAUSE to allow things to settle down.
2390 * - Reset the FIFO again because it needs resetting twice and there
2391 * may have been a false conversion trigger on some versions of
2392 * PCI230/260 due to the start conversion source being set to a
2393 * high logic level.
2394 * - Enable ADC FIFO level interrupt.
2395 * - Set actual conversion trigger source and FIFO interrupt trigger
2396 * level.
2397 * - If convert_src is TRIG_TIMER, set up the timers.
2400 adccon = PCI230_ADC_FIFO_EN;
2401 adcen = 0;
2403 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) {
2404 /* Differential - all channels must be differential. */
2405 diff = 1;
2406 adccon |= PCI230_ADC_IM_DIF;
2407 } else {
2408 /* Single ended - all channels must be single-ended. */
2409 diff = 0;
2410 adccon |= PCI230_ADC_IM_SE;
2413 range = CR_RANGE(cmd->chanlist[0]);
2414 devpriv->ai_bipolar = pci230_ai_bipolar[range];
2415 if (devpriv->ai_bipolar)
2416 adccon |= PCI230_ADC_IR_BIP;
2417 else
2418 adccon |= PCI230_ADC_IR_UNI;
2420 for (i = 0; i < cmd->chanlist_len; i++) {
2421 unsigned int gainshift;
2423 chan = CR_CHAN(cmd->chanlist[i]);
2424 range = CR_RANGE(cmd->chanlist[i]);
2425 if (diff) {
2426 gainshift = 2 * chan;
2427 if (devpriv->hwver == 0) {
2428 /* Original PCI230/260 expects both inputs of
2429 * the differential channel to be enabled. */
2430 adcen |= 3 << gainshift;
2431 } else {
2432 /* PCI230+/260+ expects only one input of the
2433 * differential channel to be enabled. */
2434 adcen |= 1 << gainshift;
2436 } else {
2437 gainshift = (chan & ~1);
2438 adcen |= 1 << chan;
2440 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift))
2441 | (pci230_ai_gain[range] << gainshift);
2444 /* Set channel scan list. */
2445 outw(adcen, dev->iobase + PCI230_ADCEN);
2447 /* Set channel gains. */
2448 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
2450 /* Set counter/timer 2 output high for use as the initial start
2451 * conversion source. */
2452 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
2454 /* Temporarily use CT2 output as conversion trigger source and
2455 * temporarily set FIFO interrupt trigger level to 'full'. */
2456 adccon |= PCI230_ADC_INT_FIFO_FULL | PCI230_ADC_TRIG_Z2CT2;
2458 /* Enable and reset FIFO, specify FIFO trigger level full, specify
2459 * uni/bip, se/diff, and temporarily set the start conversion source
2460 * to CT2 output. Note that CT2 output is currently high, and this
2461 * will produce a false conversion trigger on some versions of the
2462 * PCI230/260, but that will be dealt with later. */
2463 devpriv->adccon = adccon;
2464 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
2466 /* Delay */
2467 /* Failure to include this will result in the first few channels'-worth
2468 * of data being corrupt, normally manifesting itself by large negative
2469 * voltages. It seems the board needs time to settle between the first
2470 * FIFO reset (above) and the second FIFO reset (below). Setting the
2471 * channel gains and scan list _before_ the first FIFO reset also
2472 * helps, though only slightly. */
2473 udelay(25);
2475 /* Reset FIFO again. */
2476 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
2478 if (cmd->convert_src == TRIG_TIMER) {
2479 /* Set up CT2 as conversion timer, but gate it off for now.
2480 * Note, counter/timer output 2 can be monitored on the
2481 * connector: PCI230 pin 21, PCI260 pin 18. */
2482 zgat = GAT_CONFIG(2, GAT_GND);
2483 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2484 /* Set counter/timer 2 to the specified conversion period. */
2485 pci230_ct_setup_ns_mode(dev, 2, I8254_MODE3, cmd->convert_arg,
2486 cmd->flags & TRIG_ROUND_MASK);
2487 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2489 * Set up monostable on CT0 output for scan timing. A
2490 * rising edge on the trigger (gate) input of CT0 will
2491 * trigger the monostable, causing its output to go low
2492 * for the configured period. The period depends on
2493 * the conversion period and the number of conversions
2494 * in the scan.
2496 * Set the trigger high before setting up the
2497 * monostable to stop it triggering. The trigger
2498 * source will be changed later.
2500 zgat = GAT_CONFIG(0, GAT_VCC);
2501 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2502 pci230_ct_setup_ns_mode(dev, 0, I8254_MODE1,
2503 ((uint64_t) cmd->convert_arg
2504 * cmd->scan_end_arg),
2505 TRIG_ROUND_UP);
2506 if (cmd->scan_begin_src == TRIG_TIMER) {
2508 * Monostable on CT0 will be triggered by
2509 * output of CT1 at configured scan frequency.
2511 * Set up CT1 but gate it off for now.
2513 zgat = GAT_CONFIG(1, GAT_GND);
2514 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2515 pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
2516 cmd->scan_begin_arg,
2517 cmd->
2518 flags &
2519 TRIG_ROUND_MASK);
2524 if (cmd->start_src == TRIG_INT) {
2525 s->async->inttrig = pci230_ai_inttrig_start;
2526 } else {
2527 /* TRIG_NOW */
2528 pci230_ai_start(dev, s);
2531 return 0;
2534 static unsigned int divide_ns(uint64_t ns, unsigned int timebase,
2535 unsigned int round_mode)
2537 uint64_t div;
2538 unsigned int rem;
2540 div = ns;
2541 rem = do_div(div, timebase);
2542 round_mode &= TRIG_ROUND_MASK;
2543 switch (round_mode) {
2544 default:
2545 case TRIG_ROUND_NEAREST:
2546 div += (rem + (timebase / 2)) / timebase;
2547 break;
2548 case TRIG_ROUND_DOWN:
2549 break;
2550 case TRIG_ROUND_UP:
2551 div += (rem + timebase - 1) / timebase;
2552 break;
2554 return div > UINT_MAX ? UINT_MAX : (unsigned int)div;
2557 /* Given desired period in ns, returns the required internal clock source
2558 * and gets the initial count. */
2559 static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count,
2560 unsigned int round_mode)
2562 unsigned int clk_src, cnt;
2564 for (clk_src = CLK_10MHZ;; clk_src++) {
2565 cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode);
2566 if ((cnt <= 65536) || (clk_src == CLK_1KHZ))
2567 break;
2570 *count = cnt;
2571 return clk_src;
2574 static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round)
2576 unsigned int count;
2577 unsigned int clk_src;
2579 clk_src = pci230_choose_clk_count(*ns, &count, round);
2580 *ns = count * pci230_timebase[clk_src];
2581 return;
2584 static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
2585 unsigned int mode, uint64_t ns,
2586 unsigned int round)
2588 unsigned int clk_src;
2589 unsigned int count;
2591 /* Set mode. */
2592 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode);
2593 /* Determine clock source and count. */
2594 clk_src = pci230_choose_clk_count(ns, &count, round);
2595 /* Program clock source. */
2596 outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE);
2597 /* Set initial count. */
2598 if (count >= 65536)
2599 count = 0;
2601 i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count);
2604 static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
2606 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct,
2607 I8254_MODE1);
2608 /* Counter ct, 8254 mode 1, initial count not written. */
2611 /* Interrupt handler */
2612 static irqreturn_t pci230_interrupt(int irq, void *d)
2614 unsigned char status_int, valid_status_int;
2615 struct comedi_device *dev = (struct comedi_device *)d;
2616 struct comedi_subdevice *s;
2617 unsigned long irqflags;
2619 /* Read interrupt status/enable register. */
2620 status_int = inb(devpriv->iobase1 + PCI230_INT_STAT);
2622 if (status_int == PCI230_INT_DISABLE)
2623 return IRQ_NONE;
2626 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2627 valid_status_int = devpriv->int_en & status_int;
2628 /* Disable triggered interrupts.
2629 * (Only those interrupts that need re-enabling, are, later in the
2630 * handler). */
2631 devpriv->ier = devpriv->int_en & ~status_int;
2632 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2633 devpriv->intr_running = 1;
2634 devpriv->intr_cpuid = THISCPU;
2635 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2638 * Check the source of interrupt and handle it.
2639 * The PCI230 can cope with concurrent ADC, DAC, PPI C0 and C3
2640 * interrupts. However, at present (Comedi-0.7.60) does not allow
2641 * concurrent execution of commands, instructions or a mixture of the
2642 * two.
2645 if ((valid_status_int & PCI230_INT_ZCLK_CT1) != 0) {
2646 s = dev->write_subdev;
2647 pci230_handle_ao_nofifo(dev, s);
2648 comedi_event(dev, s);
2651 if ((valid_status_int & PCI230P2_INT_DAC) != 0) {
2652 s = dev->write_subdev;
2653 pci230_handle_ao_fifo(dev, s);
2654 comedi_event(dev, s);
2657 if ((valid_status_int & PCI230_INT_ADC) != 0) {
2658 s = dev->read_subdev;
2659 pci230_handle_ai(dev, s);
2660 comedi_event(dev, s);
2663 /* Reenable interrupts. */
2664 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2665 if (devpriv->ier != devpriv->int_en) {
2666 devpriv->ier = devpriv->int_en;
2667 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2669 devpriv->intr_running = 0;
2670 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2672 return IRQ_HANDLED;
2675 static void pci230_handle_ao_nofifo(struct comedi_device *dev,
2676 struct comedi_subdevice *s)
2678 short data;
2679 int i, ret;
2680 struct comedi_async *async = s->async;
2681 struct comedi_cmd *cmd = &async->cmd;
2683 if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0))
2684 return;
2687 for (i = 0; i < cmd->chanlist_len; i++) {
2688 /* Read sample from Comedi's circular buffer. */
2689 ret = comedi_buf_get(s->async, &data);
2690 if (ret == 0) {
2691 s->async->events |= COMEDI_CB_OVERFLOW;
2692 pci230_ao_stop(dev, s);
2693 comedi_error(dev, "AO buffer underrun");
2694 return;
2696 /* Write value to DAC. */
2697 pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
2700 async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
2701 if (!devpriv->ao_continuous) {
2702 devpriv->ao_scan_count--;
2703 if (devpriv->ao_scan_count == 0) {
2704 /* End of acquisition. */
2705 async->events |= COMEDI_CB_EOA;
2706 pci230_ao_stop(dev, s);
2711 /* Loads DAC FIFO (if using it) from buffer. */
2712 /* Returns 0 if AO finished due to completion or error, 1 if still going. */
2713 static int pci230_handle_ao_fifo(struct comedi_device *dev,
2714 struct comedi_subdevice *s)
2716 struct comedi_async *async = s->async;
2717 struct comedi_cmd *cmd = &async->cmd;
2718 unsigned int num_scans;
2719 unsigned int room;
2720 unsigned short dacstat;
2721 unsigned int i, n;
2722 unsigned int bytes_per_scan;
2723 unsigned int events = 0;
2724 int running;
2726 /* Get DAC FIFO status. */
2727 dacstat = inw(dev->iobase + PCI230_DACCON);
2729 /* Determine number of scans available in buffer. */
2730 bytes_per_scan = cmd->chanlist_len * sizeof(short);
2731 num_scans = comedi_buf_read_n_available(async) / bytes_per_scan;
2732 if (!devpriv->ao_continuous) {
2733 /* Fixed number of scans. */
2734 if (num_scans > devpriv->ao_scan_count)
2735 num_scans = devpriv->ao_scan_count;
2737 if (devpriv->ao_scan_count == 0) {
2738 /* End of acquisition. */
2739 events |= COMEDI_CB_EOA;
2742 if (events == 0) {
2743 /* Check for FIFO underrun. */
2744 if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
2745 comedi_error(dev, "AO FIFO underrun");
2746 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2748 /* Check for buffer underrun if FIFO less than half full
2749 * (otherwise there will be loads of "DAC FIFO not half full"
2750 * interrupts). */
2751 if ((num_scans == 0)
2752 && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) {
2753 comedi_error(dev, "AO buffer underrun");
2754 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2757 if (events == 0) {
2758 /* Determine how much room is in the FIFO (in samples). */
2759 if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0)
2760 room = PCI230P2_DAC_FIFOROOM_FULL;
2761 else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0)
2762 room = PCI230P2_DAC_FIFOROOM_HALFTOFULL;
2763 else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0)
2764 room = PCI230P2_DAC_FIFOROOM_EMPTY;
2765 else
2766 room = PCI230P2_DAC_FIFOROOM_ONETOHALF;
2768 /* Convert room to number of scans that can be added. */
2769 room /= cmd->chanlist_len;
2770 /* Determine number of scans to process. */
2771 if (num_scans > room)
2772 num_scans = room;
2774 /* Process scans. */
2775 for (n = 0; n < num_scans; n++) {
2776 for (i = 0; i < cmd->chanlist_len; i++) {
2777 short datum;
2779 comedi_buf_get(async, &datum);
2780 pci230_ao_write_fifo(dev, datum,
2781 CR_CHAN(cmd->chanlist[i]));
2784 events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
2785 if (!devpriv->ao_continuous) {
2786 devpriv->ao_scan_count -= num_scans;
2787 if (devpriv->ao_scan_count == 0) {
2788 /* All data for the command has been written
2789 * to FIFO. Set FIFO interrupt trigger level
2790 * to 'empty'. */
2791 devpriv->daccon = (devpriv->daccon
2793 ~PCI230P2_DAC_INT_FIFO_MASK)
2794 | PCI230P2_DAC_INT_FIFO_EMPTY;
2795 outw(devpriv->daccon,
2796 dev->iobase + PCI230_DACCON);
2799 /* Check if FIFO underrun occurred while writing to FIFO. */
2800 dacstat = inw(dev->iobase + PCI230_DACCON);
2801 if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
2802 comedi_error(dev, "AO FIFO underrun");
2803 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2806 if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
2807 != 0) {
2808 /* Stopping AO due to completion or error. */
2809 pci230_ao_stop(dev, s);
2810 running = 0;
2811 } else {
2812 running = 1;
2814 async->events |= events;
2815 return running;
2818 static void pci230_handle_ai(struct comedi_device *dev,
2819 struct comedi_subdevice *s)
2821 unsigned int events = 0;
2822 unsigned int status_fifo;
2823 unsigned int i;
2824 unsigned int todo;
2825 unsigned int fifoamount;
2826 struct comedi_async *async = s->async;
2827 unsigned int scanlen = async->cmd.scan_end_arg;
2829 /* Determine number of samples to read. */
2830 if (devpriv->ai_continuous) {
2831 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2832 } else if (devpriv->ai_scan_count == 0) {
2833 todo = 0;
2834 } else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL)
2835 || (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) {
2836 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2837 } else {
2838 todo = (devpriv->ai_scan_count * scanlen)
2839 - devpriv->ai_scan_pos;
2840 if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL)
2841 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2845 if (todo == 0)
2846 return;
2849 fifoamount = 0;
2850 for (i = 0; i < todo; i++) {
2851 if (fifoamount == 0) {
2852 /* Read FIFO state. */
2853 status_fifo = inw(dev->iobase + PCI230_ADCCON);
2855 if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) {
2856 /* Report error otherwise FIFO overruns will go
2857 * unnoticed by the caller. */
2858 comedi_error(dev, "AI FIFO overrun");
2859 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2860 break;
2861 } else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) {
2862 /* FIFO empty. */
2863 break;
2864 } else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) {
2865 /* FIFO half full. */
2866 fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
2867 } else {
2868 /* FIFO not empty. */
2869 if (devpriv->hwver > 0) {
2870 /* Read PCI230+/260+ ADC FIFO level. */
2871 fifoamount = inw(dev->iobase
2872 + PCI230P_ADCFFLEV);
2873 if (fifoamount == 0) {
2874 /* Shouldn't happen. */
2875 break;
2877 } else {
2878 fifoamount = 1;
2883 /* Read sample and store in Comedi's circular buffer. */
2884 if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) {
2885 events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
2886 comedi_error(dev, "AI buffer overflow");
2887 break;
2889 fifoamount--;
2890 devpriv->ai_scan_pos++;
2891 if (devpriv->ai_scan_pos == scanlen) {
2892 /* End of scan. */
2893 devpriv->ai_scan_pos = 0;
2894 devpriv->ai_scan_count--;
2895 async->events |= COMEDI_CB_EOS;
2899 if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
2900 /* End of acquisition. */
2901 events |= COMEDI_CB_EOA;
2902 } else {
2903 /* More samples required, tell Comedi to block. */
2904 events |= COMEDI_CB_BLOCK;
2906 async->events |= events;
2908 if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2909 COMEDI_CB_OVERFLOW)) != 0) {
2910 /* disable hardware conversions */
2911 pci230_ai_stop(dev, s);
2912 } else {
2913 /* update FIFO interrupt trigger level */
2914 pci230_ai_update_fifo_trigger_level(dev, s);
2918 static void pci230_ao_stop(struct comedi_device *dev,
2919 struct comedi_subdevice *s)
2921 unsigned long irqflags;
2922 unsigned char intsrc;
2923 int started;
2924 struct comedi_cmd *cmd;
2926 spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
2927 started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state);
2928 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
2929 if (!started)
2930 return;
2933 cmd = &s->async->cmd;
2934 if (cmd->scan_begin_src == TRIG_TIMER) {
2935 /* Stop scan rate generator. */
2936 pci230_cancel_ct(dev, 1);
2939 /* Determine interrupt source. */
2940 if (devpriv->hwver < 2) {
2941 /* Not using DAC FIFO. Using CT1 interrupt. */
2942 intsrc = PCI230_INT_ZCLK_CT1;
2943 } else {
2944 /* Using DAC FIFO interrupt. */
2945 intsrc = PCI230P2_INT_DAC;
2947 /* Disable interrupt and wait for interrupt routine to finish running
2948 * unless we are called from the interrupt routine. */
2949 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2950 devpriv->int_en &= ~intsrc;
2951 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
2952 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2953 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2955 if (devpriv->ier != devpriv->int_en) {
2956 devpriv->ier = devpriv->int_en;
2957 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2959 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2961 if (devpriv->hwver >= 2) {
2962 /* Using DAC FIFO. Reset FIFO, clear underrun error,
2963 * disable FIFO. */
2964 devpriv->daccon &= PCI230_DAC_OR_MASK;
2965 outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET
2966 | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
2967 dev->iobase + PCI230_DACCON);
2970 /* Release resources. */
2971 put_all_resources(dev, OWNER_AOCMD);
2974 static int pci230_ao_cancel(struct comedi_device *dev,
2975 struct comedi_subdevice *s)
2977 pci230_ao_stop(dev, s);
2978 return 0;
2981 static void pci230_ai_stop(struct comedi_device *dev,
2982 struct comedi_subdevice *s)
2984 unsigned long irqflags;
2985 struct comedi_cmd *cmd;
2986 int started;
2988 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2989 started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state);
2990 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2991 if (!started)
2992 return;
2995 cmd = &s->async->cmd;
2996 if (cmd->convert_src == TRIG_TIMER) {
2997 /* Stop conversion rate generator. */
2998 pci230_cancel_ct(dev, 2);
3000 if (cmd->scan_begin_src != TRIG_FOLLOW) {
3001 /* Stop scan period monostable. */
3002 pci230_cancel_ct(dev, 0);
3005 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
3006 /* Disable ADC interrupt and wait for interrupt routine to finish
3007 * running unless we are called from the interrupt routine. */
3008 devpriv->int_en &= ~PCI230_INT_ADC;
3009 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
3010 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
3011 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
3013 if (devpriv->ier != devpriv->int_en) {
3014 devpriv->ier = devpriv->int_en;
3015 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
3017 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
3019 /* Reset FIFO, disable FIFO and set start conversion source to none.
3020 * Keep se/diff and bip/uni settings */
3021 devpriv->adccon = (devpriv->adccon & (PCI230_ADC_IR_MASK
3022 | PCI230_ADC_IM_MASK)) |
3023 PCI230_ADC_TRIG_NONE;
3024 outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
3025 dev->iobase + PCI230_ADCCON);
3027 /* Release resources. */
3028 put_all_resources(dev, OWNER_AICMD);
3031 static int pci230_ai_cancel(struct comedi_device *dev,
3032 struct comedi_subdevice *s)
3034 pci230_ai_stop(dev, s);
3035 return 0;
3038 MODULE_AUTHOR("Comedi http://www.comedi.org");
3039 MODULE_DESCRIPTION("Comedi low-level driver");
3040 MODULE_LICENSE("GPL");