]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/comedi/drivers/adv_pci_dio.c
Staging: comedi: adv_pci_dio: Support Advantech PCI-1735U
[net-next-2.6.git] / drivers / staging / comedi / drivers / adv_pci_dio.c
1 /*
2  * comedi/drivers/adv_pci_dio.c
3  *
4  * Author: Michal Dobes <dobes@tesnet.cz>
5  *
6  *  Hardware driver for Advantech PCI DIO cards.
7 */
8 /*
9 Driver: adv_pci_dio
10 Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
11              PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
12              PCI-1754, PCI-1756, PCI-1762
13 Author: Michal Dobes <dobes@tesnet.cz>
14 Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
15   PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750,
16   PCI-1751, PCI-1752, PCI-1753,
17   PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
18   PCI-1760, PCI-1762
19 Status: untested
20 Updated: Tue, 04 May 2010 13:00:00 +0000
21
22 This driver supports now only insn interface for DI/DO/DIO.
23
24 Configuration options:
25   [0] - PCI bus of device (optional)
26   [1] - PCI slot of device (optional)
27           If bus/slot is not specified, the first available PCI
28           device will be used.
29
30 */
31
32 #include "../comedidev.h"
33
34 #include <linux/delay.h>
35
36 #include "comedi_pci.h"
37 #include "8255.h"
38 #include "8253.h"
39
40 #undef PCI_DIO_EXTDEBUG         /* if defined, enable extensive debug logging */
41
42 #undef DPRINTK
43 #ifdef PCI_DIO_EXTDEBUG
44 #define DPRINTK(fmt, args...) printk(fmt, ## args)
45 #else
46 #define DPRINTK(fmt, args...)
47 #endif
48
49 #define PCI_VENDOR_ID_ADVANTECH         0x13fe
50
51 /* hardware types of the cards */
52 enum hw_cards_id {
53         TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
54         TYPE_PCI1750,
55         TYPE_PCI1751,
56         TYPE_PCI1752,
57         TYPE_PCI1753, TYPE_PCI1753E,
58         TYPE_PCI1754, TYPE_PCI1756,
59         TYPE_PCI1760,
60         TYPE_PCI1762
61 };
62
63 /* which I/O instructions to use */
64 enum hw_io_access {
65         IO_8b, IO_16b
66 };
67
68 #define MAX_DI_SUBDEVS  2       /* max number of DI subdevices per card */
69 #define MAX_DO_SUBDEVS  2       /* max number of DO subdevices per card */
70 #define MAX_DIO_SUBDEVG 2       /* max number of DIO subdevices group per card */
71 #define MAX_8254_SUBDEVS   1    /* max number of 8254 counter subdevs per card */
72                                 /* (could be more than one 8254 per subdevice) */
73
74 #define SIZE_8254          4    /* 8254 IO space length */
75 #define SIZE_8255          4    /* 8255 IO space length */
76
77 #define PCIDIO_MAINREG     2    /* main I/O region for all Advantech cards? */
78
79 /* Register offset definitions */
80 /*  Advantech PCI-1730/3/4 */
81 #define PCI1730_IDI        0    /* R:   Isolated digital input  0-15 */
82 #define PCI1730_IDO        0    /* W:   Isolated digital output 0-15 */
83 #define PCI1730_DI         2    /* R:   Digital input  0-15 */
84 #define PCI1730_DO         2    /* W:   Digital output 0-15 */
85 #define PCI1733_IDI        0    /* R:   Isolated digital input  0-31 */
86 #define PCI1730_3_INT_EN        0x08    /* R/W: enable/disable interrupts */
87 #define PCI1730_3_INT_RF        0x0c    /* R/W: set falling/raising edge for interrupts */
88 #define PCI1730_3_INT_CLR       0x10    /* R/W: clear interrupts */
89 #define PCI1734_IDO        0    /* W:   Isolated digital output 0-31 */
90 #define PCI173x_BOARDID    4    /* R:   Board I/D switch for 1730/3/4 */
91
92 /* Advantech PCI-1735U */
93 #define PCI1735_DI         0    /* R:   Digital input  0-31 */
94 #define PCI1735_DO         0    /* W:   Digital output 0-31 */
95 #define PCI1735_C8254      4    /* R/W: 8254 counter */
96 #define PCI1735_BOARDID    8    /* R:   Board I/D switch for 1735U */
97
98 /*  Advantech PCI-1736UP */
99 #define PCI1736_IDI        0    /* R:   Isolated digital input  0-15 */
100 #define PCI1736_IDO        0    /* W:   Isolated digital output 0-15 */
101 #define PCI1736_3_INT_EN        0x08    /* R/W: enable/disable interrupts */
102 #define PCI1736_3_INT_RF        0x0c    /* R/W: set falling/raising edge for interrupts */
103 #define PCI1736_3_INT_CLR       0x10    /* R/W: clear interrupts */
104 #define PCI1736_BOARDID    4    /* R:   Board I/D switch for 1736UP */
105 #define PCI1736_MAINREG    0    /* Normal register (2) doesn't work */
106
107 /*  Advantech PCI-1750 */
108 #define PCI1750_IDI        0    /* R:   Isolated digital input  0-15 */
109 #define PCI1750_IDO        0    /* W:   Isolated digital output 0-15 */
110 #define PCI1750_ICR       32    /* W:   Interrupt control register */
111 #define PCI1750_ISR       32    /* R:   Interrupt status register */
112
113 /*  Advantech PCI-1751/3/3E */
114 #define PCI1751_DIO        0    /* R/W: begin of 8255 registers block */
115 #define PCI1751_ICR       32    /* W:   Interrupt control register */
116 #define PCI1751_ISR       32    /* R:   Interrupt status register */
117 #define PCI1753_DIO        0    /* R/W: begin of 8255 registers block */
118 #define PCI1753_ICR0      16    /* R/W: Interrupt control register group 0 */
119 #define PCI1753_ICR1      17    /* R/W: Interrupt control register group 1 */
120 #define PCI1753_ICR2      18    /* R/W: Interrupt control register group 2 */
121 #define PCI1753_ICR3      19    /* R/W: Interrupt control register group 3 */
122 #define PCI1753E_DIO      32    /* R/W: begin of 8255 registers block */
123 #define PCI1753E_ICR0     48    /* R/W: Interrupt control register group 0 */
124 #define PCI1753E_ICR1     49    /* R/W: Interrupt control register group 1 */
125 #define PCI1753E_ICR2     50    /* R/W: Interrupt control register group 2 */
126 #define PCI1753E_ICR3     51    /* R/W: Interrupt control register group 3 */
127
128 /*  Advantech PCI-1752/4/6 */
129 #define PCI1752_IDO        0    /* R/W: Digital output  0-31 */
130 #define PCI1752_IDO2       4    /* R/W: Digital output 32-63 */
131 #define PCI1754_IDI        0    /* R:   Digital input   0-31 */
132 #define PCI1754_IDI2       4    /* R:   Digital input  32-64 */
133 #define PCI1756_IDI        0    /* R:   Digital input   0-31 */
134 #define PCI1756_IDO        4    /* R/W: Digital output  0-31 */
135 #define PCI1754_6_ICR0  0x08    /* R/W: Interrupt control register group 0 */
136 #define PCI1754_6_ICR1  0x0a    /* R/W: Interrupt control register group 1 */
137 #define PCI1754_ICR2    0x0c    /* R/W: Interrupt control register group 2 */
138 #define PCI1754_ICR3    0x0e    /* R/W: Interrupt control register group 3 */
139 #define PCI1752_6_CFC   0x12    /* R/W: set/read channel freeze function */
140 #define PCI175x_BOARDID 0x10    /* R:   Board I/D switch for 1752/4/6 */
141
142 /*  Advantech PCI-1762 registers */
143 #define PCI1762_RO         0    /* R/W: Relays status/output */
144 #define PCI1762_IDI        2    /* R:   Isolated input status */
145 #define PCI1762_BOARDID    4    /* R:   Board I/D switch */
146 #define PCI1762_ICR        6    /* W:   Interrupt control register */
147 #define PCI1762_ISR        6    /* R:   Interrupt status register */
148
149 /*  Advantech PCI-1760 registers */
150 #define OMB0            0x0c    /* W:   Mailbox outgoing registers */
151 #define OMB1            0x0d
152 #define OMB2            0x0e
153 #define OMB3            0x0f
154 #define IMB0            0x1c    /* R:   Mailbox incoming registers */
155 #define IMB1            0x1d
156 #define IMB2            0x1e
157 #define IMB3            0x1f
158 #define INTCSR0         0x38    /* R/W: Interrupt control registers */
159 #define INTCSR1         0x39
160 #define INTCSR2         0x3a
161 #define INTCSR3         0x3b
162
163 /*  PCI-1760 mailbox commands */
164 #define CMD_ClearIMB2           0x00    /* Clear IMB2 status and return actaul DI status in IMB3 */
165 #define CMD_SetRelaysOutput     0x01    /* Set relay output from OMB0 */
166 #define CMD_GetRelaysStatus     0x02    /* Get relay status to IMB0 */
167 #define CMD_ReadCurrentStatus   0x07    /* Read the current status of the register in OMB0, result in IMB0 */
168 #define CMD_ReadFirmwareVersion 0x0e    /* Read the firmware ver., result in IMB1.IMB0 */
169 #define CMD_ReadHardwareVersion 0x0f    /* Read the hardware ver., result in IMB1.IMB0 */
170 #define CMD_EnableIDIFilters    0x20    /* Enable IDI filters based on bits in OMB0 */
171 #define CMD_EnableIDIPatternMatch 0x21  /* Enable IDI pattern match based on bits in OMB0 */
172 #define CMD_SetIDIPatternMatch  0x22    /* Enable IDI pattern match based on bits in OMB0 */
173 #define CMD_EnableIDICounters   0x28    /* Enable IDI counters based on bits in OMB0 */
174 #define CMD_ResetIDICounters    0x29    /* Reset IDI counters based on bits in OMB0 to its reset values */
175 #define CMD_OverflowIDICounters 0x2a    /* Enable IDI counters overflow interrupts  based on bits in OMB0 */
176 #define CMD_MatchIntIDICounters 0x2b    /* Enable IDI counters match value interrupts  based on bits in OMB0 */
177 #define CMD_EdgeIDICounters     0x2c    /* Set IDI up counters count edge (bit=0 - rising, =1 - falling) */
178 #define CMD_GetIDICntCurValue   0x2f    /* Read IDI{OMB0} up counter current value */
179 #define CMD_SetIDI0CntResetValue 0x40   /* Set IDI0 Counter Reset Value 256*OMB1+OMB0 */
180 #define CMD_SetIDI1CntResetValue 0x41   /* Set IDI1 Counter Reset Value 256*OMB1+OMB0 */
181 #define CMD_SetIDI2CntResetValue 0x42   /* Set IDI2 Counter Reset Value 256*OMB1+OMB0 */
182 #define CMD_SetIDI3CntResetValue 0x43   /* Set IDI3 Counter Reset Value 256*OMB1+OMB0 */
183 #define CMD_SetIDI4CntResetValue 0x44   /* Set IDI4 Counter Reset Value 256*OMB1+OMB0 */
184 #define CMD_SetIDI5CntResetValue 0x45   /* Set IDI5 Counter Reset Value 256*OMB1+OMB0 */
185 #define CMD_SetIDI6CntResetValue 0x46   /* Set IDI6 Counter Reset Value 256*OMB1+OMB0 */
186 #define CMD_SetIDI7CntResetValue 0x47   /* Set IDI7 Counter Reset Value 256*OMB1+OMB0 */
187 #define CMD_SetIDI0CntMatchValue 0x48   /* Set IDI0 Counter Match Value 256*OMB1+OMB0 */
188 #define CMD_SetIDI1CntMatchValue 0x49   /* Set IDI1 Counter Match Value 256*OMB1+OMB0 */
189 #define CMD_SetIDI2CntMatchValue 0x4a   /* Set IDI2 Counter Match Value 256*OMB1+OMB0 */
190 #define CMD_SetIDI3CntMatchValue 0x4b   /* Set IDI3 Counter Match Value 256*OMB1+OMB0 */
191 #define CMD_SetIDI4CntMatchValue 0x4c   /* Set IDI4 Counter Match Value 256*OMB1+OMB0 */
192 #define CMD_SetIDI5CntMatchValue 0x4d   /* Set IDI5 Counter Match Value 256*OMB1+OMB0 */
193 #define CMD_SetIDI6CntMatchValue 0x4e   /* Set IDI6 Counter Match Value 256*OMB1+OMB0 */
194 #define CMD_SetIDI7CntMatchValue 0x4f   /* Set IDI7 Counter Match Value 256*OMB1+OMB0 */
195
196 #define OMBCMD_RETRY    0x03    /* 3 times try request before error */
197
198 static int pci_dio_attach(struct comedi_device *dev,
199                           struct comedi_devconfig *it);
200 static int pci_dio_detach(struct comedi_device *dev);
201
202 struct diosubd_data {
203         int chans;              /*  num of chans */
204         int addr;               /*  PCI address ofset */
205         int regs;               /*  number of registers to read or 8255
206                                     subdevices or 8254 chips */
207         unsigned int specflags; /*  addon subdevice flags */
208 };
209
210 struct dio_boardtype {
211         const char *name;       /*  board name */
212         int vendor_id;          /*  vendor/device PCI ID */
213         int device_id;
214         int main_pci_region;    /*  main I/O PCI region */
215         enum hw_cards_id cardtype;
216         struct diosubd_data sdi[MAX_DI_SUBDEVS];        /*  DI chans */
217         struct diosubd_data sdo[MAX_DO_SUBDEVS];        /*  DO chans */
218         struct diosubd_data sdio[MAX_DIO_SUBDEVG];      /*  DIO 8255 chans */
219         struct diosubd_data boardid;    /*  card supports board ID switch */
220         struct diosubd_data s8254[MAX_8254_SUBDEVS];    /* 8254 subdevices */
221         enum hw_io_access io_access;
222 };
223
224 static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
225         {
226         PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
227         PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
228         PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
229         PCI_VENDOR_ID_ADVANTECH, 0x1735, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
230         PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
231         PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
232         PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
233         PCI_VENDOR_ID_ADVANTECH, 0x1752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
234         PCI_VENDOR_ID_ADVANTECH, 0x1753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
235         PCI_VENDOR_ID_ADVANTECH, 0x1754, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
236         PCI_VENDOR_ID_ADVANTECH, 0x1756, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
237         PCI_VENDOR_ID_ADVANTECH, 0x1760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
238         PCI_VENDOR_ID_ADVANTECH, 0x1762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
239         0}
240 };
241
242 MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
243
244 static const struct dio_boardtype boardtypes[] = {
245         {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
246          TYPE_PCI1730,
247          {{16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0}},
248          {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}},
249          {{0, 0, 0, 0}, {0, 0, 0, 0}},
250          {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
251          {{0, 0, 0, 0}},
252          IO_8b},
253         {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
254          TYPE_PCI1733,
255          {{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}},
256          {{0, 0, 0, 0}, {0, 0, 0, 0}},
257          {{0, 0, 0, 0}, {0, 0, 0, 0}},
258          {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
259          {{0, 0, 0, 0}},
260          IO_8b},
261         {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
262          TYPE_PCI1734,
263          {{0, 0, 0, 0}, {0, 0, 0, 0}},
264          {{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}},
265          {{0, 0, 0, 0}, {0, 0, 0, 0}},
266          {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
267          {{0, 0, 0, 0}},
268          IO_8b},
269         {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG,
270          TYPE_PCI1735,
271          {{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}},
272          {{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}},
273          {{0, 0, 0, 0}, {0, 0, 0, 0}},
274          { 4, PCI1735_BOARDID, 1, SDF_INTERNAL},
275          {{3, PCI1735_C8254, 1, 0}},
276          IO_8b},
277         {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
278          TYPE_PCI1736,
279          {{0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0}},
280          {{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}},
281          {{0, 0, 0, 0}, {0, 0, 0, 0}},
282          {4, PCI1736_BOARDID, 1, SDF_INTERNAL},
283          {{0, 0, 0, 0}},
284          IO_8b},
285         {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
286          TYPE_PCI1750,
287          {{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}},
288          {{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}},
289          {{0, 0, 0, 0}, {0, 0, 0, 0}},
290          {0, 0, 0, 0},
291          {{0, 0, 0, 0}},
292          IO_8b},
293         {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
294          TYPE_PCI1751,
295          {{0, 0, 0, 0}, {0, 0, 0, 0}},
296          {{0, 0, 0, 0}, {0, 0, 0, 0}},
297          {{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}},
298          {0, 0, 0, 0},
299          {{0, 0, 0, 0}},
300          IO_8b},
301         {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
302          TYPE_PCI1752,
303          {{0, 0, 0, 0}, {0, 0, 0, 0}},
304          {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}},
305          {{0, 0, 0, 0}, {0, 0, 0, 0}},
306          {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
307          {{0, 0, 0, 0}},
308          IO_16b},
309         {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
310          TYPE_PCI1753,
311          {{0, 0, 0, 0}, {0, 0, 0, 0}},
312          {{0, 0, 0, 0}, {0, 0, 0, 0}},
313          {{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}},
314          {0, 0, 0, 0},
315          {{0, 0, 0, 0}},
316          IO_8b},
317         {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
318          TYPE_PCI1753E,
319          {{0, 0, 0, 0}, {0, 0, 0, 0}},
320          {{0, 0, 0, 0}, {0, 0, 0, 0}},
321          {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}},
322          {0, 0, 0, 0},
323          {{0, 0, 0, 0}},
324          IO_8b},
325         {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
326          TYPE_PCI1754,
327          {{32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0}},
328          {{0, 0, 0, 0}, {0, 0, 0, 0}},
329          {{0, 0, 0, 0}, {0, 0, 0, 0}},
330          {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
331          {{0, 0, 0, 0}},
332          IO_16b},
333         {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
334          TYPE_PCI1756,
335          {{0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0}},
336          {{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}},
337          {{0, 0, 0, 0}, {0, 0, 0, 0}},
338          {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
339          {{0, 0, 0, 0}},
340          IO_16b},
341         {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
342          TYPE_PCI1760,
343          {{0, 0, 0, 0}, {0, 0, 0, 0}},  /*  This card have own setup work */
344          {{0, 0, 0, 0}, {0, 0, 0, 0}},
345          {{0, 0, 0, 0}, {0, 0, 0, 0}},
346          {0, 0, 0, 0},
347          {{0, 0, 0, 0}},
348          IO_8b},
349         {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
350          TYPE_PCI1762,
351          {{0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0}},
352          {{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}},
353          {{0, 0, 0, 0}, {0, 0, 0, 0}},
354          {4, PCI1762_BOARDID, 1, SDF_INTERNAL},
355          {{0, 0, 0, 0}},
356          IO_16b}
357 };
358
359 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype))
360
361 static struct comedi_driver driver_pci_dio = {
362         .driver_name = "adv_pci_dio",
363         .module = THIS_MODULE,
364         .attach = pci_dio_attach,
365         .detach = pci_dio_detach
366 };
367
368 struct pci_dio_private {
369         struct pci_dio_private *prev;   /*  previous private struct */
370         struct pci_dio_private *next;   /*  next private struct */
371         struct pci_dev *pcidev; /*  pointer to board's pci_dev */
372         char valid;             /*  card is usable */
373         char GlobalIrqEnabled;  /*  1= any IRQ source is enabled */
374         /*  PCI-1760 specific data */
375         unsigned char IDICntEnable;     /*  counter's counting enable status */
376         unsigned char IDICntOverEnable; /*  counter's overflow interrupts enable status */
377         unsigned char IDICntMatchEnable;        /*  counter's match interrupts enable status */
378         unsigned char IDICntEdge;       /*  counter's count edge value (bit=0 - rising, =1 - falling) */
379         unsigned short CntResValue[8];  /*  counters' reset value */
380         unsigned short CntMatchValue[8];        /*  counters' match interrupt value */
381         unsigned char IDIFiltersEn;     /*  IDI's digital filters enable status */
382         unsigned char IDIPatMatchEn;    /*  IDI's pattern match enable status */
383         unsigned char IDIPatMatchValue; /*  IDI's pattern match value */
384         unsigned short IDIFiltrLow[8];  /*  IDI's filter value low signal */
385         unsigned short IDIFiltrHigh[8]; /*  IDI's filter value high signal */
386 };
387
388 static struct pci_dio_private *pci_priv = NULL; /* list of allocated cards */
389
390 #define devpriv ((struct pci_dio_private *)dev->private)
391 #define this_board ((const struct dio_boardtype *)dev->board_ptr)
392
393 /*
394 ==============================================================================
395 */
396 static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
397                                   struct comedi_subdevice *s,
398                                   struct comedi_insn *insn, unsigned int *data)
399 {
400         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
401         int i;
402
403         data[1] = 0;
404         for (i = 0; i < d->regs; i++)
405                 data[1] |= inb(dev->iobase + d->addr + i) << (8 * i);
406
407
408         return 2;
409 }
410
411 /*
412 ==============================================================================
413 */
414 static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
415                                   struct comedi_subdevice *s,
416                                   struct comedi_insn *insn, unsigned int *data)
417 {
418         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
419         int i;
420
421         data[1] = 0;
422         for (i = 0; i < d->regs; i++)
423                 data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i);
424
425         return 2;
426 }
427
428 /*
429 ==============================================================================
430 */
431 static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
432                                   struct comedi_subdevice *s,
433                                   struct comedi_insn *insn, unsigned int *data)
434 {
435         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
436         int i;
437
438         if (data[0]) {
439                 s->state &= ~data[0];
440                 s->state |= (data[0] & data[1]);
441                 for (i = 0; i < d->regs; i++)
442                         outb((s->state >> (8 * i)) & 0xff,
443                              dev->iobase + d->addr + i);
444         }
445         data[1] = s->state;
446
447         return 2;
448 }
449
450 /*
451 ==============================================================================
452 */
453 static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
454                                   struct comedi_subdevice *s,
455                                   struct comedi_insn *insn, unsigned int *data)
456 {
457         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
458         int i;
459
460         if (data[0]) {
461                 s->state &= ~data[0];
462                 s->state |= (data[0] & data[1]);
463                 for (i = 0; i < d->regs; i++)
464                         outw((s->state >> (16 * i)) & 0xffff,
465                              dev->iobase + d->addr + 2 * i);
466         }
467         data[1] = s->state;
468
469         return 2;
470 }
471
472 /*
473 ==============================================================================
474 */
475 static int pci_8254_insn_read(struct comedi_device *dev,
476                               struct comedi_subdevice *s,
477                               struct comedi_insn *insn, unsigned int *data)
478 {
479         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
480         unsigned int chan, chip, chipchan;
481         unsigned long flags;
482
483         chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
484         chip = chan / 3;                /* chip on subdevice */
485         chipchan = chan - (3 * chip);   /* channel on chip on subdevice */
486         spin_lock_irqsave(&s->spin_lock, flags);
487         data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip),
488                         0, chipchan);
489         spin_unlock_irqrestore(&s->spin_lock, flags);
490         return 1;
491 }
492
493 /*
494 ==============================================================================
495 */
496 static int pci_8254_insn_write(struct comedi_device *dev,
497                                struct comedi_subdevice *s,
498                                struct comedi_insn *insn, unsigned int *data)
499 {
500         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
501         unsigned int chan, chip, chipchan;
502         unsigned long flags;
503
504         chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
505         chip = chan / 3;                /* chip on subdevice */
506         chipchan = chan - (3 * chip);   /* channel on chip on subdevice */
507         spin_lock_irqsave(&s->spin_lock, flags);
508         i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip),
509                         0, chipchan, data[0]);
510         spin_unlock_irqrestore(&s->spin_lock, flags);
511         return 1;
512 }
513
514 /*
515 ==============================================================================
516 */
517 static int pci_8254_insn_config(struct comedi_device *dev,
518                                 struct comedi_subdevice *s,
519                                 struct comedi_insn *insn, unsigned int *data)
520 {
521         const struct diosubd_data *d = (const struct diosubd_data *)s->private;
522         unsigned int chan, chip, chipchan;
523         unsigned long iobase;
524         int ret = 0;
525         unsigned long flags;
526
527         chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
528         chip = chan / 3;                /* chip on subdevice */
529         chipchan = chan - (3 * chip);   /* channel on chip on subdevice */
530         iobase = dev->iobase + d->addr + (SIZE_8254 * chip);
531         spin_lock_irqsave(&s->spin_lock, flags);
532         switch (data[0]) {
533         case INSN_CONFIG_SET_COUNTER_MODE:
534                 ret = i8254_set_mode(iobase, 0, chipchan, data[1]);
535                 if (ret < 0)
536                         ret = -EINVAL;
537                 break;
538         case INSN_CONFIG_8254_READ_STATUS:
539                 data[1] = i8254_status(iobase, 0, chipchan);
540                 break;
541         default:
542                 ret = -EINVAL;
543                 break;
544         }
545         spin_unlock_irqrestore(&s->spin_lock, flags);
546         return ret < 0 ? ret : insn->n;
547 }
548
549 /*
550 ==============================================================================
551 */
552 static int pci1760_unchecked_mbxrequest(struct comedi_device *dev,
553                                         unsigned char *omb, unsigned char *imb,
554                                         int repeats)
555 {
556         int cnt, tout, ok = 0;
557
558         for (cnt = 0; cnt < repeats; cnt++) {
559                 outb(omb[0], dev->iobase + OMB0);
560                 outb(omb[1], dev->iobase + OMB1);
561                 outb(omb[2], dev->iobase + OMB2);
562                 outb(omb[3], dev->iobase + OMB3);
563                 for (tout = 0; tout < 251; tout++) {
564                         imb[2] = inb(dev->iobase + IMB2);
565                         if (imb[2] == omb[2]) {
566                                 imb[0] = inb(dev->iobase + IMB0);
567                                 imb[1] = inb(dev->iobase + IMB1);
568                                 imb[3] = inb(dev->iobase + IMB3);
569                                 ok = 1;
570                                 break;
571                         }
572                         udelay(1);
573                 }
574                 if (ok)
575                         return 0;
576         }
577
578         comedi_error(dev, "PCI-1760 mailbox request timeout!");
579         return -ETIME;
580 }
581
582 static int pci1760_clear_imb2(struct comedi_device *dev)
583 {
584         unsigned char omb[4] = { 0x0, 0x0, CMD_ClearIMB2, 0x0 };
585         unsigned char imb[4];
586         /* check if imb2 is already clear */
587         if (inb(dev->iobase + IMB2) == CMD_ClearIMB2)
588                 return 0;
589         return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
590 }
591
592 static int pci1760_mbxrequest(struct comedi_device *dev,
593                               unsigned char *omb, unsigned char *imb)
594 {
595         if (omb[2] == CMD_ClearIMB2) {
596                 comedi_error(dev,
597                              "bug! this function should not be used for CMD_ClearIMB2 command");
598                 return -EINVAL;
599         }
600         if (inb(dev->iobase + IMB2) == omb[2]) {
601                 int retval;
602                 retval = pci1760_clear_imb2(dev);
603                 if (retval < 0)
604                         return retval;
605         }
606         return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
607 }
608
609 /*
610 ==============================================================================
611 */
612 static int pci1760_insn_bits_di(struct comedi_device *dev,
613                                 struct comedi_subdevice *s,
614                                 struct comedi_insn *insn, unsigned int *data)
615 {
616         data[1] = inb(dev->iobase + IMB3);
617
618         return 2;
619 }
620
621 /*
622 ==============================================================================
623 */
624 static int pci1760_insn_bits_do(struct comedi_device *dev,
625                                 struct comedi_subdevice *s,
626                                 struct comedi_insn *insn, unsigned int *data)
627 {
628         int ret;
629         unsigned char omb[4] = {
630                 0x00,
631                 0x00,
632                 CMD_SetRelaysOutput,
633                 0x00
634         };
635         unsigned char imb[4];
636
637         if (data[0]) {
638                 s->state &= ~data[0];
639                 s->state |= (data[0] & data[1]);
640                 omb[0] = s->state;
641                 ret = pci1760_mbxrequest(dev, omb, imb);
642                 if (!ret)
643                         return ret;
644         }
645         data[1] = s->state;
646
647         return 2;
648 }
649
650 /*
651 ==============================================================================
652 */
653 static int pci1760_insn_cnt_read(struct comedi_device *dev,
654                                  struct comedi_subdevice *s,
655                                  struct comedi_insn *insn, unsigned int *data)
656 {
657         int ret, n;
658         unsigned char omb[4] = {
659                 CR_CHAN(insn->chanspec) & 0x07,
660                 0x00,
661                 CMD_GetIDICntCurValue,
662                 0x00
663         };
664         unsigned char imb[4];
665
666         for (n = 0; n < insn->n; n++) {
667                 ret = pci1760_mbxrequest(dev, omb, imb);
668                 if (!ret)
669                         return ret;
670                 data[n] = (imb[1] << 8) + imb[0];
671         }
672
673         return n;
674 }
675
676 /*
677 ==============================================================================
678 */
679 static int pci1760_insn_cnt_write(struct comedi_device *dev,
680                                   struct comedi_subdevice *s,
681                                   struct comedi_insn *insn, unsigned int *data)
682 {
683         int ret;
684         unsigned char chan = CR_CHAN(insn->chanspec) & 0x07;
685         unsigned char bitmask = 1 << chan;
686         unsigned char omb[4] = {
687                 data[0] & 0xff,
688                 (data[0] >> 8) & 0xff,
689                 CMD_SetIDI0CntResetValue + chan,
690                 0x00
691         };
692         unsigned char imb[4];
693
694         if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) { /*  Set reset value if different */
695                 ret = pci1760_mbxrequest(dev, omb, imb);
696                 if (!ret)
697                         return ret;
698                 devpriv->CntResValue[chan] = data[0] & 0xffff;
699         }
700
701         omb[0] = bitmask;       /*  reset counter to it reset value */
702         omb[2] = CMD_ResetIDICounters;
703         ret = pci1760_mbxrequest(dev, omb, imb);
704         if (!ret)
705                 return ret;
706
707         if (!(bitmask & devpriv->IDICntEnable)) {       /*  start counter if it don't run */
708                 omb[0] = bitmask;
709                 omb[2] = CMD_EnableIDICounters;
710                 ret = pci1760_mbxrequest(dev, omb, imb);
711                 if (!ret)
712                         return ret;
713                 devpriv->IDICntEnable |= bitmask;
714         }
715         return 1;
716 }
717
718 /*
719 ==============================================================================
720 */
721 static int pci1760_reset(struct comedi_device *dev)
722 {
723         int i;
724         unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 };
725         unsigned char imb[4];
726
727         outb(0, dev->iobase + INTCSR0); /*  disable IRQ */
728         outb(0, dev->iobase + INTCSR1);
729         outb(0, dev->iobase + INTCSR2);
730         outb(0, dev->iobase + INTCSR3);
731         devpriv->GlobalIrqEnabled = 0;
732
733         omb[0] = 0x00;
734         omb[2] = CMD_SetRelaysOutput;   /*  reset relay outputs */
735         pci1760_mbxrequest(dev, omb, imb);
736
737         omb[0] = 0x00;
738         omb[2] = CMD_EnableIDICounters; /*  disable IDI up counters */
739         pci1760_mbxrequest(dev, omb, imb);
740         devpriv->IDICntEnable = 0;
741
742         omb[0] = 0x00;
743         omb[2] = CMD_OverflowIDICounters;       /*  disable counters overflow interrupts */
744         pci1760_mbxrequest(dev, omb, imb);
745         devpriv->IDICntOverEnable = 0;
746
747         omb[0] = 0x00;
748         omb[2] = CMD_MatchIntIDICounters;       /*  disable counters match value interrupts */
749         pci1760_mbxrequest(dev, omb, imb);
750         devpriv->IDICntMatchEnable = 0;
751
752         omb[0] = 0x00;
753         omb[1] = 0x80;
754         for (i = 0; i < 8; i++) {       /*  set IDI up counters match value */
755                 omb[2] = CMD_SetIDI0CntMatchValue + i;
756                 pci1760_mbxrequest(dev, omb, imb);
757                 devpriv->CntMatchValue[i] = 0x8000;
758         }
759
760         omb[0] = 0x00;
761         omb[1] = 0x00;
762         for (i = 0; i < 8; i++) {       /*  set IDI up counters reset value */
763                 omb[2] = CMD_SetIDI0CntResetValue + i;
764                 pci1760_mbxrequest(dev, omb, imb);
765                 devpriv->CntResValue[i] = 0x0000;
766         }
767
768         omb[0] = 0xff;
769         omb[2] = CMD_ResetIDICounters;  /*  reset IDI up counters to reset values */
770         pci1760_mbxrequest(dev, omb, imb);
771
772         omb[0] = 0x00;
773         omb[2] = CMD_EdgeIDICounters;   /*  set IDI up counters count edge */
774         pci1760_mbxrequest(dev, omb, imb);
775         devpriv->IDICntEdge = 0x00;
776
777         omb[0] = 0x00;
778         omb[2] = CMD_EnableIDIFilters;  /*  disable all digital in filters */
779         pci1760_mbxrequest(dev, omb, imb);
780         devpriv->IDIFiltersEn = 0x00;
781
782         omb[0] = 0x00;
783         omb[2] = CMD_EnableIDIPatternMatch;     /*  disable pattern matching */
784         pci1760_mbxrequest(dev, omb, imb);
785         devpriv->IDIPatMatchEn = 0x00;
786
787         omb[0] = 0x00;
788         omb[2] = CMD_SetIDIPatternMatch;        /*  set pattern match value */
789         pci1760_mbxrequest(dev, omb, imb);
790         devpriv->IDIPatMatchValue = 0x00;
791
792         return 0;
793 }
794
795 /*
796 ==============================================================================
797 */
798 static int pci_dio_reset(struct comedi_device *dev)
799 {
800         DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n");
801
802         switch (this_board->cardtype) {
803         case TYPE_PCI1730:
804                 outb(0, dev->iobase + PCI1730_DO);      /*  clear outputs */
805                 outb(0, dev->iobase + PCI1730_DO + 1);
806                 outb(0, dev->iobase + PCI1730_IDO);
807                 outb(0, dev->iobase + PCI1730_IDO + 1);
808                 /* NO break there! */
809         case TYPE_PCI1733:
810                 outb(0, dev->iobase + PCI1730_3_INT_EN);        /*  disable interrupts */
811                 outb(0x0f, dev->iobase + PCI1730_3_INT_CLR);    /*  clear interrupts */
812                 outb(0, dev->iobase + PCI1730_3_INT_RF);        /*  set rising edge trigger */
813                 break;
814         case TYPE_PCI1734:
815                 outb(0, dev->iobase + PCI1734_IDO);     /*  clear outputs */
816                 outb(0, dev->iobase + PCI1734_IDO + 1);
817                 outb(0, dev->iobase + PCI1734_IDO + 2);
818                 outb(0, dev->iobase + PCI1734_IDO + 3);
819                 break;
820         case TYPE_PCI1735:
821                 outb(0, dev->iobase + PCI1735_DO);      /*  clear outputs */
822                 outb(0, dev->iobase + PCI1735_DO + 1);
823                 outb(0, dev->iobase + PCI1735_DO + 2);
824                 outb(0, dev->iobase + PCI1735_DO + 3);
825                 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0);
826                 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0);
827                 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0);
828                 break;
829
830         case TYPE_PCI1736:
831                 outb(0, dev->iobase + PCI1736_IDO);
832                 outb(0, dev->iobase + PCI1736_IDO + 1);
833                 outb(0, dev->iobase + PCI1736_3_INT_EN);        /*  disable interrupts */
834                 outb(0x0f, dev->iobase + PCI1736_3_INT_CLR);    /*  clear interrupts */
835                 outb(0, dev->iobase + PCI1736_3_INT_RF);        /*  set rising edge trigger */
836                 break;
837
838         case TYPE_PCI1750:
839         case TYPE_PCI1751:
840                 outb(0x88, dev->iobase + PCI1750_ICR);  /*  disable & clear interrupts */
841                 break;
842         case TYPE_PCI1752:
843                 outw(0, dev->iobase + PCI1752_6_CFC);   /*  disable channel freeze function */
844                 outw(0, dev->iobase + PCI1752_IDO);     /*  clear outputs */
845                 outw(0, dev->iobase + PCI1752_IDO + 2);
846                 outw(0, dev->iobase + PCI1752_IDO2);
847                 outw(0, dev->iobase + PCI1752_IDO2 + 2);
848                 break;
849         case TYPE_PCI1753E:
850                 outb(0x88, dev->iobase + PCI1753E_ICR0);        /*  disable & clear interrupts */
851                 outb(0x80, dev->iobase + PCI1753E_ICR1);
852                 outb(0x80, dev->iobase + PCI1753E_ICR2);
853                 outb(0x80, dev->iobase + PCI1753E_ICR3);
854                 /* NO break there! */
855         case TYPE_PCI1753:
856                 outb(0x88, dev->iobase + PCI1753_ICR0); /*  disable & clear interrupts */
857                 outb(0x80, dev->iobase + PCI1753_ICR1);
858                 outb(0x80, dev->iobase + PCI1753_ICR2);
859                 outb(0x80, dev->iobase + PCI1753_ICR3);
860                 break;
861         case TYPE_PCI1754:
862                 outw(0x08, dev->iobase + PCI1754_6_ICR0);       /*  disable and clear interrupts */
863                 outw(0x08, dev->iobase + PCI1754_6_ICR1);
864                 outw(0x08, dev->iobase + PCI1754_ICR2);
865                 outw(0x08, dev->iobase + PCI1754_ICR3);
866                 break;
867         case TYPE_PCI1756:
868                 outw(0, dev->iobase + PCI1752_6_CFC);   /*  disable channel freeze function */
869                 outw(0x08, dev->iobase + PCI1754_6_ICR0);       /*  disable and clear interrupts */
870                 outw(0x08, dev->iobase + PCI1754_6_ICR1);
871                 outw(0, dev->iobase + PCI1756_IDO);     /*  clear outputs */
872                 outw(0, dev->iobase + PCI1756_IDO + 2);
873                 break;
874         case TYPE_PCI1760:
875                 pci1760_reset(dev);
876                 break;
877         case TYPE_PCI1762:
878                 outw(0x0101, dev->iobase + PCI1762_ICR);        /*  disable & clear interrupts */
879                 break;
880         }
881
882         DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n");
883
884         return 0;
885 }
886
887 /*
888 ==============================================================================
889 */
890 static int pci1760_attach(struct comedi_device *dev,
891                           struct comedi_devconfig *it)
892 {
893         struct comedi_subdevice *s;
894         int subdev = 0;
895
896         s = dev->subdevices + subdev;
897         s->type = COMEDI_SUBD_DI;
898         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
899         s->n_chan = 8;
900         s->maxdata = 1;
901         s->len_chanlist = 8;
902         s->range_table = &range_digital;
903         s->insn_bits = pci1760_insn_bits_di;
904         subdev++;
905
906         s = dev->subdevices + subdev;
907         s->type = COMEDI_SUBD_DO;
908         s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
909         s->n_chan = 8;
910         s->maxdata = 1;
911         s->len_chanlist = 8;
912         s->range_table = &range_digital;
913         s->state = 0;
914         s->insn_bits = pci1760_insn_bits_do;
915         subdev++;
916
917         s = dev->subdevices + subdev;
918         s->type = COMEDI_SUBD_TIMER;
919         s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL;
920         s->n_chan = 2;
921         s->maxdata = 0xffffffff;
922         s->len_chanlist = 2;
923 /*       s->insn_config=pci1760_insn_pwm_cfg; */
924         subdev++;
925
926         s = dev->subdevices + subdev;
927         s->type = COMEDI_SUBD_COUNTER;
928         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
929         s->n_chan = 8;
930         s->maxdata = 0xffff;
931         s->len_chanlist = 8;
932         s->insn_read = pci1760_insn_cnt_read;
933         s->insn_write = pci1760_insn_cnt_write;
934 /*       s->insn_config=pci1760_insn_cnt_cfg; */
935         subdev++;
936
937         return 0;
938 }
939
940 /*
941 ==============================================================================
942 */
943 static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s,
944                           const struct diosubd_data *d, int subdev)
945 {
946         s->type = COMEDI_SUBD_DI;
947         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags;
948         if (d->chans > 16)
949                 s->subdev_flags |= SDF_LSAMPL;
950         s->n_chan = d->chans;
951         s->maxdata = 1;
952         s->len_chanlist = d->chans;
953         s->range_table = &range_digital;
954         switch (this_board->io_access) {
955         case IO_8b:
956                 s->insn_bits = pci_dio_insn_bits_di_b;
957                 break;
958         case IO_16b:
959                 s->insn_bits = pci_dio_insn_bits_di_w;
960                 break;
961         }
962         s->private = (void *)d;
963
964         return 0;
965 }
966
967 /*
968 ==============================================================================
969 */
970 static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
971                           const struct diosubd_data *d, int subdev)
972 {
973         s->type = COMEDI_SUBD_DO;
974         s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
975         if (d->chans > 16)
976                 s->subdev_flags |= SDF_LSAMPL;
977         s->n_chan = d->chans;
978         s->maxdata = 1;
979         s->len_chanlist = d->chans;
980         s->range_table = &range_digital;
981         s->state = 0;
982         switch (this_board->io_access) {
983         case IO_8b:
984                 s->insn_bits = pci_dio_insn_bits_do_b;
985                 break;
986         case IO_16b:
987                 s->insn_bits = pci_dio_insn_bits_do_w;
988                 break;
989         }
990         s->private = (void *)d;
991
992         return 0;
993 }
994
995 /*
996 ==============================================================================
997 */
998 static int pci_dio_add_8254(struct comedi_device *dev,
999                             struct comedi_subdevice * s,
1000                             const struct diosubd_data *d, int subdev)
1001 {
1002         s->type = COMEDI_SUBD_COUNTER;
1003         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1004         s->n_chan = d->chans;
1005         s->maxdata = 65535;
1006         s->len_chanlist = d->chans;
1007         s->insn_read = pci_8254_insn_read;
1008         s->insn_write = pci_8254_insn_write;
1009         s->insn_config = pci_8254_insn_config;
1010         s->private = (void *)d;
1011
1012         return 0;
1013 }
1014
1015 /*
1016 ==============================================================================
1017 */
1018 static int CheckAndAllocCard(struct comedi_device *dev,
1019                              struct comedi_devconfig *it,
1020                              struct pci_dev *pcidev)
1021 {
1022         struct pci_dio_private *pr, *prev;
1023
1024         for (pr = pci_priv, prev = NULL; pr != NULL; prev = pr, pr = pr->next) {
1025                 if (pr->pcidev == pcidev)
1026                         return 0;       /*  this card is used, look for another */
1027
1028         }
1029
1030         if (prev) {
1031                 devpriv->prev = prev;
1032                 prev->next = devpriv;
1033         } else {
1034                 pci_priv = devpriv;
1035         }
1036
1037         devpriv->pcidev = pcidev;
1038
1039         return 1;
1040 }
1041
1042 /*
1043 ==============================================================================
1044 */
1045 static int pci_dio_attach(struct comedi_device *dev,
1046                           struct comedi_devconfig *it)
1047 {
1048         struct comedi_subdevice *s;
1049         int ret, subdev, n_subdevices, i, j;
1050         unsigned long iobase;
1051         struct pci_dev *pcidev;
1052
1053         printk("comedi%d: adv_pci_dio: ", dev->minor);
1054
1055         ret = alloc_private(dev, sizeof(struct pci_dio_private));
1056         if (ret < 0) {
1057                 printk(", Error: Cann't allocate private memory!\n");
1058                 return -ENOMEM;
1059         }
1060
1061         for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
1062              pcidev != NULL;
1063              pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
1064                 /*  loop through cards supported by this driver */
1065                 for (i = 0; i < n_boardtypes; ++i) {
1066                         if (boardtypes[i].vendor_id != pcidev->vendor)
1067                                 continue;
1068                         if (boardtypes[i].device_id != pcidev->device)
1069                                 continue;
1070                         /*  was a particular bus/slot requested? */
1071                         if (it->options[0] || it->options[1]) {
1072                                 /*  are we on the wrong bus/slot? */
1073                                 if (pcidev->bus->number != it->options[0] ||
1074                                     PCI_SLOT(pcidev->devfn) != it->options[1]) {
1075                                         continue;
1076                                 }
1077                         }
1078                         ret = CheckAndAllocCard(dev, it, pcidev);
1079                         if (ret != 1)
1080                                 continue;
1081                         dev->board_ptr = boardtypes + i;
1082                         break;
1083                 }
1084                 if (dev->board_ptr)
1085                         break;
1086         }
1087
1088         if (!dev->board_ptr) {
1089                 printk(", Error: Requested type of the card was not found!\n");
1090                 return -EIO;
1091         }
1092
1093         if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) {
1094                 printk
1095                     (", Error: Can't enable PCI device and request regions!\n");
1096                 return -EIO;
1097         }
1098         iobase = pci_resource_start(pcidev, this_board->main_pci_region);
1099         printk(", b:s:f=%d:%d:%d, io=0x%4lx",
1100                pcidev->bus->number, PCI_SLOT(pcidev->devfn),
1101                PCI_FUNC(pcidev->devfn), iobase);
1102
1103         dev->iobase = iobase;
1104         dev->board_name = this_board->name;
1105
1106         if (this_board->cardtype == TYPE_PCI1760) {
1107                 n_subdevices = 4;       /*  8 IDI, 8 IDO, 2 PWM, 8 CNT */
1108         } else {
1109                 n_subdevices = 0;
1110                 for (i = 0; i < MAX_DI_SUBDEVS; i++)
1111                         if (this_board->sdi[i].chans)
1112                                 n_subdevices++;
1113                 for (i = 0; i < MAX_DO_SUBDEVS; i++)
1114                         if (this_board->sdo[i].chans)
1115                                 n_subdevices++;
1116                 for (i = 0; i < MAX_DIO_SUBDEVG; i++)
1117                         n_subdevices += this_board->sdio[i].regs;
1118                 if (this_board->boardid.chans)
1119                         n_subdevices++;
1120                 for (i = 0; i < MAX_8254_SUBDEVS; i++)
1121                         if (this_board->s8254[i].chans)
1122                                 n_subdevices++;
1123         }
1124
1125         ret = alloc_subdevices(dev, n_subdevices);
1126         if (ret < 0) {
1127                 printk(", Error: Cann't allocate subdevice memory!\n");
1128                 return ret;
1129         }
1130
1131         printk(".\n");
1132
1133         subdev = 0;
1134
1135         for (i = 0; i < MAX_DI_SUBDEVS; i++)
1136                 if (this_board->sdi[i].chans) {
1137                         s = dev->subdevices + subdev;
1138                         pci_dio_add_di(dev, s, &this_board->sdi[i], subdev);
1139                         subdev++;
1140                 }
1141
1142         for (i = 0; i < MAX_DO_SUBDEVS; i++)
1143                 if (this_board->sdo[i].chans) {
1144                         s = dev->subdevices + subdev;
1145                         pci_dio_add_do(dev, s, &this_board->sdo[i], subdev);
1146                         subdev++;
1147                 }
1148
1149         for (i = 0; i < MAX_DIO_SUBDEVG; i++)
1150                 for (j = 0; j < this_board->sdio[i].regs; j++) {
1151                         s = dev->subdevices + subdev;
1152                         subdev_8255_init(dev, s, NULL,
1153                                          dev->iobase +
1154                                          this_board->sdio[i].addr +
1155                                          SIZE_8255 * j);
1156                         subdev++;
1157                 }
1158
1159         if (this_board->boardid.chans) {
1160                 s = dev->subdevices + subdev;
1161                 s->type = COMEDI_SUBD_DI;
1162                 pci_dio_add_di(dev, s, &this_board->boardid, subdev);
1163                 subdev++;
1164         }
1165
1166         for (i = 0; i < MAX_8254_SUBDEVS; i++)
1167                 if (this_board->s8254[i].chans) {
1168                         s = dev->subdevices + subdev;
1169                         pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev);
1170                         subdev++;
1171                 }
1172
1173         if (this_board->cardtype == TYPE_PCI1760)
1174                 pci1760_attach(dev, it);
1175
1176         devpriv->valid = 1;
1177
1178         pci_dio_reset(dev);
1179
1180         return 0;
1181 }
1182
1183 /*
1184 ==============================================================================
1185 */
1186 static int pci_dio_detach(struct comedi_device *dev)
1187 {
1188         int i, j;
1189         struct comedi_subdevice *s;
1190         int subdev;
1191
1192         if (dev->private) {
1193                 if (devpriv->valid)
1194                         pci_dio_reset(dev);
1195
1196
1197                 /* This shows the silliness of using this kind of
1198                  * scheme for numbering subdevices.  Don't do it.  --ds */
1199                 subdev = 0;
1200                 for (i = 0; i < MAX_DI_SUBDEVS; i++) {
1201                         if (this_board->sdi[i].chans)
1202                                 subdev++;
1203
1204                 }
1205                 for (i = 0; i < MAX_DO_SUBDEVS; i++) {
1206                         if (this_board->sdo[i].chans)
1207                                 subdev++;
1208
1209                 }
1210                 for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
1211                         for (j = 0; j < this_board->sdio[i].regs; j++) {
1212                                 s = dev->subdevices + subdev;
1213                                 subdev_8255_cleanup(dev, s);
1214                                 subdev++;
1215                         }
1216                 }
1217
1218                 if (this_board->boardid.chans) {
1219                         subdev++;
1220                 }
1221
1222                 for (i = 0; i < MAX_8254_SUBDEVS; i++) {
1223                         if (this_board->s8254[i].chans) {
1224                                 subdev++;
1225                         }
1226                 }
1227
1228                 for (i = 0; i < dev->n_subdevices; i++) {
1229                         s = dev->subdevices + i;
1230                         s->private = NULL;
1231                 }
1232
1233                 if (devpriv->pcidev) {
1234                         if (dev->iobase)
1235                                 comedi_pci_disable(devpriv->pcidev);
1236
1237                         pci_dev_put(devpriv->pcidev);
1238                 }
1239
1240                 if (devpriv->prev)
1241                         devpriv->prev->next = devpriv->next;
1242                 else
1243                         pci_priv = devpriv->next;
1244
1245                 if (devpriv->next)
1246                         devpriv->next->prev = devpriv->prev;
1247
1248         }
1249
1250         return 0;
1251 }
1252
1253 /*
1254 ==============================================================================
1255 */
1256 COMEDI_PCI_INITCLEANUP(driver_pci_dio, pci_dio_pci_table);
1257 /*
1258 ==============================================================================
1259 */