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