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.
22 Description: DAS16 compatible boards
23 Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
24 Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
25 DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
26 DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
28 [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
29 PC104-DAS16JR/16 (pc104-das16jr/16),
30 CIO-DAS16JR/16 (cio-das16jr/16),
31 CIO-DAS16/JR (cio-das16/jr), CIO-DAS1401/12 (cio-das1401/12),
32 CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
33 CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
34 CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
38 A rewrite of the das16 and das1600 drivers.
41 [1] - irq (does nothing, irq is not used anymore)
42 [2] - dma (optional, required for comedi_command support)
43 [3] - master clock speed in MHz (optional, 1 or 10, ignored if
44 board can probe clock, defaults to 1)
45 [4] - analog input range lowest voltage in microvolts (optional,
46 only useful if your board does not have software
48 [5] - analog input range highest voltage in microvolts (optional,
49 only useful if board does not have software programmable
51 [6] - analog output range lowest voltage in microvolts (optional)
52 [7] - analog output range highest voltage in microvolts (optional)
53 [8] - use timer mode for DMA. Timer mode is needed e.g. for
54 buggy DMA controllers in NS CS5530A (Geode Companion), and for
55 'jr' cards that lack a hardware fifo. This option is no
56 longer needed, since timer mode is _always_ used.
58 Passing a zero for an option is the same as leaving it unspecified.
63 Testing and debugging help provided by Daniel Koch.
67 4919.PDF (das1400, 1600)
69 4923.PDF (das1200, 1400, 1600)
71 Computer boards manuals also available from their website
72 www.measurementcomputing.com
76 #include <linux/module.h>
77 #include <linux/delay.h>
78 #include <linux/pci.h>
79 #include <linux/interrupt.h>
83 #include "../comedidev.h"
87 #include "comedi_fc.h"
89 #define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */
95 #define DAS16_AI_LSB 0
96 #define DAS16_AI_MSB 1
99 #define DAS16_AO_LSB(x) ((x) ? 6 : 4)
100 #define DAS16_AO_MSB(x) ((x) ? 7 : 5)
101 #define DAS16_STATUS 8
103 #define UNIPOLAR (1<<6)
104 #define DAS16_MUXBIT (1<<5)
105 #define DAS16_INT (1<<4)
106 #define DAS16_CONTROL 9
107 #define DAS16_INTE (1<<7)
108 #define DAS16_IRQ(x) (((x) & 0x7) << 4)
109 #define DMA_ENABLE (1<<2)
110 #define PACING_MASK 0x3
111 #define INT_PACER 0x03
112 #define EXT_PACER 0x02
113 #define DAS16_SOFT 0x00
114 #define DAS16_PACER 0x0A
115 #define DAS16_CTR0 (1<<1)
116 #define DAS16_TRIG0 (1<<0)
117 #define BURST_LEN_BITS(x) (((x) & 0xf) << 4)
118 #define DAS16_GAIN 0x0B
119 #define DAS16_CNTR0_DATA 0x0C
120 #define DAS16_CNTR1_DATA 0x0D
121 #define DAS16_CNTR2_DATA 0x0E
122 #define DAS16_CNTR_CONTROL 0x0F
123 #define DAS16_TERM_CNT 0x00
124 #define DAS16_ONE_SHOT 0x02
125 #define DAS16_RATE_GEN 0x04
126 #define DAS16_CNTR_LSB_MSB 0x30
127 #define DAS16_CNTR0 0x00
128 #define DAS16_CNTR1 0x40
129 #define DAS16_CNTR2 0x80
131 #define DAS1600_CONV 0x404
132 #define DAS1600_CONV_DISABLE 0x40
133 #define DAS1600_BURST 0x405
134 #define DAS1600_BURST_VAL 0x40
135 #define DAS1600_ENABLE 0x406
136 #define DAS1600_ENABLE_VAL 0x40
137 #define DAS1600_STATUS_B 0x407
138 #define DAS1600_BME 0x40
139 #define DAS1600_ME 0x20
140 #define DAS1600_CD 0x10
141 #define DAS1600_WS 0x02
142 #define DAS1600_CLK_10MHZ 0x01
144 static const struct comedi_lrange range_das1x01_bip = {
153 static const struct comedi_lrange range_das1x01_unip = {
162 static const struct comedi_lrange range_das1x02_bip = {
171 static const struct comedi_lrange range_das1x02_unip = {
180 static const struct comedi_lrange range_das16jr = {
194 static const struct comedi_lrange range_das16jr_16 = {
207 static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
208 static const int das16jr_16_gainlist[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
209 static const int das1600_gainlist[] = { 0, 1, 2, 3 };
218 static const int *const das16_gainlists[] = {
226 static const struct comedi_lrange *const das16_ai_uni_lranges[] = {
234 static const struct comedi_lrange *const das16_ai_bip_lranges[] = {
244 unsigned int ai_maxdata;
245 unsigned int ai_speed; /* max conversion speed in nanosec */
247 unsigned int has_ao:1;
249 unsigned int i8255_offset;
250 unsigned int i8254_offset;
256 #define DAS16_TIMEOUT 1000
258 /* Period for timer interrupt in jiffies. It's a function
259 * to deal with possibility of dynamic HZ patches */
260 static inline int timer_period(void)
265 struct das16_private_struct {
266 unsigned int clockbase; /* master clock speed in ns */
267 unsigned int control_state; /* dma, interrupt and trigger control bits */
268 unsigned long adc_byte_count; /* number of bytes remaining */
269 /* divisor dividing master clock to get conversion frequency */
270 unsigned int divisor1;
271 /* divisor dividing master clock to get conversion frequency */
272 unsigned int divisor2;
273 unsigned int dma_chan; /* dma channel */
274 uint16_t *dma_buffer[2];
275 dma_addr_t dma_buffer_addr[2];
276 unsigned int current_buffer;
277 unsigned int dma_transfer_size; /* target number of bytes to transfer per dma shot */
279 * user-defined analog input and output ranges
280 * defined from config options
282 struct comedi_lrange *user_ai_range_table;
283 struct comedi_lrange *user_ao_range_table;
285 struct timer_list timer; /* for timed interrupt */
288 unsigned long extra_iobase;
289 unsigned int can_burst:1;
292 static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
293 struct comedi_cmd *cmd)
295 const struct das16_board *board = comedi_board(dev);
296 struct das16_private_struct *devpriv = dev->private;
298 int gain, start_chan, i;
301 /* Step 1 : check if triggers are trivially valid */
303 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
306 if (devpriv->can_burst)
307 mask |= TRIG_TIMER | TRIG_EXT;
308 err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask);
310 tmp = cmd->convert_src;
311 mask = TRIG_TIMER | TRIG_EXT;
312 if (devpriv->can_burst)
314 err |= cfc_check_trigger_src(&cmd->convert_src, mask);
316 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
317 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
322 /* Step 2a : make sure trigger sources are unique */
324 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
325 err |= cfc_check_trigger_is_unique(cmd->convert_src);
326 err |= cfc_check_trigger_is_unique(cmd->stop_src);
328 /* Step 2b : and mutually compatible */
330 /* make sure scan_begin_src and convert_src dont conflict */
331 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
333 if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
339 /* Step 3: check if arguments are trivially valid */
341 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
343 if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
344 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
346 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
348 /* check against maximum frequency */
349 if (cmd->scan_begin_src == TRIG_TIMER)
350 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
351 board->ai_speed * cmd->chanlist_len);
353 if (cmd->convert_src == TRIG_TIMER)
354 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
357 if (cmd->stop_src == TRIG_NONE)
358 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
363 /* step 4: fix up arguments */
364 if (cmd->scan_begin_src == TRIG_TIMER) {
365 unsigned int tmp = cmd->scan_begin_arg;
366 /* set divisors, correct timing arguments */
367 i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
368 &(devpriv->divisor1),
369 &(devpriv->divisor2),
370 &(cmd->scan_begin_arg),
371 cmd->flags & TRIG_ROUND_MASK);
372 err += (tmp != cmd->scan_begin_arg);
374 if (cmd->convert_src == TRIG_TIMER) {
375 unsigned int tmp = cmd->convert_arg;
376 /* set divisors, correct timing arguments */
377 i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
378 &(devpriv->divisor1),
379 &(devpriv->divisor2),
381 cmd->flags & TRIG_ROUND_MASK);
382 err += (tmp != cmd->convert_arg);
387 /* check channel/gain list against card's limitations */
389 gain = CR_RANGE(cmd->chanlist[0]);
390 start_chan = CR_CHAN(cmd->chanlist[0]);
391 for (i = 1; i < cmd->chanlist_len; i++) {
392 if (CR_CHAN(cmd->chanlist[i]) !=
393 (start_chan + i) % s->n_chan) {
395 "entries in chanlist must be "
396 "consecutive channels, "
397 "counting upwards\n");
400 if (CR_RANGE(cmd->chanlist[i]) != gain) {
402 "entries in chanlist must all "
403 "have the same gain\n");
414 static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
417 struct das16_private_struct *devpriv = dev->private;
419 i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
420 &(devpriv->divisor2), &ns,
421 rounding_flags & TRIG_ROUND_MASK);
423 /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
424 i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
425 i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
430 static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
432 const struct das16_board *board = comedi_board(dev);
433 struct das16_private_struct *devpriv = dev->private;
434 struct comedi_async *async = s->async;
435 struct comedi_cmd *cmd = &async->cmd;
440 if (cmd->flags & TRIG_RT) {
441 comedi_error(dev, "isa dma transfers cannot be performed with "
442 "TRIG_RT, aborting");
446 devpriv->adc_byte_count =
447 cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t);
449 if (devpriv->can_burst)
450 outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV);
452 /* set scan limits */
453 byte = CR_CHAN(cmd->chanlist[0]);
454 byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;
455 outb(byte, dev->iobase + DAS16_MUX);
457 /* set gain (this is also burst rate register but according to
458 * computer boards manual, burst rate does nothing, even on
460 if (board->ai_pg != das16_pg_none) {
461 range = CR_RANGE(cmd->chanlist[0]);
462 outb((das16_gainlists[board->ai_pg])[range],
463 dev->iobase + DAS16_GAIN);
466 /* set counter mode and counts */
468 das16_set_pacer(dev, cmd->convert_arg,
469 cmd->flags & TRIG_ROUND_MASK);
471 /* enable counters */
473 if (devpriv->can_burst) {
474 if (cmd->convert_src == TRIG_NOW) {
475 outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST);
476 /* set burst length */
477 byte |= BURST_LEN_BITS(cmd->chanlist_len - 1);
479 outb(0, dev->iobase + DAS1600_BURST);
482 outb(byte, dev->iobase + DAS16_PACER);
484 /* set up dma transfer */
485 flags = claim_dma_lock();
486 disable_dma(devpriv->dma_chan);
487 /* clear flip-flop to make sure 2-byte registers for
488 * count and address get set correctly */
489 clear_dma_ff(devpriv->dma_chan);
490 devpriv->current_buffer = 0;
491 set_dma_addr(devpriv->dma_chan,
492 devpriv->dma_buffer_addr[devpriv->current_buffer]);
493 devpriv->dma_transfer_size = DAS16_DMA_SIZE;
494 set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
495 enable_dma(devpriv->dma_chan);
496 release_dma_lock(flags);
498 /* set up interrupt */
499 devpriv->timer_running = 1;
500 devpriv->timer.expires = jiffies + timer_period();
501 add_timer(&devpriv->timer);
502 devpriv->control_state &= ~DAS16_INTE;
503 devpriv->control_state |= DMA_ENABLE;
504 devpriv->control_state &= ~PACING_MASK;
505 if (cmd->convert_src == TRIG_EXT)
506 devpriv->control_state |= EXT_PACER;
508 devpriv->control_state |= INT_PACER;
509 outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
511 if (devpriv->can_burst)
512 outb(0, dev->iobase + DAS1600_CONV);
518 static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
520 struct das16_private_struct *devpriv = dev->private;
523 spin_lock_irqsave(&dev->spinlock, flags);
524 /* disable interrupts, dma and pacer clocked conversions */
525 devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE;
526 outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
527 disable_dma(devpriv->dma_chan);
529 /* disable SW timer */
530 if (devpriv->timer_running) {
531 devpriv->timer_running = 0;
532 del_timer(&devpriv->timer);
535 if (devpriv->can_burst)
536 outb(0, dev->iobase + DAS1600_BURST);
538 spin_unlock_irqrestore(&dev->spinlock, flags);
543 static void das16_reset(struct comedi_device *dev)
545 outb(0, dev->iobase + DAS16_STATUS);
546 outb(0, dev->iobase + DAS16_CONTROL);
547 outb(0, dev->iobase + DAS16_PACER);
548 outb(0, dev->iobase + DAS16_CNTR_CONTROL);
551 static int das16_ai_insn_read(struct comedi_device *dev,
552 struct comedi_subdevice *s,
553 struct comedi_insn *insn,
556 const struct das16_board *board = comedi_board(dev);
557 struct das16_private_struct *devpriv = dev->private;
562 /* disable interrupts and pacing */
563 devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK;
564 outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
566 /* set multiplexer */
567 chan = CR_CHAN(insn->chanspec);
568 chan |= CR_CHAN(insn->chanspec) << 4;
569 outb(chan, dev->iobase + DAS16_MUX);
572 if (board->ai_pg != das16_pg_none) {
573 range = CR_RANGE(insn->chanspec);
574 outb((das16_gainlists[board->ai_pg])[range],
575 dev->iobase + DAS16_GAIN);
578 for (n = 0; n < insn->n; n++) {
581 /* trigger conversion */
582 outb_p(0, dev->iobase + DAS16_TRIG);
584 for (i = 0; i < DAS16_TIMEOUT; i++) {
585 if (!(inb(dev->iobase + DAS16_STATUS) & BUSY))
588 if (i == DAS16_TIMEOUT) {
589 printk("das16: timeout\n");
593 val = inb(dev->iobase + DAS16_AI_MSB) << 8;
594 val |= inb(dev->iobase + DAS16_AI_LSB);
595 if (s->maxdata == 0x0fff)
605 static int das16_di_insn_bits(struct comedi_device *dev,
606 struct comedi_subdevice *s,
607 struct comedi_insn *insn,
610 data[1] = inb(dev->iobase + DAS16_DIO) & 0xf;
615 static int das16_do_insn_bits(struct comedi_device *dev,
616 struct comedi_subdevice *s,
617 struct comedi_insn *insn,
620 unsigned int mask = data[0];
621 unsigned int bits = data[1];
625 s->state |= (bits & mask);
627 outb(s->state, dev->iobase + DAS16_DIO);
635 static int das16_ao_insn_write(struct comedi_device *dev,
636 struct comedi_subdevice *s,
637 struct comedi_insn *insn,
640 unsigned int chan = CR_CHAN(insn->chanspec);
644 for (i = 0; i < insn->n; i++) {
648 outb(val & 0xff, dev->iobase + DAS16_AO_LSB(chan));
649 outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB(chan));
655 /* the pc104-das16jr (at least) has problems if the dma
656 transfer is interrupted in the middle of transferring
657 a 16 bit sample, so this function takes care to get
658 an even transfer count after disabling dma
661 static int disable_dma_on_even(struct comedi_device *dev)
663 struct das16_private_struct *devpriv = dev->private;
666 static const int disable_limit = 100;
667 static const int enable_timeout = 100;
669 disable_dma(devpriv->dma_chan);
670 residue = get_dma_residue(devpriv->dma_chan);
671 for (i = 0; i < disable_limit && (residue % 2); ++i) {
673 enable_dma(devpriv->dma_chan);
674 for (j = 0; j < enable_timeout; ++j) {
677 new_residue = get_dma_residue(devpriv->dma_chan);
678 if (new_residue != residue)
681 disable_dma(devpriv->dma_chan);
682 residue = get_dma_residue(devpriv->dma_chan);
684 if (i == disable_limit) {
685 comedi_error(dev, "failed to get an even dma transfer, "
686 "could be trouble.");
691 static void das16_interrupt(struct comedi_device *dev)
693 struct das16_private_struct *devpriv = dev->private;
694 unsigned long dma_flags, spin_flags;
695 struct comedi_subdevice *s = dev->read_subdev;
696 struct comedi_async *async;
697 struct comedi_cmd *cmd;
698 int num_bytes, residue;
701 if (!dev->attached) {
702 comedi_error(dev, "premature interrupt");
705 /* initialize async here to make sure it is not NULL */
709 spin_lock_irqsave(&dev->spinlock, spin_flags);
710 if ((devpriv->control_state & DMA_ENABLE) == 0) {
711 spin_unlock_irqrestore(&dev->spinlock, spin_flags);
715 dma_flags = claim_dma_lock();
716 clear_dma_ff(devpriv->dma_chan);
717 residue = disable_dma_on_even(dev);
719 /* figure out how many points to read */
720 if (residue > devpriv->dma_transfer_size) {
721 comedi_error(dev, "residue > transfer size!\n");
722 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
725 num_bytes = devpriv->dma_transfer_size - residue;
727 if (cmd->stop_src == TRIG_COUNT &&
728 num_bytes >= devpriv->adc_byte_count) {
729 num_bytes = devpriv->adc_byte_count;
730 async->events |= COMEDI_CB_EOA;
733 buffer_index = devpriv->current_buffer;
734 devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
735 devpriv->adc_byte_count -= num_bytes;
738 if ((async->events & COMEDI_CB_EOA) == 0) {
739 set_dma_addr(devpriv->dma_chan,
740 devpriv->dma_buffer_addr[devpriv->current_buffer]);
741 set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
742 enable_dma(devpriv->dma_chan);
744 release_dma_lock(dma_flags);
746 spin_unlock_irqrestore(&dev->spinlock, spin_flags);
748 cfc_write_array_to_buffer(s,
749 devpriv->dma_buffer[buffer_index], num_bytes);
751 cfc_handle_events(dev, s);
754 static void das16_timer_interrupt(unsigned long arg)
756 struct comedi_device *dev = (struct comedi_device *)arg;
757 struct das16_private_struct *devpriv = dev->private;
759 das16_interrupt(dev);
761 if (devpriv->timer_running)
762 mod_timer(&devpriv->timer, jiffies + timer_period());
765 static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
767 const struct das16_board *board = comedi_board(dev);
770 /* diobits indicates boards */
771 diobits = inb(dev->iobase + DAS16_DIO) & 0xf0;
773 printk(KERN_INFO " id bits are 0x%02x\n", diobits);
774 if (board->id != diobits) {
775 printk(KERN_INFO " requested board's id bits are 0x%x (ignore)\n",
782 static int das1600_mode_detect(struct comedi_device *dev)
784 struct das16_private_struct *devpriv = dev->private;
787 status = inb(dev->iobase + DAS1600_STATUS_B);
789 if (status & DAS1600_CLK_10MHZ) {
790 devpriv->clockbase = 100;
791 printk(KERN_INFO " 10MHz pacer clock\n");
793 devpriv->clockbase = 1000;
794 printk(KERN_INFO " 1MHz pacer clock\n");
800 static void das16_ai_munge(struct comedi_device *dev,
801 struct comedi_subdevice *s, void *array,
802 unsigned int num_bytes,
803 unsigned int start_chan_index)
805 unsigned int i, num_samples = num_bytes / sizeof(short);
808 for (i = 0; i < num_samples; i++) {
809 data[i] = le16_to_cpu(data[i]);
810 if (s->maxdata == 0x0fff)
812 data[i] &= s->maxdata;
822 * 3 Clock speed (in MHz)
824 static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
826 const struct das16_board *board = comedi_board(dev);
827 struct das16_private_struct *devpriv;
828 struct comedi_subdevice *s;
829 struct comedi_krange *user_ai_range;
830 struct comedi_krange *user_ao_range;
831 unsigned int dma_chan = it->options[2];
835 /* check that clock setting is valid */
836 if (it->options[3]) {
837 if (it->options[3] != 0 &&
838 it->options[3] != 1 && it->options[3] != 10) {
840 ("\n Invalid option. Master clock must be set "
841 "to 1 or 10 (MHz)\n");
846 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
850 if (board->size < 0x400) {
851 ret = comedi_request_region(dev, it->options[0], board->size);
855 ret = comedi_request_region(dev, it->options[0], 0x10);
858 /* Request an additional region for the 8255 */
859 ret = __comedi_request_region(dev, dev->iobase + 0x400,
860 board->size & 0x3ff);
863 devpriv->extra_iobase = dev->iobase + 0x400;
864 devpriv->can_burst = 1;
867 /* probe id bits to make sure they are consistent */
868 if (das16_probe(dev, it)) {
869 printk(KERN_ERR " id bits do not match selected board, aborting\n");
873 /* get master clock speed */
874 if (devpriv->can_burst) {
875 das1600_mode_detect(dev);
878 devpriv->clockbase = 1000 / it->options[3];
880 devpriv->clockbase = 1000; /* 1 MHz default */
884 if (dma_chan == 1 || dma_chan == 3) {
888 if (request_dma(dma_chan, dev->board_name)) {
889 dev_err(dev->class_dev,
890 "failed to request dma channel %i\n",
894 devpriv->dma_chan = dma_chan;
896 /* allocate dma buffers */
897 for (i = 0; i < 2; i++) {
900 p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE,
901 &devpriv->dma_buffer_addr[i]);
904 devpriv->dma_buffer[i] = p;
907 flags = claim_dma_lock();
908 disable_dma(devpriv->dma_chan);
909 set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
910 release_dma_lock(flags);
912 init_timer(&(devpriv->timer));
913 devpriv->timer.function = das16_timer_interrupt;
914 devpriv->timer.data = (unsigned long)dev;
917 /* get any user-defined input range */
918 if (board->ai_pg == das16_pg_none &&
919 (it->options[4] || it->options[5])) {
920 /* allocate single-range range table */
921 devpriv->user_ai_range_table =
922 kmalloc(sizeof(struct comedi_lrange) +
923 sizeof(struct comedi_krange), GFP_KERNEL);
924 /* initialize ai range */
925 devpriv->user_ai_range_table->length = 1;
926 user_ai_range = devpriv->user_ai_range_table->range;
927 user_ai_range->min = it->options[4];
928 user_ai_range->max = it->options[5];
929 user_ai_range->flags = UNIT_volt;
931 /* get any user-defined output range */
932 if (it->options[6] || it->options[7]) {
933 /* allocate single-range range table */
934 devpriv->user_ao_range_table =
935 kmalloc(sizeof(struct comedi_lrange) +
936 sizeof(struct comedi_krange), GFP_KERNEL);
937 /* initialize ao range */
938 devpriv->user_ao_range_table->length = 1;
939 user_ao_range = devpriv->user_ao_range_table->range;
940 user_ao_range->min = it->options[6];
941 user_ao_range->max = it->options[7];
942 user_ao_range->flags = UNIT_volt;
945 ret = comedi_alloc_subdevices(dev, 5);
949 status = inb(dev->iobase + DAS16_STATUS);
951 /* Analog Input subdevice */
952 s = &dev->subdevices[0];
953 s->type = COMEDI_SUBD_AI;
954 s->subdev_flags = SDF_READABLE;
955 if (status & DAS16_MUXBIT) {
956 s->subdev_flags |= SDF_GROUND;
959 s->subdev_flags |= SDF_DIFF;
962 s->len_chanlist = s->n_chan;
963 s->maxdata = board->ai_maxdata;
964 if (devpriv->user_ai_range_table) { /* user defined ai range */
965 s->range_table = devpriv->user_ai_range_table;
966 } else if (status & UNIPOLAR) {
967 s->range_table = das16_ai_uni_lranges[board->ai_pg];
969 s->range_table = das16_ai_bip_lranges[board->ai_pg];
971 s->insn_read = das16_ai_insn_read;
972 if (devpriv->dma_chan) {
973 dev->read_subdev = s;
974 s->subdev_flags |= SDF_CMD_READ;
975 s->do_cmdtest = das16_cmd_test;
976 s->do_cmd = das16_cmd_exec;
977 s->cancel = das16_cancel;
978 s->munge = das16_ai_munge;
981 /* Analog Output subdevice */
982 s = &dev->subdevices[1];
984 s->type = COMEDI_SUBD_AO;
985 s->subdev_flags = SDF_WRITABLE;
988 if (devpriv->user_ao_range_table)
989 s->range_table = devpriv->user_ao_range_table;
991 s->range_table = &range_unknown;
993 s->insn_write = das16_ao_insn_write;
995 s->type = COMEDI_SUBD_UNUSED;
998 /* Digital Input subdevice */
999 s = &dev->subdevices[2];
1000 s->type = COMEDI_SUBD_DI;
1001 s->subdev_flags = SDF_READABLE;
1004 s->range_table = &range_digital;
1005 s->insn_bits = das16_di_insn_bits;
1007 /* Digital Output subdevice */
1008 s = &dev->subdevices[3];
1009 s->type = COMEDI_SUBD_DO;
1010 s->subdev_flags = SDF_WRITABLE;
1013 s->range_table = &range_digital;
1014 s->insn_bits = das16_do_insn_bits;
1016 /* initialize digital output lines */
1017 outb(s->state, dev->iobase + DAS16_DIO);
1019 s = &dev->subdevices[4];
1021 if (board->i8255_offset != 0) {
1022 subdev_8255_init(dev, s, NULL, (dev->iobase +
1023 board->i8255_offset));
1025 s->type = COMEDI_SUBD_UNUSED;
1029 /* set the interrupt level */
1030 devpriv->control_state = DAS16_IRQ(dev->irq);
1031 outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
1033 if (devpriv->can_burst) {
1034 outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE);
1035 outb(0, dev->iobase + DAS1600_CONV);
1036 outb(0, dev->iobase + DAS1600_BURST);
1042 static void das16_detach(struct comedi_device *dev)
1044 const struct das16_board *board = comedi_board(dev);
1045 struct das16_private_struct *devpriv = dev->private;
1050 for (i = 0; i < 2; i++) {
1051 if (devpriv->dma_buffer[i])
1052 pci_free_consistent(NULL, DAS16_DMA_SIZE,
1053 devpriv->dma_buffer[i],
1055 dma_buffer_addr[i]);
1057 if (devpriv->dma_chan)
1058 free_dma(devpriv->dma_chan);
1059 kfree(devpriv->user_ai_range_table);
1060 kfree(devpriv->user_ao_range_table);
1062 if (devpriv->extra_iobase)
1063 release_region(devpriv->extra_iobase, board->size & 0x3ff);
1064 comedi_legacy_detach(dev);
1067 static const struct das16_board das16_boards[] = {
1070 .ai_maxdata = 0x0fff,
1072 .ai_pg = das16_pg_none,
1074 .i8255_offset = 0x10,
1075 .i8254_offset = 0x0c,
1080 .ai_maxdata = 0x0fff,
1082 .ai_pg = das16_pg_none,
1084 .i8255_offset = 0x10,
1085 .i8254_offset = 0x0c,
1090 .ai_maxdata = 0x0fff,
1092 .ai_pg = das16_pg_none,
1094 .i8255_offset = 0x10,
1095 .i8254_offset = 0x0c,
1099 .name = "cio-das16",
1100 .ai_maxdata = 0x0fff,
1102 .ai_pg = das16_pg_none,
1104 .i8255_offset = 0x10,
1105 .i8254_offset = 0x0c,
1109 .name = "cio-das16/f",
1110 .ai_maxdata = 0x0fff,
1112 .ai_pg = das16_pg_none,
1114 .i8255_offset = 0x10,
1115 .i8254_offset = 0x0c,
1119 .name = "cio-das16/jr",
1120 .ai_maxdata = 0x0fff,
1122 .ai_pg = das16_pg_16jr,
1124 .i8254_offset = 0x0c,
1128 .name = "pc104-das16jr",
1129 .ai_maxdata = 0x0fff,
1131 .ai_pg = das16_pg_16jr,
1133 .i8254_offset = 0x0c,
1137 .name = "cio-das16jr/16",
1138 .ai_maxdata = 0xffff,
1140 .ai_pg = das16_pg_16jr_16,
1142 .i8254_offset = 0x0c,
1146 .name = "pc104-das16jr/16",
1147 .ai_maxdata = 0xffff,
1149 .ai_pg = das16_pg_16jr_16,
1151 .i8254_offset = 0x0c,
1156 .ai_maxdata = 0x0fff,
1158 .ai_pg = das16_pg_none,
1159 .i8255_offset = 0x400,
1160 .i8254_offset = 0x0c,
1165 .ai_maxdata = 0x0fff,
1167 .ai_pg = das16_pg_none,
1168 .i8255_offset = 0x400,
1169 .i8254_offset = 0x0c,
1174 .ai_maxdata = 0x0fff,
1176 .ai_pg = das16_pg_1601,
1177 .i8255_offset = 0x0,
1178 .i8254_offset = 0x0c,
1183 .ai_maxdata = 0x0fff,
1185 .ai_pg = das16_pg_1602,
1186 .i8255_offset = 0x0,
1187 .i8254_offset = 0x0c,
1192 .ai_maxdata = 0x0fff,
1194 .ai_pg = das16_pg_1601,
1196 .i8255_offset = 0x400,
1197 .i8254_offset = 0x0c,
1202 .ai_maxdata = 0x0fff,
1204 .ai_pg = das16_pg_1602,
1206 .i8255_offset = 0x400,
1207 .i8254_offset = 0x0c,
1211 .name = "cio-das1401/12",
1212 .ai_maxdata = 0x0fff,
1214 .ai_pg = das16_pg_1601,
1216 .i8254_offset = 0x0c,
1220 .name = "cio-das1402/12",
1221 .ai_maxdata = 0x0fff,
1223 .ai_pg = das16_pg_1602,
1225 .i8254_offset = 0x0c,
1229 .name = "cio-das1402/16",
1230 .ai_maxdata = 0xffff,
1232 .ai_pg = das16_pg_1602,
1234 .i8254_offset = 0x0c,
1238 .name = "cio-das1601/12",
1239 .ai_maxdata = 0x0fff,
1241 .ai_pg = das16_pg_1601,
1243 .i8255_offset = 0x400,
1244 .i8254_offset = 0x0c,
1248 .name = "cio-das1602/12",
1249 .ai_maxdata = 0x0fff,
1251 .ai_pg = das16_pg_1602,
1253 .i8255_offset = 0x400,
1254 .i8254_offset = 0x0c,
1258 .name = "cio-das1602/16",
1259 .ai_maxdata = 0xffff,
1261 .ai_pg = das16_pg_1602,
1263 .i8255_offset = 0x400,
1264 .i8254_offset = 0x0c,
1268 .name = "cio-das16/330",
1269 .ai_maxdata = 0x0fff,
1271 .ai_pg = das16_pg_16jr,
1273 .i8254_offset = 0x0c,
1279 static struct comedi_driver das16_driver = {
1280 .driver_name = "das16",
1281 .module = THIS_MODULE,
1282 .attach = das16_attach,
1283 .detach = das16_detach,
1284 .board_name = &das16_boards[0].name,
1285 .num_names = ARRAY_SIZE(das16_boards),
1286 .offset = sizeof(das16_boards[0]),
1288 module_comedi_driver(das16_driver);
1290 MODULE_AUTHOR("Comedi http://www.comedi.org");
1291 MODULE_DESCRIPTION("Comedi low-level driver");
1292 MODULE_LICENSE("GPL");