5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7 * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
8 * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
23 * Description: DAS16 compatible boards
24 * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
25 * Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
26 * DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
27 * DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
28 * DAS-1602 (das-1602),
29 * [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
30 * PC104-DAS16JR/16 (pc104-das16jr/16), CIO-DAS16 (cio-das16),
31 * CIO-DAS16F (cio-das16/f), CIO-DAS16/JR (cio-das16/jr),
32 * CIO-DAS16JR/16 (cio-das16jr/16), CIO-DAS1401/12 (cio-das1401/12),
33 * CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
34 * CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
35 * CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
39 * A rewrite of the das16 and das1600 drivers.
42 * [0] - base io address
43 * [1] - irq (does nothing, irq is not used anymore)
44 * [2] - dma channel (optional, required for comedi_command support)
45 * [3] - master clock speed in MHz (optional, 1 or 10, ignored if
46 * board can probe clock, defaults to 1)
47 * [4] - analog input range lowest voltage in microvolts (optional,
48 * only useful if your board does not have software
50 * [5] - analog input range highest voltage in microvolts (optional,
51 * only useful if board does not have software programmable
53 * [6] - analog output range lowest voltage in microvolts (optional)
54 * [7] - analog output range highest voltage in microvolts (optional)
56 * Passing a zero for an option is the same as leaving it unspecified.
60 * Testing and debugging help provided by Daniel Koch.
64 * 4919.PDF (das1400, 1600)
66 * 4923.PDF (das1200, 1400, 1600)
68 * Computer boards manuals also available from their website
69 * www.measurementcomputing.com
72 #include <linux/module.h>
73 #include <linux/slab.h>
74 #include <linux/interrupt.h>
76 #include "../comedidev.h"
78 #include "comedi_isadma.h"
79 #include "comedi_8254.h"
82 #define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */
87 #define DAS16_TRIG_REG 0x00
88 #define DAS16_AI_LSB_REG 0x00
89 #define DAS16_AI_MSB_REG 0x01
90 #define DAS16_MUX_REG 0x02
91 #define DAS16_DIO_REG 0x03
92 #define DAS16_AO_LSB_REG(x) ((x) ? 0x06 : 0x04)
93 #define DAS16_AO_MSB_REG(x) ((x) ? 0x07 : 0x05)
94 #define DAS16_STATUS_REG 0x08
95 #define DAS16_STATUS_BUSY (1 << 7)
96 #define DAS16_STATUS_UNIPOLAR (1 << 6)
97 #define DAS16_STATUS_MUXBIT (1 << 5)
98 #define DAS16_STATUS_INT (1 << 4)
99 #define DAS16_CTRL_REG 0x09
100 #define DAS16_CTRL_INTE (1 << 7)
101 #define DAS16_CTRL_IRQ(x) (((x) & 0x7) << 4)
102 #define DAS16_CTRL_DMAE (1 << 2)
103 #define DAS16_CTRL_PACING_MASK (3 << 0)
104 #define DAS16_CTRL_INT_PACER (3 << 0)
105 #define DAS16_CTRL_EXT_PACER (2 << 0)
106 #define DAS16_CTRL_SOFT_PACER (0 << 0)
107 #define DAS16_PACER_REG 0x0a
108 #define DAS16_PACER_BURST_LEN(x) (((x) & 0xf) << 4)
109 #define DAS16_PACER_CTR0 (1 << 1)
110 #define DAS16_PACER_TRIG0 (1 << 0)
111 #define DAS16_GAIN_REG 0x0b
112 #define DAS16_TIMER_BASE_REG 0x0c /* to 0x0f */
114 #define DAS1600_CONV_REG 0x404
115 #define DAS1600_CONV_DISABLE (1 << 6)
116 #define DAS1600_BURST_REG 0x405
117 #define DAS1600_BURST_VAL (1 << 6)
118 #define DAS1600_ENABLE_REG 0x406
119 #define DAS1600_ENABLE_VAL (1 << 6)
120 #define DAS1600_STATUS_REG 0x407
121 #define DAS1600_STATUS_BME (1 << 6)
122 #define DAS1600_STATUS_ME (1 << 5)
123 #define DAS1600_STATUS_CD (1 << 4)
124 #define DAS1600_STATUS_WS (1 << 1)
125 #define DAS1600_STATUS_CLK_10MHZ (1 << 0)
127 static const struct comedi_lrange range_das1x01_bip
= {
136 static const struct comedi_lrange range_das1x01_unip
= {
145 static const struct comedi_lrange range_das1x02_bip
= {
154 static const struct comedi_lrange range_das1x02_unip
= {
163 static const struct comedi_lrange range_das16jr
= {
177 static const struct comedi_lrange range_das16jr_16
= {
190 static const int das16jr_gainlist
[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
191 static const int das16jr_16_gainlist
[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
192 static const int das1600_gainlist
[] = { 0, 1, 2, 3 };
201 static const int *const das16_gainlists
[] = {
209 static const struct comedi_lrange
*const das16_ai_uni_lranges
[] = {
217 static const struct comedi_lrange
*const das16_ai_bip_lranges
[] = {
227 unsigned int ai_maxdata
;
228 unsigned int ai_speed
; /* max conversion speed in nanosec */
230 unsigned int has_ao
:1;
231 unsigned int has_8255
:1;
233 unsigned int i8255_offset
;
239 static const struct das16_board das16_boards
[] = {
242 .ai_maxdata
= 0x0fff,
244 .ai_pg
= das16_pg_none
,
247 .i8255_offset
= 0x10,
252 .ai_maxdata
= 0x0fff,
254 .ai_pg
= das16_pg_none
,
257 .i8255_offset
= 0x10,
262 .ai_maxdata
= 0x0fff,
264 .ai_pg
= das16_pg_none
,
267 .i8255_offset
= 0x10,
272 .ai_maxdata
= 0x0fff,
274 .ai_pg
= das16_pg_none
,
277 .i8255_offset
= 0x10,
281 .name
= "cio-das16/f",
282 .ai_maxdata
= 0x0fff,
284 .ai_pg
= das16_pg_none
,
287 .i8255_offset
= 0x10,
291 .name
= "cio-das16/jr",
292 .ai_maxdata
= 0x0fff,
294 .ai_pg
= das16_pg_16jr
,
298 .name
= "pc104-das16jr",
299 .ai_maxdata
= 0x0fff,
301 .ai_pg
= das16_pg_16jr
,
305 .name
= "cio-das16jr/16",
306 .ai_maxdata
= 0xffff,
308 .ai_pg
= das16_pg_16jr_16
,
312 .name
= "pc104-das16jr/16",
313 .ai_maxdata
= 0xffff,
315 .ai_pg
= das16_pg_16jr_16
,
320 .ai_maxdata
= 0x0fff,
322 .ai_pg
= das16_pg_none
,
324 .i8255_offset
= 0x400,
329 .ai_maxdata
= 0x0fff,
331 .ai_pg
= das16_pg_none
,
333 .i8255_offset
= 0x400,
338 .ai_maxdata
= 0x0fff,
340 .ai_pg
= das16_pg_1601
,
345 .ai_maxdata
= 0x0fff,
347 .ai_pg
= das16_pg_1602
,
352 .ai_maxdata
= 0x0fff,
354 .ai_pg
= das16_pg_1601
,
357 .i8255_offset
= 0x400,
362 .ai_maxdata
= 0x0fff,
364 .ai_pg
= das16_pg_1602
,
367 .i8255_offset
= 0x400,
371 .name
= "cio-das1401/12",
372 .ai_maxdata
= 0x0fff,
374 .ai_pg
= das16_pg_1601
,
378 .name
= "cio-das1402/12",
379 .ai_maxdata
= 0x0fff,
381 .ai_pg
= das16_pg_1602
,
385 .name
= "cio-das1402/16",
386 .ai_maxdata
= 0xffff,
388 .ai_pg
= das16_pg_1602
,
392 .name
= "cio-das1601/12",
393 .ai_maxdata
= 0x0fff,
395 .ai_pg
= das16_pg_1601
,
398 .i8255_offset
= 0x400,
402 .name
= "cio-das1602/12",
403 .ai_maxdata
= 0x0fff,
405 .ai_pg
= das16_pg_1602
,
408 .i8255_offset
= 0x400,
412 .name
= "cio-das1602/16",
413 .ai_maxdata
= 0xffff,
415 .ai_pg
= das16_pg_1602
,
418 .i8255_offset
= 0x400,
422 .name
= "cio-das16/330",
423 .ai_maxdata
= 0x0fff,
425 .ai_pg
= das16_pg_16jr
,
431 /* Period for timer interrupt in jiffies. It's a function
432 * to deal with possibility of dynamic HZ patches */
433 static inline int timer_period(void)
438 struct das16_private_struct
{
439 struct comedi_isadma
*dma
;
440 unsigned int clockbase
;
441 unsigned int ctrl_reg
;
442 unsigned int divisor1
;
443 unsigned int divisor2
;
444 struct timer_list timer
;
445 unsigned long extra_iobase
;
446 unsigned int can_burst
:1;
447 unsigned int timer_running
:1;
450 static void das16_ai_setup_dma(struct comedi_device
*dev
,
451 struct comedi_subdevice
*s
,
452 unsigned int unread_samples
)
454 struct das16_private_struct
*devpriv
= dev
->private;
455 struct comedi_isadma
*dma
= devpriv
->dma
;
456 struct comedi_isadma_desc
*desc
= &dma
->desc
[dma
->cur_dma
];
457 unsigned int max_samples
= comedi_bytes_to_samples(s
, desc
->maxsize
);
458 unsigned int nsamples
;
461 * Determine dma size based on the buffer size plus the number of
462 * unread samples and the number of samples remaining in the command.
464 nsamples
= comedi_nsamples_left(s
, max_samples
+ unread_samples
);
465 if (nsamples
> unread_samples
) {
466 nsamples
-= unread_samples
;
467 desc
->size
= comedi_samples_to_bytes(s
, nsamples
);
468 comedi_isadma_program(desc
);
472 static void das16_interrupt(struct comedi_device
*dev
)
474 struct das16_private_struct
*devpriv
= dev
->private;
475 struct comedi_subdevice
*s
= dev
->read_subdev
;
476 struct comedi_async
*async
= s
->async
;
477 struct comedi_cmd
*cmd
= &async
->cmd
;
478 struct comedi_isadma
*dma
= devpriv
->dma
;
479 struct comedi_isadma_desc
*desc
= &dma
->desc
[dma
->cur_dma
];
480 unsigned long spin_flags
;
481 unsigned int residue
;
483 unsigned int nsamples
;
485 spin_lock_irqsave(&dev
->spinlock
, spin_flags
);
486 if (!(devpriv
->ctrl_reg
& DAS16_CTRL_DMAE
)) {
487 spin_unlock_irqrestore(&dev
->spinlock
, spin_flags
);
492 * The pc104-das16jr (at least) has problems if the dma
493 * transfer is interrupted in the middle of transferring
496 residue
= comedi_isadma_disable_on_sample(desc
->chan
,
497 comedi_bytes_per_sample(s
));
499 /* figure out how many samples to read */
500 if (residue
> desc
->size
) {
501 dev_err(dev
->class_dev
, "residue > transfer size!\n");
502 async
->events
|= COMEDI_CB_ERROR
;
505 nbytes
= desc
->size
- residue
;
507 nsamples
= comedi_bytes_to_samples(s
, nbytes
);
509 /* restart DMA if more samples are needed */
511 dma
->cur_dma
= 1 - dma
->cur_dma
;
512 das16_ai_setup_dma(dev
, s
, nsamples
);
515 spin_unlock_irqrestore(&dev
->spinlock
, spin_flags
);
517 comedi_buf_write_samples(s
, desc
->virt_addr
, nsamples
);
519 if (cmd
->stop_src
== TRIG_COUNT
&& async
->scans_done
>= cmd
->stop_arg
)
520 async
->events
|= COMEDI_CB_EOA
;
522 comedi_handle_events(dev
, s
);
525 static void das16_timer_interrupt(unsigned long arg
)
527 struct comedi_device
*dev
= (struct comedi_device
*)arg
;
528 struct das16_private_struct
*devpriv
= dev
->private;
531 das16_interrupt(dev
);
533 spin_lock_irqsave(&dev
->spinlock
, flags
);
534 if (devpriv
->timer_running
)
535 mod_timer(&devpriv
->timer
, jiffies
+ timer_period());
536 spin_unlock_irqrestore(&dev
->spinlock
, flags
);
539 static void das16_ai_set_mux_range(struct comedi_device
*dev
,
540 unsigned int first_chan
,
541 unsigned int last_chan
,
544 const struct das16_board
*board
= dev
->board_ptr
;
546 /* set multiplexer */
547 outb(first_chan
| (last_chan
<< 4), dev
->iobase
+ DAS16_MUX_REG
);
549 /* some boards do not have programmable gain */
550 if (board
->ai_pg
== das16_pg_none
)
554 * Set gain (this is also burst rate register but according to
555 * computer boards manual, burst rate does nothing, even on
558 outb((das16_gainlists
[board
->ai_pg
])[range
],
559 dev
->iobase
+ DAS16_GAIN_REG
);
562 static int das16_ai_check_chanlist(struct comedi_device
*dev
,
563 struct comedi_subdevice
*s
,
564 struct comedi_cmd
*cmd
)
566 unsigned int chan0
= CR_CHAN(cmd
->chanlist
[0]);
567 unsigned int range0
= CR_RANGE(cmd
->chanlist
[0]);
570 for (i
= 1; i
< cmd
->chanlist_len
; i
++) {
571 unsigned int chan
= CR_CHAN(cmd
->chanlist
[i
]);
572 unsigned int range
= CR_RANGE(cmd
->chanlist
[i
]);
574 if (chan
!= ((chan0
+ i
) % s
->n_chan
)) {
575 dev_dbg(dev
->class_dev
,
576 "entries in chanlist must be consecutive channels, counting upwards\n");
580 if (range
!= range0
) {
581 dev_dbg(dev
->class_dev
,
582 "entries in chanlist must all have the same gain\n");
590 static int das16_cmd_test(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
591 struct comedi_cmd
*cmd
)
593 const struct das16_board
*board
= dev
->board_ptr
;
594 struct das16_private_struct
*devpriv
= dev
->private;
596 unsigned int trig_mask
;
599 /* Step 1 : check if triggers are trivially valid */
601 err
|= comedi_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
603 trig_mask
= TRIG_FOLLOW
;
604 if (devpriv
->can_burst
)
605 trig_mask
|= TRIG_TIMER
| TRIG_EXT
;
606 err
|= comedi_check_trigger_src(&cmd
->scan_begin_src
, trig_mask
);
608 trig_mask
= TRIG_TIMER
| TRIG_EXT
;
609 if (devpriv
->can_burst
)
610 trig_mask
|= TRIG_NOW
;
611 err
|= comedi_check_trigger_src(&cmd
->convert_src
, trig_mask
);
613 err
|= comedi_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
614 err
|= comedi_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
619 /* Step 2a : make sure trigger sources are unique */
621 err
|= comedi_check_trigger_is_unique(cmd
->scan_begin_src
);
622 err
|= comedi_check_trigger_is_unique(cmd
->convert_src
);
623 err
|= comedi_check_trigger_is_unique(cmd
->stop_src
);
625 /* Step 2b : and mutually compatible */
627 /* make sure scan_begin_src and convert_src dont conflict */
628 if (cmd
->scan_begin_src
== TRIG_FOLLOW
&& cmd
->convert_src
== TRIG_NOW
)
630 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
&& cmd
->convert_src
!= TRIG_NOW
)
636 /* Step 3: check if arguments are trivially valid */
638 err
|= comedi_check_trigger_arg_is(&cmd
->start_arg
, 0);
640 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) /* internal trigger */
641 err
|= comedi_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
643 err
|= comedi_check_trigger_arg_is(&cmd
->scan_end_arg
,
646 /* check against maximum frequency */
647 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
648 err
|= comedi_check_trigger_arg_min(&cmd
->scan_begin_arg
,
653 if (cmd
->convert_src
== TRIG_TIMER
) {
654 err
|= comedi_check_trigger_arg_min(&cmd
->convert_arg
,
658 if (cmd
->stop_src
== TRIG_COUNT
)
659 err
|= comedi_check_trigger_arg_min(&cmd
->stop_arg
, 1);
661 err
|= comedi_check_trigger_arg_is(&cmd
->stop_arg
, 0);
666 /* step 4: fix up arguments */
667 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
668 arg
= cmd
->scan_begin_arg
;
669 comedi_8254_cascade_ns_to_timer(dev
->pacer
, &arg
, cmd
->flags
);
670 err
|= comedi_check_trigger_arg_is(&cmd
->scan_begin_arg
, arg
);
672 if (cmd
->convert_src
== TRIG_TIMER
) {
673 arg
= cmd
->convert_arg
;
674 comedi_8254_cascade_ns_to_timer(dev
->pacer
, &arg
, cmd
->flags
);
675 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, arg
);
680 /* Step 5: check channel list if it exists */
681 if (cmd
->chanlist
&& cmd
->chanlist_len
> 0)
682 err
|= das16_ai_check_chanlist(dev
, s
, cmd
);
690 static unsigned int das16_set_pacer(struct comedi_device
*dev
, unsigned int ns
,
693 comedi_8254_cascade_ns_to_timer(dev
->pacer
, &ns
, flags
);
694 comedi_8254_update_divisors(dev
->pacer
);
695 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
700 static int das16_cmd_exec(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
702 struct das16_private_struct
*devpriv
= dev
->private;
703 struct comedi_isadma
*dma
= devpriv
->dma
;
704 struct comedi_async
*async
= s
->async
;
705 struct comedi_cmd
*cmd
= &async
->cmd
;
706 unsigned int first_chan
= CR_CHAN(cmd
->chanlist
[0]);
707 unsigned int last_chan
= CR_CHAN(cmd
->chanlist
[cmd
->chanlist_len
- 1]);
708 unsigned int range
= CR_RANGE(cmd
->chanlist
[0]);
712 if (cmd
->flags
& CMDF_PRIORITY
) {
713 dev_err(dev
->class_dev
,
714 "isa dma transfers cannot be performed with CMDF_PRIORITY, aborting\n");
718 if (devpriv
->can_burst
)
719 outb(DAS1600_CONV_DISABLE
, dev
->iobase
+ DAS1600_CONV_REG
);
721 /* set mux and range for chanlist scan */
722 das16_ai_set_mux_range(dev
, first_chan
, last_chan
, range
);
724 /* set counter mode and counts */
725 cmd
->convert_arg
= das16_set_pacer(dev
, cmd
->convert_arg
, cmd
->flags
);
727 /* enable counters */
729 if (devpriv
->can_burst
) {
730 if (cmd
->convert_src
== TRIG_NOW
) {
731 outb(DAS1600_BURST_VAL
,
732 dev
->iobase
+ DAS1600_BURST_REG
);
733 /* set burst length */
734 byte
|= DAS16_PACER_BURST_LEN(cmd
->chanlist_len
- 1);
736 outb(0, dev
->iobase
+ DAS1600_BURST_REG
);
739 outb(byte
, dev
->iobase
+ DAS16_PACER_REG
);
741 /* set up dma transfer */
743 das16_ai_setup_dma(dev
, s
, 0);
746 spin_lock_irqsave(&dev
->spinlock
, flags
);
747 devpriv
->timer_running
= 1;
748 devpriv
->timer
.expires
= jiffies
+ timer_period();
749 add_timer(&devpriv
->timer
);
751 /* enable DMA interrupt with external or internal pacing */
752 devpriv
->ctrl_reg
&= ~(DAS16_CTRL_INTE
| DAS16_CTRL_PACING_MASK
);
753 devpriv
->ctrl_reg
|= DAS16_CTRL_DMAE
;
754 if (cmd
->convert_src
== TRIG_EXT
)
755 devpriv
->ctrl_reg
|= DAS16_CTRL_EXT_PACER
;
757 devpriv
->ctrl_reg
|= DAS16_CTRL_INT_PACER
;
758 outb(devpriv
->ctrl_reg
, dev
->iobase
+ DAS16_CTRL_REG
);
760 if (devpriv
->can_burst
)
761 outb(0, dev
->iobase
+ DAS1600_CONV_REG
);
762 spin_unlock_irqrestore(&dev
->spinlock
, flags
);
767 static int das16_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
769 struct das16_private_struct
*devpriv
= dev
->private;
770 struct comedi_isadma
*dma
= devpriv
->dma
;
773 spin_lock_irqsave(&dev
->spinlock
, flags
);
775 /* disable interrupts, dma and pacer clocked conversions */
776 devpriv
->ctrl_reg
&= ~(DAS16_CTRL_INTE
| DAS16_CTRL_DMAE
|
777 DAS16_CTRL_PACING_MASK
);
778 outb(devpriv
->ctrl_reg
, dev
->iobase
+ DAS16_CTRL_REG
);
780 comedi_isadma_disable(dma
->chan
);
782 /* disable SW timer */
783 if (devpriv
->timer_running
) {
784 devpriv
->timer_running
= 0;
785 del_timer(&devpriv
->timer
);
788 if (devpriv
->can_burst
)
789 outb(0, dev
->iobase
+ DAS1600_BURST_REG
);
791 spin_unlock_irqrestore(&dev
->spinlock
, flags
);
796 static void das16_ai_munge(struct comedi_device
*dev
,
797 struct comedi_subdevice
*s
, void *array
,
798 unsigned int num_bytes
,
799 unsigned int start_chan_index
)
801 unsigned short *data
= array
;
802 unsigned int num_samples
= comedi_bytes_to_samples(s
, num_bytes
);
805 for (i
= 0; i
< num_samples
; i
++) {
806 data
[i
] = le16_to_cpu(data
[i
]);
807 if (s
->maxdata
== 0x0fff)
809 data
[i
] &= s
->maxdata
;
813 static int das16_ai_eoc(struct comedi_device
*dev
,
814 struct comedi_subdevice
*s
,
815 struct comedi_insn
*insn
,
816 unsigned long context
)
820 status
= inb(dev
->iobase
+ DAS16_STATUS_REG
);
821 if ((status
& DAS16_STATUS_BUSY
) == 0)
826 static int das16_ai_insn_read(struct comedi_device
*dev
,
827 struct comedi_subdevice
*s
,
828 struct comedi_insn
*insn
,
831 unsigned int chan
= CR_CHAN(insn
->chanspec
);
832 unsigned int range
= CR_RANGE(insn
->chanspec
);
837 /* set mux and range for single channel */
838 das16_ai_set_mux_range(dev
, chan
, chan
, range
);
840 for (i
= 0; i
< insn
->n
; i
++) {
841 /* trigger conversion */
842 outb_p(0, dev
->iobase
+ DAS16_TRIG_REG
);
844 ret
= comedi_timeout(dev
, s
, insn
, das16_ai_eoc
, 0);
848 val
= inb(dev
->iobase
+ DAS16_AI_MSB_REG
) << 8;
849 val
|= inb(dev
->iobase
+ DAS16_AI_LSB_REG
);
850 if (s
->maxdata
== 0x0fff)
860 static int das16_ao_insn_write(struct comedi_device
*dev
,
861 struct comedi_subdevice
*s
,
862 struct comedi_insn
*insn
,
865 unsigned int chan
= CR_CHAN(insn
->chanspec
);
868 for (i
= 0; i
< insn
->n
; i
++) {
869 unsigned int val
= data
[i
];
871 s
->readback
[chan
] = val
;
875 outb(val
& 0xff, dev
->iobase
+ DAS16_AO_LSB_REG(chan
));
876 outb((val
>> 8) & 0xff, dev
->iobase
+ DAS16_AO_MSB_REG(chan
));
882 static int das16_di_insn_bits(struct comedi_device
*dev
,
883 struct comedi_subdevice
*s
,
884 struct comedi_insn
*insn
,
887 data
[1] = inb(dev
->iobase
+ DAS16_DIO_REG
) & 0xf;
892 static int das16_do_insn_bits(struct comedi_device
*dev
,
893 struct comedi_subdevice
*s
,
894 struct comedi_insn
*insn
,
897 if (comedi_dio_update_state(s
, data
))
898 outb(s
->state
, dev
->iobase
+ DAS16_DIO_REG
);
905 static int das16_probe(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
907 const struct das16_board
*board
= dev
->board_ptr
;
910 /* diobits indicates boards */
911 diobits
= inb(dev
->iobase
+ DAS16_DIO_REG
) & 0xf0;
912 if (board
->id
!= diobits
) {
913 dev_err(dev
->class_dev
,
914 "requested board's id bits are incorrect (0x%x != 0x%x)\n",
922 static void das16_reset(struct comedi_device
*dev
)
924 outb(0, dev
->iobase
+ DAS16_STATUS_REG
);
925 outb(0, dev
->iobase
+ DAS16_CTRL_REG
);
926 outb(0, dev
->iobase
+ DAS16_PACER_REG
);
929 static void das16_alloc_dma(struct comedi_device
*dev
, unsigned int dma_chan
)
931 struct das16_private_struct
*devpriv
= dev
->private;
933 /* only DMA channels 3 and 1 are valid */
934 if (!(dma_chan
== 1 || dma_chan
== 3))
937 /* DMA uses two buffers */
938 devpriv
->dma
= comedi_isadma_alloc(dev
, 2, dma_chan
, dma_chan
,
939 DAS16_DMA_SIZE
, COMEDI_ISADMA_READ
);
941 setup_timer(&devpriv
->timer
, das16_timer_interrupt
,
946 static void das16_free_dma(struct comedi_device
*dev
)
948 struct das16_private_struct
*devpriv
= dev
->private;
951 if (devpriv
->timer
.data
)
952 del_timer_sync(&devpriv
->timer
);
953 comedi_isadma_free(devpriv
->dma
);
957 static const struct comedi_lrange
*das16_ai_range(struct comedi_device
*dev
,
958 struct comedi_subdevice
*s
,
959 struct comedi_devconfig
*it
,
960 unsigned int pg_type
,
963 unsigned int min
= it
->options
[4];
964 unsigned int max
= it
->options
[5];
966 /* get any user-defined input range */
967 if (pg_type
== das16_pg_none
&& (min
|| max
)) {
968 struct comedi_lrange
*lrange
;
969 struct comedi_krange
*krange
;
971 /* allocate single-range range table */
972 lrange
= comedi_alloc_spriv(s
,
973 sizeof(*lrange
) + sizeof(*krange
));
975 return &range_unknown
;
977 /* initialize ai range */
979 krange
= lrange
->range
;
982 krange
->flags
= UNIT_volt
;
987 /* use software programmable range */
988 if (status
& DAS16_STATUS_UNIPOLAR
)
989 return das16_ai_uni_lranges
[pg_type
];
990 return das16_ai_bip_lranges
[pg_type
];
993 static const struct comedi_lrange
*das16_ao_range(struct comedi_device
*dev
,
994 struct comedi_subdevice
*s
,
995 struct comedi_devconfig
*it
)
997 unsigned int min
= it
->options
[6];
998 unsigned int max
= it
->options
[7];
1000 /* get any user-defined output range */
1002 struct comedi_lrange
*lrange
;
1003 struct comedi_krange
*krange
;
1005 /* allocate single-range range table */
1006 lrange
= comedi_alloc_spriv(s
,
1007 sizeof(*lrange
) + sizeof(*krange
));
1009 return &range_unknown
;
1011 /* initialize ao range */
1013 krange
= lrange
->range
;
1016 krange
->flags
= UNIT_volt
;
1021 return &range_unknown
;
1024 static int das16_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1026 const struct das16_board
*board
= dev
->board_ptr
;
1027 struct das16_private_struct
*devpriv
;
1028 struct comedi_subdevice
*s
;
1029 unsigned int osc_base
;
1030 unsigned int status
;
1033 /* check that clock setting is valid */
1034 if (it
->options
[3]) {
1035 if (it
->options
[3] != 1 && it
->options
[3] != 10) {
1036 dev_err(dev
->class_dev
,
1037 "Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
1042 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
1046 if (board
->size
< 0x400) {
1047 ret
= comedi_request_region(dev
, it
->options
[0], board
->size
);
1051 ret
= comedi_request_region(dev
, it
->options
[0], 0x10);
1054 /* Request an additional region for the 8255 */
1055 ret
= __comedi_request_region(dev
, dev
->iobase
+ 0x400,
1056 board
->size
& 0x3ff);
1059 devpriv
->extra_iobase
= dev
->iobase
+ 0x400;
1060 devpriv
->can_burst
= 1;
1063 /* probe id bits to make sure they are consistent */
1064 if (das16_probe(dev
, it
))
1067 /* get master clock speed */
1068 osc_base
= I8254_OSC_BASE_1MHZ
;
1069 if (devpriv
->can_burst
) {
1070 status
= inb(dev
->iobase
+ DAS1600_STATUS_REG
);
1071 if (status
& DAS1600_STATUS_CLK_10MHZ
)
1072 osc_base
= I8254_OSC_BASE_10MHZ
;
1075 osc_base
= I8254_OSC_BASE_1MHZ
/ it
->options
[3];
1078 dev
->pacer
= comedi_8254_init(dev
->iobase
+ DAS16_TIMER_BASE_REG
,
1079 osc_base
, I8254_IO8
, 0);
1083 das16_alloc_dma(dev
, it
->options
[2]);
1085 ret
= comedi_alloc_subdevices(dev
, 4 + board
->has_8255
);
1089 status
= inb(dev
->iobase
+ DAS16_STATUS_REG
);
1091 /* Analog Input subdevice */
1092 s
= &dev
->subdevices
[0];
1093 s
->type
= COMEDI_SUBD_AI
;
1094 s
->subdev_flags
= SDF_READABLE
;
1095 if (status
& DAS16_STATUS_MUXBIT
) {
1096 s
->subdev_flags
|= SDF_GROUND
;
1099 s
->subdev_flags
|= SDF_DIFF
;
1102 s
->len_chanlist
= s
->n_chan
;
1103 s
->maxdata
= board
->ai_maxdata
;
1104 s
->range_table
= das16_ai_range(dev
, s
, it
, board
->ai_pg
, status
);
1105 s
->insn_read
= das16_ai_insn_read
;
1107 dev
->read_subdev
= s
;
1108 s
->subdev_flags
|= SDF_CMD_READ
;
1109 s
->do_cmdtest
= das16_cmd_test
;
1110 s
->do_cmd
= das16_cmd_exec
;
1111 s
->cancel
= das16_cancel
;
1112 s
->munge
= das16_ai_munge
;
1115 /* Analog Output subdevice */
1116 s
= &dev
->subdevices
[1];
1117 if (board
->has_ao
) {
1118 s
->type
= COMEDI_SUBD_AO
;
1119 s
->subdev_flags
= SDF_WRITABLE
;
1121 s
->maxdata
= 0x0fff;
1122 s
->range_table
= das16_ao_range(dev
, s
, it
);
1123 s
->insn_write
= das16_ao_insn_write
;
1125 ret
= comedi_alloc_subdev_readback(s
);
1129 s
->type
= COMEDI_SUBD_UNUSED
;
1132 /* Digital Input subdevice */
1133 s
= &dev
->subdevices
[2];
1134 s
->type
= COMEDI_SUBD_DI
;
1135 s
->subdev_flags
= SDF_READABLE
;
1138 s
->range_table
= &range_digital
;
1139 s
->insn_bits
= das16_di_insn_bits
;
1141 /* Digital Output subdevice */
1142 s
= &dev
->subdevices
[3];
1143 s
->type
= COMEDI_SUBD_DO
;
1144 s
->subdev_flags
= SDF_WRITABLE
;
1147 s
->range_table
= &range_digital
;
1148 s
->insn_bits
= das16_do_insn_bits
;
1150 /* initialize digital output lines */
1151 outb(s
->state
, dev
->iobase
+ DAS16_DIO_REG
);
1153 /* 8255 Digital I/O subdevice */
1154 if (board
->has_8255
) {
1155 s
= &dev
->subdevices
[4];
1156 ret
= subdev_8255_init(dev
, s
, NULL
, board
->i8255_offset
);
1162 /* set the interrupt level */
1163 devpriv
->ctrl_reg
= DAS16_CTRL_IRQ(dev
->irq
);
1164 outb(devpriv
->ctrl_reg
, dev
->iobase
+ DAS16_CTRL_REG
);
1166 if (devpriv
->can_burst
) {
1167 outb(DAS1600_ENABLE_VAL
, dev
->iobase
+ DAS1600_ENABLE_REG
);
1168 outb(0, dev
->iobase
+ DAS1600_CONV_REG
);
1169 outb(0, dev
->iobase
+ DAS1600_BURST_REG
);
1175 static void das16_detach(struct comedi_device
*dev
)
1177 const struct das16_board
*board
= dev
->board_ptr
;
1178 struct das16_private_struct
*devpriv
= dev
->private;
1183 das16_free_dma(dev
);
1185 if (devpriv
->extra_iobase
)
1186 release_region(devpriv
->extra_iobase
,
1187 board
->size
& 0x3ff);
1190 comedi_legacy_detach(dev
);
1193 static struct comedi_driver das16_driver
= {
1194 .driver_name
= "das16",
1195 .module
= THIS_MODULE
,
1196 .attach
= das16_attach
,
1197 .detach
= das16_detach
,
1198 .board_name
= &das16_boards
[0].name
,
1199 .num_names
= ARRAY_SIZE(das16_boards
),
1200 .offset
= sizeof(das16_boards
[0]),
1202 module_comedi_driver(das16_driver
);
1204 MODULE_AUTHOR("Comedi http://www.comedi.org");
1205 MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
1206 MODULE_LICENSE("GPL");