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