amplc_dio200.c revision 90f703d30dd3e0c16ff80f35e34e511385a05ad5
1/*
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.)
6
7    Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/>
8
9    COMEDI - Linux Control and Measurement Device Interface
10    Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
11
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.
16
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.
21
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.
25
26*/
27/*
28Driver: amplc_dio200
29Description: Amplicon 200 Series Digital I/O
30Author: Ian Abbott <abbotti@mev.co.uk>
31Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e),
32  PCI215 (pci215 or amplc_dio200), PC218E (pc218e), PC272E (pc272e),
33  PCI272 (pci272 or amplc_dio200)
34Updated: Wed, 22 Oct 2008 13:36:02 +0100
35Status: works
36
37Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E:
38  [0] - I/O port base address
39  [1] - IRQ (optional, but commands won't work without it)
40
41Configuration 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
45  be used.
46
47Passing a zero for an option is the same as leaving it unspecified.
48
49SUBDEVICES
50
51		    PC218E         PC212E      PC215E/PCI215
52		 -------------  -------------  -------------
53  Subdevices           7              6              5
54   0                 CTR-X1         PPI-X          PPI-X
55   1                 CTR-X2         CTR-Y1         PPI-Y
56   2                 CTR-Y1         CTR-Y2         CTR-Z1
57   3                 CTR-Y2         CTR-Z1         CTR-Z2
58   4                 CTR-Z1         CTR-Z2       INTERRUPT
59   5                 CTR-Z2       INTERRUPT
60   6               INTERRUPT
61
62		    PC214E      PC272E/PCI272
63		 -------------  -------------
64  Subdevices           4              4
65   0                 PPI-X          PPI-X
66   1                 PPI-Y          PPI-Y
67   2                 CTR-Z1*        PPI-Z
68   3               INTERRUPT*     INTERRUPT
69
70Each PPI is a 8255 chip providing 24 DIO channels.  The DIO channels
71are configurable as inputs or outputs in four groups:
72
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
77
78Only mode 0 of the 8255 chips is supported.
79
80Each CTR is a 8254 chip providing 3 16-bit counter channels.  Each
81channel is configured individually with INSN_CONFIG instructions.  The
82specific type of configuration instruction is specified in data[0].
83Some configuration instructions expect an additional parameter in
84data[1]; others return a value in data[1].  The following configuration
85instructions are supported:
86
87  INSN_CONFIG_SET_COUNTER_MODE.  Sets the counter channel's mode and
88    BCD/binary setting specified in data[1].
89
90  INSN_CONFIG_8254_READ_STATUS.  Reads the status register value for the
91    counter channel into data[1].
92
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
96    0 to 7 as follows:
97
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.
110
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
113    to the period in ns.
114
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
118    to 7 as follows:
119
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
126	2 below).
127      4.  Reserved.
128      5.  Reserved.
129      6.  Reserved.
130      7.  Reserved.
131
132  INSN_CONFIG_GET_GATE_SRC.  Returns the counter channel's current gate
133    source in data[2].
134
135Clock and gate interconnection notes:
136
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.
140
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.
144
145  3.  The counter subdevices are connected in a ring, so the highest
146  counter subdevice precedes the lowest.
147
148The 'INTERRUPT' subdevice pretends to be a digital input subdevice.  The
149digital inputs come from the interrupt status register.  The number of
150channels matches the number of interrupt sources.  The PC214E does not
151have an interrupt status register; see notes on 'INTERRUPT SOURCES'
152below.
153
154INTERRUPT SOURCES
155
156		    PC218E         PC212E      PC215E/PCI215
157		 -------------  -------------  -------------
158  Sources              6              6              6
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
165
166		    PC214E      PC272E/PCI272
167		 -------------  -------------
168  Sources              1              6
169   0               JUMPER-J5      PPI-X-C0
170   1                              PPI-X-C3
171   2                              PPI-Y-C0
172   3                              PPI-Y-C3
173   4                              PPI-Z-C0
174   5                              PPI-Z-C3
175
176When an interrupt source is enabled in the interrupt source enable
177register, a rising edge on the source signal latches the corresponding
178bit to 1 in the interrupt status register.
179
180When the interrupt status register value as a whole (actually, just the
1816 least significant bits) goes from zero to non-zero, the board will
182generate an interrupt.  For level-triggered hardware interrupts (PCI
183card), the interrupt will remain asserted until the interrupt status
184register is cleared to zero.  For edge-triggered hardware interrupts
185(ISA card), no further interrupts will occur until the interrupt status
186register is cleared to zero.  To clear a bit to zero in the interrupt
187status register, the corresponding interrupt source must be disabled
188in the interrupt source enable register (there is no separate interrupt
189clear register).
190
191The PC214E does not have an interrupt source enable register or an
192interrupt status register; its 'INTERRUPT' subdevice has a single
193channel and its interrupt source is selected by the position of jumper
194J5.
195
196COMMANDS
197
198The driver supports a read streaming acquisition command on the
199'INTERRUPT' subdevice.  The channel list selects the interrupt sources
200to be enabled.  All channels will be sampled together (convert_src ==
201TRIG_NOW).  The scan begins a short time after the hardware interrupt
202occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT,
203scan_begin_arg == 0).  The value read from the interrupt status register
204is packed into a short value, one bit per requested channel, in the
205order they appear in the channel list.
206*/
207
208#include <linux/interrupt.h>
209#include <linux/slab.h>
210
211#include "../comedidev.h"
212
213#include "comedi_pci.h"
214
215#include "8255.h"
216#include "8253.h"
217
218#define DIO200_DRIVER_NAME	"amplc_dio200"
219
220/* PCI IDs */
221#define PCI_VENDOR_ID_AMPLICON 0x14dc
222#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
223#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
224#define PCI_DEVICE_ID_INVALID 0xffff
225
226/* 200 series registers */
227#define DIO200_IO_SIZE		0x20
228#define DIO200_XCLK_SCE		0x18	/* Group X clock selection register */
229#define DIO200_YCLK_SCE		0x19	/* Group Y clock selection register */
230#define DIO200_ZCLK_SCE		0x1a	/* Group Z clock selection register */
231#define DIO200_XGAT_SCE		0x1b	/* Group X gate selection register */
232#define DIO200_YGAT_SCE		0x1c	/* Group Y gate selection register */
233#define DIO200_ZGAT_SCE		0x1d	/* Group Z gate selection register */
234#define DIO200_INT_SCE		0x1e	/* Interrupt enable/status register */
235
236/*
237 * Macros for constructing value for DIO_200_?CLK_SCE and
238 * DIO_200_?GAT_SCE registers:
239 *
240 * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
241 * 'chan' is the channel: 0, 1 or 2.
242 * 'source' is the signal source: 0 to 7.
243 */
244#define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
245#define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
246
247/*
248 * Periods of the internal clock sources in nanoseconds.
249 */
250static const unsigned clock_period[8] = {
251	0,			/* dedicated clock input/output pin */
252	100,			/* 10 MHz */
253	1000,			/* 1 MHz */
254	10000,			/* 100 kHz */
255	100000,			/* 10 kHz */
256	1000000,		/* 1 kHz */
257	0,			/* OUT N-1 */
258	0			/* group clock input pin */
259};
260
261/*
262 * Board descriptions.
263 */
264
265enum dio200_bustype { isa_bustype, pci_bustype };
266
267enum dio200_model {
268	pc212e_model,
269	pc214e_model,
270	pc215e_model, pci215_model,
271	pc218e_model,
272	pc272e_model, pci272_model,
273	anypci_model
274};
275
276enum dio200_layout {
277	pc212_layout,
278	pc214_layout,
279	pc215_layout,
280	pc218_layout,
281	pc272_layout
282};
283
284struct dio200_board {
285	const char *name;
286	unsigned short devid;
287	enum dio200_bustype bustype;
288	enum dio200_model model;
289	enum dio200_layout layout;
290};
291
292static const struct dio200_board dio200_boards[] = {
293	{
294	 .name = "pc212e",
295	 .bustype = isa_bustype,
296	 .model = pc212e_model,
297	 .layout = pc212_layout,
298	 },
299	{
300	 .name = "pc214e",
301	 .bustype = isa_bustype,
302	 .model = pc214e_model,
303	 .layout = pc214_layout,
304	 },
305	{
306	 .name = "pc215e",
307	 .bustype = isa_bustype,
308	 .model = pc215e_model,
309	 .layout = pc215_layout,
310	 },
311#ifdef CONFIG_COMEDI_PCI
312	{
313	 .name = "pci215",
314	 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
315	 .bustype = pci_bustype,
316	 .model = pci215_model,
317	 .layout = pc215_layout,
318	 },
319#endif
320	{
321	 .name = "pc218e",
322	 .bustype = isa_bustype,
323	 .model = pc218e_model,
324	 .layout = pc218_layout,
325	 },
326	{
327	 .name = "pc272e",
328	 .bustype = isa_bustype,
329	 .model = pc272e_model,
330	 .layout = pc272_layout,
331	 },
332#ifdef CONFIG_COMEDI_PCI
333	{
334	 .name = "pci272",
335	 .devid = PCI_DEVICE_ID_AMPLICON_PCI272,
336	 .bustype = pci_bustype,
337	 .model = pci272_model,
338	 .layout = pc272_layout,
339	 },
340#endif
341#ifdef CONFIG_COMEDI_PCI
342	{
343	 .name = DIO200_DRIVER_NAME,
344	 .devid = PCI_DEVICE_ID_INVALID,
345	 .bustype = pci_bustype,
346	 .model = anypci_model,	/* wildcard */
347	 },
348#endif
349};
350
351/*
352 * Layout descriptions - some ISA and PCI board descriptions share the same
353 * layout.
354 */
355
356enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
357
358#define DIO200_MAX_SUBDEVS	7
359#define DIO200_MAX_ISNS		6
360
361struct 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 */
367};
368
369static const struct dio200_layout_struct dio200_layouts[] = {
370	[pc212_layout] = {
371			  .n_subdevs = 6,
372			  .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
373				     sd_8254,
374				     sd_intr},
375			  .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14,
376				     0x3F},
377			  .has_int_sce = 1,
378			  .has_clk_gat_sce = 1,
379			  },
380	[pc214_layout] = {
381			  .n_subdevs = 4,
382			  .sdtype = {sd_8255, sd_8255, sd_8254,
383				     sd_intr},
384			  .sdinfo = {0x00, 0x08, 0x10, 0x01},
385			  .has_int_sce = 0,
386			  .has_clk_gat_sce = 0,
387			  },
388	[pc215_layout] = {
389			  .n_subdevs = 5,
390			  .sdtype = {sd_8255, sd_8255, sd_8254,
391				     sd_8254,
392				     sd_intr},
393			  .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
394			  .has_int_sce = 1,
395			  .has_clk_gat_sce = 1,
396			  },
397	[pc218_layout] = {
398			  .n_subdevs = 7,
399			  .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
400				     sd_8254,
401				     sd_intr},
402			  .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10,
403				     0x14,
404				     0x3F},
405			  .has_int_sce = 1,
406			  .has_clk_gat_sce = 1,
407			  },
408	[pc272_layout] = {
409			  .n_subdevs = 4,
410			  .sdtype = {sd_8255, sd_8255, sd_8255,
411				     sd_intr},
412			  .sdinfo = {0x00, 0x08, 0x10, 0x3F},
413			  .has_int_sce = 1,
414			  .has_clk_gat_sce = 0,
415			  },
416};
417
418/*
419 * PCI driver table.
420 */
421
422#ifdef CONFIG_COMEDI_PCI
423static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
424	{
425	PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
426		    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
427	PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
428		    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
429	0}
430};
431
432MODULE_DEVICE_TABLE(pci, dio200_pci_table);
433#endif /* CONFIG_COMEDI_PCI */
434
435/*
436 * Useful for shorthand access to the particular board structure
437 */
438#define thisboard ((const struct dio200_board *)dev->board_ptr)
439#define thislayout (&dio200_layouts[((struct dio200_board *) \
440		    dev->board_ptr)->layout])
441
442/* this structure is for data unique to this hardware driver.  If
443   several hardware drivers keep similar information in this structure,
444   feel free to suggest moving the variable to the struct comedi_device struct.
445 */
446struct dio200_private {
447#ifdef CONFIG_COMEDI_PCI
448	struct pci_dev *pci_dev;	/* PCI device */
449#endif
450	int intr_sd;
451};
452
453#define devpriv ((struct dio200_private *)dev->private)
454
455struct dio200_subdev_8254 {
456	unsigned long iobase;	/* Counter base address */
457	unsigned long clk_sce_iobase;	/* CLK_SCE base address */
458	unsigned long gat_sce_iobase;	/* GAT_SCE base address */
459	int which;		/* Bit 5 of CLK_SCE or GAT_SCE */
460	int has_clk_gat_sce;
461	unsigned clock_src[3];	/* Current clock sources */
462	unsigned gate_src[3];	/* Current gate sources */
463	spinlock_t spinlock;
464};
465
466struct dio200_subdev_intr {
467	unsigned long iobase;
468	spinlock_t spinlock;
469	int active;
470	int has_int_sce;
471	unsigned int valid_isns;
472	unsigned int enabled_isns;
473	unsigned int stopcount;
474	int continuous;
475};
476
477/*
478 * The struct comedi_driver structure tells the Comedi core module
479 * which functions to call to configure/deconfigure (attach/detach)
480 * the board, and also about the kernel module that contains
481 * the device code.
482 */
483static int dio200_attach(struct comedi_device *dev,
484			 struct comedi_devconfig *it);
485static int dio200_detach(struct comedi_device *dev);
486static struct comedi_driver driver_amplc_dio200 = {
487	.driver_name = DIO200_DRIVER_NAME,
488	.module = THIS_MODULE,
489	.attach = dio200_attach,
490	.detach = dio200_detach,
491	.board_name = &dio200_boards[0].name,
492	.offset = sizeof(struct dio200_board),
493	.num_names = ARRAY_SIZE(dio200_boards),
494};
495
496#ifdef CONFIG_COMEDI_PCI
497COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
498#else
499COMEDI_INITCLEANUP(driver_amplc_dio200);
500#endif
501
502/*
503 * This function looks for a PCI device matching the requested board name,
504 * bus and slot.
505 */
506#ifdef CONFIG_COMEDI_PCI
507static int
508dio200_find_pci(struct comedi_device *dev, int bus, int slot,
509		struct pci_dev **pci_dev_p)
510{
511	struct pci_dev *pci_dev = NULL;
512
513	*pci_dev_p = NULL;
514
515	/* Look for matching PCI device. */
516	for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
517	     pci_dev != NULL;
518	     pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
519				      PCI_ANY_ID, pci_dev)) {
520		/* If bus/slot specified, check them. */
521		if (bus || slot) {
522			if (bus != pci_dev->bus->number
523			    || slot != PCI_SLOT(pci_dev->devfn))
524				continue;
525		}
526		if (thisboard->model == anypci_model) {
527			/* Match any supported model. */
528			int i;
529
530			for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
531				if (dio200_boards[i].bustype != pci_bustype)
532					continue;
533				if (pci_dev->device == dio200_boards[i].devid) {
534					/* Change board_ptr to matched board. */
535					dev->board_ptr = &dio200_boards[i];
536					break;
537				}
538			}
539			if (i == ARRAY_SIZE(dio200_boards))
540				continue;
541		} else {
542			/* Match specific model name. */
543			if (pci_dev->device != thisboard->devid)
544				continue;
545		}
546
547		/* Found a match. */
548		*pci_dev_p = pci_dev;
549		return 0;
550	}
551	/* No match found. */
552	if (bus || slot) {
553		printk(KERN_ERR
554		       "comedi%d: error! no %s found at pci %02x:%02x!\n",
555		       dev->minor, thisboard->name, bus, slot);
556	} else {
557		printk(KERN_ERR "comedi%d: error! no %s found!\n",
558		       dev->minor, thisboard->name);
559	}
560	return -EIO;
561}
562#endif
563
564/*
565 * This function checks and requests an I/O region, reporting an error
566 * if there is a conflict.
567 */
568static int
569dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
570{
571	if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
572		printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
573		       minor, from, extent);
574		return -EIO;
575	}
576	return 0;
577}
578
579/*
580 * 'insn_bits' function for an 'INTERRUPT' subdevice.
581 */
582static int
583dio200_subdev_intr_insn_bits(struct comedi_device *dev,
584			     struct comedi_subdevice *s,
585			     struct comedi_insn *insn, unsigned int *data)
586{
587	struct dio200_subdev_intr *subpriv = s->private;
588
589	if (subpriv->has_int_sce) {
590		/* Just read the interrupt status register.  */
591		data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
592	} else {
593		/* No interrupt status register. */
594		data[0] = 0;
595	}
596
597	return 2;
598}
599
600/*
601 * Called to stop acquisition for an 'INTERRUPT' subdevice.
602 */
603static void dio200_stop_intr(struct comedi_device *dev,
604			     struct comedi_subdevice *s)
605{
606	struct dio200_subdev_intr *subpriv = s->private;
607
608	subpriv->active = 0;
609	subpriv->enabled_isns = 0;
610	if (subpriv->has_int_sce)
611		outb(0, subpriv->iobase);
612}
613
614/*
615 * Called to start acquisition for an 'INTERRUPT' subdevice.
616 */
617static int dio200_start_intr(struct comedi_device *dev,
618			     struct comedi_subdevice *s)
619{
620	unsigned int n;
621	unsigned isn_bits;
622	struct dio200_subdev_intr *subpriv = s->private;
623	struct comedi_cmd *cmd = &s->async->cmd;
624	int retval = 0;
625
626	if (!subpriv->continuous && subpriv->stopcount == 0) {
627		/* An empty acquisition! */
628		s->async->events |= COMEDI_CB_EOA;
629		subpriv->active = 0;
630		retval = 1;
631	} else {
632		/* Determine interrupt sources to enable. */
633		isn_bits = 0;
634		if (cmd->chanlist) {
635			for (n = 0; n < cmd->chanlist_len; n++)
636				isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
637		}
638		isn_bits &= subpriv->valid_isns;
639		/* Enable interrupt sources. */
640		subpriv->enabled_isns = isn_bits;
641		if (subpriv->has_int_sce)
642			outb(isn_bits, subpriv->iobase);
643	}
644
645	return retval;
646}
647
648/*
649 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
650 */
651static int
652dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
653			  unsigned int trignum)
654{
655	struct dio200_subdev_intr *subpriv;
656	unsigned long flags;
657	int event = 0;
658
659	if (trignum != 0)
660		return -EINVAL;
661
662	subpriv = s->private;
663
664	spin_lock_irqsave(&subpriv->spinlock, flags);
665	s->async->inttrig = NULL;
666	if (subpriv->active)
667		event = dio200_start_intr(dev, s);
668
669	spin_unlock_irqrestore(&subpriv->spinlock, flags);
670
671	if (event)
672		comedi_event(dev, s);
673
674	return 1;
675}
676
677/*
678 * This is called from the interrupt service routine to handle a read
679 * scan on an 'INTERRUPT' subdevice.
680 */
681static int dio200_handle_read_intr(struct comedi_device *dev,
682				   struct comedi_subdevice *s)
683{
684	struct dio200_subdev_intr *subpriv = s->private;
685	unsigned triggered;
686	unsigned intstat;
687	unsigned cur_enabled;
688	unsigned int oldevents;
689	unsigned long flags;
690
691	triggered = 0;
692
693	spin_lock_irqsave(&subpriv->spinlock, flags);
694	oldevents = s->async->events;
695	if (subpriv->has_int_sce) {
696		/*
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.
702		 *
703		 * Mask off interrupt sources already seen to avoid infinite
704		 * loop in case of misconfiguration.
705		 */
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);
712		}
713	} else {
714		/*
715		 * No interrupt status register.  Assume the single interrupt
716		 * source has triggered.
717		 */
718		triggered = subpriv->enabled_isns;
719	}
720
721	if (triggered) {
722		/*
723		 * Some interrupt sources have triggered and have been
724		 * temporarily disabled to clear the cause of the interrupt.
725		 *
726		 * Reenable them NOW to minimize the time they are disabled.
727		 */
728		cur_enabled = subpriv->enabled_isns;
729		if (subpriv->has_int_sce)
730			outb(cur_enabled, subpriv->iobase);
731
732		if (subpriv->active) {
733			/*
734			 * The command is still active.
735			 *
736			 * Ignore interrupt sources that the command isn't
737			 * interested in (just in case there's a race
738			 * condition).
739			 */
740			if (triggered & subpriv->enabled_isns) {
741				/* Collect scan data. */
742				short val;
743				unsigned int n, ch, len;
744
745				val = 0;
746				len = s->async->cmd.chanlist_len;
747				for (n = 0; n < len; n++) {
748					ch = CR_CHAN(s->async->cmd.chanlist[n]);
749					if (triggered & (1U << ch))
750						val |= (1U << n);
751				}
752				/* Write the scan to the buffer. */
753				if (comedi_buf_put(s->async, val)) {
754					s->async->events |= (COMEDI_CB_BLOCK |
755							     COMEDI_CB_EOS);
756				} else {
757					/* Error!  Stop acquisition.  */
758					dio200_stop_intr(dev, s);
759					s->async->events |= COMEDI_CB_ERROR
760					    | COMEDI_CB_OVERFLOW;
761					comedi_error(dev, "buffer overflow");
762				}
763
764				/* Check for end of acquisition. */
765				if (!subpriv->continuous) {
766					/* stop_src == TRIG_COUNT */
767					if (subpriv->stopcount > 0) {
768						subpriv->stopcount--;
769						if (subpriv->stopcount == 0) {
770							s->async->events |=
771							    COMEDI_CB_EOA;
772							dio200_stop_intr(dev,
773									 s);
774						}
775					}
776				}
777			}
778		}
779	}
780	spin_unlock_irqrestore(&subpriv->spinlock, flags);
781
782	if (oldevents != s->async->events)
783		comedi_event(dev, s);
784
785	return (triggered != 0);
786}
787
788/*
789 * 'cancel' function for an 'INTERRUPT' subdevice.
790 */
791static int dio200_subdev_intr_cancel(struct comedi_device *dev,
792				     struct comedi_subdevice *s)
793{
794	struct dio200_subdev_intr *subpriv = s->private;
795	unsigned long flags;
796
797	spin_lock_irqsave(&subpriv->spinlock, flags);
798	if (subpriv->active)
799		dio200_stop_intr(dev, s);
800
801	spin_unlock_irqrestore(&subpriv->spinlock, flags);
802
803	return 0;
804}
805
806/*
807 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
808 */
809static int
810dio200_subdev_intr_cmdtest(struct comedi_device *dev,
811			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
812{
813	int err = 0;
814	unsigned int tmp;
815
816	/* step 1: make sure trigger sources are trivially valid */
817
818	tmp = cmd->start_src;
819	cmd->start_src &= (TRIG_NOW | TRIG_INT);
820	if (!cmd->start_src || tmp != cmd->start_src)
821		err++;
822
823	tmp = cmd->scan_begin_src;
824	cmd->scan_begin_src &= TRIG_EXT;
825	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
826		err++;
827
828	tmp = cmd->convert_src;
829	cmd->convert_src &= TRIG_NOW;
830	if (!cmd->convert_src || tmp != cmd->convert_src)
831		err++;
832
833	tmp = cmd->scan_end_src;
834	cmd->scan_end_src &= TRIG_COUNT;
835	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
836		err++;
837
838	tmp = cmd->stop_src;
839	cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
840	if (!cmd->stop_src || tmp != cmd->stop_src)
841		err++;
842
843	if (err)
844		return 1;
845
846	/* step 2: make sure trigger sources are unique and mutually
847		   compatible */
848
849	/* these tests are true if more than one _src bit is set */
850	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
851		err++;
852	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
853		err++;
854	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
855		err++;
856	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
857		err++;
858	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
859		err++;
860
861	if (err)
862		return 2;
863
864	/* step 3: make sure arguments are trivially compatible */
865
866	/* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
867	if (cmd->start_arg != 0) {
868		cmd->start_arg = 0;
869		err++;
870	}
871
872	/* cmd->scan_begin_src == TRIG_EXT */
873	if (cmd->scan_begin_arg != 0) {
874		cmd->scan_begin_arg = 0;
875		err++;
876	}
877
878	/* cmd->convert_src == TRIG_NOW */
879	if (cmd->convert_arg != 0) {
880		cmd->convert_arg = 0;
881		err++;
882	}
883
884	/* cmd->scan_end_src == TRIG_COUNT */
885	if (cmd->scan_end_arg != cmd->chanlist_len) {
886		cmd->scan_end_arg = cmd->chanlist_len;
887		err++;
888	}
889
890	switch (cmd->stop_src) {
891	case TRIG_COUNT:
892		/* any count allowed */
893		break;
894	case TRIG_NONE:
895		if (cmd->stop_arg != 0) {
896			cmd->stop_arg = 0;
897			err++;
898		}
899		break;
900	default:
901		break;
902	}
903
904	if (err)
905		return 3;
906
907	/* step 4: fix up any arguments */
908
909	/* if (err) return 4; */
910
911	return 0;
912}
913
914/*
915 * 'do_cmd' function for an 'INTERRUPT' subdevice.
916 */
917static int dio200_subdev_intr_cmd(struct comedi_device *dev,
918				  struct comedi_subdevice *s)
919{
920	struct comedi_cmd *cmd = &s->async->cmd;
921	struct dio200_subdev_intr *subpriv = s->private;
922	unsigned long flags;
923	int event = 0;
924
925	spin_lock_irqsave(&subpriv->spinlock, flags);
926	subpriv->active = 1;
927
928	/* Set up end of acquisition. */
929	switch (cmd->stop_src) {
930	case TRIG_COUNT:
931		subpriv->continuous = 0;
932		subpriv->stopcount = cmd->stop_arg;
933		break;
934	default:
935		/* TRIG_NONE */
936		subpriv->continuous = 1;
937		subpriv->stopcount = 0;
938		break;
939	}
940
941	/* Set up start of acquisition. */
942	switch (cmd->start_src) {
943	case TRIG_INT:
944		s->async->inttrig = dio200_inttrig_start_intr;
945		break;
946	default:
947		/* TRIG_NOW */
948		event = dio200_start_intr(dev, s);
949		break;
950	}
951	spin_unlock_irqrestore(&subpriv->spinlock, flags);
952
953	if (event)
954		comedi_event(dev, s);
955
956	return 0;
957}
958
959/*
960 * This function initializes an 'INTERRUPT' subdevice.
961 */
962static int
963dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
964			unsigned long iobase, unsigned valid_isns,
965			int has_int_sce)
966{
967	struct dio200_subdev_intr *subpriv;
968
969	subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
970	if (!subpriv) {
971		printk(KERN_ERR "comedi%d: error! out of memory!\n",
972		       dev->minor);
973		return -ENOMEM;
974	}
975	subpriv->iobase = iobase;
976	subpriv->has_int_sce = has_int_sce;
977	subpriv->valid_isns = valid_isns;
978	spin_lock_init(&subpriv->spinlock);
979
980	if (has_int_sce)
981		outb(0, subpriv->iobase);	/* Disable interrupt sources. */
982
983	s->private = subpriv;
984	s->type = COMEDI_SUBD_DI;
985	s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
986	if (has_int_sce) {
987		s->n_chan = DIO200_MAX_ISNS;
988		s->len_chanlist = DIO200_MAX_ISNS;
989	} else {
990		/* No interrupt source register.  Support single channel. */
991		s->n_chan = 1;
992		s->len_chanlist = 1;
993	}
994	s->range_table = &range_digital;
995	s->maxdata = 1;
996	s->insn_bits = dio200_subdev_intr_insn_bits;
997	s->do_cmdtest = dio200_subdev_intr_cmdtest;
998	s->do_cmd = dio200_subdev_intr_cmd;
999	s->cancel = dio200_subdev_intr_cancel;
1000
1001	return 0;
1002}
1003
1004/*
1005 * This function cleans up an 'INTERRUPT' subdevice.
1006 */
1007static void
1008dio200_subdev_intr_cleanup(struct comedi_device *dev,
1009			   struct comedi_subdevice *s)
1010{
1011	struct dio200_subdev_intr *subpriv = s->private;
1012	kfree(subpriv);
1013}
1014
1015/*
1016 * Interrupt service routine.
1017 */
1018static irqreturn_t dio200_interrupt(int irq, void *d)
1019{
1020	struct comedi_device *dev = d;
1021	int handled;
1022
1023	if (!dev->attached)
1024		return IRQ_NONE;
1025
1026	if (devpriv->intr_sd >= 0) {
1027		handled = dio200_handle_read_intr(dev,
1028						  dev->subdevices +
1029						  devpriv->intr_sd);
1030	} else {
1031		handled = 0;
1032	}
1033
1034	return IRQ_RETVAL(handled);
1035}
1036
1037/*
1038 * Handle 'insn_read' for an '8254' counter subdevice.
1039 */
1040static int
1041dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
1042			struct comedi_insn *insn, unsigned int *data)
1043{
1044	struct dio200_subdev_8254 *subpriv = s->private;
1045	int chan = CR_CHAN(insn->chanspec);
1046	unsigned long flags;
1047
1048	spin_lock_irqsave(&subpriv->spinlock, flags);
1049	data[0] = i8254_read(subpriv->iobase, 0, chan);
1050	spin_unlock_irqrestore(&subpriv->spinlock, flags);
1051
1052	return 1;
1053}
1054
1055/*
1056 * Handle 'insn_write' for an '8254' counter subdevice.
1057 */
1058static int
1059dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1060			 struct comedi_insn *insn, unsigned int *data)
1061{
1062	struct dio200_subdev_8254 *subpriv = s->private;
1063	int chan = CR_CHAN(insn->chanspec);
1064	unsigned long flags;
1065
1066	spin_lock_irqsave(&subpriv->spinlock, flags);
1067	i8254_write(subpriv->iobase, 0, chan, data[0]);
1068	spin_unlock_irqrestore(&subpriv->spinlock, flags);
1069
1070	return 1;
1071}
1072
1073/*
1074 * Set gate source for an '8254' counter subdevice channel.
1075 */
1076static int
1077dio200_set_gate_src(struct dio200_subdev_8254 *subpriv,
1078		    unsigned int counter_number, unsigned int gate_src)
1079{
1080	unsigned char byte;
1081
1082	if (!subpriv->has_clk_gat_sce)
1083		return -1;
1084	if (counter_number > 2)
1085		return -1;
1086	if (gate_src > 7)
1087		return -1;
1088
1089	subpriv->gate_src[counter_number] = gate_src;
1090	byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1091	outb(byte, subpriv->gat_sce_iobase);
1092
1093	return 0;
1094}
1095
1096/*
1097 * Get gate source for an '8254' counter subdevice channel.
1098 */
1099static int
1100dio200_get_gate_src(struct dio200_subdev_8254 *subpriv,
1101		    unsigned int counter_number)
1102{
1103	if (!subpriv->has_clk_gat_sce)
1104		return -1;
1105	if (counter_number > 2)
1106		return -1;
1107
1108	return subpriv->gate_src[counter_number];
1109}
1110
1111/*
1112 * Set clock source for an '8254' counter subdevice channel.
1113 */
1114static int
1115dio200_set_clock_src(struct dio200_subdev_8254 *subpriv,
1116		     unsigned int counter_number, unsigned int clock_src)
1117{
1118	unsigned char byte;
1119
1120	if (!subpriv->has_clk_gat_sce)
1121		return -1;
1122	if (counter_number > 2)
1123		return -1;
1124	if (clock_src > 7)
1125		return -1;
1126
1127	subpriv->clock_src[counter_number] = clock_src;
1128	byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1129	outb(byte, subpriv->clk_sce_iobase);
1130
1131	return 0;
1132}
1133
1134/*
1135 * Get clock source for an '8254' counter subdevice channel.
1136 */
1137static int
1138dio200_get_clock_src(struct dio200_subdev_8254 *subpriv,
1139		     unsigned int counter_number, unsigned int *period_ns)
1140{
1141	unsigned clock_src;
1142
1143	if (!subpriv->has_clk_gat_sce)
1144		return -1;
1145	if (counter_number > 2)
1146		return -1;
1147
1148	clock_src = subpriv->clock_src[counter_number];
1149	*period_ns = clock_period[clock_src];
1150	return clock_src;
1151}
1152
1153/*
1154 * Handle 'insn_config' for an '8254' counter subdevice.
1155 */
1156static int
1157dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1158			  struct comedi_insn *insn, unsigned int *data)
1159{
1160	struct dio200_subdev_8254 *subpriv = s->private;
1161	int ret = 0;
1162	int chan = CR_CHAN(insn->chanspec);
1163	unsigned long flags;
1164
1165	spin_lock_irqsave(&subpriv->spinlock, flags);
1166	switch (data[0]) {
1167	case INSN_CONFIG_SET_COUNTER_MODE:
1168		ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1169		if (ret < 0)
1170			ret = -EINVAL;
1171		break;
1172	case INSN_CONFIG_8254_READ_STATUS:
1173		data[1] = i8254_status(subpriv->iobase, 0, chan);
1174		break;
1175	case INSN_CONFIG_SET_GATE_SRC:
1176		ret = dio200_set_gate_src(subpriv, chan, data[2]);
1177		if (ret < 0)
1178			ret = -EINVAL;
1179		break;
1180	case INSN_CONFIG_GET_GATE_SRC:
1181		ret = dio200_get_gate_src(subpriv, chan);
1182		if (ret < 0) {
1183			ret = -EINVAL;
1184			break;
1185		}
1186		data[2] = ret;
1187		break;
1188	case INSN_CONFIG_SET_CLOCK_SRC:
1189		ret = dio200_set_clock_src(subpriv, chan, data[1]);
1190		if (ret < 0)
1191			ret = -EINVAL;
1192		break;
1193	case INSN_CONFIG_GET_CLOCK_SRC:
1194		ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1195		if (ret < 0) {
1196			ret = -EINVAL;
1197			break;
1198		}
1199		data[1] = ret;
1200		break;
1201	default:
1202		ret = -EINVAL;
1203		break;
1204	}
1205	spin_unlock_irqrestore(&subpriv->spinlock, flags);
1206	return ret < 0 ? ret : insn->n;
1207}
1208
1209/*
1210 * This function initializes an '8254' counter subdevice.
1211 *
1212 * Note: iobase is the base address of the board, not the subdevice;
1213 * offset is the offset to the 8254 chip.
1214 */
1215static int
1216dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1217			unsigned long iobase, unsigned offset,
1218			int has_clk_gat_sce)
1219{
1220	struct dio200_subdev_8254 *subpriv;
1221	unsigned int chan;
1222
1223	subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1224	if (!subpriv) {
1225		printk(KERN_ERR "comedi%d: error! out of memory!\n",
1226		       dev->minor);
1227		return -ENOMEM;
1228	}
1229
1230	s->private = subpriv;
1231	s->type = COMEDI_SUBD_COUNTER;
1232	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1233	s->n_chan = 3;
1234	s->maxdata = 0xFFFF;
1235	s->insn_read = dio200_subdev_8254_read;
1236	s->insn_write = dio200_subdev_8254_write;
1237	s->insn_config = dio200_subdev_8254_config;
1238
1239	spin_lock_init(&subpriv->spinlock);
1240	subpriv->iobase = offset + iobase;
1241	subpriv->has_clk_gat_sce = has_clk_gat_sce;
1242	if (has_clk_gat_sce) {
1243		/* Derive CLK_SCE and GAT_SCE register offsets from
1244		 * 8254 offset. */
1245		subpriv->clk_sce_iobase =
1246		    DIO200_XCLK_SCE + (offset >> 3) + iobase;
1247		subpriv->gat_sce_iobase =
1248		    DIO200_XGAT_SCE + (offset >> 3) + iobase;
1249		subpriv->which = (offset >> 2) & 1;
1250	}
1251
1252	/* Initialize channels. */
1253	for (chan = 0; chan < 3; chan++) {
1254		i8254_set_mode(subpriv->iobase, 0, chan,
1255			       I8254_MODE0 | I8254_BINARY);
1256		if (subpriv->has_clk_gat_sce) {
1257			/* Gate source 0 is VCC (logic 1). */
1258			dio200_set_gate_src(subpriv, chan, 0);
1259			/* Clock source 0 is the dedicated clock input. */
1260			dio200_set_clock_src(subpriv, chan, 0);
1261		}
1262	}
1263
1264	return 0;
1265}
1266
1267/*
1268 * This function cleans up an '8254' counter subdevice.
1269 */
1270static void
1271dio200_subdev_8254_cleanup(struct comedi_device *dev,
1272			   struct comedi_subdevice *s)
1273{
1274	struct dio200_subdev_intr *subpriv = s->private;
1275	kfree(subpriv);
1276}
1277
1278/*
1279 * Attach is called by the Comedi core to configure the driver
1280 * for a particular board.  If you specified a board_name array
1281 * in the driver structure, dev->board_ptr contains that
1282 * address.
1283 */
1284static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1285{
1286	struct comedi_subdevice *s;
1287	unsigned long iobase = 0;
1288	unsigned int irq = 0;
1289#ifdef CONFIG_COMEDI_PCI
1290	struct pci_dev *pci_dev = NULL;
1291	int bus = 0, slot = 0;
1292#endif
1293	const struct dio200_layout_struct *layout;
1294	int share_irq = 0;
1295	int sdx;
1296	unsigned n;
1297	int ret;
1298
1299	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1300	       DIO200_DRIVER_NAME);
1301
1302	ret = alloc_private(dev, sizeof(struct dio200_private));
1303	if (ret < 0) {
1304		printk(KERN_ERR "comedi%d: error! out of memory!\n",
1305		       dev->minor);
1306		return ret;
1307	}
1308
1309	/* Process options. */
1310	switch (thisboard->bustype) {
1311	case isa_bustype:
1312		iobase = it->options[0];
1313		irq = it->options[1];
1314		share_irq = 0;
1315		break;
1316#ifdef CONFIG_COMEDI_PCI
1317	case pci_bustype:
1318		bus = it->options[0];
1319		slot = it->options[1];
1320		share_irq = 1;
1321
1322		ret = dio200_find_pci(dev, bus, slot, &pci_dev);
1323		if (ret < 0)
1324			return ret;
1325		devpriv->pci_dev = pci_dev;
1326		break;
1327#endif
1328	default:
1329		printk(KERN_ERR
1330		       "comedi%d: %s: BUG! cannot determine board type!\n",
1331		       dev->minor, DIO200_DRIVER_NAME);
1332		return -EINVAL;
1333		break;
1334	}
1335
1336	devpriv->intr_sd = -1;
1337
1338	/* Enable device and reserve I/O spaces. */
1339#ifdef CONFIG_COMEDI_PCI
1340	if (pci_dev) {
1341		ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1342		if (ret < 0) {
1343			printk(KERN_ERR
1344			       "comedi%d: error! cannot enable PCI device and request regions!\n",
1345			       dev->minor);
1346			return ret;
1347		}
1348		iobase = pci_resource_start(pci_dev, 2);
1349		irq = pci_dev->irq;
1350	} else
1351#endif
1352	{
1353		ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
1354		if (ret < 0)
1355			return ret;
1356	}
1357	dev->iobase = iobase;
1358
1359	layout = thislayout;
1360
1361	ret = alloc_subdevices(dev, layout->n_subdevs);
1362	if (ret < 0) {
1363		printk(KERN_ERR "comedi%d: error! out of memory!\n",
1364		       dev->minor);
1365		return ret;
1366	}
1367
1368	for (n = 0; n < dev->n_subdevices; n++) {
1369		s = &dev->subdevices[n];
1370		switch (layout->sdtype[n]) {
1371		case sd_8254:
1372			/* counter subdevice (8254) */
1373			ret = dio200_subdev_8254_init(dev, s, iobase,
1374						      layout->sdinfo[n],
1375						      layout->has_clk_gat_sce);
1376			if (ret < 0)
1377				return ret;
1378
1379			break;
1380		case sd_8255:
1381			/* digital i/o subdevice (8255) */
1382			ret = subdev_8255_init(dev, s, NULL,
1383					       iobase + layout->sdinfo[n]);
1384			if (ret < 0)
1385				return ret;
1386
1387			break;
1388		case sd_intr:
1389			/* 'INTERRUPT' subdevice */
1390			if (irq) {
1391				ret = dio200_subdev_intr_init(dev, s,
1392							      iobase +
1393							      DIO200_INT_SCE,
1394							      layout->sdinfo[n],
1395							      layout->
1396							      has_int_sce);
1397				if (ret < 0)
1398					return ret;
1399
1400				devpriv->intr_sd = n;
1401			} else {
1402				s->type = COMEDI_SUBD_UNUSED;
1403			}
1404			break;
1405		default:
1406			s->type = COMEDI_SUBD_UNUSED;
1407			break;
1408		}
1409	}
1410
1411	sdx = devpriv->intr_sd;
1412	if (sdx >= 0 && sdx < dev->n_subdevices)
1413		dev->read_subdev = &dev->subdevices[sdx];
1414
1415	dev->board_name = thisboard->name;
1416
1417	if (irq) {
1418		unsigned long flags = share_irq ? IRQF_SHARED : 0;
1419
1420		if (request_irq(irq, dio200_interrupt, flags,
1421				DIO200_DRIVER_NAME, dev) >= 0) {
1422			dev->irq = irq;
1423		} else {
1424			printk(KERN_WARNING
1425			       "comedi%d: warning! irq %u unavailable!\n",
1426			       dev->minor, irq);
1427		}
1428	}
1429
1430	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1431	if (thisboard->bustype == isa_bustype) {
1432		printk("(base %#lx) ", iobase);
1433	} else {
1434#ifdef CONFIG_COMEDI_PCI
1435		printk("(pci %s) ", pci_name(pci_dev));
1436#endif
1437	}
1438	if (irq)
1439		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1440	else
1441		printk("(no irq) ");
1442
1443	printk("attached\n");
1444
1445	return 1;
1446}
1447
1448/*
1449 * _detach is called to deconfigure a device.  It should deallocate
1450 * resources.
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.
1455 */
1456static int dio200_detach(struct comedi_device *dev)
1457{
1458	const struct dio200_layout_struct *layout;
1459	unsigned n;
1460
1461	printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1462	       DIO200_DRIVER_NAME);
1463
1464	if (dev->irq)
1465		free_irq(dev->irq, dev);
1466	if (dev->subdevices) {
1467		layout = thislayout;
1468		for (n = 0; n < dev->n_subdevices; n++) {
1469			struct comedi_subdevice *s = &dev->subdevices[n];
1470			switch (layout->sdtype[n]) {
1471			case sd_8254:
1472				dio200_subdev_8254_cleanup(dev, s);
1473				break;
1474			case sd_8255:
1475				subdev_8255_cleanup(dev, s);
1476				break;
1477			case sd_intr:
1478				dio200_subdev_intr_cleanup(dev, s);
1479				break;
1480			default:
1481				break;
1482			}
1483		}
1484	}
1485	if (devpriv) {
1486#ifdef CONFIG_COMEDI_PCI
1487		if (devpriv->pci_dev) {
1488			if (dev->iobase)
1489				comedi_pci_disable(devpriv->pci_dev);
1490			pci_dev_put(devpriv->pci_dev);
1491		} else
1492#endif
1493		{
1494			if (dev->iobase)
1495				release_region(dev->iobase, DIO200_IO_SIZE);
1496		}
1497	}
1498	if (dev->board_name)
1499		printk(KERN_INFO "comedi%d: %s removed\n",
1500		       dev->minor, dev->board_name);
1501
1502	return 0;
1503}
1504
1505MODULE_AUTHOR("Comedi http://www.comedi.org");
1506MODULE_DESCRIPTION("Comedi low-level driver");
1507MODULE_LICENSE("GPL");
1508