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