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 short value, one bit per requested channel, in the
205 order they appear in the channel list.
208 #include <linux/interrupt.h>
209 #include <linux/slab.h>
211 #include "../comedidev.h"
216 #define DIO200_DRIVER_NAME "amplc_dio200"
219 #define PCI_VENDOR_ID_AMPLICON 0x14dc
220 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
221 #define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
222 #define PCI_DEVICE_ID_INVALID 0xffff
224 /* 200 series registers */
225 #define DIO200_IO_SIZE 0x20
226 #define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */
227 #define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */
228 #define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */
229 #define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */
230 #define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
231 #define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
232 #define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
235 * Macros for constructing value for DIO_200_?CLK_SCE and
236 * DIO_200_?GAT_SCE registers:
238 * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
239 * 'chan' is the channel: 0, 1 or 2.
240 * 'source' is the signal source: 0 to 7.
242 #define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
243 #define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
246 * Periods of the internal clock sources in nanoseconds.
248 static const unsigned clock_period[8] = {
249 0, /* dedicated clock input/output pin */
256 0 /* group clock input pin */
260 * Board descriptions.
263 enum dio200_bustype { isa_bustype, pci_bustype };
268 pc215e_model, pci215_model,
270 pc272e_model, pci272_model,
275 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
280 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
286 struct dio200_board {
288 unsigned short devid;
289 enum dio200_bustype bustype;
290 enum dio200_model model;
291 enum dio200_layout layout;
294 static const struct dio200_board dio200_boards[] = {
295 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
298 .bustype = isa_bustype,
299 .model = pc212e_model,
300 .layout = pc212_layout,
304 .bustype = isa_bustype,
305 .model = pc214e_model,
306 .layout = pc214_layout,
310 .bustype = isa_bustype,
311 .model = pc215e_model,
312 .layout = pc215_layout,
316 .bustype = isa_bustype,
317 .model = pc218e_model,
318 .layout = pc218_layout,
322 .bustype = isa_bustype,
323 .model = pc272e_model,
324 .layout = pc272_layout,
327 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
330 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
331 .bustype = pci_bustype,
332 .model = pci215_model,
333 .layout = pc215_layout,
337 .devid = PCI_DEVICE_ID_AMPLICON_PCI272,
338 .bustype = pci_bustype,
339 .model = pci272_model,
340 .layout = pc272_layout,
343 .name = DIO200_DRIVER_NAME,
344 .devid = PCI_DEVICE_ID_INVALID,
345 .bustype = pci_bustype,
346 .model = anypci_model, /* wildcard */
352 * Layout descriptions - some ISA and PCI board descriptions share the same
356 enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
358 #define DIO200_MAX_SUBDEVS 7
359 #define DIO200_MAX_ISNS 6
361 struct dio200_layout_struct {
362 unsigned short n_subdevs; /* number of subdevices */
363 unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
364 unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
365 char has_int_sce; /* has interrupt enable/status register */
366 char has_clk_gat_sce; /* has clock/gate selection registers */
369 static const struct dio200_layout_struct dio200_layouts[] = {
370 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
373 .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
376 .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14,
379 .has_clk_gat_sce = 1,
383 .sdtype = {sd_8255, sd_8255, sd_8254,
385 .sdinfo = {0x00, 0x08, 0x10, 0x01},
387 .has_clk_gat_sce = 0,
392 .sdtype = {sd_8255, sd_8255, sd_8254,
395 .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
397 .has_clk_gat_sce = 1,
399 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
402 .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
405 .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10,
409 .has_clk_gat_sce = 1,
414 .sdtype = {sd_8255, sd_8255, sd_8255,
416 .sdinfo = {0x00, 0x08, 0x10, 0x3F},
418 .has_clk_gat_sce = 0,
422 /* this structure is for data unique to this hardware driver. If
423 several hardware drivers keep similar information in this structure,
424 feel free to suggest moving the variable to the struct comedi_device struct.
426 struct dio200_private {
430 struct dio200_subdev_8254 {
431 unsigned long iobase; /* Counter base address */
432 unsigned long clk_sce_iobase; /* CLK_SCE base address */
433 unsigned long gat_sce_iobase; /* GAT_SCE base address */
434 int which; /* Bit 5 of CLK_SCE or GAT_SCE */
436 unsigned clock_src[3]; /* Current clock sources */
437 unsigned gate_src[3]; /* Current gate sources */
441 struct dio200_subdev_intr {
442 unsigned long iobase;
446 unsigned int valid_isns;
447 unsigned int enabled_isns;
448 unsigned int stopcount;
453 * This function looks for a board matching the supplied PCI device.
455 static const struct dio200_board *
456 dio200_find_pci_board(struct pci_dev *pci_dev)
460 for (i = 0; i < ARRAY_SIZE(dio200_boards); i++)
461 if (dio200_boards[i].bustype == pci_bustype &&
462 pci_dev->device == dio200_boards[i].devid)
463 return &dio200_boards[i];
468 * This function looks for a PCI device matching the requested board name,
471 static struct pci_dev *dio200_find_pci_dev(struct comedi_device *dev,
472 struct comedi_devconfig *it)
474 const struct dio200_board *thisboard = comedi_board(dev);
475 struct pci_dev *pci_dev = NULL;
476 int bus = it->options[0];
477 int slot = it->options[1];
479 for_each_pci_dev(pci_dev) {
481 if (bus != pci_dev->bus->number ||
482 slot != PCI_SLOT(pci_dev->devfn))
485 if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
488 if (thisboard->model == anypci_model) {
489 /* Wildcard board matches any supported PCI board. */
490 const struct dio200_board *foundboard;
492 foundboard = dio200_find_pci_board(pci_dev);
493 if (foundboard == NULL)
495 /* Replace wildcard board_ptr. */
496 dev->board_ptr = foundboard;
498 /* Match specific model name. */
499 if (pci_dev->device != thisboard->devid)
504 dev_err(dev->class_dev,
505 "No supported board found! (req. bus %d, slot %d)\n",
511 * This function checks and requests an I/O region, reporting an error
512 * if there is a conflict.
515 dio200_request_region(struct comedi_device *dev,
516 unsigned long from, unsigned long extent)
518 if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
519 dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
527 * 'insn_bits' function for an 'INTERRUPT' subdevice.
530 dio200_subdev_intr_insn_bits(struct comedi_device *dev,
531 struct comedi_subdevice *s,
532 struct comedi_insn *insn, unsigned int *data)
534 struct dio200_subdev_intr *subpriv = s->private;
536 if (subpriv->has_int_sce) {
537 /* Just read the interrupt status register. */
538 data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
540 /* No interrupt status register. */
548 * Called to stop acquisition for an 'INTERRUPT' subdevice.
550 static void dio200_stop_intr(struct comedi_device *dev,
551 struct comedi_subdevice *s)
553 struct dio200_subdev_intr *subpriv = s->private;
556 subpriv->enabled_isns = 0;
557 if (subpriv->has_int_sce)
558 outb(0, subpriv->iobase);
562 * Called to start acquisition for an 'INTERRUPT' subdevice.
564 static int dio200_start_intr(struct comedi_device *dev,
565 struct comedi_subdevice *s)
569 struct dio200_subdev_intr *subpriv = s->private;
570 struct comedi_cmd *cmd = &s->async->cmd;
573 if (!subpriv->continuous && subpriv->stopcount == 0) {
574 /* An empty acquisition! */
575 s->async->events |= COMEDI_CB_EOA;
579 /* Determine interrupt sources to enable. */
582 for (n = 0; n < cmd->chanlist_len; n++)
583 isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
585 isn_bits &= subpriv->valid_isns;
586 /* Enable interrupt sources. */
587 subpriv->enabled_isns = isn_bits;
588 if (subpriv->has_int_sce)
589 outb(isn_bits, subpriv->iobase);
596 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
599 dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
600 unsigned int trignum)
602 struct dio200_subdev_intr *subpriv;
609 subpriv = s->private;
611 spin_lock_irqsave(&subpriv->spinlock, flags);
612 s->async->inttrig = NULL;
614 event = dio200_start_intr(dev, s);
616 spin_unlock_irqrestore(&subpriv->spinlock, flags);
619 comedi_event(dev, s);
625 * This is called from the interrupt service routine to handle a read
626 * scan on an 'INTERRUPT' subdevice.
628 static int dio200_handle_read_intr(struct comedi_device *dev,
629 struct comedi_subdevice *s)
631 struct dio200_subdev_intr *subpriv = s->private;
634 unsigned cur_enabled;
635 unsigned int oldevents;
640 spin_lock_irqsave(&subpriv->spinlock, flags);
641 oldevents = s->async->events;
642 if (subpriv->has_int_sce) {
644 * Collect interrupt sources that have triggered and disable
645 * them temporarily. Loop around until no extra interrupt
646 * sources have triggered, at which point, the valid part of
647 * the interrupt status register will read zero, clearing the
648 * cause of the interrupt.
650 * Mask off interrupt sources already seen to avoid infinite
651 * loop in case of misconfiguration.
653 cur_enabled = subpriv->enabled_isns;
654 while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
655 & ~triggered)) != 0) {
656 triggered |= intstat;
657 cur_enabled &= ~triggered;
658 outb(cur_enabled, subpriv->iobase);
662 * No interrupt status register. Assume the single interrupt
663 * source has triggered.
665 triggered = subpriv->enabled_isns;
670 * Some interrupt sources have triggered and have been
671 * temporarily disabled to clear the cause of the interrupt.
673 * Reenable them NOW to minimize the time they are disabled.
675 cur_enabled = subpriv->enabled_isns;
676 if (subpriv->has_int_sce)
677 outb(cur_enabled, subpriv->iobase);
679 if (subpriv->active) {
681 * The command is still active.
683 * Ignore interrupt sources that the command isn't
684 * interested in (just in case there's a race
687 if (triggered & subpriv->enabled_isns) {
688 /* Collect scan data. */
690 unsigned int n, ch, len;
693 len = s->async->cmd.chanlist_len;
694 for (n = 0; n < len; n++) {
695 ch = CR_CHAN(s->async->cmd.chanlist[n]);
696 if (triggered & (1U << ch))
699 /* Write the scan to the buffer. */
700 if (comedi_buf_put(s->async, val)) {
701 s->async->events |= (COMEDI_CB_BLOCK |
704 /* Error! Stop acquisition. */
705 dio200_stop_intr(dev, s);
706 s->async->events |= COMEDI_CB_ERROR
707 | COMEDI_CB_OVERFLOW;
708 comedi_error(dev, "buffer overflow");
711 /* Check for end of acquisition. */
712 if (!subpriv->continuous) {
713 /* stop_src == TRIG_COUNT */
714 if (subpriv->stopcount > 0) {
715 subpriv->stopcount--;
716 if (subpriv->stopcount == 0) {
719 dio200_stop_intr(dev,
727 spin_unlock_irqrestore(&subpriv->spinlock, flags);
729 if (oldevents != s->async->events)
730 comedi_event(dev, s);
732 return (triggered != 0);
736 * 'cancel' function for an 'INTERRUPT' subdevice.
738 static int dio200_subdev_intr_cancel(struct comedi_device *dev,
739 struct comedi_subdevice *s)
741 struct dio200_subdev_intr *subpriv = s->private;
744 spin_lock_irqsave(&subpriv->spinlock, flags);
746 dio200_stop_intr(dev, s);
748 spin_unlock_irqrestore(&subpriv->spinlock, flags);
754 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
757 dio200_subdev_intr_cmdtest(struct comedi_device *dev,
758 struct comedi_subdevice *s, struct comedi_cmd *cmd)
763 /* step 1: make sure trigger sources are trivially valid */
765 tmp = cmd->start_src;
766 cmd->start_src &= (TRIG_NOW | TRIG_INT);
767 if (!cmd->start_src || tmp != cmd->start_src)
770 tmp = cmd->scan_begin_src;
771 cmd->scan_begin_src &= TRIG_EXT;
772 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
775 tmp = cmd->convert_src;
776 cmd->convert_src &= TRIG_NOW;
777 if (!cmd->convert_src || tmp != cmd->convert_src)
780 tmp = cmd->scan_end_src;
781 cmd->scan_end_src &= TRIG_COUNT;
782 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
786 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
787 if (!cmd->stop_src || tmp != cmd->stop_src)
793 /* step 2: make sure trigger sources are unique and mutually
796 /* these tests are true if more than one _src bit is set */
797 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
799 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
801 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
803 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
805 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
811 /* step 3: make sure arguments are trivially compatible */
813 /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
814 if (cmd->start_arg != 0) {
819 /* cmd->scan_begin_src == TRIG_EXT */
820 if (cmd->scan_begin_arg != 0) {
821 cmd->scan_begin_arg = 0;
825 /* cmd->convert_src == TRIG_NOW */
826 if (cmd->convert_arg != 0) {
827 cmd->convert_arg = 0;
831 /* cmd->scan_end_src == TRIG_COUNT */
832 if (cmd->scan_end_arg != cmd->chanlist_len) {
833 cmd->scan_end_arg = cmd->chanlist_len;
837 switch (cmd->stop_src) {
839 /* any count allowed */
842 if (cmd->stop_arg != 0) {
854 /* step 4: fix up any arguments */
856 /* if (err) return 4; */
862 * 'do_cmd' function for an 'INTERRUPT' subdevice.
864 static int dio200_subdev_intr_cmd(struct comedi_device *dev,
865 struct comedi_subdevice *s)
867 struct comedi_cmd *cmd = &s->async->cmd;
868 struct dio200_subdev_intr *subpriv = s->private;
872 spin_lock_irqsave(&subpriv->spinlock, flags);
875 /* Set up end of acquisition. */
876 switch (cmd->stop_src) {
878 subpriv->continuous = 0;
879 subpriv->stopcount = cmd->stop_arg;
883 subpriv->continuous = 1;
884 subpriv->stopcount = 0;
888 /* Set up start of acquisition. */
889 switch (cmd->start_src) {
891 s->async->inttrig = dio200_inttrig_start_intr;
895 event = dio200_start_intr(dev, s);
898 spin_unlock_irqrestore(&subpriv->spinlock, flags);
901 comedi_event(dev, s);
907 * This function initializes an 'INTERRUPT' subdevice.
910 dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
911 unsigned long iobase, unsigned valid_isns,
914 struct dio200_subdev_intr *subpriv;
916 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
918 dev_err(dev->class_dev, "error! out of memory!\n");
921 subpriv->iobase = iobase;
922 subpriv->has_int_sce = has_int_sce;
923 subpriv->valid_isns = valid_isns;
924 spin_lock_init(&subpriv->spinlock);
927 outb(0, subpriv->iobase); /* Disable interrupt sources. */
929 s->private = subpriv;
930 s->type = COMEDI_SUBD_DI;
931 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
933 s->n_chan = DIO200_MAX_ISNS;
934 s->len_chanlist = DIO200_MAX_ISNS;
936 /* No interrupt source register. Support single channel. */
940 s->range_table = &range_digital;
942 s->insn_bits = dio200_subdev_intr_insn_bits;
943 s->do_cmdtest = dio200_subdev_intr_cmdtest;
944 s->do_cmd = dio200_subdev_intr_cmd;
945 s->cancel = dio200_subdev_intr_cancel;
951 * This function cleans up an 'INTERRUPT' subdevice.
954 dio200_subdev_intr_cleanup(struct comedi_device *dev,
955 struct comedi_subdevice *s)
957 struct dio200_subdev_intr *subpriv = s->private;
962 * Interrupt service routine.
964 static irqreturn_t dio200_interrupt(int irq, void *d)
966 struct comedi_device *dev = d;
967 struct dio200_private *devpriv = dev->private;
973 if (devpriv->intr_sd >= 0) {
974 handled = dio200_handle_read_intr(dev,
981 return IRQ_RETVAL(handled);
985 * Handle 'insn_read' for an '8254' counter subdevice.
988 dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
989 struct comedi_insn *insn, unsigned int *data)
991 struct dio200_subdev_8254 *subpriv = s->private;
992 int chan = CR_CHAN(insn->chanspec);
995 spin_lock_irqsave(&subpriv->spinlock, flags);
996 data[0] = i8254_read(subpriv->iobase, 0, chan);
997 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1003 * Handle 'insn_write' for an '8254' counter subdevice.
1006 dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1007 struct comedi_insn *insn, unsigned int *data)
1009 struct dio200_subdev_8254 *subpriv = s->private;
1010 int chan = CR_CHAN(insn->chanspec);
1011 unsigned long flags;
1013 spin_lock_irqsave(&subpriv->spinlock, flags);
1014 i8254_write(subpriv->iobase, 0, chan, data[0]);
1015 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1021 * Set gate source for an '8254' counter subdevice channel.
1024 dio200_set_gate_src(struct dio200_subdev_8254 *subpriv,
1025 unsigned int counter_number, unsigned int gate_src)
1029 if (!subpriv->has_clk_gat_sce)
1031 if (counter_number > 2)
1036 subpriv->gate_src[counter_number] = gate_src;
1037 byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1038 outb(byte, subpriv->gat_sce_iobase);
1044 * Get gate source for an '8254' counter subdevice channel.
1047 dio200_get_gate_src(struct dio200_subdev_8254 *subpriv,
1048 unsigned int counter_number)
1050 if (!subpriv->has_clk_gat_sce)
1052 if (counter_number > 2)
1055 return subpriv->gate_src[counter_number];
1059 * Set clock source for an '8254' counter subdevice channel.
1062 dio200_set_clock_src(struct dio200_subdev_8254 *subpriv,
1063 unsigned int counter_number, unsigned int clock_src)
1067 if (!subpriv->has_clk_gat_sce)
1069 if (counter_number > 2)
1074 subpriv->clock_src[counter_number] = clock_src;
1075 byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1076 outb(byte, subpriv->clk_sce_iobase);
1082 * Get clock source for an '8254' counter subdevice channel.
1085 dio200_get_clock_src(struct dio200_subdev_8254 *subpriv,
1086 unsigned int counter_number, unsigned int *period_ns)
1090 if (!subpriv->has_clk_gat_sce)
1092 if (counter_number > 2)
1095 clock_src = subpriv->clock_src[counter_number];
1096 *period_ns = clock_period[clock_src];
1101 * Handle 'insn_config' for an '8254' counter subdevice.
1104 dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1105 struct comedi_insn *insn, unsigned int *data)
1107 struct dio200_subdev_8254 *subpriv = s->private;
1109 int chan = CR_CHAN(insn->chanspec);
1110 unsigned long flags;
1112 spin_lock_irqsave(&subpriv->spinlock, flags);
1114 case INSN_CONFIG_SET_COUNTER_MODE:
1115 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1119 case INSN_CONFIG_8254_READ_STATUS:
1120 data[1] = i8254_status(subpriv->iobase, 0, chan);
1122 case INSN_CONFIG_SET_GATE_SRC:
1123 ret = dio200_set_gate_src(subpriv, chan, data[2]);
1127 case INSN_CONFIG_GET_GATE_SRC:
1128 ret = dio200_get_gate_src(subpriv, chan);
1135 case INSN_CONFIG_SET_CLOCK_SRC:
1136 ret = dio200_set_clock_src(subpriv, chan, data[1]);
1140 case INSN_CONFIG_GET_CLOCK_SRC:
1141 ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1152 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1153 return ret < 0 ? ret : insn->n;
1157 * This function initializes an '8254' counter subdevice.
1159 * Note: iobase is the base address of the board, not the subdevice;
1160 * offset is the offset to the 8254 chip.
1163 dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1164 unsigned long iobase, unsigned offset,
1165 int has_clk_gat_sce)
1167 struct dio200_subdev_8254 *subpriv;
1170 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1172 dev_err(dev->class_dev, "error! out of memory!\n");
1176 s->private = subpriv;
1177 s->type = COMEDI_SUBD_COUNTER;
1178 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1180 s->maxdata = 0xFFFF;
1181 s->insn_read = dio200_subdev_8254_read;
1182 s->insn_write = dio200_subdev_8254_write;
1183 s->insn_config = dio200_subdev_8254_config;
1185 spin_lock_init(&subpriv->spinlock);
1186 subpriv->iobase = offset + iobase;
1187 subpriv->has_clk_gat_sce = has_clk_gat_sce;
1188 if (has_clk_gat_sce) {
1189 /* Derive CLK_SCE and GAT_SCE register offsets from
1191 subpriv->clk_sce_iobase =
1192 DIO200_XCLK_SCE + (offset >> 3) + iobase;
1193 subpriv->gat_sce_iobase =
1194 DIO200_XGAT_SCE + (offset >> 3) + iobase;
1195 subpriv->which = (offset >> 2) & 1;
1198 /* Initialize channels. */
1199 for (chan = 0; chan < 3; chan++) {
1200 i8254_set_mode(subpriv->iobase, 0, chan,
1201 I8254_MODE0 | I8254_BINARY);
1202 if (subpriv->has_clk_gat_sce) {
1203 /* Gate source 0 is VCC (logic 1). */
1204 dio200_set_gate_src(subpriv, chan, 0);
1205 /* Clock source 0 is the dedicated clock input. */
1206 dio200_set_clock_src(subpriv, chan, 0);
1214 * This function cleans up an '8254' counter subdevice.
1217 dio200_subdev_8254_cleanup(struct comedi_device *dev,
1218 struct comedi_subdevice *s)
1220 struct dio200_subdev_intr *subpriv = s->private;
1224 static void dio200_report_attach(struct comedi_device *dev, unsigned int irq)
1226 const struct dio200_board *thisboard = comedi_board(dev);
1227 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1231 if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
1232 thisboard->bustype == isa_bustype)
1233 tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
1234 "(base %#lx) ", dev->iobase);
1235 else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
1236 thisboard->bustype == pci_bustype)
1237 tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
1238 "(pci %s) ", pci_name(pcidev));
1242 tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
1244 (dev->irq ? "" : " UNAVAILABLE"));
1246 tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
1248 dev_info(dev->class_dev, "%s %sattached\n", dev->board_name, tmpbuf);
1251 static int dio200_common_attach(struct comedi_device *dev, unsigned long iobase,
1252 unsigned int irq, unsigned long req_irq_flags)
1254 const struct dio200_board *thisboard = comedi_board(dev);
1255 struct dio200_private *devpriv = dev->private;
1256 const struct dio200_layout_struct *layout =
1257 &dio200_layouts[thisboard->layout];
1258 struct comedi_subdevice *s;
1263 devpriv->intr_sd = -1;
1264 dev->iobase = iobase;
1265 dev->board_name = thisboard->name;
1267 ret = comedi_alloc_subdevices(dev, layout->n_subdevs);
1271 for (n = 0; n < dev->n_subdevices; n++) {
1272 s = &dev->subdevices[n];
1273 switch (layout->sdtype[n]) {
1275 /* counter subdevice (8254) */
1276 ret = dio200_subdev_8254_init(dev, s, iobase,
1278 layout->has_clk_gat_sce);
1283 /* digital i/o subdevice (8255) */
1284 ret = subdev_8255_init(dev, s, NULL,
1285 iobase + layout->sdinfo[n]);
1290 /* 'INTERRUPT' subdevice */
1292 ret = dio200_subdev_intr_init(dev, s,
1300 devpriv->intr_sd = n;
1302 s->type = COMEDI_SUBD_UNUSED;
1306 s->type = COMEDI_SUBD_UNUSED;
1310 sdx = devpriv->intr_sd;
1311 if (sdx >= 0 && sdx < dev->n_subdevices)
1312 dev->read_subdev = &dev->subdevices[sdx];
1314 if (request_irq(irq, dio200_interrupt, req_irq_flags,
1315 DIO200_DRIVER_NAME, dev) >= 0) {
1318 dev_warn(dev->class_dev,
1319 "warning! irq %u unavailable!\n", irq);
1322 dio200_report_attach(dev, irq);
1326 static int dio200_pci_common_attach(struct comedi_device *dev,
1327 struct pci_dev *pci_dev)
1329 unsigned long iobase;
1332 comedi_set_hw_dev(dev, &pci_dev->dev);
1334 ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1336 dev_err(dev->class_dev,
1337 "error! cannot enable PCI device and request regions!\n");
1340 iobase = pci_resource_start(pci_dev, 2);
1341 return dio200_common_attach(dev, iobase, pci_dev->irq, IRQF_SHARED);
1345 * Attach is called by the Comedi core to configure the driver
1346 * for a particular board. If you specified a board_name array
1347 * in the driver structure, dev->board_ptr contains that
1350 static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1352 const struct dio200_board *thisboard = comedi_board(dev);
1355 dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach\n");
1357 ret = alloc_private(dev, sizeof(struct dio200_private));
1359 dev_err(dev->class_dev, "error! out of memory!\n");
1363 /* Process options and reserve resources according to bus type. */
1364 if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
1365 thisboard->bustype == isa_bustype) {
1366 unsigned long iobase;
1369 iobase = it->options[0];
1370 irq = it->options[1];
1371 ret = dio200_request_region(dev, iobase, DIO200_IO_SIZE);
1374 return dio200_common_attach(dev, iobase, irq, 0);
1375 } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
1376 thisboard->bustype == pci_bustype) {
1377 struct pci_dev *pci_dev;
1379 pci_dev = dio200_find_pci_dev(dev, it);
1382 return dio200_pci_common_attach(dev, pci_dev);
1384 dev_err(dev->class_dev, DIO200_DRIVER_NAME
1385 ": BUG! cannot determine board type!\n");
1391 * The attach_pci hook (if non-NULL) is called at PCI probe time in preference
1392 * to the "manual" attach hook. dev->board_ptr is NULL on entry. There should
1393 * be a board entry matching the supplied PCI device.
1395 static int __devinit dio200_attach_pci(struct comedi_device *dev,
1396 struct pci_dev *pci_dev)
1400 if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI))
1403 dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach pci %s\n",
1405 ret = alloc_private(dev, sizeof(struct dio200_private));
1407 dev_err(dev->class_dev, "error! out of memory!\n");
1410 dev->board_ptr = dio200_find_pci_board(pci_dev);
1411 if (dev->board_ptr == NULL) {
1412 dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
1415 return dio200_pci_common_attach(dev, pci_dev);
1418 static void dio200_detach(struct comedi_device *dev)
1420 const struct dio200_board *thisboard = comedi_board(dev);
1421 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1422 const struct dio200_layout_struct *layout;
1426 free_irq(dev->irq, dev);
1427 if (dev->subdevices) {
1428 layout = &dio200_layouts[thisboard->layout];
1429 for (n = 0; n < dev->n_subdevices; n++) {
1430 struct comedi_subdevice *s = &dev->subdevices[n];
1431 switch (layout->sdtype[n]) {
1433 dio200_subdev_8254_cleanup(dev, s);
1436 subdev_8255_cleanup(dev, s);
1439 dio200_subdev_intr_cleanup(dev, s);
1448 comedi_pci_disable(pcidev);
1449 pci_dev_put(pcidev);
1452 release_region(dev->iobase, DIO200_IO_SIZE);
1457 * The struct comedi_driver structure tells the Comedi core module
1458 * which functions to call to configure/deconfigure (attach/detach)
1459 * the board, and also about the kernel module that contains
1462 static struct comedi_driver amplc_dio200_driver = {
1463 .driver_name = DIO200_DRIVER_NAME,
1464 .module = THIS_MODULE,
1465 .attach = dio200_attach,
1466 .attach_pci = dio200_attach_pci,
1467 .detach = dio200_detach,
1468 .board_name = &dio200_boards[0].name,
1469 .offset = sizeof(struct dio200_board),
1470 .num_names = ARRAY_SIZE(dio200_boards),
1473 #if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
1474 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
1475 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
1476 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
1480 MODULE_DEVICE_TABLE(pci, dio200_pci_table);
1482 static int __devinit amplc_dio200_pci_probe(struct pci_dev *dev,
1483 const struct pci_device_id
1486 return comedi_pci_auto_config(dev, &lc_dio200_driver);
1489 static void __devexit amplc_dio200_pci_remove(struct pci_dev *dev)
1491 comedi_pci_auto_unconfig(dev);
1494 static struct pci_driver amplc_dio200_pci_driver = {
1495 .name = DIO200_DRIVER_NAME,
1496 .id_table = dio200_pci_table,
1497 .probe = &lc_dio200_pci_probe,
1498 .remove = __devexit_p(&lc_dio200_pci_remove)
1500 module_comedi_pci_driver(amplc_dio200_driver, amplc_dio200_pci_driver);
1502 module_comedi_driver(amplc_dio200_driver);
1505 MODULE_AUTHOR("Comedi http://www.comedi.org");
1506 MODULE_DESCRIPTION("Comedi low-level driver");
1507 MODULE_LICENSE("GPL");