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