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>
210 #include "../comedidev.h"
212 #include "comedi_pci.h"
217 #define DIO200_DRIVER_NAME "amplc_dio200"
220 /* #define PCI_VENDOR_ID_AMPLICON 0x14dc */
221 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
222 #define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
223 #define PCI_DEVICE_ID_INVALID 0xffff
225 /* 200 series registers */
226 #define DIO200_IO_SIZE 0x20
227 #define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */
228 #define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */
229 #define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */
230 #define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */
231 #define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
232 #define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
233 #define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
236 * Macros for constructing value for DIO_200_?CLK_SCE and
237 * DIO_200_?GAT_SCE registers:
239 * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
240 * 'chan' is the channel: 0, 1 or 2.
241 * 'source' is the signal source: 0 to 7.
243 #define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
244 #define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
247 * Periods of the internal clock sources in nanoseconds.
249 static const unsigned clock_period[8] = {
250 0, /* dedicated clock input/output pin */
257 0 /* group clock input pin */
261 * Board descriptions.
264 enum dio200_bustype { isa_bustype, pci_bustype };
269 pc215e_model, pci215_model,
271 pc272e_model, pci272_model,
283 struct dio200_board {
285 unsigned short devid;
286 enum dio200_bustype bustype;
287 enum dio200_model model;
288 enum dio200_layout layout;
291 static const struct dio200_board dio200_boards[] = {
294 .bustype = isa_bustype,
295 .model = pc212e_model,
296 .layout = pc212_layout,
300 .bustype = isa_bustype,
301 .model = pc214e_model,
302 .layout = pc214_layout,
306 .bustype = isa_bustype,
307 .model = pc215e_model,
308 .layout = pc215_layout,
310 #ifdef CONFIG_COMEDI_PCI
313 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
314 .bustype = pci_bustype,
315 .model = pci215_model,
316 .layout = pc215_layout,
321 .bustype = isa_bustype,
322 .model = pc218e_model,
323 .layout = pc218_layout,
327 .bustype = isa_bustype,
328 .model = pc272e_model,
329 .layout = pc272_layout,
331 #ifdef CONFIG_COMEDI_PCI
334 .devid = PCI_DEVICE_ID_AMPLICON_PCI272,
335 .bustype = pci_bustype,
336 .model = pci272_model,
337 .layout = pc272_layout,
340 #ifdef CONFIG_COMEDI_PCI
342 .name = DIO200_DRIVER_NAME,
343 .devid = PCI_DEVICE_ID_INVALID,
344 .bustype = pci_bustype,
345 .model = anypci_model, /* wildcard */
351 * Layout descriptions - some ISA and PCI board descriptions share the same
355 enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
357 #define DIO200_MAX_SUBDEVS 7
358 #define DIO200_MAX_ISNS 6
360 struct dio200_layout_struct {
361 unsigned short n_subdevs; /* number of subdevices */
362 unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
363 unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
364 char has_int_sce; /* has interrupt enable/status register */
365 char has_clk_gat_sce; /* has clock/gate selection registers */
368 static const struct dio200_layout_struct dio200_layouts[] = {
371 .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
374 .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14,
377 .has_clk_gat_sce = 1,
381 .sdtype = {sd_8255, sd_8255, sd_8254,
383 .sdinfo = {0x00, 0x08, 0x10, 0x01},
385 .has_clk_gat_sce = 0,
389 .sdtype = {sd_8255, sd_8255, sd_8254,
392 .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
394 .has_clk_gat_sce = 1,
398 .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
401 .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10,
405 .has_clk_gat_sce = 1,
409 .sdtype = {sd_8255, sd_8255, sd_8255,
411 .sdinfo = {0x00, 0x08, 0x10, 0x3F},
413 .has_clk_gat_sce = 0,
421 #ifdef CONFIG_COMEDI_PCI
422 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
424 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
425 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
426 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
427 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
431 MODULE_DEVICE_TABLE(pci, dio200_pci_table);
432 #endif /* CONFIG_COMEDI_PCI */
435 * Useful for shorthand access to the particular board structure
437 #define thisboard ((const struct dio200_board *)dev->board_ptr)
438 #define thislayout (&dio200_layouts[((struct dio200_board *)dev->board_ptr)->layout])
440 /* this structure is for data unique to this hardware driver. If
441 several hardware drivers keep similar information in this structure,
442 feel free to suggest moving the variable to the struct comedi_device struct. */
443 struct dio200_private {
444 #ifdef CONFIG_COMEDI_PCI
445 struct pci_dev *pci_dev; /* PCI device */
450 #define devpriv ((struct dio200_private *)dev->private)
452 struct dio200_subdev_8254 {
453 unsigned long iobase; /* Counter base address */
454 unsigned long clk_sce_iobase; /* CLK_SCE base address */
455 unsigned long gat_sce_iobase; /* GAT_SCE base address */
456 int which; /* Bit 5 of CLK_SCE or GAT_SCE */
458 unsigned clock_src[3]; /* Current clock sources */
459 unsigned gate_src[3]; /* Current gate sources */
462 struct dio200_subdev_intr {
463 unsigned long iobase;
467 unsigned int valid_isns;
468 unsigned int enabled_isns;
469 unsigned int stopcount;
474 * The struct comedi_driver structure tells the Comedi core module
475 * which functions to call to configure/deconfigure (attach/detach)
476 * the board, and also about the kernel module that contains
479 static int dio200_attach(struct comedi_device *dev,
480 struct comedi_devconfig *it);
481 static int dio200_detach(struct comedi_device *dev);
482 static struct comedi_driver driver_amplc_dio200 = {
483 .driver_name = DIO200_DRIVER_NAME,
484 .module = THIS_MODULE,
485 .attach = dio200_attach,
486 .detach = dio200_detach,
487 .board_name = &dio200_boards[0].name,
488 .offset = sizeof(struct dio200_board),
489 .num_names = ARRAY_SIZE(dio200_boards),
492 #ifdef CONFIG_COMEDI_PCI
493 COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
495 COMEDI_INITCLEANUP(driver_amplc_dio200);
499 * This function looks for a PCI device matching the requested board name,
502 #ifdef CONFIG_COMEDI_PCI
504 dio200_find_pci(struct comedi_device *dev, int bus, int slot,
505 struct pci_dev **pci_dev_p)
507 struct pci_dev *pci_dev = NULL;
511 /* Look for matching PCI device. */
512 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
514 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
515 PCI_ANY_ID, pci_dev)) {
516 /* If bus/slot specified, check them. */
518 if (bus != pci_dev->bus->number
519 || slot != PCI_SLOT(pci_dev->devfn))
522 if (thisboard->model == anypci_model) {
523 /* Match any supported model. */
526 for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
527 if (dio200_boards[i].bustype != pci_bustype)
529 if (pci_dev->device == dio200_boards[i].devid) {
530 /* Change board_ptr to matched board. */
531 dev->board_ptr = &dio200_boards[i];
535 if (i == ARRAY_SIZE(dio200_boards))
538 /* Match specific model name. */
539 if (pci_dev->device != thisboard->devid)
544 *pci_dev_p = pci_dev;
547 /* No match found. */
550 "comedi%d: error! no %s found at pci %02x:%02x!\n",
551 dev->minor, thisboard->name, bus, slot);
553 printk(KERN_ERR "comedi%d: error! no %s found!\n",
554 dev->minor, thisboard->name);
561 * This function checks and requests an I/O region, reporting an error
562 * if there is a conflict.
565 dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
567 if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
568 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
569 minor, from, extent);
576 * 'insn_bits' function for an 'INTERRUPT' subdevice.
579 dio200_subdev_intr_insn_bits(struct comedi_device *dev,
580 struct comedi_subdevice *s,
581 struct comedi_insn *insn, unsigned int *data)
583 struct dio200_subdev_intr *subpriv = s->private;
585 if (subpriv->has_int_sce) {
586 /* Just read the interrupt status register. */
587 data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
589 /* No interrupt status register. */
597 * Called to stop acquisition for an 'INTERRUPT' subdevice.
599 static void dio200_stop_intr(struct comedi_device *dev,
600 struct comedi_subdevice *s)
602 struct dio200_subdev_intr *subpriv = s->private;
605 subpriv->enabled_isns = 0;
606 if (subpriv->has_int_sce) {
607 outb(0, subpriv->iobase);
612 * Called to start acquisition for an 'INTERRUPT' subdevice.
614 static int dio200_start_intr(struct comedi_device *dev,
615 struct comedi_subdevice *s)
619 struct dio200_subdev_intr *subpriv = s->private;
620 struct comedi_cmd *cmd = &s->async->cmd;
623 if (!subpriv->continuous && subpriv->stopcount == 0) {
624 /* An empty acquisition! */
625 s->async->events |= COMEDI_CB_EOA;
629 /* Determine interrupt sources to enable. */
632 for (n = 0; n < cmd->chanlist_len; n++) {
633 isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
636 isn_bits &= subpriv->valid_isns;
637 /* Enable interrupt sources. */
638 subpriv->enabled_isns = isn_bits;
639 if (subpriv->has_int_sce) {
640 outb(isn_bits, subpriv->iobase);
648 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
651 dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
652 unsigned int trignum)
654 struct dio200_subdev_intr *subpriv;
661 subpriv = s->private;
663 spin_lock_irqsave(&subpriv->spinlock, flags);
664 s->async->inttrig = 0;
665 if (subpriv->active) {
666 event = dio200_start_intr(dev, s);
668 spin_unlock_irqrestore(&subpriv->spinlock, flags);
671 comedi_event(dev, s);
678 * This is called from the interrupt service routine to handle a read
679 * scan on an 'INTERRUPT' subdevice.
681 static int dio200_handle_read_intr(struct comedi_device *dev,
682 struct comedi_subdevice *s)
684 struct dio200_subdev_intr *subpriv = s->private;
687 unsigned cur_enabled;
688 unsigned int oldevents;
693 spin_lock_irqsave(&subpriv->spinlock, flags);
694 oldevents = s->async->events;
695 if (subpriv->has_int_sce) {
697 * Collect interrupt sources that have triggered and disable
698 * them temporarily. Loop around until no extra interrupt
699 * sources have triggered, at which point, the valid part of
700 * the interrupt status register will read zero, clearing the
701 * cause of the interrupt.
703 * Mask off interrupt sources already seen to avoid infinite
704 * loop in case of misconfiguration.
706 cur_enabled = subpriv->enabled_isns;
707 while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
708 & ~triggered)) != 0) {
709 triggered |= intstat;
710 cur_enabled &= ~triggered;
711 outb(cur_enabled, subpriv->iobase);
715 * No interrupt status register. Assume the single interrupt
716 * source has triggered.
718 triggered = subpriv->enabled_isns;
723 * Some interrupt sources have triggered and have been
724 * temporarily disabled to clear the cause of the interrupt.
726 * Reenable them NOW to minimize the time they are disabled.
728 cur_enabled = subpriv->enabled_isns;
729 if (subpriv->has_int_sce) {
730 outb(cur_enabled, subpriv->iobase);
733 if (subpriv->active) {
735 * The command is still active.
737 * Ignore interrupt sources that the command isn't
738 * interested in (just in case there's a race
741 if (triggered & subpriv->enabled_isns) {
742 /* Collect scan data. */
744 unsigned int n, ch, len;
747 len = s->async->cmd.chanlist_len;
748 for (n = 0; n < len; n++) {
749 ch = CR_CHAN(s->async->cmd.chanlist[n]);
750 if (triggered & (1U << ch)) {
754 /* Write the scan to the buffer. */
755 if (comedi_buf_put(s->async, val)) {
756 s->async->events |= (COMEDI_CB_BLOCK |
759 /* Error! Stop acquisition. */
760 dio200_stop_intr(dev, s);
761 s->async->events |= COMEDI_CB_ERROR
762 | COMEDI_CB_OVERFLOW;
763 comedi_error(dev, "buffer overflow");
766 /* Check for end of acquisition. */
767 if (!subpriv->continuous) {
768 /* stop_src == TRIG_COUNT */
769 if (subpriv->stopcount > 0) {
770 subpriv->stopcount--;
771 if (subpriv->stopcount == 0) {
774 dio200_stop_intr(dev,
782 spin_unlock_irqrestore(&subpriv->spinlock, flags);
784 if (oldevents != s->async->events) {
785 comedi_event(dev, s);
788 return (triggered != 0);
792 * 'cancel' function for an 'INTERRUPT' subdevice.
794 static int dio200_subdev_intr_cancel(struct comedi_device *dev,
795 struct comedi_subdevice *s)
797 struct dio200_subdev_intr *subpriv = s->private;
800 spin_lock_irqsave(&subpriv->spinlock, flags);
801 if (subpriv->active) {
802 dio200_stop_intr(dev, s);
804 spin_unlock_irqrestore(&subpriv->spinlock, flags);
810 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
813 dio200_subdev_intr_cmdtest(struct comedi_device *dev,
814 struct comedi_subdevice *s, struct comedi_cmd *cmd)
819 /* step 1: make sure trigger sources are trivially valid */
821 tmp = cmd->start_src;
822 cmd->start_src &= (TRIG_NOW | TRIG_INT);
823 if (!cmd->start_src || tmp != cmd->start_src)
826 tmp = cmd->scan_begin_src;
827 cmd->scan_begin_src &= TRIG_EXT;
828 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
831 tmp = cmd->convert_src;
832 cmd->convert_src &= TRIG_NOW;
833 if (!cmd->convert_src || tmp != cmd->convert_src)
836 tmp = cmd->scan_end_src;
837 cmd->scan_end_src &= TRIG_COUNT;
838 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
842 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
843 if (!cmd->stop_src || tmp != cmd->stop_src)
849 /* step 2: make sure trigger sources are unique and mutually compatible */
851 /* these tests are true if more than one _src bit is set */
852 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
854 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
856 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
858 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
860 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
866 /* step 3: make sure arguments are trivially compatible */
868 /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
869 if (cmd->start_arg != 0) {
874 /* cmd->scan_begin_src == TRIG_EXT */
875 if (cmd->scan_begin_arg != 0) {
876 cmd->scan_begin_arg = 0;
880 /* cmd->convert_src == TRIG_NOW */
881 if (cmd->convert_arg != 0) {
882 cmd->convert_arg = 0;
886 /* cmd->scan_end_src == TRIG_COUNT */
887 if (cmd->scan_end_arg != cmd->chanlist_len) {
888 cmd->scan_end_arg = cmd->chanlist_len;
892 switch (cmd->stop_src) {
894 /* any count allowed */
897 if (cmd->stop_arg != 0) {
909 /* step 4: fix up any arguments */
911 /* if (err) return 4; */
917 * 'do_cmd' function for an 'INTERRUPT' subdevice.
919 static int dio200_subdev_intr_cmd(struct comedi_device *dev,
920 struct comedi_subdevice *s)
922 struct comedi_cmd *cmd = &s->async->cmd;
923 struct dio200_subdev_intr *subpriv = s->private;
927 spin_lock_irqsave(&subpriv->spinlock, flags);
930 /* Set up end of acquisition. */
931 switch (cmd->stop_src) {
933 subpriv->continuous = 0;
934 subpriv->stopcount = cmd->stop_arg;
938 subpriv->continuous = 1;
939 subpriv->stopcount = 0;
943 /* Set up start of acquisition. */
944 switch (cmd->start_src) {
946 s->async->inttrig = dio200_inttrig_start_intr;
950 event = dio200_start_intr(dev, s);
953 spin_unlock_irqrestore(&subpriv->spinlock, flags);
956 comedi_event(dev, s);
963 * This function initializes an 'INTERRUPT' subdevice.
966 dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
967 unsigned long iobase, unsigned valid_isns,
970 struct dio200_subdev_intr *subpriv;
972 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
974 printk(KERN_ERR "comedi%d: error! out of memory!\n",
978 subpriv->iobase = iobase;
979 subpriv->has_int_sce = has_int_sce;
980 subpriv->valid_isns = valid_isns;
981 spin_lock_init(&subpriv->spinlock);
984 outb(0, subpriv->iobase); /* Disable interrupt sources. */
987 s->private = subpriv;
988 s->type = COMEDI_SUBD_DI;
989 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
991 s->n_chan = DIO200_MAX_ISNS;
992 s->len_chanlist = DIO200_MAX_ISNS;
994 /* No interrupt source register. Support single channel. */
998 s->range_table = &range_digital;
1000 s->insn_bits = dio200_subdev_intr_insn_bits;
1001 s->do_cmdtest = dio200_subdev_intr_cmdtest;
1002 s->do_cmd = dio200_subdev_intr_cmd;
1003 s->cancel = dio200_subdev_intr_cancel;
1009 * This function cleans up an 'INTERRUPT' subdevice.
1012 dio200_subdev_intr_cleanup(struct comedi_device *dev,
1013 struct comedi_subdevice *s)
1015 struct dio200_subdev_intr *subpriv = s->private;
1023 * Interrupt service routine.
1025 static irqreturn_t dio200_interrupt(int irq, void *d)
1027 struct comedi_device *dev = d;
1030 if (!dev->attached) {
1034 if (devpriv->intr_sd >= 0) {
1035 handled = dio200_handle_read_intr(dev,
1042 return IRQ_RETVAL(handled);
1046 * Handle 'insn_read' for an '8254' counter subdevice.
1049 dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
1050 struct comedi_insn *insn, unsigned int *data)
1052 struct dio200_subdev_8254 *subpriv = s->private;
1053 int chan = CR_CHAN(insn->chanspec);
1055 data[0] = i8254_read(subpriv->iobase, 0, chan);
1061 * Handle 'insn_write' for an '8254' counter subdevice.
1064 dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1065 struct comedi_insn *insn, unsigned int *data)
1067 struct dio200_subdev_8254 *subpriv = s->private;
1068 int chan = CR_CHAN(insn->chanspec);
1070 i8254_write(subpriv->iobase, 0, chan, data[0]);
1076 * Set gate source for an '8254' counter subdevice channel.
1079 dio200_set_gate_src(struct dio200_subdev_8254 *subpriv,
1080 unsigned int counter_number, unsigned int gate_src)
1084 if (!subpriv->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_get_gate_src(struct dio200_subdev_8254 *subpriv,
1103 unsigned int counter_number)
1105 if (!subpriv->has_clk_gat_sce)
1107 if (counter_number > 2)
1110 return subpriv->gate_src[counter_number];
1114 * Set clock source for an '8254' counter subdevice channel.
1117 dio200_set_clock_src(struct dio200_subdev_8254 *subpriv,
1118 unsigned int counter_number, unsigned int clock_src)
1122 if (!subpriv->has_clk_gat_sce)
1124 if (counter_number > 2)
1129 subpriv->clock_src[counter_number] = clock_src;
1130 byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1131 outb(byte, subpriv->clk_sce_iobase);
1137 * Get clock source for an '8254' counter subdevice channel.
1140 dio200_get_clock_src(struct dio200_subdev_8254 *subpriv,
1141 unsigned int counter_number, unsigned int *period_ns)
1145 if (!subpriv->has_clk_gat_sce)
1147 if (counter_number > 2)
1150 clock_src = subpriv->clock_src[counter_number];
1151 *period_ns = clock_period[clock_src];
1156 * Handle 'insn_config' for an '8254' counter subdevice.
1159 dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1160 struct comedi_insn *insn, unsigned int *data)
1162 struct dio200_subdev_8254 *subpriv = s->private;
1164 int chan = CR_CHAN(insn->chanspec);
1167 case INSN_CONFIG_SET_COUNTER_MODE:
1168 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1172 case INSN_CONFIG_8254_READ_STATUS:
1173 data[1] = i8254_status(subpriv->iobase, 0, chan);
1175 case INSN_CONFIG_SET_GATE_SRC:
1176 ret = dio200_set_gate_src(subpriv, chan, data[2]);
1180 case INSN_CONFIG_GET_GATE_SRC:
1181 ret = dio200_get_gate_src(subpriv, chan);
1186 case INSN_CONFIG_SET_CLOCK_SRC:
1187 ret = dio200_set_clock_src(subpriv, chan, data[1]);
1191 case INSN_CONFIG_GET_CLOCK_SRC:
1192 ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1205 * This function initializes an '8254' counter subdevice.
1207 * Note: iobase is the base address of the board, not the subdevice;
1208 * offset is the offset to the 8254 chip.
1211 dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1212 unsigned long iobase, unsigned offset,
1213 int has_clk_gat_sce)
1215 struct dio200_subdev_8254 *subpriv;
1218 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1220 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1225 s->private = subpriv;
1226 s->type = COMEDI_SUBD_COUNTER;
1227 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1229 s->maxdata = 0xFFFF;
1230 s->insn_read = dio200_subdev_8254_read;
1231 s->insn_write = dio200_subdev_8254_write;
1232 s->insn_config = dio200_subdev_8254_config;
1234 subpriv->iobase = offset + iobase;
1235 subpriv->has_clk_gat_sce = has_clk_gat_sce;
1236 if (has_clk_gat_sce) {
1237 /* Derive CLK_SCE and GAT_SCE register offsets from
1239 subpriv->clk_sce_iobase =
1240 DIO200_XCLK_SCE + (offset >> 3) + iobase;
1241 subpriv->gat_sce_iobase =
1242 DIO200_XGAT_SCE + (offset >> 3) + iobase;
1243 subpriv->which = (offset >> 2) & 1;
1246 /* Initialize channels. */
1247 for (chan = 0; chan < 3; chan++) {
1248 i8254_set_mode(subpriv->iobase, 0, chan,
1249 I8254_MODE0 | I8254_BINARY);
1250 if (subpriv->has_clk_gat_sce) {
1251 /* Gate source 0 is VCC (logic 1). */
1252 dio200_set_gate_src(subpriv, chan, 0);
1253 /* Clock source 0 is the dedicated clock input. */
1254 dio200_set_clock_src(subpriv, chan, 0);
1262 * This function cleans up an '8254' counter subdevice.
1265 dio200_subdev_8254_cleanup(struct comedi_device *dev,
1266 struct comedi_subdevice *s)
1268 struct dio200_subdev_intr *subpriv = s->private;
1276 * Attach is called by the Comedi core to configure the driver
1277 * for a particular board. If you specified a board_name array
1278 * in the driver structure, dev->board_ptr contains that
1281 static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1283 struct comedi_subdevice *s;
1284 unsigned long iobase = 0;
1285 unsigned int irq = 0;
1286 #ifdef CONFIG_COMEDI_PCI
1287 struct pci_dev *pci_dev = NULL;
1288 int bus = 0, slot = 0;
1290 const struct dio200_layout_struct *layout;
1296 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1297 DIO200_DRIVER_NAME);
1299 ret = alloc_private(dev, sizeof(struct dio200_private));
1301 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1306 /* Process options. */
1307 switch (thisboard->bustype) {
1309 iobase = it->options[0];
1310 irq = it->options[1];
1313 #ifdef CONFIG_COMEDI_PCI
1315 bus = it->options[0];
1316 slot = it->options[1];
1319 ret = dio200_find_pci(dev, bus, slot, &pci_dev);
1322 devpriv->pci_dev = pci_dev;
1327 "comedi%d: %s: BUG! cannot determine board type!\n",
1328 dev->minor, DIO200_DRIVER_NAME);
1333 devpriv->intr_sd = -1;
1335 /* Enable device and reserve I/O spaces. */
1336 #ifdef CONFIG_COMEDI_PCI
1338 ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1341 "comedi%d: error! cannot enable PCI device and request regions!\n",
1345 iobase = pci_resource_start(pci_dev, 2);
1350 ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
1355 dev->iobase = iobase;
1357 layout = thislayout;
1359 ret = alloc_subdevices(dev, layout->n_subdevs);
1361 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1366 for (n = 0; n < dev->n_subdevices; n++) {
1367 s = &dev->subdevices[n];
1368 switch (layout->sdtype[n]) {
1370 /* counter subdevice (8254) */
1371 ret = dio200_subdev_8254_init(dev, s, iobase,
1373 layout->has_clk_gat_sce);
1379 /* digital i/o subdevice (8255) */
1380 ret = subdev_8255_init(dev, s, 0,
1381 iobase + layout->sdinfo[n]);
1387 /* 'INTERRUPT' subdevice */
1389 ret = dio200_subdev_intr_init(dev, s,
1398 devpriv->intr_sd = n;
1400 s->type = COMEDI_SUBD_UNUSED;
1404 s->type = COMEDI_SUBD_UNUSED;
1409 sdx = devpriv->intr_sd;
1410 if (sdx >= 0 && sdx < dev->n_subdevices) {
1411 dev->read_subdev = &dev->subdevices[sdx];
1414 dev->board_name = thisboard->name;
1417 unsigned long flags = share_irq ? IRQF_SHARED : 0;
1419 if (request_irq(irq, dio200_interrupt, flags,
1420 DIO200_DRIVER_NAME, dev) >= 0) {
1424 "comedi%d: warning! irq %u unavailable!\n",
1429 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1430 if (thisboard->bustype == isa_bustype) {
1431 printk("(base %#lx) ", iobase);
1433 #ifdef CONFIG_COMEDI_PCI
1434 printk("(pci %s) ", pci_name(pci_dev));
1438 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1440 printk("(no irq) ");
1443 printk("attached\n");
1449 * _detach is called to deconfigure a device. It should deallocate
1451 * This function is also called when _attach() fails, so it should be
1452 * careful not to release resources that were not necessarily
1453 * allocated by _attach(). dev->private and dev->subdevices are
1454 * deallocated automatically by the core.
1456 static int dio200_detach(struct comedi_device *dev)
1458 const struct dio200_layout_struct *layout;
1461 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1462 DIO200_DRIVER_NAME);
1465 free_irq(dev->irq, dev);
1467 if (dev->subdevices) {
1468 layout = thislayout;
1469 for (n = 0; n < dev->n_subdevices; n++) {
1470 struct comedi_subdevice *s = &dev->subdevices[n];
1471 switch (layout->sdtype[n]) {
1473 dio200_subdev_8254_cleanup(dev, s);
1476 subdev_8255_cleanup(dev, s);
1479 dio200_subdev_intr_cleanup(dev, s);
1487 #ifdef CONFIG_COMEDI_PCI
1488 if (devpriv->pci_dev) {
1490 comedi_pci_disable(devpriv->pci_dev);
1492 pci_dev_put(devpriv->pci_dev);
1497 release_region(dev->iobase, DIO200_IO_SIZE);
1501 if (dev->board_name) {
1502 printk(KERN_INFO "comedi%d: %s removed\n",
1503 dev->minor, dev->board_name);