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
72 the card type (perhaps with the help of the channel number readback
73 of the A/D Data register).
74 - Add external multiplexer support.
78 #include "../comedidev.h"
80 #include <linux/delay.h>
81 #include <linux/interrupt.h>
84 #include "comedi_fc.h"
86 #define PCI9111_DRIVER_NAME "adl_pci9111"
87 #define PCI9111_HR_DEVICE_ID 0x9111
89 /* TODO: Add other pci9111 board id */
91 #define PCI9111_IO_RANGE 0x0100
93 #define PCI9111_FIFO_HALF_SIZE 512
95 #define PCI9111_AI_CHANNEL_NBR 16
97 #define PCI9111_AI_RESOLUTION 12
98 #define PCI9111_AI_RESOLUTION_MASK 0x0FFF
99 #define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800
101 #define PCI9111_HR_AI_RESOLUTION 16
102 #define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF
103 #define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000
105 #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
106 #define PCI9111_AO_CHANNEL_NBR 1
107 #define PCI9111_AO_RESOLUTION 12
108 #define PCI9111_AO_RESOLUTION_MASK 0x0FFF
109 #define PCI9111_DI_CHANNEL_NBR 16
110 #define PCI9111_DO_CHANNEL_NBR 16
111 #define PCI9111_DO_MASK 0xFFFF
113 #define PCI9111_RANGE_SETTING_DELAY 10
114 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2
115 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100
117 #define PCI9111_8254_CLOCK_PERIOD_NS 500
121 #define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored
123 #define PCI9111_REGISTER_DA_OUTPUT 0x00
124 #define PCI9111_DIO_REG 0x02
125 #define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
126 #define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel
128 #define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
129 #define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08
130 #define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08
131 #define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
132 #define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
133 #define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
134 #define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
135 #define PCI9111_8254_BASE_REG 0x40
136 #define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
138 #define PCI9111_TRIGGER_MASK 0x0F
139 #define PCI9111_PTRG_OFF (0 << 3)
140 #define PCI9111_PTRG_ON (1 << 3)
141 #define PCI9111_EITS_EXTERNAL (1 << 2)
142 #define PCI9111_EITS_INTERNAL (0 << 2)
143 #define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)
144 #define PCI9111_TPST_TIMER_PACER (1 << 1)
145 #define PCI9111_ASCAN_ON (1 << 0)
146 #define PCI9111_ASCAN_OFF (0 << 0)
148 #define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
149 #define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)
150 #define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
151 #define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
152 #define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
153 #define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)
155 #define PCI9111_CHANNEL_MASK 0x0F
157 #define PCI9111_RANGE_MASK 0x07
158 #define PCI9111_FIFO_EMPTY_MASK 0x10
159 #define PCI9111_FIFO_HALF_FULL_MASK 0x20
160 #define PCI9111_FIFO_FULL_MASK 0x40
161 #define PCI9111_AD_BUSY_MASK 0x80
164 * Define inlined function
167 #define pci9111_trigger_and_autoscan_get() \
168 (inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
170 #define pci9111_trigger_and_autoscan_set(flags) \
171 outb(flags, dev->iobase + PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
173 #define pci9111_interrupt_and_fifo_get() \
174 ((inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \
177 #define pci9111_interrupt_and_fifo_set(flags) \
178 outb(flags, dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL)
180 #define pci9111_interrupt_clear() \
181 outb(0, dev->iobase + PCI9111_REGISTER_INTERRUPT_CLEAR)
183 #define pci9111_software_trigger() \
184 outb(0, dev->iobase + PCI9111_REGISTER_SOFTWARE_TRIGGER)
186 #define pci9111_fifo_reset() do { \
187 outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
188 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
189 outb(PCI9111_FFEN_SET_FIFO_DISABLE, \
190 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
191 outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
192 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
195 #define pci9111_is_fifo_full() \
196 ((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
197 PCI9111_FIFO_FULL_MASK) == 0)
199 #define pci9111_is_fifo_half_full() \
200 ((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
201 PCI9111_FIFO_HALF_FULL_MASK) == 0)
203 #define pci9111_is_fifo_empty() \
204 ((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
205 PCI9111_FIFO_EMPTY_MASK) == 0)
207 #define pci9111_ai_channel_set(channel) \
208 outb((channel)&PCI9111_CHANNEL_MASK, \
209 dev->iobase + PCI9111_REGISTER_AD_CHANNEL_CONTROL)
211 #define pci9111_ai_channel_get() \
212 (inb(dev->iobase + PCI9111_REGISTER_AD_CHANNEL_READBACK) \
213 &PCI9111_CHANNEL_MASK)
215 #define pci9111_ai_range_set(range) \
216 outb((range)&PCI9111_RANGE_MASK, \
217 dev->iobase + PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
219 #define pci9111_ai_range_get() \
220 (inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK) \
223 #define pci9111_ai_get_data() \
224 (((inw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \
225 &PCI9111_AI_RESOLUTION_MASK) \
226 ^ PCI9111_AI_RESOLUTION_2_CMP_BIT)
228 #define pci9111_hr_ai_get_data() \
229 ((inw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE) \
230 &PCI9111_HR_AI_RESOLUTION_MASK) \
231 ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT)
233 #define pci9111_ao_set_data(data) \
234 outw(data&PCI9111_AO_RESOLUTION_MASK, \
235 dev->iobase + PCI9111_REGISTER_DA_OUTPUT)
238 static const struct comedi_lrange pci9111_hr_ai_range = {
250 /* Board specification structure */
253 struct pci9111_board {
254 const char *name; /* driver name */
256 int ai_channel_nbr; /* num of A/D chans */
257 int ao_channel_nbr; /* num of D/A chans */
258 int ai_resolution; /* resolution of A/D */
259 int ai_resolution_mask;
260 int ao_resolution; /* resolution of D/A */
261 int ao_resolution_mask;
262 const struct comedi_lrange *ai_range_list; /* rangelist for A/D */
263 const struct comedi_lrange *ao_range_list; /* rangelist for D/A */
264 unsigned int ai_acquisition_period_min_ns;
267 static const struct pci9111_board pci9111_boards[] = {
269 .name = "pci9111_hr",
270 .device_id = PCI9111_HR_DEVICE_ID,
271 .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR,
272 .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR,
273 .ai_resolution = PCI9111_HR_AI_RESOLUTION,
274 .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK,
275 .ao_resolution = PCI9111_AO_RESOLUTION,
276 .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK,
277 .ai_range_list = &pci9111_hr_ai_range,
278 .ao_range_list = &range_bipolar10,
279 .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
282 /* Private data structure */
284 struct pci9111_private_data {
285 unsigned long io_range; /* PCI6503 io range */
287 unsigned long lcr_io_base; /* Local configuration register base
289 unsigned long lcr_io_range;
294 unsigned int scan_delay;
295 unsigned int chanlist_len;
296 unsigned int chunk_counter;
297 unsigned int chunk_num_samples;
299 int ao_readback; /* Last written analog output data */
301 unsigned int timer_divisor_1; /* Divisor values for the 8254 timer
303 unsigned int timer_divisor_2;
305 int is_valid; /* Is device valid */
307 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
310 /* ------------------------------------------------------------------ */
311 /* PLX9050 SECTION */
312 /* ------------------------------------------------------------------ */
314 #define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
316 #define PLX9050_LINTI1_ENABLE (1 << 0)
317 #define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
318 #define PLX9050_LINTI1_STATUS (1 << 2)
319 #define PLX9050_LINTI2_ENABLE (1 << 3)
320 #define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
321 #define PLX9050_LINTI2_STATUS (1 << 5)
322 #define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
323 #define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
325 static void plx9050_interrupt_control(unsigned long io_base,
327 bool LINTi1_active_high,
329 bool LINTi2_active_high,
330 bool interrupt_enable)
335 flags |= PLX9050_LINTI1_ENABLE;
336 if (LINTi1_active_high)
337 flags |= PLX9050_LINTI1_ACTIVE_HIGH;
339 flags |= PLX9050_LINTI2_ENABLE;
340 if (LINTi2_active_high)
341 flags |= PLX9050_LINTI2_ACTIVE_HIGH;
343 if (interrupt_enable)
344 flags |= PLX9050_PCI_INTERRUPT_ENABLE;
346 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
349 /* ------------------------------------------------------------------ */
350 /* MISCELLANEOUS SECTION */
351 /* ------------------------------------------------------------------ */
355 static void pci9111_timer_set(struct comedi_device *dev)
357 struct pci9111_private_data *dev_private = dev->private;
358 unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
360 i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
361 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
362 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
366 i8254_write(timer_base, 1, 2, dev_private->timer_divisor_2);
367 i8254_write(timer_base, 1, 1, dev_private->timer_divisor_1);
370 enum pci9111_trigger_sources {
376 static void pci9111_trigger_source_set(struct comedi_device *dev,
377 enum pci9111_trigger_sources source)
381 flags = pci9111_trigger_and_autoscan_get() & 0x09;
385 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
389 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
393 flags |= PCI9111_EITS_EXTERNAL;
397 pci9111_trigger_and_autoscan_set(flags);
400 static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
404 flags = pci9111_trigger_and_autoscan_get() & 0x07;
407 flags |= PCI9111_PTRG_ON;
409 pci9111_trigger_and_autoscan_set(flags);
412 static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
416 flags = pci9111_trigger_and_autoscan_get() & 0x0e;
419 flags |= PCI9111_ASCAN_ON;
421 pci9111_trigger_and_autoscan_set(flags);
424 enum pci9111_ISC0_sources {
426 irq_on_fifo_half_full
429 enum pci9111_ISC1_sources {
431 irq_on_external_trigger
434 static void pci9111_interrupt_source_set(struct comedi_device *dev,
435 enum pci9111_ISC0_sources irq_0_source,
436 enum pci9111_ISC1_sources irq_1_source)
440 flags = pci9111_interrupt_and_fifo_get() & 0x04;
442 if (irq_0_source == irq_on_fifo_half_full)
443 flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
445 if (irq_1_source == irq_on_external_trigger)
446 flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
448 pci9111_interrupt_and_fifo_set(flags);
451 /* ------------------------------------------------------------------ */
452 /* HARDWARE TRIGGERED ANALOG INPUT SECTION */
453 /* ------------------------------------------------------------------ */
455 /* Cancel analog input autoscan */
457 #undef AI_DO_CMD_DEBUG
459 static int pci9111_ai_cancel(struct comedi_device *dev,
460 struct comedi_subdevice *s)
462 struct pci9111_private_data *dev_private = dev->private;
464 /* Disable interrupts */
466 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
469 pci9111_trigger_source_set(dev, software);
471 pci9111_autoscan_set(dev, false);
473 pci9111_fifo_reset();
475 #ifdef AI_DO_CMD_DEBUG
476 printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
482 /* Test analog input command */
484 #define pci9111_check_trigger_src(src, flags) do { \
487 if (!src || tmp != src) \
492 pci9111_ai_do_cmd_test(struct comedi_device *dev,
493 struct comedi_subdevice *s, struct comedi_cmd *cmd)
495 struct pci9111_private_data *dev_private = dev->private;
498 int range, reference;
500 struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr;
502 /* Step 1 : check if trigger are trivialy valid */
504 pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
505 pci9111_check_trigger_src(cmd->scan_begin_src,
506 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
507 pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
508 pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
509 pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
514 /* step 2 : make sure trigger sources are unique and mutually
517 if (cmd->start_src != TRIG_NOW)
520 if ((cmd->scan_begin_src != TRIG_TIMER) &&
521 (cmd->scan_begin_src != TRIG_FOLLOW) &&
522 (cmd->scan_begin_src != TRIG_EXT))
525 if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT))
527 if ((cmd->convert_src == TRIG_TIMER) &&
528 !((cmd->scan_begin_src == TRIG_TIMER) ||
529 (cmd->scan_begin_src == TRIG_FOLLOW)))
531 if ((cmd->convert_src == TRIG_EXT) &&
532 !((cmd->scan_begin_src == TRIG_EXT) ||
533 (cmd->scan_begin_src == TRIG_FOLLOW)))
537 if (cmd->scan_end_src != TRIG_COUNT)
539 if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
545 /* Step 3 : make sure arguments are trivialy compatible */
547 if (cmd->chanlist_len < 1) {
548 cmd->chanlist_len = 1;
552 if (cmd->chanlist_len > board->ai_channel_nbr) {
553 cmd->chanlist_len = board->ai_channel_nbr;
557 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
562 if ((cmd->convert_src == TRIG_TIMER) &&
563 (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
564 cmd->convert_arg = board->ai_acquisition_period_min_ns;
567 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
568 cmd->convert_arg = 0;
572 if ((cmd->scan_begin_src == TRIG_TIMER) &&
573 (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
574 cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
577 if ((cmd->scan_begin_src == TRIG_FOLLOW)
578 && (cmd->scan_begin_arg != 0)) {
579 cmd->scan_begin_arg = 0;
582 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
583 cmd->scan_begin_arg = 0;
587 if ((cmd->scan_end_src == TRIG_COUNT) &&
588 (cmd->scan_end_arg != cmd->chanlist_len)) {
589 cmd->scan_end_arg = cmd->chanlist_len;
593 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
597 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
605 /* Step 4 : fix up any arguments */
607 if (cmd->convert_src == TRIG_TIMER) {
608 tmp = cmd->convert_arg;
609 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
610 &(dev_private->timer_divisor_1),
611 &(dev_private->timer_divisor_2),
613 cmd->flags & TRIG_ROUND_MASK);
614 if (tmp != cmd->convert_arg)
617 /* There's only one timer on this card, so the scan_begin timer must */
618 /* be a multiple of chanlist_len*convert_arg */
620 if (cmd->scan_begin_src == TRIG_TIMER) {
622 unsigned int scan_begin_min;
623 unsigned int scan_begin_arg;
624 unsigned int scan_factor;
626 scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
628 if (cmd->scan_begin_arg != scan_begin_min) {
629 if (scan_begin_min < cmd->scan_begin_arg) {
631 cmd->scan_begin_arg / scan_begin_min;
632 scan_begin_arg = scan_factor * scan_begin_min;
633 if (cmd->scan_begin_arg != scan_begin_arg) {
634 cmd->scan_begin_arg = scan_begin_arg;
638 cmd->scan_begin_arg = scan_begin_min;
647 /* Step 5 : check channel list */
651 range = CR_RANGE(cmd->chanlist[0]);
652 reference = CR_AREF(cmd->chanlist[0]);
654 if (cmd->chanlist_len > 1) {
655 for (i = 0; i < cmd->chanlist_len; i++) {
656 if (CR_CHAN(cmd->chanlist[i]) != i) {
658 "entries in chanlist must be consecutive "
659 "channels,counting upwards from 0\n");
662 if (CR_RANGE(cmd->chanlist[i]) != range) {
664 "entries in chanlist must all have the same gain\n");
667 if (CR_AREF(cmd->chanlist[i]) != reference) {
669 "entries in chanlist must all have the same reference\n");
674 if ((CR_CHAN(cmd->chanlist[0]) >
675 (board->ai_channel_nbr - 1))
676 || (CR_CHAN(cmd->chanlist[0]) < 0)) {
678 "channel number is out of limits\n");
691 /* Analog input command */
693 static int pci9111_ai_do_cmd(struct comedi_device *dev,
694 struct comedi_subdevice *s)
696 struct pci9111_private_data *dev_private = dev->private;
697 struct comedi_cmd *async_cmd = &s->async->cmd;
701 "no irq assigned for PCI9111, cannot do hardware conversion");
704 /* Set channel scan limit */
705 /* PCI9111 allows only scanning from channel 0 to channel n */
706 /* TODO: handle the case of an external multiplexer */
708 if (async_cmd->chanlist_len > 1) {
709 pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
710 pci9111_autoscan_set(dev, true);
712 pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
713 pci9111_autoscan_set(dev, false);
717 /* This is the same gain on every channel */
719 pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
723 switch (async_cmd->stop_src) {
725 dev_private->stop_counter =
726 async_cmd->stop_arg * async_cmd->chanlist_len;
727 dev_private->stop_is_none = 0;
731 dev_private->stop_counter = 0;
732 dev_private->stop_is_none = 1;
736 comedi_error(dev, "Invalid stop trigger");
740 /* Set timer pacer */
742 dev_private->scan_delay = 0;
743 switch (async_cmd->convert_src) {
745 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
746 &(dev_private->timer_divisor_1),
747 &(dev_private->timer_divisor_2),
748 &(async_cmd->convert_arg),
750 flags & TRIG_ROUND_MASK);
751 #ifdef AI_DO_CMD_DEBUG
752 printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
753 dev_private->timer_divisor_1,
754 dev_private->timer_divisor_2);
757 pci9111_trigger_source_set(dev, software);
758 pci9111_timer_set(dev);
759 pci9111_fifo_reset();
760 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
762 pci9111_trigger_source_set(dev, timer_pacer);
763 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
766 if (async_cmd->scan_begin_src == TRIG_TIMER) {
767 dev_private->scan_delay =
768 (async_cmd->scan_begin_arg /
769 (async_cmd->convert_arg *
770 async_cmd->chanlist_len)) - 1;
777 pci9111_trigger_source_set(dev, external);
778 pci9111_fifo_reset();
779 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
781 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
787 comedi_error(dev, "Invalid convert trigger");
791 dev_private->stop_counter *= (1 + dev_private->scan_delay);
792 dev_private->chanlist_len = async_cmd->chanlist_len;
793 dev_private->chunk_counter = 0;
794 dev_private->chunk_num_samples =
795 dev_private->chanlist_len * (1 + dev_private->scan_delay);
797 #ifdef AI_DO_CMD_DEBUG
798 printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
799 printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
800 pci9111_trigger_and_autoscan_get());
801 printk(PCI9111_DRIVER_NAME ": irq source = %2x\n",
802 pci9111_interrupt_and_fifo_get());
803 printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
804 printk(PCI9111_DRIVER_NAME ": stop counter = %d\n",
805 dev_private->stop_counter);
806 printk(PCI9111_DRIVER_NAME ": scan delay = %d\n",
807 dev_private->scan_delay);
808 printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n",
809 dev_private->chanlist_len);
810 printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
811 dev_private->chunk_num_samples);
817 static void pci9111_ai_munge(struct comedi_device *dev,
818 struct comedi_subdevice *s, void *data,
819 unsigned int num_bytes,
820 unsigned int start_chan_index)
822 unsigned int i, num_samples = num_bytes / sizeof(short);
825 ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
827 for (i = 0; i < num_samples; i++) {
828 if (resolution == PCI9111_HR_AI_RESOLUTION)
830 (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
831 PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
834 ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
835 PCI9111_AI_RESOLUTION_2_CMP_BIT;
839 /* ------------------------------------------------------------------ */
840 /* INTERRUPT SECTION */
841 /* ------------------------------------------------------------------ */
843 #undef INTERRUPT_DEBUG
845 static irqreturn_t pci9111_interrupt(int irq, void *p_device)
847 struct comedi_device *dev = p_device;
848 struct pci9111_private_data *dev_private = dev->private;
849 struct comedi_subdevice *s = dev->read_subdev;
850 struct comedi_async *async;
851 unsigned long irq_flags;
852 unsigned char intcsr;
854 if (!dev->attached) {
855 /* Ignore interrupt before device fully attached. */
856 /* Might not even have allocated subdevices yet! */
862 spin_lock_irqsave(&dev->spinlock, irq_flags);
864 /* Check if we are source of interrupt */
865 intcsr = inb(dev_private->lcr_io_base +
866 PLX9050_REGISTER_INTERRUPT_CONTROL);
867 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
868 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
869 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
870 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
871 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
872 /* Not the source of the interrupt. */
873 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
874 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
878 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
879 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
880 /* Interrupt comes from fifo_half-full signal */
882 if (pci9111_is_fifo_full()) {
883 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
884 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
885 pci9111_interrupt_clear();
886 pci9111_ai_cancel(dev, s);
887 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
888 comedi_event(dev, s);
893 if (pci9111_is_fifo_half_full()) {
894 unsigned int num_samples;
895 unsigned int bytes_written = 0;
897 #ifdef INTERRUPT_DEBUG
898 printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
902 PCI9111_FIFO_HALF_SIZE >
903 dev_private->stop_counter
905 stop_is_none ? dev_private->stop_counter :
906 PCI9111_FIFO_HALF_SIZE;
907 insw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE,
908 dev_private->ai_bounce_buffer, num_samples);
910 if (dev_private->scan_delay < 1) {
912 cfc_write_array_to_buffer(s,
921 while (position < num_samples) {
922 if (dev_private->chunk_counter <
923 dev_private->chanlist_len) {
925 dev_private->chanlist_len -
926 dev_private->chunk_counter;
929 num_samples - position)
935 cfc_write_array_to_buffer
937 dev_private->ai_bounce_buffer
939 to_read * sizeof(short));
942 dev_private->chunk_num_samples
944 dev_private->chunk_counter;
946 num_samples - position)
952 sizeof(short) * to_read;
956 dev_private->chunk_counter += to_read;
958 if (dev_private->chunk_counter >=
959 dev_private->chunk_num_samples)
960 dev_private->chunk_counter = 0;
964 dev_private->stop_counter -=
965 bytes_written / sizeof(short);
969 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
970 async->events |= COMEDI_CB_EOA;
971 pci9111_ai_cancel(dev, s);
974 /* Very important, otherwise another interrupt request will be inserted
975 * and will cause driver hangs on processing interrupt event. */
977 pci9111_interrupt_clear();
979 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
981 comedi_event(dev, s);
986 /* ------------------------------------------------------------------ */
987 /* INSTANT ANALOG INPUT OUTPUT SECTION */
988 /* ------------------------------------------------------------------ */
990 /* analog instant input */
994 static int pci9111_ai_insn_read(struct comedi_device *dev,
995 struct comedi_subdevice *s,
996 struct comedi_insn *insn, unsigned int *data)
999 ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
1003 #ifdef AI_INSN_DEBUG
1004 printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
1005 CR_CHAN((&insn->chanspec)[0]),
1006 CR_RANGE((&insn->chanspec)[0]), insn->n);
1009 pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
1011 if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0]))
1012 pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
1014 pci9111_fifo_reset();
1016 for (i = 0; i < insn->n; i++) {
1017 pci9111_software_trigger();
1019 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
1022 if (!pci9111_is_fifo_empty())
1023 goto conversion_done;
1026 comedi_error(dev, "A/D read timeout");
1028 pci9111_fifo_reset();
1033 if (resolution == PCI9111_HR_AI_RESOLUTION)
1034 data[i] = pci9111_hr_ai_get_data();
1036 data[i] = pci9111_ai_get_data();
1039 #ifdef AI_INSN_DEBUG
1040 printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
1041 pci9111_ai_channel_get(),
1042 pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
1048 /* Analog instant output */
1051 pci9111_ao_insn_write(struct comedi_device *dev,
1052 struct comedi_subdevice *s, struct comedi_insn *insn,
1055 struct pci9111_private_data *dev_private = dev->private;
1058 for (i = 0; i < insn->n; i++) {
1059 pci9111_ao_set_data(data[i]);
1060 dev_private->ao_readback = data[i];
1066 /* Analog output readback */
1068 static int pci9111_ao_insn_read(struct comedi_device *dev,
1069 struct comedi_subdevice *s,
1070 struct comedi_insn *insn, unsigned int *data)
1072 struct pci9111_private_data *dev_private = dev->private;
1075 for (i = 0; i < insn->n; i++)
1076 data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK;
1081 static int pci9111_di_insn_bits(struct comedi_device *dev,
1082 struct comedi_subdevice *s,
1083 struct comedi_insn *insn,
1086 data[1] = inw(dev->iobase + PCI9111_DIO_REG);
1091 /* Digital outputs */
1093 static int pci9111_do_insn_bits(struct comedi_device *dev,
1094 struct comedi_subdevice *s,
1095 struct comedi_insn *insn, unsigned int *data)
1099 /* Only set bits that have been masked */
1100 /* data[0] = mask */
1101 /* data[1] = bit state */
1103 data[0] &= PCI9111_DO_MASK;
1107 bits |= data[0] & data[1];
1110 outw(bits, dev->iobase + PCI9111_DIO_REG);
1117 /* ------------------------------------------------------------------ */
1118 /* INITIALISATION SECTION */
1119 /* ------------------------------------------------------------------ */
1123 static int pci9111_reset(struct comedi_device *dev)
1125 struct pci9111_private_data *dev_private = dev->private;
1127 /* Set trigger source to software */
1129 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
1132 pci9111_trigger_source_set(dev, software);
1133 pci9111_pretrigger_set(dev, false);
1134 pci9111_autoscan_set(dev, false);
1136 /* Reset 8254 chip */
1138 dev_private->timer_divisor_1 = 0;
1139 dev_private->timer_divisor_2 = 0;
1141 pci9111_timer_set(dev);
1146 static struct pci_dev *pci9111_find_pci(struct comedi_device *dev,
1147 struct comedi_devconfig *it)
1149 struct pci_dev *pcidev = NULL;
1150 int bus = it->options[0];
1151 int slot = it->options[1];
1154 for_each_pci_dev(pcidev) {
1155 if (pcidev->vendor != PCI_VENDOR_ID_ADLINK)
1157 for (i = 0; i < ARRAY_SIZE(pci9111_boards); i++) {
1158 if (pcidev->device != pci9111_boards[i].device_id)
1161 /* requested particular bus/slot */
1162 if (pcidev->bus->number != bus ||
1163 PCI_SLOT(pcidev->devfn) != slot)
1166 dev->board_ptr = pci9111_boards + i;
1168 "comedi%d: found %s (b:s:f=%d:%d:%d), irq=%d\n",
1169 dev->minor, pci9111_boards[i].name,
1170 pcidev->bus->number, PCI_SLOT(pcidev->devfn),
1171 PCI_FUNC(pcidev->devfn), pcidev->irq);
1176 "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
1177 dev->minor, bus, slot);
1181 static int pci9111_attach(struct comedi_device *dev,
1182 struct comedi_devconfig *it)
1184 struct pci9111_private_data *dev_private;
1185 struct pci_dev *pcidev;
1186 struct comedi_subdevice *s;
1187 unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
1189 const struct pci9111_board *board;
1191 ret = alloc_private(dev, sizeof(*dev_private));
1194 dev_private = dev->private;
1196 /* Probe the device to determine what device in the series it is. */
1198 printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n",
1201 pcidev = pci9111_find_pci(dev, it);
1204 comedi_set_hw_dev(dev, &pcidev->dev);
1205 board = (struct pci9111_board *)dev->board_ptr;
1207 /* TODO: Warn about non-tested boards. */
1209 /* Read local configuration register base address
1210 * [PCI_BASE_ADDRESS #1]. */
1212 lcr_io_base = pci_resource_start(pcidev, 1);
1213 lcr_io_range = pci_resource_len(pcidev, 1);
1216 ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
1217 dev->minor, lcr_io_base, lcr_io_range);
1219 /* Enable PCI device and request regions */
1220 if (comedi_pci_enable(pcidev, PCI9111_DRIVER_NAME) < 0) {
1222 ("comedi%d: Failed to enable PCI device and request regions\n",
1226 /* Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */
1228 io_base = pci_resource_start(pcidev, 2);
1229 io_range = pci_resource_len(pcidev, 2);
1231 printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
1232 dev->minor, io_base, io_range);
1234 dev->iobase = io_base;
1235 dev->board_name = board->name;
1236 dev_private->io_range = io_range;
1237 dev_private->is_valid = 0;
1238 dev_private->lcr_io_base = lcr_io_base;
1239 dev_private->lcr_io_range = lcr_io_range;
1246 if (pcidev->irq > 0) {
1247 dev->irq = pcidev->irq;
1249 if (request_irq(dev->irq, pci9111_interrupt,
1250 IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
1252 "comedi%d: unable to allocate irq %u\n",
1253 dev->minor, dev->irq);
1258 /* TODO: Add external multiplexer setup (according to option[2]). */
1260 ret = comedi_alloc_subdevices(dev, 4);
1264 s = &dev->subdevices[0];
1265 dev->read_subdev = s;
1267 s->type = COMEDI_SUBD_AI;
1268 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1270 /* TODO: Add external multiplexer data */
1271 /* if (devpriv->usemux) { s->n_chan = devpriv->usemux; } */
1272 /* else { s->n_chan = this_board->n_aichan; } */
1274 s->n_chan = board->ai_channel_nbr;
1275 s->maxdata = board->ai_resolution_mask;
1276 s->len_chanlist = board->ai_channel_nbr;
1277 s->range_table = board->ai_range_list;
1278 s->cancel = pci9111_ai_cancel;
1279 s->insn_read = pci9111_ai_insn_read;
1280 s->do_cmdtest = pci9111_ai_do_cmd_test;
1281 s->do_cmd = pci9111_ai_do_cmd;
1282 s->munge = pci9111_ai_munge;
1284 s = &dev->subdevices[1];
1285 s->type = COMEDI_SUBD_AO;
1286 s->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1287 s->n_chan = board->ao_channel_nbr;
1288 s->maxdata = board->ao_resolution_mask;
1289 s->len_chanlist = board->ao_channel_nbr;
1290 s->range_table = board->ao_range_list;
1291 s->insn_write = pci9111_ao_insn_write;
1292 s->insn_read = pci9111_ao_insn_read;
1294 s = &dev->subdevices[2];
1295 s->type = COMEDI_SUBD_DI;
1296 s->subdev_flags = SDF_READABLE;
1297 s->n_chan = PCI9111_DI_CHANNEL_NBR;
1299 s->range_table = &range_digital;
1300 s->insn_bits = pci9111_di_insn_bits;
1302 s = &dev->subdevices[3];
1303 s->type = COMEDI_SUBD_DO;
1304 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1305 s->n_chan = PCI9111_DO_CHANNEL_NBR;
1307 s->range_table = &range_digital;
1308 s->insn_bits = pci9111_do_insn_bits;
1310 dev_private->is_valid = 1;
1315 static void pci9111_detach(struct comedi_device *dev)
1317 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1318 struct pci9111_private_data *dev_private = dev->private;
1321 if (dev_private->is_valid)
1325 free_irq(dev->irq, dev);
1328 comedi_pci_disable(pcidev);
1329 pci_dev_put(pcidev);
1333 static struct comedi_driver adl_pci9111_driver = {
1334 .driver_name = "adl_pci9111",
1335 .module = THIS_MODULE,
1336 .attach = pci9111_attach,
1337 .detach = pci9111_detach,
1340 static int __devinit pci9111_pci_probe(struct pci_dev *dev,
1341 const struct pci_device_id *ent)
1343 return comedi_pci_auto_config(dev, &adl_pci9111_driver);
1346 static void __devexit pci9111_pci_remove(struct pci_dev *dev)
1348 comedi_pci_auto_unconfig(dev);
1351 static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
1352 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
1353 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
1356 MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
1358 static struct pci_driver adl_pci9111_pci_driver = {
1359 .name = "adl_pci9111",
1360 .id_table = pci9111_pci_table,
1361 .probe = pci9111_pci_probe,
1362 .remove = __devexit_p(pci9111_pci_remove),
1364 module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
1366 MODULE_AUTHOR("Comedi http://www.comedi.org");
1367 MODULE_DESCRIPTION("Comedi low-level driver");
1368 MODULE_LICENSE("GPL");