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: not applicable, uses PCI auto config
56 2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
57 a multiple of chanlist_len*convert_arg.
58 2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
59 2002/02/18 Added external trigger support for analog input.
63 - Really test implemented functionality.
64 - Add support for the PCI-9111DG with a probe routine to identify
65 the card type (perhaps with the help of the channel number readback
66 of the A/D Data register).
67 - Add external multiplexer support.
71 #include "../comedidev.h"
73 #include <linux/delay.h>
74 #include <linux/interrupt.h>
77 #include "comedi_fc.h"
79 #define PCI9111_DRIVER_NAME "adl_pci9111"
80 #define PCI9111_HR_DEVICE_ID 0x9111
82 #define PCI9111_FIFO_HALF_SIZE 512
84 #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
86 #define PCI9111_RANGE_SETTING_DELAY 10
87 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2
88 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100
90 #define PCI9111_8254_CLOCK_PERIOD_NS 500
94 #define PCI9111_AI_FIFO_REG 0x00
95 #define PCI9111_AO_REG 0x00
96 #define PCI9111_DIO_REG 0x02
97 #define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
98 #define PCI9111_AI_CHANNEL_REG 0x06
99 #define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
100 #define PCI9111_AI_RANGE_REG 0x08
101 #define PCI9111_RANGE_STATUS_REG 0x08
102 #define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
103 #define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
104 #define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
105 #define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
106 #define PCI9111_8254_BASE_REG 0x40
107 #define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
109 #define PCI9111_TRIGGER_MASK 0x0F
110 #define PCI9111_PTRG_OFF (0 << 3)
111 #define PCI9111_PTRG_ON (1 << 3)
112 #define PCI9111_EITS_EXTERNAL (1 << 2)
113 #define PCI9111_EITS_INTERNAL (0 << 2)
114 #define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)
115 #define PCI9111_TPST_TIMER_PACER (1 << 1)
116 #define PCI9111_ASCAN_ON (1 << 0)
117 #define PCI9111_ASCAN_OFF (0 << 0)
119 #define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
120 #define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)
121 #define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
122 #define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
123 #define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
124 #define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)
126 #define PCI9111_RANGE_MASK 0x07
127 #define PCI9111_FIFO_EMPTY_MASK 0x10
128 #define PCI9111_FIFO_HALF_FULL_MASK 0x20
129 #define PCI9111_FIFO_FULL_MASK 0x40
130 #define PCI9111_AD_BUSY_MASK 0x80
133 * Define inlined function
136 #define pci9111_trigger_and_autoscan_get() \
137 (inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
139 #define pci9111_trigger_and_autoscan_set(flags) \
140 outb(flags, dev->iobase + PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
142 #define pci9111_interrupt_and_fifo_get() \
143 ((inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \
146 #define pci9111_interrupt_and_fifo_set(flags) \
147 outb(flags, dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL)
149 #define pci9111_interrupt_clear() \
150 outb(0, dev->iobase + PCI9111_REGISTER_INTERRUPT_CLEAR)
152 #define pci9111_software_trigger() \
153 outb(0, dev->iobase + PCI9111_REGISTER_SOFTWARE_TRIGGER)
155 #define pci9111_fifo_reset() do { \
156 outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
157 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
158 outb(PCI9111_FFEN_SET_FIFO_DISABLE, \
159 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
160 outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
161 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
164 #define pci9111_is_fifo_full() \
165 ((inb(dev->iobase + PCI9111_RANGE_STATUS_REG)& \
166 PCI9111_FIFO_FULL_MASK) == 0)
168 #define pci9111_is_fifo_half_full() \
169 ((inb(dev->iobase + PCI9111_RANGE_STATUS_REG)& \
170 PCI9111_FIFO_HALF_FULL_MASK) == 0)
172 #define pci9111_is_fifo_empty() \
173 ((inb(dev->iobase + PCI9111_RANGE_STATUS_REG)& \
174 PCI9111_FIFO_EMPTY_MASK) == 0)
176 static const struct comedi_lrange pci9111_hr_ai_range = {
187 /* Private data structure */
189 struct pci9111_private_data {
190 unsigned long lcr_io_base; /* Local configuration register base
196 unsigned int scan_delay;
197 unsigned int chanlist_len;
198 unsigned int chunk_counter;
199 unsigned int chunk_num_samples;
201 int ao_readback; /* Last written analog output data */
203 unsigned int timer_divisor_1; /* Divisor values for the 8254 timer
205 unsigned int timer_divisor_2;
207 int is_valid; /* Is device valid */
209 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
212 /* ------------------------------------------------------------------ */
213 /* PLX9050 SECTION */
214 /* ------------------------------------------------------------------ */
216 #define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
218 #define PLX9050_LINTI1_ENABLE (1 << 0)
219 #define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
220 #define PLX9050_LINTI1_STATUS (1 << 2)
221 #define PLX9050_LINTI2_ENABLE (1 << 3)
222 #define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
223 #define PLX9050_LINTI2_STATUS (1 << 5)
224 #define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
225 #define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
227 static void plx9050_interrupt_control(unsigned long io_base,
229 bool LINTi1_active_high,
231 bool LINTi2_active_high,
232 bool interrupt_enable)
237 flags |= PLX9050_LINTI1_ENABLE;
238 if (LINTi1_active_high)
239 flags |= PLX9050_LINTI1_ACTIVE_HIGH;
241 flags |= PLX9050_LINTI2_ENABLE;
242 if (LINTi2_active_high)
243 flags |= PLX9050_LINTI2_ACTIVE_HIGH;
245 if (interrupt_enable)
246 flags |= PLX9050_PCI_INTERRUPT_ENABLE;
248 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
251 /* ------------------------------------------------------------------ */
252 /* MISCELLANEOUS SECTION */
253 /* ------------------------------------------------------------------ */
257 static void pci9111_timer_set(struct comedi_device *dev)
259 struct pci9111_private_data *dev_private = dev->private;
260 unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
262 i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
263 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
264 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
268 i8254_write(timer_base, 1, 2, dev_private->timer_divisor_2);
269 i8254_write(timer_base, 1, 1, dev_private->timer_divisor_1);
272 enum pci9111_trigger_sources {
278 static void pci9111_trigger_source_set(struct comedi_device *dev,
279 enum pci9111_trigger_sources source)
283 flags = pci9111_trigger_and_autoscan_get() & 0x09;
287 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
291 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
295 flags |= PCI9111_EITS_EXTERNAL;
299 pci9111_trigger_and_autoscan_set(flags);
302 static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
306 flags = pci9111_trigger_and_autoscan_get() & 0x07;
309 flags |= PCI9111_PTRG_ON;
311 pci9111_trigger_and_autoscan_set(flags);
314 static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
318 flags = pci9111_trigger_and_autoscan_get() & 0x0e;
321 flags |= PCI9111_ASCAN_ON;
323 pci9111_trigger_and_autoscan_set(flags);
326 enum pci9111_ISC0_sources {
328 irq_on_fifo_half_full
331 enum pci9111_ISC1_sources {
333 irq_on_external_trigger
336 static void pci9111_interrupt_source_set(struct comedi_device *dev,
337 enum pci9111_ISC0_sources irq_0_source,
338 enum pci9111_ISC1_sources irq_1_source)
342 flags = pci9111_interrupt_and_fifo_get() & 0x04;
344 if (irq_0_source == irq_on_fifo_half_full)
345 flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
347 if (irq_1_source == irq_on_external_trigger)
348 flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
350 pci9111_interrupt_and_fifo_set(flags);
353 /* ------------------------------------------------------------------ */
354 /* HARDWARE TRIGGERED ANALOG INPUT SECTION */
355 /* ------------------------------------------------------------------ */
357 /* Cancel analog input autoscan */
359 static int pci9111_ai_cancel(struct comedi_device *dev,
360 struct comedi_subdevice *s)
362 struct pci9111_private_data *dev_private = dev->private;
364 /* Disable interrupts */
366 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
369 pci9111_trigger_source_set(dev, software);
371 pci9111_autoscan_set(dev, false);
373 pci9111_fifo_reset();
378 /* Test analog input command */
380 #define pci9111_check_trigger_src(src, flags) do { \
383 if (!src || tmp != src) \
388 pci9111_ai_do_cmd_test(struct comedi_device *dev,
389 struct comedi_subdevice *s, struct comedi_cmd *cmd)
391 struct pci9111_private_data *dev_private = dev->private;
394 int range, reference;
397 /* Step 1 : check if trigger are trivialy valid */
399 pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
400 pci9111_check_trigger_src(cmd->scan_begin_src,
401 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
402 pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
403 pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
404 pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
409 /* step 2 : make sure trigger sources are unique and mutually
412 if (cmd->start_src != TRIG_NOW)
415 if ((cmd->scan_begin_src != TRIG_TIMER) &&
416 (cmd->scan_begin_src != TRIG_FOLLOW) &&
417 (cmd->scan_begin_src != TRIG_EXT))
420 if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT))
422 if ((cmd->convert_src == TRIG_TIMER) &&
423 !((cmd->scan_begin_src == TRIG_TIMER) ||
424 (cmd->scan_begin_src == TRIG_FOLLOW)))
426 if ((cmd->convert_src == TRIG_EXT) &&
427 !((cmd->scan_begin_src == TRIG_EXT) ||
428 (cmd->scan_begin_src == TRIG_FOLLOW)))
432 if (cmd->scan_end_src != TRIG_COUNT)
434 if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
440 /* Step 3 : make sure arguments are trivialy compatible */
442 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
447 if ((cmd->convert_src == TRIG_TIMER) &&
448 (cmd->convert_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
449 cmd->convert_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
452 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
453 cmd->convert_arg = 0;
457 if ((cmd->scan_begin_src == TRIG_TIMER) &&
458 (cmd->scan_begin_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
459 cmd->scan_begin_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
462 if ((cmd->scan_begin_src == TRIG_FOLLOW)
463 && (cmd->scan_begin_arg != 0)) {
464 cmd->scan_begin_arg = 0;
467 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
468 cmd->scan_begin_arg = 0;
472 if ((cmd->scan_end_src == TRIG_COUNT) &&
473 (cmd->scan_end_arg != cmd->chanlist_len)) {
474 cmd->scan_end_arg = cmd->chanlist_len;
478 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
482 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
490 /* Step 4 : fix up any arguments */
492 if (cmd->convert_src == TRIG_TIMER) {
493 tmp = cmd->convert_arg;
494 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
495 &(dev_private->timer_divisor_1),
496 &(dev_private->timer_divisor_2),
498 cmd->flags & TRIG_ROUND_MASK);
499 if (tmp != cmd->convert_arg)
502 /* There's only one timer on this card, so the scan_begin timer must */
503 /* be a multiple of chanlist_len*convert_arg */
505 if (cmd->scan_begin_src == TRIG_TIMER) {
507 unsigned int scan_begin_min;
508 unsigned int scan_begin_arg;
509 unsigned int scan_factor;
511 scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
513 if (cmd->scan_begin_arg != scan_begin_min) {
514 if (scan_begin_min < cmd->scan_begin_arg) {
516 cmd->scan_begin_arg / scan_begin_min;
517 scan_begin_arg = scan_factor * scan_begin_min;
518 if (cmd->scan_begin_arg != scan_begin_arg) {
519 cmd->scan_begin_arg = scan_begin_arg;
523 cmd->scan_begin_arg = scan_begin_min;
532 /* Step 5 : check channel list */
536 range = CR_RANGE(cmd->chanlist[0]);
537 reference = CR_AREF(cmd->chanlist[0]);
539 if (cmd->chanlist_len > 1) {
540 for (i = 0; i < cmd->chanlist_len; i++) {
541 if (CR_CHAN(cmd->chanlist[i]) != i) {
543 "entries in chanlist must be consecutive "
544 "channels,counting upwards from 0\n");
547 if (CR_RANGE(cmd->chanlist[i]) != range) {
549 "entries in chanlist must all have the same gain\n");
552 if (CR_AREF(cmd->chanlist[i]) != reference) {
554 "entries in chanlist must all have the same reference\n");
568 /* Analog input command */
570 static int pci9111_ai_do_cmd(struct comedi_device *dev,
571 struct comedi_subdevice *s)
573 struct pci9111_private_data *dev_private = dev->private;
574 struct comedi_cmd *async_cmd = &s->async->cmd;
578 "no irq assigned for PCI9111, cannot do hardware conversion");
581 /* Set channel scan limit */
582 /* PCI9111 allows only scanning from channel 0 to channel n */
583 /* TODO: handle the case of an external multiplexer */
585 if (async_cmd->chanlist_len > 1) {
586 outb(async_cmd->chanlist_len - 1,
587 dev->iobase + PCI9111_AI_CHANNEL_REG);
588 pci9111_autoscan_set(dev, true);
590 outb(CR_CHAN(async_cmd->chanlist[0]),
591 dev->iobase + PCI9111_AI_CHANNEL_REG);
592 pci9111_autoscan_set(dev, false);
596 /* This is the same gain on every channel */
598 outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_RANGE_MASK,
599 dev->iobase + PCI9111_AI_RANGE_REG);
603 switch (async_cmd->stop_src) {
605 dev_private->stop_counter =
606 async_cmd->stop_arg * async_cmd->chanlist_len;
607 dev_private->stop_is_none = 0;
611 dev_private->stop_counter = 0;
612 dev_private->stop_is_none = 1;
616 comedi_error(dev, "Invalid stop trigger");
620 /* Set timer pacer */
622 dev_private->scan_delay = 0;
623 switch (async_cmd->convert_src) {
625 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
626 &(dev_private->timer_divisor_1),
627 &(dev_private->timer_divisor_2),
628 &(async_cmd->convert_arg),
630 flags & TRIG_ROUND_MASK);
632 pci9111_trigger_source_set(dev, software);
633 pci9111_timer_set(dev);
634 pci9111_fifo_reset();
635 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
637 pci9111_trigger_source_set(dev, timer_pacer);
638 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
641 if (async_cmd->scan_begin_src == TRIG_TIMER) {
642 dev_private->scan_delay =
643 (async_cmd->scan_begin_arg /
644 (async_cmd->convert_arg *
645 async_cmd->chanlist_len)) - 1;
652 pci9111_trigger_source_set(dev, external);
653 pci9111_fifo_reset();
654 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
656 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
662 comedi_error(dev, "Invalid convert trigger");
666 dev_private->stop_counter *= (1 + dev_private->scan_delay);
667 dev_private->chanlist_len = async_cmd->chanlist_len;
668 dev_private->chunk_counter = 0;
669 dev_private->chunk_num_samples =
670 dev_private->chanlist_len * (1 + dev_private->scan_delay);
675 static void pci9111_ai_munge(struct comedi_device *dev,
676 struct comedi_subdevice *s, void *data,
677 unsigned int num_bytes,
678 unsigned int start_chan_index)
681 unsigned int maxdata = s->maxdata;
682 unsigned int invert = (maxdata + 1) >> 1;
683 unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
684 unsigned int num_samples = num_bytes / sizeof(short);
687 for (i = 0; i < num_samples; i++)
688 array[i] = ((array[i] >> shift) & maxdata) ^ invert;
691 /* ------------------------------------------------------------------ */
692 /* INTERRUPT SECTION */
693 /* ------------------------------------------------------------------ */
695 static irqreturn_t pci9111_interrupt(int irq, void *p_device)
697 struct comedi_device *dev = p_device;
698 struct pci9111_private_data *dev_private = dev->private;
699 struct comedi_subdevice *s = dev->read_subdev;
700 struct comedi_async *async;
701 unsigned long irq_flags;
702 unsigned char intcsr;
704 if (!dev->attached) {
705 /* Ignore interrupt before device fully attached. */
706 /* Might not even have allocated subdevices yet! */
712 spin_lock_irqsave(&dev->spinlock, irq_flags);
714 /* Check if we are source of interrupt */
715 intcsr = inb(dev_private->lcr_io_base +
716 PLX9050_REGISTER_INTERRUPT_CONTROL);
717 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
718 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
719 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
720 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
721 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
722 /* Not the source of the interrupt. */
723 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
724 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
728 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
729 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
730 /* Interrupt comes from fifo_half-full signal */
732 if (pci9111_is_fifo_full()) {
733 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
734 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
735 pci9111_interrupt_clear();
736 pci9111_ai_cancel(dev, s);
737 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
738 comedi_event(dev, s);
743 if (pci9111_is_fifo_half_full()) {
744 unsigned int num_samples;
745 unsigned int bytes_written = 0;
748 PCI9111_FIFO_HALF_SIZE >
749 dev_private->stop_counter
751 stop_is_none ? dev_private->stop_counter :
752 PCI9111_FIFO_HALF_SIZE;
753 insw(dev->iobase + PCI9111_AI_FIFO_REG,
754 dev_private->ai_bounce_buffer, num_samples);
756 if (dev_private->scan_delay < 1) {
758 cfc_write_array_to_buffer(s,
767 while (position < num_samples) {
768 if (dev_private->chunk_counter <
769 dev_private->chanlist_len) {
771 dev_private->chanlist_len -
772 dev_private->chunk_counter;
775 num_samples - position)
781 cfc_write_array_to_buffer
783 dev_private->ai_bounce_buffer
785 to_read * sizeof(short));
788 dev_private->chunk_num_samples
790 dev_private->chunk_counter;
792 num_samples - position)
798 sizeof(short) * to_read;
802 dev_private->chunk_counter += to_read;
804 if (dev_private->chunk_counter >=
805 dev_private->chunk_num_samples)
806 dev_private->chunk_counter = 0;
810 dev_private->stop_counter -=
811 bytes_written / sizeof(short);
815 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
816 async->events |= COMEDI_CB_EOA;
817 pci9111_ai_cancel(dev, s);
820 /* Very important, otherwise another interrupt request will be inserted
821 * and will cause driver hangs on processing interrupt event. */
823 pci9111_interrupt_clear();
825 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
827 comedi_event(dev, s);
832 /* ------------------------------------------------------------------ */
833 /* INSTANT ANALOG INPUT OUTPUT SECTION */
834 /* ------------------------------------------------------------------ */
836 /* analog instant input */
838 static int pci9111_ai_insn_read(struct comedi_device *dev,
839 struct comedi_subdevice *s,
840 struct comedi_insn *insn, unsigned int *data)
842 unsigned int chan = CR_CHAN(insn->chanspec);
843 unsigned int range = CR_RANGE(insn->chanspec);
844 unsigned int maxdata = s->maxdata;
845 unsigned int invert = (maxdata + 1) >> 1;
846 unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
847 unsigned int current_range;
851 outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
853 current_range = inb(dev->iobase + PCI9111_RANGE_STATUS_REG);
854 if ((current_range & PCI9111_RANGE_MASK) != range) {
855 outb(range & PCI9111_RANGE_MASK,
856 dev->iobase + PCI9111_AI_RANGE_REG);
859 pci9111_fifo_reset();
861 for (i = 0; i < insn->n; i++) {
862 pci9111_software_trigger();
864 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
867 if (!pci9111_is_fifo_empty())
868 goto conversion_done;
871 comedi_error(dev, "A/D read timeout");
873 pci9111_fifo_reset();
878 data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
879 data[i] = ((data[i] >> shift) & maxdata) ^ invert;
885 static int pci9111_ao_insn_write(struct comedi_device *dev,
886 struct comedi_subdevice *s,
887 struct comedi_insn *insn,
890 struct pci9111_private_data *dev_private = dev->private;
891 unsigned int val = 0;
894 for (i = 0; i < insn->n; i++) {
896 outw(val, dev->iobase + PCI9111_AO_REG);
898 dev_private->ao_readback = val;
903 static int pci9111_ao_insn_read(struct comedi_device *dev,
904 struct comedi_subdevice *s,
905 struct comedi_insn *insn,
908 struct pci9111_private_data *dev_private = dev->private;
911 for (i = 0; i < insn->n; i++)
912 data[i] = dev_private->ao_readback;
917 static int pci9111_di_insn_bits(struct comedi_device *dev,
918 struct comedi_subdevice *s,
919 struct comedi_insn *insn,
922 data[1] = inw(dev->iobase + PCI9111_DIO_REG);
927 static int pci9111_do_insn_bits(struct comedi_device *dev,
928 struct comedi_subdevice *s,
929 struct comedi_insn *insn,
932 unsigned int mask = data[0];
933 unsigned int bits = data[1];
937 s->state |= (bits & mask);
939 outw(s->state, dev->iobase + PCI9111_DIO_REG);
947 /* ------------------------------------------------------------------ */
948 /* INITIALISATION SECTION */
949 /* ------------------------------------------------------------------ */
953 static int pci9111_reset(struct comedi_device *dev)
955 struct pci9111_private_data *dev_private = dev->private;
957 /* Set trigger source to software */
959 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
962 pci9111_trigger_source_set(dev, software);
963 pci9111_pretrigger_set(dev, false);
964 pci9111_autoscan_set(dev, false);
966 /* Reset 8254 chip */
968 dev_private->timer_divisor_1 = 0;
969 dev_private->timer_divisor_2 = 0;
971 pci9111_timer_set(dev);
976 static int pci9111_attach_pci(struct comedi_device *dev,
977 struct pci_dev *pcidev)
979 struct pci9111_private_data *dev_private;
980 struct comedi_subdevice *s;
983 comedi_set_hw_dev(dev, &pcidev->dev);
984 dev->board_name = dev->driver->driver_name;
986 ret = alloc_private(dev, sizeof(*dev_private));
989 dev_private = dev->private;
991 ret = comedi_pci_enable(pcidev, dev->board_name);
994 dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
995 dev->iobase = pci_resource_start(pcidev, 2);
999 if (pcidev->irq > 0) {
1000 ret = request_irq(dev->irq, pci9111_interrupt,
1001 IRQF_SHARED, dev->board_name, dev);
1004 dev->irq = pcidev->irq;
1007 ret = comedi_alloc_subdevices(dev, 4);
1011 s = &dev->subdevices[0];
1012 dev->read_subdev = s;
1013 s->type = COMEDI_SUBD_AI;
1014 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1016 s->maxdata = 0xffff;
1017 s->len_chanlist = 16;
1018 s->range_table = &pci9111_hr_ai_range;
1019 s->cancel = pci9111_ai_cancel;
1020 s->insn_read = pci9111_ai_insn_read;
1021 s->do_cmdtest = pci9111_ai_do_cmd_test;
1022 s->do_cmd = pci9111_ai_do_cmd;
1023 s->munge = pci9111_ai_munge;
1025 s = &dev->subdevices[1];
1026 s->type = COMEDI_SUBD_AO;
1027 s->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1029 s->maxdata = 0x0fff;
1030 s->len_chanlist = 1;
1031 s->range_table = &range_bipolar10;
1032 s->insn_write = pci9111_ao_insn_write;
1033 s->insn_read = pci9111_ao_insn_read;
1035 s = &dev->subdevices[2];
1036 s->type = COMEDI_SUBD_DI;
1037 s->subdev_flags = SDF_READABLE;
1040 s->range_table = &range_digital;
1041 s->insn_bits = pci9111_di_insn_bits;
1043 s = &dev->subdevices[3];
1044 s->type = COMEDI_SUBD_DO;
1045 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1048 s->range_table = &range_digital;
1049 s->insn_bits = pci9111_do_insn_bits;
1051 dev_private->is_valid = 1;
1053 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
1058 static void pci9111_detach(struct comedi_device *dev)
1060 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1061 struct pci9111_private_data *dev_private = dev->private;
1064 if (dev_private->is_valid)
1068 free_irq(dev->irq, dev);
1071 comedi_pci_disable(pcidev);
1072 pci_dev_put(pcidev);
1076 static struct comedi_driver adl_pci9111_driver = {
1077 .driver_name = "adl_pci9111",
1078 .module = THIS_MODULE,
1079 .attach_pci = pci9111_attach_pci,
1080 .detach = pci9111_detach,
1083 static int __devinit pci9111_pci_probe(struct pci_dev *dev,
1084 const struct pci_device_id *ent)
1086 return comedi_pci_auto_config(dev, &adl_pci9111_driver);
1089 static void __devexit pci9111_pci_remove(struct pci_dev *dev)
1091 comedi_pci_auto_unconfig(dev);
1094 static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
1095 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
1096 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
1099 MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
1101 static struct pci_driver adl_pci9111_pci_driver = {
1102 .name = "adl_pci9111",
1103 .id_table = pci9111_pci_table,
1104 .probe = pci9111_pci_probe,
1105 .remove = __devexit_p(pci9111_pci_remove),
1107 module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
1109 MODULE_AUTHOR("Comedi http://www.comedi.org");
1110 MODULE_DESCRIPTION("Comedi low-level driver");
1111 MODULE_LICENSE("GPL");