5e8a394fbdb915d075ef139affe0699b8db9f8bf
[comedi.git] / comedi / drivers / amplc_dio200.c
1 /*
2     comedi/drivers/amplc_dio200.c
3     Driver for various Amplicon 200 series 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-2012 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
29 Description: Amplicon 200 Series Digital I/O
30 Author: Ian Abbott <abbotti@mev.co.uk>
31 Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e),
32   PCI215 (pci215 or amplc_dio200), PCIe215 (pcie215 or amplc_dio200),
33   PC218E (pc218e), PCIe236 (pcie236 or amplc_dio200), PC272E (pc272e),
34   PCI272 (pci272 or amplc_dio200), PCIe296 (pcie296 or amplc_dio200)
35 Updated: Wed, 16 May 2012 13:57:58 +0100
36 Status: works
37
38 Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E:
39   [0] - I/O port base address
40   [1] - IRQ (optional, but commands won't work without it)
41
42 Configuration options - PCI215, PCIe215, PCIe236, PCI272, PCIe296:
43   [0] - PCI bus of device (optional)
44   [1] - PCI slot of device (optional)
45   If bus/slot is not specified, the first available PCI device will
46   be used.
47
48 Passing a zero for an option is the same as leaving it unspecified.
49
50 SUBDEVICES
51
52                     PC212E         PC214E      PC215E/PCI215
53                  -------------  -------------  -------------
54   Subdevices           6              4              5
55    0                 PPI-X          PPI-X          PPI-X
56    1                 CTR-Y1         PPI-Y          PPI-Y
57    2                 CTR-Y2         CTR-Z1*        CTR-Z1
58    3                 CTR-Z1       INTERRUPT*       CTR-Z2
59    4                 CTR-Z2                      INTERRUPT
60    5               INTERRUPT
61
62                     PCIe215        PC218E         PCIe236
63                  -------------  -------------  -------------
64   Subdevices           8              7              8
65    0                 PPI-X          CTR-X1         PPI-X
66    1                 UNUSED         CTR-X2         UNUSED
67    2                 PPI-Y          CTR-Y1         UNUSED
68    3                 UNUSED         CTR-Y2         UNUSED
69    4                 CTR-Z1         CTR-Z1         CTR-Z1
70    5                 CTR-Z2         CTR-Z2         CTR-Z2
71    6                 TIMER        INTERRUPT        TIMER
72    7               INTERRUPT                     INTERRUPT
73
74                  PC272E/PCI272     PCIe296
75                  -------------  -------------
76   Subdevices           4              8
77    0                 PPI-X          PPI-X1
78    1                 PPI-Y          PPI-X2
79    2                 PPI-Z          PPI-Y1
80    3               INTERRUPT        PPI-Y2
81    4                                CTR-Z1
82    5                                CTR-Z2
83    6                                TIMER
84    7                              INTERRUPT
85
86 Each PPI is a 8255 chip providing 24 DIO channels.  The DIO channels
87 are configurable as inputs or outputs in four groups:
88
89   Port A  - channels  0 to  7
90   Port B  - channels  8 to 15
91   Port CL - channels 16 to 19
92   Port CH - channels 20 to 23
93
94 Only mode 0 of the 8255 chips is supported.
95
96 Each CTR is a 8254 chip providing 3 16-bit counter channels.  Each
97 channel is configured individually with INSN_CONFIG instructions.  The
98 specific type of configuration instruction is specified in data[0].
99 Some configuration instructions expect an additional parameter in
100 data[1]; others return a value in data[1].  The following configuration
101 instructions are supported:
102
103   INSN_CONFIG_SET_COUNTER_MODE.  Sets the counter channel's mode and
104     BCD/binary setting specified in data[1].
105
106   INSN_CONFIG_8254_READ_STATUS.  Reads the status register value for the
107     counter channel into data[1].
108
109   INSN_CONFIG_SET_CLOCK_SRC.  Sets the counter channel's clock source as
110     specified in data[1] (this is a hardware-specific value).  Not
111     supported on PC214E.  For the other boards, valid clock sources are
112     0 to 7 as follows:
113
114       0.  CLK n, the counter channel's dedicated CLK input from the SK1
115         connector.  (N.B. for other values, the counter channel's CLKn
116         pin on the SK1 connector is an output!)
117       1.  Internal 10 MHz clock.
118       2.  Internal 1 MHz clock.
119       3.  Internal 100 kHz clock.
120       4.  Internal 10 kHz clock.
121       5.  Internal 1 kHz clock.
122       6.  OUT n-1, the output of counter channel n-1 (see note 1 below).
123       7.  Ext Clock, the counter chip's dedicated Ext Clock input from
124         the SK1 connector.  This pin is shared by all three counter
125         channels on the chip.
126
127   INSN_CONFIG_GET_CLOCK_SRC.  Returns the counter channel's current
128     clock source in data[1].  For internal clock sources, data[2] is set
129     to the period in ns.
130
131   INSN_CONFIG_SET_GATE_SRC.  Sets the counter channel's gate source as
132     specified in data[2] (this is a hardware-specific value).  Not
133     supported on PC214E.  For the other boards, valid gate sources are 0
134     to 7 as follows:
135
136       0.  VCC (internal +5V d.c.), i.e. gate permanently enabled.
137       1.  GND (internal 0V d.c.), i.e. gate permanently disabled.
138       2.  GAT n, the counter channel's dedicated GAT input from the SK1
139         connector.  (N.B. for other values, the counter channel's GATn
140         pin on the SK1 connector is an output!)
141       3.  /OUT n-2, the inverted output of counter channel n-2 (see note
142         2 below).
143       4.  Reserved.
144       5.  Reserved.
145       6.  Reserved.
146       7.  Reserved.
147
148   INSN_CONFIG_GET_GATE_SRC.  Returns the counter channel's current gate
149     source in data[2].
150
151 Clock and gate interconnection notes:
152
153   1.  Clock source OUT n-1 is the output of the preceding channel on the
154   same counter subdevice if n > 0, or the output of channel 2 on the
155   preceding counter subdevice (see note 3) if n = 0.
156
157   2.  Gate source /OUT n-2 is the inverted output of channel 0 on the
158   same counter subdevice if n = 2, or the inverted output of channel n+1
159   on the preceding counter subdevice (see note 3) if n < 2.
160
161   3.  The counter subdevices are connected in a ring, so the highest
162   counter subdevice precedes the lowest.
163
164 The 'TIMER' subdevice is a free-running 32-bit timer subdevice.
165
166 The 'INTERRUPT' subdevice pretends to be a digital input subdevice.  The
167 digital inputs come from the interrupt status register.  The number of
168 channels matches the number of interrupt sources.  The PC214E does not
169 have an interrupt status register; see notes on 'INTERRUPT SOURCES'
170 below.
171
172 INTERRUPT SOURCES
173
174                     PC212E         PC214E      PC215E/PCI215
175                  -------------  -------------  -------------
176   Sources              6              1              6
177    0               PPI-X-C0       JUMPER-J5      PPI-X-C0
178    1               PPI-X-C3                      PPI-X-C3
179    2              CTR-Y1-OUT                     PPI-Y-C0
180    3              CTR-Y2-OUT                     PPI-Y-C3
181    4              CTR-Z1-OUT                    CTR-Z1-OUT
182    5              CTR-Z2-OUT                    CTR-Z2-OUT
183
184                     PCIe215        PC218E         PCIe236
185                  -------------  -------------  -------------
186   Sources              6              6              6
187    0               PPI-X-C0      CTR-X1-OUT      PPI-X-C0
188    1               PPI-X-C3      CTR-X2-OUT      PPI-X-C3
189    2               PPI-Y-C0      CTR-Y1-OUT       unused
190    3               PPI-Y-C3      CTR-Y2-OUT       unused
191    4              CTR-Z1-OUT     CTR-Z1-OUT     CTR-Z1-OUT
192    5              CTR-Z2-OUT     CTR-Z2-OUT     CTR-Z2-OUT
193
194                  PC272E/PCI272     PCIe296
195                  -------------  -------------
196   Sources              6              6
197    0               PPI-X-C0       PPI-X1-C0
198    1               PPI-X-C3       PPI-X1-C3
199    2               PPI-Y-C0       PPI-Y1-C0
200    3               PPI-Y-C3       PPI-Y2-C3
201    4               PPI-Z-C0      CTR-Z1-OUT
202    5               PPI-Z-C3      CTR-Z2-OUT
203
204 When an interrupt source is enabled in the interrupt source enable
205 register, a rising edge on the source signal latches the corresponding
206 bit to 1 in the interrupt status register.
207
208 When the interrupt status register value as a whole (actually, just the
209 6 least significant bits) goes from zero to non-zero, the board will
210 generate an interrupt.  For level-triggered hardware interrupts (PCI
211 card), the interrupt will remain asserted until the interrupt status
212 register is cleared to zero.  For edge-triggered hardware interrupts
213 (ISA card), no further interrupts will occur until the interrupt status
214 register is cleared to zero.  To clear a bit to zero in the interrupt
215 status register, the corresponding interrupt source must be disabled
216 in the interrupt source enable register (there is no separate interrupt
217 clear register).
218
219 The PC214E does not have an interrupt source enable register or an
220 interrupt status register; its 'INTERRUPT' subdevice has a single
221 channel and its interrupt source is selected by the position of jumper
222 J5.
223
224 COMMANDS
225
226 The driver supports a read streaming acquisition command on the
227 'INTERRUPT' subdevice.  The channel list selects the interrupt sources
228 to be enabled.  All channels will be sampled together (convert_src ==
229 TRIG_NOW).  The scan begins a short time after the hardware interrupt
230 occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT,
231 scan_begin_arg == 0).  The value read from the interrupt status register
232 is packed into a sampl_t value, one bit per requested channel, in the
233 order they appear in the channel list.
234 */
235
236 #include <linux/comedidev.h>
237
238 #include "comedi_pci.h"
239
240 #include "8255.h"
241 #include "8253.h"
242
243 #define DIO200_DRIVER_NAME      "amplc_dio200"
244
245 /* PCI IDs */
246 /* #define PCI_VENDOR_ID_AMPLICON 0x14dc */
247 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
248 #define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
249 #define PCI_DEVICE_ID_AMPLICON_PCIE236 0x0011
250 #define PCI_DEVICE_ID_AMPLICON_PCIE215 0x0012
251 #define PCI_DEVICE_ID_AMPLICON_PCIE296 0x0014
252 #define PCI_DEVICE_ID_INVALID 0xffff
253
254 /* 8255 control register bits */
255 #define CR_C_LO_IO      0x01
256 #define CR_B_IO         0x02
257 #define CR_B_MODE       0x04
258 #define CR_C_HI_IO      0x08
259 #define CR_A_IO         0x10
260 #define CR_A_MODE(a)    ((a)<<5)
261 #define CR_CW           0x80
262
263 /* 200 series registers */
264 #define DIO200_IO_SIZE          0x20
265 #define DIO200_PCIE_IO_SIZE     0x4000
266 #define DIO200_XCLK_SCE         0x18    /* Group X clock selection register */
267 #define DIO200_YCLK_SCE         0x19    /* Group Y clock selection register */
268 #define DIO200_ZCLK_SCE         0x1a    /* Group Z clock selection register */
269 #define DIO200_XGAT_SCE         0x1b    /* Group X gate selection register */
270 #define DIO200_YGAT_SCE         0x1c    /* Group Y gate selection register */
271 #define DIO200_ZGAT_SCE         0x1d    /* Group Z gate selection register */
272 #define DIO200_INT_SCE          0x1e    /* Interrupt enable/status register */
273 /* Extra registers for new PCIe boards */
274 #define DIO200_ENHANCE          0x20    /* 1 to enable enhanced features */
275 #define DIO200_VERSION          0x24    /* Hardware version */
276
277 /*
278  * Macros for constructing value for DIO_200_?CLK_SCE and
279  * DIO_200_?GAT_SCE registers:
280  *
281  * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
282  * 'chan' is the channel: 0, 1 or 2.
283  * 'source' is the signal source: 0 to 7.
284  */
285 #define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
286 #define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
287
288 /*
289  * Periods of the internal clock sources in nanoseconds.
290  */
291 static const unsigned clock_period[8] = {
292         0,                      /* dedicated clock input/output pin */
293         100,                    /* 10 MHz */
294         1000,                   /* 1 MHz */
295         10000,                  /* 100 kHz */
296         100000,                 /* 10 kHz */
297         1000000,                /* 1 kHz */
298         0,                      /* OUT N-1 */
299         0                       /* group clock input pin */
300 };
301
302 /*
303  * Register region.
304  */
305 enum dio200_regtype { no_regtype, io_regtype, mmio_regtype };
306 struct dio200_region {
307         union {
308                 unsigned long iobase;           /* I/O base address */
309                 unsigned char __iomem *membase; /* Mapped MMIO base address */
310         } u;
311         unsigned char regtype;
312         unsigned char regshift;
313 };
314
315 /*
316  * Board descriptions.
317  */
318
319 enum dio200_bustype { isa_bustype, pci_bustype };
320
321 enum dio200_model {
322         pc212e_model,
323         pc214e_model,
324         pc215e_model, pci215_model, pcie215_model,
325         pc218e_model,
326         pcie236_model,
327         pc272e_model, pci272_model,
328         pcie296_model,
329         anypci_model
330 };
331
332 enum dio200_layout {
333         pc212_layout,
334         pc214_layout,
335         pc215_layout,
336         pc218_layout,
337         pc272_layout,
338 #ifdef CONFIG_COMEDI_PCI
339         pcie215_layout,
340         pcie236_layout,
341         pcie296_layout,
342 #endif
343         num_layouts
344 };
345
346 typedef struct dio200_board_struct {
347         const char *name;
348         unsigned short devid;
349         enum dio200_bustype bustype;
350         enum dio200_model model;
351         enum dio200_layout layout;
352         unsigned char mainbar;
353         unsigned char mainshift;
354         unsigned int mainsize;
355 } dio200_board;
356
357 static const dio200_board dio200_boards[] = {
358         {
359               name:     "pc212e",
360               bustype:  isa_bustype,
361               model:    pc212e_model,
362               layout:   pc212_layout,
363               mainsize: DIO200_IO_SIZE,
364                 },
365         {
366               name:     "pc214e",
367               bustype:  isa_bustype,
368               model:    pc214e_model,
369               layout:   pc214_layout,
370               mainsize: DIO200_IO_SIZE,
371                 },
372         {
373               name:     "pc215e",
374               bustype:  isa_bustype,
375               model:    pc215e_model,
376               layout:   pc215_layout,
377               mainsize: DIO200_IO_SIZE,
378                 },
379 #ifdef CONFIG_COMEDI_PCI
380         {
381               name:     "pci215",
382               devid:    PCI_DEVICE_ID_AMPLICON_PCI215,
383               bustype:  pci_bustype,
384               model:    pci215_model,
385               layout:   pc215_layout,
386               mainsize: DIO200_IO_SIZE,
387               mainbar:  2,
388                 },
389 #endif
390 #ifdef CONFIG_COMEDI_PCI
391         {
392               name:     "pcie215",
393               devid:    PCI_DEVICE_ID_AMPLICON_PCIE215,
394               bustype:  pci_bustype,
395               model:    pcie215_model,
396               layout:   pcie215_layout,
397               mainsize: DIO200_PCIE_IO_SIZE,
398               mainbar:  1,
399               mainshift: 3,
400                 },
401 #endif
402         {
403               name:     "pc218e",
404               bustype:  isa_bustype,
405               model:    pc218e_model,
406               layout:   pc218_layout,
407               mainsize: DIO200_IO_SIZE,
408                 },
409 #ifdef CONFIG_COMEDI_PCI
410         {
411               name:     "pcie236",
412               devid:    PCI_DEVICE_ID_AMPLICON_PCIE236,
413               bustype:  pci_bustype,
414               model:    pcie236_model,
415               layout:   pcie236_layout,
416               mainsize: DIO200_PCIE_IO_SIZE,
417               mainbar:  1,
418               mainshift: 3,
419                 },
420 #endif
421         {
422               name:     "pc272e",
423               bustype:  isa_bustype,
424               model:    pc272e_model,
425               layout:   pc272_layout,
426               mainsize: DIO200_IO_SIZE,
427                 },
428 #ifdef CONFIG_COMEDI_PCI
429         {
430               name:     "pci272",
431               devid:    PCI_DEVICE_ID_AMPLICON_PCI272,
432               bustype:  pci_bustype,
433               model:    pci272_model,
434               layout:   pc272_layout,
435               mainsize: DIO200_IO_SIZE,
436               mainbar:  2,
437                 },
438 #endif
439 #ifdef CONFIG_COMEDI_PCI
440         {
441               name:     "pcie296",
442               devid:    PCI_DEVICE_ID_AMPLICON_PCIE296,
443               bustype:  pci_bustype,
444               model:    pcie296_model,
445               layout:   pcie296_layout,
446               mainsize: DIO200_PCIE_IO_SIZE,
447               mainbar:  1,
448               mainshift: 3,
449                 },
450 #endif
451 #ifdef CONFIG_COMEDI_PCI
452         {
453               name:     DIO200_DRIVER_NAME,
454               devid:    PCI_DEVICE_ID_INVALID,
455               bustype:  pci_bustype,
456               model:    anypci_model,   /* wildcard */
457                 },
458 #endif
459 };
460
461 /*
462  * Layout descriptions - some ISA and PCI board descriptions share the same
463  * layout.
464  */
465
466 enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254, sd_timer };
467
468 #define DIO200_MAX_SUBDEVS      8
469 #define DIO200_MAX_ISNS         6
470
471 typedef struct dio200_layout_struct {
472         unsigned short n_subdevs;       /* number of subdevices */
473         unsigned char sdtype[DIO200_MAX_SUBDEVS];       /* enum dio200_sdtype */
474         unsigned char sdinfo[DIO200_MAX_SUBDEVS];       /* depends on sdtype */
475         char has_int_sce;       /* has interrupt enable/status register */
476         char has_clk_gat_sce;   /* has clock/gate selection registers */
477         char has_enhancements;  /* has enhanced features */
478 } dio200_layout;
479
480 static const dio200_layout dio200_layouts[] = {
481         [pc212_layout] = {
482               n_subdevs:6,
483               sdtype:   {sd_8255, sd_8254, sd_8254, sd_8254,
484                                         sd_8254,
485                                 sd_intr},
486               sdinfo:   {0x00, 0x08, 0x0C, 0x10, 0x14,
487                                 0x3F},
488               has_int_sce:1,
489               has_clk_gat_sce:1,
490               has_enhancements:0,
491                 },
492         [pc214_layout] = {
493               n_subdevs:4,
494               sdtype:   {sd_8255, sd_8255, sd_8254,
495                                 sd_intr},
496               sdinfo:   {0x00, 0x08, 0x10, 0x01},
497               has_int_sce:0,
498               has_clk_gat_sce:0,
499               has_enhancements:0,
500                 },
501         [pc215_layout] = {
502               n_subdevs:5,
503               sdtype:   {sd_8255, sd_8255, sd_8254,
504                                         sd_8254,
505                                 sd_intr},
506               sdinfo:   {0x00, 0x08, 0x10, 0x14, 0x3F},
507               has_int_sce:1,
508               has_clk_gat_sce:1,
509               has_enhancements:0,
510                 },
511         [pc218_layout] = {
512               n_subdevs:7,
513               sdtype:   {sd_8254, sd_8254, sd_8255, sd_8254,
514                                         sd_8254,
515                                 sd_intr},
516               sdinfo:   {0x00, 0x04, 0x08, 0x0C, 0x10,
517                                         0x14,
518                                 0x3F},
519               has_int_sce:1,
520               has_clk_gat_sce:1,
521               has_enhancements:0,
522                 },
523         [pc272_layout] = {
524               n_subdevs:4,
525               sdtype:   {sd_8255, sd_8255, sd_8255,
526                                 sd_intr},
527               sdinfo:   {0x00, 0x08, 0x10, 0x3F},
528               has_int_sce:1,
529               has_clk_gat_sce:0,
530               has_enhancements:0,
531                 },
532 #ifdef CONFIG_COMEDI_PCI
533         [pcie215_layout] = {
534               n_subdevs:8,
535               sdtype:   {sd_8255, sd_none, sd_8255, sd_none, sd_8254, sd_8254,
536                                 sd_timer, sd_intr},
537               sdinfo:   {0x00, 0x00, 0x08, 0x00, 0x10, 0x14, 0x00, 0x3F},
538               has_int_sce:1,
539               has_clk_gat_sce:1,
540               has_enhancements:1,
541                 },
542         [pcie236_layout] = {
543               n_subdevs:8,
544               sdtype:   {sd_8255, sd_none, sd_none, sd_none, sd_8254, sd_8254,
545                                 sd_timer, sd_intr},
546               sdinfo:   {0x00, 0x00, 0x00, 0x00, 0x10, 0x14, 0x00, 0x3F},
547               has_int_sce:1,
548               has_clk_gat_sce:1,
549               has_enhancements:1,
550                 },
551         [pcie296_layout] = {
552               n_subdevs:8,
553               sdtype:   {sd_8255, sd_8255, sd_8255, sd_8255, sd_8254, sd_8254,
554                                 sd_timer, sd_intr},
555               sdinfo:   {0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x00, 0x3F},
556               has_int_sce:1,
557               has_clk_gat_sce:1,
558               has_enhancements:1,
559                 },
560 #endif
561 };
562
563 /*
564  * PCI driver table.
565  */
566
567 #ifdef CONFIG_COMEDI_PCI
568 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
569         {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
570                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
571         {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
572                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
573         {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE236,
574                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
575         {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE215,
576                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
577         {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE296,
578                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
579         {0}
580 };
581
582 MODULE_DEVICE_TABLE(pci, dio200_pci_table);
583 #endif /* CONFIG_COMEDI_PCI */
584
585 /*
586  * Useful for shorthand access to the particular board structure
587  */
588 #define thisboard ((const dio200_board *)dev->board_ptr)
589 #define thislayout (&dio200_layouts[((dio200_board *)dev->board_ptr)->layout])
590
591 /* this structure is for data unique to this hardware driver.  If
592    several hardware drivers keep similar information in this structure,
593    feel free to suggest moving the variable to the comedi_device struct.  */
594 typedef struct {
595 #ifdef CONFIG_COMEDI_PCI
596         struct pci_dev *pci_dev;        /* PCI device */
597 #endif
598         struct dio200_region io;        /* Register region */
599         int intr_sd;
600 } dio200_private;
601
602 #define devpriv ((dio200_private *)dev->private)
603
604 typedef struct {
605         unsigned int ofs;               /* Counter base offset */
606         unsigned int clk_sce_ofs;       /* CLK_SCE base offset */
607         unsigned int gat_sce_ofs;       /* GAT_SCE base offset */
608         int which;                      /* Bit 5 of CLK_SCE or GAT_SCE */
609         unsigned int clock_src[3];      /* Current clock sources */
610         unsigned int gate_src[3];       /* Current gate sources */
611         spinlock_t spinlock;
612 } dio200_subdev_8254;
613
614 typedef struct {
615         unsigned int ofs;               /* DIO base offset */
616 } dio200_subdev_8255;
617
618 typedef struct {
619         unsigned int ofs;
620         spinlock_t spinlock;
621         int active;
622         unsigned int valid_isns;
623         unsigned int enabled_isns;
624         unsigned int stopcount;
625         int continuous;
626 } dio200_subdev_intr;
627
628 /*
629  * The comedi_driver structure tells the Comedi core module
630  * which functions to call to configure/deconfigure (attach/detach)
631  * the board, and also about the kernel module that contains
632  * the device code.
633  */
634 static int dio200_attach(comedi_device * dev, comedi_devconfig * it);
635 static int dio200_detach(comedi_device * dev);
636 static comedi_driver driver_amplc_dio200 = {
637       driver_name:DIO200_DRIVER_NAME,
638       module:THIS_MODULE,
639       attach:dio200_attach,
640       detach:dio200_detach,
641       board_name:&dio200_boards[0].name,
642       offset:sizeof(dio200_board),
643       num_names:sizeof(dio200_boards) / sizeof(dio200_board),
644 };
645
646 #ifdef CONFIG_COMEDI_PCI
647 COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
648 #else
649 COMEDI_INITCLEANUP(driver_amplc_dio200);
650 #endif
651
652 /*
653  * Read 8-bit register.
654  */
655 static unsigned char dio200_read8(comedi_device * dev, unsigned int offset)
656 {
657         offset <<= devpriv->io.regshift;
658         if (devpriv->io.regtype == io_regtype)
659                 return inb(devpriv->io.u.iobase + offset);
660         else
661                 return readb(devpriv->io.u.membase + offset);
662 }
663
664 /*
665  * Write 8-bit register.
666  */
667 static void dio200_write8(comedi_device * dev, unsigned int offset,
668                 unsigned char val)
669 {
670         offset <<= devpriv->io.regshift;
671         if (devpriv->io.regtype == io_regtype)
672                 outb(val, devpriv->io.u.iobase + offset);
673         else
674                 writeb(val, devpriv->io.u.membase + offset);
675 }
676
677 /*
678  * This function looks for a PCI device matching the requested board name,
679  * bus and slot.
680  */
681 #ifdef CONFIG_COMEDI_PCI
682 static int
683 dio200_find_pci(comedi_device * dev, int bus, int slot,
684         struct pci_dev **pci_dev_p)
685 {
686         struct pci_dev *pci_dev = NULL;
687
688         *pci_dev_p = NULL;
689
690         /* Look for matching PCI device. */
691         for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
692                 pci_dev != NULL;
693                 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
694                         PCI_ANY_ID, pci_dev)) {
695                 /* If bus/slot specified, check them. */
696                 if (bus || slot) {
697                         if (bus != pci_dev->bus->number
698                                 || slot != PCI_SLOT(pci_dev->devfn))
699                                 continue;
700                 }
701                 if (thisboard->model == anypci_model) {
702                         /* Match any supported model. */
703                         int i;
704
705                         for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
706                                 if (dio200_boards[i].bustype != pci_bustype)
707                                         continue;
708                                 if (pci_dev->device == dio200_boards[i].devid) {
709                                         /* Change board_ptr to matched board. */
710                                         dev->board_ptr = &dio200_boards[i];
711                                         break;
712                                 }
713                         }
714                         if (i == ARRAY_SIZE(dio200_boards))
715                                 continue;
716                 } else {
717                         /* Match specific model name. */
718                         if (pci_dev->device != thisboard->devid)
719                                 continue;
720                 }
721
722                 /* Found a match. */
723                 *pci_dev_p = pci_dev;
724                 return 0;
725         }
726         /* No match found. */
727         if (bus || slot) {
728                 printk(KERN_ERR
729                         "comedi%d: error! no %s found at pci %02x:%02x!\n",
730                         dev->minor, thisboard->name, bus, slot);
731         } else {
732                 printk(KERN_ERR "comedi%d: error! no %s found!\n",
733                         dev->minor, thisboard->name);
734         }
735         return -EIO;
736 }
737 #endif
738
739 /*
740  * This function checks and requests an I/O region, reporting an error
741  * if there is a conflict.
742  */
743 static int
744 dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
745 {
746         if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
747                 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
748                         minor, from, extent);
749                 return -EIO;
750         }
751         return 0;
752 }
753
754 /*
755  * 'insn_bits' function for an 'INTERRUPT' subdevice.
756  */
757 static int
758 dio200_subdev_intr_insn_bits(comedi_device * dev, comedi_subdevice * s,
759         comedi_insn * insn, lsampl_t * data)
760 {
761         dio200_subdev_intr *subpriv = s->private;
762
763         if (thislayout->has_int_sce) {
764                 /* Just read the interrupt status register.  */
765                 data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
766         } else {
767                 /* No interrupt status register. */
768                 data[0] = 0;
769         }
770
771         return 2;
772 }
773
774 /*
775  * Called to stop acquisition for an 'INTERRUPT' subdevice.
776  */
777 static void dio200_stop_intr(comedi_device * dev, comedi_subdevice * s)
778 {
779         dio200_subdev_intr *subpriv = s->private;
780
781         subpriv->active = 0;
782         subpriv->enabled_isns = 0;
783         if (thislayout->has_int_sce) {
784                 dio200_write8(dev, subpriv->ofs, 0);
785         }
786 }
787
788 /*
789  * Called to start acquisition for an 'INTERRUPT' subdevice.
790  */
791 static int dio200_start_intr(comedi_device * dev, comedi_subdevice * s)
792 {
793         unsigned int n;
794         unsigned isn_bits;
795         dio200_subdev_intr *subpriv = s->private;
796         comedi_cmd *cmd = &s->async->cmd;
797         int retval = 0;
798
799         if (!subpriv->continuous && subpriv->stopcount == 0) {
800                 /* An empty acquisition! */
801                 s->async->events |= COMEDI_CB_EOA;
802                 subpriv->active = 0;
803                 retval = 1;
804         } else {
805                 /* Determine interrupt sources to enable. */
806                 isn_bits = 0;
807                 if (cmd->chanlist) {
808                         for (n = 0; n < cmd->chanlist_len; n++) {
809                                 isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
810                         }
811                 }
812                 isn_bits &= subpriv->valid_isns;
813                 /* Enable interrupt sources. */
814                 subpriv->enabled_isns = isn_bits;
815                 if (thislayout->has_int_sce) {
816                         dio200_write8(dev, subpriv->ofs, isn_bits);
817                 }
818         }
819
820         return retval;
821 }
822
823 /*
824  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
825  */
826 static int
827 dio200_inttrig_start_intr(comedi_device * dev, comedi_subdevice * s,
828         unsigned int trignum)
829 {
830         dio200_subdev_intr *subpriv;
831         unsigned long flags;
832         int event = 0;
833
834         if (trignum != 0)
835                 return -EINVAL;
836
837         subpriv = s->private;
838
839         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
840         s->async->inttrig = 0;
841         if (subpriv->active) {
842                 event = dio200_start_intr(dev, s);
843         }
844         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
845
846         if (event) {
847                 comedi_event(dev, s);
848         }
849
850         return 1;
851 }
852
853 /*
854  * This is called from the interrupt service routine to handle a read
855  * scan on an 'INTERRUPT' subdevice.
856  */
857 static int dio200_handle_read_intr(comedi_device * dev, comedi_subdevice * s)
858 {
859         dio200_subdev_intr *subpriv = s->private;
860         unsigned triggered;
861         unsigned intstat;
862         unsigned cur_enabled;
863         unsigned int oldevents;
864         unsigned long flags;
865         unsigned int int_sce_ofs;
866
867         int_sce_ofs = subpriv->ofs;
868         triggered = 0;
869
870         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
871         oldevents = s->async->events;
872         if (thislayout->has_int_sce) {
873                 /*
874                  * Collect interrupt sources that have triggered and disable
875                  * them temporarily.  Loop around until no extra interrupt
876                  * sources have triggered, at which point, the valid part of
877                  * the interrupt status register will read zero, clearing the
878                  * cause of the interrupt.
879                  *
880                  * Mask off interrupt sources already seen to avoid infinite
881                  * loop in case of misconfiguration.
882                  */
883                 cur_enabled = subpriv->enabled_isns;
884                 while ((intstat = (dio200_read8(dev, int_sce_ofs)
885                                         & subpriv->valid_isns & ~triggered))
886                                 != 0) {
887                         triggered |= intstat;
888                         cur_enabled &= ~triggered;
889                         dio200_write8(dev, int_sce_ofs, cur_enabled);
890                 }
891         } else {
892                 /*
893                  * No interrupt status register.  Assume the single interrupt
894                  * source has triggered.
895                  */
896                 triggered = subpriv->enabled_isns;
897         }
898
899         if (triggered) {
900                 /*
901                  * Some interrupt sources have triggered and have been
902                  * temporarily disabled to clear the cause of the interrupt.
903                  *
904                  * Reenable them NOW to minimize the time they are disabled.
905                  */
906                 cur_enabled = subpriv->enabled_isns;
907                 if (thislayout->has_int_sce) {
908                         dio200_write8(dev, int_sce_ofs, cur_enabled);
909                 }
910
911                 if (subpriv->active) {
912                         /*
913                          * The command is still active.
914                          *
915                          * Ignore interrupt sources that the command isn't
916                          * interested in (just in case there's a race
917                          * condition).
918                          */
919                         if (triggered & subpriv->enabled_isns) {
920                                 /* Collect scan data. */
921                                 sampl_t val;
922                                 unsigned int n, ch, len;
923
924                                 val = 0;
925                                 len = s->async->cmd.chanlist_len;
926                                 for (n = 0; n < len; n++) {
927                                         ch = CR_CHAN(s->async->cmd.chanlist[n]);
928                                         if (triggered & (1U << ch)) {
929                                                 val |= (1U << n);
930                                         }
931                                 }
932                                 /* Write the scan to the buffer. */
933                                 if (comedi_buf_put(s->async, val)) {
934                                         s->async->events |= (COMEDI_CB_BLOCK |
935                                                 COMEDI_CB_EOS);
936                                 } else {
937                                         /* Error!  Stop acquisition.  */
938                                         dio200_stop_intr(dev, s);
939                                         s->async->events |= COMEDI_CB_ERROR
940                                                 | COMEDI_CB_OVERFLOW;
941                                         comedi_error(dev, "buffer overflow");
942                                 }
943
944                                 /* Check for end of acquisition. */
945                                 if (!subpriv->continuous) {
946                                         /* stop_src == TRIG_COUNT */
947                                         if (subpriv->stopcount > 0) {
948                                                 subpriv->stopcount--;
949                                                 if (subpriv->stopcount == 0) {
950                                                         s->async->events |=
951                                                                 COMEDI_CB_EOA;
952                                                         dio200_stop_intr(dev,
953                                                                 s);
954                                                 }
955                                         }
956                                 }
957                         }
958                 }
959         }
960         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
961
962         if (oldevents != s->async->events) {
963                 comedi_event(dev, s);
964         }
965
966         return (triggered != 0);
967 }
968
969 /*
970  * 'cancel' function for an 'INTERRUPT' subdevice.
971  */
972 static int dio200_subdev_intr_cancel(comedi_device * dev, comedi_subdevice * s)
973 {
974         dio200_subdev_intr *subpriv = s->private;
975         unsigned long flags;
976
977         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
978         if (subpriv->active) {
979                 dio200_stop_intr(dev, s);
980         }
981         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
982
983         return 0;
984 }
985
986 /*
987  * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
988  */
989 static int
990 dio200_subdev_intr_cmdtest(comedi_device * dev, comedi_subdevice * s,
991         comedi_cmd * cmd)
992 {
993         int err = 0;
994         unsigned int tmp;
995
996         /* step 1: make sure trigger sources are trivially valid */
997
998         tmp = cmd->start_src;
999         cmd->start_src &= (TRIG_NOW | TRIG_INT);
1000         if (!cmd->start_src || tmp != cmd->start_src)
1001                 err++;
1002
1003         tmp = cmd->scan_begin_src;
1004         cmd->scan_begin_src &= TRIG_EXT;
1005         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1006                 err++;
1007
1008         tmp = cmd->convert_src;
1009         cmd->convert_src &= TRIG_NOW;
1010         if (!cmd->convert_src || tmp != cmd->convert_src)
1011                 err++;
1012
1013         tmp = cmd->scan_end_src;
1014         cmd->scan_end_src &= TRIG_COUNT;
1015         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1016                 err++;
1017
1018         tmp = cmd->stop_src;
1019         cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
1020         if (!cmd->stop_src || tmp != cmd->stop_src)
1021                 err++;
1022
1023         if (err)
1024                 return 1;
1025
1026         /* step 2: make sure trigger sources are unique and mutually compatible */
1027
1028         /* these tests are true if more than one _src bit is set */
1029         if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1030                 err++;
1031         if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1032                 err++;
1033         if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1034                 err++;
1035         if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1036                 err++;
1037         if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1038                 err++;
1039
1040         if (err)
1041                 return 2;
1042
1043         /* step 3: make sure arguments are trivially compatible */
1044
1045         /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
1046         if (cmd->start_arg != 0) {
1047                 cmd->start_arg = 0;
1048                 err++;
1049         }
1050
1051         /* cmd->scan_begin_src == TRIG_EXT */
1052         if (cmd->scan_begin_arg != 0) {
1053                 cmd->scan_begin_arg = 0;
1054                 err++;
1055         }
1056
1057         /* cmd->convert_src == TRIG_NOW */
1058         if (cmd->convert_arg != 0) {
1059                 cmd->convert_arg = 0;
1060                 err++;
1061         }
1062
1063         /* cmd->scan_end_src == TRIG_COUNT */
1064         if (cmd->scan_end_arg != cmd->chanlist_len) {
1065                 cmd->scan_end_arg = cmd->chanlist_len;
1066                 err++;
1067         }
1068
1069         switch (cmd->stop_src) {
1070         case TRIG_COUNT:
1071                 /* any count allowed */
1072                 break;
1073         case TRIG_NONE:
1074                 if (cmd->stop_arg != 0) {
1075                         cmd->stop_arg = 0;
1076                         err++;
1077                 }
1078                 break;
1079         default:
1080                 break;
1081         }
1082
1083         if (err)
1084                 return 3;
1085
1086         /* step 4: fix up any arguments */
1087
1088         /* if (err) return 4; */
1089
1090         return 0;
1091 }
1092
1093 /*
1094  * 'do_cmd' function for an 'INTERRUPT' subdevice.
1095  */
1096 static int dio200_subdev_intr_cmd(comedi_device * dev, comedi_subdevice * s)
1097 {
1098         comedi_cmd *cmd = &s->async->cmd;
1099         dio200_subdev_intr *subpriv = s->private;
1100         unsigned long flags;
1101         int event = 0;
1102
1103         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1104         subpriv->active = 1;
1105
1106         /* Set up end of acquisition. */
1107         switch (cmd->stop_src) {
1108         case TRIG_COUNT:
1109                 subpriv->continuous = 0;
1110                 subpriv->stopcount = cmd->stop_arg;
1111                 break;
1112         default:
1113                 /* TRIG_NONE */
1114                 subpriv->continuous = 1;
1115                 subpriv->stopcount = 0;
1116                 break;
1117         }
1118
1119         /* Set up start of acquisition. */
1120         switch (cmd->start_src) {
1121         case TRIG_INT:
1122                 s->async->inttrig = dio200_inttrig_start_intr;
1123                 break;
1124         default:
1125                 /* TRIG_NOW */
1126                 event = dio200_start_intr(dev, s);
1127                 break;
1128         }
1129         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1130
1131         if (event) {
1132                 comedi_event(dev, s);
1133         }
1134
1135         return 0;
1136 }
1137
1138 /*
1139  * This function initializes an 'INTERRUPT' subdevice.
1140  */
1141 static int
1142 dio200_subdev_intr_init(comedi_device * dev, comedi_subdevice * s,
1143         unsigned int offset, unsigned valid_isns)
1144 {
1145         dio200_subdev_intr *subpriv;
1146
1147         subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1148         if (!subpriv) {
1149                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1150                         dev->minor);
1151                 return -ENOMEM;
1152         }
1153         subpriv->ofs = offset;
1154         subpriv->valid_isns = valid_isns;
1155         spin_lock_init(&subpriv->spinlock);
1156
1157         if (thislayout->has_int_sce) {
1158                 /* Disable interrupt sources. */
1159                 dio200_write8(dev, subpriv->ofs, 0);
1160         }
1161
1162         s->private = subpriv;
1163         s->type = COMEDI_SUBD_DI;
1164         s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1165         if (thislayout->has_int_sce) {
1166                 s->n_chan = DIO200_MAX_ISNS;
1167                 s->len_chanlist = DIO200_MAX_ISNS;
1168         } else {
1169                 /* No interrupt source register.  Support single channel. */
1170                 s->n_chan = 1;
1171                 s->len_chanlist = 1;
1172         }
1173         s->range_table = &range_digital;
1174         s->maxdata = 1;
1175         s->insn_bits = dio200_subdev_intr_insn_bits;
1176         s->do_cmdtest = dio200_subdev_intr_cmdtest;
1177         s->do_cmd = dio200_subdev_intr_cmd;
1178         s->cancel = dio200_subdev_intr_cancel;
1179
1180         return 0;
1181 }
1182
1183 /*
1184  * This function cleans up an 'INTERRUPT' subdevice.
1185  */
1186 static void
1187 dio200_subdev_intr_cleanup(comedi_device * dev, comedi_subdevice * s)
1188 {
1189         dio200_subdev_intr *subpriv = s->private;
1190
1191         if (subpriv) {
1192                 kfree(subpriv);
1193         }
1194 }
1195
1196 /*
1197  * Interrupt service routine.
1198  */
1199 static irqreturn_t dio200_interrupt(int irq, void *d PT_REGS_ARG)
1200 {
1201         comedi_device *dev = d;
1202         int handled;
1203
1204         if (!dev->attached) {
1205                 return IRQ_NONE;
1206         }
1207
1208         if (devpriv->intr_sd >= 0) {
1209                 handled = dio200_handle_read_intr(dev,
1210                         dev->subdevices + devpriv->intr_sd);
1211         } else {
1212                 handled = 0;
1213         }
1214
1215         return IRQ_RETVAL(handled);
1216 }
1217
1218 /*
1219  * Read an '8254' counter subdevice channel.
1220  */
1221 static inline unsigned int
1222 dio200_subdev_8254_read_chan(comedi_device * dev, comedi_subdevice * s,
1223         unsigned int chan)
1224 {
1225         unsigned int i8254_ofs = ((dio200_subdev_8254 *)s->private)->ofs;
1226         unsigned int val;
1227
1228         /* latch counter */
1229         val = chan << 6;
1230         dio200_write8(dev, i8254_ofs + i8254_control_reg, val);
1231
1232         /* read lsb */
1233         val = dio200_read8(dev, i8254_ofs + chan);
1234         /* read msb */
1235         val += dio200_read8(dev, i8254_ofs + chan) << 8;
1236
1237         return val;
1238 }
1239
1240 /*
1241  * Write an '8254' counter subdevice channel.
1242  */
1243 static inline void
1244 dio200_subdev_8254_write_chan(comedi_device * dev, comedi_subdevice * s,
1245         unsigned int chan, unsigned int count)
1246 {
1247         unsigned int i8254_ofs = ((dio200_subdev_8254 *)s->private)->ofs;
1248
1249         /* write lsb */
1250         dio200_write8(dev, i8254_ofs + chan, count & 0xff);
1251         /* write msb */
1252         dio200_write8(dev, i8254_ofs + chan, (count >> 8) & 0xff);
1253 }
1254
1255 /*
1256  * Set mode of an '8254' counter subdevice channel.
1257  */
1258 static inline void
1259 dio200_subdev_8254_set_mode(comedi_device * dev, comedi_subdevice * s,
1260         unsigned int chan, unsigned int mode)
1261 {
1262         unsigned int i8254_ofs = ((dio200_subdev_8254 *)s->private)->ofs;
1263         unsigned int byte;
1264
1265         byte = chan << 6;
1266         byte |= 0x30;           /* load lsb then msb */
1267         byte |= (mode & 0xf);   /* set counter mode and BCD|binary */
1268         dio200_write8(dev, i8254_ofs + i8254_control_reg, byte);
1269 }
1270
1271 /*
1272  * Read status byte of an '8254' counter subdevice channel.
1273  */
1274 static inline unsigned int
1275 dio200_subdev_8254_status(comedi_device * dev, comedi_subdevice * s,
1276         unsigned int chan)
1277 {
1278         unsigned int i8254_ofs = ((dio200_subdev_8254 *)s->private)->ofs;
1279
1280         dio200_write8(dev, i8254_ofs + i8254_control_reg, (0xE0 | 2 << chan));
1281         return dio200_read8(dev, i8254_ofs + chan);
1282 }
1283
1284 /*
1285  * Handle 'insn_read' for an '8254' counter subdevice.
1286  */
1287 static int
1288 dio200_subdev_8254_read(comedi_device * dev, comedi_subdevice * s,
1289         comedi_insn * insn, lsampl_t * data)
1290 {
1291         dio200_subdev_8254 *subpriv = s->private;
1292         int chan = CR_CHAN(insn->chanspec);
1293         unsigned long flags;
1294
1295         if (insn->n == 0)
1296                 return 0;
1297
1298         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1299         data[0] = dio200_subdev_8254_read_chan(dev, s, chan);
1300         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1301
1302         return 1;
1303 }
1304
1305 /*
1306  * Handle 'insn_write' for an '8254' counter subdevice.
1307  */
1308 static int
1309 dio200_subdev_8254_write(comedi_device * dev, comedi_subdevice * s,
1310         comedi_insn * insn, lsampl_t * data)
1311 {
1312         dio200_subdev_8254 *subpriv = s->private;
1313         int chan = CR_CHAN(insn->chanspec);
1314         unsigned long flags;
1315
1316         if (insn->n == 0)
1317                 return 0;
1318
1319         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1320         dio200_subdev_8254_write_chan(dev, s, chan, data[0]);
1321         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1322
1323         return 1;
1324 }
1325
1326 /*
1327  * Set gate source for an '8254' counter subdevice channel.
1328  */
1329 static int
1330 dio200_subdev_8254_set_gate_src(comedi_device * dev, comedi_subdevice *s,
1331         unsigned int counter_number, unsigned int gate_src)
1332 {
1333         dio200_subdev_8254 *subpriv = s->private;
1334         unsigned char byte;
1335
1336         if (!thislayout->has_clk_gat_sce)
1337                 return -1;
1338         if (counter_number > 2)
1339                 return -1;
1340         if (gate_src > 7)
1341                 return -1;
1342
1343         subpriv->gate_src[counter_number] = gate_src;
1344         byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1345         dio200_write8(dev, subpriv->gat_sce_ofs, byte);
1346
1347         return 0;
1348 }
1349
1350 /*
1351  * Get gate source for an '8254' counter subdevice channel.
1352  */
1353 static int
1354 dio200_subdev_8254_get_gate_src(comedi_device * dev, comedi_subdevice *s,
1355         unsigned int counter_number)
1356 {
1357         dio200_subdev_8254 *subpriv = s->private;
1358
1359         if (!thislayout->has_clk_gat_sce)
1360                 return -1;
1361         if (counter_number > 2)
1362                 return -1;
1363
1364         return subpriv->gate_src[counter_number];
1365 }
1366
1367 /*
1368  * Set clock source for an '8254' counter subdevice channel.
1369  */
1370 static int
1371 dio200_subdev_8254_set_clock_src(comedi_device * dev, comedi_subdevice *s,
1372         unsigned int counter_number, unsigned int clock_src)
1373 {
1374         dio200_subdev_8254 *subpriv = s->private;
1375         unsigned char byte;
1376
1377         if (!thislayout->has_clk_gat_sce)
1378                 return -1;
1379         if (counter_number > 2)
1380                 return -1;
1381         if (clock_src > 7)
1382                 return -1;
1383
1384         subpriv->clock_src[counter_number] = clock_src;
1385         byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1386         dio200_write8(dev, subpriv->clk_sce_ofs, byte);
1387
1388         return 0;
1389 }
1390
1391 /*
1392  * Get clock source for an '8254' counter subdevice channel.
1393  */
1394 static int
1395 dio200_subdev_8254_get_clock_src(comedi_device * dev, comedi_subdevice *s,
1396         unsigned int counter_number, lsampl_t * period_ns)
1397 {
1398         dio200_subdev_8254 *subpriv = s->private;
1399         unsigned clock_src;
1400
1401         if (!thislayout->has_clk_gat_sce)
1402                 return -1;
1403         if (counter_number > 2)
1404                 return -1;
1405
1406         clock_src = subpriv->clock_src[counter_number];
1407         *period_ns = clock_period[clock_src];
1408         return clock_src;
1409 }
1410
1411 /*
1412  * Handle 'insn_config' for an '8254' counter subdevice.
1413  */
1414 static int
1415 dio200_subdev_8254_config(comedi_device * dev, comedi_subdevice * s,
1416         comedi_insn * insn, lsampl_t * data)
1417 {
1418         dio200_subdev_8254 *subpriv = s->private;
1419         int ret = 0;
1420         int chan = CR_CHAN(insn->chanspec);
1421         unsigned long flags;
1422
1423         comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
1424         switch (data[0]) {
1425         case INSN_CONFIG_SET_COUNTER_MODE:
1426                 if (data[1] > (I8254_MODE5 | I8254_BINARY))
1427                         ret = -EINVAL;
1428                 else
1429                         dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
1430                 break;
1431         case INSN_CONFIG_8254_READ_STATUS:
1432                 data[1] = dio200_subdev_8254_status(dev, s, chan);
1433                 break;
1434         case INSN_CONFIG_SET_GATE_SRC:
1435                 ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
1436                 if (ret < 0)
1437                         ret = -EINVAL;
1438                 break;
1439         case INSN_CONFIG_GET_GATE_SRC:
1440                 ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
1441                 if (ret < 0) {
1442                         ret = -EINVAL;
1443                         break;
1444                 }
1445                 data[2] = ret;
1446                 break;
1447         case INSN_CONFIG_SET_CLOCK_SRC:
1448                 ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
1449                 if (ret < 0)
1450                         ret = -EINVAL;
1451                 break;
1452         case INSN_CONFIG_GET_CLOCK_SRC:
1453                 ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
1454                 if (ret < 0) {
1455                         ret = -EINVAL;
1456                         break;
1457                 }
1458                 data[1] = ret;
1459                 break;
1460         default:
1461                 ret = -EINVAL;
1462                 break;
1463         }
1464         comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
1465         return ret < 0 ? ret : insn->n;
1466 }
1467
1468 /*
1469  * This function initializes an '8254' counter subdevice.
1470  *
1471  * offset is the offset to the 8254 chip.
1472  */
1473 static int
1474 dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
1475         unsigned int offset)
1476 {
1477         dio200_subdev_8254 *subpriv;
1478         unsigned int chan;
1479
1480         subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1481         if (!subpriv) {
1482                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1483                         dev->minor);
1484                 return -ENOMEM;
1485         }
1486
1487         s->private = subpriv;
1488         s->type = COMEDI_SUBD_COUNTER;
1489         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1490         s->n_chan = 3;
1491         s->maxdata = 0xFFFF;
1492         s->insn_read = dio200_subdev_8254_read;
1493         s->insn_write = dio200_subdev_8254_write;
1494         s->insn_config = dio200_subdev_8254_config;
1495
1496         spin_lock_init(&subpriv->spinlock);
1497         subpriv->ofs = offset;
1498         if (thislayout->has_clk_gat_sce) {
1499                 /* Derive CLK_SCE and GAT_SCE register offsets from
1500                  * 8254 offset. */
1501                 subpriv->clk_sce_ofs =
1502                         DIO200_XCLK_SCE + (offset >> 3);
1503                 subpriv->gat_sce_ofs =
1504                         DIO200_XGAT_SCE + (offset >> 3);
1505                 subpriv->which = (offset >> 2) & 1;
1506         }
1507
1508         /* Initialize channels. */
1509         for (chan = 0; chan < 3; chan++) {
1510                 dio200_subdev_8254_set_mode(dev, s, chan,
1511                         (I8254_MODE0 | I8254_BINARY));
1512                 if (thislayout->has_clk_gat_sce) {
1513                         /* Gate source 0 is VCC (logic 1). */
1514                         dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
1515                         /* Clock source 0 is the dedicated clock input. */
1516                         dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
1517                 }
1518         }
1519
1520         return 0;
1521 }
1522
1523 /*
1524  * This function cleans up an '8254' counter subdevice.
1525  */
1526 static void
1527 dio200_subdev_8254_cleanup(comedi_device * dev, comedi_subdevice * s)
1528 {
1529         dio200_subdev_8254 *subpriv = s->private;
1530
1531         if (subpriv) {
1532                 kfree(subpriv);
1533         }
1534 }
1535
1536 /*
1537  * This function sets I/O directions for an '8255' DIO subdevice.
1538  */
1539 static void
1540 dio200_subdev_8255_set_dir(comedi_device * dev, comedi_subdevice * s)
1541 {
1542         dio200_subdev_8255 *subpriv = s->private;
1543         int config;
1544
1545         config = CR_CW;
1546         /* 1 in io_bits indicates output, 1 in config indicates input */
1547         if (!(s->io_bits & 0x0000ff))
1548                 config |= CR_A_IO;
1549         if (!(s->io_bits & 0x00ff00))
1550                 config |= CR_B_IO;
1551         if (!(s->io_bits & 0x0f0000))
1552                 config |= CR_C_LO_IO;
1553         if (!(s->io_bits & 0xf00000))
1554                 config |= CR_C_HI_IO;
1555
1556         dio200_write8(dev, subpriv->ofs + 3, config);
1557 }
1558
1559 /*
1560  * Handle 'insn_bits' for an '8255' DIO subdevice.
1561  */
1562 static int
1563 dio200_subdev_8255_bits(comedi_device * dev, comedi_subdevice * s,
1564         comedi_insn * insn, lsampl_t * data)
1565 {
1566         unsigned int i8255_ofs = ((dio200_subdev_8255 *)s->private)->ofs;
1567
1568         if (data[0]) {
1569                 s->state &= ~data[0];
1570                 s->state |= (data[0] & data[1]);
1571
1572                 if (data[0] & 0xff) {
1573                         dio200_write8(dev, i8255_ofs, s->state & 0xff);
1574                 }
1575                 if (data[0] & 0xff00) {
1576                         dio200_write8(dev, i8255_ofs + 1,
1577                                 (s->state >> 8) & 0xff);
1578                 }
1579                 if (data[0] & 0xff0000) {
1580                         dio200_write8(dev, i8255_ofs + 2,
1581                                 (s->state >> 16) & 0xff);
1582                 }
1583         }
1584
1585         data[1] = dio200_read8(dev, i8255_ofs);
1586         data[1] |= dio200_read8(dev, i8255_ofs + 1) << 8;
1587         data[1] |= dio200_read8(dev, i8255_ofs + 2) << 16;
1588
1589         return 2;
1590 }
1591
1592 /*
1593  * Handle 'insn_config' for an '8255' DIO subdevice.
1594  */
1595 static int
1596 dio200_subdev_8255_config(comedi_device * dev, comedi_subdevice * s,
1597         comedi_insn * insn, lsampl_t * data)
1598 {
1599         unsigned int mask;
1600         unsigned int bits;
1601
1602         mask = 1 << CR_CHAN(insn->chanspec);
1603         if (mask & 0x0000ff) {
1604                 bits = 0x0000ff;
1605         } else if (mask & 0x00ff00) {
1606                 bits = 0x00ff00;
1607         } else if (mask & 0x0f0000) {
1608                 bits = 0x0f0000;
1609         } else {
1610                 bits = 0xf00000;
1611         }
1612
1613         switch (data[0]) {
1614         case INSN_CONFIG_DIO_INPUT:
1615                 s->io_bits &= ~bits;
1616                 break;
1617         case INSN_CONFIG_DIO_OUTPUT:
1618                 s->io_bits |= bits;
1619                 break;
1620         case INSN_CONFIG_DIO_QUERY:
1621                 data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
1622                 return insn->n;
1623                 break;
1624         default:
1625                 return -EINVAL;
1626         }
1627
1628         dio200_subdev_8255_set_dir(dev, s);
1629
1630         return 1;
1631 }
1632
1633 /*
1634  * This function initializes an '8255' DIO subdevice.
1635  *
1636  * offset is the offset to the 8255 chip.
1637  */
1638 static int
1639 dio200_subdev_8255_init(comedi_device * dev, comedi_subdevice * s,
1640         unsigned int offset)
1641 {
1642         dio200_subdev_8255 *subpriv;
1643
1644         subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1645         if (!subpriv) {
1646                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1647                         dev->minor);
1648                 return -ENOMEM;
1649         }
1650
1651         subpriv->ofs = offset;
1652
1653         s->private = subpriv;
1654         s->type = COMEDI_SUBD_DIO;
1655         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1656         s->n_chan = 24;
1657         s->range_table = &range_digital;
1658         s->maxdata = 1;
1659         s->insn_bits = dio200_subdev_8255_bits;
1660         s->insn_config = dio200_subdev_8255_config;
1661
1662         s->state = 0;
1663         s->io_bits = 0;
1664         dio200_subdev_8255_set_dir(dev, s);
1665
1666         return 0;
1667 }
1668
1669 /*
1670  * This function cleans up an '8255' DIO subdevice.
1671  */
1672 static void
1673 dio200_subdev_8255_cleanup(comedi_device * dev, comedi_subdevice * s)
1674 {
1675         dio200_subdev_8255 *subpriv = s->private;
1676
1677         if (subpriv) {
1678                 kfree(subpriv);
1679         }
1680 }
1681
1682 #ifdef CONFIG_COMEDI_PCI
1683 /*
1684  * This function does some special set-up for the PCIe boards
1685  * PCIe215, PCIe236, PCIe296.
1686  */
1687 static int
1688 dio200_pcie_board_setup(comedi_device * dev)
1689 {
1690         struct pci_dev *pci_dev = devpriv->pci_dev;
1691         unsigned char __iomem *brbase;
1692         resource_size_t brlen;
1693
1694         /*
1695          * The board uses Altera Cyclone IV with PCI-Express hard IP.
1696          * The FPGA configuration has the PCI-Express Avalon-MM Bridge
1697          * Control registers in PCI BAR 0, offset 0, and the length of
1698          * these registers is 0x4000.
1699          *
1700          * We need to write 0x80 to the "Avalon-MM to PCI-Express Interrupt
1701          * Enable" register at offset 0x50 to allow generation of PCIe
1702          * interrupts when RXmlrq_i is asserted in the SOPC Builder system.
1703          */
1704         brlen = pci_resource_len(pci_dev, 0);
1705         if (brlen < 0x4000 ||
1706                         !(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) {
1707                 printk(KERN_ERR "comedi%d: error! bad PCI region!\n",
1708                         dev->minor);
1709                 return -EINVAL;
1710         }
1711         brbase = ioremap_nocache(pci_resource_start(pci_dev, 0), brlen);
1712         if (!brbase) {
1713                 printk(KERN_ERR "comedi%d: error! failed to map registers!\n",
1714                         dev->minor);
1715                 return -ENOMEM;
1716         }
1717         writel(0x80, brbase + 0x50);
1718         iounmap(brbase);
1719         /*
1720          * Enable "enhanced" features of board.
1721          */
1722         dio200_write8(dev, DIO200_ENHANCE, 1);
1723         return 0;
1724 }
1725 #endif
1726
1727 /*
1728  * Attach is called by the Comedi core to configure the driver
1729  * for a particular board.  If you specified a board_name array
1730  * in the driver structure, dev->board_ptr contains that
1731  * address.
1732  */
1733 static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
1734 {
1735         comedi_subdevice *s;
1736         unsigned long iobase = 0;
1737         unsigned int irq = 0;
1738 #ifdef CONFIG_COMEDI_PCI
1739         struct pci_dev *pci_dev = NULL;
1740         int bus = 0, slot = 0;
1741 #endif
1742         const dio200_layout *layout;
1743         int share_irq = 0;
1744         int sdx;
1745         unsigned n;
1746         int ret;
1747
1748         printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1749                 DIO200_DRIVER_NAME);
1750
1751         if ((ret = alloc_private(dev, sizeof(dio200_private))) < 0) {
1752                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1753                         dev->minor);
1754                 return ret;
1755         }
1756
1757         /* Process options. */
1758         switch (thisboard->bustype) {
1759         case isa_bustype:
1760                 iobase = it->options[0];
1761                 irq = it->options[1];
1762                 share_irq = 0;
1763                 break;
1764 #ifdef CONFIG_COMEDI_PCI
1765         case pci_bustype:
1766                 bus = it->options[0];
1767                 slot = it->options[1];
1768                 share_irq = 1;
1769
1770                 if ((ret = dio200_find_pci(dev, bus, slot, &pci_dev)) < 0)
1771                         return ret;
1772                 devpriv->pci_dev = pci_dev;
1773                 break;
1774 #endif
1775         default:
1776                 printk(KERN_ERR
1777                         "comedi%d: %s: BUG! cannot determine board type!\n",
1778                         dev->minor, DIO200_DRIVER_NAME);
1779                 return -EINVAL;
1780                 break;
1781         }
1782
1783         devpriv->intr_sd = -1;
1784         devpriv->io.regtype = no_regtype;
1785         devpriv->io.regshift = thisboard->mainshift;
1786
1787         /* Enable device and reserve I/O spaces. */
1788 #ifdef CONFIG_COMEDI_PCI
1789         if (pci_dev) {
1790                 resource_size_t base, len;
1791                 unsigned int bar;
1792
1793                 ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1794                 if (ret < 0) {
1795                         printk(KERN_ERR
1796                                 "comedi%d: error! cannot enable PCI device and request regions!\n",
1797                                 dev->minor);
1798                         return ret;
1799                 }
1800                 bar = thisboard->mainbar;
1801                 base = pci_resource_start(pci_dev, bar);
1802                 len = pci_resource_len(pci_dev, bar);
1803                 if (len < thisboard->mainsize) {
1804                         printk(KERN_ERR
1805                                 "comedi%d: error! PCI region size too small!\n",
1806                                 dev->minor);
1807                         return -EINVAL;
1808                 }
1809                 if ((pci_resource_flags(pci_dev, bar) & IORESOURCE_MEM) != 0) {
1810                         devpriv->io.u.membase = ioremap_nocache(base, len);
1811                         if (!devpriv->io.u.membase) {
1812                                 printk(KERN_ERR
1813                                         "comedi%d: error! cannot remap registers!\n",
1814                                         dev->minor);
1815                                 return -ENOMEM;
1816                         }
1817                         devpriv->io.regtype = mmio_regtype;
1818                 } else {
1819                         devpriv->io.u.iobase = (unsigned long)base;
1820                         devpriv->io.regtype = io_regtype;
1821                 }
1822                 irq = pci_dev->irq;
1823         } else
1824 #endif
1825         {
1826                 ret = dio200_request_region(dev->minor, iobase,
1827                         thisboard->mainsize);
1828                 if (ret < 0) {
1829                         return ret;
1830                 }
1831                 devpriv->io.u.iobase = iobase;
1832                 devpriv->io.regtype = io_regtype;
1833         }
1834
1835         switch (thisboard->model) {
1836 #ifdef CONFIG_COMEDI_PCI
1837         case pcie215_model:
1838         case pcie236_model:
1839         case pcie296_model:
1840                 ret = dio200_pcie_board_setup(dev);
1841                 if (ret < 0) {
1842                         return ret;
1843                 }
1844                 break;
1845 #endif
1846         default:
1847                 break;
1848         }
1849
1850         layout = thislayout;
1851         if ((ret = alloc_subdevices(dev, layout->n_subdevs)) < 0) {
1852                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1853                         dev->minor);
1854                 return ret;
1855         }
1856
1857         for (n = 0; n < dev->n_subdevices; n++) {
1858                 s = &dev->subdevices[n];
1859                 switch (layout->sdtype[n]) {
1860                 case sd_8254:
1861                         /* counter subdevice (8254) */
1862                         ret = dio200_subdev_8254_init(dev, s,
1863                                 layout->sdinfo[n]);
1864                         if (ret < 0) {
1865                                 return ret;
1866                         }
1867                         break;
1868                 case sd_8255:
1869                         /* digital i/o subdevice (8255) */
1870                         ret = dio200_subdev_8255_init(dev, s,
1871                                 layout->sdinfo[n]);
1872                         if (ret < 0) {
1873                                 return ret;
1874                         }
1875                         break;
1876                 case sd_intr:
1877                         /* 'INTERRUPT' subdevice */
1878                         if (irq) {
1879                                 ret = dio200_subdev_intr_init(dev, s,
1880                                         DIO200_INT_SCE, layout->sdinfo[n]);
1881                                 if (ret < 0) {
1882                                         return ret;
1883                                 }
1884                                 devpriv->intr_sd = n;
1885                         } else {
1886                                 s->type = COMEDI_SUBD_UNUSED;
1887                         }
1888                         break;
1889                 case sd_timer:
1890                         /* TODO.  Fall-thru to default for now. */
1891                 default:
1892                         s->type = COMEDI_SUBD_UNUSED;
1893                         break;
1894                 }
1895         }
1896
1897         sdx = devpriv->intr_sd;
1898         if (sdx >= 0 && sdx < dev->n_subdevices) {
1899                 dev->read_subdev = &dev->subdevices[sdx];
1900         }
1901
1902         dev->board_name = thisboard->name;
1903
1904         if (irq) {
1905                 unsigned long flags = share_irq ? IRQF_SHARED : 0;
1906
1907                 if (comedi_request_irq(irq, dio200_interrupt, flags,
1908                                 DIO200_DRIVER_NAME, dev) >= 0) {
1909                         dev->irq = irq;
1910                 } else {
1911                         printk(KERN_WARNING
1912                                 "comedi%d: warning! irq %u unavailable!\n",
1913                                 dev->minor, irq);
1914                 }
1915         }
1916
1917         printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1918         if (thisboard->bustype == isa_bustype) {
1919                 printk("(base %#lx) ", iobase);
1920         } else {
1921 #ifdef CONFIG_COMEDI_PCI
1922                 printk("(pci %s) ", pci_name(pci_dev));
1923 #endif
1924         }
1925         if (irq) {
1926                 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1927         } else {
1928                 printk("(no irq) ");
1929         }
1930
1931         printk("attached\n");
1932
1933         return 1;
1934 }
1935
1936 /*
1937  * _detach is called to deconfigure a device.  It should deallocate
1938  * resources.
1939  * This function is also called when _attach() fails, so it should be
1940  * careful not to release resources that were not necessarily
1941  * allocated by _attach().  dev->private and dev->subdevices are
1942  * deallocated automatically by the core.
1943  */
1944 static int dio200_detach(comedi_device * dev)
1945 {
1946         const dio200_layout *layout;
1947         unsigned n;
1948
1949         printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1950                 DIO200_DRIVER_NAME);
1951
1952         if (dev->irq) {
1953                 comedi_free_irq(dev->irq, dev);
1954         }
1955         if (dev->subdevices) {
1956                 layout = thislayout;
1957                 for (n = 0; n < dev->n_subdevices; n++) {
1958                         comedi_subdevice *s = &dev->subdevices[n];
1959                         switch (layout->sdtype[n]) {
1960                         case sd_8254:
1961                                 dio200_subdev_8254_cleanup(dev, s);
1962                                 break;
1963                         case sd_8255:
1964                                 dio200_subdev_8255_cleanup(dev, s);
1965                                 break;
1966                         case sd_intr:
1967                                 dio200_subdev_intr_cleanup(dev, s);
1968                                 break;
1969                         default:
1970                                 break;
1971                         }
1972                 }
1973         }
1974         if (devpriv) {
1975                 if (devpriv->io.regtype == mmio_regtype) {
1976                         iounmap(devpriv->io.u.membase);
1977                 }
1978 #ifdef CONFIG_COMEDI_PCI
1979                 if (devpriv->pci_dev) {
1980                         if (devpriv->io.regtype != no_regtype) {
1981                                 comedi_pci_disable(devpriv->pci_dev);
1982                         }
1983                         pci_dev_put(devpriv->pci_dev);
1984                 } else
1985 #endif
1986                 {
1987                         if (devpriv->io.regtype == io_regtype) {
1988                                 release_region(devpriv->io.u.iobase,
1989                                         thisboard->mainsize);
1990                         }
1991                 }
1992         }
1993         if (dev->board_name) {
1994                 printk(KERN_INFO "comedi%d: %s removed\n",
1995                         dev->minor, dev->board_name);
1996         }
1997
1998         return 0;
1999 }