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