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
89 #define PCI9111_8254_CLOCK_PERIOD_NS 500
92 * IO address map and bit defines
94 #define PCI9111_AI_FIFO_REG 0x00
95 #define PCI9111_AO_REG 0x00
96 #define PCI9111_DIO_REG 0x02
97 #define PCI9111_EDIO_REG 0x04
98 #define PCI9111_AI_CHANNEL_REG 0x06
99 #define PCI9111_AI_RANGE_STAT_REG 0x08
100 #define PCI9111_AI_STAT_AD_BUSY (1 << 7)
101 #define PCI9111_AI_STAT_FF_FF (1 << 6)
102 #define PCI9111_AI_STAT_FF_HF (1 << 5)
103 #define PCI9111_AI_STAT_FF_EF (1 << 4)
104 #define PCI9111_AI_RANGE_MASK (7 << 0)
105 #define PCI9111_AI_TRIG_CTRL_REG 0x0a
106 #define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5)
107 #define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4)
108 #define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3)
109 #define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2)
110 #define PCI9111_AI_TRIG_CTRL_TPST (1 << 1)
111 #define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0)
112 #define PCI9111_INT_CTRL_REG 0x0c
113 #define PCI9111_INT_CTRL_ISC2 (1 << 3)
114 #define PCI9111_INT_CTRL_FFEN (1 << 2)
115 #define PCI9111_INT_CTRL_ISC1 (1 << 1)
116 #define PCI9111_INT_CTRL_ISC0 (1 << 0)
117 #define PCI9111_SOFT_TRIG_REG 0x0e
118 #define PCI9111_8254_BASE_REG 0x40
119 #define PCI9111_INT_CLR_REG 0x48
121 /* PLX 9052 Local Interrupt 1 enabled and active */
122 #define PCI9111_LI1_ACTIVE (PLX9052_INTCSR_LI1ENAB | \
123 PLX9052_INTCSR_LI1STAT)
125 /* PLX 9052 Local Interrupt 2 enabled and active */
126 #define PCI9111_LI2_ACTIVE (PLX9052_INTCSR_LI2ENAB | \
127 PLX9052_INTCSR_LI2STAT)
129 static const struct comedi_lrange pci9111_ai_range
= {
140 struct pci9111_private_data
{
141 unsigned long lcr_io_base
;
146 unsigned int scan_delay
;
147 unsigned int chanlist_len
;
148 unsigned int chunk_counter
;
149 unsigned int chunk_num_samples
;
156 short ai_bounce_buffer
[2 * PCI9111_FIFO_HALF_SIZE
];
159 static void plx9050_interrupt_control(unsigned long io_base
,
161 bool LINTi1_active_high
,
163 bool LINTi2_active_high
,
164 bool interrupt_enable
)
169 flags
|= PLX9052_INTCSR_LI1ENAB
;
170 if (LINTi1_active_high
)
171 flags
|= PLX9052_INTCSR_LI1POL
;
173 flags
|= PLX9052_INTCSR_LI2ENAB
;
174 if (LINTi2_active_high
)
175 flags
|= PLX9052_INTCSR_LI2POL
;
177 if (interrupt_enable
)
178 flags
|= PLX9052_INTCSR_PCIENAB
;
180 outb(flags
, io_base
+ PLX9052_INTCSR
);
183 static void pci9111_timer_set(struct comedi_device
*dev
)
185 struct pci9111_private_data
*dev_private
= dev
->private;
186 unsigned long timer_base
= dev
->iobase
+ PCI9111_8254_BASE_REG
;
188 i8254_set_mode(timer_base
, 1, 0, I8254_MODE0
| I8254_BINARY
);
189 i8254_set_mode(timer_base
, 1, 1, I8254_MODE2
| I8254_BINARY
);
190 i8254_set_mode(timer_base
, 1, 2, I8254_MODE2
| I8254_BINARY
);
194 i8254_write(timer_base
, 1, 2, dev_private
->div2
);
195 i8254_write(timer_base
, 1, 1, dev_private
->div1
);
198 enum pci9111_trigger_sources
{
204 static void pci9111_trigger_source_set(struct comedi_device
*dev
,
205 enum pci9111_trigger_sources source
)
209 /* Read the current trigger mode control bits */
210 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
211 /* Mask off the EITS and TPST bits */
219 flags
|= PCI9111_AI_TRIG_CTRL_TPST
;
223 flags
|= PCI9111_AI_TRIG_CTRL_ETIS
;
227 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
230 static void pci9111_pretrigger_set(struct comedi_device
*dev
, bool pretrigger
)
234 /* Read the current trigger mode control bits */
235 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
236 /* Mask off the PTRG bit */
240 flags
|= PCI9111_AI_TRIG_CTRL_PTRG
;
242 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
245 static void pci9111_autoscan_set(struct comedi_device
*dev
, bool autoscan
)
249 /* Read the current trigger mode control bits */
250 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
251 /* Mask off the ASCAN bit */
255 flags
|= PCI9111_AI_TRIG_CTRL_ASCAN
;
257 outb(flags
, dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
260 enum pci9111_ISC0_sources
{
262 irq_on_fifo_half_full
265 enum pci9111_ISC1_sources
{
267 irq_on_external_trigger
270 static void pci9111_interrupt_source_set(struct comedi_device
*dev
,
271 enum pci9111_ISC0_sources irq_0_source
,
272 enum pci9111_ISC1_sources irq_1_source
)
276 /* Read the current interrupt control bits */
277 flags
= inb(dev
->iobase
+ PCI9111_AI_TRIG_CTRL_REG
);
278 /* Shift the bits so they are compatible with the write register */
280 /* Mask off the ISCx bits */
283 /* Now set the new ISCx bits */
284 if (irq_0_source
== irq_on_fifo_half_full
)
285 flags
|= PCI9111_INT_CTRL_ISC0
;
287 if (irq_1_source
== irq_on_external_trigger
)
288 flags
|= PCI9111_INT_CTRL_ISC1
;
290 outb(flags
, dev
->iobase
+ PCI9111_INT_CTRL_REG
);
293 static void pci9111_fifo_reset(struct comedi_device
*dev
)
295 unsigned long int_ctrl_reg
= dev
->iobase
+ PCI9111_INT_CTRL_REG
;
297 /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
298 outb(0, int_ctrl_reg
);
299 outb(PCI9111_INT_CTRL_FFEN
, int_ctrl_reg
);
300 outb(0, int_ctrl_reg
);
303 static int pci9111_ai_cancel(struct comedi_device
*dev
,
304 struct comedi_subdevice
*s
)
306 struct pci9111_private_data
*dev_private
= dev
->private;
308 /* Disable interrupts */
309 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true, true,
312 pci9111_trigger_source_set(dev
, software
);
314 pci9111_autoscan_set(dev
, false);
316 pci9111_fifo_reset(dev
);
321 static int pci9111_ai_do_cmd_test(struct comedi_device
*dev
,
322 struct comedi_subdevice
*s
,
323 struct comedi_cmd
*cmd
)
325 struct pci9111_private_data
*dev_private
= dev
->private;
328 int range
, reference
;
331 /* Step 1 : check if triggers are trivially valid */
333 error
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
334 error
|= cfc_check_trigger_src(&cmd
->scan_begin_src
,
335 TRIG_TIMER
| TRIG_FOLLOW
| TRIG_EXT
);
336 error
|= cfc_check_trigger_src(&cmd
->convert_src
,
337 TRIG_TIMER
| TRIG_EXT
);
338 error
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
339 error
|= cfc_check_trigger_src(&cmd
->stop_src
,
340 TRIG_COUNT
| TRIG_NONE
);
345 /* Step 2a : make sure trigger sources are unique */
347 error
|= cfc_check_trigger_is_unique(cmd
->scan_begin_src
);
348 error
|= cfc_check_trigger_is_unique(cmd
->convert_src
);
349 error
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
351 /* Step 2b : and mutually compatible */
353 if ((cmd
->convert_src
== TRIG_TIMER
) &&
354 !((cmd
->scan_begin_src
== TRIG_TIMER
) ||
355 (cmd
->scan_begin_src
== TRIG_FOLLOW
)))
357 if ((cmd
->convert_src
== TRIG_EXT
) &&
358 !((cmd
->scan_begin_src
== TRIG_EXT
) ||
359 (cmd
->scan_begin_src
== TRIG_FOLLOW
)))
365 /* Step 3: check if arguments are trivially valid */
367 error
|= cfc_check_trigger_arg_is(&cmd
->start_arg
, 0);
369 if (cmd
->convert_src
== TRIG_TIMER
)
370 error
|= cfc_check_trigger_arg_min(&cmd
->convert_arg
,
371 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS
);
373 error
|= cfc_check_trigger_arg_is(&cmd
->convert_arg
, 0);
375 if (cmd
->scan_begin_src
== TRIG_TIMER
)
376 error
|= cfc_check_trigger_arg_min(&cmd
->scan_begin_arg
,
377 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS
);
378 else /* TRIG_FOLLOW || TRIG_EXT */
379 error
|= cfc_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
381 error
|= cfc_check_trigger_arg_is(&cmd
->scan_end_arg
,
384 if (cmd
->stop_src
== TRIG_COUNT
)
385 error
|= cfc_check_trigger_arg_min(&cmd
->stop_arg
, 1);
387 error
|= cfc_check_trigger_arg_is(&cmd
->stop_arg
, 0);
392 /* Step 4 : fix up any arguments */
394 if (cmd
->convert_src
== TRIG_TIMER
) {
395 tmp
= cmd
->convert_arg
;
396 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS
,
400 cmd
->flags
& TRIG_ROUND_MASK
);
401 if (tmp
!= cmd
->convert_arg
)
404 /* There's only one timer on this card, so the scan_begin timer must */
405 /* be a multiple of chanlist_len*convert_arg */
407 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
409 unsigned int scan_begin_min
;
410 unsigned int scan_begin_arg
;
411 unsigned int scan_factor
;
413 scan_begin_min
= cmd
->chanlist_len
* cmd
->convert_arg
;
415 if (cmd
->scan_begin_arg
!= scan_begin_min
) {
416 if (scan_begin_min
< cmd
->scan_begin_arg
) {
418 cmd
->scan_begin_arg
/ scan_begin_min
;
419 scan_begin_arg
= scan_factor
* scan_begin_min
;
420 if (cmd
->scan_begin_arg
!= scan_begin_arg
) {
421 cmd
->scan_begin_arg
= scan_begin_arg
;
425 cmd
->scan_begin_arg
= scan_begin_min
;
434 /* Step 5 : check channel list */
438 range
= CR_RANGE(cmd
->chanlist
[0]);
439 reference
= CR_AREF(cmd
->chanlist
[0]);
441 if (cmd
->chanlist_len
> 1) {
442 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
443 if (CR_CHAN(cmd
->chanlist
[i
]) != i
) {
445 "entries in chanlist must be consecutive "
446 "channels,counting upwards from 0\n");
449 if (CR_RANGE(cmd
->chanlist
[i
]) != range
) {
451 "entries in chanlist must all have the same gain\n");
454 if (CR_AREF(cmd
->chanlist
[i
]) != reference
) {
456 "entries in chanlist must all have the same reference\n");
470 static int pci9111_ai_do_cmd(struct comedi_device
*dev
,
471 struct comedi_subdevice
*s
)
473 struct pci9111_private_data
*dev_private
= dev
->private;
474 struct comedi_cmd
*async_cmd
= &s
->async
->cmd
;
478 "no irq assigned for PCI9111, cannot do hardware conversion");
481 /* Set channel scan limit */
482 /* PCI9111 allows only scanning from channel 0 to channel n */
483 /* TODO: handle the case of an external multiplexer */
485 if (async_cmd
->chanlist_len
> 1) {
486 outb(async_cmd
->chanlist_len
- 1,
487 dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
488 pci9111_autoscan_set(dev
, true);
490 outb(CR_CHAN(async_cmd
->chanlist
[0]),
491 dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
492 pci9111_autoscan_set(dev
, false);
496 /* This is the same gain on every channel */
498 outb(CR_RANGE(async_cmd
->chanlist
[0]) & PCI9111_AI_RANGE_MASK
,
499 dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
503 switch (async_cmd
->stop_src
) {
505 dev_private
->stop_counter
=
506 async_cmd
->stop_arg
* async_cmd
->chanlist_len
;
507 dev_private
->stop_is_none
= 0;
511 dev_private
->stop_counter
= 0;
512 dev_private
->stop_is_none
= 1;
516 comedi_error(dev
, "Invalid stop trigger");
520 /* Set timer pacer */
522 dev_private
->scan_delay
= 0;
523 switch (async_cmd
->convert_src
) {
525 pci9111_trigger_source_set(dev
, software
);
526 pci9111_timer_set(dev
);
527 pci9111_fifo_reset(dev
);
528 pci9111_interrupt_source_set(dev
, irq_on_fifo_half_full
,
530 pci9111_trigger_source_set(dev
, timer_pacer
);
531 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true,
534 if (async_cmd
->scan_begin_src
== TRIG_TIMER
) {
535 dev_private
->scan_delay
=
536 (async_cmd
->scan_begin_arg
/
537 (async_cmd
->convert_arg
*
538 async_cmd
->chanlist_len
)) - 1;
545 pci9111_trigger_source_set(dev
, external
);
546 pci9111_fifo_reset(dev
);
547 pci9111_interrupt_source_set(dev
, irq_on_fifo_half_full
,
549 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true,
555 comedi_error(dev
, "Invalid convert trigger");
559 dev_private
->stop_counter
*= (1 + dev_private
->scan_delay
);
560 dev_private
->chanlist_len
= async_cmd
->chanlist_len
;
561 dev_private
->chunk_counter
= 0;
562 dev_private
->chunk_num_samples
=
563 dev_private
->chanlist_len
* (1 + dev_private
->scan_delay
);
568 static void pci9111_ai_munge(struct comedi_device
*dev
,
569 struct comedi_subdevice
*s
, void *data
,
570 unsigned int num_bytes
,
571 unsigned int start_chan_index
)
574 unsigned int maxdata
= s
->maxdata
;
575 unsigned int invert
= (maxdata
+ 1) >> 1;
576 unsigned int shift
= (maxdata
== 0xffff) ? 0 : 4;
577 unsigned int num_samples
= num_bytes
/ sizeof(short);
580 for (i
= 0; i
< num_samples
; i
++)
581 array
[i
] = ((array
[i
] >> shift
) & maxdata
) ^ invert
;
584 static irqreturn_t
pci9111_interrupt(int irq
, void *p_device
)
586 struct comedi_device
*dev
= p_device
;
587 struct pci9111_private_data
*dev_private
= dev
->private;
588 struct comedi_subdevice
*s
= dev
->read_subdev
;
589 struct comedi_async
*async
;
591 unsigned long irq_flags
;
592 unsigned char intcsr
;
594 if (!dev
->attached
) {
595 /* Ignore interrupt before device fully attached. */
596 /* Might not even have allocated subdevices yet! */
602 spin_lock_irqsave(&dev
->spinlock
, irq_flags
);
604 /* Check if we are source of interrupt */
605 intcsr
= inb(dev_private
->lcr_io_base
+ PLX9052_INTCSR
);
606 if (!(((intcsr
& PLX9052_INTCSR_PCIENAB
) != 0) &&
607 (((intcsr
& PCI9111_LI1_ACTIVE
) == PCI9111_LI1_ACTIVE
) ||
608 ((intcsr
& PCI9111_LI2_ACTIVE
) == PCI9111_LI2_ACTIVE
)))) {
609 /* Not the source of the interrupt. */
610 /* (N.B. not using PLX9052_INTCSR_SOFTINT) */
611 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
615 if ((intcsr
& PCI9111_LI1_ACTIVE
) == PCI9111_LI1_ACTIVE
) {
616 /* Interrupt comes from fifo_half-full signal */
618 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
620 /* '0' means FIFO is full, data may have been lost */
621 if (!(status
& PCI9111_AI_STAT_FF_FF
)) {
622 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
623 comedi_error(dev
, PCI9111_DRIVER_NAME
" fifo overflow");
624 outb(0, dev
->iobase
+ PCI9111_INT_CLR_REG
);
625 pci9111_ai_cancel(dev
, s
);
626 async
->events
|= COMEDI_CB_ERROR
| COMEDI_CB_EOA
;
627 comedi_event(dev
, s
);
632 /* '0' means FIFO is half-full */
633 if (!(status
& PCI9111_AI_STAT_FF_HF
)) {
634 unsigned int num_samples
;
635 unsigned int bytes_written
= 0;
638 PCI9111_FIFO_HALF_SIZE
>
639 dev_private
->stop_counter
641 stop_is_none
? dev_private
->stop_counter
:
642 PCI9111_FIFO_HALF_SIZE
;
643 insw(dev
->iobase
+ PCI9111_AI_FIFO_REG
,
644 dev_private
->ai_bounce_buffer
, num_samples
);
646 if (dev_private
->scan_delay
< 1) {
648 cfc_write_array_to_buffer(s
,
657 while (position
< num_samples
) {
658 if (dev_private
->chunk_counter
<
659 dev_private
->chanlist_len
) {
661 dev_private
->chanlist_len
-
662 dev_private
->chunk_counter
;
665 num_samples
- position
)
671 cfc_write_array_to_buffer
673 dev_private
->ai_bounce_buffer
675 to_read
* sizeof(short));
678 dev_private
->chunk_num_samples
680 dev_private
->chunk_counter
;
682 num_samples
- position
)
688 sizeof(short) * to_read
;
692 dev_private
->chunk_counter
+= to_read
;
694 if (dev_private
->chunk_counter
>=
695 dev_private
->chunk_num_samples
)
696 dev_private
->chunk_counter
= 0;
700 dev_private
->stop_counter
-=
701 bytes_written
/ sizeof(short);
705 if ((dev_private
->stop_counter
== 0) && (!dev_private
->stop_is_none
)) {
706 async
->events
|= COMEDI_CB_EOA
;
707 pci9111_ai_cancel(dev
, s
);
710 outb(0, dev
->iobase
+ PCI9111_INT_CLR_REG
);
712 spin_unlock_irqrestore(&dev
->spinlock
, irq_flags
);
714 comedi_event(dev
, s
);
719 static int pci9111_ai_insn_read(struct comedi_device
*dev
,
720 struct comedi_subdevice
*s
,
721 struct comedi_insn
*insn
, unsigned int *data
)
723 unsigned int chan
= CR_CHAN(insn
->chanspec
);
724 unsigned int range
= CR_RANGE(insn
->chanspec
);
725 unsigned int maxdata
= s
->maxdata
;
726 unsigned int invert
= (maxdata
+ 1) >> 1;
727 unsigned int shift
= (maxdata
== 0xffff) ? 0 : 4;
732 outb(chan
, dev
->iobase
+ PCI9111_AI_CHANNEL_REG
);
734 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
735 if ((status
& PCI9111_AI_RANGE_MASK
) != range
) {
736 outb(range
& PCI9111_AI_RANGE_MASK
,
737 dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
740 pci9111_fifo_reset(dev
);
742 for (i
= 0; i
< insn
->n
; i
++) {
743 /* Generate a software trigger */
744 outb(0, dev
->iobase
+ PCI9111_SOFT_TRIG_REG
);
746 timeout
= PCI9111_AI_INSTANT_READ_TIMEOUT
;
749 status
= inb(dev
->iobase
+ PCI9111_AI_RANGE_STAT_REG
);
750 /* '1' means FIFO is not empty */
751 if (status
& PCI9111_AI_STAT_FF_EF
)
752 goto conversion_done
;
755 comedi_error(dev
, "A/D read timeout");
757 pci9111_fifo_reset(dev
);
762 data
[i
] = inw(dev
->iobase
+ PCI9111_AI_FIFO_REG
);
763 data
[i
] = ((data
[i
] >> shift
) & maxdata
) ^ invert
;
769 static int pci9111_ao_insn_write(struct comedi_device
*dev
,
770 struct comedi_subdevice
*s
,
771 struct comedi_insn
*insn
,
774 struct pci9111_private_data
*dev_private
= dev
->private;
775 unsigned int val
= 0;
778 for (i
= 0; i
< insn
->n
; i
++) {
780 outw(val
, dev
->iobase
+ PCI9111_AO_REG
);
782 dev_private
->ao_readback
= val
;
787 static int pci9111_ao_insn_read(struct comedi_device
*dev
,
788 struct comedi_subdevice
*s
,
789 struct comedi_insn
*insn
,
792 struct pci9111_private_data
*dev_private
= dev
->private;
795 for (i
= 0; i
< insn
->n
; i
++)
796 data
[i
] = dev_private
->ao_readback
;
801 static int pci9111_di_insn_bits(struct comedi_device
*dev
,
802 struct comedi_subdevice
*s
,
803 struct comedi_insn
*insn
,
806 data
[1] = inw(dev
->iobase
+ PCI9111_DIO_REG
);
811 static int pci9111_do_insn_bits(struct comedi_device
*dev
,
812 struct comedi_subdevice
*s
,
813 struct comedi_insn
*insn
,
816 unsigned int mask
= data
[0];
817 unsigned int bits
= data
[1];
821 s
->state
|= (bits
& mask
);
823 outw(s
->state
, dev
->iobase
+ PCI9111_DIO_REG
);
831 static int pci9111_reset(struct comedi_device
*dev
)
833 struct pci9111_private_data
*dev_private
= dev
->private;
835 /* Set trigger source to software */
836 plx9050_interrupt_control(dev_private
->lcr_io_base
, true, true, true,
839 pci9111_trigger_source_set(dev
, software
);
840 pci9111_pretrigger_set(dev
, false);
841 pci9111_autoscan_set(dev
, false);
843 /* Reset 8254 chip */
844 dev_private
->div1
= 0;
845 dev_private
->div2
= 0;
846 pci9111_timer_set(dev
);
851 static int pci9111_auto_attach(struct comedi_device
*dev
,
852 unsigned long context_unused
)
854 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
855 struct pci9111_private_data
*dev_private
;
856 struct comedi_subdevice
*s
;
859 dev_private
= comedi_alloc_devpriv(dev
, sizeof(*dev_private
));
863 ret
= comedi_pci_enable(dev
);
866 dev_private
->lcr_io_base
= pci_resource_start(pcidev
, 1);
867 dev
->iobase
= pci_resource_start(pcidev
, 2);
871 if (pcidev
->irq
> 0) {
872 ret
= request_irq(dev
->irq
, pci9111_interrupt
,
873 IRQF_SHARED
, dev
->board_name
, dev
);
876 dev
->irq
= pcidev
->irq
;
879 ret
= comedi_alloc_subdevices(dev
, 4);
883 s
= &dev
->subdevices
[0];
884 dev
->read_subdev
= s
;
885 s
->type
= COMEDI_SUBD_AI
;
886 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_CMD_READ
;
889 s
->len_chanlist
= 16;
890 s
->range_table
= &pci9111_ai_range
;
891 s
->cancel
= pci9111_ai_cancel
;
892 s
->insn_read
= pci9111_ai_insn_read
;
893 s
->do_cmdtest
= pci9111_ai_do_cmd_test
;
894 s
->do_cmd
= pci9111_ai_do_cmd
;
895 s
->munge
= pci9111_ai_munge
;
897 s
= &dev
->subdevices
[1];
898 s
->type
= COMEDI_SUBD_AO
;
899 s
->subdev_flags
= SDF_WRITABLE
| SDF_COMMON
;
903 s
->range_table
= &range_bipolar10
;
904 s
->insn_write
= pci9111_ao_insn_write
;
905 s
->insn_read
= pci9111_ao_insn_read
;
907 s
= &dev
->subdevices
[2];
908 s
->type
= COMEDI_SUBD_DI
;
909 s
->subdev_flags
= SDF_READABLE
;
912 s
->range_table
= &range_digital
;
913 s
->insn_bits
= pci9111_di_insn_bits
;
915 s
= &dev
->subdevices
[3];
916 s
->type
= COMEDI_SUBD_DO
;
917 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
920 s
->range_table
= &range_digital
;
921 s
->insn_bits
= pci9111_do_insn_bits
;
923 dev_info(dev
->class_dev
, "%s attached\n", dev
->board_name
);
928 static void pci9111_detach(struct comedi_device
*dev
)
933 free_irq(dev
->irq
, dev
);
934 comedi_pci_disable(dev
);
937 static struct comedi_driver adl_pci9111_driver
= {
938 .driver_name
= "adl_pci9111",
939 .module
= THIS_MODULE
,
940 .auto_attach
= pci9111_auto_attach
,
941 .detach
= pci9111_detach
,
944 static int pci9111_pci_probe(struct pci_dev
*dev
,
945 const struct pci_device_id
*id
)
947 return comedi_pci_auto_config(dev
, &adl_pci9111_driver
,
951 static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table
) = {
952 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK
, PCI9111_HR_DEVICE_ID
) },
953 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
956 MODULE_DEVICE_TABLE(pci
, pci9111_pci_table
);
958 static struct pci_driver adl_pci9111_pci_driver
= {
959 .name
= "adl_pci9111",
960 .id_table
= pci9111_pci_table
,
961 .probe
= pci9111_pci_probe
,
962 .remove
= comedi_pci_auto_unconfig
,
964 module_comedi_pci_driver(adl_pci9111_driver
, adl_pci9111_pci_driver
);
966 MODULE_AUTHOR("Comedi http://www.comedi.org");
967 MODULE_DESCRIPTION("Comedi low-level driver");
968 MODULE_LICENSE("GPL");