1 /*
2  * comedi/drivers/adv_pci1710.c
3  *
4  * Author: Michal Dobes <dobes@tesnet.cz>
5  *
6  * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7  * for testing and informations.
8  *
9  *  hardware driver for Advantech cards:
10  *   card:   PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
11  *   driver: pci1710,  pci1710hg,  pci1711,  pci1713,  pci1720,  pci1731
12  *
13  * Options:
14  *  [0] - PCI bus number - if bus number and slot number are 0,
15  *                         then driver search for first unused card
16  *  [1] - PCI slot number
17  *
18 */
19 /*
20 Driver: adv_pci1710
21 Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
22 	     Advantech PCI-1720, PCI-1731
23 Author: Michal Dobes <dobes@tesnet.cz>
24 Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
25   PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
26   PCI-1731
27 Status: works
28 
29 This driver supports AI, AO, DI and DO subdevices.
30 AI subdevice supports cmd and insn interface,
31 other subdevices support only insn interface.
32 
33 The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
34 driver cannot distinguish between them, as would be normal for a
35 PCI driver.
36 
37 Configuration options:
38   [0] - PCI bus of device (optional)
39   [1] - PCI slot of device (optional)
40 	If bus/slot is not specified, the first available PCI
41 	device will be used.
42 */
43 
44 #include <linux/interrupt.h>
45 
46 #include "../comedidev.h"
47 
48 #include "comedi_pci.h"
49 
50 #include "8253.h"
51 #include "amcc_s5933.h"
52 
53 #define PCI171x_PARANOIDCHECK	/* if defined, then is used code which control
54 				 * correct channel number on every 12 bit
55 				 * sample */
56 
57 #undef PCI171X_EXTDEBUG
58 
59 #define DRV_NAME "adv_pci1710"
60 
61 #undef DPRINTK
62 #ifdef PCI171X_EXTDEBUG
63 #define DPRINTK(fmt, args...) printk(fmt, ## args)
64 #else
65 #define DPRINTK(fmt, args...)
66 #endif
67 
68 #define PCI_VENDOR_ID_ADVANTECH		0x13fe
69 
70 /* hardware types of the cards */
71 #define TYPE_PCI171X	0
72 #define TYPE_PCI1713	2
73 #define TYPE_PCI1720	3
74 
75 #define IORANGE_171x	32
76 #define IORANGE_1720	16
77 
78 #define PCI171x_AD_DATA	 0	/* R:   A/D data */
79 #define PCI171x_SOFTTRG	 0	/* W:   soft trigger for A/D */
80 #define PCI171x_RANGE	 2	/* W:   A/D gain/range register */
81 #define PCI171x_MUX	 4	/* W:   A/D multiplexor control */
82 #define PCI171x_STATUS	 6	/* R:   status register */
83 #define PCI171x_CONTROL	 6	/* W:   control register */
84 #define PCI171x_CLRINT	 8	/* W:   clear interrupts request */
85 #define PCI171x_CLRFIFO	 9	/* W:   clear FIFO */
86 #define PCI171x_DA1	10	/* W:   D/A register */
87 #define PCI171x_DA2	12	/* W:   D/A register */
88 #define PCI171x_DAREF	14	/* W:   D/A reference control */
89 #define PCI171x_DI	16	/* R:   digi inputs */
90 #define PCI171x_DO	16	/* R:   digi inputs */
91 #define PCI171x_CNT0	24	/* R/W: 8254 counter 0 */
92 #define PCI171x_CNT1	26	/* R/W: 8254 counter 1 */
93 #define PCI171x_CNT2	28	/* R/W: 8254 counter 2 */
94 #define PCI171x_CNTCTRL	30	/* W:   8254 counter control */
95 
96 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
97  * reg) */
98 #define	Status_FE	0x0100	/* 1=FIFO is empty */
99 #define Status_FH	0x0200	/* 1=FIFO is half full */
100 #define Status_FF	0x0400	/* 1=FIFO is full, fatal error */
101 #define Status_IRQ	0x0800	/* 1=IRQ occurred */
102 /* bits from control register (PCI171x_CONTROL) */
103 #define Control_CNT0	0x0040	/* 1=CNT0 have external source,
104 				 * 0=have internal 100kHz source */
105 #define Control_ONEFH	0x0020	/* 1=IRQ on FIFO is half full, 0=every sample */
106 #define Control_IRQEN	0x0010	/* 1=enable IRQ */
107 #define Control_GATE	0x0008	/* 1=enable external trigger GATE (8254?) */
108 #define Control_EXT	0x0004	/* 1=external trigger source */
109 #define Control_PACER	0x0002	/* 1=enable internal 8254 trigger source */
110 #define Control_SW	0x0001	/* 1=enable software trigger source */
111 /* bits from counter control register (PCI171x_CNTCTRL) */
112 #define Counter_BCD     0x0001	/* 0 = binary counter, 1 = BCD counter */
113 #define Counter_M0      0x0002	/* M0-M2 select modes 0-5 */
114 #define Counter_M1      0x0004	/* 000 = mode 0, 010 = mode 2 ... */
115 #define Counter_M2      0x0008
116 #define Counter_RW0     0x0010	/* RW0/RW1 select read/write mode */
117 #define Counter_RW1     0x0020
118 #define Counter_SC0     0x0040	/* Select Counter. Only 00 or 11 may */
119 #define Counter_SC1     0x0080	/* be used, 00 for CNT0,
120 				 * 11 for read-back command */
121 
122 #define PCI1720_DA0	 0	/* W:   D/A register 0 */
123 #define PCI1720_DA1	 2	/* W:   D/A register 1 */
124 #define PCI1720_DA2	 4	/* W:   D/A register 2 */
125 #define PCI1720_DA3	 6	/* W:   D/A register 3 */
126 #define PCI1720_RANGE	 8	/* R/W: D/A range register */
127 #define PCI1720_SYNCOUT	 9	/* W:   D/A synchronized output register */
128 #define PCI1720_SYNCONT	15	/* R/W: D/A synchronized control */
129 
130 /* D/A synchronized control (PCI1720_SYNCONT) */
131 #define Syncont_SC0	 1	/* set synchronous output mode */
132 
133 static const struct comedi_lrange range_pci1710_3 = { 9, {
134 							  BIP_RANGE(5),
135 							  BIP_RANGE(2.5),
136 							  BIP_RANGE(1.25),
137 							  BIP_RANGE(0.625),
138 							  BIP_RANGE(10),
139 							  UNI_RANGE(10),
140 							  UNI_RANGE(5),
141 							  UNI_RANGE(2.5),
142 							  UNI_RANGE(1.25)
143 							  }
144 };
145 
146 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147 					      0x10, 0x11, 0x12, 0x13 };
148 
149 static const struct comedi_lrange range_pci1710hg = { 12, {
150 							   BIP_RANGE(5),
151 							   BIP_RANGE(0.5),
152 							   BIP_RANGE(0.05),
153 							   BIP_RANGE(0.005),
154 							   BIP_RANGE(10),
155 							   BIP_RANGE(1),
156 							   BIP_RANGE(0.1),
157 							   BIP_RANGE(0.01),
158 							   UNI_RANGE(10),
159 							   UNI_RANGE(1),
160 							   UNI_RANGE(0.1),
161 							   UNI_RANGE(0.01)
162 							   }
163 };
164 
165 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
166 					      0x05, 0x06, 0x07, 0x10, 0x11,
167 					      0x12, 0x13 };
168 
169 static const struct comedi_lrange range_pci17x1 = { 5, {
170 							BIP_RANGE(10),
171 							BIP_RANGE(5),
172 							BIP_RANGE(2.5),
173 							BIP_RANGE(1.25),
174 							BIP_RANGE(0.625)
175 							}
176 };
177 
178 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
179 
180 static const struct comedi_lrange range_pci1720 = { 4, {
181 							UNI_RANGE(5),
182 							UNI_RANGE(10),
183 							BIP_RANGE(5),
184 							BIP_RANGE(10)
185 							}
186 };
187 
188 static const struct comedi_lrange range_pci171x_da = { 2, {
189 							   UNI_RANGE(5),
190 							   UNI_RANGE(10),
191 							   }
192 };
193 
194 static int pci1710_attach(struct comedi_device *dev,
195 			  struct comedi_devconfig *it);
196 static int pci1710_detach(struct comedi_device *dev);
197 
198 struct boardtype {
199 	const char *name;	/*  board name */
200 	int device_id;
201 	int iorange;		/*  I/O range len */
202 	char have_irq;		/*  1=card support IRQ */
203 	char cardtype;		/*  0=1710& co. 2=1713, ... */
204 	int n_aichan;		/*  num of A/D chans */
205 	int n_aichand;		/*  num of A/D chans in diff mode */
206 	int n_aochan;		/*  num of D/A chans */
207 	int n_dichan;		/*  num of DI chans */
208 	int n_dochan;		/*  num of DO chans */
209 	int n_counter;		/*  num of counters */
210 	int ai_maxdata;		/*  resolution of A/D */
211 	int ao_maxdata;		/*  resolution of D/A */
212 	const struct comedi_lrange *rangelist_ai;	/*  rangelist for A/D */
213 	const char *rangecode_ai;	/*  range codes for programming */
214 	const struct comedi_lrange *rangelist_ao;	/*  rangelist for D/A */
215 	unsigned int ai_ns_min;	/*  max sample speed of card v ns */
216 	unsigned int fifo_half_size;	/*  size of FIFO/2 */
217 };
218 
219 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
220 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
221 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
222 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
223 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
224 	{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
225 	{ 0 }
226 };
227 
228 MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
229 
230 static const struct boardtype boardtypes[] = {
231 	{"pci1710", 0x1710,
232 	 IORANGE_171x, 1, TYPE_PCI171X,
233 	 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
234 	 &range_pci1710_3, range_codes_pci1710_3,
235 	 &range_pci171x_da,
236 	 10000, 2048},
237 	{"pci1710hg", 0x1710,
238 	 IORANGE_171x, 1, TYPE_PCI171X,
239 	 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
240 	 &range_pci1710hg, range_codes_pci1710hg,
241 	 &range_pci171x_da,
242 	 10000, 2048},
243 	{"pci1711", 0x1711,
244 	 IORANGE_171x, 1, TYPE_PCI171X,
245 	 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
246 	 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
247 	 10000, 512},
248 	{"pci1713", 0x1713,
249 	 IORANGE_171x, 1, TYPE_PCI1713,
250 	 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
251 	 &range_pci1710_3, range_codes_pci1710_3, NULL,
252 	 10000, 2048},
253 	{"pci1720", 0x1720,
254 	 IORANGE_1720, 0, TYPE_PCI1720,
255 	 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
256 	 NULL, NULL, &range_pci1720,
257 	 0, 0},
258 	{"pci1731", 0x1731,
259 	 IORANGE_171x, 1, TYPE_PCI171X,
260 	 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
261 	 &range_pci17x1, range_codes_pci17x1, NULL,
262 	 10000, 512},
263 	/*  dummy entry corresponding to driver name */
264 	{.name = DRV_NAME},
265 };
266 
267 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
268 
269 static struct comedi_driver driver_pci1710 = {
270 	.driver_name = DRV_NAME,
271 	.module = THIS_MODULE,
272 	.attach = pci1710_attach,
273 	.detach = pci1710_detach,
274 	.num_names = n_boardtypes,
275 	.board_name = &boardtypes[0].name,
276 	.offset = sizeof(struct boardtype),
277 };
278 
279 struct pci1710_private {
280 	struct pci_dev *pcidev;	/*  ptr to PCI device */
281 	char valid;		/*  card is usable */
282 	char neverending_ai;	/*  we do unlimited AI */
283 	unsigned int CntrlReg;	/*  Control register */
284 	unsigned int i8254_osc_base;	/*  frequence of onboard oscilator */
285 	unsigned int ai_do;	/*  what do AI? 0=nothing, 1 to 4 mode */
286 	unsigned int ai_act_scan;	/*  how many scans we finished */
287 	unsigned int ai_act_chan;	/*  actual position in actual scan */
288 	unsigned int ai_buf_ptr;	/*  data buffer ptr in samples */
289 	unsigned char ai_eos;	/*  1=EOS wake up */
290 	unsigned char ai_et;
291 	unsigned int ai_et_CntrlReg;
292 	unsigned int ai_et_MuxVal;
293 	unsigned int ai_et_div1, ai_et_div2;
294 	unsigned int act_chanlist[32];	/*  list of scaned channel */
295 	unsigned char act_chanlist_len;	/*  len of scanlist */
296 	unsigned char act_chanlist_pos;	/*  actual position in MUX list */
297 	unsigned char da_ranges;	/*  copy of D/A outpit range register */
298 	unsigned int ai_scans;	/*  len of scanlist */
299 	unsigned int ai_n_chan;	/*  how many channels is measured */
300 	unsigned int *ai_chanlist;	/*  actaul chanlist */
301 	unsigned int ai_flags;	/*  flaglist */
302 	unsigned int ai_data_len;	/*  len of data buffer */
303 	short *ai_data;		/*  data buffer */
304 	unsigned int ai_timer1;	/*  timers */
305 	unsigned int ai_timer2;
306 	short ao_data[4];	/*  data output buffer */
307 	unsigned int cnt0_write_wait;	/* after a write, wait for update of the
308 					 * internal state */
309 };
310 
311 #define devpriv ((struct pci1710_private *)dev->private)
312 #define this_board ((const struct boardtype *)dev->board_ptr)
313 
314 /*
315 ==============================================================================
316 */
317 
318 static int check_channel_list(struct comedi_device *dev,
319 			      struct comedi_subdevice *s,
320 			      unsigned int *chanlist, unsigned int n_chan);
321 static void setup_channel_list(struct comedi_device *dev,
322 			       struct comedi_subdevice *s,
323 			       unsigned int *chanlist, unsigned int n_chan,
324 			       unsigned int seglen);
325 static void start_pacer(struct comedi_device *dev, int mode,
326 			unsigned int divisor1, unsigned int divisor2);
327 static int pci1710_reset(struct comedi_device *dev);
328 static int pci171x_ai_cancel(struct comedi_device *dev,
329 			     struct comedi_subdevice *s);
330 
331 /*  used for gain list programming */
332 static const unsigned int muxonechan[] = {
333 	0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
334 	0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
335 	0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
336 	0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
337 };
338 
339 /*
340 ==============================================================================
341 */
pci171x_insn_read_ai(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)342 static int pci171x_insn_read_ai(struct comedi_device *dev,
343 				struct comedi_subdevice *s,
344 				struct comedi_insn *insn, unsigned int *data)
345 {
346 	int n, timeout;
347 #ifdef PCI171x_PARANOIDCHECK
348 	unsigned int idata;
349 #endif
350 
351 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
352 	devpriv->CntrlReg &= Control_CNT0;
353 	devpriv->CntrlReg |= Control_SW;	/*  set software trigger */
354 	outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
355 	outb(0, dev->iobase + PCI171x_CLRFIFO);
356 	outb(0, dev->iobase + PCI171x_CLRINT);
357 
358 	setup_channel_list(dev, s, &insn->chanspec, 1, 1);
359 
360 	DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
361 		inw(dev->iobase + PCI171x_STATUS),
362 		dev->iobase + PCI171x_STATUS);
363 	for (n = 0; n < insn->n; n++) {
364 		outw(0, dev->iobase + PCI171x_SOFTTRG);	/* start conversion */
365 		DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
366 			inw(dev->iobase + PCI171x_STATUS));
367 		/* udelay(1); */
368 		DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
369 			inw(dev->iobase + PCI171x_STATUS));
370 		timeout = 100;
371 		while (timeout--) {
372 			if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
373 				goto conv_finish;
374 			if (!(timeout % 10))
375 				DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
376 					timeout,
377 					inw(dev->iobase + PCI171x_STATUS));
378 		}
379 		comedi_error(dev, "A/D insn timeout");
380 		outb(0, dev->iobase + PCI171x_CLRFIFO);
381 		outb(0, dev->iobase + PCI171x_CLRINT);
382 		data[n] = 0;
383 		DPRINTK
384 		    ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
385 		     n);
386 		return -ETIME;
387 
388 conv_finish:
389 #ifdef PCI171x_PARANOIDCHECK
390 		idata = inw(dev->iobase + PCI171x_AD_DATA);
391 		if (this_board->cardtype != TYPE_PCI1713)
392 			if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
393 				comedi_error(dev, "A/D insn data droput!");
394 				return -ETIME;
395 			}
396 		data[n] = idata & 0x0fff;
397 #else
398 		data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
399 #endif
400 
401 	}
402 
403 	outb(0, dev->iobase + PCI171x_CLRFIFO);
404 	outb(0, dev->iobase + PCI171x_CLRINT);
405 
406 	DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
407 	return n;
408 }
409 
410 /*
411 ==============================================================================
412 */
pci171x_insn_write_ao(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)413 static int pci171x_insn_write_ao(struct comedi_device *dev,
414 				 struct comedi_subdevice *s,
415 				 struct comedi_insn *insn, unsigned int *data)
416 {
417 	int n, chan, range, ofs;
418 
419 	chan = CR_CHAN(insn->chanspec);
420 	range = CR_RANGE(insn->chanspec);
421 	if (chan) {
422 		devpriv->da_ranges &= 0xfb;
423 		devpriv->da_ranges |= (range << 2);
424 		outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
425 		ofs = PCI171x_DA2;
426 	} else {
427 		devpriv->da_ranges &= 0xfe;
428 		devpriv->da_ranges |= range;
429 		outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
430 		ofs = PCI171x_DA1;
431 	}
432 
433 	for (n = 0; n < insn->n; n++)
434 		outw(data[n], dev->iobase + ofs);
435 
436 	devpriv->ao_data[chan] = data[n];
437 
438 	return n;
439 
440 }
441 
442 /*
443 ==============================================================================
444 */
pci171x_insn_read_ao(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)445 static int pci171x_insn_read_ao(struct comedi_device *dev,
446 				struct comedi_subdevice *s,
447 				struct comedi_insn *insn, unsigned int *data)
448 {
449 	int n, chan;
450 
451 	chan = CR_CHAN(insn->chanspec);
452 	for (n = 0; n < insn->n; n++)
453 		data[n] = devpriv->ao_data[chan];
454 
455 	return n;
456 }
457 
458 /*
459 ==============================================================================
460 */
pci171x_insn_bits_di(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)461 static int pci171x_insn_bits_di(struct comedi_device *dev,
462 				struct comedi_subdevice *s,
463 				struct comedi_insn *insn, unsigned int *data)
464 {
465 	data[1] = inw(dev->iobase + PCI171x_DI);
466 
467 	return 2;
468 }
469 
470 /*
471 ==============================================================================
472 */
pci171x_insn_bits_do(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)473 static int pci171x_insn_bits_do(struct comedi_device *dev,
474 				struct comedi_subdevice *s,
475 				struct comedi_insn *insn, unsigned int *data)
476 {
477 	if (data[0]) {
478 		s->state &= ~data[0];
479 		s->state |= (data[0] & data[1]);
480 		outw(s->state, dev->iobase + PCI171x_DO);
481 	}
482 	data[1] = s->state;
483 
484 	return 2;
485 }
486 
487 /*
488 ==============================================================================
489 */
pci171x_insn_counter_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)490 static int pci171x_insn_counter_read(struct comedi_device *dev,
491 				     struct comedi_subdevice *s,
492 				     struct comedi_insn *insn,
493 				     unsigned int *data)
494 {
495 	unsigned int msb, lsb, ccntrl;
496 	int i;
497 
498 	ccntrl = 0xD2;		/* count only */
499 	for (i = 0; i < insn->n; i++) {
500 		outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
501 
502 		lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
503 		msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
504 
505 		data[0] = lsb | (msb << 8);
506 	}
507 
508 	return insn->n;
509 }
510 
511 /*
512 ==============================================================================
513 */
pci171x_insn_counter_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)514 static int pci171x_insn_counter_write(struct comedi_device *dev,
515 				      struct comedi_subdevice *s,
516 				      struct comedi_insn *insn,
517 				      unsigned int *data)
518 {
519 	uint msb, lsb, ccntrl, status;
520 
521 	lsb = data[0] & 0x00FF;
522 	msb = (data[0] & 0xFF00) >> 8;
523 
524 	/* write lsb, then msb */
525 	outw(lsb, dev->iobase + PCI171x_CNT0);
526 	outw(msb, dev->iobase + PCI171x_CNT0);
527 
528 	if (devpriv->cnt0_write_wait) {
529 		/* wait for the new count to be loaded */
530 		ccntrl = 0xE2;
531 		do {
532 			outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
533 			status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
534 		} while (status & 0x40);
535 	}
536 
537 	return insn->n;
538 }
539 
540 /*
541 ==============================================================================
542 */
pci171x_insn_counter_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)543 static int pci171x_insn_counter_config(struct comedi_device *dev,
544 				       struct comedi_subdevice *s,
545 				       struct comedi_insn *insn,
546 				       unsigned int *data)
547 {
548 #ifdef unused
549 	/* This doesn't work like a normal Comedi counter config */
550 	uint ccntrl = 0;
551 
552 	devpriv->cnt0_write_wait = data[0] & 0x20;
553 
554 	/* internal or external clock? */
555 	if (!(data[0] & 0x10)) {	/* internal */
556 		devpriv->CntrlReg &= ~Control_CNT0;
557 	} else {
558 		devpriv->CntrlReg |= Control_CNT0;
559 	}
560 	outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
561 
562 	if (data[0] & 0x01)
563 		ccntrl |= Counter_M0;
564 	if (data[0] & 0x02)
565 		ccntrl |= Counter_M1;
566 	if (data[0] & 0x04)
567 		ccntrl |= Counter_M2;
568 	if (data[0] & 0x08)
569 		ccntrl |= Counter_BCD;
570 	ccntrl |= Counter_RW0;	/* set read/write mode */
571 	ccntrl |= Counter_RW1;
572 	outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
573 #endif
574 
575 	return 1;
576 }
577 
578 /*
579 ==============================================================================
580 */
pci1720_insn_write_ao(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)581 static int pci1720_insn_write_ao(struct comedi_device *dev,
582 				 struct comedi_subdevice *s,
583 				 struct comedi_insn *insn, unsigned int *data)
584 {
585 	int n, rangereg, chan;
586 
587 	chan = CR_CHAN(insn->chanspec);
588 	rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
589 	rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
590 	if (rangereg != devpriv->da_ranges) {
591 		outb(rangereg, dev->iobase + PCI1720_RANGE);
592 		devpriv->da_ranges = rangereg;
593 	}
594 
595 	for (n = 0; n < insn->n; n++) {
596 		outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
597 		outb(0, dev->iobase + PCI1720_SYNCOUT);	/*  update outputs */
598 	}
599 
600 	devpriv->ao_data[chan] = data[n];
601 
602 	return n;
603 }
604 
605 /*
606 ==============================================================================
607 */
interrupt_pci1710_every_sample(void * d)608 static void interrupt_pci1710_every_sample(void *d)
609 {
610 	struct comedi_device *dev = d;
611 	struct comedi_subdevice *s = dev->subdevices + 0;
612 	int m;
613 #ifdef PCI171x_PARANOIDCHECK
614 	short sampl;
615 #endif
616 
617 	DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
618 	m = inw(dev->iobase + PCI171x_STATUS);
619 	if (m & Status_FE) {
620 		printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
621 		pci171x_ai_cancel(dev, s);
622 		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
623 		comedi_event(dev, s);
624 		return;
625 	}
626 	if (m & Status_FF) {
627 		printk
628 		    ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
629 		     dev->minor, m);
630 		pci171x_ai_cancel(dev, s);
631 		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
632 		comedi_event(dev, s);
633 		return;
634 	}
635 
636 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
637 
638 	DPRINTK("FOR ");
639 	for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
640 #ifdef PCI171x_PARANOIDCHECK
641 		sampl = inw(dev->iobase + PCI171x_AD_DATA);
642 		DPRINTK("%04x:", sampl);
643 		if (this_board->cardtype != TYPE_PCI1713)
644 			if ((sampl & 0xf000) !=
645 			    devpriv->act_chanlist[s->async->cur_chan]) {
646 				printk
647 				    ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
648 				     (sampl & 0xf000) >> 12,
649 				     (devpriv->
650 				      act_chanlist[s->
651 						   async->cur_chan] & 0xf000) >>
652 				     12);
653 				pci171x_ai_cancel(dev, s);
654 				s->async->events |=
655 				    COMEDI_CB_EOA | COMEDI_CB_ERROR;
656 				comedi_event(dev, s);
657 				return;
658 			}
659 		DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
660 			s->async->cur_chan, s->async->buf_int_count);
661 		comedi_buf_put(s->async, sampl & 0x0fff);
662 #else
663 		comedi_buf_put(s->async,
664 			       inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
665 #endif
666 		++s->async->cur_chan;
667 
668 		if (s->async->cur_chan >= devpriv->ai_n_chan)
669 			s->async->cur_chan = 0;
670 
671 
672 		if (s->async->cur_chan == 0) {	/*  one scan done */
673 			devpriv->ai_act_scan++;
674 			DPRINTK
675 			    ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
676 			     s->async->buf_int_count, s->async->buf_int_ptr,
677 			     s->async->buf_user_count, s->async->buf_user_ptr);
678 			DPRINTK("adv_pci1710 EDBG: EOS2\n");
679 			if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) {	/*  all data sampled */
680 				pci171x_ai_cancel(dev, s);
681 				s->async->events |= COMEDI_CB_EOA;
682 				comedi_event(dev, s);
683 				return;
684 			}
685 		}
686 	}
687 
688 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
689 	DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
690 
691 	comedi_event(dev, s);
692 }
693 
694 /*
695 ==============================================================================
696 */
move_block_from_fifo(struct comedi_device * dev,struct comedi_subdevice * s,int n,int turn)697 static int move_block_from_fifo(struct comedi_device *dev,
698 				struct comedi_subdevice *s, int n, int turn)
699 {
700 	int i, j;
701 #ifdef PCI171x_PARANOIDCHECK
702 	int sampl;
703 #endif
704 	DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
705 		turn);
706 	j = s->async->cur_chan;
707 	for (i = 0; i < n; i++) {
708 #ifdef PCI171x_PARANOIDCHECK
709 		sampl = inw(dev->iobase + PCI171x_AD_DATA);
710 		if (this_board->cardtype != TYPE_PCI1713)
711 			if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
712 				printk
713 				    ("comedi%d: A/D  FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
714 				     dev->minor, (sampl & 0xf000) >> 12,
715 				     (devpriv->act_chanlist[j] & 0xf000) >> 12,
716 				     i, j, devpriv->ai_act_scan, n, turn,
717 				     sampl);
718 				pci171x_ai_cancel(dev, s);
719 				s->async->events |=
720 				    COMEDI_CB_EOA | COMEDI_CB_ERROR;
721 				comedi_event(dev, s);
722 				return 1;
723 			}
724 		comedi_buf_put(s->async, sampl & 0x0fff);
725 #else
726 		comedi_buf_put(s->async,
727 			       inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
728 #endif
729 		j++;
730 		if (j >= devpriv->ai_n_chan) {
731 			j = 0;
732 			devpriv->ai_act_scan++;
733 		}
734 	}
735 	s->async->cur_chan = j;
736 	DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
737 	return 0;
738 }
739 
740 /*
741 ==============================================================================
742 */
interrupt_pci1710_half_fifo(void * d)743 static void interrupt_pci1710_half_fifo(void *d)
744 {
745 	struct comedi_device *dev = d;
746 	struct comedi_subdevice *s = dev->subdevices + 0;
747 	int m, samplesinbuf;
748 
749 	DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
750 	m = inw(dev->iobase + PCI171x_STATUS);
751 	if (!(m & Status_FH)) {
752 		printk("comedi%d: A/D FIFO not half full! (%4x)\n",
753 		       dev->minor, m);
754 		pci171x_ai_cancel(dev, s);
755 		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
756 		comedi_event(dev, s);
757 		return;
758 	}
759 	if (m & Status_FF) {
760 		printk
761 		    ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
762 		     dev->minor, m);
763 		pci171x_ai_cancel(dev, s);
764 		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
765 		comedi_event(dev, s);
766 		return;
767 	}
768 
769 	samplesinbuf = this_board->fifo_half_size;
770 	if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
771 		m = devpriv->ai_data_len / sizeof(short);
772 		if (move_block_from_fifo(dev, s, m, 0))
773 			return;
774 		samplesinbuf -= m;
775 	}
776 
777 	if (samplesinbuf) {
778 		if (move_block_from_fifo(dev, s, samplesinbuf, 1))
779 			return;
780 	}
781 
782 	if (!devpriv->neverending_ai)
783 		if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
784 								    sampled */
785 			pci171x_ai_cancel(dev, s);
786 			s->async->events |= COMEDI_CB_EOA;
787 			comedi_event(dev, s);
788 			return;
789 		}
790 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
791 	DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
792 
793 	comedi_event(dev, s);
794 }
795 
796 /*
797 ==============================================================================
798 */
interrupt_service_pci1710(int irq,void * d)799 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
800 {
801 	struct comedi_device *dev = d;
802 
803 	DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
804 		irq);
805 	if (!dev->attached)	/*  is device attached? */
806 		return IRQ_NONE;	/*  no, exit */
807 
808 	if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))	/*  is this interrupt from our board? */
809 		return IRQ_NONE;	/*  no, exit */
810 
811 	DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
812 		inw(dev->iobase + PCI171x_STATUS));
813 
814 	if (devpriv->ai_et) {	/*  Switch from initial TRIG_EXT to TRIG_xxx. */
815 		devpriv->ai_et = 0;
816 		devpriv->CntrlReg &= Control_CNT0;
817 		devpriv->CntrlReg |= Control_SW;	/*  set software trigger */
818 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
819 		devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
820 		outb(0, dev->iobase + PCI171x_CLRFIFO);
821 		outb(0, dev->iobase + PCI171x_CLRINT);
822 		outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
823 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
824 		/*  start pacer */
825 		start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
826 		return IRQ_HANDLED;
827 	}
828 	if (devpriv->ai_eos) {	/*  We use FIFO half full INT or not? */
829 		interrupt_pci1710_every_sample(d);
830 	} else {
831 		interrupt_pci1710_half_fifo(d);
832 	}
833 	DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
834 	return IRQ_HANDLED;
835 }
836 
837 /*
838 ==============================================================================
839 */
pci171x_ai_docmd_and_mode(int mode,struct comedi_device * dev,struct comedi_subdevice * s)840 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
841 				     struct comedi_subdevice *s)
842 {
843 	unsigned int divisor1 = 0, divisor2 = 0;
844 	unsigned int seglen;
845 
846 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
847 		mode);
848 	start_pacer(dev, -1, 0, 0);	/*  stop pacer */
849 
850 	seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
851 				    devpriv->ai_n_chan);
852 	if (seglen < 1)
853 		return -EINVAL;
854 	setup_channel_list(dev, s, devpriv->ai_chanlist,
855 			   devpriv->ai_n_chan, seglen);
856 
857 	outb(0, dev->iobase + PCI171x_CLRFIFO);
858 	outb(0, dev->iobase + PCI171x_CLRINT);
859 
860 	devpriv->ai_do = mode;
861 
862 	devpriv->ai_act_scan = 0;
863 	s->async->cur_chan = 0;
864 	devpriv->ai_buf_ptr = 0;
865 	devpriv->neverending_ai = 0;
866 
867 	devpriv->CntrlReg &= Control_CNT0;
868 	if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {	/*  don't we want wake up every scan?            devpriv->ai_eos=1; */
869 		devpriv->ai_eos = 1;
870 	} else {
871 		devpriv->CntrlReg |= Control_ONEFH;
872 		devpriv->ai_eos = 0;
873 	}
874 
875 	if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
876 		devpriv->neverending_ai = 1;
877 	/* well, user want neverending */
878 	else
879 		devpriv->neverending_ai = 0;
880 
881 	switch (mode) {
882 	case 1:
883 	case 2:
884 		if (devpriv->ai_timer1 < this_board->ai_ns_min)
885 			devpriv->ai_timer1 = this_board->ai_ns_min;
886 		devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
887 		if (mode == 2) {
888 			devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
889 			devpriv->CntrlReg &=
890 			    ~(Control_PACER | Control_ONEFH | Control_GATE);
891 			devpriv->CntrlReg |= Control_EXT;
892 			devpriv->ai_et = 1;
893 		} else {
894 			devpriv->ai_et = 0;
895 		}
896 		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
897 					  &divisor2, &devpriv->ai_timer1,
898 					  devpriv->ai_flags & TRIG_ROUND_MASK);
899 		DPRINTK
900 		    ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
901 		     devpriv->i8254_osc_base, divisor1, divisor2,
902 		     devpriv->ai_timer1);
903 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
904 		if (mode != 2) {
905 			/*  start pacer */
906 			start_pacer(dev, mode, divisor1, divisor2);
907 		} else {
908 			devpriv->ai_et_div1 = divisor1;
909 			devpriv->ai_et_div2 = divisor2;
910 		}
911 		break;
912 	case 3:
913 		devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
914 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
915 		break;
916 	}
917 
918 	DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
919 	return 0;
920 }
921 
922 #ifdef PCI171X_EXTDEBUG
923 /*
924 ==============================================================================
925 */
pci171x_cmdtest_out(int e,struct comedi_cmd * cmd)926 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
927 {
928 	printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
929 	       cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
930 	printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
931 	       cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
932 	printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
933 	       cmd->scan_end_src);
934 	printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
935 	       e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
936 }
937 #endif
938 
939 /*
940 ==============================================================================
941 */
pci171x_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)942 static int pci171x_ai_cmdtest(struct comedi_device *dev,
943 			      struct comedi_subdevice *s,
944 			      struct comedi_cmd *cmd)
945 {
946 	int err = 0;
947 	int tmp;
948 	unsigned int divisor1 = 0, divisor2 = 0;
949 
950 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
951 #ifdef PCI171X_EXTDEBUG
952 	pci171x_cmdtest_out(-1, cmd);
953 #endif
954 	/* step 1: make sure trigger sources are trivially valid */
955 
956 	tmp = cmd->start_src;
957 	cmd->start_src &= TRIG_NOW | TRIG_EXT;
958 	if (!cmd->start_src || tmp != cmd->start_src)
959 		err++;
960 
961 	tmp = cmd->scan_begin_src;
962 	cmd->scan_begin_src &= TRIG_FOLLOW;
963 	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
964 		err++;
965 
966 	tmp = cmd->convert_src;
967 	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
968 	if (!cmd->convert_src || tmp != cmd->convert_src)
969 		err++;
970 
971 	tmp = cmd->scan_end_src;
972 	cmd->scan_end_src &= TRIG_COUNT;
973 	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
974 		err++;
975 
976 	tmp = cmd->stop_src;
977 	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
978 	if (!cmd->stop_src || tmp != cmd->stop_src)
979 		err++;
980 
981 	if (err) {
982 #ifdef PCI171X_EXTDEBUG
983 		pci171x_cmdtest_out(1, cmd);
984 #endif
985 		DPRINTK
986 		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
987 		     err);
988 		return 1;
989 	}
990 
991 	/* step 2: make sure trigger sources are unique and mutually compatible */
992 
993 	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
994 		cmd->start_src = TRIG_NOW;
995 		err++;
996 	}
997 
998 	if (cmd->scan_begin_src != TRIG_FOLLOW) {
999 		cmd->scan_begin_src = TRIG_FOLLOW;
1000 		err++;
1001 	}
1002 
1003 	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1004 		err++;
1005 
1006 	if (cmd->scan_end_src != TRIG_COUNT) {
1007 		cmd->scan_end_src = TRIG_COUNT;
1008 		err++;
1009 	}
1010 
1011 	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1012 		err++;
1013 
1014 	if (err) {
1015 #ifdef PCI171X_EXTDEBUG
1016 		pci171x_cmdtest_out(2, cmd);
1017 #endif
1018 		DPRINTK
1019 		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1020 		     err);
1021 		return 2;
1022 	}
1023 
1024 	/* step 3: make sure arguments are trivially compatible */
1025 
1026 	if (cmd->start_arg != 0) {
1027 		cmd->start_arg = 0;
1028 		err++;
1029 	}
1030 
1031 	if (cmd->scan_begin_arg != 0) {
1032 		cmd->scan_begin_arg = 0;
1033 		err++;
1034 	}
1035 
1036 	if (cmd->convert_src == TRIG_TIMER) {
1037 		if (cmd->convert_arg < this_board->ai_ns_min) {
1038 			cmd->convert_arg = this_board->ai_ns_min;
1039 			err++;
1040 		}
1041 	} else {		/* TRIG_FOLLOW */
1042 		if (cmd->convert_arg != 0) {
1043 			cmd->convert_arg = 0;
1044 			err++;
1045 		}
1046 	}
1047 
1048 	if (cmd->scan_end_arg != cmd->chanlist_len) {
1049 		cmd->scan_end_arg = cmd->chanlist_len;
1050 		err++;
1051 	}
1052 	if (cmd->stop_src == TRIG_COUNT) {
1053 		if (!cmd->stop_arg) {
1054 			cmd->stop_arg = 1;
1055 			err++;
1056 		}
1057 	} else {		/* TRIG_NONE */
1058 		if (cmd->stop_arg != 0) {
1059 			cmd->stop_arg = 0;
1060 			err++;
1061 		}
1062 	}
1063 
1064 	if (err) {
1065 #ifdef PCI171X_EXTDEBUG
1066 		pci171x_cmdtest_out(3, cmd);
1067 #endif
1068 		DPRINTK
1069 		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1070 		     err);
1071 		return 3;
1072 	}
1073 
1074 	/* step 4: fix up any arguments */
1075 
1076 	if (cmd->convert_src == TRIG_TIMER) {
1077 		tmp = cmd->convert_arg;
1078 		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1079 					  &divisor2, &cmd->convert_arg,
1080 					  cmd->flags & TRIG_ROUND_MASK);
1081 		if (cmd->convert_arg < this_board->ai_ns_min)
1082 			cmd->convert_arg = this_board->ai_ns_min;
1083 		if (tmp != cmd->convert_arg)
1084 			err++;
1085 	}
1086 
1087 	if (err) {
1088 		DPRINTK
1089 		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1090 		     err);
1091 		return 4;
1092 	}
1093 
1094 	/* step 5: complain about special chanlist considerations */
1095 
1096 	if (cmd->chanlist) {
1097 		if (!check_channel_list(dev, s, cmd->chanlist,
1098 					cmd->chanlist_len))
1099 			return 5;	/*  incorrect channels list */
1100 	}
1101 
1102 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1103 	return 0;
1104 }
1105 
1106 /*
1107 ==============================================================================
1108 */
pci171x_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)1109 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1110 {
1111 	struct comedi_cmd *cmd = &s->async->cmd;
1112 
1113 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1114 	devpriv->ai_n_chan = cmd->chanlist_len;
1115 	devpriv->ai_chanlist = cmd->chanlist;
1116 	devpriv->ai_flags = cmd->flags;
1117 	devpriv->ai_data_len = s->async->prealloc_bufsz;
1118 	devpriv->ai_data = s->async->prealloc_buf;
1119 	devpriv->ai_timer1 = 0;
1120 	devpriv->ai_timer2 = 0;
1121 
1122 	if (cmd->stop_src == TRIG_COUNT)
1123 		devpriv->ai_scans = cmd->stop_arg;
1124 	else
1125 		devpriv->ai_scans = 0;
1126 
1127 
1128 	if (cmd->scan_begin_src == TRIG_FOLLOW) {	/*  mode 1, 2, 3 */
1129 		if (cmd->convert_src == TRIG_TIMER) {	/*  mode 1 and 2 */
1130 			devpriv->ai_timer1 = cmd->convert_arg;
1131 			return pci171x_ai_docmd_and_mode(cmd->start_src ==
1132 							 TRIG_EXT ? 2 : 1, dev,
1133 							 s);
1134 		}
1135 		if (cmd->convert_src == TRIG_EXT) {	/*  mode 3 */
1136 			return pci171x_ai_docmd_and_mode(3, dev, s);
1137 		}
1138 	}
1139 
1140 	return -1;
1141 }
1142 
1143 /*
1144 ==============================================================================
1145  Check if channel list from user is builded correctly
1146  If it's ok, then program scan/gain logic.
1147  This works for all cards.
1148 */
check_channel_list(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int n_chan)1149 static int check_channel_list(struct comedi_device *dev,
1150 			      struct comedi_subdevice *s,
1151 			      unsigned int *chanlist, unsigned int n_chan)
1152 {
1153 	unsigned int chansegment[32];
1154 	unsigned int i, nowmustbechan, seglen, segpos;
1155 
1156 	DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
1157 	/* correct channel and range number check itself comedi/range.c */
1158 	if (n_chan < 1) {
1159 		comedi_error(dev, "range/channel list is empty!");
1160 		return 0;
1161 	}
1162 
1163 	if (n_chan > 1) {
1164 		chansegment[0] = chanlist[0];	/*  first channel is every time ok */
1165 		for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {	/*  build part of chanlist */
1166 			/*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1167 			if (chanlist[0] == chanlist[i])
1168 				break;	/*  we detect loop, this must by finish */
1169 			if (CR_CHAN(chanlist[i]) & 1)	/*  odd channel cann't by differencial */
1170 				if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1171 					comedi_error(dev,
1172 						     "Odd channel can't be differential input!\n");
1173 					return 0;
1174 				}
1175 			nowmustbechan =
1176 			    (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1177 			if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1178 				nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1179 			if (nowmustbechan != CR_CHAN(chanlist[i])) {	/*  channel list isn't continuous :-( */
1180 				printk
1181 				    ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1182 				     i, CR_CHAN(chanlist[i]), nowmustbechan,
1183 				     CR_CHAN(chanlist[0]));
1184 				return 0;
1185 			}
1186 			chansegment[i] = chanlist[i];	/*  well, this is next correct channel in list */
1187 		}
1188 
1189 		for (i = 0, segpos = 0; i < n_chan; i++) {	/*  check whole chanlist */
1190 			/* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1191 			if (chanlist[i] != chansegment[i % seglen]) {
1192 				printk
1193 				    ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1194 				     i, CR_CHAN(chansegment[i]),
1195 				     CR_RANGE(chansegment[i]),
1196 				     CR_AREF(chansegment[i]),
1197 				     CR_CHAN(chanlist[i % seglen]),
1198 				     CR_RANGE(chanlist[i % seglen]),
1199 				     CR_AREF(chansegment[i % seglen]));
1200 				return 0;	/*  chan/gain list is strange */
1201 			}
1202 		}
1203 	} else {
1204 		seglen = 1;
1205 	}
1206 	return seglen;
1207 }
1208 
setup_channel_list(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int n_chan,unsigned int seglen)1209 static void setup_channel_list(struct comedi_device *dev,
1210 			       struct comedi_subdevice *s,
1211 			       unsigned int *chanlist, unsigned int n_chan,
1212 			       unsigned int seglen)
1213 {
1214 	unsigned int i, range, chanprog;
1215 
1216 	DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
1217 		seglen);
1218 	devpriv->act_chanlist_len = seglen;
1219 	devpriv->act_chanlist_pos = 0;
1220 
1221 	DPRINTK("SegLen: %d\n", seglen);
1222 	for (i = 0; i < seglen; i++) {	/*  store range list to card */
1223 		chanprog = muxonechan[CR_CHAN(chanlist[i])];
1224 		outw(chanprog, dev->iobase + PCI171x_MUX);	/* select channel */
1225 		range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1226 		if (CR_AREF(chanlist[i]) == AREF_DIFF)
1227 			range |= 0x0020;
1228 		outw(range, dev->iobase + PCI171x_RANGE);	/* select gain */
1229 #ifdef PCI171x_PARANOIDCHECK
1230 		devpriv->act_chanlist[i] =
1231 		    (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1232 #endif
1233 		DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1234 			devpriv->act_chanlist[i]);
1235 	}
1236 #ifdef PCI171x_PARANOIDCHECK
1237 	for ( ; i < n_chan; i++) { /* store remainder of channel list */
1238 		devpriv->act_chanlist[i] =
1239 		    (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1240 	}
1241 #endif
1242 
1243 	devpriv->ai_et_MuxVal =
1244 	    CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1245 	outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);	/* select channel interval to scan */
1246 	DPRINTK("MUX: %4x L%4x.H%4x\n",
1247 		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1248 		CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1249 }
1250 
1251 /*
1252 ==============================================================================
1253 */
start_pacer(struct comedi_device * dev,int mode,unsigned int divisor1,unsigned int divisor2)1254 static void start_pacer(struct comedi_device *dev, int mode,
1255 			unsigned int divisor1, unsigned int divisor2)
1256 {
1257 	DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1258 		divisor1, divisor2);
1259 	outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1260 	outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1261 
1262 	if (mode == 1) {
1263 		outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1264 		outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1265 		outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1266 		outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1267 	}
1268 	DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1269 }
1270 
1271 /*
1272 ==============================================================================
1273 */
pci171x_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)1274 static int pci171x_ai_cancel(struct comedi_device *dev,
1275 			     struct comedi_subdevice *s)
1276 {
1277 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1278 
1279 	switch (this_board->cardtype) {
1280 	default:
1281 		devpriv->CntrlReg &= Control_CNT0;
1282 		devpriv->CntrlReg |= Control_SW;
1283 
1284 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);	/*  reset any operations */
1285 		start_pacer(dev, -1, 0, 0);
1286 		outb(0, dev->iobase + PCI171x_CLRFIFO);
1287 		outb(0, dev->iobase + PCI171x_CLRINT);
1288 		break;
1289 	}
1290 
1291 	devpriv->ai_do = 0;
1292 	devpriv->ai_act_scan = 0;
1293 	s->async->cur_chan = 0;
1294 	devpriv->ai_buf_ptr = 0;
1295 	devpriv->neverending_ai = 0;
1296 
1297 	DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1298 	return 0;
1299 }
1300 
1301 /*
1302 ==============================================================================
1303 */
pci171x_reset(struct comedi_device * dev)1304 static int pci171x_reset(struct comedi_device *dev)
1305 {
1306 	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1307 	outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1308 	devpriv->CntrlReg = Control_SW | Control_CNT0;	/*  Software trigger, CNT0=external */
1309 	outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);	/*  reset any operations */
1310 	outb(0, dev->iobase + PCI171x_CLRFIFO);	/*  clear FIFO */
1311 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear INT request */
1312 	start_pacer(dev, -1, 0, 0);	/*  stop 8254 */
1313 	devpriv->da_ranges = 0;
1314 	if (this_board->n_aochan) {
1315 		outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);	/*  set DACs to 0..5V */
1316 		outw(0, dev->iobase + PCI171x_DA1);	/*  set DA outputs to 0V */
1317 		devpriv->ao_data[0] = 0x0000;
1318 		if (this_board->n_aochan > 1) {
1319 			outw(0, dev->iobase + PCI171x_DA2);
1320 			devpriv->ao_data[1] = 0x0000;
1321 		}
1322 	}
1323 	outw(0, dev->iobase + PCI171x_DO);	/*  digital outputs to 0 */
1324 	outb(0, dev->iobase + PCI171x_CLRFIFO);	/*  clear FIFO */
1325 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear INT request */
1326 
1327 	DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1328 	return 0;
1329 }
1330 
1331 /*
1332 ==============================================================================
1333 */
pci1720_reset(struct comedi_device * dev)1334 static int pci1720_reset(struct comedi_device *dev)
1335 {
1336 	DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1337 	outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);	/*  set synchronous output mode */
1338 	devpriv->da_ranges = 0xAA;
1339 	outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);	/*  set all ranges to +/-5V */
1340 	outw(0x0800, dev->iobase + PCI1720_DA0);	/*  set outputs to 0V */
1341 	outw(0x0800, dev->iobase + PCI1720_DA1);
1342 	outw(0x0800, dev->iobase + PCI1720_DA2);
1343 	outw(0x0800, dev->iobase + PCI1720_DA3);
1344 	outb(0, dev->iobase + PCI1720_SYNCOUT);	/*  update outputs */
1345 	devpriv->ao_data[0] = 0x0800;
1346 	devpriv->ao_data[1] = 0x0800;
1347 	devpriv->ao_data[2] = 0x0800;
1348 	devpriv->ao_data[3] = 0x0800;
1349 	DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1350 	return 0;
1351 }
1352 
1353 /*
1354 ==============================================================================
1355 */
pci1710_reset(struct comedi_device * dev)1356 static int pci1710_reset(struct comedi_device *dev)
1357 {
1358 	DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1359 	switch (this_board->cardtype) {
1360 	case TYPE_PCI1720:
1361 		return pci1720_reset(dev);
1362 	default:
1363 		return pci171x_reset(dev);
1364 	}
1365 	DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1366 }
1367 
1368 /*
1369 ==============================================================================
1370 */
pci1710_attach(struct comedi_device * dev,struct comedi_devconfig * it)1371 static int pci1710_attach(struct comedi_device *dev,
1372 			  struct comedi_devconfig *it)
1373 {
1374 	struct comedi_subdevice *s;
1375 	int ret, subdev, n_subdevices;
1376 	unsigned int irq;
1377 	unsigned long iobase;
1378 	struct pci_dev *pcidev;
1379 	int opt_bus, opt_slot;
1380 	const char *errstr;
1381 	unsigned char pci_bus, pci_slot, pci_func;
1382 	int i;
1383 	int board_index;
1384 
1385 	dev_info(dev->hw_dev, "comedi%d: adv_pci1710:\n", dev->minor);
1386 
1387 	opt_bus = it->options[0];
1388 	opt_slot = it->options[1];
1389 
1390 	ret = alloc_private(dev, sizeof(struct pci1710_private));
1391 	if (ret < 0)
1392 		return -ENOMEM;
1393 
1394 	/* Look for matching PCI device */
1395 	errstr = "not found!";
1396 	pcidev = NULL;
1397 	board_index = this_board - boardtypes;
1398 	while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1399 						PCI_ANY_ID, pcidev))) {
1400 		if (strcmp(this_board->name, DRV_NAME) == 0) {
1401 			for (i = 0; i < n_boardtypes; ++i) {
1402 				if (pcidev->device == boardtypes[i].device_id) {
1403 					board_index = i;
1404 					break;
1405 				}
1406 			}
1407 			if (i == n_boardtypes)
1408 				continue;
1409 		} else {
1410 			if (pcidev->device != boardtypes[board_index].device_id)
1411 				continue;
1412 		}
1413 
1414 		/* Found matching vendor/device. */
1415 		if (opt_bus || opt_slot) {
1416 			/* Check bus/slot. */
1417 			if (opt_bus != pcidev->bus->number
1418 			    || opt_slot != PCI_SLOT(pcidev->devfn))
1419 				continue;	/* no match */
1420 		}
1421 		/*
1422 		 * Look for device that isn't in use.
1423 		 * Enable PCI device and request regions.
1424 		 */
1425 		if (comedi_pci_enable(pcidev, DRV_NAME)) {
1426 			errstr =
1427 			    "failed to enable PCI device and request regions!";
1428 			continue;
1429 		}
1430 		/*  fixup board_ptr in case we were using the dummy entry with the driver name */
1431 		dev->board_ptr = &boardtypes[board_index];
1432 		break;
1433 	}
1434 
1435 	if (!pcidev) {
1436 		if (opt_bus || opt_slot) {
1437 			dev_err(dev->hw_dev, "- Card at b:s %d:%d %s\n",
1438 				opt_bus, opt_slot, errstr);
1439 		} else {
1440 			dev_err(dev->hw_dev, "- Card %s\n", errstr);
1441 		}
1442 		return -EIO;
1443 	}
1444 
1445 	pci_bus = pcidev->bus->number;
1446 	pci_slot = PCI_SLOT(pcidev->devfn);
1447 	pci_func = PCI_FUNC(pcidev->devfn);
1448 	irq = pcidev->irq;
1449 	iobase = pci_resource_start(pcidev, 2);
1450 
1451 	dev_dbg(dev->hw_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n", pci_bus, pci_slot,
1452 		pci_func, iobase);
1453 
1454 	dev->iobase = iobase;
1455 
1456 	dev->board_name = this_board->name;
1457 	devpriv->pcidev = pcidev;
1458 
1459 	n_subdevices = 0;
1460 	if (this_board->n_aichan)
1461 		n_subdevices++;
1462 	if (this_board->n_aochan)
1463 		n_subdevices++;
1464 	if (this_board->n_dichan)
1465 		n_subdevices++;
1466 	if (this_board->n_dochan)
1467 		n_subdevices++;
1468 	if (this_board->n_counter)
1469 		n_subdevices++;
1470 
1471 	ret = alloc_subdevices(dev, n_subdevices);
1472 	if (ret < 0)
1473 		return ret;
1474 
1475 	pci1710_reset(dev);
1476 
1477 	if (this_board->have_irq) {
1478 		if (irq) {
1479 			if (request_irq(irq, interrupt_service_pci1710,
1480 					IRQF_SHARED, "Advantech PCI-1710",
1481 					dev)) {
1482 				dev_dbg(dev->hw_dev, "unable to allocate IRQ %d, DISABLING IT",
1483 					irq);
1484 				irq = 0;	/* Can't use IRQ */
1485 			} else {
1486 				dev_dbg(dev->hw_dev, "irq=%u", irq);
1487 			}
1488 		} else {
1489 			dev_dbg(dev->hw_dev, "IRQ disabled");
1490 		}
1491 	} else {
1492 		irq = 0;
1493 	}
1494 
1495 	dev->irq = irq;
1496 	subdev = 0;
1497 
1498 	if (this_board->n_aichan) {
1499 		s = dev->subdevices + subdev;
1500 		dev->read_subdev = s;
1501 		s->type = COMEDI_SUBD_AI;
1502 		s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1503 		if (this_board->n_aichand)
1504 			s->subdev_flags |= SDF_DIFF;
1505 		s->n_chan = this_board->n_aichan;
1506 		s->maxdata = this_board->ai_maxdata;
1507 		s->len_chanlist = this_board->n_aichan;
1508 		s->range_table = this_board->rangelist_ai;
1509 		s->cancel = pci171x_ai_cancel;
1510 		s->insn_read = pci171x_insn_read_ai;
1511 		if (irq) {
1512 			s->subdev_flags |= SDF_CMD_READ;
1513 			s->do_cmdtest = pci171x_ai_cmdtest;
1514 			s->do_cmd = pci171x_ai_cmd;
1515 		}
1516 		devpriv->i8254_osc_base = 100;	/*  100ns=10MHz */
1517 		subdev++;
1518 	}
1519 
1520 	if (this_board->n_aochan) {
1521 		s = dev->subdevices + subdev;
1522 		s->type = COMEDI_SUBD_AO;
1523 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1524 		s->n_chan = this_board->n_aochan;
1525 		s->maxdata = this_board->ao_maxdata;
1526 		s->len_chanlist = this_board->n_aochan;
1527 		s->range_table = this_board->rangelist_ao;
1528 		switch (this_board->cardtype) {
1529 		case TYPE_PCI1720:
1530 			s->insn_write = pci1720_insn_write_ao;
1531 			break;
1532 		default:
1533 			s->insn_write = pci171x_insn_write_ao;
1534 			break;
1535 		}
1536 		s->insn_read = pci171x_insn_read_ao;
1537 		subdev++;
1538 	}
1539 
1540 	if (this_board->n_dichan) {
1541 		s = dev->subdevices + subdev;
1542 		s->type = COMEDI_SUBD_DI;
1543 		s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1544 		s->n_chan = this_board->n_dichan;
1545 		s->maxdata = 1;
1546 		s->len_chanlist = this_board->n_dichan;
1547 		s->range_table = &range_digital;
1548 		s->io_bits = 0;	/* all bits input */
1549 		s->insn_bits = pci171x_insn_bits_di;
1550 		subdev++;
1551 	}
1552 
1553 	if (this_board->n_dochan) {
1554 		s = dev->subdevices + subdev;
1555 		s->type = COMEDI_SUBD_DO;
1556 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1557 		s->n_chan = this_board->n_dochan;
1558 		s->maxdata = 1;
1559 		s->len_chanlist = this_board->n_dochan;
1560 		s->range_table = &range_digital;
1561 		/* all bits output */
1562 		s->io_bits = (1 << this_board->n_dochan) - 1;
1563 		s->state = 0;
1564 		s->insn_bits = pci171x_insn_bits_do;
1565 		subdev++;
1566 	}
1567 
1568 	if (this_board->n_counter) {
1569 		s = dev->subdevices + subdev;
1570 		s->type = COMEDI_SUBD_COUNTER;
1571 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1572 		s->n_chan = this_board->n_counter;
1573 		s->len_chanlist = this_board->n_counter;
1574 		s->maxdata = 0xffff;
1575 		s->range_table = &range_unknown;
1576 		s->insn_read = pci171x_insn_counter_read;
1577 		s->insn_write = pci171x_insn_counter_write;
1578 		s->insn_config = pci171x_insn_counter_config;
1579 		subdev++;
1580 	}
1581 
1582 	devpriv->valid = 1;
1583 
1584 	return 0;
1585 }
1586 
1587 /*
1588 ==============================================================================
1589 */
pci1710_detach(struct comedi_device * dev)1590 static int pci1710_detach(struct comedi_device *dev)
1591 {
1592 
1593 	if (dev->private) {
1594 		if (devpriv->valid)
1595 			pci1710_reset(dev);
1596 		if (dev->irq)
1597 			free_irq(dev->irq, dev);
1598 		if (devpriv->pcidev) {
1599 			if (dev->iobase)
1600 				comedi_pci_disable(devpriv->pcidev);
1601 
1602 			pci_dev_put(devpriv->pcidev);
1603 		}
1604 	}
1605 
1606 	return 0;
1607 }
1608 
1609 /*
1610 ==============================================================================
1611 */
driver_pci1710_pci_probe(struct pci_dev * dev,const struct pci_device_id * ent)1612 static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
1613 					      const struct pci_device_id *ent)
1614 {
1615 	return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
1616 }
1617 
driver_pci1710_pci_remove(struct pci_dev * dev)1618 static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
1619 {
1620 	comedi_pci_auto_unconfig(dev);
1621 }
1622 
1623 static struct pci_driver driver_pci1710_pci_driver = {
1624 	.id_table = pci1710_pci_table,
1625 	.probe = &driver_pci1710_pci_probe,
1626 	.remove = __devexit_p(&driver_pci1710_pci_remove)
1627 };
1628 
driver_pci1710_init_module(void)1629 static int __init driver_pci1710_init_module(void)
1630 {
1631 	int retval;
1632 
1633 	retval = comedi_driver_register(&driver_pci1710);
1634 	if (retval < 0)
1635 		return retval;
1636 
1637 	driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
1638 	return pci_register_driver(&driver_pci1710_pci_driver);
1639 }
1640 
driver_pci1710_cleanup_module(void)1641 static void __exit driver_pci1710_cleanup_module(void)
1642 {
1643 	pci_unregister_driver(&driver_pci1710_pci_driver);
1644 	comedi_driver_unregister(&driver_pci1710);
1645 }
1646 
1647 module_init(driver_pci1710_init_module);
1648 module_exit(driver_pci1710_cleanup_module);
1649 /*
1650 ==============================================================================
1651 */
1652 
1653 MODULE_AUTHOR("Comedi http://www.comedi.org");
1654 MODULE_DESCRIPTION("Comedi low-level driver");
1655 MODULE_LICENSE("GPL");
1656