3 comedi/drivers/adl_pci9111.c
5 Hardware driver for PCI9111 ADLink cards:
9 Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 Description: Adlink PCI-9111HR
29 Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
30 Devices: [ADLink] PCI-9111HR (adl_pci9111)
39 - ai_do_cmd mode with the following sources:
42 - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT
43 - convert_src TRIG_TIMER TRIG_EXT
44 - scan_end_src TRIG_COUNT
45 - stop_src TRIG_COUNT TRIG_NONE
47 The scanned channels must be consecutive and start from 0. They must
48 all have the same range and aref.
50 Configuration options:
52 [0] - PCI bus number (optional)
53 [1] - PCI slot number (optional)
55 If bus/slot is not specified, the first available PCI
63 2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
64 a multiple of chanlist_len*convert_arg.
65 2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
66 2002/02/18 Added external trigger support for analog input.
70 - Really test implemented functionality.
71 - Add support for the PCI-9111DG with a probe routine to identify the card type
72 (perhaps with the help of the channel number readback of the A/D Data register).
73 - Add external multiplexer support.
77 #include "../comedidev.h"
79 #include <linux/delay.h>
82 #include "comedi_pci.h"
83 #include "comedi_fc.h"
85 #define PCI9111_DRIVER_NAME "adl_pci9111"
86 #define PCI9111_HR_DEVICE_ID 0x9111
88 // TODO: Add other pci9111 board id
90 #define PCI9111_IO_RANGE 0x0100
92 #define PCI9111_FIFO_HALF_SIZE 512
94 #define PCI9111_AI_CHANNEL_NBR 16
96 #define PCI9111_AI_RESOLUTION 12
97 #define PCI9111_AI_RESOLUTION_MASK 0x0FFF
98 #define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800
100 #define PCI9111_HR_AI_RESOLUTION 16
101 #define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF
102 #define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000
104 #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
105 #define PCI9111_AO_CHANNEL_NBR 1
106 #define PCI9111_AO_RESOLUTION 12
107 #define PCI9111_AO_RESOLUTION_MASK 0x0FFF
108 #define PCI9111_DI_CHANNEL_NBR 16
109 #define PCI9111_DO_CHANNEL_NBR 16
110 #define PCI9111_DO_MASK 0xFFFF
112 #define PCI9111_RANGE_SETTING_DELAY 10
113 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2
114 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100
116 #define PCI9111_8254_CLOCK_PERIOD_NS 500
118 #define PCI9111_8254_COUNTER_0 0x00
119 #define PCI9111_8254_COUNTER_1 0x40
120 #define PCI9111_8254_COUNTER_2 0x80
121 #define PCI9111_8254_COUNTER_LATCH 0x00
122 #define PCI9111_8254_READ_LOAD_LSB_ONLY 0x10
123 #define PCI9111_8254_READ_LOAD_MSB_ONLY 0x20
124 #define PCI9111_8254_READ_LOAD_LSB_MSB 0x30
125 #define PCI9111_8254_MODE_0 0x00
126 #define PCI9111_8254_MODE_1 0x02
127 #define PCI9111_8254_MODE_2 0x04
128 #define PCI9111_8254_MODE_3 0x06
129 #define PCI9111_8254_MODE_4 0x08
130 #define PCI9111_8254_MODE_5 0x0A
131 #define PCI9111_8254_BINARY_COUNTER 0x00
132 #define PCI9111_8254_BCD_COUNTER 0x01
136 #define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 // AD Data stored in FIFO
137 #define PCI9111_REGISTER_DA_OUTPUT 0x00
138 #define PCI9111_REGISTER_DIGITAL_IO 0x02
139 #define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
140 #define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 // Channel selection
141 #define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
142 #define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08
143 #define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08
144 #define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
145 #define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
146 #define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
147 #define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
148 #define PCI9111_REGISTER_8254_COUNTER_0 0x40
149 #define PCI9111_REGISTER_8254_COUNTER_1 0x42
150 #define PCI9111_REGISTER_8254_COUNTER_2 0X44
151 #define PCI9111_REGISTER_8254_CONTROL 0x46
152 #define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
154 #define PCI9111_TRIGGER_MASK 0x0F
155 #define PCI9111_PTRG_OFF (0 << 3)
156 #define PCI9111_PTRG_ON (1 << 3)
157 #define PCI9111_EITS_EXTERNAL (1 << 2)
158 #define PCI9111_EITS_INTERNAL (0 << 2)
159 #define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)
160 #define PCI9111_TPST_TIMER_PACER (1 << 1)
161 #define PCI9111_ASCAN_ON (1 << 0)
162 #define PCI9111_ASCAN_OFF (0 << 0)
164 #define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
165 #define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)
166 #define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
167 #define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
168 #define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
169 #define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)
171 #define PCI9111_CHANNEL_MASK 0x0F
173 #define PCI9111_RANGE_MASK 0x07
174 #define PCI9111_FIFO_EMPTY_MASK 0x10
175 #define PCI9111_FIFO_HALF_FULL_MASK 0x20
176 #define PCI9111_FIFO_FULL_MASK 0x40
177 #define PCI9111_AD_BUSY_MASK 0x80
179 #define PCI9111_IO_BASE dev->iobase
182 * Define inlined function
185 #define pci9111_trigger_and_autoscan_get() \
186 (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
188 #define pci9111_trigger_and_autoscan_set(flags) \
189 outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
191 #define pci9111_interrupt_and_fifo_get() \
192 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03)
194 #define pci9111_interrupt_and_fifo_set(flags) \
195 outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
197 #define pci9111_interrupt_clear() \
198 outb(0,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR)
200 #define pci9111_software_trigger() \
201 outb(0,PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)
203 #define pci9111_fifo_reset() \
204 outb(PCI9111_FFEN_SET_FIFO_ENABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
205 outb(PCI9111_FFEN_SET_FIFO_DISABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
206 outb(PCI9111_FFEN_SET_FIFO_ENABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
208 #define pci9111_is_fifo_full() \
209 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
210 PCI9111_FIFO_FULL_MASK)==0)
212 #define pci9111_is_fifo_half_full() \
213 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
214 PCI9111_FIFO_HALF_FULL_MASK)==0)
216 #define pci9111_is_fifo_empty() \
217 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
218 PCI9111_FIFO_EMPTY_MASK)==0)
220 #define pci9111_ai_channel_set(channel) \
221 outb((channel)&PCI9111_CHANNEL_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
223 #define pci9111_ai_channel_get() \
224 inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK
226 #define pci9111_ai_range_set(range) \
227 outb((range)&PCI9111_RANGE_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
229 #define pci9111_ai_range_get() \
230 inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK
232 #define pci9111_ai_get_data() \
233 ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4)&PCI9111_AI_RESOLUTION_MASK) \
234 ^ PCI9111_AI_RESOLUTION_2_CMP_BIT
236 #define pci9111_hr_ai_get_data() \
237 (inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) & PCI9111_HR_AI_RESOLUTION_MASK) \
238 ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT
240 #define pci9111_ao_set_data(data) \
241 outw(data&PCI9111_AO_RESOLUTION_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
243 #define pci9111_di_get_bits() \
244 inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
246 #define pci9111_do_set_bits(bits) \
247 outw(bits,PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
249 #define pci9111_8254_control_set(flags) \
250 outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL)
252 #define pci9111_8254_counter_0_set(data) \
253 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \
254 outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0)
256 #define pci9111_8254_counter_1_set(data) \
257 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \
258 outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1)
260 #define pci9111_8254_counter_2_set(data) \
261 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
262 outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2)
265 // Function prototypes
268 static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * it);
269 static int pci9111_detach(struct comedi_device * dev);
270 static void pci9111_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s,
271 void *data, unsigned int num_bytes, unsigned int start_chan_index);
273 static const struct comedi_lrange pci9111_hr_ai_range = {
284 static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
285 {PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0,
287 //{ PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
291 MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
294 // Board specification structure
297 struct pci9111_board {
298 const char *name; // driver name
300 int ai_channel_nbr; // num of A/D chans
301 int ao_channel_nbr; // num of D/A chans
302 int ai_resolution; // resolution of A/D
303 int ai_resolution_mask;
304 int ao_resolution; // resolution of D/A
305 int ao_resolution_mask;
306 const struct comedi_lrange *ai_range_list; // rangelist for A/D
307 const struct comedi_lrange *ao_range_list; // rangelist for D/A
308 unsigned int ai_acquisition_period_min_ns;
311 static const struct pci9111_board pci9111_boards[] = {
314 device_id:PCI9111_HR_DEVICE_ID,
315 ai_channel_nbr:PCI9111_AI_CHANNEL_NBR,
316 ao_channel_nbr:PCI9111_AO_CHANNEL_NBR,
317 ai_resolution:PCI9111_HR_AI_RESOLUTION,
318 ai_resolution_mask:PCI9111_HR_AI_RESOLUTION_MASK,
319 ao_resolution:PCI9111_AO_RESOLUTION,
320 ao_resolution_mask:PCI9111_AO_RESOLUTION_MASK,
321 ai_range_list:&pci9111_hr_ai_range,
322 ao_range_list:&range_bipolar10,
323 ai_acquisition_period_min_ns:PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
326 #define pci9111_board_nbr \
327 (sizeof(pci9111_boards)/sizeof(struct pci9111_board))
329 static struct comedi_driver pci9111_driver = {
330 driver_name:PCI9111_DRIVER_NAME,
332 attach:pci9111_attach,
333 detach:pci9111_detach,
336 COMEDI_PCI_INITCLEANUP(pci9111_driver, pci9111_pci_table);
339 // Private data structure
342 struct pci9111_private_data {
343 struct pci_dev *pci_device;
344 unsigned long io_range; // PCI6503 io range
346 unsigned long lcr_io_base; // Local configuration register base address
347 unsigned long lcr_io_range;
352 unsigned int scan_delay;
353 unsigned int chanlist_len;
354 unsigned int chunk_counter;
355 unsigned int chunk_num_samples;
357 int ao_readback; // Last written analog output data
359 int timer_divisor_1; // Divisor values for the 8254 timer pacer
362 int is_valid; // Is device valid
364 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
367 #define dev_private ((struct pci9111_private_data *)dev->private)
369 // ------------------------------------------------------------------
373 // ------------------------------------------------------------------
375 #define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
377 #define PLX9050_LINTI1_ENABLE (1 << 0)
378 #define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
379 #define PLX9050_LINTI1_STATUS (1 << 2)
380 #define PLX9050_LINTI2_ENABLE (1 << 3)
381 #define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
382 #define PLX9050_LINTI2_STATUS (1 << 5)
383 #define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
384 #define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
386 static void plx9050_interrupt_control(unsigned long io_base,
388 bool LINTi1_active_high,
389 bool LINTi2_enable, bool LINTi2_active_high, bool interrupt_enable)
394 flags |= PLX9050_LINTI1_ENABLE;
395 if (LINTi1_active_high)
396 flags |= PLX9050_LINTI1_ACTIVE_HIGH;
398 flags |= PLX9050_LINTI2_ENABLE;
399 if (LINTi2_active_high)
400 flags |= PLX9050_LINTI2_ACTIVE_HIGH;
402 if (interrupt_enable)
403 flags |= PLX9050_PCI_INTERRUPT_ENABLE;
405 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
408 // ------------------------------------------------------------------
410 // MISCELLANEOUS SECTION
412 // ------------------------------------------------------------------
418 static void pci9111_timer_set(struct comedi_device * dev)
420 pci9111_8254_control_set(PCI9111_8254_COUNTER_0 |
421 PCI9111_8254_READ_LOAD_LSB_MSB |
422 PCI9111_8254_MODE_0 | PCI9111_8254_BINARY_COUNTER);
424 pci9111_8254_control_set(PCI9111_8254_COUNTER_1 |
425 PCI9111_8254_READ_LOAD_LSB_MSB |
426 PCI9111_8254_MODE_2 | PCI9111_8254_BINARY_COUNTER);
428 pci9111_8254_control_set(PCI9111_8254_COUNTER_2 |
429 PCI9111_8254_READ_LOAD_LSB_MSB |
430 PCI9111_8254_MODE_2 | PCI9111_8254_BINARY_COUNTER);
434 pci9111_8254_counter_2_set(dev_private->timer_divisor_2);
435 pci9111_8254_counter_1_set(dev_private->timer_divisor_1);
438 enum pci9111_trigger_sources {
444 static void pci9111_trigger_source_set(struct comedi_device * dev,
445 enum pci9111_trigger_sources source)
449 flags = pci9111_trigger_and_autoscan_get() & 0x09;
453 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
457 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
461 flags |= PCI9111_EITS_EXTERNAL;
465 pci9111_trigger_and_autoscan_set(flags);
468 static void pci9111_pretrigger_set(struct comedi_device * dev, bool pretrigger)
472 flags = pci9111_trigger_and_autoscan_get() & 0x07;
475 flags |= PCI9111_PTRG_ON;
477 pci9111_trigger_and_autoscan_set(flags);
480 static void pci9111_autoscan_set(struct comedi_device * dev, bool autoscan)
484 flags = pci9111_trigger_and_autoscan_get() & 0x0e;
487 flags |= PCI9111_ASCAN_ON;
489 pci9111_trigger_and_autoscan_set(flags);
492 enum pci9111_ISC0_sources {
494 irq_on_fifo_half_full
499 irq_on_external_trigger
500 } pci9111_ISC1_sources;
502 static void pci9111_interrupt_source_set(struct comedi_device * dev,
503 enum pci9111_ISC0_sources irq_0_source, pci9111_ISC1_sources irq_1_source)
507 flags = pci9111_interrupt_and_fifo_get() & 0x04;
509 if (irq_0_source == irq_on_fifo_half_full)
510 flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
512 if (irq_1_source == irq_on_external_trigger)
513 flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
515 pci9111_interrupt_and_fifo_set(flags);
518 // ------------------------------------------------------------------
520 // HARDWARE TRIGGERED ANALOG INPUT SECTION
522 // ------------------------------------------------------------------
525 // Cancel analog input autoscan
528 #undef AI_DO_CMD_DEBUG
530 static int pci9111_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
532 // Disable interrupts
534 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
537 pci9111_trigger_source_set(dev, software);
539 pci9111_autoscan_set(dev, false);
541 pci9111_fifo_reset();
543 #ifdef AI_DO_CMD_DEBUG
544 printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
551 // Test analog input command
554 #define pci9111_check_trigger_src(src,flags) \
557 if (!src || tmp != src) error++
560 pci9111_ai_do_cmd_test(struct comedi_device * dev,
561 struct comedi_subdevice * s, struct comedi_cmd * cmd)
565 int range, reference;
567 struct pci9111_board *board = (struct pci9111_board *) dev->board_ptr;
569 // Step 1 : check if trigger are trivialy valid
571 pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
572 pci9111_check_trigger_src(cmd->scan_begin_src,
573 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
574 pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
575 pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
576 pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
581 // step 2 : make sure trigger sources are unique and mutually compatible
583 if (cmd->start_src != TRIG_NOW)
586 if ((cmd->scan_begin_src != TRIG_TIMER) &&
587 (cmd->scan_begin_src != TRIG_FOLLOW) &&
588 (cmd->scan_begin_src != TRIG_EXT))
591 if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) {
594 if ((cmd->convert_src == TRIG_TIMER) &&
595 !((cmd->scan_begin_src == TRIG_TIMER) ||
596 (cmd->scan_begin_src == TRIG_FOLLOW))) {
599 if ((cmd->convert_src == TRIG_EXT) &&
600 !((cmd->scan_begin_src == TRIG_EXT) ||
601 (cmd->scan_begin_src == TRIG_FOLLOW))) {
605 if (cmd->scan_end_src != TRIG_COUNT)
607 if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
613 // Step 3 : make sure arguments are trivialy compatible
615 if (cmd->chanlist_len < 1) {
616 cmd->chanlist_len = 1;
620 if (cmd->chanlist_len > board->ai_channel_nbr) {
621 cmd->chanlist_len = board->ai_channel_nbr;
625 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
630 if ((cmd->convert_src == TRIG_TIMER) &&
631 (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
632 cmd->convert_arg = board->ai_acquisition_period_min_ns;
635 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
636 cmd->convert_arg = 0;
640 if ((cmd->scan_begin_src == TRIG_TIMER) &&
641 (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
642 cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
645 if ((cmd->scan_begin_src == TRIG_FOLLOW) && (cmd->scan_begin_arg != 0)) {
646 cmd->scan_begin_arg = 0;
649 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
650 cmd->scan_begin_arg = 0;
654 if ((cmd->scan_end_src == TRIG_COUNT) &&
655 (cmd->scan_end_arg != cmd->chanlist_len)) {
656 cmd->scan_end_arg = cmd->chanlist_len;
660 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
664 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
672 // Step 4 : fix up any arguments
674 if (cmd->convert_src == TRIG_TIMER) {
675 tmp = cmd->convert_arg;
676 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
677 &(dev_private->timer_divisor_1),
678 &(dev_private->timer_divisor_2),
679 &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);
680 if (tmp != cmd->convert_arg)
683 // There's only one timer on this card, so the scan_begin timer must
684 // be a multiple of chanlist_len*convert_arg
686 if (cmd->scan_begin_src == TRIG_TIMER) {
688 unsigned int scan_begin_min;
689 unsigned int scan_begin_arg;
690 unsigned int scan_factor;
692 scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
694 if (cmd->scan_begin_arg != scan_begin_min) {
695 if (scan_begin_min < cmd->scan_begin_arg) {
697 cmd->scan_begin_arg / scan_begin_min;
698 scan_begin_arg = scan_factor * scan_begin_min;
699 if (cmd->scan_begin_arg != scan_begin_arg) {
700 cmd->scan_begin_arg = scan_begin_arg;
704 cmd->scan_begin_arg = scan_begin_min;
713 // Step 5 : check channel list
717 range = CR_RANGE(cmd->chanlist[0]);
718 reference = CR_AREF(cmd->chanlist[0]);
720 if (cmd->chanlist_len > 1) {
721 for (i = 0; i < cmd->chanlist_len; i++) {
722 if (CR_CHAN(cmd->chanlist[i]) != i) {
724 "entries in chanlist must be consecutive "
725 "channels,counting upwards from 0\n");
728 if (CR_RANGE(cmd->chanlist[i]) != range) {
730 "entries in chanlist must all have the same gain\n");
733 if (CR_AREF(cmd->chanlist[i]) != reference) {
735 "entries in chanlist must all have the same reference\n");
740 if ((CR_CHAN(cmd->chanlist[0]) >
741 (board->ai_channel_nbr - 1))
742 || (CR_CHAN(cmd->chanlist[0]) < 0)) {
744 "channel number is out of limits\n");
758 // Analog input command
761 static int pci9111_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice * subdevice)
763 struct comedi_cmd *async_cmd = &subdevice->async->cmd;
767 "no irq assigned for PCI9111, cannot do hardware conversion");
770 // Set channel scan limit
772 // PCI9111 allows only scanning from channel 0 to channel n
774 // TODO: handle the case of an external multiplexer
777 if (async_cmd->chanlist_len > 1) {
778 pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
779 pci9111_autoscan_set(dev, true);
781 pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
782 pci9111_autoscan_set(dev, false);
787 // This is the same gain on every channel
790 pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
794 switch (async_cmd->stop_src) {
796 dev_private->stop_counter =
797 async_cmd->stop_arg * async_cmd->chanlist_len;
798 dev_private->stop_is_none = 0;
802 dev_private->stop_counter = 0;
803 dev_private->stop_is_none = 1;
807 comedi_error(dev, "Invalid stop trigger");
813 dev_private->scan_delay = 0;
814 switch (async_cmd->convert_src) {
816 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
817 &(dev_private->timer_divisor_1),
818 &(dev_private->timer_divisor_2),
819 &(async_cmd->convert_arg),
820 async_cmd->flags & TRIG_ROUND_MASK);
821 #ifdef AI_DO_CMD_DEBUG
822 printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
823 dev_private->timer_divisor_1,
824 dev_private->timer_divisor_2);
827 pci9111_trigger_source_set(dev, software);
828 pci9111_timer_set(dev);
829 pci9111_fifo_reset();
830 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
832 pci9111_trigger_source_set(dev, timer_pacer);
833 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
836 dev_private->scan_delay =
837 (async_cmd->scan_begin_arg / (async_cmd->convert_arg *
838 async_cmd->chanlist_len)) - 1;
844 pci9111_trigger_source_set(dev, external);
845 pci9111_fifo_reset();
846 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
848 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
854 comedi_error(dev, "Invalid convert trigger");
858 dev_private->stop_counter *= (1 + dev_private->scan_delay);
859 dev_private->chanlist_len = async_cmd->chanlist_len;
860 dev_private->chunk_counter = 0;
861 dev_private->chunk_num_samples =
862 dev_private->chanlist_len * (1 + dev_private->scan_delay);
864 #ifdef AI_DO_CMD_DEBUG
865 printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
866 printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
867 pci9111_trigger_and_autoscan_get());
868 printk(PCI9111_DRIVER_NAME ": irq source = %2x\n",
869 pci9111_interrupt_and_fifo_get());
870 printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
871 printk(PCI9111_DRIVER_NAME ": stop counter = %d\n",
872 dev_private->stop_counter);
873 printk(PCI9111_DRIVER_NAME ": scan delay = %d\n",
874 dev_private->scan_delay);
875 printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n",
876 dev_private->chanlist_len);
877 printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
878 dev_private->chunk_num_samples);
884 static void pci9111_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s,
885 void *data, unsigned int num_bytes, unsigned int start_chan_index)
887 unsigned int i, num_samples = num_bytes / sizeof(short);
890 ((struct pci9111_board *) dev->board_ptr)->ai_resolution;
892 for (i = 0; i < num_samples; i++) {
893 if (resolution == PCI9111_HR_AI_RESOLUTION)
895 (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
896 PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
899 ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
900 PCI9111_AI_RESOLUTION_2_CMP_BIT;
904 // ------------------------------------------------------------------
908 // ------------------------------------------------------------------
910 #undef INTERRUPT_DEBUG
912 static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG)
914 struct comedi_device *dev = p_device;
915 struct comedi_subdevice *subdevice = dev->read_subdev;
916 struct comedi_async *async;
917 unsigned long irq_flags;
918 unsigned char intcsr;
920 if (!dev->attached) {
921 // Ignore interrupt before device fully attached.
922 // Might not even have allocated subdevices yet!
926 async = subdevice->async;
928 comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);
930 // Check if we are source of interrupt
931 intcsr = inb(dev_private->lcr_io_base +
932 PLX9050_REGISTER_INTERRUPT_CONTROL);
933 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
934 && (((intcsr & (PLX9050_LINTI1_ENABLE |
935 PLX9050_LINTI1_STATUS))
937 (PLX9050_LINTI1_ENABLE |
938 PLX9050_LINTI1_STATUS))
939 || ((intcsr & (PLX9050_LINTI2_ENABLE |
940 PLX9050_LINTI2_STATUS))
942 (PLX9050_LINTI2_ENABLE |
943 PLX9050_LINTI2_STATUS))))) {
944 // Not the source of the interrupt.
945 // (N.B. not using PLX9050_SOFTWARE_INTERRUPT)
946 comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);
950 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
951 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
952 // Interrupt comes from fifo_half-full signal
954 if (pci9111_is_fifo_full()) {
955 comedi_spin_unlock_irqrestore(&dev->spinlock,
957 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
958 pci9111_interrupt_clear();
959 pci9111_ai_cancel(dev, subdevice);
960 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
961 comedi_event(dev, subdevice);
966 if (pci9111_is_fifo_half_full()) {
967 unsigned int num_samples;
968 unsigned int bytes_written = 0;
970 #ifdef INTERRUPT_DEBUG
971 printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
975 PCI9111_FIFO_HALF_SIZE >
976 dev_private->stop_counter
977 && !dev_private->stop_is_none ? dev_private->
978 stop_counter : PCI9111_FIFO_HALF_SIZE;
979 insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE,
980 dev_private->ai_bounce_buffer, num_samples);
982 if (dev_private->scan_delay < 1) {
984 cfc_write_array_to_buffer(subdevice,
985 dev_private->ai_bounce_buffer,
986 num_samples * sizeof(short));
991 while (position < num_samples) {
992 if (dev_private->chunk_counter <
993 dev_private->chanlist_len) {
1001 num_samples - position)
1007 cfc_write_array_to_buffer
1021 num_samples - position)
1031 position += to_read;
1032 dev_private->chunk_counter += to_read;
1034 if (dev_private->chunk_counter >=
1035 dev_private->chunk_num_samples)
1036 dev_private->chunk_counter = 0;
1040 dev_private->stop_counter -=
1041 bytes_written / sizeof(short);
1045 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
1046 async->events |= COMEDI_CB_EOA;
1047 pci9111_ai_cancel(dev, subdevice);
1050 /* Very important, otherwise another interrupt request will be inserted
1051 * and will cause driver hangs on processing interrupt event. */
1053 pci9111_interrupt_clear();
1055 comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);
1057 comedi_event(dev, subdevice);
1062 // ------------------------------------------------------------------
1064 // INSTANT ANALOG INPUT OUTPUT SECTION
1066 // ------------------------------------------------------------------
1069 // analog instant input
1072 #undef AI_INSN_DEBUG
1074 static int pci9111_ai_insn_read(struct comedi_device * dev,
1075 struct comedi_subdevice * subdevice, struct comedi_insn * insn, unsigned int * data)
1078 ((struct pci9111_board *) dev->board_ptr)->ai_resolution;
1082 #ifdef AI_INSN_DEBUG
1083 printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
1084 CR_CHAN((&insn->chanspec)[0]),
1085 CR_RANGE((&insn->chanspec)[0]), insn->n);
1088 pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
1090 if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) {
1091 pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
1094 pci9111_fifo_reset();
1096 for (i = 0; i < insn->n; i++) {
1097 pci9111_software_trigger();
1099 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
1102 if (!pci9111_is_fifo_empty())
1103 goto conversion_done;
1106 comedi_error(dev, "A/D read timeout");
1108 pci9111_fifo_reset();
1113 if (resolution == PCI9111_HR_AI_RESOLUTION) {
1114 data[i] = pci9111_hr_ai_get_data();
1116 data[i] = pci9111_ai_get_data();
1120 #ifdef AI_INSN_DEBUG
1121 printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
1122 pci9111_ai_channel_get(),
1123 pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
1130 // Analog instant output
1134 pci9111_ao_insn_write(struct comedi_device * dev,
1135 struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
1139 for (i = 0; i < insn->n; i++) {
1140 pci9111_ao_set_data(data[i]);
1141 dev_private->ao_readback = data[i];
1148 // Analog output readback
1151 static int pci9111_ao_insn_read(struct comedi_device * dev,
1152 struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
1156 for (i = 0; i < insn->n; i++) {
1157 data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK;
1163 // ------------------------------------------------------------------
1165 // DIGITAL INPUT OUTPUT SECTION
1167 // ------------------------------------------------------------------
1173 static int pci9111_di_insn_bits(struct comedi_device * dev,
1174 struct comedi_subdevice * subdevice, struct comedi_insn * insn, unsigned int * data)
1178 bits = pci9111_di_get_bits();
1188 static int pci9111_do_insn_bits(struct comedi_device * dev,
1189 struct comedi_subdevice * subdevice, struct comedi_insn * insn, unsigned int * data)
1193 // Only set bits that have been masked
1195 // data[1] = bit state
1197 data[0] &= PCI9111_DO_MASK;
1199 bits = subdevice->state;
1201 bits |= data[0] & data[1];
1202 subdevice->state = bits;
1204 pci9111_do_set_bits(bits);
1211 // ------------------------------------------------------------------
1213 // INITIALISATION SECTION
1215 // ------------------------------------------------------------------
1221 static int pci9111_reset(struct comedi_device * dev)
1223 // Set trigger source to software
1225 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
1228 pci9111_trigger_source_set(dev, software);
1229 pci9111_pretrigger_set(dev, false);
1230 pci9111_autoscan_set(dev, false);
1234 dev_private->timer_divisor_1 = 0;
1235 dev_private->timer_divisor_2 = 0;
1237 pci9111_timer_set(dev);
1245 // - Register PCI device
1246 // - Declare device driver capability
1249 static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * it)
1251 struct comedi_subdevice *subdevice;
1252 unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
1253 struct pci_dev *pci_device;
1255 const struct pci9111_board *board;
1257 if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0) {
1261 // Probe the device to determine what device in the series it is.
1264 printk("comedi%d: " PCI9111_DRIVER_NAME " driver\n", dev->minor);
1266 for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
1269 pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
1270 if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) {
1271 for (i = 0; i < pci9111_board_nbr; i++) {
1272 if (pci9111_boards[i].device_id ==
1273 pci_device->device) {
1274 // was a particular bus/slot requested?
1275 if ((it->options[0] != 0)
1276 || (it->options[1] != 0)) {
1277 // are we on the wrong bus/slot?
1278 if (pci_device->bus->number !=
1280 || PCI_SLOT(pci_device->
1287 dev->board_ptr = pci9111_boards + i;
1288 board = (struct pci9111_board *) dev->
1290 dev_private->pci_device = pci_device;
1297 printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
1298 dev->minor, it->options[0], it->options[1]);
1303 printk("comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n",
1305 pci9111_boards[i].name,
1306 pci_device->bus->number,
1307 PCI_SLOT(pci_device->devfn),
1308 PCI_FUNC(pci_device->devfn), pci_device->irq);
1310 // TODO: Warn about non-tested boards.
1312 switch (board->device_id) {
1315 // Read local configuration register base address [PCI_BASE_ADDRESS #1].
1317 lcr_io_base = pci_resource_start(pci_device, 1);
1318 lcr_io_range = pci_resource_len(pci_device, 1);
1320 printk("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n", dev->minor, lcr_io_base, lcr_io_range);
1322 // Enable PCI device and request regions
1323 if (comedi_pci_enable(pci_device, PCI9111_DRIVER_NAME) < 0) {
1324 printk("comedi%d: Failed to enable PCI device and request regions\n", dev->minor);
1327 // Read PCI6308 register base address [PCI_BASE_ADDRESS #2].
1329 io_base = pci_resource_start(pci_device, 2);
1330 io_range = pci_resource_len(pci_device, 2);
1332 printk("comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
1333 dev->minor, io_base, io_range);
1335 dev->iobase = io_base;
1336 dev->board_name = board->name;
1337 dev_private->io_range = io_range;
1338 dev_private->is_valid = 0;
1339 dev_private->lcr_io_base = lcr_io_base;
1340 dev_private->lcr_io_range = lcr_io_range;
1347 if (pci_device->irq > 0) {
1348 if (comedi_request_irq(pci_device->irq,
1350 IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
1351 printk("comedi%d: unable to allocate irq %u\n",
1352 dev->minor, pci_device->irq);
1356 dev->irq = pci_device->irq;
1359 // TODO: Add external multiplexer setup (according to option[2]).
1362 if ((error = alloc_subdevices(dev, 4)) < 0)
1365 subdevice = dev->subdevices + 0;
1366 dev->read_subdev = subdevice;
1368 subdevice->type = COMEDI_SUBD_AI;
1369 subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1372 // TODO: Add external multiplexer data
1374 // if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; }
1375 // else { subdevice->n_chan = this_board->n_aichan; }
1378 subdevice->n_chan = board->ai_channel_nbr;
1379 subdevice->maxdata = board->ai_resolution_mask;
1380 subdevice->len_chanlist = board->ai_channel_nbr;
1381 subdevice->range_table = board->ai_range_list;
1382 subdevice->cancel = pci9111_ai_cancel;
1383 subdevice->insn_read = pci9111_ai_insn_read;
1384 subdevice->do_cmdtest = pci9111_ai_do_cmd_test;
1385 subdevice->do_cmd = pci9111_ai_do_cmd;
1386 subdevice->munge = pci9111_ai_munge;
1388 subdevice = dev->subdevices + 1;
1389 subdevice->type = COMEDI_SUBD_AO;
1390 subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1391 subdevice->n_chan = board->ao_channel_nbr;
1392 subdevice->maxdata = board->ao_resolution_mask;
1393 subdevice->len_chanlist = board->ao_channel_nbr;
1394 subdevice->range_table = board->ao_range_list;
1395 subdevice->insn_write = pci9111_ao_insn_write;
1396 subdevice->insn_read = pci9111_ao_insn_read;
1398 subdevice = dev->subdevices + 2;
1399 subdevice->type = COMEDI_SUBD_DI;
1400 subdevice->subdev_flags = SDF_READABLE;
1401 subdevice->n_chan = PCI9111_DI_CHANNEL_NBR;
1402 subdevice->maxdata = 1;
1403 subdevice->range_table = &range_digital;
1404 subdevice->insn_bits = pci9111_di_insn_bits;
1406 subdevice = dev->subdevices + 3;
1407 subdevice->type = COMEDI_SUBD_DO;
1408 subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1409 subdevice->n_chan = PCI9111_DO_CHANNEL_NBR;
1410 subdevice->maxdata = 1;
1411 subdevice->range_table = &range_digital;
1412 subdevice->insn_bits = pci9111_do_insn_bits;
1414 dev_private->is_valid = 1;
1423 static int pci9111_detach(struct comedi_device * dev)
1427 if (dev->private != 0) {
1428 if (dev_private->is_valid)
1432 // Release previously allocated irq
1434 if (dev->irq != 0) {
1435 comedi_free_irq(dev->irq, dev);
1438 if (dev_private != 0 && dev_private->pci_device != 0) {
1440 comedi_pci_disable(dev_private->pci_device);
1442 pci_dev_put(dev_private->pci_device);