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