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.
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)
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
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.
60 The AI subdevice has 16 single-ended channels or 8 differential
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:
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|
95 | |--------------|-----------| | |
96 | | TRIG_TIMER(1)|TRIG_TIMER | | |
97 | | TRIG_EXT(2) | | | |
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
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.
137 The AO subdevice has 2 channels with 12-bit resolution.
139 The following output ranges are supported:
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|
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
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.
190 #include <linux/comedidev.h>
192 #include <linux/delay.h>
194 #include "comedi_pci.h"
198 /* PCI230 PCI configuration register information */
199 #define PCI_VENDOR_ID_AMPLICON 0x14dc
200 #define PCI_DEVICE_ID_PCI230 0x0000
201 #define PCI_DEVICE_ID_PCI260 0x0006
202 #define PCI_DEVICE_ID_INVALID 0xffff
204 #define PCI230_IO1_SIZE 32 /* Size of I/O space 1 */
205 #define PCI230_IO2_SIZE 16 /* Size of I/O space 2 */
207 /* PCI230 i/o space 1 registers. */
208 #define PCI230_PPI_X_BASE 0x00 /* User PPI (82C55) base */
209 #define PCI230_PPI_X_A 0x00 /* User PPI (82C55) port A */
210 #define PCI230_PPI_X_B 0x01 /* User PPI (82C55) port B */
211 #define PCI230_PPI_X_C 0x02 /* User PPI (82C55) port C */
212 #define PCI230_PPI_X_CMD 0x03 /* User PPI (82C55) control word */
213 #define PCI230_Z2_CT_BASE 0x14 /* 82C54 counter/timer base */
214 #define PCI230_Z2_CT0 0x14 /* 82C54 counter/timer 0 */
215 #define PCI230_Z2_CT1 0x15 /* 82C54 counter/timer 1 */
216 #define PCI230_Z2_CT2 0x16 /* 82C54 counter/timer 2 */
217 #define PCI230_Z2_CTC 0x17 /* 82C54 counter/timer control word */
218 #define PCI230_ZCLK_SCE 0x1A /* Group Z Clock Configuration */
219 #define PCI230_ZGAT_SCE 0x1D /* Group Z Gate Configuration */
220 #define PCI230_INT_SCE 0x1E /* Interrupt source mask (w) */
221 #define PCI230_INT_STAT 0x1E /* Interrupt status (r) */
223 /* PCI230 i/o space 2 registers. */
224 #define PCI230_DACCON 0x00 /* DAC control */
225 #define PCI230_DACOUT1 0x02 /* DAC channel 0 (w) */
226 #define PCI230_DACOUT2 0x04 /* DAC channel 1 (w) (not FIFO mode) */
227 #define PCI230_ADCDATA 0x08 /* ADC data (r) */
228 #define PCI230_ADCSWTRIG 0x08 /* ADC software trigger (w) */
229 #define PCI230_ADCCON 0x0A /* ADC control */
230 #define PCI230_ADCEN 0x0C /* ADC channel enable bits */
231 #define PCI230_ADCG 0x0E /* ADC gain control bits */
232 /* PCI230+ i/o space 2 additional registers. */
233 #define PCI230P_ADCTRIG 0x10 /* ADC start acquisition trigger */
234 #define PCI230P_ADCTH 0x12 /* ADC analog trigger threshold */
235 #define PCI230P_ADCFFTH 0x14 /* ADC FIFO interrupt threshold */
236 #define PCI230P_ADCFFLEV 0x16 /* ADC FIFO level (r) */
237 #define PCI230P_ADCPTSC 0x18 /* ADC pre-trigger sample count (r) */
238 #define PCI230P_ADCHYST 0x1A /* ADC analog trigger hysteresys */
239 #define PCI230P_EXTFUNC 0x1C /* Extended functions */
240 #define PCI230P_HWVER 0x1E /* Hardware version (r) */
241 /* PCI230+ hardware version 2 onwards. */
242 #define PCI230P2_DACDATA 0x02 /* DAC data (FIFO mode) (w) */
243 #define PCI230P2_DACSWTRIG 0x02 /* DAC soft trigger (FIFO mode) (r) */
244 #define PCI230P2_DACEN 0x06 /* DAC channel enable (FIFO mode) */
246 /* Convertor related constants. */
247 #define PCI230_DAC_SETTLE 5 /* Analogue output settling time in µs */
248 /* (DAC itself is 1µs nominally). */
249 #define PCI230_ADC_SETTLE 1 /* Analogue input settling time in µs */
250 /* (ADC itself is 1.6µs nominally but we poll
252 #define PCI230_MUX_SETTLE 10 /* ADC MUX settling time in µS */
253 /* - 10µs for se, 20µs de. */
255 /* DACCON read-write values. */
256 #define PCI230_DAC_OR_UNI (0<<0) /* Output range unipolar */
257 #define PCI230_DAC_OR_BIP (1<<0) /* Output range bipolar */
258 #define PCI230_DAC_OR_MASK (1<<0)
259 /* The following applies only if DAC FIFO support is enabled in the EXTFUNC
260 * register (and only for PCI230+ hardware version 2 onwards). */
261 #define PCI230P2_DAC_FIFO_EN (1<<8) /* FIFO enable */
262 /* The following apply only if the DAC FIFO is enabled (and only for PCI230+
263 * hardware version 2 onwards). */
264 #define PCI230P2_DAC_TRIG_NONE (0<<2) /* No trigger */
265 #define PCI230P2_DAC_TRIG_SW (1<<2) /* Software trigger trigger */
266 #define PCI230P2_DAC_TRIG_EXTP (2<<2) /* EXTTRIG +ve edge trigger */
267 #define PCI230P2_DAC_TRIG_EXTN (3<<2) /* EXTTRIG -ve edge trigger */
268 #define PCI230P2_DAC_TRIG_Z2CT0 (4<<2) /* CT0-OUT +ve edge trigger */
269 #define PCI230P2_DAC_TRIG_Z2CT1 (5<<2) /* CT1-OUT +ve edge trigger */
270 #define PCI230P2_DAC_TRIG_Z2CT2 (6<<2) /* CT2-OUT +ve edge trigger */
271 #define PCI230P2_DAC_TRIG_MASK (7<<2)
272 #define PCI230P2_DAC_FIFO_WRAP (1<<7) /* FIFO wraparound mode */
273 #define PCI230P2_DAC_INT_FIFO_EMPTY (0<<9) /* FIFO interrupt empty */
274 #define PCI230P2_DAC_INT_FIFO_NEMPTY (1<<9)
275 #define PCI230P2_DAC_INT_FIFO_NHALF (2<<9) /* FIFO intr not half full */
276 #define PCI230P2_DAC_INT_FIFO_HALF (3<<9)
277 #define PCI230P2_DAC_INT_FIFO_NFULL (4<<9) /* FIFO interrupt not full */
278 #define PCI230P2_DAC_INT_FIFO_FULL (5<<9)
279 #define PCI230P2_DAC_INT_FIFO_MASK (7<<9)
281 /* DACCON read-only values. */
282 #define PCI230_DAC_BUSY (1<<1) /* DAC busy. */
283 /* The following apply only if the DAC FIFO is enabled (and only for PCI230+
284 * hardware version 2 onwards). */
285 #define PCI230P2_DAC_FIFO_UNDERRUN_LATCHED (1<<5) /* Underrun error */
286 #define PCI230P2_DAC_FIFO_EMPTY (1<<13) /* FIFO empty */
287 #define PCI230P2_DAC_FIFO_FULL (1<<14) /* FIFO full */
288 #define PCI230P2_DAC_FIFO_HALF (1<<15) /* FIFO half full */
290 /* DACCON write-only, transient values. */
291 /* The following apply only if the DAC FIFO is enabled (and only for PCI230+
292 * hardware version 2 onwards). */
293 #define PCI230P2_DAC_FIFO_UNDERRUN_CLEAR (1<<5) /* Clear underrun */
294 #define PCI230P2_DAC_FIFO_RESET (1<<12) /* FIFO reset */
296 /* PCI230+ hardware version 2 DAC FIFO levels. */
297 #define PCI230P2_DAC_FIFOLEVEL_HALF 512
298 #define PCI230P2_DAC_FIFOLEVEL_FULL 1024
299 /* Free space in DAC FIFO. */
300 #define PCI230P2_DAC_FIFOROOM_EMPTY PCI230P2_DAC_FIFOLEVEL_FULL
301 #define PCI230P2_DAC_FIFOROOM_ONETOHALF \
302 (PCI230P2_DAC_FIFOLEVEL_FULL - PCI230P2_DAC_FIFOLEVEL_HALF)
303 #define PCI230P2_DAC_FIFOROOM_HALFTOFULL 1
304 #define PCI230P2_DAC_FIFOROOM_FULL 0
306 /* ADCCON read/write values. */
307 #define PCI230_ADC_TRIG_NONE (0<<0) /* No trigger */
308 #define PCI230_ADC_TRIG_SW (1<<0) /* Software trigger trigger */
309 #define PCI230_ADC_TRIG_EXTP (2<<0) /* EXTTRIG +ve edge trigger */
310 #define PCI230_ADC_TRIG_EXTN (3<<0) /* EXTTRIG -ve edge trigger */
311 #define PCI230_ADC_TRIG_Z2CT0 (4<<0) /* CT0-OUT +ve edge trigger */
312 #define PCI230_ADC_TRIG_Z2CT1 (5<<0) /* CT1-OUT +ve edge trigger */
313 #define PCI230_ADC_TRIG_Z2CT2 (6<<0) /* CT2-OUT +ve edge trigger */
314 #define PCI230_ADC_TRIG_MASK (7<<0)
315 #define PCI230_ADC_IR_UNI (0<<3) /* Input range unipolar */
316 #define PCI230_ADC_IR_BIP (1<<3) /* Input range bipolar */
317 #define PCI230_ADC_IR_MASK (1<<3)
318 #define PCI230_ADC_IM_SE (0<<4) /* Input mode single ended */
319 #define PCI230_ADC_IM_DIF (1<<4) /* Input mode differential */
320 #define PCI230_ADC_IM_MASK (1<<4)
321 #define PCI230_ADC_FIFO_EN (1<<8) /* FIFO enable */
322 #define PCI230_ADC_INT_FIFO_EMPTY (0<<9)
323 #define PCI230_ADC_INT_FIFO_NEMPTY (1<<9) /* FIFO interrupt not empty */
324 #define PCI230_ADC_INT_FIFO_NHALF (2<<9)
325 #define PCI230_ADC_INT_FIFO_HALF (3<<9) /* FIFO interrupt half full */
326 #define PCI230_ADC_INT_FIFO_NFULL (4<<9)
327 #define PCI230_ADC_INT_FIFO_FULL (5<<9) /* FIFO interrupt full */
328 #define PCI230P_ADC_INT_FIFO_THRESH (7<<9) /* FIFO interrupt threshold */
329 #define PCI230_ADC_INT_FIFO_MASK (7<<9)
331 /* ADCCON write-only, transient values. */
332 #define PCI230_ADC_FIFO_RESET (1<<12) /* FIFO reset */
333 #define PCI230_ADC_GLOB_RESET (1<<13) /* Global reset */
335 /* ADCCON read-only values. */
336 #define PCI230_ADC_BUSY (1<<15) /* ADC busy */
337 #define PCI230_ADC_FIFO_EMPTY (1<<12) /* FIFO empty */
338 #define PCI230_ADC_FIFO_FULL (1<<13) /* FIFO full */
339 #define PCI230_ADC_FIFO_HALF (1<<14) /* FIFO half full */
340 #define PCI230_ADC_FIFO_FULL_LATCHED (1<<5) /* Indicates overrun occurred */
342 /* PCI230 ADC FIFO levels. */
343 #define PCI230_ADC_FIFOLEVEL_HALFFULL 2049 /* Value for FIFO half full */
344 #define PCI230_ADC_FIFOLEVEL_FULL 4096 /* FIFO size */
346 /* Value to write to ADCSWTRIG to trigger ADC conversion in software trigger
347 * mode. Can be anything. */
348 #define PCI230_ADC_CONV 0xffff
350 /* PCI230+ EXTFUNC values. */
351 #define PCI230P_EXTFUNC_GAT_EXTTRIG (1<<0)
352 /* Route EXTTRIG pin to external gate inputs. */
353 /* PCI230+ hardware version 2 values. */
354 #define PCI230P2_EXTFUNC_DACFIFO (1<<1)
355 /* Allow DAC FIFO to be enabled. */
358 * Counter/timer clock input configuration sources.
360 #define CLK_CLK 0 /* reserved (channel-specific clock) */
361 #define CLK_10MHZ 1 /* internal 10 MHz clock */
362 #define CLK_1MHZ 2 /* internal 1 MHz clock */
363 #define CLK_100KHZ 3 /* internal 100 kHz clock */
364 #define CLK_10KHZ 4 /* internal 10 kHz clock */
365 #define CLK_1KHZ 5 /* internal 1 kHz clock */
366 #define CLK_OUTNM1 6 /* output of channel-1 modulo total */
367 #define CLK_EXT 7 /* external clock */
368 /* Macro to construct clock input configuration register value. */
369 #define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
370 /* Timebases in ns. */
371 #define TIMEBASE_10MHZ 100
372 #define TIMEBASE_1MHZ 1000
373 #define TIMEBASE_100KHZ 10000
374 #define TIMEBASE_10KHZ 100000
375 #define TIMEBASE_1KHZ 1000000
378 * Counter/timer gate input configuration sources.
380 #define GAT_VCC 0 /* VCC (i.e. enabled) */
381 #define GAT_GND 1 /* GND (i.e. disabled) */
382 #define GAT_EXT 2 /* external gate input (PPCn on PCI230) */
383 #define GAT_NOUTNM2 3 /* inverted output of channel-2 modulo total */
384 /* Macro to construct gate input configuration register value. */
385 #define GAT_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
388 * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI230 and PCI260:
390 * Channel's Channel's
391 * clock input gate input
392 * Channel CLK_OUTNM1 GAT_NOUTNM2
393 * ------- ---------- -----------
394 * Z2-CT0 Z2-CT2-OUT /Z2-CT1-OUT
395 * Z2-CT1 Z2-CT0-OUT /Z2-CT2-OUT
396 * Z2-CT2 Z2-CT1-OUT /Z2-CT0-OUT
399 /* Interrupt enables/status register values. */
400 #define PCI230_INT_DISABLE 0
401 #define PCI230_INT_PPI_C0 (1<<0)
402 #define PCI230_INT_PPI_C3 (1<<1)
403 #define PCI230_INT_ADC (1<<2)
404 #define PCI230_INT_ZCLK_CT1 (1<<5)
405 /* For PCI230+ hardware version 2 when DAC FIFO enabled. */
406 #define PCI230P2_INT_DAC (1<<4)
408 #define PCI230_TEST_BIT(val, n) ((val>>n)&1)
409 /* Assumes bits numbered with zero offset, ie. 0-15 */
411 /* (Potentially) shared resources and their owners */
413 RES_Z2CT0, /* Z2-CT0 */
414 RES_Z2CT1, /* Z2-CT1 */
415 RES_Z2CT2, /* Z2-CT2 */
416 NUM_RESOURCES /* Number of (potentially) shared resources. */
420 OWNER_NONE, /* Not owned */
421 OWNER_AICMD, /* Owned by AI command */
422 OWNER_AOCMD /* Owned by AO command */
429 /* Combine old and new bits. */
430 #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
432 /* A generic null function pointer value. */
435 /* Current CPU. XXX should this be hard_smp_processor_id()? */
436 #define THISCPU smp_processor_id()
438 /* State flags for atomic bit operations */
439 #define AI_CMD_STARTED 0
440 #define AO_CMD_STARTED 1
443 * Board descriptions for the two boards supported.
446 typedef struct pci230_board_struct {
454 unsigned int min_hwver; /* Minimum hardware version supported. */
456 static const pci230_board pci230_boards[] = {
459 id: PCI_DEVICE_ID_PCI230,
469 id: PCI_DEVICE_ID_PCI260,
479 id: PCI_DEVICE_ID_PCI230,
488 id: PCI_DEVICE_ID_PCI260,
496 name: "amplc_pci230", /* Wildcard matches any above */
497 id: PCI_DEVICE_ID_INVALID,
501 static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = {
502 {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230, PCI_ANY_ID, PCI_ANY_ID,
504 {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260, PCI_ANY_ID, PCI_ANY_ID,
509 MODULE_DEVICE_TABLE(pci, pci230_pci_table);
511 * Useful for shorthand access to the particular board structure
513 #define n_pci230_boards (sizeof(pci230_boards)/sizeof(pci230_boards[0]))
514 #define thisboard ((const pci230_board *)dev->board_ptr)
516 /* this structure is for data unique to this hardware driver. If
517 several hardware drivers keep similar information in this structure,
518 feel free to suggest moving the variable to the comedi_device struct. */
519 struct pci230_private {
520 struct pci_dev *pci_dev;
521 spinlock_t isr_spinlock; /* Interrupt spin lock */
522 spinlock_t res_spinlock; /* Shared resources spin lock */
523 spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */
524 spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */
525 unsigned long state; /* State flags */
526 unsigned long iobase1; /* PCI230's I/O space 1 */
527 lsampl_t ao_readback[2]; /* Used for AO readback */
528 unsigned int ai_scan_count; /* Number of analogue input scans
530 unsigned int ai_scan_pos; /* Current position within analogue
532 unsigned int ao_scan_count; /* Number of analogue output scans
534 int intr_cpuid; /* ID of CPU running interrupt routine. */
535 unsigned short hwver; /* Hardware version (for '+' models). */
536 unsigned short adccon; /* ADCCON register value. */
537 unsigned short daccon; /* DACCON register value. */
538 unsigned short adcfifothresh; /* ADC FIFO programmable interrupt
539 * level threshold (PCI230+/260+). */
540 unsigned short adcg; /* ADCG register value. */
541 unsigned char int_en; /* Interrupt enables bits. */
542 unsigned char ai_continuous; /* Flag set when cmd->stop_src ==
543 * TRIG_NONE - user chooses to stop
544 * continuous conversion by
546 unsigned char ao_continuous; /* Flag set when cmd->stop_src ==
547 * TRIG_NONE - user chooses to stop
548 * continuous conversion by
550 unsigned char ai_bipolar; /* Set if bipolar input range so we
551 * know to mangle it. */
552 unsigned char ao_bipolar; /* Set if bipolar output range so we
553 * know to mangle it. */
554 unsigned char ier; /* Copy of interrupt enables/status register. */
555 unsigned char intr_running; /* Flag set in interrupt routine. */
556 unsigned char res_owner[NUM_RESOURCES]; /* Shared resource owners. */
559 #define devpriv ((struct pci230_private *)dev->private)
561 /* PCI230 clock source periods in ns */
562 static const unsigned int pci230_timebase[8] = {
563 [CLK_10MHZ] = TIMEBASE_10MHZ,
564 [CLK_1MHZ] = TIMEBASE_1MHZ,
565 [CLK_100KHZ] = TIMEBASE_100KHZ,
566 [CLK_10KHZ] = TIMEBASE_10KHZ,
567 [CLK_1KHZ] = TIMEBASE_1KHZ,
570 /* PCI230 analogue input range table */
571 static const comedi_lrange pci230_ai_range = { 7, {
582 /* PCI230 analogue gain bits for each input range. */
583 static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 };
585 /* PCI230 adccon bipolar flag for each analogue input range. */
586 static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 };
588 /* PCI230 analogue output range table */
589 static const comedi_lrange pci230_ao_range = { 2, {
595 /* PCI230 daccon bipolar flag for each analogue output range. */
596 static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
599 * The comedi_driver structure tells the Comedi core module
600 * which functions to call to configure/deconfigure (attach/detach)
601 * the board, and also about the kernel module that contains
604 static int pci230_attach(comedi_device * dev, comedi_devconfig * it);
605 static int pci230_detach(comedi_device * dev);
606 static comedi_driver driver_amplc_pci230 = {
607 driver_name:"amplc_pci230",
609 attach:pci230_attach,
610 detach:pci230_detach,
611 board_name:&pci230_boards[0].name,
612 offset:sizeof(pci230_boards[0]),
613 num_names:sizeof(pci230_boards) / sizeof(pci230_boards[0]),
616 COMEDI_PCI_INITCLEANUP(driver_amplc_pci230, pci230_pci_table);
618 static int pci230_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
619 comedi_insn * insn, lsampl_t * data);
620 static int pci230_ao_winsn(comedi_device * dev, comedi_subdevice * s,
621 comedi_insn * insn, lsampl_t * data);
622 static int pci230_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
623 comedi_insn * insn, lsampl_t * data);
624 static void pci230_ct_setup_ns_mode(comedi_device * dev, unsigned int ct,
625 unsigned int mode, uint64_t ns, unsigned int round);
626 static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round);
627 static void pci230_cancel_ct(comedi_device * dev, unsigned int ct);
628 static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG);
629 static int pci230_ao_cmdtest(comedi_device * dev, comedi_subdevice * s,
631 static int pci230_ao_cmd(comedi_device * dev, comedi_subdevice * s);
632 static int pci230_ao_cancel(comedi_device * dev, comedi_subdevice * s);
633 static void pci230_ao_stop(comedi_device * dev, comedi_subdevice * s);
634 static void pci230_handle_ao_nofifo(comedi_device * dev, comedi_subdevice * s);
635 static int pci230_handle_ao_fifo(comedi_device * dev, comedi_subdevice * s);
636 static int pci230_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
638 static int pci230_ai_cmd(comedi_device * dev, comedi_subdevice * s);
639 static int pci230_ai_cancel(comedi_device * dev, comedi_subdevice * s);
640 static void pci230_ai_stop(comedi_device * dev, comedi_subdevice * s);
641 static void pci230_handle_ai(comedi_device * dev, comedi_subdevice * s);
643 static sampl_t pci230_ai_read(comedi_device * dev)
646 sampl_t data = (sampl_t) inw(dev->iobase + PCI230_ADCDATA);
648 /* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
649 * four bits reserved for expansion). */
650 /* PCI230+ is 16 bit AI. */
651 data = data >> (16 - thisboard->ai_bits);
653 /* If a bipolar range was specified, mangle it (twos
654 * complement->straight binary). */
655 if (devpriv->ai_bipolar) {
656 data ^= 1 << (thisboard->ai_bits - 1);
661 static inline unsigned short pci230_ao_mangle_datum(comedi_device * dev,
664 /* If a bipolar range was specified, mangle it (straight binary->twos
666 if (devpriv->ao_bipolar) {
667 datum ^= 1 << (thisboard->ao_bits - 1);
670 /* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
671 * four bits reserved for expansion). */
672 /* PCI230+ is also 12 bit AO. */
673 datum <<= (16 - thisboard->ao_bits);
674 return (unsigned short)datum;
677 static inline void pci230_ao_write_nofifo(comedi_device * dev, sampl_t datum,
680 /* Store unmangled datum to be read back later. */
681 devpriv->ao_readback[chan] = datum;
683 /* Write mangled datum to appropriate DACOUT register. */
684 outw(pci230_ao_mangle_datum(dev, datum), dev->iobase + (((chan) == 0)
685 ? PCI230_DACOUT1 : PCI230_DACOUT2));
688 static inline void pci230_ao_write_fifo(comedi_device * dev, sampl_t datum,
691 /* Store unmangled datum to be read back later. */
692 devpriv->ao_readback[chan] = datum;
694 /* Write mangled datum to appropriate DACDATA register. */
695 outw(pci230_ao_mangle_datum(dev, datum),
696 dev->iobase + PCI230P2_DACDATA);
700 * Attach is called by the Comedi core to configure the driver
701 * for a particular board. If you specified a board_name array
702 * in the driver structure, dev->board_ptr contains that
705 static int pci230_attach(comedi_device * dev, comedi_devconfig * it)
708 unsigned long iobase1, iobase2;
709 /* PCI230's I/O spaces 1 and 2 respectively. */
710 struct pci_dev *pci_dev;
711 int i = 0, irq_hdl, rc;
713 printk("comedi%d: amplc_pci230: attach %s %d,%d\n", dev->minor,
714 thisboard->name, it->options[0], it->options[1]);
716 /* Allocate the private structure area using alloc_private().
717 * Macro defined in comedidev.h - memsets struct fields to 0. */
718 if ((alloc_private(dev, sizeof(struct pci230_private))) < 0) {
721 spin_lock_init(&devpriv->isr_spinlock);
722 spin_lock_init(&devpriv->res_spinlock);
723 spin_lock_init(&devpriv->ai_stop_spinlock);
724 spin_lock_init(&devpriv->ao_stop_spinlock);
726 for (pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
728 pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) {
729 if (it->options[0] || it->options[1]) {
730 /* Match against bus/slot options. */
731 if (it->options[0] != pci_dev->bus->number ||
732 it->options[1] != PCI_SLOT(pci_dev->devfn))
735 if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
737 if (thisboard->id == PCI_DEVICE_ID_INVALID) {
738 /* The name was specified as "amplc_pci230" which is
739 * used to match any supported device. Replace the
740 * current dev->board_ptr with one that matches the
742 for (i = 0; i < n_pci230_boards; i++) {
743 if (pci_dev->device == pci230_boards[i].id) {
744 if (pci230_boards[i].min_hwver > 0) {
745 /* Check for a '+' model.
746 * First check length of
748 if (pci_resource_len(pci_dev, 3)
750 /* Not a '+' model. */
753 /* TODO: temporarily enable the
754 * PCI device and read the
755 * hardware version register.
756 * For now assume it's okay. */
758 /* Change board_ptr to matched board */
759 dev->board_ptr = &pci230_boards[i];
763 if (i < n_pci230_boards)
766 /* The name was specified as a specific device name.
767 * The current dev->board_ptr is correct. Check
768 * whether it matches the PCI device ID. */
769 if (thisboard->id == pci_dev->device) {
770 /* Check minimum hardware version. */
771 if (thisboard->min_hwver > 0) {
772 /* Looking for a '+' model. First
773 * check length of registers. */
774 if (pci_resource_len(pci_dev, 3) < 32) {
775 /* Not a '+' model. */
778 /* TODO: temporarily enable the PCI
779 * device and read the hardware version
780 * register. For now, assume it's
790 printk("comedi%d: No %s card found\n", dev->minor,
794 devpriv->pci_dev = pci_dev;
797 * Initialize dev->board_name.
799 dev->board_name = thisboard->name;
801 /* Enable PCI device and reserve I/O spaces. */
802 if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) {
803 printk("comedi%d: failed to enable PCI device "
804 "and request regions\n", dev->minor);
808 /* Read base addresses of the PCI230's two I/O regions from PCI
809 * configuration register. */
810 iobase1 = pci_resource_start(pci_dev, 2);
811 iobase2 = pci_resource_start(pci_dev, 3);
813 printk("comedi%d: %s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
814 dev->minor, dev->board_name, iobase1, iobase2);
816 devpriv->iobase1 = iobase1;
817 dev->iobase = iobase2;
819 /* Read bits of DACCON register - only the output range. */
820 devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK;
822 /* Read hardware version register and set extended function register
824 if (pci_resource_len(pci_dev, 3) >= 32) {
825 unsigned short extfunc = 0;
827 devpriv->hwver = inw(dev->iobase + PCI230P_HWVER);
828 if (devpriv->hwver < thisboard->min_hwver) {
829 printk("comedi%d: %s - bad hardware version "
830 "- got %u, need %u\n", dev->minor,
831 dev->board_name, devpriv->hwver,
832 thisboard->min_hwver);
835 if (devpriv->hwver > 0) {
836 if (!thisboard->have_dio) {
837 /* No DIO ports. Route counters' external gates
838 * to the EXTTRIG signal (PCI260+ pin 17).
839 * (Otherwise, they would be routed to DIO
840 * inputs PC0, PC1 and PC2 which don't exist
842 extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
844 if ((thisboard->ao_chans > 0)
845 && (devpriv->hwver >= 2)) {
846 /* Enable DAC FIFO functionality. */
847 extfunc |= PCI230P2_EXTFUNC_DACFIFO;
850 outw(extfunc, dev->iobase + PCI230P_EXTFUNC);
851 if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) {
852 /* Temporarily enable DAC FIFO, reset it and disable
853 * FIFO wraparound. */
854 outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN
855 | PCI230P2_DAC_FIFO_RESET,
856 dev->iobase + PCI230_DACCON);
857 /* Clear DAC FIFO channel enable register. */
858 outw(0, dev->iobase + PCI230P2_DACEN);
859 /* Disable DAC FIFO. */
860 outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
864 /* Disable board's interrupts. */
865 outb(0, devpriv->iobase1 + PCI230_INT_SCE);
867 /* Set ADC to a reasonable state. */
869 devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE
871 outw(1 << 0, dev->iobase + PCI230_ADCEN);
872 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
873 outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
874 dev->iobase + PCI230_ADCCON);
876 /* Register the interrupt handler. */
877 irq_hdl = comedi_request_irq(devpriv->pci_dev->irq, pci230_interrupt,
878 IRQF_SHARED, "amplc_pci230", dev);
880 printk("comedi%d: unable to register irq, "
881 "commands will not be available %d\n", dev->minor,
882 devpriv->pci_dev->irq);
884 dev->irq = devpriv->pci_dev->irq;
885 printk("comedi%d: registered irq %u\n", dev->minor,
886 devpriv->pci_dev->irq);
890 * Allocate the subdevice structures. alloc_subdevice() is a
891 * convenient macro defined in comedidev.h.
893 if (alloc_subdevices(dev, 3) < 0)
896 s = dev->subdevices + 0;
897 /* analog input subdevice */
898 s->type = COMEDI_SUBD_AI;
899 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
900 s->n_chan = thisboard->ai_chans;
901 s->maxdata = (1 << thisboard->ai_bits) - 1;
902 s->range_table = &pci230_ai_range;
903 s->insn_read = &pci230_ai_rinsn;
904 s->len_chanlist = 256; /* but there are restrictions. */
905 /* Only register commands if the interrupt handler is installed. */
907 dev->read_subdev = s;
908 s->subdev_flags |= SDF_CMD_READ;
909 s->do_cmd = &pci230_ai_cmd;
910 s->do_cmdtest = &pci230_ai_cmdtest;
911 s->cancel = pci230_ai_cancel;
914 s = dev->subdevices + 1;
915 /* analog output subdevice */
916 if (thisboard->ao_chans > 0) {
917 s->type = COMEDI_SUBD_AO;
918 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
919 s->n_chan = thisboard->ao_chans;;
920 s->maxdata = (1 << thisboard->ao_bits) - 1;
921 s->range_table = &pci230_ao_range;
922 s->insn_write = &pci230_ao_winsn;
923 s->insn_read = &pci230_ao_rinsn;
924 s->len_chanlist = thisboard->ao_chans;
925 /* Only register commands if the interrupt handler is
928 dev->write_subdev = s;
929 s->subdev_flags |= SDF_CMD_WRITE;
930 s->do_cmd = &pci230_ao_cmd;
931 s->do_cmdtest = &pci230_ao_cmdtest;
932 s->cancel = pci230_ao_cancel;
935 s->type = COMEDI_SUBD_UNUSED;
938 s = dev->subdevices + 2;
939 /* digital i/o subdevice */
940 if (thisboard->have_dio) {
941 rc = subdev_8255_init(dev, s, NULL,
942 (devpriv->iobase1 + PCI230_PPI_X_BASE));
946 s->type = COMEDI_SUBD_UNUSED;
949 printk("comedi%d: attached\n", dev->minor);
955 * _detach is called to deconfigure a device. It should deallocate
957 * This function is also called when _attach() fails, so it should be
958 * careful not to release resources that were not necessarily
959 * allocated by _attach(). dev->private and dev->subdevices are
960 * deallocated automatically by the core.
962 static int pci230_detach(comedi_device * dev)
964 printk("comedi%d: amplc_pci230: remove\n", dev->minor);
966 if (dev->subdevices && thisboard->have_dio)
967 /* Clean up dio subdevice. */
968 subdev_8255_cleanup(dev, dev->subdevices + 2);
971 comedi_free_irq(dev->irq, dev);
974 if (devpriv->pci_dev) {
976 comedi_pci_disable(devpriv->pci_dev);
978 pci_dev_put(devpriv->pci_dev);
985 static int get_resources(comedi_device * dev, unsigned int res_mask,
991 unsigned int claimed;
992 unsigned long irqflags;
996 comedi_spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
997 for (b = 1, i = 0; (i < NUM_RESOURCES)
998 && (res_mask != 0); b <<= 1, i++) {
999 if ((res_mask & b) != 0) {
1001 if (devpriv->res_owner[i] == OWNER_NONE) {
1002 devpriv->res_owner[i] = owner;
1004 } else if (devpriv->res_owner[i] != owner) {
1005 for (b = 1, i = 0; claimed != 0; b <<= 1, i++) {
1006 if ((claimed & b) != 0) {
1007 devpriv->res_owner[i]
1017 comedi_spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
1021 static inline int get_one_resource(comedi_device * dev, unsigned int resource,
1022 unsigned char owner)
1024 return get_resources(dev, (1U << resource), owner);
1027 static void put_resources(comedi_device * dev, unsigned int res_mask,
1028 unsigned char owner)
1032 unsigned long irqflags;
1034 comedi_spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
1035 for (b = 1, i = 0; (i < NUM_RESOURCES)
1036 && (res_mask != 0); b <<= 1, i++) {
1037 if ((res_mask & b) != 0) {
1039 if (devpriv->res_owner[i] == owner) {
1040 devpriv->res_owner[i] = OWNER_NONE;
1044 comedi_spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
1047 static inline void put_one_resource(comedi_device * dev, unsigned int resource,
1048 unsigned char owner)
1050 put_resources(dev, (1U << resource), owner);
1053 static inline void put_all_resources(comedi_device * dev, unsigned char owner)
1055 put_resources(dev, (1U << NUM_RESOURCES) - 1, owner);
1059 * COMEDI_SUBD_AI instruction;
1061 static int pci230_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
1062 comedi_insn * insn, lsampl_t * data)
1065 unsigned int chan, range, aref;
1066 unsigned int gainshift;
1067 unsigned int status;
1068 unsigned short adccon, adcen;
1070 /* Unpack channel and range. */
1071 chan = CR_CHAN(insn->chanspec);
1072 range = CR_RANGE(insn->chanspec);
1073 aref = CR_AREF(insn->chanspec);
1074 if (aref == AREF_DIFF) {
1076 if (chan >= s->n_chan / 2) {
1077 DPRINTK("comedi%d: amplc_pci230: ai_rinsn: "
1078 "differential channel number out of range "
1079 "0 to %u\n", dev->minor, (s->n_chan / 2) - 1);
1084 /* Use Z2-CT2 as a conversion trigger instead of the built-in
1085 * software trigger, as otherwise triggering of differential channels
1086 * doesn't work properly for some versions of PCI230/260. Also set
1087 * FIFO mode because the ADC busy bit only works for software triggers.
1089 adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
1090 /* Set Z2-CT2 output low to avoid any false triggers. */
1091 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
1092 devpriv->ai_bipolar = pci230_ai_bipolar[range];
1093 if (aref == AREF_DIFF) {
1095 gainshift = chan * 2;
1096 if (devpriv->hwver == 0) {
1097 /* Original PCI230/260 expects both inputs of the
1098 * differential channel to be enabled. */
1099 adcen = 3 << gainshift;
1101 /* PCI230+/260+ expects only one input of the
1102 * differential channel to be enabled. */
1103 adcen = 1 << gainshift;
1105 adccon |= PCI230_ADC_IM_DIF;
1109 gainshift = chan & ~1;
1110 adccon |= PCI230_ADC_IM_SE;
1112 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift))
1113 | (pci230_ai_gain[range] << gainshift);
1114 if (devpriv->ai_bipolar) {
1115 adccon |= PCI230_ADC_IR_BIP;
1117 adccon |= PCI230_ADC_IR_UNI;
1120 /* Enable only this channel in the scan list - otherwise by default
1121 * we'll get one sample from each channel. */
1122 outw(adcen, dev->iobase + PCI230_ADCEN);
1124 /* Set gain for channel. */
1125 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
1127 /* Specify uni/bip, se/diff, conversion source, and reset FIFO. */
1128 devpriv->adccon = adccon;
1129 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
1131 /* Convert n samples */
1132 for (n = 0; n < insn->n; n++) {
1133 /* Trigger conversion by toggling Z2-CT2 output (finish with
1135 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
1137 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
1141 /* wait for conversion to end */
1142 for (i = 0; i < TIMEOUT; i++) {
1143 status = inw(dev->iobase + PCI230_ADCCON);
1144 if (!(status & PCI230_ADC_FIFO_EMPTY))
1149 /* rt_printk() should be used instead of printk()
1150 * whenever the code can be called from real-time. */
1151 rt_printk("timeout\n");
1156 data[n] = pci230_ai_read(dev);
1159 /* return the number of samples read/written */
1164 * COMEDI_SUBD_AO instructions;
1166 static int pci230_ao_winsn(comedi_device * dev, comedi_subdevice * s,
1167 comedi_insn * insn, lsampl_t * data)
1172 /* Unpack channel and range. */
1173 chan = CR_CHAN(insn->chanspec);
1174 range = CR_RANGE(insn->chanspec);
1176 /* Set range - see analogue output range table; 0 => unipolar 10V,
1177 * 1 => bipolar +/-10V range scale */
1178 devpriv->ao_bipolar = pci230_ao_bipolar[range];
1179 outw(range, dev->iobase + PCI230_DACCON);
1181 /* Writing a list of values to an AO channel is probably not
1182 * very useful, but that's how the interface is defined. */
1183 for (i = 0; i < insn->n; i++) {
1184 /* Write value to DAC and store it. */
1185 pci230_ao_write_nofifo(dev, data[i], chan);
1188 /* return the number of samples read/written */
1192 /* AO subdevices should have a read insn as well as a write insn.
1193 * Usually this means copying a value stored in devpriv. */
1194 static int pci230_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
1195 comedi_insn * insn, lsampl_t * data)
1198 int chan = CR_CHAN(insn->chanspec);
1200 for (i = 0; i < insn->n; i++)
1201 data[i] = devpriv->ao_readback[chan];
1206 static int pci230_ao_cmdtest(comedi_device * dev, comedi_subdevice * s,
1212 /* cmdtest tests a particular command to see if it is valid.
1213 * Using the cmdtest ioctl, a user can create a valid cmd
1214 * and then have it executes by the cmd ioctl.
1216 * cmdtest returns 1,2,3,4 or 0, depending on which tests
1217 * the command passes. */
1219 /* Step 1: make sure trigger sources are trivially valid.
1220 * "invalid source" returned by comedilib to user mode process
1223 tmp = cmd->start_src;
1224 cmd->start_src &= TRIG_INT;
1225 if (!cmd->start_src || tmp != cmd->start_src)
1228 tmp = cmd->scan_begin_src;
1229 if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) {
1231 * For PCI230+ hardware version 2 onwards, allow external
1232 * trigger from EXTTRIG/EXTCONVCLK input (PCI230+ pin 25).
1234 * FIXME: The permitted scan_begin_src values shouldn't depend
1235 * on devpriv->hwver (the detected card's actual hardware
1236 * version). They should only depend on thisboard->min_hwver
1237 * (the static capabilities of the configured card). To fix
1238 * it, a new card model, e.g. "pci230+2" would have to be
1239 * defined with min_hwver set to 2. It doesn't seem worth it
1240 * for this alone. At the moment, please consider
1241 * scan_begin_src==TRIG_EXT support to be a bonus rather than a
1244 cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT;
1246 cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT;
1248 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1251 tmp = cmd->convert_src;
1252 cmd->convert_src &= TRIG_NOW;
1253 if (!cmd->convert_src || tmp != cmd->convert_src)
1256 tmp = cmd->scan_end_src;
1257 cmd->scan_end_src &= TRIG_COUNT;
1258 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1261 tmp = cmd->stop_src;
1262 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1263 if (!cmd->stop_src || tmp != cmd->stop_src)
1269 /* Step 2: make sure trigger sources are unique and mutually compatible
1270 * "source conflict" returned by comedilib to user mode process
1273 /* these tests are true if more than one _src bit is set */
1274 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1276 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1278 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1280 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1282 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1288 /* Step 3: make sure arguments are trivially compatible.
1289 * "invalid argument" returned by comedilib to user mode process
1292 if (cmd->start_arg != 0) {
1296 #define MAX_SPEED_AO 8000 /* 8000 ns => 125 kHz */
1297 #define MIN_SPEED_AO 4294967295u /* 4294967295ns = 4.29s */
1298 /*- Comedi limit due to unsigned int cmd. Driver limit
1299 * = 2^16 (16bit * counter) * 1000000ns (1kHz onboard
1300 * clock) = 65.536s */
1302 switch (cmd->scan_begin_src) {
1304 if (cmd->scan_begin_arg < MAX_SPEED_AO) {
1305 cmd->scan_begin_arg = MAX_SPEED_AO;
1308 if (cmd->scan_begin_arg > MIN_SPEED_AO) {
1309 cmd->scan_begin_arg = MIN_SPEED_AO;
1314 /* External trigger - for PCI230+ hardware version 2 onwards. */
1315 /* Trigger number must be 0. */
1316 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
1317 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1321 /* The only flags allowed are CR_EDGE and CR_INVERT. The
1322 * CR_EDGE flag is ignored. */
1323 if ((cmd->scan_begin_arg
1324 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) !=
1326 cmd->scan_begin_arg =
1327 COMBINE(cmd->scan_begin_arg, 0,
1328 CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
1333 if (cmd->scan_begin_arg != 0) {
1334 cmd->scan_begin_arg = 0;
1340 if (cmd->scan_end_arg != cmd->chanlist_len) {
1341 cmd->scan_end_arg = cmd->chanlist_len;
1344 if (cmd->stop_src == TRIG_NONE) {
1346 if (cmd->stop_arg != 0) {
1355 /* Step 4: fix up any arguments.
1356 * "argument conflict" returned by comedilib to user mode process
1359 if (cmd->scan_begin_src == TRIG_TIMER) {
1360 tmp = cmd->scan_begin_arg;
1361 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1362 cmd->flags & TRIG_ROUND_MASK);
1363 if (tmp != cmd->scan_begin_arg)
1370 /* Step 5: check channel list if it exists. */
1372 if (cmd->chanlist && cmd->chanlist_len > 0) {
1375 range_err = (1 << 1)
1377 unsigned int errors;
1379 unsigned int chan, prev_chan;
1380 unsigned int range, first_range;
1382 prev_chan = CR_CHAN(cmd->chanlist[0]);
1383 first_range = CR_RANGE(cmd->chanlist[0]);
1385 for (n = 1; n < cmd->chanlist_len; n++) {
1386 chan = CR_CHAN(cmd->chanlist[n]);
1387 range = CR_RANGE(cmd->chanlist[n]);
1388 /* Channel numbers must strictly increase. */
1389 if (chan < prev_chan) {
1392 /* Ranges must be the same. */
1393 if (range != first_range) {
1394 errors |= range_err;
1400 if ((errors & seq_err) != 0) {
1401 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1402 "channel numbers must increase\n",
1405 if ((errors & range_err) != 0) {
1406 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1407 "channels must have the same range\n",
1419 static int pci230_ao_inttrig_scan_begin(comedi_device * dev,
1420 comedi_subdevice * s, unsigned int trig_num)
1422 unsigned long irqflags;
1427 comedi_spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
1428 if (test_bit(AO_CMD_STARTED, &devpriv->state)) {
1430 if (devpriv->hwver < 2) {
1431 /* Not using DAC FIFO. */
1432 comedi_spin_unlock_irqrestore(&devpriv->
1433 ao_stop_spinlock, irqflags);
1434 pci230_handle_ao_nofifo(dev, s);
1435 comedi_event(dev, s);
1437 /* Using DAC FIFO. */
1438 /* Read DACSWTRIG register to trigger conversion. */
1439 inw(dev->iobase + PCI230P2_DACSWTRIG);
1440 comedi_spin_unlock_irqrestore(&devpriv->
1441 ao_stop_spinlock, irqflags);
1443 /* Delay. Should driver be responsible for this? */
1444 /* XXX TODO: See if DAC busy bit can be used. */
1447 comedi_spin_unlock_irqrestore(&devpriv-> ao_stop_spinlock,
1454 static void pci230_ao_start(comedi_device * dev, comedi_subdevice * s)
1456 comedi_async *async = s->async;
1457 comedi_cmd *cmd = &async->cmd;
1458 unsigned long irqflags;
1460 set_bit(AO_CMD_STARTED, &devpriv->state);
1461 if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
1462 /* An empty acquisition! */
1463 async->events |= COMEDI_CB_EOA;
1464 pci230_ao_stop(dev, s);
1465 comedi_event(dev, s);
1467 if (devpriv->hwver >= 2) {
1468 /* Using DAC FIFO. */
1469 unsigned short scantrig;
1472 /* Preload FIFO data. */
1473 run = pci230_handle_ao_fifo(dev, s);
1474 comedi_event(dev, s);
1479 /* Set scan trigger source. */
1480 switch (cmd->scan_begin_src) {
1482 scantrig = PCI230P2_DAC_TRIG_Z2CT1;
1485 /* Trigger on EXTTRIG/EXTCONVCLK pin. */
1486 if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
1488 scantrig = PCI230P2_DAC_TRIG_EXTP;
1491 scantrig = PCI230P2_DAC_TRIG_EXTN;
1495 scantrig = PCI230P2_DAC_TRIG_SW;
1498 /* Shouldn't get here. */
1499 scantrig = PCI230P2_DAC_TRIG_NONE;
1502 devpriv->daccon = (devpriv->daccon
1503 & ~PCI230P2_DAC_TRIG_MASK) | scantrig;
1504 outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
1507 switch (cmd->scan_begin_src) {
1509 if (devpriv->hwver < 2) {
1510 /* Not using DAC FIFO. */
1511 /* Enable CT1 timer interrupt. */
1512 comedi_spin_lock_irqsave(&devpriv->isr_spinlock,
1514 devpriv->int_en |= PCI230_INT_ZCLK_CT1;
1515 devpriv->ier |= PCI230_INT_ZCLK_CT1;
1517 devpriv->iobase1 + PCI230_INT_SCE);
1518 comedi_spin_unlock_irqrestore(&devpriv->
1519 isr_spinlock, irqflags);
1521 /* Set CT1 gate high to start counting. */
1522 outb(GAT_CONFIG(1, GAT_VCC),
1523 devpriv->iobase1 + PCI230_ZGAT_SCE);
1526 async->inttrig = pci230_ao_inttrig_scan_begin;
1529 if (devpriv->hwver >= 2) {
1530 /* Using DAC FIFO. Enable DAC FIFO interrupt. */
1531 comedi_spin_lock_irqsave(&devpriv->isr_spinlock,
1533 devpriv->int_en |= PCI230P2_INT_DAC;
1534 devpriv->ier |= PCI230P2_INT_DAC;
1535 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
1536 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock,
1542 static int pci230_ao_inttrig_start(comedi_device * dev, comedi_subdevice * s,
1543 unsigned int trig_num)
1548 s->async->inttrig = NULLFUNC;
1549 pci230_ao_start(dev, s);
1554 static int pci230_ao_cmd(comedi_device * dev, comedi_subdevice * s)
1556 unsigned short daccon;
1559 /* Get the command. */
1560 comedi_cmd *cmd = &s->async->cmd;
1562 if (cmd->scan_begin_src == TRIG_TIMER) {
1564 if (!get_one_resource(dev, RES_Z2CT1, OWNER_AOCMD)) {
1569 /* Get number of scans required. */
1570 if (cmd->stop_src == TRIG_COUNT) {
1571 devpriv->ao_scan_count = cmd->stop_arg;
1572 devpriv->ao_continuous = 0;
1574 /* TRIG_NONE, user calls cancel. */
1575 devpriv->ao_scan_count = 0;
1576 devpriv->ao_continuous = 1;
1579 /* Set range - see analogue output range table; 0 => unipolar 10V,
1580 * 1 => bipolar +/-10V range scale */
1581 range = CR_RANGE(cmd->chanlist[0]);
1582 devpriv->ao_bipolar = pci230_ao_bipolar[range];
1583 daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI;
1584 /* Use DAC FIFO for hardware version 2 onwards. */
1585 if (devpriv->hwver >= 2) {
1586 unsigned short dacen;
1590 for (i = 0; i < cmd->chanlist_len; i++) {
1591 dacen |= 1 << CR_CHAN(cmd->chanlist[i]);
1593 /* Set channel scan list. */
1594 outw(dacen, dev->iobase + PCI230P2_DACEN);
1597 * Set DAC scan source to 'none'.
1598 * Set DAC FIFO interrupt trigger level to 'not half full'.
1599 * Reset DAC FIFO and clear underrun.
1601 * N.B. DAC FIFO interrupts are currently disabled.
1603 daccon |= PCI230P2_DAC_FIFO_EN | PCI230P2_DAC_FIFO_RESET
1604 | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR
1605 | PCI230P2_DAC_TRIG_NONE | PCI230P2_DAC_INT_FIFO_NHALF;
1609 outw(daccon, dev->iobase + PCI230_DACCON);
1610 /* Preserve most of DACCON apart from write-only, transient bits. */
1611 devpriv->daccon = daccon
1612 & ~(PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR);
1614 if (cmd->scan_begin_src == TRIG_TIMER) {
1615 /* Set the counter timer 1 to the specified scan frequency. */
1616 /* cmd->scan_begin_arg is sampling period in ns */
1617 /* gate it off for now. */
1618 outb(GAT_CONFIG(1, GAT_GND),
1619 devpriv->iobase1 + PCI230_ZGAT_SCE);
1620 pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
1621 cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
1624 /* N.B. cmd->start_src == TRIG_INT */
1625 s->async->inttrig = pci230_ao_inttrig_start;
1630 static int pci230_ai_check_scan_period(comedi_cmd * cmd)
1632 unsigned int min_scan_period, chanlist_len;
1635 chanlist_len = cmd->chanlist_len;
1636 if (cmd->chanlist_len == 0) {
1639 min_scan_period = chanlist_len * cmd->convert_arg;
1640 if ((min_scan_period < chanlist_len)
1641 || (min_scan_period < cmd->convert_arg)) {
1642 /* Arithmetic overflow. */
1643 min_scan_period = UINT_MAX;
1646 if (cmd->scan_begin_arg < min_scan_period) {
1647 cmd->scan_begin_arg = min_scan_period;
1654 static int pci230_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
1660 /* cmdtest tests a particular command to see if it is valid.
1661 * Using the cmdtest ioctl, a user can create a valid cmd
1662 * and then have it executes by the cmd ioctl.
1664 * cmdtest returns 1,2,3,4,5 or 0, depending on which tests
1665 * the command passes. */
1667 /* Step 1: make sure trigger sources are trivially valid.
1668 * "invalid source" returned by comedilib to user mode process
1671 tmp = cmd->start_src;
1672 cmd->start_src &= TRIG_NOW | TRIG_INT;
1673 if (!cmd->start_src || tmp != cmd->start_src)
1676 tmp = cmd->scan_begin_src;
1677 /* Unfortunately, we cannot trigger a scan off an external source
1678 * on the PCI260 board, since it uses the PPIC0 (DIO) input, which
1679 * isn't present on the PCI260. For PCI260+ we can use the
1680 * EXTTRIG/EXTCONVCLK input on pin 17 instead. */
1681 if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) {
1682 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT
1685 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
1687 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1690 tmp = cmd->convert_src;
1691 cmd->convert_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT;
1692 if (!cmd->convert_src || tmp != cmd->convert_src)
1695 tmp = cmd->scan_end_src;
1696 cmd->scan_end_src &= TRIG_COUNT;
1697 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1700 tmp = cmd->stop_src;
1701 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1702 if (!cmd->stop_src || tmp != cmd->stop_src)
1708 /* Step 2: make sure trigger sources are unique and mutually compatible
1709 * "source conflict" returned by comedilib to user mode process
1712 /* these tests are true if more than one _src bit is set */
1713 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1715 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1717 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1719 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1721 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1724 /* If scan_begin_src is not TRIG_FOLLOW, then a monostable will be
1725 * set up to generate a fixed number of timed conversion pulses. */
1726 if ((cmd->scan_begin_src != TRIG_FOLLOW)
1727 && (cmd->convert_src != TRIG_TIMER))
1733 /* Step 3: make sure arguments are trivially compatible.
1734 * "invalid argument" returned by comedilib to user mode process
1737 if (cmd->start_arg != 0) {
1741 #define MAX_SPEED_AI_SE 3200 /* PCI230 SE: 3200 ns => 312.5 kHz */
1742 #define MAX_SPEED_AI_DIFF 8000 /* PCI230 DIFF: 8000 ns => 125 kHz */
1743 #define MAX_SPEED_AI_PLUS 4000 /* PCI230+: 4000 ns => 250 kHz */
1744 #define MIN_SPEED_AI 4294967295u /* 4294967295ns = 4.29s */
1745 /*- Comedi limit due to unsigned int cmd. Driver limit
1746 * = 2^16 (16bit * counter) * 1000000ns (1kHz onboard
1747 * clock) = 65.536s */
1749 if (cmd->convert_src == TRIG_TIMER) {
1750 unsigned int max_speed_ai;
1752 if (devpriv->hwver == 0) {
1753 /* PCI230 or PCI260. Max speed depends whether
1754 * single-ended or pseudo-differential. */
1755 if (cmd->chanlist && (cmd->chanlist_len > 0)) {
1756 /* Peek analogue reference of first channel. */
1757 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) {
1758 max_speed_ai = MAX_SPEED_AI_DIFF;
1760 max_speed_ai = MAX_SPEED_AI_SE;
1763 /* No channel list. Assume single-ended. */
1764 max_speed_ai = MAX_SPEED_AI_SE;
1767 /* PCI230+ or PCI260+. */
1768 max_speed_ai = MAX_SPEED_AI_PLUS;
1771 if (cmd->convert_arg < max_speed_ai) {
1772 cmd->convert_arg = max_speed_ai;
1775 if (cmd->convert_arg > MIN_SPEED_AI) {
1776 cmd->convert_arg = MIN_SPEED_AI;
1779 } else if (cmd->convert_src == TRIG_EXT) {
1783 * convert_arg == (CR_EDGE | 0)
1784 * => trigger on +ve edge.
1785 * convert_arg == (CR_EDGE | CR_INVERT | 0)
1786 * => trigger on -ve edge.
1788 if ((cmd->convert_arg & CR_FLAGS_MASK) != 0) {
1789 /* Trigger number must be 0. */
1790 if ((cmd->convert_arg & ~CR_FLAGS_MASK) != 0) {
1791 cmd->convert_arg = COMBINE(cmd->convert_arg, 0,
1795 /* The only flags allowed are CR_INVERT and CR_EDGE.
1796 * CR_EDGE is required. */
1797 if ((cmd->convert_arg & (CR_FLAGS_MASK & ~CR_INVERT))
1799 /* Set CR_EDGE, preserve CR_INVERT. */
1801 COMBINE(cmd->start_arg, (CR_EDGE | 0),
1802 CR_FLAGS_MASK & ~CR_INVERT);
1806 /* Backwards compatibility with previous versions. */
1807 /* convert_arg == 0 => trigger on -ve edge. */
1808 /* convert_arg == 1 => trigger on +ve edge. */
1809 if (cmd->convert_arg > 1) {
1810 /* Default to trigger on +ve edge. */
1811 cmd->convert_arg = 1;
1816 if (cmd->convert_arg != 0) {
1817 cmd->convert_arg = 0;
1822 if (cmd->scan_end_arg != cmd->chanlist_len) {
1823 cmd->scan_end_arg = cmd->chanlist_len;
1827 if (cmd->stop_src == TRIG_NONE) {
1828 if (cmd->stop_arg != 0) {
1834 if (cmd->scan_begin_src == TRIG_EXT) {
1835 /* external "trigger" to begin each scan
1836 * scan_begin_arg==0 => use PPC0 input -> gate of CT0 -> gate
1837 * of CT2 (sample convert trigger is CT2) */
1838 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
1839 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1843 /* The only flag allowed is CR_EDGE, which is ignored. */
1844 if ((cmd->scan_begin_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
1845 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1846 CR_FLAGS_MASK & ~CR_EDGE);
1849 } else if (cmd->scan_begin_src == TRIG_TIMER) {
1850 /* N.B. cmd->convert_arg is also TRIG_TIMER */
1851 if (!pci230_ai_check_scan_period(cmd)) {
1855 if (cmd->scan_begin_arg != 0) {
1856 cmd->scan_begin_arg = 0;
1864 /* Step 4: fix up any arguments.
1865 * "argument conflict" returned by comedilib to user mode process
1868 if (cmd->convert_src == TRIG_TIMER) {
1869 tmp = cmd->convert_arg;
1870 pci230_ns_to_single_timer(&cmd->convert_arg,
1871 cmd->flags & TRIG_ROUND_MASK);
1872 if (tmp != cmd->convert_arg)
1876 if (cmd->scan_begin_src == TRIG_TIMER) {
1877 /* N.B. cmd->convert_arg is also TRIG_TIMER */
1878 tmp = cmd->scan_begin_arg;
1879 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1880 cmd->flags & TRIG_ROUND_MASK);
1881 if (!pci230_ai_check_scan_period(cmd)) {
1882 /* Was below minimum required. Round up. */
1883 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1885 pci230_ai_check_scan_period(cmd);
1887 if (tmp != cmd->scan_begin_arg)
1894 /* Step 5: check channel list if it exists. */
1896 if (cmd->chanlist && cmd->chanlist_len > 0) {
1899 rangepair_err = 1 << 1,
1900 polarity_err = 1 << 2,
1902 diffchan_err = 1 << 4,
1903 buggy_chan0_err = 1 << 5
1905 unsigned int errors;
1906 unsigned int chan, prev_chan;
1907 unsigned int range, prev_range;
1908 unsigned int polarity, prev_polarity;
1909 unsigned int aref, prev_aref;
1910 unsigned int subseq_len;
1915 prev_chan = prev_aref = prev_range = prev_polarity = 0;
1916 for (n = 0; n < cmd->chanlist_len; n++) {
1917 chan = CR_CHAN(cmd->chanlist[n]);
1918 range = CR_RANGE(cmd->chanlist[n]);
1919 aref = CR_AREF(cmd->chanlist[n]);
1920 polarity = pci230_ai_bipolar[range];
1921 /* Only the first half of the channels are available if
1922 * differential. (These are remapped in software. In
1923 * hardware, only the even channels are available.) */
1924 if ((aref == AREF_DIFF)
1925 && (chan >= (s->n_chan / 2))) {
1926 errors |= diffchan_err;
1929 /* Channel numbers must strictly increase or
1930 * subsequence must repeat exactly. */
1931 if ((chan <= prev_chan)
1932 && (subseq_len == 0)) {
1935 if ((subseq_len > 0)
1936 && (cmd->chanlist[n] !=
1941 /* Channels must have same AREF. */
1942 if (aref != prev_aref) {
1945 /* Channel ranges must have same polarity. */
1946 if (polarity != prev_polarity) {
1947 errors |= polarity_err;
1949 /* Single-ended channel pairs must have same
1951 if ((aref != AREF_DIFF)
1952 && (((chan ^ prev_chan) & ~1) == 0)
1953 && (range != prev_range)) {
1954 errors |= rangepair_err;
1960 prev_polarity = polarity;
1962 if (subseq_len == 0) {
1963 /* Subsequence is whole sequence. */
1966 /* If channel list is a repeating subsequence, need a whole
1967 * number of repeats. */
1968 if ((n % subseq_len) != 0) {
1971 if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) {
1973 * Buggy PCI230+ or PCI260+ requires channel 0 to be
1974 * (first) in the sequence if the sequence contains
1975 * more than one channel. Hardware versions 1 and 2
1976 * have the bug. There is no hardware version 3.
1978 * Actually, there are two firmwares that report
1979 * themselves as hardware version 1 (the boards
1980 * have different ADC chips with slightly different
1981 * timing requirements, which was supposed to be
1982 * invisible to software). The first one doesn't
1983 * seem to have the bug, but the second one
1984 * does, and we can't tell them apart!
1986 if ((subseq_len > 1)
1987 && (CR_CHAN(cmd->chanlist[0]) != 0)) {
1988 errors |= buggy_chan0_err;
1993 if ((errors & seq_err) != 0) {
1994 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
1995 "channel numbers must increase or "
1996 "sequence must repeat exactly\n",
1999 if ((errors & rangepair_err) != 0) {
2000 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2001 "single-ended channel pairs must "
2002 "have the same range\n", dev->minor);
2004 if ((errors & polarity_err) != 0) {
2005 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2006 "channel sequence ranges must be all "
2007 "bipolar or all unipolar\n",
2010 if ((errors & aref_err) != 0) {
2011 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2012 "channel sequence analogue references "
2013 "must be all the same (single-ended "
2014 "or differential)\n", dev->minor);
2016 if ((errors & diffchan_err) != 0) {
2017 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
2018 "differential channel number out of "
2019 "range 0 to %u\n", dev->minor,
2020 (s->n_chan / 2) - 1);
2022 if ((errors & buggy_chan0_err) != 0) {
2023 /* Use printk instead of DPRINTK here. */
2024 printk("comedi: comedi%d: amplc_pci230: "
2025 "ai_cmdtest: Buggy PCI230+/260+ "
2026 "h/w version %u requires first channel "
2027 "of multi-channel sequence to be 0 "
2028 "(corrected in h/w version 4)\n",
2029 dev->minor, devpriv->hwver);
2040 static void pci230_ai_update_fifo_trigger_level(comedi_device * dev,
2041 comedi_subdevice * s)
2043 comedi_cmd *cmd = &s->async->cmd;
2044 unsigned int scanlen = cmd->scan_end_arg;
2046 unsigned short triglev;
2047 unsigned short adccon;
2049 if ((cmd->flags & TRIG_WAKE_EOS) != 0) {
2050 /* Wake at end of scan. */
2051 wake = scanlen - devpriv->ai_scan_pos;
2053 if (devpriv->ai_continuous
2054 || (devpriv->ai_scan_count
2055 >= PCI230_ADC_FIFOLEVEL_HALFFULL)
2056 || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) {
2057 wake = PCI230_ADC_FIFOLEVEL_HALFFULL;
2059 wake = (devpriv->ai_scan_count * scanlen)
2060 - devpriv->ai_scan_pos;
2063 if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) {
2064 triglev = PCI230_ADC_INT_FIFO_HALF;
2066 if ((wake > 1) && (devpriv->hwver > 0)) {
2067 /* PCI230+/260+ programmable FIFO interrupt level. */
2068 if (devpriv->adcfifothresh != wake) {
2069 devpriv->adcfifothresh = wake;
2070 outw(wake, dev->iobase + PCI230P_ADCFFTH);
2072 triglev = PCI230P_ADC_INT_FIFO_THRESH;
2074 triglev = PCI230_ADC_INT_FIFO_NEMPTY;
2077 adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev;
2078 if (adccon != devpriv->adccon) {
2079 devpriv->adccon = adccon;
2080 outw(adccon, dev->iobase + PCI230_ADCCON);
2084 static int pci230_ai_inttrig_convert(comedi_device * dev, comedi_subdevice * s,
2085 unsigned int trig_num)
2087 unsigned long irqflags;
2092 comedi_spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2093 if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
2094 unsigned int delayus;
2096 /* Trigger conversion by toggling Z2-CT2 output. Finish
2097 * with output high. */
2098 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
2100 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
2102 /* Delay. Should driver be responsible for this? An
2103 * alternative would be to wait until conversion is complete,
2104 * but we can't tell when it's complete because the ADC busy
2105 * bit has a different meaning when FIFO enabled (and when
2106 * FIFO not enabled, it only works for software triggers). */
2107 if (((devpriv->adccon & PCI230_ADC_IM_MASK)
2108 == PCI230_ADC_IM_DIF)
2109 && (devpriv->hwver == 0)) {
2110 /* PCI230/260 in differential mode */
2113 /* single-ended or PCI230+/260+ */
2116 comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock,
2118 comedi_udelay(delayus);
2120 comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock,
2127 static int pci230_ai_inttrig_scan_begin(comedi_device * dev,
2128 comedi_subdevice * s, unsigned int trig_num)
2130 unsigned long irqflags;
2136 comedi_spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2137 if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
2138 /* Trigger scan by waggling CT0 gate source. */
2139 zgat = GAT_CONFIG(0, GAT_GND);
2140 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2141 zgat = GAT_CONFIG(0, GAT_VCC);
2142 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2144 comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2149 static void pci230_ai_start(comedi_device * dev, comedi_subdevice * s)
2151 unsigned long irqflags;
2152 unsigned short conv;
2153 comedi_async *async = s->async;
2154 comedi_cmd *cmd = &async->cmd;
2156 set_bit(AI_CMD_STARTED, &devpriv->state);
2157 if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
2158 /* An empty acquisition! */
2159 async->events |= COMEDI_CB_EOA;
2160 pci230_ai_stop(dev, s);
2161 comedi_event(dev, s);
2163 /* Enable ADC FIFO trigger level interrupt. */
2164 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2165 devpriv->int_en |= PCI230_INT_ADC;
2166 devpriv->ier |= PCI230_INT_ADC;
2167 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2168 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2170 /* Update conversion trigger source which is currently set
2171 * to CT2 output, which is currently stuck high. */
2172 switch (cmd->convert_src) {
2174 conv = PCI230_ADC_TRIG_NONE;
2177 /* Using CT2 output. */
2178 conv = PCI230_ADC_TRIG_Z2CT2;
2181 if ((cmd->convert_arg & CR_EDGE) != 0) {
2182 if ((cmd->convert_arg & CR_INVERT) == 0) {
2183 /* Trigger on +ve edge. */
2184 conv = PCI230_ADC_TRIG_EXTP;
2186 /* Trigger on -ve edge. */
2187 conv = PCI230_ADC_TRIG_EXTN;
2190 /* Backwards compatibility. */
2191 if (cmd->convert_arg != 0) {
2192 /* Trigger on +ve edge. */
2193 conv = PCI230_ADC_TRIG_EXTP;
2195 /* Trigger on -ve edge. */
2196 conv = PCI230_ADC_TRIG_EXTN;
2201 /* Use CT2 output for software trigger due to problems
2202 * in differential mode on PCI230/260. */
2203 conv = PCI230_ADC_TRIG_Z2CT2;
2206 devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK)
2208 outw(devpriv->adccon, dev->iobase + PCI230_ADCCON);
2209 if (cmd->convert_src == TRIG_INT) {
2210 async->inttrig = pci230_ai_inttrig_convert;
2212 /* Update FIFO interrupt trigger level, which is currently
2214 pci230_ai_update_fifo_trigger_level(dev, s);
2215 if (cmd->convert_src == TRIG_TIMER) {
2216 /* Update timer gates. */
2219 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2220 /* Conversion timer CT2 needs to be gated by
2221 * inverted output of monostable CT2. */
2222 zgat = GAT_CONFIG(2, GAT_NOUTNM2);
2224 /* Conversion timer CT2 needs to be gated on
2226 zgat = GAT_CONFIG(2, GAT_VCC);
2228 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2229 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2230 /* Set monostable CT0 trigger source. */
2231 switch (cmd->scan_begin_src) {
2233 zgat = GAT_CONFIG(0, GAT_VCC);
2237 * For CT0 on PCI230, the external
2238 * trigger (gate) signal comes from
2239 * PPC0, which is channel 16 of the DIO
2240 * subdevice. The application needs to
2241 * configure this as an input in order
2242 * to use it as an external scan
2245 zgat = GAT_CONFIG(0, GAT_EXT);
2249 * Monostable CT0 triggered by rising
2250 * edge on inverted output of CT1
2251 * (falling edge on CT1).
2253 zgat = GAT_CONFIG(0, GAT_NOUTNM2);
2257 * Monostable CT0 is triggered by
2258 * inttrig function waggling the CT0
2261 zgat = GAT_CONFIG(0, GAT_VCC);
2264 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2265 switch (cmd->scan_begin_src) {
2267 /* Scan period timer CT1 needs to be
2268 * gated on to start counting. */
2269 zgat = GAT_CONFIG(1, GAT_VCC);
2270 outb(zgat, devpriv->iobase1
2275 pci230_ai_inttrig_scan_begin;
2279 } else if (cmd->convert_src != TRIG_INT) {
2280 /* No longer need Z2-CT2. */
2281 put_one_resource(dev, RES_Z2CT2, OWNER_AICMD);
2286 static int pci230_ai_inttrig_start(comedi_device * dev, comedi_subdevice * s,
2287 unsigned int trig_num)
2292 s->async->inttrig = NULLFUNC;
2293 pci230_ai_start(dev, s);
2298 static int pci230_ai_cmd(comedi_device * dev, comedi_subdevice * s)
2300 unsigned int i, chan, range, diff;
2301 unsigned int res_mask;
2302 unsigned short adccon, adcen;
2305 /* Get the command. */
2306 comedi_async *async = s->async;
2307 comedi_cmd *cmd = &async->cmd;
2310 * Determine which shared resources are needed.
2313 /* Need Z2-CT2 to supply a conversion trigger source at a high
2314 * logic level, even if not doing timed conversions. */
2315 res_mask |= (1U << RES_Z2CT2);
2316 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2317 /* Using Z2-CT0 monostable to gate Z2-CT2 conversion timer */
2318 res_mask |= (1U << RES_Z2CT0);
2319 if (cmd->scan_begin_src == TRIG_TIMER) {
2320 /* Using Z2-CT1 for scan frequency */
2321 res_mask |= (1U << RES_Z2CT1);
2324 /* Claim resources. */
2325 if (!get_resources(dev, res_mask, OWNER_AICMD)) {
2329 /* Get number of scans required. */
2330 if (cmd->stop_src == TRIG_COUNT) {
2331 devpriv->ai_scan_count = cmd->stop_arg;
2332 devpriv->ai_continuous = 0;
2334 /* TRIG_NONE, user calls cancel. */
2335 devpriv->ai_scan_count = 0;
2336 devpriv->ai_continuous = 1;
2338 devpriv->ai_scan_pos = 0; /* Position within scan. */
2341 * - Set channel scan list.
2342 * - Set channel gains.
2343 * - Enable and reset FIFO, specify uni/bip, se/diff, and set
2344 * start conversion source to point to something at a high logic
2345 * level (we use the output of counter/timer 2 for this purpose.
2346 * - PAUSE to allow things to settle down.
2347 * - Reset the FIFO again because it needs resetting twice and there
2348 * may have been a false conversion trigger on some versions of
2349 * PCI230/260 due to the start conversion source being set to a
2351 * - Enable ADC FIFO level interrupt.
2352 * - Set actual conversion trigger source and FIFO interrupt trigger
2354 * - If convert_src is TRIG_TIMER, set up the timers.
2357 adccon = PCI230_ADC_FIFO_EN;
2360 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) {
2361 /* Differential - all channels must be differential. */
2363 adccon |= PCI230_ADC_IM_DIF;
2365 /* Single ended - all channels must be single-ended. */
2367 adccon |= PCI230_ADC_IM_SE;
2370 range = CR_RANGE(cmd->chanlist[0]);
2371 devpriv->ai_bipolar = pci230_ai_bipolar[range];
2372 if (devpriv->ai_bipolar) {
2373 adccon |= PCI230_ADC_IR_BIP;
2375 adccon |= PCI230_ADC_IR_UNI;
2377 for (i = 0; i < cmd->chanlist_len; i++) {
2378 unsigned int gainshift;
2380 chan = CR_CHAN(cmd->chanlist[i]);
2381 range = CR_RANGE(cmd->chanlist[i]);
2383 gainshift = 2 * chan;
2384 if (devpriv->hwver == 0) {
2385 /* Original PCI230/260 expects both inputs of
2386 * the differential channel to be enabled. */
2387 adcen |= 3 << gainshift;
2389 /* PCI230+/260+ expects only one input of the
2390 * differential channel to be enabled. */
2391 adcen |= 1 << gainshift;
2394 gainshift = (chan & ~1);
2397 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift))
2398 | (pci230_ai_gain[range] << gainshift);
2401 /* Set channel scan list. */
2402 outw(adcen, dev->iobase + PCI230_ADCEN);
2404 /* Set channel gains. */
2405 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
2407 /* Set counter/timer 2 output high for use as the initial start
2408 * conversion source. */
2409 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
2411 /* Temporarily use CT2 output as conversion trigger source and
2412 * temporarily set FIFO interrupt trigger level to 'full'. */
2413 adccon |= PCI230_ADC_INT_FIFO_FULL | PCI230_ADC_TRIG_Z2CT2;
2415 /* Enable and reset FIFO, specify FIFO trigger level full, specify
2416 * uni/bip, se/diff, and temporarily set the start conversion source
2417 * to CT2 output. Note that CT2 output is currently high, and this
2418 * will produce a false conversion trigger on some versions of the
2419 * PCI230/260, but that will be dealt with later. */
2420 devpriv->adccon = adccon;
2421 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
2424 /* Failure to include this will result in the first few channels'-worth
2425 * of data being corrupt, normally manifesting itself by large negative
2426 * voltages. It seems the board needs time to settle between the first
2427 * FIFO reset (above) and the second FIFO reset (below). Setting the
2428 * channel gains and scan list _before_ the first FIFO reset also
2429 * helps, though only slightly. */
2432 /* Reset FIFO again. */
2433 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
2435 if (cmd->convert_src == TRIG_TIMER) {
2436 /* Set up CT2 as conversion timer, but gate it off for now.
2437 * Note, counter/timer output 2 can be monitored on the
2438 * connector: PCI230 pin 21, PCI260 pin 18. */
2439 zgat = GAT_CONFIG(2, GAT_GND);
2440 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2441 /* Set counter/timer 2 to the specified conversion period. */
2442 pci230_ct_setup_ns_mode(dev, 2, I8254_MODE3, cmd->convert_arg,
2443 cmd->flags & TRIG_ROUND_MASK);
2444 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2446 * Set up monostable on CT0 output for scan timing. A
2447 * rising edge on the trigger (gate) input of CT0 will
2448 * trigger the monostable, causing its output to go low
2449 * for the configured period. The period depends on
2450 * the conversion period and the number of conversions
2453 * Set the trigger high before setting up the
2454 * monostable to stop it triggering. The trigger
2455 * source will be changed later.
2457 zgat = GAT_CONFIG(0, GAT_VCC);
2458 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2459 pci230_ct_setup_ns_mode(dev, 0, I8254_MODE1,
2460 ((uint64_t) cmd->convert_arg
2461 * cmd->scan_end_arg), TRIG_ROUND_UP);
2462 if (cmd->scan_begin_src == TRIG_TIMER) {
2464 * Monostable on CT0 will be triggered by
2465 * output of CT1 at configured scan frequency.
2467 * Set up CT1 but gate it off for now.
2469 zgat = GAT_CONFIG(1, GAT_GND);
2470 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2471 pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
2472 cmd->scan_begin_arg,
2473 cmd->flags & TRIG_ROUND_MASK);
2478 if (cmd->start_src == TRIG_INT) {
2479 s->async->inttrig = pci230_ai_inttrig_start;
2482 pci230_ai_start(dev, s);
2488 static unsigned int divide_ns(uint64_t ns, unsigned int timebase,
2489 unsigned int round_mode)
2495 rem = do_div(div, timebase);
2496 round_mode &= TRIG_ROUND_MASK;
2497 switch (round_mode) {
2499 case TRIG_ROUND_NEAREST:
2500 div += (rem + (timebase / 2)) / timebase;
2502 case TRIG_ROUND_DOWN:
2505 div += (rem + timebase - 1) / timebase;
2508 return div > UINT_MAX ? UINT_MAX : (unsigned int)div;
2511 /* Given desired period in ns, returns the required internal clock source
2512 * and gets the initial count. */
2513 static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count,
2514 unsigned int round_mode)
2516 unsigned int clk_src, cnt;
2518 for (clk_src = CLK_10MHZ;; clk_src++) {
2519 cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode);
2520 if ((cnt <= 65536) || (clk_src == CLK_1KHZ)) {
2528 static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round)
2531 unsigned int clk_src;
2533 clk_src = pci230_choose_clk_count(*ns, &count, round);
2534 *ns = count * pci230_timebase[clk_src];
2538 static void pci230_ct_setup_ns_mode(comedi_device * dev, unsigned int ct,
2539 unsigned int mode, uint64_t ns, unsigned int round)
2541 unsigned int clk_src;
2545 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode);
2546 /* Determine clock source and count. */
2547 clk_src = pci230_choose_clk_count(ns, &count, round);
2548 /* Program clock source. */
2549 outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE);
2550 /* Set initial count. */
2551 if (count >= 65536) {
2554 i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count);
2557 static void pci230_cancel_ct(comedi_device * dev, unsigned int ct)
2559 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct,
2561 /* Counter ct, 8254 mode 1, initial count not written. */
2564 /* Interrupt handler */
2565 static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG)
2567 unsigned char status_int, valid_status_int;
2568 comedi_device *dev = (comedi_device *) d;
2569 comedi_subdevice *s;
2570 unsigned long irqflags;
2572 /* Read interrupt status/enable register. */
2573 status_int = inb(devpriv->iobase1 + PCI230_INT_STAT);
2575 if (status_int == PCI230_INT_DISABLE) {
2579 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2580 valid_status_int = devpriv->int_en & status_int;
2581 /* Disable triggered interrupts.
2582 * (Only those interrupts that need re-enabling, are, later in the
2584 devpriv->ier = devpriv->int_en & ~status_int;
2585 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2586 devpriv->intr_running = 1;
2587 devpriv->intr_cpuid = THISCPU;
2588 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2591 * Check the source of interrupt and handle it.
2592 * The PCI230 can cope with concurrent ADC, DAC, PPI C0 and C3
2593 * interrupts. However, at present (Comedi-0.7.60) does not allow
2594 * concurrent execution of commands, instructions or a mixture of the
2598 if ((valid_status_int & PCI230_INT_ZCLK_CT1) != 0) {
2599 s = dev->write_subdev;
2600 pci230_handle_ao_nofifo(dev, s);
2601 comedi_event(dev, s);
2604 if ((valid_status_int & PCI230P2_INT_DAC) != 0) {
2605 s = dev->write_subdev;
2606 pci230_handle_ao_fifo(dev, s);
2607 comedi_event(dev, s);
2610 if ((valid_status_int & PCI230_INT_ADC) != 0) {
2611 s = dev->read_subdev;
2612 pci230_handle_ai(dev, s);
2613 comedi_event(dev, s);
2616 /* Reenable interrupts. */
2617 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2618 if (devpriv->ier != devpriv->int_en) {
2619 devpriv->ier = devpriv->int_en;
2620 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2622 devpriv->intr_running = 0;
2623 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2628 static void pci230_handle_ao_nofifo(comedi_device * dev, comedi_subdevice * s)
2632 comedi_async *async = s->async;
2633 comedi_cmd *cmd = &async->cmd;
2635 if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
2639 for (i = 0; i < cmd->chanlist_len; i++) {
2640 /* Read sample from Comedi's circular buffer. */
2641 ret = comedi_buf_get(s->async, &data);
2643 s->async->events |= COMEDI_CB_OVERFLOW;
2644 pci230_ao_stop(dev, s);
2645 comedi_error(dev, "AO buffer underrun");
2648 /* Write value to DAC. */
2649 pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
2652 async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
2653 if (!devpriv->ao_continuous) {
2654 devpriv->ao_scan_count--;
2655 if (devpriv->ao_scan_count == 0) {
2656 /* End of acquisition. */
2657 async->events |= COMEDI_CB_EOA;
2658 pci230_ao_stop(dev, s);
2663 /* Loads DAC FIFO (if using it) from buffer. */
2664 /* Returns 0 if AO finished due to completion or error, 1 if still going. */
2665 static int pci230_handle_ao_fifo(comedi_device * dev, comedi_subdevice * s)
2667 comedi_async *async = s->async;
2668 comedi_cmd *cmd = &async->cmd;
2669 unsigned int num_scans;
2671 unsigned short dacstat;
2673 unsigned int bytes_per_scan;
2674 unsigned int events = 0;
2677 /* Get DAC FIFO status. */
2678 dacstat = inw(dev->iobase + PCI230_DACCON);
2680 /* Determine number of scans available in buffer. */
2681 bytes_per_scan = cmd->chanlist_len * sizeof(sampl_t);
2682 num_scans = comedi_buf_read_n_available(async) / bytes_per_scan;
2683 if (!devpriv->ao_continuous) {
2684 /* Fixed number of scans. */
2685 if (num_scans > devpriv->ao_scan_count) {
2686 num_scans = devpriv->ao_scan_count;
2688 if (devpriv->ao_scan_count == 0) {
2689 /* End of acquisition. */
2690 events |= COMEDI_CB_EOA;
2694 /* Check for FIFO underrun. */
2695 if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
2696 comedi_error(dev, "AO FIFO underrun");
2697 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2699 /* Check for buffer underrun if FIFO less than half full
2700 * (otherwise there will be loads of "DAC FIFO not half full"
2702 if ((num_scans == 0)
2703 && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) {
2704 comedi_error(dev, "AO buffer underrun");
2705 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2709 /* Determine how much room is in the FIFO (in samples). */
2710 if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0) {
2711 room = PCI230P2_DAC_FIFOROOM_FULL;
2712 } else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0) {
2713 room = PCI230P2_DAC_FIFOROOM_HALFTOFULL;
2714 } else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0) {
2715 room = PCI230P2_DAC_FIFOROOM_EMPTY;
2717 room = PCI230P2_DAC_FIFOROOM_ONETOHALF;
2719 /* Convert room to number of scans that can be added. */
2720 room /= cmd->chanlist_len;
2721 /* Determine number of scans to process. */
2722 if (num_scans > room) {
2725 /* Process scans. */
2726 for (n = 0; n < num_scans; n++) {
2727 for (i = 0; i < cmd->chanlist_len; i++) {
2730 comedi_buf_get(async, &datum);
2731 pci230_ao_write_fifo(dev, datum,
2732 CR_CHAN(cmd->chanlist[i]));
2735 events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
2736 if (!devpriv->ao_continuous) {
2737 devpriv->ao_scan_count -= num_scans;
2738 if (devpriv->ao_scan_count == 0) {
2739 /* All data for the command has been written
2740 * to FIFO. Set FIFO interrupt trigger level
2742 devpriv->daccon = (devpriv->daccon
2743 & ~PCI230P2_DAC_INT_FIFO_MASK)
2744 | PCI230P2_DAC_INT_FIFO_EMPTY;
2745 outw(devpriv->daccon,
2746 dev->iobase + PCI230_DACCON);
2749 /* Check if FIFO underrun occurred while writing to FIFO. */
2750 dacstat = inw(dev->iobase + PCI230_DACCON);
2751 if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
2752 comedi_error(dev, "AO FIFO underrun");
2753 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2756 if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
2758 /* Stopping AO due to completion or error. */
2759 pci230_ao_stop(dev, s);
2764 async->events |= events;
2768 static void pci230_handle_ai(comedi_device * dev, comedi_subdevice * s)
2770 unsigned int events = 0;
2771 unsigned int status_fifo;
2774 unsigned int fifoamount;
2775 comedi_async *async = s->async;
2776 unsigned int scanlen = async->cmd.scan_end_arg;
2778 /* Determine number of samples to read. */
2779 if (devpriv->ai_continuous) {
2780 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2781 } else if (devpriv->ai_scan_count == 0) {
2783 } else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL)
2784 || (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) {
2785 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2787 todo = (devpriv->ai_scan_count * scanlen)
2788 - devpriv->ai_scan_pos;
2789 if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL) {
2790 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2799 for (i = 0; i < todo; i++) {
2800 if (fifoamount == 0) {
2801 /* Read FIFO state. */
2802 status_fifo = inw(dev->iobase + PCI230_ADCCON);
2804 if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) {
2805 /* Report error otherwise FIFO overruns will go
2806 * unnoticed by the caller. */
2807 comedi_error(dev, "AI FIFO overrun");
2808 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2810 } else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) {
2813 } else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) {
2814 /* FIFO half full. */
2815 fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
2817 /* FIFO not empty. */
2818 if (devpriv->hwver > 0) {
2819 /* Read PCI230+/260+ ADC FIFO level. */
2820 fifoamount = inw(dev->iobase
2821 + PCI230P_ADCFFLEV);
2822 if (fifoamount == 0) {
2823 /* Shouldn't happen. */
2832 /* Read sample and store in Comedi's circular buffer. */
2833 if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) {
2834 events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
2835 comedi_error(dev, "AI buffer overflow");
2839 devpriv->ai_scan_pos++;
2840 if (devpriv->ai_scan_pos == scanlen) {
2842 devpriv->ai_scan_pos = 0;
2843 devpriv->ai_scan_count--;
2844 async->events |= COMEDI_CB_EOS;
2848 if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
2849 /* End of acquisition. */
2850 events |= COMEDI_CB_EOA;
2852 /* More samples required, tell Comedi to block. */
2853 events |= COMEDI_CB_BLOCK;
2855 async->events |= events;
2857 if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2858 COMEDI_CB_OVERFLOW)) != 0) {
2859 /* disable hardware conversions */
2860 pci230_ai_stop(dev, s);
2862 /* update FIFO interrupt trigger level */
2863 pci230_ai_update_fifo_trigger_level(dev, s);
2867 static void pci230_ao_stop(comedi_device * dev, comedi_subdevice * s)
2869 unsigned long irqflags;
2870 unsigned char intsrc;
2874 comedi_spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
2875 started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state);
2876 comedi_spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
2881 cmd = &s->async->cmd;
2882 if (cmd->scan_begin_src == TRIG_TIMER) {
2883 /* Stop scan rate generator. */
2884 pci230_cancel_ct(dev, 1);
2887 /* Determine interrupt source. */
2888 if (devpriv->hwver < 2) {
2889 /* Not using DAC FIFO. Using CT1 interrupt. */
2890 intsrc = PCI230_INT_ZCLK_CT1;
2892 /* Using DAC FIFO interrupt. */
2893 intsrc = PCI230P2_INT_DAC;
2895 /* Disable interrupt and wait for interrupt routine to finish running
2896 * unless we are called from the interrupt routine. */
2897 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2898 devpriv->int_en &= ~intsrc;
2899 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
2900 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2901 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2903 if (devpriv->ier != devpriv->int_en) {
2904 devpriv->ier = devpriv->int_en;
2905 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2907 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2909 if (devpriv->hwver >= 2) {
2910 /* Using DAC FIFO. Reset FIFO, clear underrun error,
2912 devpriv->daccon &= PCI230_DAC_OR_MASK;
2913 outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET
2914 | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
2915 dev->iobase + PCI230_DACCON);
2918 /* Release resources. */
2919 put_all_resources(dev, OWNER_AOCMD);
2922 static int pci230_ao_cancel(comedi_device * dev, comedi_subdevice * s)
2924 pci230_ao_stop(dev, s);
2928 static void pci230_ai_stop(comedi_device * dev, comedi_subdevice * s)
2930 unsigned long irqflags;
2934 comedi_spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2935 started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state);
2936 comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2941 cmd = &s->async->cmd;
2942 if (cmd->convert_src == TRIG_TIMER) {
2943 /* Stop conversion rate generator. */
2944 pci230_cancel_ct(dev, 2);
2946 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2947 /* Stop scan period monostable. */
2948 pci230_cancel_ct(dev, 0);
2951 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2952 /* Disable ADC interrupt and wait for interrupt routine to finish
2953 * running unless we are called from the interrupt routine. */
2954 devpriv->int_en &= ~PCI230_INT_ADC;
2955 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
2956 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2957 comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2959 if (devpriv->ier != devpriv->int_en) {
2960 devpriv->ier = devpriv->int_en;
2961 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2963 comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2965 /* Reset FIFO, disable FIFO and set start conversion source to none.
2966 * Keep se/diff and bip/uni settings */
2967 devpriv->adccon = (devpriv->adccon & (PCI230_ADC_IR_MASK
2968 | PCI230_ADC_IM_MASK)) | PCI230_ADC_TRIG_NONE;
2969 outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
2970 dev->iobase + PCI230_ADCCON);
2972 /* Release resources. */
2973 put_all_resources(dev, OWNER_AICMD);
2976 static int pci230_ai_cancel(comedi_device * dev, comedi_subdevice * s)
2978 pci230_ai_stop(dev, s);