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 <linux/pci.h>
72 #include <linux/delay.h>
73 #include <linux/interrupt.h>
75 #include "../comedidev.h"
78 #include "comedi_fc.h"
80 #define PCI9111_DRIVER_NAME "adl_pci9111"
81 #define PCI9111_HR_DEVICE_ID 0x9111
83 #define PCI9111_FIFO_HALF_SIZE 512
85 #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
87 #define PCI9111_RANGE_SETTING_DELAY 10
88 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2
89 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100
91 #define PCI9111_8254_CLOCK_PERIOD_NS 500
94 * IO address map and bit defines
96 #define PCI9111_AI_FIFO_REG 0x00
97 #define PCI9111_AO_REG 0x00
98 #define PCI9111_DIO_REG 0x02
99 #define PCI9111_EDIO_REG 0x04
100 #define PCI9111_AI_CHANNEL_REG 0x06
101 #define PCI9111_AI_RANGE_STAT_REG 0x08
102 #define PCI9111_AI_STAT_AD_BUSY (1 << 7)
103 #define PCI9111_AI_STAT_FF_FF (1 << 6)
104 #define PCI9111_AI_STAT_FF_HF (1 << 5)
105 #define PCI9111_AI_STAT_FF_EF (1 << 4)
106 #define PCI9111_AI_RANGE_MASK (7 << 0)
107 #define PCI9111_AI_TRIG_CTRL_REG 0x0a
108 #define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5)
109 #define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4)
110 #define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3)
111 #define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2)
112 #define PCI9111_AI_TRIG_CTRL_TPST (1 << 1)
113 #define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0)
114 #define PCI9111_INT_CTRL_REG 0x0c
115 #define PCI9111_INT_CTRL_ISC2 (1 << 3)
116 #define PCI9111_INT_CTRL_FFEN (1 << 2)
117 #define PCI9111_INT_CTRL_ISC1 (1 << 1)
118 #define PCI9111_INT_CTRL_ISC0 (1 << 0)
119 #define PCI9111_SOFT_TRIG_REG 0x0e
120 #define PCI9111_8254_BASE_REG 0x40
121 #define PCI9111_INT_CLR_REG 0x48
123 static const struct comedi_lrange pci9111_ai_range
= {
134 struct pci9111_private_data
{
135 unsigned long lcr_io_base
;
140 unsigned int scan_delay
;
141 unsigned int chanlist_len
;
142 unsigned int chunk_counter
;
143 unsigned int chunk_num_samples
;
150 short ai_bounce_buffer
[2 * PCI9111_FIFO_HALF_SIZE
];
153 #define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
155 #define PLX9050_LINTI1_ENABLE (1 << 0)
156 #define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
157 #define PLX9050_LINTI1_STATUS (1 << 2)
158 #define PLX9050_LINTI2_ENABLE (1 << 3)
159 #define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
160 #define PLX9050_LINTI2_STATUS (1 << 5)
161 #define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
162 #define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
164 static void plx9050_interrupt_control(unsigned long io_base
,
166 bool LINTi1_active_high
,
168 bool LINTi2_active_high
,
169 bool interrupt_enable
)
174 flags
|= PLX9050_LINTI1_ENABLE
;
175 if (LINTi1_active_high
)
176 flags
|= PLX9050_LINTI1_ACTIVE_HIGH
;
178 flags
|= PLX9050_LINTI2_ENABLE
;
179 if (LINTi2_active_high
)
180 flags
|= PLX9050_LINTI2_ACTIVE_HIGH
;
182 if (interrupt_enable
)
183 flags
|= PLX9050_PCI_INTERRUPT_ENABLE
;
185 outb(flags
, io_base
+ PLX9050_REGISTER_INTERRUPT_CONTROL
);
188 static void pci9111_timer_set(struct comedi_device
*dev
)
190 struct pci9111_private_data
*dev_private
= dev
->private;
191 unsigned long timer_base
= dev
->iobase
+ PCI9111_8254_BASE_REG
;
193 i8254_set_mode(timer_base
, 1, 0, I8254_MODE0
| I8254_BINARY
);
194 i8254_set_mode(timer_base
, 1, 1, I8254_MODE2
| I8254_BINARY
);
195 i8254_set_mode(timer_base
, 1, 2, I8254_MODE2
| I8254_BINARY
);
199 i8254_write(timer_base
, 1, 2, dev_private
->div2
);
200 i8254_write(timer_base
, 1, 1, dev_private
->div1
);
203 enum pci9111_trigger_sources
{
209 static void pci9111_trigger_source_set(struct comedi_device
*dev
,
210 enum pci9111_trigger_sources source
)
214 /* Read the current trigger mode control bits */
215 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
216 /* Mask off the EITS and TPST bits */
224 flags
|= PCI9111_AI_TRIG_CTRL_TPST
;
228 flags
|= PCI9111_AI_TRIG_CTRL_ETIS
;
232 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
235 static void pci9111_pretrigger_set(struct comedi_device
*dev
, bool pretrigger
)
239 /* Read the current trigger mode control bits */
240 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
241 /* Mask off the PTRG bit */
245 flags
|= PCI9111_AI_TRIG_CTRL_PTRG
;
247 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
250 static void pci9111_autoscan_set(struct comedi_device
*dev
, bool autoscan
)
254 /* Read the current trigger mode control bits */
255 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
256 /* Mask off the ASCAN bit */
260 flags
|= PCI9111_AI_TRIG_CTRL_ASCAN
;
262 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
265 enum pci9111_ISC0_sources
{
267 irq_on_fifo_half_full
270 enum pci9111_ISC1_sources
{
272 irq_on_external_trigger
275 static void pci9111_interrupt_source_set(struct comedi_device
*dev
,
276 enum pci9111_ISC0_sources irq_0_source
,
277 enum pci9111_ISC1_sources irq_1_source
)
281 /* Read the current interrupt control bits */
282 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
283 /* Shift the bits so they are compatible with the write register */
285 /* Mask off the ISCx bits */
288 /* Now set the new ISCx bits */
289 if (irq_0_source
== irq_on_fifo_half_full
)
290 flags
|= PCI9111_INT_CTRL_ISC0
;
292 if (irq_1_source
== irq_on_external_trigger
)
293 flags
|= PCI9111_INT_CTRL_ISC1
;
295 outb(flags
, dev
->iobase
+ PCI9111_INT_CTRL_REG
);
298 static void pci9111_fifo_reset(struct comedi_device
*dev
)
300 unsigned long int_ctrl_reg
= dev
->iobase
+ PCI9111_INT_CTRL_REG
;
302 /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
303 outb(0, int_ctrl_reg
);
304 outb(PCI9111_INT_CTRL_FFEN
, int_ctrl_reg
);
305 outb(0, int_ctrl_reg
);
308 static int pci9111_ai_cancel(struct comedi_device
*dev
,
309 struct comedi_subdevice
*s
)
311 struct pci9111_private_data
*dev_private
= dev
->private;
313 /* Disable interrupts */
314 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true, true,
317 pci9111_trigger_source_set(dev
, software
);
319 pci9111_autoscan_set(dev
, false);
321 pci9111_fifo_reset(dev
);
326 static int pci9111_ai_do_cmd_test(struct comedi_device
*dev
,
327 struct comedi_subdevice
*s
,
328 struct comedi_cmd
*cmd
)
330 struct pci9111_private_data
*dev_private
= dev
->private;
333 int range
, reference
;
336 /* Step 1 : check if triggers are trivially valid */
338 error
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
339 error
|= cfc_check_trigger_src(&cmd
->scan_begin_src
,
340 TRIG_TIMER
| TRIG_FOLLOW
| TRIG_EXT
);
341 error
|= cfc_check_trigger_src(&cmd
->convert_src
,
342 TRIG_TIMER
| TRIG_EXT
);
343 error
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
344 error
|= cfc_check_trigger_src(&cmd
->stop_src
,
345 TRIG_COUNT
| TRIG_NONE
);
350 /* Step 2a : make sure trigger sources are unique */
352 error
|= cfc_check_trigger_is_unique(cmd
->scan_begin_src
);
353 error
|= cfc_check_trigger_is_unique(cmd
->convert_src
);
354 error
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
356 /* Step 2b : and mutually compatible */
358 if ((cmd
->convert_src
== TRIG_TIMER
) &&
359 !((cmd
->scan_begin_src
== TRIG_TIMER
) ||
360 (cmd
->scan_begin_src
== TRIG_FOLLOW
)))
362 if ((cmd
->convert_src
== TRIG_EXT
) &&
363 !((cmd
->scan_begin_src
== TRIG_EXT
) ||
364 (cmd
->scan_begin_src
== TRIG_FOLLOW
)))
370 /* Step 3: check if arguments are trivially valid */
372 error
|= cfc_check_trigger_arg_is(&cmd
->start_arg
, 0);
374 if (cmd
->convert_src
== TRIG_TIMER
)
375 error
|= cfc_check_trigger_arg_min(&cmd
->convert_arg
,
376 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS
);
378 error
|= cfc_check_trigger_arg_is(&cmd
->convert_arg
, 0);
380 if (cmd
->scan_begin_src
== TRIG_TIMER
)
381 error
|= cfc_check_trigger_arg_min(&cmd
->scan_begin_arg
,
382 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS
);
383 else /* TRIG_FOLLOW || TRIG_EXT */
384 error
|= cfc_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
386 error
|= cfc_check_trigger_arg_is(&cmd
->scan_end_arg
,
389 if (cmd
->stop_src
== TRIG_COUNT
)
390 error
|= cfc_check_trigger_arg_min(&cmd
->stop_arg
, 1);
392 error
|= cfc_check_trigger_arg_is(&cmd
->stop_arg
, 0);
397 /* Step 4 : fix up any arguments */
399 if (cmd
->convert_src
== TRIG_TIMER
) {
400 tmp
= cmd
->convert_arg
;
401 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS
,
405 cmd
->flags
& TRIG_ROUND_MASK
);
406 if (tmp
!= cmd
->convert_arg
)
409 /* There's only one timer on this card, so the scan_begin timer must */
410 /* be a multiple of chanlist_len*convert_arg */
412 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
414 unsigned int scan_begin_min
;
415 unsigned int scan_begin_arg
;
416 unsigned int scan_factor
;
418 scan_begin_min
= cmd
->chanlist_len
* cmd
->convert_arg
;
420 if (cmd
->scan_begin_arg
!= scan_begin_min
) {
421 if (scan_begin_min
< cmd
->scan_begin_arg
) {
423 cmd
->scan_begin_arg
/ scan_begin_min
;
424 scan_begin_arg
= scan_factor
* scan_begin_min
;
425 if (cmd
->scan_begin_arg
!= scan_begin_arg
) {
426 cmd
->scan_begin_arg
= scan_begin_arg
;
430 cmd
->scan_begin_arg
= scan_begin_min
;
439 /* Step 5 : check channel list */
443 range
= CR_RANGE(cmd
->chanlist
[0]);
444 reference
= CR_AREF(cmd
->chanlist
[0]);
446 if (cmd
->chanlist_len
> 1) {
447 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
448 if (CR_CHAN(cmd
->chanlist
[i
]) != i
) {
450 "entries in chanlist must be consecutive "
451 "channels,counting upwards from 0\n");
454 if (CR_RANGE(cmd
->chanlist
[i
]) != range
) {
456 "entries in chanlist must all have the same gain\n");
459 if (CR_AREF(cmd
->chanlist
[i
]) != reference
) {
461 "entries in chanlist must all have the same reference\n");
475 static int pci9111_ai_do_cmd(struct comedi_device
*dev
,
476 struct comedi_subdevice
*s
)
478 struct pci9111_private_data
*dev_private
= dev
->private;
479 struct comedi_cmd
*async_cmd
= &s
->async
->cmd
;
483 "no irq assigned for PCI9111, cannot do hardware conversion");
486 /* Set channel scan limit */
487 /* PCI9111 allows only scanning from channel 0 to channel n */
488 /* TODO: handle the case of an external multiplexer */
490 if (async_cmd
->chanlist_len
> 1) {
491 outb(async_cmd
->chanlist_len
- 1,
492 dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
493 pci9111_autoscan_set(dev
, true);
495 outb(CR_CHAN(async_cmd
->chanlist
[0]),
496 dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
497 pci9111_autoscan_set(dev
, false);
501 /* This is the same gain on every channel */
503 outb(CR_RANGE(async_cmd
->chanlist
[0]) & PCI9111_AI_RANGE_MASK
,
504 dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
508 switch (async_cmd
->stop_src
) {
510 dev_private
->stop_counter
=
511 async_cmd
->stop_arg
* async_cmd
->chanlist_len
;
512 dev_private
->stop_is_none
= 0;
516 dev_private
->stop_counter
= 0;
517 dev_private
->stop_is_none
= 1;
521 comedi_error(dev
, "Invalid stop trigger");
525 /* Set timer pacer */
527 dev_private
->scan_delay
= 0;
528 switch (async_cmd
->convert_src
) {
530 pci9111_trigger_source_set(dev
, software
);
531 pci9111_timer_set(dev
);
532 pci9111_fifo_reset(dev
);
533 pci9111_interrupt_source_set(dev
, irq_on_fifo_half_full
,
535 pci9111_trigger_source_set(dev
, timer_pacer
);
536 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true,
539 if (async_cmd
->scan_begin_src
== TRIG_TIMER
) {
540 dev_private
->scan_delay
=
541 (async_cmd
->scan_begin_arg
/
542 (async_cmd
->convert_arg
*
543 async_cmd
->chanlist_len
)) - 1;
550 pci9111_trigger_source_set(dev
, external
);
551 pci9111_fifo_reset(dev
);
552 pci9111_interrupt_source_set(dev
, irq_on_fifo_half_full
,
554 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true,
560 comedi_error(dev
, "Invalid convert trigger");
564 dev_private
->stop_counter
*= (1 + dev_private
->scan_delay
);
565 dev_private
->chanlist_len
= async_cmd
->chanlist_len
;
566 dev_private
->chunk_counter
= 0;
567 dev_private
->chunk_num_samples
=
568 dev_private
->chanlist_len
* (1 + dev_private
->scan_delay
);
573 static void pci9111_ai_munge(struct comedi_device
*dev
,
574 struct comedi_subdevice
*s
, void *data
,
575 unsigned int num_bytes
,
576 unsigned int start_chan_index
)
579 unsigned int maxdata
= s
->maxdata
;
580 unsigned int invert
= (maxdata
+ 1) >> 1;
581 unsigned int shift
= (maxdata
== 0xffff) ? 0 : 4;
582 unsigned int num_samples
= num_bytes
/ sizeof(short);
585 for (i
= 0; i
< num_samples
; i
++)
586 array
[i
] = ((array
[i
] >> shift
) & maxdata
) ^ invert
;
589 static irqreturn_t
pci9111_interrupt(int irq
, void *p_device
)
591 struct comedi_device
*dev
= p_device
;
592 struct pci9111_private_data
*dev_private
= dev
->private;
593 struct comedi_subdevice
*s
= dev
->read_subdev
;
594 struct comedi_async
*async
;
596 unsigned long irq_flags
;
597 unsigned char intcsr
;
599 if (!dev
->attached
) {
600 /* Ignore interrupt before device fully attached. */
601 /* Might not even have allocated subdevices yet! */
607 spin_lock_irqsave(&dev
->spinlock
, irq_flags
);
609 /* Check if we are source of interrupt */
610 intcsr
= inb(dev_private
->lcr_io_base
+
611 PLX9050_REGISTER_INTERRUPT_CONTROL
);
612 if (!(((intcsr
& PLX9050_PCI_INTERRUPT_ENABLE
) != 0)
613 && (((intcsr
& (PLX9050_LINTI1_ENABLE
| PLX9050_LINTI1_STATUS
))
614 == (PLX9050_LINTI1_ENABLE
| PLX9050_LINTI1_STATUS
))
615 || ((intcsr
& (PLX9050_LINTI2_ENABLE
| PLX9050_LINTI2_STATUS
))
616 == (PLX9050_LINTI2_ENABLE
| PLX9050_LINTI2_STATUS
))))) {
617 /* Not the source of the interrupt. */
618 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
619 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
623 if ((intcsr
& (PLX9050_LINTI1_ENABLE
| PLX9050_LINTI1_STATUS
)) ==
624 (PLX9050_LINTI1_ENABLE
| PLX9050_LINTI1_STATUS
)) {
625 /* Interrupt comes from fifo_half-full signal */
627 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
629 /* '0' means FIFO is full, data may have been lost */
630 if (!(status
& PCI9111_AI_STAT_FF_FF
)) {
631 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
632 comedi_error(dev
, PCI9111_DRIVER_NAME
" fifo overflow");
633 outb(0, dev
->iobase
+ PCI9111_INT_CLR_REG
);
634 pci9111_ai_cancel(dev
, s
);
635 async
->events
|= COMEDI_CB_ERROR
| COMEDI_CB_EOA
;
636 comedi_event(dev
, s
);
641 /* '0' means FIFO is half-full */
642 if (!(status
& PCI9111_AI_STAT_FF_HF
)) {
643 unsigned int num_samples
;
644 unsigned int bytes_written
= 0;
647 PCI9111_FIFO_HALF_SIZE
>
648 dev_private
->stop_counter
650 stop_is_none
? dev_private
->stop_counter
:
651 PCI9111_FIFO_HALF_SIZE
;
652 insw(dev
->iobase
+ PCI9111_AI_FIFO_REG
,
653 dev_private
->ai_bounce_buffer
, num_samples
);
655 if (dev_private
->scan_delay
< 1) {
657 cfc_write_array_to_buffer(s
,
666 while (position
< num_samples
) {
667 if (dev_private
->chunk_counter
<
668 dev_private
->chanlist_len
) {
670 dev_private
->chanlist_len
-
671 dev_private
->chunk_counter
;
674 num_samples
- position
)
680 cfc_write_array_to_buffer
682 dev_private
->ai_bounce_buffer
684 to_read
* sizeof(short));
687 dev_private
->chunk_num_samples
689 dev_private
->chunk_counter
;
691 num_samples
- position
)
697 sizeof(short) * to_read
;
701 dev_private
->chunk_counter
+= to_read
;
703 if (dev_private
->chunk_counter
>=
704 dev_private
->chunk_num_samples
)
705 dev_private
->chunk_counter
= 0;
709 dev_private
->stop_counter
-=
710 bytes_written
/ sizeof(short);
714 if ((dev_private
->stop_counter
== 0) && (!dev_private
->stop_is_none
)) {
715 async
->events
|= COMEDI_CB_EOA
;
716 pci9111_ai_cancel(dev
, s
);
719 outb(0, dev
->iobase
+ PCI9111_INT_CLR_REG
);
721 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
723 comedi_event(dev
, s
);
728 static int pci9111_ai_insn_read(struct comedi_device
*dev
,
729 struct comedi_subdevice
*s
,
730 struct comedi_insn
*insn
, unsigned int *data
)
732 unsigned int chan
= CR_CHAN(insn
->chanspec
);
733 unsigned int range
= CR_RANGE(insn
->chanspec
);
734 unsigned int maxdata
= s
->maxdata
;
735 unsigned int invert
= (maxdata
+ 1) >> 1;
736 unsigned int shift
= (maxdata
== 0xffff) ? 0 : 4;
741 outb(chan
, dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
743 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
744 if ((status
& PCI9111_AI_RANGE_MASK
) != range
) {
745 outb(range
& PCI9111_AI_RANGE_MASK
,
746 dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
749 pci9111_fifo_reset(dev
);
751 for (i
= 0; i
< insn
->n
; i
++) {
752 /* Generate a software trigger */
753 outb(0, dev
->iobase
+ PCI9111_SOFT_TRIG_REG
);
755 timeout
= PCI9111_AI_INSTANT_READ_TIMEOUT
;
758 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
759 /* '1' means FIFO is not empty */
760 if (status
& PCI9111_AI_STAT_FF_EF
)
761 goto conversion_done
;
764 comedi_error(dev
, "A/D read timeout");
766 pci9111_fifo_reset(dev
);
771 data
[i
] = inw(dev
->iobase
+ PCI9111_AI_FIFO_REG
);
772 data
[i
] = ((data
[i
] >> shift
) & maxdata
) ^ invert
;
778 static int pci9111_ao_insn_write(struct comedi_device
*dev
,
779 struct comedi_subdevice
*s
,
780 struct comedi_insn
*insn
,
783 struct pci9111_private_data
*dev_private
= dev
->private;
784 unsigned int val
= 0;
787 for (i
= 0; i
< insn
->n
; i
++) {
789 outw(val
, dev
->iobase
+ PCI9111_AO_REG
);
791 dev_private
->ao_readback
= val
;
796 static int pci9111_ao_insn_read(struct comedi_device
*dev
,
797 struct comedi_subdevice
*s
,
798 struct comedi_insn
*insn
,
801 struct pci9111_private_data
*dev_private
= dev
->private;
804 for (i
= 0; i
< insn
->n
; i
++)
805 data
[i
] = dev_private
->ao_readback
;
810 static int pci9111_di_insn_bits(struct comedi_device
*dev
,
811 struct comedi_subdevice
*s
,
812 struct comedi_insn
*insn
,
815 data
[1] = inw(dev
->iobase
+ PCI9111_DIO_REG
);
820 static int pci9111_do_insn_bits(struct comedi_device
*dev
,
821 struct comedi_subdevice
*s
,
822 struct comedi_insn
*insn
,
825 unsigned int mask
= data
[0];
826 unsigned int bits
= data
[1];
830 s
->state
|= (bits
& mask
);
832 outw(s
->state
, dev
->iobase
+ PCI9111_DIO_REG
);
840 static int pci9111_reset(struct comedi_device
*dev
)
842 struct pci9111_private_data
*dev_private
= dev
->private;
844 /* Set trigger source to software */
845 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true, true,
848 pci9111_trigger_source_set(dev
, software
);
849 pci9111_pretrigger_set(dev
, false);
850 pci9111_autoscan_set(dev
, false);
852 /* Reset 8254 chip */
853 dev_private
->div1
= 0;
854 dev_private
->div2
= 0;
855 pci9111_timer_set(dev
);
860 static int pci9111_auto_attach(struct comedi_device
*dev
,
861 unsigned long context_unused
)
863 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
864 struct pci9111_private_data
*dev_private
;
865 struct comedi_subdevice
*s
;
868 dev_private
= kzalloc(sizeof(*dev_private
), GFP_KERNEL
);
871 dev
->private = dev_private
;
873 ret
= comedi_pci_enable(dev
);
876 dev_private
->lcr_io_base
= pci_resource_start(pcidev
, 1);
877 dev
->iobase
= pci_resource_start(pcidev
, 2);
881 if (pcidev
->irq
> 0) {
882 ret
= request_irq(dev
->irq
, pci9111_interrupt
,
883 IRQF_SHARED
, dev
->board_name
, dev
);
886 dev
->irq
= pcidev
->irq
;
889 ret
= comedi_alloc_subdevices(dev
, 4);
893 s
= &dev
->subdevices
[0];
894 dev
->read_subdev
= s
;
895 s
->type
= COMEDI_SUBD_AI
;
896 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_CMD_READ
;
899 s
->len_chanlist
= 16;
900 s
->range_table
= &pci9111_ai_range
;
901 s
->cancel
= pci9111_ai_cancel
;
902 s
->insn_read
= pci9111_ai_insn_read
;
903 s
->do_cmdtest
= pci9111_ai_do_cmd_test
;
904 s
->do_cmd
= pci9111_ai_do_cmd
;
905 s
->munge
= pci9111_ai_munge
;
907 s
= &dev
->subdevices
[1];
908 s
->type
= COMEDI_SUBD_AO
;
909 s
->subdev_flags
= SDF_WRITABLE
| SDF_COMMON
;
913 s
->range_table
= &range_bipolar10
;
914 s
->insn_write
= pci9111_ao_insn_write
;
915 s
->insn_read
= pci9111_ao_insn_read
;
917 s
= &dev
->subdevices
[2];
918 s
->type
= COMEDI_SUBD_DI
;
919 s
->subdev_flags
= SDF_READABLE
;
922 s
->range_table
= &range_digital
;
923 s
->insn_bits
= pci9111_di_insn_bits
;
925 s
= &dev
->subdevices
[3];
926 s
->type
= COMEDI_SUBD_DO
;
927 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
930 s
->range_table
= &range_digital
;
931 s
->insn_bits
= pci9111_do_insn_bits
;
933 dev_info(dev
->class_dev
, "%s attached\n", dev
->board_name
);
938 static void pci9111_detach(struct comedi_device
*dev
)
943 free_irq(dev
->irq
, dev
);
944 comedi_pci_disable(dev
);
947 static struct comedi_driver adl_pci9111_driver
= {
948 .driver_name
= "adl_pci9111",
949 .module
= THIS_MODULE
,
950 .auto_attach
= pci9111_auto_attach
,
951 .detach
= pci9111_detach
,
954 static int pci9111_pci_probe(struct pci_dev
*dev
,
955 const struct pci_device_id
*id
)
957 return comedi_pci_auto_config(dev
, &adl_pci9111_driver
,
961 static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table
) = {
962 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK
, PCI9111_HR_DEVICE_ID
) },
963 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
966 MODULE_DEVICE_TABLE(pci
, pci9111_pci_table
);
968 static struct pci_driver adl_pci9111_pci_driver
= {
969 .name
= "adl_pci9111",
970 .id_table
= pci9111_pci_table
,
971 .probe
= pci9111_pci_probe
,
972 .remove
= comedi_pci_auto_unconfig
,
974 module_comedi_pci_driver(adl_pci9111_driver
, adl_pci9111_pci_driver
);
976 MODULE_AUTHOR("Comedi http://www.comedi.org");
977 MODULE_DESCRIPTION("Comedi low-level driver");
978 MODULE_LICENSE("GPL");