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.
191 #include "../comedidev.h"
193 #include <linux/delay.h>
194 #include <linux/interrupt.h>
196 #include "comedi_pci.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
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 */
415 RES_Z2CT0
, /* Z2-CT0 */
416 RES_Z2CT1
, /* Z2-CT1 */
417 RES_Z2CT2
, /* Z2-CT2 */
418 NUM_RESOURCES
/* Number of (potentially) shared resources. */
422 OWNER_NONE
, /* Not owned */
423 OWNER_AICMD
, /* Owned by AI command */
424 OWNER_AOCMD
/* Owned by AO command */
431 /* Combine old and new bits. */
432 #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
434 /* A generic null function pointer value. */
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
{
455 unsigned int min_hwver
; /* Minimum hardware version supported. */
457 static const struct pci230_board pci230_boards
[] = {
460 .id
= PCI_DEVICE_ID_PCI230
,
470 .id
= PCI_DEVICE_ID_PCI260
,
480 .id
= PCI_DEVICE_ID_PCI230
,
489 .id
= PCI_DEVICE_ID_PCI260
,
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
532 unsigned int ai_scan_pos
; /* Current position within analogue
534 unsigned int ao_scan_count
; /* Number of analogue output scans
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
548 unsigned char ao_continuous
; /* Flag set when cmd->stop_src ==
549 * TRIG_NONE - user chooses to stop
550 * continuous conversion by
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, {
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, {
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
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
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)
641 retval
= comedi_driver_register(&driver_amplc_pci230
);
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
,
662 static int pci230_ao_winsn(struct comedi_device
*dev
,
663 struct comedi_subdevice
*s
, struct comedi_insn
*insn
,
665 static int pci230_ao_rinsn(struct comedi_device
*dev
,
666 struct comedi_subdevice
*s
, struct comedi_insn
*insn
,
668 static void pci230_ct_setup_ns_mode(struct comedi_device
*dev
, unsigned int ct
,
669 unsigned int mode
, uint64_t ns
,
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
)
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);
715 static inline unsigned short pci230_ao_mangle_datum(struct comedi_device
*dev
,
718 /* If a bipolar range was specified, mangle it (straight binary->twos
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)
744 static inline void pci230_ao_write_fifo(struct comedi_device
*dev
, short datum
,
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
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)
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
);
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
))
789 if (pci_dev
->vendor
!= PCI_VENDOR_ID_AMPLICON
)
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
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
802 if (pci_resource_len(pci_dev
, 3)
804 /* Not a '+' model. */
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
];
817 if (i
< n_pci230_boards
)
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. */
832 /* TODO: temporarily enable the PCI
833 * device and read the hardware version
834 * register. For now, assume it's
844 printk("comedi%d: No %s card found\n", dev
->minor
,
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
);
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
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
);
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
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. */
923 devpriv
->adccon
= PCI230_ADC_TRIG_NONE
| PCI230_ADC_IM_SE
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
);
934 printk("comedi%d: unable to register irq, "
935 "commands will not be available %d\n", dev
->minor
,
936 devpriv
->pci_dev
->irq
);
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)
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. */
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
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
;
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
));
1000 s
->type
= COMEDI_SUBD_UNUSED
;
1003 printk("comedi%d: attached\n", dev
->minor
);
1009 * _detach is called to deconfigure a device. It should deallocate
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);
1025 free_irq(dev
->irq
, dev
);
1028 if (devpriv
->pci_dev
) {
1030 comedi_pci_disable(devpriv
->pci_dev
);
1032 pci_dev_put(devpriv
->pci_dev
);
1039 static int get_resources(struct comedi_device
*dev
, unsigned int res_mask
,
1040 unsigned char owner
)
1045 unsigned int claimed
;
1046 unsigned long irqflags
;
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) {
1055 if (devpriv
->res_owner
[i
] == OWNER_NONE
) {
1056 devpriv
->res_owner
[i
] = owner
;
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
]
1071 spin_unlock_irqrestore(&devpriv
->res_spinlock
, irqflags
);
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
)
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) {
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
,
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
) {
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);
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
) {
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
;
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
;
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
;
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
1191 i8254_set_mode(devpriv
->iobase1
+ PCI230_Z2_CT_BASE
, 0, 2,
1193 i8254_set_mode(devpriv
->iobase1
+ PCI230_Z2_CT_BASE
, 0, 2,
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
))
1205 /* printk() should be used instead of printk()
1206 * whenever the code can be called from real-time. */
1207 printk("timeout\n");
1212 data
[n
] = pci230_ai_read(dev
);
1215 /* return the number of samples read/written */
1220 * COMEDI_SUBD_AO instructions;
1222 static int pci230_ao_winsn(struct comedi_device
*dev
,
1223 struct comedi_subdevice
*s
, struct comedi_insn
*insn
,
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 */
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
,
1256 int chan
= CR_CHAN(insn
->chanspec
);
1258 for (i
= 0; i
< insn
->n
; i
++)
1259 data
[i
] = devpriv
->ao_readback
[chan
];
1264 static int pci230_ao_cmdtest(struct comedi_device
*dev
,
1265 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
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
1281 tmp
= cmd
->start_src
;
1282 cmd
->start_src
&= TRIG_INT
;
1283 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
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
;
1290 cmd
->scan_begin_src
&= TRIG_TIMER
| TRIG_INT
;
1292 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
1295 tmp
= cmd
->convert_src
;
1296 cmd
->convert_src
&= TRIG_NOW
;
1297 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
1300 tmp
= cmd
->scan_end_src
;
1301 cmd
->scan_end_src
&= TRIG_COUNT
;
1302 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
1305 tmp
= cmd
->stop_src
;
1306 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
1307 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
1313 /* Step 2: make sure trigger sources are unique and mutually compatible
1314 * "source conflict" returned by comedilib to user mode process
1317 /* these tests are true if more than one _src bit is set */
1318 if ((cmd
->start_src
& (cmd
->start_src
- 1)) != 0)
1320 if ((cmd
->scan_begin_src
& (cmd
->scan_begin_src
- 1)) != 0)
1322 if ((cmd
->convert_src
& (cmd
->convert_src
- 1)) != 0)
1324 if ((cmd
->scan_end_src
& (cmd
->scan_end_src
- 1)) != 0)
1326 if ((cmd
->stop_src
& (cmd
->stop_src
- 1)) != 0)
1332 /* Step 3: make sure arguments are trivially compatible.
1333 * "invalid argument" returned by comedilib to user mode process
1336 if (cmd
->start_arg
!= 0) {
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
) {
1348 if (cmd
->scan_begin_arg
< MAX_SPEED_AO
) {
1349 cmd
->scan_begin_arg
= MAX_SPEED_AO
;
1352 if (cmd
->scan_begin_arg
> MIN_SPEED_AO
) {
1353 cmd
->scan_begin_arg
= MIN_SPEED_AO
;
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,
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
));
1376 if (cmd
->scan_begin_arg
!= 0) {
1377 cmd
->scan_begin_arg
= 0;
1383 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1384 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1387 if (cmd
->stop_src
== TRIG_NONE
) {
1389 if (cmd
->stop_arg
!= 0) {
1398 /* Step 4: fix up any arguments.
1399 * "argument conflict" returned by comedilib to user mode process
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
)
1413 /* Step 5: check channel list if it exists. */
1415 if (cmd
->chanlist
&& cmd
->chanlist_len
> 0) {
1418 range_err
= (1 << 1)
1420 unsigned int errors
;
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]);
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
)
1435 /* Ranges must be the same. */
1436 if (range
!= first_range
)
1437 errors
|= range_err
;
1443 if ((errors
& seq_err
) != 0) {
1444 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1445 "channel numbers must increase\n",
1448 if ((errors
& range_err
) != 0) {
1449 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1450 "channels must have the same range\n",
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
;
1471 spin_lock_irqsave(&devpriv
->ao_stop_spinlock
, irqflags
);
1472 if (test_bit(AO_CMD_STARTED
, &devpriv
->state
)) {
1474 if (devpriv
->hwver
< 2) {
1475 /* Not using DAC FIFO. */
1476 spin_unlock_irqrestore(&devpriv
->ao_stop_spinlock
,
1478 pci230_handle_ao_nofifo(dev
, s
);
1479 comedi_event(dev
, s
);
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
,
1487 /* Delay. Should driver be responsible for this? */
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
);
1508 if (devpriv
->hwver
>= 2) {
1509 /* Using DAC FIFO. */
1510 unsigned short scantrig
;
1513 /* Preload FIFO data. */
1514 run
= pci230_handle_ao_fifo(dev
, s
);
1515 comedi_event(dev
, s
);
1520 /* Set scan trigger source. */
1521 switch (cmd
->scan_begin_src
) {
1523 scantrig
= PCI230P2_DAC_TRIG_Z2CT1
;
1526 /* Trigger on EXTTRIG/EXTCONVCLK pin. */
1527 if ((cmd
->scan_begin_arg
& CR_INVERT
) == 0) {
1529 scantrig
= PCI230P2_DAC_TRIG_EXTP
;
1532 scantrig
= PCI230P2_DAC_TRIG_EXTN
;
1536 scantrig
= PCI230P2_DAC_TRIG_SW
;
1539 /* Shouldn't get here. */
1540 scantrig
= PCI230P2_DAC_TRIG_NONE
;
1543 devpriv
->daccon
= (devpriv
->daccon
1544 & ~PCI230P2_DAC_TRIG_MASK
) |
1546 outw(devpriv
->daccon
, dev
->iobase
+ PCI230_DACCON
);
1549 switch (cmd
->scan_begin_src
) {
1551 if (devpriv
->hwver
< 2) {
1552 /* Not using DAC FIFO. */
1553 /* Enable CT1 timer interrupt. */
1554 spin_lock_irqsave(&devpriv
->isr_spinlock
,
1556 devpriv
->int_en
|= PCI230_INT_ZCLK_CT1
;
1557 devpriv
->ier
|= PCI230_INT_ZCLK_CT1
;
1559 devpriv
->iobase1
+ PCI230_INT_SCE
);
1560 spin_unlock_irqrestore(&devpriv
->isr_spinlock
,
1563 /* Set CT1 gate high to start counting. */
1564 outb(GAT_CONFIG(1, GAT_VCC
),
1565 devpriv
->iobase1
+ PCI230_ZGAT_SCE
);
1568 async
->inttrig
= pci230_ao_inttrig_scan_begin
;
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
,
1583 static int pci230_ao_inttrig_start(struct comedi_device
*dev
,
1584 struct comedi_subdevice
*s
,
1585 unsigned int trig_num
)
1590 s
->async
->inttrig
= NULLFUNC
;
1591 pci230_ao_start(dev
, s
);
1596 static int pci230_ao_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1598 unsigned short daccon
;
1601 /* Get the command. */
1602 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1604 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
1606 if (!get_one_resource(dev
, RES_Z2CT1
, OWNER_AOCMD
))
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;
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
;
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
);
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
;
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
;
1673 static int pci230_ai_check_scan_period(struct comedi_cmd
*cmd
)
1675 unsigned int min_scan_period
, chanlist_len
;
1678 chanlist_len
= cmd
->chanlist_len
;
1679 if (cmd
->chanlist_len
== 0)
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
;
1689 if (cmd
->scan_begin_arg
< min_scan_period
) {
1690 cmd
->scan_begin_arg
= min_scan_period
;
1697 static int pci230_ai_cmdtest(struct comedi_device
*dev
,
1698 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
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
1714 tmp
= cmd
->start_src
;
1715 cmd
->start_src
&= TRIG_NOW
| TRIG_INT
;
1716 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
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
1728 cmd
->scan_begin_src
&= TRIG_FOLLOW
| TRIG_TIMER
| TRIG_INT
;
1730 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
1733 tmp
= cmd
->convert_src
;
1734 cmd
->convert_src
&= TRIG_TIMER
| TRIG_INT
| TRIG_EXT
;
1735 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
1738 tmp
= cmd
->scan_end_src
;
1739 cmd
->scan_end_src
&= TRIG_COUNT
;
1740 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
1743 tmp
= cmd
->stop_src
;
1744 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
1745 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
1751 /* Step 2: make sure trigger sources are unique and mutually compatible
1752 * "source conflict" returned by comedilib to user mode process
1755 /* these tests are true if more than one _src bit is set */
1756 if ((cmd
->start_src
& (cmd
->start_src
- 1)) != 0)
1758 if ((cmd
->scan_begin_src
& (cmd
->scan_begin_src
- 1)) != 0)
1760 if ((cmd
->convert_src
& (cmd
->convert_src
- 1)) != 0)
1762 if ((cmd
->scan_end_src
& (cmd
->scan_end_src
- 1)) != 0)
1764 if ((cmd
->stop_src
& (cmd
->stop_src
- 1)) != 0)
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
))
1776 /* Step 3: make sure arguments are trivially compatible.
1777 * "invalid argument" returned by comedilib to user mode process
1780 if (cmd
->start_arg
!= 0) {
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
;
1803 max_speed_ai
= MAX_SPEED_AI_SE
;
1806 /* No channel list. Assume single-ended. */
1807 max_speed_ai
= MAX_SPEED_AI_SE
;
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
;
1818 if (cmd
->convert_arg
> MIN_SPEED_AI
) {
1819 cmd
->convert_arg
= MIN_SPEED_AI
;
1822 } else if (cmd
->convert_src
== TRIG_EXT
) {
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,
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
))
1842 /* Set CR_EDGE, preserve CR_INVERT. */
1844 COMBINE(cmd
->start_arg
, (CR_EDGE
| 0),
1845 CR_FLAGS_MASK
& ~CR_INVERT
);
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;
1859 if (cmd
->convert_arg
!= 0) {
1860 cmd
->convert_arg
= 0;
1865 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1866 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1870 if (cmd
->stop_src
== TRIG_NONE
) {
1871 if (cmd
->stop_arg
!= 0) {
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,
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
);
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
))
1898 if (cmd
->scan_begin_arg
!= 0) {
1899 cmd
->scan_begin_arg
= 0;
1907 /* Step 4: fix up any arguments.
1908 * "argument conflict" returned by comedilib to user mode process
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
)
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
,
1928 pci230_ai_check_scan_period(cmd
);
1930 if (tmp
!= cmd
->scan_begin_arg
)
1937 /* Step 5: check channel list if it exists. */
1939 if (cmd
->chanlist
&& cmd
->chanlist_len
> 0) {
1942 rangepair_err
= 1 << 1,
1943 polarity_err
= 1 << 2,
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
;
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
;
1972 /* Channel numbers must strictly increase or
1973 * subsequence must repeat exactly. */
1974 if ((chan
<= prev_chan
)
1975 && (subseq_len
== 0)) {
1978 if ((subseq_len
> 0)
1979 && (cmd
->chanlist
[n
] !=
1980 cmd
->chanlist
[n
% subseq_len
])) {
1983 /* Channels must have same AREF. */
1984 if (aref
!= prev_aref
)
1987 /* Channel ranges must have same polarity. */
1988 if (polarity
!= prev_polarity
)
1989 errors
|= polarity_err
;
1991 /* Single-ended channel pairs must have same
1993 if ((aref
!= AREF_DIFF
)
1994 && (((chan
^ prev_chan
) & ~1) == 0)
1995 && (range
!= prev_range
)) {
1996 errors
|= rangepair_err
;
2002 prev_polarity
= polarity
;
2004 if (subseq_len
== 0) {
2005 /* Subsequence is whole sequence. */
2008 /* If channel list is a repeating subsequence, need a whole
2009 * number of repeats. */
2010 if ((n
% subseq_len
) != 0)
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
;
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",
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",
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
);
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
;
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
;
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
;
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
;
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
;
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
;
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,
2142 i8254_set_mode(devpriv
->iobase1
+ PCI230_Z2_CT_BASE
, 0, 2,
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 */
2155 /* single-ended or PCI230+/260+ */
2158 spin_unlock_irqrestore(&devpriv
->ai_stop_spinlock
, irqflags
);
2161 spin_unlock_irqrestore(&devpriv
->ai_stop_spinlock
, irqflags
);
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
;
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
);
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
);
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
) {
2216 conv
= PCI230_ADC_TRIG_NONE
;
2219 /* Using CT2 output. */
2220 conv
= PCI230_ADC_TRIG_Z2CT2
;
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
;
2228 /* Trigger on -ve edge. */
2229 conv
= PCI230_ADC_TRIG_EXTN
;
2232 /* Backwards compatibility. */
2233 if (cmd
->convert_arg
!= 0) {
2234 /* Trigger on +ve edge. */
2235 conv
= PCI230_ADC_TRIG_EXTP
;
2237 /* Trigger on -ve edge. */
2238 conv
= PCI230_ADC_TRIG_EXTN
;
2243 /* Use CT2 output for software trigger due to problems
2244 * in differential mode on PCI230/260. */
2245 conv
= PCI230_ADC_TRIG_Z2CT2
;
2248 devpriv
->adccon
= (devpriv
->adccon
& ~PCI230_ADC_TRIG_MASK
)
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
2256 pci230_ai_update_fifo_trigger_level(dev
, s
);
2257 if (cmd
->convert_src
== TRIG_TIMER
) {
2258 /* Update timer gates. */
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
);
2266 /* Conversion timer CT2 needs to be gated on
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
) {
2275 zgat
= GAT_CONFIG(0, GAT_VCC
);
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
2287 zgat
= GAT_CONFIG(0, GAT_EXT
);
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
);
2299 * Monostable CT0 is triggered by
2300 * inttrig function waggling the CT0
2303 zgat
= GAT_CONFIG(0, GAT_VCC
);
2306 outb(zgat
, devpriv
->iobase1
+ PCI230_ZGAT_SCE
);
2307 switch (cmd
->scan_begin_src
) {
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
2317 pci230_ai_inttrig_scan_begin
;
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
)
2335 s
->async
->inttrig
= NULLFUNC
;
2336 pci230_ai_start(dev
, s
);
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
;
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.
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
))
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;
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. */
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
2394 * - Enable ADC FIFO level interrupt.
2395 * - Set actual conversion trigger source and FIFO interrupt trigger
2397 * - If convert_src is TRIG_TIMER, set up the timers.
2400 adccon
= PCI230_ADC_FIFO_EN
;
2403 if (CR_AREF(cmd
->chanlist
[0]) == AREF_DIFF
) {
2404 /* Differential - all channels must be differential. */
2406 adccon
|= PCI230_ADC_IM_DIF
;
2408 /* Single ended - all channels must be single-ended. */
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
;
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
]);
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
;
2432 /* PCI230+/260+ expects only one input of the
2433 * differential channel to be enabled. */
2434 adcen
|= 1 << gainshift
;
2437 gainshift
= (chan
& ~1);
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
);
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. */
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
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
),
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
,
2524 if (cmd
->start_src
== TRIG_INT
) {
2525 s
->async
->inttrig
= pci230_ai_inttrig_start
;
2528 pci230_ai_start(dev
, s
);
2534 static unsigned int divide_ns(uint64_t ns
, unsigned int timebase
,
2535 unsigned int round_mode
)
2541 rem
= do_div(div
, timebase
);
2542 round_mode
&= TRIG_ROUND_MASK
;
2543 switch (round_mode
) {
2545 case TRIG_ROUND_NEAREST
:
2546 div
+= (rem
+ (timebase
/ 2)) / timebase
;
2548 case TRIG_ROUND_DOWN
:
2551 div
+= (rem
+ timebase
- 1) / timebase
;
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
))
2574 static void pci230_ns_to_single_timer(unsigned int *ns
, unsigned int round
)
2577 unsigned int clk_src
;
2579 clk_src
= pci230_choose_clk_count(*ns
, &count
, round
);
2580 *ns
= count
* pci230_timebase
[clk_src
];
2584 static void pci230_ct_setup_ns_mode(struct comedi_device
*dev
, unsigned int ct
,
2585 unsigned int mode
, uint64_t ns
,
2588 unsigned int clk_src
;
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. */
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
,
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
)
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
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
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
);
2675 static void pci230_handle_ao_nofifo(struct comedi_device
*dev
,
2676 struct comedi_subdevice
*s
)
2680 struct comedi_async
*async
= s
->async
;
2681 struct comedi_cmd
*cmd
= &async
->cmd
;
2683 if (!devpriv
->ao_continuous
&& (devpriv
->ao_scan_count
== 0))
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
);
2691 s
->async
->events
|= COMEDI_CB_OVERFLOW
;
2692 pci230_ao_stop(dev
, s
);
2693 comedi_error(dev
, "AO buffer underrun");
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
;
2720 unsigned short dacstat
;
2722 unsigned int bytes_per_scan
;
2723 unsigned int events
= 0;
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
;
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"
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
;
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
;
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
)
2774 /* Process scans. */
2775 for (n
= 0; n
< num_scans
; n
++) {
2776 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
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
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
))
2808 /* Stopping AO due to completion or error. */
2809 pci230_ao_stop(dev
, s
);
2814 async
->events
|= events
;
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
;
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) {
2834 } else if ((devpriv
->ai_scan_count
> PCI230_ADC_FIFOLEVEL_HALFFULL
)
2835 || (scanlen
> PCI230_ADC_FIFOLEVEL_HALFFULL
)) {
2836 todo
= PCI230_ADC_FIFOLEVEL_HALFFULL
;
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
;
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
;
2861 } else if ((status_fifo
& PCI230_ADC_FIFO_EMPTY
) != 0) {
2864 } else if ((status_fifo
& PCI230_ADC_FIFO_HALF
) != 0) {
2865 /* FIFO half full. */
2866 fifoamount
= PCI230_ADC_FIFOLEVEL_HALFFULL
;
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. */
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");
2890 devpriv
->ai_scan_pos
++;
2891 if (devpriv
->ai_scan_pos
== scanlen
) {
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
;
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
);
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
;
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
);
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
;
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,
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
);
2981 static void pci230_ai_stop(struct comedi_device
*dev
,
2982 struct comedi_subdevice
*s
)
2984 unsigned long irqflags
;
2985 struct comedi_cmd
*cmd
;
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
);
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
);
3038 MODULE_AUTHOR("Comedi http://www.comedi.org");
3039 MODULE_DESCRIPTION("Comedi low-level driver");
3040 MODULE_LICENSE("GPL");