adv_pci1710.c revision d991058efbc140957af0f3338ad6f52448c2890e
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/*
20Driver: adv_pci1710
21Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
22	     Advantech PCI-1720, PCI-1731
23Author: Michal Dobes <dobes@tesnet.cz>
24Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
25  PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
26  PCI-1731
27Status: works
28
29This driver supports AI, AO, DI and DO subdevices.
30AI subdevice supports cmd and insn interface,
31other subdevices support only insn interface.
32
33The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
34driver cannot distinguish between them, as would be normal for a
35PCI driver.
36
37Configuration 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 occured */
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
133static 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
146static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147					      0x10, 0x11, 0x12, 0x13 };
148
149static 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
165static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
166					      0x05, 0x06, 0x07, 0x10, 0x11,
167					      0x12, 0x13 };
168
169static 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
178static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
179
180static 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
188static const struct comedi_lrange range_pci171x_da = { 2, {
189							   UNI_RANGE(5),
190							   UNI_RANGE(10),
191							   }
192};
193
194static int pci1710_attach(struct comedi_device *dev,
195			  struct comedi_devconfig *it);
196static int pci1710_detach(struct comedi_device *dev);
197
198struct 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
219static 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
228MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
229
230static 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
269static 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
279struct 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
318static int check_channel_list(struct comedi_device *dev,
319			      struct comedi_subdevice *s,
320			      unsigned int *chanlist, unsigned int n_chan);
321static 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);
325static void start_pacer(struct comedi_device *dev, int mode,
326			unsigned int divisor1, unsigned int divisor2);
327static int pci1710_reset(struct comedi_device *dev);
328static int pci171x_ai_cancel(struct comedi_device *dev,
329			     struct comedi_subdevice *s);
330
331/*  used for gain list programming */
332static 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*/
342static 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
388conv_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*/
413static 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*/
445static 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*/
461static 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*/
473static 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*/
490static 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*/
514static 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*/
543static 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*/
581static 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*/
608static 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*/
697static 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*/
743static 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*/
799static 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*/
840static 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*/
926static 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*/
942static 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*/
1109static 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*/
1149static 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 everytime 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 continous :-( */
1180				printk
1181				    ("channel list must be continous! 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
1209static 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*/
1254static 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*/
1274static 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*/
1304static 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*/
1334static 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*/
1356static 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*/
1371static 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	printk("comedi%d: adv_pci1710: ", 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		printk(" - Allocation failed!\n");
1393		return -ENOMEM;
1394	}
1395
1396	/* Look for matching PCI device */
1397	errstr = "not found!";
1398	pcidev = NULL;
1399	board_index = this_board - boardtypes;
1400	while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1401						PCI_ANY_ID, pcidev))) {
1402		if (strcmp(this_board->name, DRV_NAME) == 0) {
1403			for (i = 0; i < n_boardtypes; ++i) {
1404				if (pcidev->device == boardtypes[i].device_id) {
1405					board_index = i;
1406					break;
1407				}
1408			}
1409			if (i == n_boardtypes)
1410				continue;
1411		} else {
1412			if (pcidev->device != boardtypes[board_index].device_id)
1413				continue;
1414		}
1415
1416		/* Found matching vendor/device. */
1417		if (opt_bus || opt_slot) {
1418			/* Check bus/slot. */
1419			if (opt_bus != pcidev->bus->number
1420			    || opt_slot != PCI_SLOT(pcidev->devfn))
1421				continue;	/* no match */
1422		}
1423		/*
1424		 * Look for device that isn't in use.
1425		 * Enable PCI device and request regions.
1426		 */
1427		if (comedi_pci_enable(pcidev, DRV_NAME)) {
1428			errstr =
1429			    "failed to enable PCI device and request regions!";
1430			continue;
1431		}
1432		/*  fixup board_ptr in case we were using the dummy entry with the driver name */
1433		dev->board_ptr = &boardtypes[board_index];
1434		break;
1435	}
1436
1437	if (!pcidev) {
1438		if (opt_bus || opt_slot) {
1439			printk(" - Card at b:s %d:%d %s\n",
1440			       opt_bus, opt_slot, errstr);
1441		} else {
1442			printk(" - Card %s\n", errstr);
1443		}
1444		return -EIO;
1445	}
1446
1447	pci_bus = pcidev->bus->number;
1448	pci_slot = PCI_SLOT(pcidev->devfn);
1449	pci_func = PCI_FUNC(pcidev->devfn);
1450	irq = pcidev->irq;
1451	iobase = pci_resource_start(pcidev, 2);
1452
1453	printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1454	       iobase);
1455
1456	dev->iobase = iobase;
1457
1458	dev->board_name = this_board->name;
1459	devpriv->pcidev = pcidev;
1460
1461	n_subdevices = 0;
1462	if (this_board->n_aichan)
1463		n_subdevices++;
1464	if (this_board->n_aochan)
1465		n_subdevices++;
1466	if (this_board->n_dichan)
1467		n_subdevices++;
1468	if (this_board->n_dochan)
1469		n_subdevices++;
1470	if (this_board->n_counter)
1471		n_subdevices++;
1472
1473	ret = alloc_subdevices(dev, n_subdevices);
1474	if (ret < 0) {
1475		printk(" - Allocation failed!\n");
1476		return ret;
1477	}
1478
1479	pci1710_reset(dev);
1480
1481	if (this_board->have_irq) {
1482		if (irq) {
1483			if (request_irq(irq, interrupt_service_pci1710,
1484					IRQF_SHARED, "Advantech PCI-1710",
1485					dev)) {
1486				printk
1487				    (", unable to allocate IRQ %d, DISABLING IT",
1488				     irq);
1489				irq = 0;	/* Can't use IRQ */
1490			} else {
1491				printk(", irq=%u", irq);
1492			}
1493		} else {
1494			printk(", IRQ disabled");
1495		}
1496	} else {
1497		irq = 0;
1498	}
1499
1500	dev->irq = irq;
1501
1502	printk(".\n");
1503
1504	subdev = 0;
1505
1506	if (this_board->n_aichan) {
1507		s = dev->subdevices + subdev;
1508		dev->read_subdev = s;
1509		s->type = COMEDI_SUBD_AI;
1510		s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1511		if (this_board->n_aichand)
1512			s->subdev_flags |= SDF_DIFF;
1513		s->n_chan = this_board->n_aichan;
1514		s->maxdata = this_board->ai_maxdata;
1515		s->len_chanlist = this_board->n_aichan;
1516		s->range_table = this_board->rangelist_ai;
1517		s->cancel = pci171x_ai_cancel;
1518		s->insn_read = pci171x_insn_read_ai;
1519		if (irq) {
1520			s->subdev_flags |= SDF_CMD_READ;
1521			s->do_cmdtest = pci171x_ai_cmdtest;
1522			s->do_cmd = pci171x_ai_cmd;
1523		}
1524		devpriv->i8254_osc_base = 100;	/*  100ns=10MHz */
1525		subdev++;
1526	}
1527
1528	if (this_board->n_aochan) {
1529		s = dev->subdevices + subdev;
1530		s->type = COMEDI_SUBD_AO;
1531		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1532		s->n_chan = this_board->n_aochan;
1533		s->maxdata = this_board->ao_maxdata;
1534		s->len_chanlist = this_board->n_aochan;
1535		s->range_table = this_board->rangelist_ao;
1536		switch (this_board->cardtype) {
1537		case TYPE_PCI1720:
1538			s->insn_write = pci1720_insn_write_ao;
1539			break;
1540		default:
1541			s->insn_write = pci171x_insn_write_ao;
1542			break;
1543		}
1544		s->insn_read = pci171x_insn_read_ao;
1545		subdev++;
1546	}
1547
1548	if (this_board->n_dichan) {
1549		s = dev->subdevices + subdev;
1550		s->type = COMEDI_SUBD_DI;
1551		s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1552		s->n_chan = this_board->n_dichan;
1553		s->maxdata = 1;
1554		s->len_chanlist = this_board->n_dichan;
1555		s->range_table = &range_digital;
1556		s->io_bits = 0;	/* all bits input */
1557		s->insn_bits = pci171x_insn_bits_di;
1558		subdev++;
1559	}
1560
1561	if (this_board->n_dochan) {
1562		s = dev->subdevices + subdev;
1563		s->type = COMEDI_SUBD_DO;
1564		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1565		s->n_chan = this_board->n_dochan;
1566		s->maxdata = 1;
1567		s->len_chanlist = this_board->n_dochan;
1568		s->range_table = &range_digital;
1569		/* all bits output */
1570		s->io_bits = (1 << this_board->n_dochan) - 1;
1571		s->state = 0;
1572		s->insn_bits = pci171x_insn_bits_do;
1573		subdev++;
1574	}
1575
1576	if (this_board->n_counter) {
1577		s = dev->subdevices + subdev;
1578		s->type = COMEDI_SUBD_COUNTER;
1579		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1580		s->n_chan = this_board->n_counter;
1581		s->len_chanlist = this_board->n_counter;
1582		s->maxdata = 0xffff;
1583		s->range_table = &range_unknown;
1584		s->insn_read = pci171x_insn_counter_read;
1585		s->insn_write = pci171x_insn_counter_write;
1586		s->insn_config = pci171x_insn_counter_config;
1587		subdev++;
1588	}
1589
1590	devpriv->valid = 1;
1591
1592	return 0;
1593}
1594
1595/*
1596==============================================================================
1597*/
1598static int pci1710_detach(struct comedi_device *dev)
1599{
1600
1601	if (dev->private) {
1602		if (devpriv->valid)
1603			pci1710_reset(dev);
1604		if (dev->irq)
1605			free_irq(dev->irq, dev);
1606		if (devpriv->pcidev) {
1607			if (dev->iobase)
1608				comedi_pci_disable(devpriv->pcidev);
1609
1610			pci_dev_put(devpriv->pcidev);
1611		}
1612	}
1613
1614	return 0;
1615}
1616
1617/*
1618==============================================================================
1619*/
1620static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
1621					      const struct pci_device_id *ent)
1622{
1623	return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
1624}
1625
1626static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
1627{
1628	comedi_pci_auto_unconfig(dev);
1629}
1630
1631static struct pci_driver driver_pci1710_pci_driver = {
1632	.id_table = pci1710_pci_table,
1633	.probe = &driver_pci1710_pci_probe,
1634	.remove = __devexit_p(&driver_pci1710_pci_remove)
1635};
1636
1637static int __init driver_pci1710_init_module(void)
1638{
1639	int retval;
1640
1641	retval = comedi_driver_register(&driver_pci1710);
1642	if (retval < 0)
1643		return retval;
1644
1645	driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
1646	return pci_register_driver(&driver_pci1710_pci_driver);
1647}
1648
1649static void __exit driver_pci1710_cleanup_module(void)
1650{
1651	pci_unregister_driver(&driver_pci1710_pci_driver);
1652	comedi_driver_unregister(&driver_pci1710);
1653}
1654
1655module_init(driver_pci1710_init_module);
1656module_exit(driver_pci1710_cleanup_module);
1657/*
1658==============================================================================
1659*/
1660
1661MODULE_AUTHOR("Comedi http://www.comedi.org");
1662MODULE_DESCRIPTION("Comedi low-level driver");
1663MODULE_LICENSE("GPL");
1664