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