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