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