2 comedi/drivers/amplc_dio200.c
3 Driver for Amplicon PC272E and PCI272 DIO boards.
4 (Support for other boards in Amplicon 200 series may be added at
5 a later date, e.g. PCI215.)
7 Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/>
9 COMEDI - Linux Control and Measurement Device Interface
10 Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 Description: Amplicon 200 Series Digital I/O
30 Author: Ian Abbott <abbotti@mev.co.uk>
31 Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e),
32 PCI215 (pci215 or amplc_dio200), PC218E (pc218e), PC272E (pc272e),
33 PCI272 (pci272 or amplc_dio200)
34 Updated: Wed, 22 Oct 2008 13:36:02 +0100
37 Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E:
38 [0] - I/O port base address
39 [1] - IRQ (optional, but commands won't work without it)
41 Configuration options - PCI215, PCI272:
42 [0] - PCI bus of device (optional)
43 [1] - PCI slot of device (optional)
44 If bus/slot is not specified, the first available PCI device will
47 Passing a zero for an option is the same as leaving it unspecified.
51 PC218E PC212E PC215E/PCI215
52 ------------- ------------- -------------
56 2 CTR-Y1 CTR-Y2 CTR-Z1
57 3 CTR-Y2 CTR-Z1 CTR-Z2
58 4 CTR-Z1 CTR-Z2 INTERRUPT
63 ------------- -------------
68 3 INTERRUPT* INTERRUPT
70 Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels
71 are configurable as inputs or outputs in four groups:
73 Port A - channels 0 to 7
74 Port B - channels 8 to 15
75 Port CL - channels 16 to 19
76 Port CH - channels 20 to 23
78 Only mode 0 of the 8255 chips is supported.
80 Each CTR is a 8254 chip providing 3 16-bit counter channels. Each
81 channel is configured individually with INSN_CONFIG instructions. The
82 specific type of configuration instruction is specified in data[0].
83 Some configuration instructions expect an additional parameter in
84 data[1]; others return a value in data[1]. The following configuration
85 instructions are supported:
87 INSN_CONFIG_SET_COUNTER_MODE. Sets the counter channel's mode and
88 BCD/binary setting specified in data[1].
90 INSN_CONFIG_8254_READ_STATUS. Reads the status register value for the
91 counter channel into data[1].
93 INSN_CONFIG_SET_CLOCK_SRC. Sets the counter channel's clock source as
94 specified in data[1] (this is a hardware-specific value). Not
95 supported on PC214E. For the other boards, valid clock sources are
98 0. CLK n, the counter channel's dedicated CLK input from the SK1
99 connector. (N.B. for other values, the counter channel's CLKn
100 pin on the SK1 connector is an output!)
101 1. Internal 10 MHz clock.
102 2. Internal 1 MHz clock.
103 3. Internal 100 kHz clock.
104 4. Internal 10 kHz clock.
105 5. Internal 1 kHz clock.
106 6. OUT n-1, the output of counter channel n-1 (see note 1 below).
107 7. Ext Clock, the counter chip's dedicated Ext Clock input from
108 the SK1 connector. This pin is shared by all three counter
109 channels on the chip.
111 INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current
112 clock source in data[1]. For internal clock sources, data[2] is set
115 INSN_CONFIG_SET_GATE_SRC. Sets the counter channel's gate source as
116 specified in data[2] (this is a hardware-specific value). Not
117 supported on PC214E. For the other boards, valid gate sources are 0
120 0. VCC (internal +5V d.c.), i.e. gate permanently enabled.
121 1. GND (internal 0V d.c.), i.e. gate permanently disabled.
122 2. GAT n, the counter channel's dedicated GAT input from the SK1
123 connector. (N.B. for other values, the counter channel's GATn
124 pin on the SK1 connector is an output!)
125 3. /OUT n-2, the inverted output of counter channel n-2 (see note
132 INSN_CONFIG_GET_GATE_SRC. Returns the counter channel's current gate
135 Clock and gate interconnection notes:
137 1. Clock source OUT n-1 is the output of the preceding channel on the
138 same counter subdevice if n > 0, or the output of channel 2 on the
139 preceding counter subdevice (see note 3) if n = 0.
141 2. Gate source /OUT n-2 is the inverted output of channel 0 on the
142 same counter subdevice if n = 2, or the inverted output of channel n+1
143 on the preceding counter subdevice (see note 3) if n < 2.
145 3. The counter subdevices are connected in a ring, so the highest
146 counter subdevice precedes the lowest.
148 The 'INTERRUPT' subdevice pretends to be a digital input subdevice. The
149 digital inputs come from the interrupt status register. The number of
150 channels matches the number of interrupt sources. The PC214E does not
151 have an interrupt status register; see notes on 'INTERRUPT SOURCES'
156 PC218E PC212E PC215E/PCI215
157 ------------- ------------- -------------
159 0 CTR-X1-OUT PPI-X-C0 PPI-X-C0
160 1 CTR-X2-OUT PPI-X-C3 PPI-X-C3
161 2 CTR-Y1-OUT CTR-Y1-OUT PPI-Y-C0
162 3 CTR-Y2-OUT CTR-Y2-OUT PPI-Y-C3
163 4 CTR-Z1-OUT CTR-Z1-OUT CTR-Z1-OUT
164 5 CTR-Z2-OUT CTR-Z2-OUT CTR-Z2-OUT
167 ------------- -------------
176 When an interrupt source is enabled in the interrupt source enable
177 register, a rising edge on the source signal latches the corresponding
178 bit to 1 in the interrupt status register.
180 When the interrupt status register value as a whole (actually, just the
181 6 least significant bits) goes from zero to non-zero, the board will
182 generate an interrupt. For level-triggered hardware interrupts (PCI
183 card), the interrupt will remain asserted until the interrupt status
184 register is cleared to zero. For edge-triggered hardware interrupts
185 (ISA card), no further interrupts will occur until the interrupt status
186 register is cleared to zero. To clear a bit to zero in the interrupt
187 status register, the corresponding interrupt source must be disabled
188 in the interrupt source enable register (there is no separate interrupt
191 The PC214E does not have an interrupt source enable register or an
192 interrupt status register; its 'INTERRUPT' subdevice has a single
193 channel and its interrupt source is selected by the position of jumper
198 The driver supports a read streaming acquisition command on the
199 'INTERRUPT' subdevice. The channel list selects the interrupt sources
200 to be enabled. All channels will be sampled together (convert_src ==
201 TRIG_NOW). The scan begins a short time after the hardware interrupt
202 occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT,
203 scan_begin_arg == 0). The value read from the interrupt status register
204 is packed into a sampl_t value, one bit per requested channel, in the
205 order they appear in the channel list.
208 #include <linux/comedidev.h>
210 #include "comedi_pci.h"
215 #define DIO200_DRIVER_NAME "amplc_dio200"
218 /* #define PCI_VENDOR_ID_AMPLICON 0x14dc */
219 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
220 #define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
221 #define PCI_DEVICE_ID_INVALID 0xffff
223 /* 200 series registers */
224 #define DIO200_IO_SIZE 0x20
225 #define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */
226 #define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */
227 #define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */
228 #define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */
229 #define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
230 #define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
231 #define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
234 * Macros for constructing value for DIO_200_?CLK_SCE and
235 * DIO_200_?GAT_SCE registers:
237 * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
238 * 'chan' is the channel: 0, 1 or 2.
239 * 'source' is the signal source: 0 to 7.
241 #define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
242 #define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
245 * Periods of the internal clock sources in nanoseconds.
247 static const unsigned clock_period[8] = {
248 0, /* dedicated clock input/output pin */
255 0 /* group clock input pin */
259 * Board descriptions.
262 enum dio200_bustype { isa_bustype, pci_bustype };
267 pc215e_model, pci215_model,
269 pc272e_model, pci272_model,
281 typedef struct dio200_board_struct {
283 unsigned short devid;
284 enum dio200_bustype bustype;
285 enum dio200_model model;
286 enum dio200_layout layout;
289 static const dio200_board dio200_boards[] = {
292 bustype: isa_bustype,
294 layout: pc212_layout,
298 bustype: isa_bustype,
300 layout: pc214_layout,
304 bustype: isa_bustype,
306 layout: pc215_layout,
308 #ifdef CONFIG_COMEDI_PCI
311 devid: PCI_DEVICE_ID_AMPLICON_PCI215,
312 bustype: pci_bustype,
314 layout: pc215_layout,
319 bustype: isa_bustype,
321 layout: pc218_layout,
325 bustype: isa_bustype,
327 layout: pc272_layout,
329 #ifdef CONFIG_COMEDI_PCI
332 devid: PCI_DEVICE_ID_AMPLICON_PCI272,
333 bustype: pci_bustype,
335 layout: pc272_layout,
338 #ifdef CONFIG_COMEDI_PCI
340 name: DIO200_DRIVER_NAME,
341 devid: PCI_DEVICE_ID_INVALID,
342 bustype: pci_bustype,
343 model: anypci_model, /* wildcard */
349 * Layout descriptions - some ISA and PCI board descriptions share the same
353 enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
355 #define DIO200_MAX_SUBDEVS 7
356 #define DIO200_MAX_ISNS 6
358 typedef struct dio200_layout_struct {
359 unsigned short n_subdevs; /* number of subdevices */
360 unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
361 unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
362 char has_int_sce; /* has interrupt enable/status register */
363 char has_clk_gat_sce; /* has clock/gate selection registers */
366 static const dio200_layout dio200_layouts[] = {
369 sdtype: {sd_8255, sd_8254, sd_8254, sd_8254,
372 sdinfo: {0x00, 0x08, 0x0C, 0x10, 0x14,
379 sdtype: {sd_8255, sd_8255, sd_8254,
381 sdinfo: {0x00, 0x08, 0x10, 0x01},
387 sdtype: {sd_8255, sd_8255, sd_8254,
390 sdinfo: {0x00, 0x08, 0x10, 0x14, 0x3F},
396 sdtype: {sd_8254, sd_8254, sd_8255, sd_8254,
399 sdinfo: {0x00, 0x04, 0x08, 0x0C, 0x10,
407 sdtype: {sd_8255, sd_8255, sd_8255,
409 sdinfo: {0x00, 0x08, 0x10, 0x3F},
419 #ifdef CONFIG_COMEDI_PCI
420 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
421 {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
422 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
423 {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
424 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
428 MODULE_DEVICE_TABLE(pci, dio200_pci_table);
429 #endif /* CONFIG_COMEDI_PCI */
432 * Useful for shorthand access to the particular board structure
434 #define thisboard ((const dio200_board *)dev->board_ptr)
435 #define thislayout (&dio200_layouts[((dio200_board *)dev->board_ptr)->layout])
437 /* this structure is for data unique to this hardware driver. If
438 several hardware drivers keep similar information in this structure,
439 feel free to suggest moving the variable to the comedi_device struct. */
441 #ifdef CONFIG_COMEDI_PCI
442 struct pci_dev *pci_dev; /* PCI device */
447 #define devpriv ((dio200_private *)dev->private)
450 unsigned long iobase; /* Counter base address */
451 unsigned long clk_sce_iobase; /* CLK_SCE base address */
452 unsigned long gat_sce_iobase; /* GAT_SCE base address */
453 int which; /* Bit 5 of CLK_SCE or GAT_SCE */
454 unsigned clock_src[3]; /* Current clock sources */
455 unsigned gate_src[3]; /* Current gate sources */
457 } dio200_subdev_8254;
460 unsigned long iobase;
464 unsigned int valid_isns;
465 unsigned int enabled_isns;
466 unsigned int stopcount;
468 } dio200_subdev_intr;
471 * The comedi_driver structure tells the Comedi core module
472 * which functions to call to configure/deconfigure (attach/detach)
473 * the board, and also about the kernel module that contains
476 static int dio200_attach(comedi_device * dev, comedi_devconfig * it);
477 static int dio200_detach(comedi_device * dev);
478 static comedi_driver driver_amplc_dio200 = {
479 driver_name:DIO200_DRIVER_NAME,
481 attach:dio200_attach,
482 detach:dio200_detach,
483 board_name:&dio200_boards[0].name,
484 offset:sizeof(dio200_board),
485 num_names:sizeof(dio200_boards) / sizeof(dio200_board),
488 #ifdef CONFIG_COMEDI_PCI
489 COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
491 COMEDI_INITCLEANUP(driver_amplc_dio200);
495 * This function looks for a PCI device matching the requested board name,
498 #ifdef CONFIG_COMEDI_PCI
500 dio200_find_pci(comedi_device * dev, int bus, int slot,
501 struct pci_dev **pci_dev_p)
503 struct pci_dev *pci_dev = NULL;
507 /* Look for matching PCI device. */
508 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
510 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
511 PCI_ANY_ID, pci_dev)) {
512 /* If bus/slot specified, check them. */
514 if (bus != pci_dev->bus->number
515 || slot != PCI_SLOT(pci_dev->devfn))
518 if (thisboard->model == anypci_model) {
519 /* Match any supported model. */
522 for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
523 if (dio200_boards[i].bustype != pci_bustype)
525 if (pci_dev->device == dio200_boards[i].devid) {
526 /* Change board_ptr to matched board. */
527 dev->board_ptr = &dio200_boards[i];
531 if (i == ARRAY_SIZE(dio200_boards))
534 /* Match specific model name. */
535 if (pci_dev->device != thisboard->devid)
540 *pci_dev_p = pci_dev;
543 /* No match found. */
546 "comedi%d: error! no %s found at pci %02x:%02x!\n",
547 dev->minor, thisboard->name, bus, slot);
549 printk(KERN_ERR "comedi%d: error! no %s found!\n",
550 dev->minor, thisboard->name);
557 * This function checks and requests an I/O region, reporting an error
558 * if there is a conflict.
561 dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
563 if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
564 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
565 minor, from, extent);
572 * 'insn_bits' function for an 'INTERRUPT' subdevice.
575 dio200_subdev_intr_insn_bits(comedi_device * dev, comedi_subdevice * s,
576 comedi_insn * insn, lsampl_t * data)
578 dio200_subdev_intr *subpriv = s->private;
580 if (subpriv->has_int_sce) {
581 /* Just read the interrupt status register. */
582 data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
584 /* No interrupt status register. */
592 * Called to stop acquisition for an 'INTERRUPT' subdevice.
594 static void dio200_stop_intr(comedi_device * dev, comedi_subdevice * s)
596 dio200_subdev_intr *subpriv = s->private;
599 subpriv->enabled_isns = 0;
600 if (subpriv->has_int_sce) {
601 outb(0, subpriv->iobase);
606 * Called to start acquisition for an 'INTERRUPT' subdevice.
608 static int dio200_start_intr(comedi_device * dev, comedi_subdevice * s)
612 dio200_subdev_intr *subpriv = s->private;
613 comedi_cmd *cmd = &s->async->cmd;
616 if (!subpriv->continuous && subpriv->stopcount == 0) {
617 /* An empty acquisition! */
618 s->async->events |= COMEDI_CB_EOA;
622 /* Determine interrupt sources to enable. */
625 for (n = 0; n < cmd->chanlist_len; n++) {
626 isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
629 isn_bits &= subpriv->valid_isns;
630 /* Enable interrupt sources. */
631 subpriv->enabled_isns = isn_bits;
632 if (subpriv->has_int_sce) {
633 outb(isn_bits, subpriv->iobase);
641 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
644 dio200_inttrig_start_intr(comedi_device * dev, comedi_subdevice * s,
645 unsigned int trignum)
647 dio200_subdev_intr *subpriv;
654 subpriv = s->private;
656 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
657 s->async->inttrig = 0;
658 if (subpriv->active) {
659 event = dio200_start_intr(dev, s);
661 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
664 comedi_event(dev, s);
671 * This is called from the interrupt service routine to handle a read
672 * scan on an 'INTERRUPT' subdevice.
674 static int dio200_handle_read_intr(comedi_device * dev, comedi_subdevice * s)
676 dio200_subdev_intr *subpriv = s->private;
679 unsigned cur_enabled;
680 unsigned int oldevents;
685 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
686 oldevents = s->async->events;
687 if (subpriv->has_int_sce) {
689 * Collect interrupt sources that have triggered and disable
690 * them temporarily. Loop around until no extra interrupt
691 * sources have triggered, at which point, the valid part of
692 * the interrupt status register will read zero, clearing the
693 * cause of the interrupt.
695 * Mask off interrupt sources already seen to avoid infinite
696 * loop in case of misconfiguration.
698 cur_enabled = subpriv->enabled_isns;
699 while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
700 & ~triggered)) != 0) {
701 triggered |= intstat;
702 cur_enabled &= ~triggered;
703 outb(cur_enabled, subpriv->iobase);
707 * No interrupt status register. Assume the single interrupt
708 * source has triggered.
710 triggered = subpriv->enabled_isns;
715 * Some interrupt sources have triggered and have been
716 * temporarily disabled to clear the cause of the interrupt.
718 * Reenable them NOW to minimize the time they are disabled.
720 cur_enabled = subpriv->enabled_isns;
721 if (subpriv->has_int_sce) {
722 outb(cur_enabled, subpriv->iobase);
725 if (subpriv->active) {
727 * The command is still active.
729 * Ignore interrupt sources that the command isn't
730 * interested in (just in case there's a race
733 if (triggered & subpriv->enabled_isns) {
734 /* Collect scan data. */
736 unsigned int n, ch, len;
739 len = s->async->cmd.chanlist_len;
740 for (n = 0; n < len; n++) {
741 ch = CR_CHAN(s->async->cmd.chanlist[n]);
742 if (triggered & (1U << ch)) {
746 /* Write the scan to the buffer. */
747 if (comedi_buf_put(s->async, val)) {
748 s->async->events |= (COMEDI_CB_BLOCK |
751 /* Error! Stop acquisition. */
752 dio200_stop_intr(dev, s);
753 s->async->events |= COMEDI_CB_ERROR
754 | COMEDI_CB_OVERFLOW;
755 comedi_error(dev, "buffer overflow");
758 /* Check for end of acquisition. */
759 if (!subpriv->continuous) {
760 /* stop_src == TRIG_COUNT */
761 if (subpriv->stopcount > 0) {
762 subpriv->stopcount--;
763 if (subpriv->stopcount == 0) {
766 dio200_stop_intr(dev,
774 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
776 if (oldevents != s->async->events) {
777 comedi_event(dev, s);
780 return (triggered != 0);
784 * 'cancel' function for an 'INTERRUPT' subdevice.
786 static int dio200_subdev_intr_cancel(comedi_device * dev, comedi_subdevice * s)
788 dio200_subdev_intr *subpriv = s->private;
791 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
792 if (subpriv->active) {
793 dio200_stop_intr(dev, s);
795 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
801 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
804 dio200_subdev_intr_cmdtest(comedi_device * dev, comedi_subdevice * s,
810 /* step 1: make sure trigger sources are trivially valid */
812 tmp = cmd->start_src;
813 cmd->start_src &= (TRIG_NOW | TRIG_INT);
814 if (!cmd->start_src || tmp != cmd->start_src)
817 tmp = cmd->scan_begin_src;
818 cmd->scan_begin_src &= TRIG_EXT;
819 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
822 tmp = cmd->convert_src;
823 cmd->convert_src &= TRIG_NOW;
824 if (!cmd->convert_src || tmp != cmd->convert_src)
827 tmp = cmd->scan_end_src;
828 cmd->scan_end_src &= TRIG_COUNT;
829 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
833 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
834 if (!cmd->stop_src || tmp != cmd->stop_src)
840 /* step 2: make sure trigger sources are unique and mutually compatible */
842 /* these tests are true if more than one _src bit is set */
843 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
845 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
847 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
849 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
851 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
857 /* step 3: make sure arguments are trivially compatible */
859 /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
860 if (cmd->start_arg != 0) {
865 /* cmd->scan_begin_src == TRIG_EXT */
866 if (cmd->scan_begin_arg != 0) {
867 cmd->scan_begin_arg = 0;
871 /* cmd->convert_src == TRIG_NOW */
872 if (cmd->convert_arg != 0) {
873 cmd->convert_arg = 0;
877 /* cmd->scan_end_src == TRIG_COUNT */
878 if (cmd->scan_end_arg != cmd->chanlist_len) {
879 cmd->scan_end_arg = cmd->chanlist_len;
883 switch (cmd->stop_src) {
885 /* any count allowed */
888 if (cmd->stop_arg != 0) {
900 /* step 4: fix up any arguments */
902 /* if (err) return 4; */
908 * 'do_cmd' function for an 'INTERRUPT' subdevice.
910 static int dio200_subdev_intr_cmd(comedi_device * dev, comedi_subdevice * s)
912 comedi_cmd *cmd = &s->async->cmd;
913 dio200_subdev_intr *subpriv = s->private;
917 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
920 /* Set up end of acquisition. */
921 switch (cmd->stop_src) {
923 subpriv->continuous = 0;
924 subpriv->stopcount = cmd->stop_arg;
928 subpriv->continuous = 1;
929 subpriv->stopcount = 0;
933 /* Set up start of acquisition. */
934 switch (cmd->start_src) {
936 s->async->inttrig = dio200_inttrig_start_intr;
940 event = dio200_start_intr(dev, s);
943 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
946 comedi_event(dev, s);
953 * This function initializes an 'INTERRUPT' subdevice.
956 dio200_subdev_intr_init(comedi_device * dev, comedi_subdevice * s,
957 unsigned long iobase, unsigned valid_isns, int has_int_sce)
959 dio200_subdev_intr *subpriv;
961 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
963 printk(KERN_ERR "comedi%d: error! out of memory!\n",
967 subpriv->iobase = iobase;
968 subpriv->has_int_sce = has_int_sce;
969 subpriv->valid_isns = valid_isns;
970 spin_lock_init(&subpriv->spinlock);
973 outb(0, subpriv->iobase); /* Disable interrupt sources. */
976 s->private = subpriv;
977 s->type = COMEDI_SUBD_DI;
978 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
980 s->n_chan = DIO200_MAX_ISNS;
981 s->len_chanlist = DIO200_MAX_ISNS;
983 /* No interrupt source register. Support single channel. */
987 s->range_table = &range_digital;
989 s->insn_bits = dio200_subdev_intr_insn_bits;
990 s->do_cmdtest = dio200_subdev_intr_cmdtest;
991 s->do_cmd = dio200_subdev_intr_cmd;
992 s->cancel = dio200_subdev_intr_cancel;
998 * This function cleans up an 'INTERRUPT' subdevice.
1001 dio200_subdev_intr_cleanup(comedi_device * dev, comedi_subdevice * s)
1003 dio200_subdev_intr *subpriv = s->private;
1011 * Interrupt service routine.
1013 static irqreturn_t dio200_interrupt(int irq, void *d PT_REGS_ARG)
1015 comedi_device *dev = d;
1018 if (!dev->attached) {
1022 if (devpriv->intr_sd >= 0) {
1023 handled = dio200_handle_read_intr(dev,
1024 dev->subdevices + devpriv->intr_sd);
1029 return IRQ_RETVAL(handled);
1033 * Handle 'insn_read' for an '8254' counter subdevice.
1036 dio200_subdev_8254_read(comedi_device * dev, comedi_subdevice * s,
1037 comedi_insn * insn, lsampl_t * data)
1039 dio200_subdev_8254 *subpriv = s->private;
1040 int chan = CR_CHAN(insn->chanspec);
1041 unsigned long flags;
1046 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1047 data[0] = i8254_read(subpriv->iobase, 0, chan);
1048 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1054 * Handle 'insn_write' for an '8254' counter subdevice.
1057 dio200_subdev_8254_write(comedi_device * dev, comedi_subdevice * s,
1058 comedi_insn * insn, lsampl_t * data)
1060 dio200_subdev_8254 *subpriv = s->private;
1061 int chan = CR_CHAN(insn->chanspec);
1062 unsigned long flags;
1067 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1068 i8254_write(subpriv->iobase, 0, chan, data[0]);
1069 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1075 * Set gate source for an '8254' counter subdevice channel.
1078 dio200_subdev_8254_set_gate_src(comedi_device * dev, comedi_subdevice *s,
1079 unsigned int counter_number, unsigned int gate_src)
1081 dio200_subdev_8254 *subpriv = s->private;
1084 if (!thislayout->has_clk_gat_sce)
1086 if (counter_number > 2)
1091 subpriv->gate_src[counter_number] = gate_src;
1092 byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1093 outb(byte, subpriv->gat_sce_iobase);
1099 * Get gate source for an '8254' counter subdevice channel.
1102 dio200_subdev_8254_get_gate_src(comedi_device * dev, comedi_subdevice *s,
1103 unsigned int counter_number)
1105 dio200_subdev_8254 *subpriv = s->private;
1107 if (!thislayout->has_clk_gat_sce)
1109 if (counter_number > 2)
1112 return subpriv->gate_src[counter_number];
1116 * Set clock source for an '8254' counter subdevice channel.
1119 dio200_subdev_8254_set_clock_src(comedi_device * dev, comedi_subdevice *s,
1120 unsigned int counter_number, unsigned int clock_src)
1122 dio200_subdev_8254 *subpriv = s->private;
1125 if (!thislayout->has_clk_gat_sce)
1127 if (counter_number > 2)
1132 subpriv->clock_src[counter_number] = clock_src;
1133 byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1134 outb(byte, subpriv->clk_sce_iobase);
1140 * Get clock source for an '8254' counter subdevice channel.
1143 dio200_subdev_8254_get_clock_src(comedi_device * dev, comedi_subdevice *s,
1144 unsigned int counter_number, lsampl_t * period_ns)
1146 dio200_subdev_8254 *subpriv = s->private;
1149 if (!thislayout->has_clk_gat_sce)
1151 if (counter_number > 2)
1154 clock_src = subpriv->clock_src[counter_number];
1155 *period_ns = clock_period[clock_src];
1160 * Handle 'insn_config' for an '8254' counter subdevice.
1163 dio200_subdev_8254_config(comedi_device * dev, comedi_subdevice * s,
1164 comedi_insn * insn, lsampl_t * data)
1166 dio200_subdev_8254 *subpriv = s->private;
1168 int chan = CR_CHAN(insn->chanspec);
1169 unsigned long flags;
1171 comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1173 case INSN_CONFIG_SET_COUNTER_MODE:
1174 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1178 case INSN_CONFIG_8254_READ_STATUS:
1179 data[1] = i8254_status(subpriv->iobase, 0, chan);
1181 case INSN_CONFIG_SET_GATE_SRC:
1182 ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
1186 case INSN_CONFIG_GET_GATE_SRC:
1187 ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
1194 case INSN_CONFIG_SET_CLOCK_SRC:
1195 ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
1199 case INSN_CONFIG_GET_CLOCK_SRC:
1200 ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
1211 comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1212 return ret < 0 ? ret : insn->n;
1216 * This function initializes an '8254' counter subdevice.
1218 * Note: iobase is the base address of the board, not the subdevice;
1219 * offset is the offset to the 8254 chip.
1222 dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
1223 unsigned long iobase, unsigned offset)
1225 dio200_subdev_8254 *subpriv;
1228 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1230 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1235 s->private = subpriv;
1236 s->type = COMEDI_SUBD_COUNTER;
1237 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1239 s->maxdata = 0xFFFF;
1240 s->insn_read = dio200_subdev_8254_read;
1241 s->insn_write = dio200_subdev_8254_write;
1242 s->insn_config = dio200_subdev_8254_config;
1244 spin_lock_init(&subpriv->spinlock);
1245 subpriv->iobase = offset + iobase;
1246 if (thislayout->has_clk_gat_sce) {
1247 /* Derive CLK_SCE and GAT_SCE register offsets from
1249 subpriv->clk_sce_iobase =
1250 DIO200_XCLK_SCE + (offset >> 3) + iobase;
1251 subpriv->gat_sce_iobase =
1252 DIO200_XGAT_SCE + (offset >> 3) + iobase;
1253 subpriv->which = (offset >> 2) & 1;
1256 /* Initialize channels. */
1257 for (chan = 0; chan < 3; chan++) {
1258 i8254_set_mode(subpriv->iobase, 0, chan,
1259 I8254_MODE0 | I8254_BINARY);
1260 if (thislayout->has_clk_gat_sce) {
1261 /* Gate source 0 is VCC (logic 1). */
1262 dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
1263 /* Clock source 0 is the dedicated clock input. */
1264 dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
1272 * This function cleans up an '8254' counter subdevice.
1275 dio200_subdev_8254_cleanup(comedi_device * dev, comedi_subdevice * s)
1277 dio200_subdev_8254 *subpriv = s->private;
1285 * Attach is called by the Comedi core to configure the driver
1286 * for a particular board. If you specified a board_name array
1287 * in the driver structure, dev->board_ptr contains that
1290 static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
1292 comedi_subdevice *s;
1293 unsigned long iobase = 0;
1294 unsigned int irq = 0;
1295 #ifdef CONFIG_COMEDI_PCI
1296 struct pci_dev *pci_dev = NULL;
1297 int bus = 0, slot = 0;
1299 const dio200_layout *layout;
1305 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1306 DIO200_DRIVER_NAME);
1308 if ((ret = alloc_private(dev, sizeof(dio200_private))) < 0) {
1309 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1314 /* Process options. */
1315 switch (thisboard->bustype) {
1317 iobase = it->options[0];
1318 irq = it->options[1];
1321 #ifdef CONFIG_COMEDI_PCI
1323 bus = it->options[0];
1324 slot = it->options[1];
1327 if ((ret = dio200_find_pci(dev, bus, slot, &pci_dev)) < 0)
1329 devpriv->pci_dev = pci_dev;
1334 "comedi%d: %s: BUG! cannot determine board type!\n",
1335 dev->minor, DIO200_DRIVER_NAME);
1340 devpriv->intr_sd = -1;
1342 /* Enable device and reserve I/O spaces. */
1343 #ifdef CONFIG_COMEDI_PCI
1345 ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1348 "comedi%d: error! cannot enable PCI device and request regions!\n",
1352 iobase = pci_resource_start(pci_dev, 2);
1357 ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
1362 dev->iobase = iobase;
1364 layout = thislayout;
1365 if ((ret = alloc_subdevices(dev, layout->n_subdevs)) < 0) {
1366 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1371 for (n = 0; n < dev->n_subdevices; n++) {
1372 s = &dev->subdevices[n];
1373 switch (layout->sdtype[n]) {
1375 /* counter subdevice (8254) */
1376 ret = dio200_subdev_8254_init(dev, s, iobase,
1383 /* digital i/o subdevice (8255) */
1384 ret = subdev_8255_init(dev, s, 0,
1385 iobase + layout->sdinfo[n]);
1391 /* 'INTERRUPT' subdevice */
1393 ret = dio200_subdev_intr_init(dev, s,
1394 iobase + DIO200_INT_SCE,
1395 layout->sdinfo[n], layout->has_int_sce);
1399 devpriv->intr_sd = n;
1401 s->type = COMEDI_SUBD_UNUSED;
1405 s->type = COMEDI_SUBD_UNUSED;
1410 sdx = devpriv->intr_sd;
1411 if (sdx >= 0 && sdx < dev->n_subdevices) {
1412 dev->read_subdev = &dev->subdevices[sdx];
1415 dev->board_name = thisboard->name;
1418 unsigned long flags = share_irq ? IRQF_SHARED : 0;
1420 if (comedi_request_irq(irq, dio200_interrupt, flags,
1421 DIO200_DRIVER_NAME, dev) >= 0) {
1425 "comedi%d: warning! irq %u unavailable!\n",
1430 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1431 if (thisboard->bustype == isa_bustype) {
1432 printk("(base %#lx) ", iobase);
1434 #ifdef CONFIG_COMEDI_PCI
1435 printk("(pci %s) ", pci_name(pci_dev));
1439 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1441 printk("(no irq) ");
1444 printk("attached\n");
1450 * _detach is called to deconfigure a device. It should deallocate
1452 * This function is also called when _attach() fails, so it should be
1453 * careful not to release resources that were not necessarily
1454 * allocated by _attach(). dev->private and dev->subdevices are
1455 * deallocated automatically by the core.
1457 static int dio200_detach(comedi_device * dev)
1459 const dio200_layout *layout;
1462 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1463 DIO200_DRIVER_NAME);
1466 comedi_free_irq(dev->irq, dev);
1468 if (dev->subdevices) {
1469 layout = thislayout;
1470 for (n = 0; n < dev->n_subdevices; n++) {
1471 comedi_subdevice *s = &dev->subdevices[n];
1472 switch (layout->sdtype[n]) {
1474 dio200_subdev_8254_cleanup(dev, s);
1477 subdev_8255_cleanup(dev, s);
1480 dio200_subdev_intr_cleanup(dev, s);
1488 #ifdef CONFIG_COMEDI_PCI
1489 if (devpriv->pci_dev) {
1491 comedi_pci_disable(devpriv->pci_dev);
1493 pci_dev_put(devpriv->pci_dev);
1498 release_region(dev->iobase, DIO200_IO_SIZE);
1502 if (dev->board_name) {
1503 printk(KERN_INFO "comedi%d: %s removed\n",
1504 dev->minor, dev->board_name);