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