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.
24 Description: Adlink PCI-9111HR
25 Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
26 Devices: [ADLink] PCI-9111HR (adl_pci9111)
35 - ai_do_cmd mode with the following sources:
38 - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT
39 - convert_src TRIG_TIMER TRIG_EXT
40 - scan_end_src TRIG_COUNT
41 - stop_src TRIG_COUNT TRIG_NONE
43 The scanned channels must be consecutive and start from 0. They must
44 all have the same range and aref.
46 Configuration options: not applicable, uses PCI auto config
52 2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
53 a multiple of chanlist_len*convert_arg.
54 2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
55 2002/02/18 Added external trigger support for analog input.
59 - Really test implemented functionality.
60 - Add support for the PCI-9111DG with a probe routine to identify
61 the card type (perhaps with the help of the channel number readback
62 of the A/D Data register).
63 - Add external multiplexer support.
67 #include <linux/module.h>
68 #include <linux/pci.h>
69 #include <linux/delay.h>
70 #include <linux/interrupt.h>
72 #include "../comedidev.h"
76 #include "comedi_fc.h"
78 #define PCI9111_DRIVER_NAME "adl_pci9111"
79 #define PCI9111_HR_DEVICE_ID 0x9111
81 #define PCI9111_FIFO_HALF_SIZE 512
83 #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
85 #define PCI9111_RANGE_SETTING_DELAY 10
86 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2
87 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100
90 * IO address map and bit defines
92 #define PCI9111_AI_FIFO_REG 0x00
93 #define PCI9111_AO_REG 0x00
94 #define PCI9111_DIO_REG 0x02
95 #define PCI9111_EDIO_REG 0x04
96 #define PCI9111_AI_CHANNEL_REG 0x06
97 #define PCI9111_AI_RANGE_STAT_REG 0x08
98 #define PCI9111_AI_STAT_AD_BUSY (1 << 7)
99 #define PCI9111_AI_STAT_FF_FF (1 << 6)
100 #define PCI9111_AI_STAT_FF_HF (1 << 5)
101 #define PCI9111_AI_STAT_FF_EF (1 << 4)
102 #define PCI9111_AI_RANGE_MASK (7 << 0)
103 #define PCI9111_AI_TRIG_CTRL_REG 0x0a
104 #define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5)
105 #define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4)
106 #define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3)
107 #define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2)
108 #define PCI9111_AI_TRIG_CTRL_TPST (1 << 1)
109 #define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0)
110 #define PCI9111_INT_CTRL_REG 0x0c
111 #define PCI9111_INT_CTRL_ISC2 (1 << 3)
112 #define PCI9111_INT_CTRL_FFEN (1 << 2)
113 #define PCI9111_INT_CTRL_ISC1 (1 << 1)
114 #define PCI9111_INT_CTRL_ISC0 (1 << 0)
115 #define PCI9111_SOFT_TRIG_REG 0x0e
116 #define PCI9111_8254_BASE_REG 0x40
117 #define PCI9111_INT_CLR_REG 0x48
119 /* PLX 9052 Local Interrupt 1 enabled and active */
120 #define PCI9111_LI1_ACTIVE (PLX9052_INTCSR_LI1ENAB | \
121 PLX9052_INTCSR_LI1STAT)
123 /* PLX 9052 Local Interrupt 2 enabled and active */
124 #define PCI9111_LI2_ACTIVE (PLX9052_INTCSR_LI2ENAB | \
125 PLX9052_INTCSR_LI2STAT)
127 static const struct comedi_lrange pci9111_ai_range
= {
138 struct pci9111_private_data
{
139 unsigned long lcr_io_base
;
144 unsigned int scan_delay
;
145 unsigned int chanlist_len
;
146 unsigned int chunk_counter
;
147 unsigned int chunk_num_samples
;
154 unsigned short ai_bounce_buffer
[2 * PCI9111_FIFO_HALF_SIZE
];
157 static void plx9050_interrupt_control(unsigned long io_base
,
159 bool LINTi1_active_high
,
161 bool LINTi2_active_high
,
162 bool interrupt_enable
)
167 flags
|= PLX9052_INTCSR_LI1ENAB
;
168 if (LINTi1_active_high
)
169 flags
|= PLX9052_INTCSR_LI1POL
;
171 flags
|= PLX9052_INTCSR_LI2ENAB
;
172 if (LINTi2_active_high
)
173 flags
|= PLX9052_INTCSR_LI2POL
;
175 if (interrupt_enable
)
176 flags
|= PLX9052_INTCSR_PCIENAB
;
178 outb(flags
, io_base
+ PLX9052_INTCSR
);
181 static void pci9111_timer_set(struct comedi_device
*dev
)
183 struct pci9111_private_data
*dev_private
= dev
->private;
184 unsigned long timer_base
= dev
->iobase
+ PCI9111_8254_BASE_REG
;
186 i8254_set_mode(timer_base
, 1, 0, I8254_MODE0
| I8254_BINARY
);
187 i8254_set_mode(timer_base
, 1, 1, I8254_MODE2
| I8254_BINARY
);
188 i8254_set_mode(timer_base
, 1, 2, I8254_MODE2
| I8254_BINARY
);
192 i8254_write(timer_base
, 1, 2, dev_private
->div2
);
193 i8254_write(timer_base
, 1, 1, dev_private
->div1
);
196 enum pci9111_trigger_sources
{
202 static void pci9111_trigger_source_set(struct comedi_device
*dev
,
203 enum pci9111_trigger_sources source
)
207 /* Read the current trigger mode control bits */
208 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
209 /* Mask off the EITS and TPST bits */
217 flags
|= PCI9111_AI_TRIG_CTRL_TPST
;
221 flags
|= PCI9111_AI_TRIG_CTRL_ETIS
;
225 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
228 static void pci9111_pretrigger_set(struct comedi_device
*dev
, bool pretrigger
)
232 /* Read the current trigger mode control bits */
233 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
234 /* Mask off the PTRG bit */
238 flags
|= PCI9111_AI_TRIG_CTRL_PTRG
;
240 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
243 static void pci9111_autoscan_set(struct comedi_device
*dev
, bool autoscan
)
247 /* Read the current trigger mode control bits */
248 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
249 /* Mask off the ASCAN bit */
253 flags
|= PCI9111_AI_TRIG_CTRL_ASCAN
;
255 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
258 enum pci9111_ISC0_sources
{
260 irq_on_fifo_half_full
263 enum pci9111_ISC1_sources
{
265 irq_on_external_trigger
268 static void pci9111_interrupt_source_set(struct comedi_device
*dev
,
269 enum pci9111_ISC0_sources irq_0_source
,
270 enum pci9111_ISC1_sources irq_1_source
)
274 /* Read the current interrupt control bits */
275 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
276 /* Shift the bits so they are compatible with the write register */
278 /* Mask off the ISCx bits */
281 /* Now set the new ISCx bits */
282 if (irq_0_source
== irq_on_fifo_half_full
)
283 flags
|= PCI9111_INT_CTRL_ISC0
;
285 if (irq_1_source
== irq_on_external_trigger
)
286 flags
|= PCI9111_INT_CTRL_ISC1
;
288 outb(flags
, dev
->iobase
+ PCI9111_INT_CTRL_REG
);
291 static void pci9111_fifo_reset(struct comedi_device
*dev
)
293 unsigned long int_ctrl_reg
= dev
->iobase
+ PCI9111_INT_CTRL_REG
;
295 /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
296 outb(0, int_ctrl_reg
);
297 outb(PCI9111_INT_CTRL_FFEN
, int_ctrl_reg
);
298 outb(0, int_ctrl_reg
);
301 static int pci9111_ai_cancel(struct comedi_device
*dev
,
302 struct comedi_subdevice
*s
)
304 struct pci9111_private_data
*dev_private
= dev
->private;
306 /* Disable interrupts */
307 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true, true,
310 pci9111_trigger_source_set(dev
, software
);
312 pci9111_autoscan_set(dev
, false);
314 pci9111_fifo_reset(dev
);
319 static int pci9111_ai_do_cmd_test(struct comedi_device
*dev
,
320 struct comedi_subdevice
*s
,
321 struct comedi_cmd
*cmd
)
323 struct pci9111_private_data
*dev_private
= dev
->private;
326 int range
, reference
;
329 /* Step 1 : check if triggers are trivially valid */
331 error
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
332 error
|= cfc_check_trigger_src(&cmd
->scan_begin_src
,
333 TRIG_TIMER
| TRIG_FOLLOW
| TRIG_EXT
);
334 error
|= cfc_check_trigger_src(&cmd
->convert_src
,
335 TRIG_TIMER
| TRIG_EXT
);
336 error
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
337 error
|= cfc_check_trigger_src(&cmd
->stop_src
,
338 TRIG_COUNT
| TRIG_NONE
);
343 /* Step 2a : make sure trigger sources are unique */
345 error
|= cfc_check_trigger_is_unique(cmd
->scan_begin_src
);
346 error
|= cfc_check_trigger_is_unique(cmd
->convert_src
);
347 error
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
349 /* Step 2b : and mutually compatible */
351 if ((cmd
->convert_src
== TRIG_TIMER
) &&
352 !((cmd
->scan_begin_src
== TRIG_TIMER
) ||
353 (cmd
->scan_begin_src
== TRIG_FOLLOW
)))
355 if ((cmd
->convert_src
== TRIG_EXT
) &&
356 !((cmd
->scan_begin_src
== TRIG_EXT
) ||
357 (cmd
->scan_begin_src
== TRIG_FOLLOW
)))
363 /* Step 3: check if arguments are trivially valid */
365 error
|= cfc_check_trigger_arg_is(&cmd
->start_arg
, 0);
367 if (cmd
->convert_src
== TRIG_TIMER
)
368 error
|= cfc_check_trigger_arg_min(&cmd
->convert_arg
,
369 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS
);
371 error
|= cfc_check_trigger_arg_is(&cmd
->convert_arg
, 0);
373 if (cmd
->scan_begin_src
== TRIG_TIMER
)
374 error
|= cfc_check_trigger_arg_min(&cmd
->scan_begin_arg
,
375 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS
);
376 else /* TRIG_FOLLOW || TRIG_EXT */
377 error
|= cfc_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
379 error
|= cfc_check_trigger_arg_is(&cmd
->scan_end_arg
,
382 if (cmd
->stop_src
== TRIG_COUNT
)
383 error
|= cfc_check_trigger_arg_min(&cmd
->stop_arg
, 1);
385 error
|= cfc_check_trigger_arg_is(&cmd
->stop_arg
, 0);
390 /* Step 4 : fix up any arguments */
392 if (cmd
->convert_src
== TRIG_TIMER
) {
393 tmp
= cmd
->convert_arg
;
394 i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ
,
397 &cmd
->convert_arg
, cmd
->flags
);
398 if (tmp
!= cmd
->convert_arg
)
401 /* There's only one timer on this card, so the scan_begin timer must */
402 /* be a multiple of chanlist_len*convert_arg */
404 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
406 unsigned int scan_begin_min
;
407 unsigned int scan_begin_arg
;
408 unsigned int scan_factor
;
410 scan_begin_min
= cmd
->chanlist_len
* cmd
->convert_arg
;
412 if (cmd
->scan_begin_arg
!= scan_begin_min
) {
413 if (scan_begin_min
< cmd
->scan_begin_arg
) {
415 cmd
->scan_begin_arg
/ scan_begin_min
;
416 scan_begin_arg
= scan_factor
* scan_begin_min
;
417 if (cmd
->scan_begin_arg
!= scan_begin_arg
) {
418 cmd
->scan_begin_arg
= scan_begin_arg
;
422 cmd
->scan_begin_arg
= scan_begin_min
;
431 /* Step 5 : check channel list */
435 range
= CR_RANGE(cmd
->chanlist
[0]);
436 reference
= CR_AREF(cmd
->chanlist
[0]);
438 if (cmd
->chanlist_len
> 1) {
439 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
440 if (CR_CHAN(cmd
->chanlist
[i
]) != i
) {
442 "entries in chanlist must be consecutive "
443 "channels,counting upwards from 0\n");
446 if (CR_RANGE(cmd
->chanlist
[i
]) != range
) {
448 "entries in chanlist must all have the same gain\n");
451 if (CR_AREF(cmd
->chanlist
[i
]) != reference
) {
453 "entries in chanlist must all have the same reference\n");
467 static int pci9111_ai_do_cmd(struct comedi_device
*dev
,
468 struct comedi_subdevice
*s
)
470 struct pci9111_private_data
*dev_private
= dev
->private;
471 struct comedi_cmd
*async_cmd
= &s
->async
->cmd
;
475 "no irq assigned for PCI9111, cannot do hardware conversion");
478 /* Set channel scan limit */
479 /* PCI9111 allows only scanning from channel 0 to channel n */
480 /* TODO: handle the case of an external multiplexer */
482 if (async_cmd
->chanlist_len
> 1) {
483 outb(async_cmd
->chanlist_len
- 1,
484 dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
485 pci9111_autoscan_set(dev
, true);
487 outb(CR_CHAN(async_cmd
->chanlist
[0]),
488 dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
489 pci9111_autoscan_set(dev
, false);
493 /* This is the same gain on every channel */
495 outb(CR_RANGE(async_cmd
->chanlist
[0]) & PCI9111_AI_RANGE_MASK
,
496 dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
500 switch (async_cmd
->stop_src
) {
502 dev_private
->stop_counter
=
503 async_cmd
->stop_arg
* async_cmd
->chanlist_len
;
504 dev_private
->stop_is_none
= 0;
508 dev_private
->stop_counter
= 0;
509 dev_private
->stop_is_none
= 1;
513 comedi_error(dev
, "Invalid stop trigger");
517 /* Set timer pacer */
519 dev_private
->scan_delay
= 0;
520 switch (async_cmd
->convert_src
) {
522 pci9111_trigger_source_set(dev
, software
);
523 pci9111_timer_set(dev
);
524 pci9111_fifo_reset(dev
);
525 pci9111_interrupt_source_set(dev
, irq_on_fifo_half_full
,
527 pci9111_trigger_source_set(dev
, timer_pacer
);
528 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true,
531 if (async_cmd
->scan_begin_src
== TRIG_TIMER
) {
532 dev_private
->scan_delay
=
533 (async_cmd
->scan_begin_arg
/
534 (async_cmd
->convert_arg
*
535 async_cmd
->chanlist_len
)) - 1;
542 pci9111_trigger_source_set(dev
, external
);
543 pci9111_fifo_reset(dev
);
544 pci9111_interrupt_source_set(dev
, irq_on_fifo_half_full
,
546 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true,
552 comedi_error(dev
, "Invalid convert trigger");
556 dev_private
->stop_counter
*= (1 + dev_private
->scan_delay
);
557 dev_private
->chanlist_len
= async_cmd
->chanlist_len
;
558 dev_private
->chunk_counter
= 0;
559 dev_private
->chunk_num_samples
=
560 dev_private
->chanlist_len
* (1 + dev_private
->scan_delay
);
565 static void pci9111_ai_munge(struct comedi_device
*dev
,
566 struct comedi_subdevice
*s
, void *data
,
567 unsigned int num_bytes
,
568 unsigned int start_chan_index
)
570 unsigned short *array
= data
;
571 unsigned int maxdata
= s
->maxdata
;
572 unsigned int invert
= (maxdata
+ 1) >> 1;
573 unsigned int shift
= (maxdata
== 0xffff) ? 0 : 4;
574 unsigned int num_samples
= num_bytes
/ sizeof(short);
577 for (i
= 0; i
< num_samples
; i
++)
578 array
[i
] = ((array
[i
] >> shift
) & maxdata
) ^ invert
;
581 static irqreturn_t
pci9111_interrupt(int irq
, void *p_device
)
583 struct comedi_device
*dev
= p_device
;
584 struct pci9111_private_data
*dev_private
= dev
->private;
585 struct comedi_subdevice
*s
= dev
->read_subdev
;
586 struct comedi_async
*async
;
588 unsigned long irq_flags
;
589 unsigned char intcsr
;
591 if (!dev
->attached
) {
592 /* Ignore interrupt before device fully attached. */
593 /* Might not even have allocated subdevices yet! */
599 spin_lock_irqsave(&dev
->spinlock
, irq_flags
);
601 /* Check if we are source of interrupt */
602 intcsr
= inb(dev_private
->lcr_io_base
+ PLX9052_INTCSR
);
603 if (!(((intcsr
& PLX9052_INTCSR_PCIENAB
) != 0) &&
604 (((intcsr
& PCI9111_LI1_ACTIVE
) == PCI9111_LI1_ACTIVE
) ||
605 ((intcsr
& PCI9111_LI2_ACTIVE
) == PCI9111_LI2_ACTIVE
)))) {
606 /* Not the source of the interrupt. */
607 /* (N.B. not using PLX9052_INTCSR_SOFTINT) */
608 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
612 if ((intcsr
& PCI9111_LI1_ACTIVE
) == PCI9111_LI1_ACTIVE
) {
613 /* Interrupt comes from fifo_half-full signal */
615 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
617 /* '0' means FIFO is full, data may have been lost */
618 if (!(status
& PCI9111_AI_STAT_FF_FF
)) {
619 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
620 comedi_error(dev
, PCI9111_DRIVER_NAME
" fifo overflow");
621 outb(0, dev
->iobase
+ PCI9111_INT_CLR_REG
);
622 pci9111_ai_cancel(dev
, s
);
623 async
->events
|= COMEDI_CB_ERROR
| COMEDI_CB_EOA
;
624 comedi_event(dev
, s
);
629 /* '0' means FIFO is half-full */
630 if (!(status
& PCI9111_AI_STAT_FF_HF
)) {
631 unsigned int num_samples
;
632 unsigned int bytes_written
= 0;
635 PCI9111_FIFO_HALF_SIZE
>
636 dev_private
->stop_counter
638 stop_is_none
? dev_private
->stop_counter
:
639 PCI9111_FIFO_HALF_SIZE
;
640 insw(dev
->iobase
+ PCI9111_AI_FIFO_REG
,
641 dev_private
->ai_bounce_buffer
, num_samples
);
643 if (dev_private
->scan_delay
< 1) {
645 cfc_write_array_to_buffer(s
,
654 while (position
< num_samples
) {
655 if (dev_private
->chunk_counter
<
656 dev_private
->chanlist_len
) {
658 dev_private
->chanlist_len
-
659 dev_private
->chunk_counter
;
662 num_samples
- position
)
668 cfc_write_array_to_buffer
670 dev_private
->ai_bounce_buffer
672 to_read
* sizeof(short));
675 dev_private
->chunk_num_samples
677 dev_private
->chunk_counter
;
679 num_samples
- position
)
685 sizeof(short) * to_read
;
689 dev_private
->chunk_counter
+= to_read
;
691 if (dev_private
->chunk_counter
>=
692 dev_private
->chunk_num_samples
)
693 dev_private
->chunk_counter
= 0;
697 dev_private
->stop_counter
-=
698 bytes_written
/ sizeof(short);
702 if ((dev_private
->stop_counter
== 0) && (!dev_private
->stop_is_none
)) {
703 async
->events
|= COMEDI_CB_EOA
;
704 pci9111_ai_cancel(dev
, s
);
707 outb(0, dev
->iobase
+ PCI9111_INT_CLR_REG
);
709 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
711 comedi_event(dev
, s
);
716 static int pci9111_ai_insn_read(struct comedi_device
*dev
,
717 struct comedi_subdevice
*s
,
718 struct comedi_insn
*insn
, unsigned int *data
)
720 unsigned int chan
= CR_CHAN(insn
->chanspec
);
721 unsigned int range
= CR_RANGE(insn
->chanspec
);
722 unsigned int maxdata
= s
->maxdata
;
723 unsigned int invert
= (maxdata
+ 1) >> 1;
724 unsigned int shift
= (maxdata
== 0xffff) ? 0 : 4;
729 outb(chan
, dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
731 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
732 if ((status
& PCI9111_AI_RANGE_MASK
) != range
) {
733 outb(range
& PCI9111_AI_RANGE_MASK
,
734 dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
737 pci9111_fifo_reset(dev
);
739 for (i
= 0; i
< insn
->n
; i
++) {
740 /* Generate a software trigger */
741 outb(0, dev
->iobase
+ PCI9111_SOFT_TRIG_REG
);
743 timeout
= PCI9111_AI_INSTANT_READ_TIMEOUT
;
746 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
747 /* '1' means FIFO is not empty */
748 if (status
& PCI9111_AI_STAT_FF_EF
)
749 goto conversion_done
;
752 comedi_error(dev
, "A/D read timeout");
754 pci9111_fifo_reset(dev
);
759 data
[i
] = inw(dev
->iobase
+ PCI9111_AI_FIFO_REG
);
760 data
[i
] = ((data
[i
] >> shift
) & maxdata
) ^ invert
;
766 static int pci9111_ao_insn_write(struct comedi_device
*dev
,
767 struct comedi_subdevice
*s
,
768 struct comedi_insn
*insn
,
771 struct pci9111_private_data
*dev_private
= dev
->private;
772 unsigned int val
= 0;
775 for (i
= 0; i
< insn
->n
; i
++) {
777 outw(val
, dev
->iobase
+ PCI9111_AO_REG
);
779 dev_private
->ao_readback
= val
;
784 static int pci9111_ao_insn_read(struct comedi_device
*dev
,
785 struct comedi_subdevice
*s
,
786 struct comedi_insn
*insn
,
789 struct pci9111_private_data
*dev_private
= dev
->private;
792 for (i
= 0; i
< insn
->n
; i
++)
793 data
[i
] = dev_private
->ao_readback
;
798 static int pci9111_di_insn_bits(struct comedi_device
*dev
,
799 struct comedi_subdevice
*s
,
800 struct comedi_insn
*insn
,
803 data
[1] = inw(dev
->iobase
+ PCI9111_DIO_REG
);
808 static int pci9111_do_insn_bits(struct comedi_device
*dev
,
809 struct comedi_subdevice
*s
,
810 struct comedi_insn
*insn
,
813 if (comedi_dio_update_state(s
, data
))
814 outw(s
->state
, dev
->iobase
+ PCI9111_DIO_REG
);
821 static int pci9111_reset(struct comedi_device
*dev
)
823 struct pci9111_private_data
*dev_private
= dev
->private;
825 /* Set trigger source to software */
826 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true, true,
829 pci9111_trigger_source_set(dev
, software
);
830 pci9111_pretrigger_set(dev
, false);
831 pci9111_autoscan_set(dev
, false);
833 /* Reset 8254 chip */
834 dev_private
->div1
= 0;
835 dev_private
->div2
= 0;
836 pci9111_timer_set(dev
);
841 static int pci9111_auto_attach(struct comedi_device
*dev
,
842 unsigned long context_unused
)
844 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
845 struct pci9111_private_data
*dev_private
;
846 struct comedi_subdevice
*s
;
849 dev_private
= comedi_alloc_devpriv(dev
, sizeof(*dev_private
));
853 ret
= comedi_pci_enable(dev
);
856 dev_private
->lcr_io_base
= pci_resource_start(pcidev
, 1);
857 dev
->iobase
= pci_resource_start(pcidev
, 2);
861 if (pcidev
->irq
> 0) {
862 ret
= request_irq(dev
->irq
, pci9111_interrupt
,
863 IRQF_SHARED
, dev
->board_name
, dev
);
866 dev
->irq
= pcidev
->irq
;
869 ret
= comedi_alloc_subdevices(dev
, 4);
873 s
= &dev
->subdevices
[0];
874 dev
->read_subdev
= s
;
875 s
->type
= COMEDI_SUBD_AI
;
876 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_CMD_READ
;
879 s
->len_chanlist
= 16;
880 s
->range_table
= &pci9111_ai_range
;
881 s
->cancel
= pci9111_ai_cancel
;
882 s
->insn_read
= pci9111_ai_insn_read
;
883 s
->do_cmdtest
= pci9111_ai_do_cmd_test
;
884 s
->do_cmd
= pci9111_ai_do_cmd
;
885 s
->munge
= pci9111_ai_munge
;
887 s
= &dev
->subdevices
[1];
888 s
->type
= COMEDI_SUBD_AO
;
889 s
->subdev_flags
= SDF_WRITABLE
| SDF_COMMON
;
893 s
->range_table
= &range_bipolar10
;
894 s
->insn_write
= pci9111_ao_insn_write
;
895 s
->insn_read
= pci9111_ao_insn_read
;
897 s
= &dev
->subdevices
[2];
898 s
->type
= COMEDI_SUBD_DI
;
899 s
->subdev_flags
= SDF_READABLE
;
902 s
->range_table
= &range_digital
;
903 s
->insn_bits
= pci9111_di_insn_bits
;
905 s
= &dev
->subdevices
[3];
906 s
->type
= COMEDI_SUBD_DO
;
907 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
910 s
->range_table
= &range_digital
;
911 s
->insn_bits
= pci9111_do_insn_bits
;
913 dev_info(dev
->class_dev
, "%s attached\n", dev
->board_name
);
918 static void pci9111_detach(struct comedi_device
*dev
)
923 free_irq(dev
->irq
, dev
);
924 comedi_pci_disable(dev
);
927 static struct comedi_driver adl_pci9111_driver
= {
928 .driver_name
= "adl_pci9111",
929 .module
= THIS_MODULE
,
930 .auto_attach
= pci9111_auto_attach
,
931 .detach
= pci9111_detach
,
934 static int pci9111_pci_probe(struct pci_dev
*dev
,
935 const struct pci_device_id
*id
)
937 return comedi_pci_auto_config(dev
, &adl_pci9111_driver
,
941 static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table
) = {
942 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK
, PCI9111_HR_DEVICE_ID
) },
943 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
946 MODULE_DEVICE_TABLE(pci
, pci9111_pci_table
);
948 static struct pci_driver adl_pci9111_pci_driver
= {
949 .name
= "adl_pci9111",
950 .id_table
= pci9111_pci_table
,
951 .probe
= pci9111_pci_probe
,
952 .remove
= comedi_pci_auto_unconfig
,
954 module_comedi_pci_driver(adl_pci9111_driver
, adl_pci9111_pci_driver
);
956 MODULE_AUTHOR("Comedi http://www.comedi.org");
957 MODULE_DESCRIPTION("Comedi low-level driver");
958 MODULE_LICENSE("GPL");