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