amplc_dio200.c revision a7f22a84ba2e5a99b874bf36a772b5d7424cec11
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};
464
465struct dio200_subdev_intr {
466	unsigned long iobase;
467	spinlock_t spinlock;
468	int active;
469	int has_int_sce;
470	unsigned int valid_isns;
471	unsigned int enabled_isns;
472	unsigned int stopcount;
473	int continuous;
474};
475
476/*
477 * The struct comedi_driver structure tells the Comedi core module
478 * which functions to call to configure/deconfigure (attach/detach)
479 * the board, and also about the kernel module that contains
480 * the device code.
481 */
482static int dio200_attach(struct comedi_device *dev,
483			 struct comedi_devconfig *it);
484static int dio200_detach(struct comedi_device *dev);
485static struct comedi_driver driver_amplc_dio200 = {
486	.driver_name = DIO200_DRIVER_NAME,
487	.module = THIS_MODULE,
488	.attach = dio200_attach,
489	.detach = dio200_detach,
490	.board_name = &dio200_boards[0].name,
491	.offset = sizeof(struct dio200_board),
492	.num_names = ARRAY_SIZE(dio200_boards),
493};
494
495#ifdef CONFIG_COMEDI_PCI
496COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
497#else
498COMEDI_INITCLEANUP(driver_amplc_dio200);
499#endif
500
501/*
502 * This function looks for a PCI device matching the requested board name,
503 * bus and slot.
504 */
505#ifdef CONFIG_COMEDI_PCI
506static int
507dio200_find_pci(struct comedi_device *dev, int bus, int slot,
508		struct pci_dev **pci_dev_p)
509{
510	struct pci_dev *pci_dev = NULL;
511
512	*pci_dev_p = NULL;
513
514	/* Look for matching PCI device. */
515	for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
516	     pci_dev != NULL;
517	     pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
518				      PCI_ANY_ID, pci_dev)) {
519		/* If bus/slot specified, check them. */
520		if (bus || slot) {
521			if (bus != pci_dev->bus->number
522			    || slot != PCI_SLOT(pci_dev->devfn))
523				continue;
524		}
525		if (thisboard->model == anypci_model) {
526			/* Match any supported model. */
527			int i;
528
529			for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
530				if (dio200_boards[i].bustype != pci_bustype)
531					continue;
532				if (pci_dev->device == dio200_boards[i].devid) {
533					/* Change board_ptr to matched board. */
534					dev->board_ptr = &dio200_boards[i];
535					break;
536				}
537			}
538			if (i == ARRAY_SIZE(dio200_boards))
539				continue;
540		} else {
541			/* Match specific model name. */
542			if (pci_dev->device != thisboard->devid)
543				continue;
544		}
545
546		/* Found a match. */
547		*pci_dev_p = pci_dev;
548		return 0;
549	}
550	/* No match found. */
551	if (bus || slot) {
552		printk(KERN_ERR
553		       "comedi%d: error! no %s found at pci %02x:%02x!\n",
554		       dev->minor, thisboard->name, bus, slot);
555	} else {
556		printk(KERN_ERR "comedi%d: error! no %s found!\n",
557		       dev->minor, thisboard->name);
558	}
559	return -EIO;
560}
561#endif
562
563/*
564 * This function checks and requests an I/O region, reporting an error
565 * if there is a conflict.
566 */
567static int
568dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
569{
570	if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
571		printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
572		       minor, from, extent);
573		return -EIO;
574	}
575	return 0;
576}
577
578/*
579 * 'insn_bits' function for an 'INTERRUPT' subdevice.
580 */
581static int
582dio200_subdev_intr_insn_bits(struct comedi_device *dev,
583			     struct comedi_subdevice *s,
584			     struct comedi_insn *insn, unsigned int *data)
585{
586	struct dio200_subdev_intr *subpriv = s->private;
587
588	if (subpriv->has_int_sce) {
589		/* Just read the interrupt status register.  */
590		data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
591	} else {
592		/* No interrupt status register. */
593		data[0] = 0;
594	}
595
596	return 2;
597}
598
599/*
600 * Called to stop acquisition for an 'INTERRUPT' subdevice.
601 */
602static void dio200_stop_intr(struct comedi_device *dev,
603			     struct comedi_subdevice *s)
604{
605	struct dio200_subdev_intr *subpriv = s->private;
606
607	subpriv->active = 0;
608	subpriv->enabled_isns = 0;
609	if (subpriv->has_int_sce)
610		outb(0, subpriv->iobase);
611}
612
613/*
614 * Called to start acquisition for an 'INTERRUPT' subdevice.
615 */
616static int dio200_start_intr(struct comedi_device *dev,
617			     struct comedi_subdevice *s)
618{
619	unsigned int n;
620	unsigned isn_bits;
621	struct dio200_subdev_intr *subpriv = s->private;
622	struct comedi_cmd *cmd = &s->async->cmd;
623	int retval = 0;
624
625	if (!subpriv->continuous && subpriv->stopcount == 0) {
626		/* An empty acquisition! */
627		s->async->events |= COMEDI_CB_EOA;
628		subpriv->active = 0;
629		retval = 1;
630	} else {
631		/* Determine interrupt sources to enable. */
632		isn_bits = 0;
633		if (cmd->chanlist) {
634			for (n = 0; n < cmd->chanlist_len; n++)
635				isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
636		}
637		isn_bits &= subpriv->valid_isns;
638		/* Enable interrupt sources. */
639		subpriv->enabled_isns = isn_bits;
640		if (subpriv->has_int_sce)
641			outb(isn_bits, subpriv->iobase);
642	}
643
644	return retval;
645}
646
647/*
648 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
649 */
650static int
651dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
652			  unsigned int trignum)
653{
654	struct dio200_subdev_intr *subpriv;
655	unsigned long flags;
656	int event = 0;
657
658	if (trignum != 0)
659		return -EINVAL;
660
661	subpriv = s->private;
662
663	spin_lock_irqsave(&subpriv->spinlock, flags);
664	s->async->inttrig = NULL;
665	if (subpriv->active)
666		event = dio200_start_intr(dev, s);
667
668	spin_unlock_irqrestore(&subpriv->spinlock, flags);
669
670	if (event)
671		comedi_event(dev, s);
672
673	return 1;
674}
675
676/*
677 * This is called from the interrupt service routine to handle a read
678 * scan on an 'INTERRUPT' subdevice.
679 */
680static int dio200_handle_read_intr(struct comedi_device *dev,
681				   struct comedi_subdevice *s)
682{
683	struct dio200_subdev_intr *subpriv = s->private;
684	unsigned triggered;
685	unsigned intstat;
686	unsigned cur_enabled;
687	unsigned int oldevents;
688	unsigned long flags;
689
690	triggered = 0;
691
692	spin_lock_irqsave(&subpriv->spinlock, flags);
693	oldevents = s->async->events;
694	if (subpriv->has_int_sce) {
695		/*
696		 * Collect interrupt sources that have triggered and disable
697		 * them temporarily.  Loop around until no extra interrupt
698		 * sources have triggered, at which point, the valid part of
699		 * the interrupt status register will read zero, clearing the
700		 * cause of the interrupt.
701		 *
702		 * Mask off interrupt sources already seen to avoid infinite
703		 * loop in case of misconfiguration.
704		 */
705		cur_enabled = subpriv->enabled_isns;
706		while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
707				   & ~triggered)) != 0) {
708			triggered |= intstat;
709			cur_enabled &= ~triggered;
710			outb(cur_enabled, subpriv->iobase);
711		}
712	} else {
713		/*
714		 * No interrupt status register.  Assume the single interrupt
715		 * source has triggered.
716		 */
717		triggered = subpriv->enabled_isns;
718	}
719
720	if (triggered) {
721		/*
722		 * Some interrupt sources have triggered and have been
723		 * temporarily disabled to clear the cause of the interrupt.
724		 *
725		 * Reenable them NOW to minimize the time they are disabled.
726		 */
727		cur_enabled = subpriv->enabled_isns;
728		if (subpriv->has_int_sce)
729			outb(cur_enabled, subpriv->iobase);
730
731		if (subpriv->active) {
732			/*
733			 * The command is still active.
734			 *
735			 * Ignore interrupt sources that the command isn't
736			 * interested in (just in case there's a race
737			 * condition).
738			 */
739			if (triggered & subpriv->enabled_isns) {
740				/* Collect scan data. */
741				short val;
742				unsigned int n, ch, len;
743
744				val = 0;
745				len = s->async->cmd.chanlist_len;
746				for (n = 0; n < len; n++) {
747					ch = CR_CHAN(s->async->cmd.chanlist[n]);
748					if (triggered & (1U << ch))
749						val |= (1U << n);
750				}
751				/* Write the scan to the buffer. */
752				if (comedi_buf_put(s->async, val)) {
753					s->async->events |= (COMEDI_CB_BLOCK |
754							     COMEDI_CB_EOS);
755				} else {
756					/* Error!  Stop acquisition.  */
757					dio200_stop_intr(dev, s);
758					s->async->events |= COMEDI_CB_ERROR
759					    | COMEDI_CB_OVERFLOW;
760					comedi_error(dev, "buffer overflow");
761				}
762
763				/* Check for end of acquisition. */
764				if (!subpriv->continuous) {
765					/* stop_src == TRIG_COUNT */
766					if (subpriv->stopcount > 0) {
767						subpriv->stopcount--;
768						if (subpriv->stopcount == 0) {
769							s->async->events |=
770							    COMEDI_CB_EOA;
771							dio200_stop_intr(dev,
772									 s);
773						}
774					}
775				}
776			}
777		}
778	}
779	spin_unlock_irqrestore(&subpriv->spinlock, flags);
780
781	if (oldevents != s->async->events)
782		comedi_event(dev, s);
783
784	return (triggered != 0);
785}
786
787/*
788 * 'cancel' function for an 'INTERRUPT' subdevice.
789 */
790static int dio200_subdev_intr_cancel(struct comedi_device *dev,
791				     struct comedi_subdevice *s)
792{
793	struct dio200_subdev_intr *subpriv = s->private;
794	unsigned long flags;
795
796	spin_lock_irqsave(&subpriv->spinlock, flags);
797	if (subpriv->active)
798		dio200_stop_intr(dev, s);
799
800	spin_unlock_irqrestore(&subpriv->spinlock, flags);
801
802	return 0;
803}
804
805/*
806 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
807 */
808static int
809dio200_subdev_intr_cmdtest(struct comedi_device *dev,
810			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
811{
812	int err = 0;
813	unsigned int tmp;
814
815	/* step 1: make sure trigger sources are trivially valid */
816
817	tmp = cmd->start_src;
818	cmd->start_src &= (TRIG_NOW | TRIG_INT);
819	if (!cmd->start_src || tmp != cmd->start_src)
820		err++;
821
822	tmp = cmd->scan_begin_src;
823	cmd->scan_begin_src &= TRIG_EXT;
824	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
825		err++;
826
827	tmp = cmd->convert_src;
828	cmd->convert_src &= TRIG_NOW;
829	if (!cmd->convert_src || tmp != cmd->convert_src)
830		err++;
831
832	tmp = cmd->scan_end_src;
833	cmd->scan_end_src &= TRIG_COUNT;
834	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
835		err++;
836
837	tmp = cmd->stop_src;
838	cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
839	if (!cmd->stop_src || tmp != cmd->stop_src)
840		err++;
841
842	if (err)
843		return 1;
844
845	/* step 2: make sure trigger sources are unique and mutually
846		   compatible */
847
848	/* these tests are true if more than one _src bit is set */
849	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
850		err++;
851	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
852		err++;
853	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
854		err++;
855	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
856		err++;
857	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
858		err++;
859
860	if (err)
861		return 2;
862
863	/* step 3: make sure arguments are trivially compatible */
864
865	/* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
866	if (cmd->start_arg != 0) {
867		cmd->start_arg = 0;
868		err++;
869	}
870
871	/* cmd->scan_begin_src == TRIG_EXT */
872	if (cmd->scan_begin_arg != 0) {
873		cmd->scan_begin_arg = 0;
874		err++;
875	}
876
877	/* cmd->convert_src == TRIG_NOW */
878	if (cmd->convert_arg != 0) {
879		cmd->convert_arg = 0;
880		err++;
881	}
882
883	/* cmd->scan_end_src == TRIG_COUNT */
884	if (cmd->scan_end_arg != cmd->chanlist_len) {
885		cmd->scan_end_arg = cmd->chanlist_len;
886		err++;
887	}
888
889	switch (cmd->stop_src) {
890	case TRIG_COUNT:
891		/* any count allowed */
892		break;
893	case TRIG_NONE:
894		if (cmd->stop_arg != 0) {
895			cmd->stop_arg = 0;
896			err++;
897		}
898		break;
899	default:
900		break;
901	}
902
903	if (err)
904		return 3;
905
906	/* step 4: fix up any arguments */
907
908	/* if (err) return 4; */
909
910	return 0;
911}
912
913/*
914 * 'do_cmd' function for an 'INTERRUPT' subdevice.
915 */
916static int dio200_subdev_intr_cmd(struct comedi_device *dev,
917				  struct comedi_subdevice *s)
918{
919	struct comedi_cmd *cmd = &s->async->cmd;
920	struct dio200_subdev_intr *subpriv = s->private;
921	unsigned long flags;
922	int event = 0;
923
924	spin_lock_irqsave(&subpriv->spinlock, flags);
925	subpriv->active = 1;
926
927	/* Set up end of acquisition. */
928	switch (cmd->stop_src) {
929	case TRIG_COUNT:
930		subpriv->continuous = 0;
931		subpriv->stopcount = cmd->stop_arg;
932		break;
933	default:
934		/* TRIG_NONE */
935		subpriv->continuous = 1;
936		subpriv->stopcount = 0;
937		break;
938	}
939
940	/* Set up start of acquisition. */
941	switch (cmd->start_src) {
942	case TRIG_INT:
943		s->async->inttrig = dio200_inttrig_start_intr;
944		break;
945	default:
946		/* TRIG_NOW */
947		event = dio200_start_intr(dev, s);
948		break;
949	}
950	spin_unlock_irqrestore(&subpriv->spinlock, flags);
951
952	if (event)
953		comedi_event(dev, s);
954
955	return 0;
956}
957
958/*
959 * This function initializes an 'INTERRUPT' subdevice.
960 */
961static int
962dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
963			unsigned long iobase, unsigned valid_isns,
964			int has_int_sce)
965{
966	struct dio200_subdev_intr *subpriv;
967
968	subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
969	if (!subpriv) {
970		printk(KERN_ERR "comedi%d: error! out of memory!\n",
971		       dev->minor);
972		return -ENOMEM;
973	}
974	subpriv->iobase = iobase;
975	subpriv->has_int_sce = has_int_sce;
976	subpriv->valid_isns = valid_isns;
977	spin_lock_init(&subpriv->spinlock);
978
979	if (has_int_sce)
980		outb(0, subpriv->iobase);	/* Disable interrupt sources. */
981
982	s->private = subpriv;
983	s->type = COMEDI_SUBD_DI;
984	s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
985	if (has_int_sce) {
986		s->n_chan = DIO200_MAX_ISNS;
987		s->len_chanlist = DIO200_MAX_ISNS;
988	} else {
989		/* No interrupt source register.  Support single channel. */
990		s->n_chan = 1;
991		s->len_chanlist = 1;
992	}
993	s->range_table = &range_digital;
994	s->maxdata = 1;
995	s->insn_bits = dio200_subdev_intr_insn_bits;
996	s->do_cmdtest = dio200_subdev_intr_cmdtest;
997	s->do_cmd = dio200_subdev_intr_cmd;
998	s->cancel = dio200_subdev_intr_cancel;
999
1000	return 0;
1001}
1002
1003/*
1004 * This function cleans up an 'INTERRUPT' subdevice.
1005 */
1006static void
1007dio200_subdev_intr_cleanup(struct comedi_device *dev,
1008			   struct comedi_subdevice *s)
1009{
1010	struct dio200_subdev_intr *subpriv = s->private;
1011	kfree(subpriv);
1012}
1013
1014/*
1015 * Interrupt service routine.
1016 */
1017static irqreturn_t dio200_interrupt(int irq, void *d)
1018{
1019	struct comedi_device *dev = d;
1020	int handled;
1021
1022	if (!dev->attached)
1023		return IRQ_NONE;
1024
1025	if (devpriv->intr_sd >= 0) {
1026		handled = dio200_handle_read_intr(dev,
1027						  dev->subdevices +
1028						  devpriv->intr_sd);
1029	} else {
1030		handled = 0;
1031	}
1032
1033	return IRQ_RETVAL(handled);
1034}
1035
1036/*
1037 * Handle 'insn_read' for an '8254' counter subdevice.
1038 */
1039static int
1040dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
1041			struct comedi_insn *insn, unsigned int *data)
1042{
1043	struct dio200_subdev_8254 *subpriv = s->private;
1044	int chan = CR_CHAN(insn->chanspec);
1045
1046	data[0] = i8254_read(subpriv->iobase, 0, chan);
1047
1048	return 1;
1049}
1050
1051/*
1052 * Handle 'insn_write' for an '8254' counter subdevice.
1053 */
1054static int
1055dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1056			 struct comedi_insn *insn, unsigned int *data)
1057{
1058	struct dio200_subdev_8254 *subpriv = s->private;
1059	int chan = CR_CHAN(insn->chanspec);
1060
1061	i8254_write(subpriv->iobase, 0, chan, data[0]);
1062
1063	return 1;
1064}
1065
1066/*
1067 * Set gate source for an '8254' counter subdevice channel.
1068 */
1069static int
1070dio200_set_gate_src(struct dio200_subdev_8254 *subpriv,
1071		    unsigned int counter_number, unsigned int gate_src)
1072{
1073	unsigned char byte;
1074
1075	if (!subpriv->has_clk_gat_sce)
1076		return -1;
1077	if (counter_number > 2)
1078		return -1;
1079	if (gate_src > 7)
1080		return -1;
1081
1082	subpriv->gate_src[counter_number] = gate_src;
1083	byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1084	outb(byte, subpriv->gat_sce_iobase);
1085
1086	return 0;
1087}
1088
1089/*
1090 * Get gate source for an '8254' counter subdevice channel.
1091 */
1092static int
1093dio200_get_gate_src(struct dio200_subdev_8254 *subpriv,
1094		    unsigned int counter_number)
1095{
1096	if (!subpriv->has_clk_gat_sce)
1097		return -1;
1098	if (counter_number > 2)
1099		return -1;
1100
1101	return subpriv->gate_src[counter_number];
1102}
1103
1104/*
1105 * Set clock source for an '8254' counter subdevice channel.
1106 */
1107static int
1108dio200_set_clock_src(struct dio200_subdev_8254 *subpriv,
1109		     unsigned int counter_number, unsigned int clock_src)
1110{
1111	unsigned char byte;
1112
1113	if (!subpriv->has_clk_gat_sce)
1114		return -1;
1115	if (counter_number > 2)
1116		return -1;
1117	if (clock_src > 7)
1118		return -1;
1119
1120	subpriv->clock_src[counter_number] = clock_src;
1121	byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1122	outb(byte, subpriv->clk_sce_iobase);
1123
1124	return 0;
1125}
1126
1127/*
1128 * Get clock source for an '8254' counter subdevice channel.
1129 */
1130static int
1131dio200_get_clock_src(struct dio200_subdev_8254 *subpriv,
1132		     unsigned int counter_number, unsigned int *period_ns)
1133{
1134	unsigned clock_src;
1135
1136	if (!subpriv->has_clk_gat_sce)
1137		return -1;
1138	if (counter_number > 2)
1139		return -1;
1140
1141	clock_src = subpriv->clock_src[counter_number];
1142	*period_ns = clock_period[clock_src];
1143	return clock_src;
1144}
1145
1146/*
1147 * Handle 'insn_config' for an '8254' counter subdevice.
1148 */
1149static int
1150dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1151			  struct comedi_insn *insn, unsigned int *data)
1152{
1153	struct dio200_subdev_8254 *subpriv = s->private;
1154	int ret;
1155	int chan = CR_CHAN(insn->chanspec);
1156
1157	switch (data[0]) {
1158	case INSN_CONFIG_SET_COUNTER_MODE:
1159		ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1160		if (ret < 0)
1161			return -EINVAL;
1162		break;
1163	case INSN_CONFIG_8254_READ_STATUS:
1164		data[1] = i8254_status(subpriv->iobase, 0, chan);
1165		break;
1166	case INSN_CONFIG_SET_GATE_SRC:
1167		ret = dio200_set_gate_src(subpriv, chan, data[2]);
1168		if (ret < 0)
1169			return -EINVAL;
1170		break;
1171	case INSN_CONFIG_GET_GATE_SRC:
1172		ret = dio200_get_gate_src(subpriv, chan);
1173		if (ret < 0)
1174			return -EINVAL;
1175		data[2] = ret;
1176		break;
1177	case INSN_CONFIG_SET_CLOCK_SRC:
1178		ret = dio200_set_clock_src(subpriv, chan, data[1]);
1179		if (ret < 0)
1180			return -EINVAL;
1181		break;
1182	case INSN_CONFIG_GET_CLOCK_SRC:
1183		ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1184		if (ret < 0)
1185			return -EINVAL;
1186		data[1] = ret;
1187		break;
1188	default:
1189		return -EINVAL;
1190		break;
1191	}
1192	return insn->n;
1193}
1194
1195/*
1196 * This function initializes an '8254' counter subdevice.
1197 *
1198 * Note: iobase is the base address of the board, not the subdevice;
1199 * offset is the offset to the 8254 chip.
1200 */
1201static int
1202dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1203			unsigned long iobase, unsigned offset,
1204			int has_clk_gat_sce)
1205{
1206	struct dio200_subdev_8254 *subpriv;
1207	unsigned int chan;
1208
1209	subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1210	if (!subpriv) {
1211		printk(KERN_ERR "comedi%d: error! out of memory!\n",
1212		       dev->minor);
1213		return -ENOMEM;
1214	}
1215
1216	s->private = subpriv;
1217	s->type = COMEDI_SUBD_COUNTER;
1218	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1219	s->n_chan = 3;
1220	s->maxdata = 0xFFFF;
1221	s->insn_read = dio200_subdev_8254_read;
1222	s->insn_write = dio200_subdev_8254_write;
1223	s->insn_config = dio200_subdev_8254_config;
1224
1225	subpriv->iobase = offset + iobase;
1226	subpriv->has_clk_gat_sce = has_clk_gat_sce;
1227	if (has_clk_gat_sce) {
1228		/* Derive CLK_SCE and GAT_SCE register offsets from
1229		 * 8254 offset. */
1230		subpriv->clk_sce_iobase =
1231		    DIO200_XCLK_SCE + (offset >> 3) + iobase;
1232		subpriv->gat_sce_iobase =
1233		    DIO200_XGAT_SCE + (offset >> 3) + iobase;
1234		subpriv->which = (offset >> 2) & 1;
1235	}
1236
1237	/* Initialize channels. */
1238	for (chan = 0; chan < 3; chan++) {
1239		i8254_set_mode(subpriv->iobase, 0, chan,
1240			       I8254_MODE0 | I8254_BINARY);
1241		if (subpriv->has_clk_gat_sce) {
1242			/* Gate source 0 is VCC (logic 1). */
1243			dio200_set_gate_src(subpriv, chan, 0);
1244			/* Clock source 0 is the dedicated clock input. */
1245			dio200_set_clock_src(subpriv, chan, 0);
1246		}
1247	}
1248
1249	return 0;
1250}
1251
1252/*
1253 * This function cleans up an '8254' counter subdevice.
1254 */
1255static void
1256dio200_subdev_8254_cleanup(struct comedi_device *dev,
1257			   struct comedi_subdevice *s)
1258{
1259	struct dio200_subdev_intr *subpriv = s->private;
1260	kfree(subpriv);
1261}
1262
1263/*
1264 * Attach is called by the Comedi core to configure the driver
1265 * for a particular board.  If you specified a board_name array
1266 * in the driver structure, dev->board_ptr contains that
1267 * address.
1268 */
1269static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1270{
1271	struct comedi_subdevice *s;
1272	unsigned long iobase = 0;
1273	unsigned int irq = 0;
1274#ifdef CONFIG_COMEDI_PCI
1275	struct pci_dev *pci_dev = NULL;
1276	int bus = 0, slot = 0;
1277#endif
1278	const struct dio200_layout_struct *layout;
1279	int share_irq = 0;
1280	int sdx;
1281	unsigned n;
1282	int ret;
1283
1284	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1285	       DIO200_DRIVER_NAME);
1286
1287	ret = alloc_private(dev, sizeof(struct dio200_private));
1288	if (ret < 0) {
1289		printk(KERN_ERR "comedi%d: error! out of memory!\n",
1290		       dev->minor);
1291		return ret;
1292	}
1293
1294	/* Process options. */
1295	switch (thisboard->bustype) {
1296	case isa_bustype:
1297		iobase = it->options[0];
1298		irq = it->options[1];
1299		share_irq = 0;
1300		break;
1301#ifdef CONFIG_COMEDI_PCI
1302	case pci_bustype:
1303		bus = it->options[0];
1304		slot = it->options[1];
1305		share_irq = 1;
1306
1307		ret = dio200_find_pci(dev, bus, slot, &pci_dev);
1308		if (ret < 0)
1309			return ret;
1310		devpriv->pci_dev = pci_dev;
1311		break;
1312#endif
1313	default:
1314		printk(KERN_ERR
1315		       "comedi%d: %s: BUG! cannot determine board type!\n",
1316		       dev->minor, DIO200_DRIVER_NAME);
1317		return -EINVAL;
1318		break;
1319	}
1320
1321	devpriv->intr_sd = -1;
1322
1323	/* Enable device and reserve I/O spaces. */
1324#ifdef CONFIG_COMEDI_PCI
1325	if (pci_dev) {
1326		ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1327		if (ret < 0) {
1328			printk(KERN_ERR
1329			       "comedi%d: error! cannot enable PCI device and request regions!\n",
1330			       dev->minor);
1331			return ret;
1332		}
1333		iobase = pci_resource_start(pci_dev, 2);
1334		irq = pci_dev->irq;
1335	} else
1336#endif
1337	{
1338		ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
1339		if (ret < 0)
1340			return ret;
1341	}
1342	dev->iobase = iobase;
1343
1344	layout = thislayout;
1345
1346	ret = alloc_subdevices(dev, layout->n_subdevs);
1347	if (ret < 0) {
1348		printk(KERN_ERR "comedi%d: error! out of memory!\n",
1349		       dev->minor);
1350		return ret;
1351	}
1352
1353	for (n = 0; n < dev->n_subdevices; n++) {
1354		s = &dev->subdevices[n];
1355		switch (layout->sdtype[n]) {
1356		case sd_8254:
1357			/* counter subdevice (8254) */
1358			ret = dio200_subdev_8254_init(dev, s, iobase,
1359						      layout->sdinfo[n],
1360						      layout->has_clk_gat_sce);
1361			if (ret < 0)
1362				return ret;
1363
1364			break;
1365		case sd_8255:
1366			/* digital i/o subdevice (8255) */
1367			ret = subdev_8255_init(dev, s, NULL,
1368					       iobase + layout->sdinfo[n]);
1369			if (ret < 0)
1370				return ret;
1371
1372			break;
1373		case sd_intr:
1374			/* 'INTERRUPT' subdevice */
1375			if (irq) {
1376				ret = dio200_subdev_intr_init(dev, s,
1377							      iobase +
1378							      DIO200_INT_SCE,
1379							      layout->sdinfo[n],
1380							      layout->
1381							      has_int_sce);
1382				if (ret < 0)
1383					return ret;
1384
1385				devpriv->intr_sd = n;
1386			} else {
1387				s->type = COMEDI_SUBD_UNUSED;
1388			}
1389			break;
1390		default:
1391			s->type = COMEDI_SUBD_UNUSED;
1392			break;
1393		}
1394	}
1395
1396	sdx = devpriv->intr_sd;
1397	if (sdx >= 0 && sdx < dev->n_subdevices)
1398		dev->read_subdev = &dev->subdevices[sdx];
1399
1400	dev->board_name = thisboard->name;
1401
1402	if (irq) {
1403		unsigned long flags = share_irq ? IRQF_SHARED : 0;
1404
1405		if (request_irq(irq, dio200_interrupt, flags,
1406				DIO200_DRIVER_NAME, dev) >= 0) {
1407			dev->irq = irq;
1408		} else {
1409			printk(KERN_WARNING
1410			       "comedi%d: warning! irq %u unavailable!\n",
1411			       dev->minor, irq);
1412		}
1413	}
1414
1415	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1416	if (thisboard->bustype == isa_bustype) {
1417		printk("(base %#lx) ", iobase);
1418	} else {
1419#ifdef CONFIG_COMEDI_PCI
1420		printk("(pci %s) ", pci_name(pci_dev));
1421#endif
1422	}
1423	if (irq)
1424		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1425	else
1426		printk("(no irq) ");
1427
1428	printk("attached\n");
1429
1430	return 1;
1431}
1432
1433/*
1434 * _detach is called to deconfigure a device.  It should deallocate
1435 * resources.
1436 * This function is also called when _attach() fails, so it should be
1437 * careful not to release resources that were not necessarily
1438 * allocated by _attach().  dev->private and dev->subdevices are
1439 * deallocated automatically by the core.
1440 */
1441static int dio200_detach(struct comedi_device *dev)
1442{
1443	const struct dio200_layout_struct *layout;
1444	unsigned n;
1445
1446	printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1447	       DIO200_DRIVER_NAME);
1448
1449	if (dev->irq)
1450		free_irq(dev->irq, dev);
1451	if (dev->subdevices) {
1452		layout = thislayout;
1453		for (n = 0; n < dev->n_subdevices; n++) {
1454			struct comedi_subdevice *s = &dev->subdevices[n];
1455			switch (layout->sdtype[n]) {
1456			case sd_8254:
1457				dio200_subdev_8254_cleanup(dev, s);
1458				break;
1459			case sd_8255:
1460				subdev_8255_cleanup(dev, s);
1461				break;
1462			case sd_intr:
1463				dio200_subdev_intr_cleanup(dev, s);
1464				break;
1465			default:
1466				break;
1467			}
1468		}
1469	}
1470	if (devpriv) {
1471#ifdef CONFIG_COMEDI_PCI
1472		if (devpriv->pci_dev) {
1473			if (dev->iobase)
1474				comedi_pci_disable(devpriv->pci_dev);
1475			pci_dev_put(devpriv->pci_dev);
1476		} else
1477#endif
1478		{
1479			if (dev->iobase)
1480				release_region(dev->iobase, DIO200_IO_SIZE);
1481		}
1482	}
1483	if (dev->board_name)
1484		printk(KERN_INFO "comedi%d: %s removed\n",
1485		       dev->minor, dev->board_name);
1486
1487	return 0;
1488}
1489