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