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