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