]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/comedi/drivers/adv_pci1710.c
Staging: comedi: Remove comedi_device typedef
[net-next-2.6.git] / drivers / staging / comedi / drivers / adv_pci1710.c
CommitLineData
0e8db97a
MD
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 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 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 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 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 comedi_lrange range_pci171x_da = { 2, {
180 UNI_RANGE(5),
181 UNI_RANGE(10),
182 }
183};
184
71b5f4f1
BP
185static int pci1710_attach(struct comedi_device * dev, comedi_devconfig * it);
186static int pci1710_detach(struct comedi_device * dev);
0e8db97a
MD
187
188typedef struct {
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 comedi_lrange *rangelist_ai; // rangelist for A/D
203 const char *rangecode_ai; // range codes for programming
204 const 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} boardtype;
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 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(boardtype))
258
259static 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(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
790c5541 293 short *ai_data; // data buffer
0e8db97a
MD
294 unsigned int ai_timer1; // timers
295 unsigned int ai_timer2;
790c5541 296 short ao_data[4]; // data output buffer
0e8db97a
MD
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 boardtype *)dev->board_ptr)
302
303/*
304==============================================================================
305*/
306
71b5f4f1 307static int check_channel_list(struct comedi_device * dev, comedi_subdevice * s,
0e8db97a 308 unsigned int *chanlist, unsigned int n_chan);
71b5f4f1 309static void setup_channel_list(struct comedi_device * dev, comedi_subdevice * s,
0e8db97a 310 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);
71b5f4f1 311static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
0e8db97a 312 unsigned int divisor2);
71b5f4f1
BP
313static int pci1710_reset(struct comedi_device * dev);
314static int pci171x_ai_cancel(struct comedi_device * dev, comedi_subdevice * s);
0e8db97a
MD
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*/
71b5f4f1 325static int pci171x_insn_read_ai(struct comedi_device * dev, comedi_subdevice * s,
790c5541 326 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 393static int pci171x_insn_write_ao(struct comedi_device * dev, comedi_subdevice * s,
790c5541 394 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 424static int pci171x_insn_read_ao(struct comedi_device * dev, comedi_subdevice * s,
790c5541 425 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 439static int pci171x_insn_bits_di(struct comedi_device * dev, comedi_subdevice * s,
790c5541 440 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
441{
442 data[1] = inw(dev->iobase + PCI171x_DI);
443
444 return 2;
445}
446
447/*
448==============================================================================
449*/
71b5f4f1 450static int pci171x_insn_bits_do(struct comedi_device * dev, comedi_subdevice * s,
790c5541 451 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 466static int pci171x_insn_counter_read(struct comedi_device * dev, comedi_subdevice * s,
790c5541 467 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 488static int pci171x_insn_counter_write(struct comedi_device * dev, comedi_subdevice * s,
790c5541 489 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 515static int pci171x_insn_counter_config(struct comedi_device * dev,
790c5541 516 comedi_subdevice * s, comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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*/
71b5f4f1 551static int pci1720_insn_write_ao(struct comedi_device * dev, comedi_subdevice * s,
790c5541 552 comedi_insn * insn, unsigned int * data)
0e8db97a
MD
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{
71b5f4f1 579 struct comedi_device *dev = d;
0e8db97a
MD
580 comedi_subdevice *s = dev->subdevices + 0;
581 int m;
582#ifdef PCI171x_PARANOIDCHECK
790c5541 583 short sampl;
0e8db97a
MD
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*/
71b5f4f1 662static int move_block_from_fifo(struct comedi_device * dev, comedi_subdevice * s,
0e8db97a
MD
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{
71b5f4f1 710 struct comedi_device *dev = d;
0e8db97a
MD
711 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;
790c5541
BP
735 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
736 m = devpriv->ai_data_len / sizeof(short);
0e8db97a
MD
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{
71b5f4f1 765 struct comedi_device *dev = d;
0e8db97a
MD
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*/
71b5f4f1 804static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device * dev,
0e8db97a
MD
805 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, 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*/
71b5f4f1 903static int pci171x_ai_cmdtest(struct comedi_device * dev, comedi_subdevice * s,
0e8db97a
MD
904 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*/
71b5f4f1 1068static int pci171x_ai_cmd(struct comedi_device * dev, comedi_subdevice * s)
0e8db97a
MD
1069{
1070 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*/
71b5f4f1 1107static int check_channel_list(struct comedi_device * dev, comedi_subdevice * s,
0e8db97a
MD
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
71b5f4f1 1166static void setup_channel_list(struct comedi_device * dev, comedi_subdevice * s,
0e8db97a
MD
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*/
71b5f4f1 1203static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
0e8db97a
MD
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*/
71b5f4f1 1223static int pci171x_ai_cancel(struct comedi_device * dev, comedi_subdevice * s)
0e8db97a
MD
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*/
71b5f4f1 1252static int pci171x_reset(struct comedi_device * dev)
0e8db97a
MD
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*/
71b5f4f1 1282static int pci1720_reset(struct comedi_device * dev)
0e8db97a
MD
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*/
71b5f4f1 1304static int pci1710_reset(struct comedi_device * dev)
0e8db97a
MD
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*/
71b5f4f1 1319static int pci1710_attach(struct comedi_device * dev, comedi_devconfig * it)
0e8db97a
MD
1320{
1321 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*/
71b5f4f1 1543static int pci1710_detach(struct comedi_device * dev)
0e8db97a
MD
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*/