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