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