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