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