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