1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104#include <linux/interrupt.h>
105#include <linux/delay.h>
106
107#include "../comedidev.h"
108#include "comedi_pci.h"
109
110#define DRV_NAME "rtd520"
111
112
113
114
115
116
117
118
119
120#define DMA_CHAIN_COUNT 2
121
122
123
124
125#define TRANS_TARGET_PERIOD 10000000
126
127
128
129#define RTD_MAX_CHANLIST 128
130
131
132#ifdef FAST_SPIN
133#define WAIT_QUIETLY
134#define RTD_ADC_TIMEOUT 66000
135#define RTD_DAC_TIMEOUT 66000
136#define RTD_DMA_TIMEOUT 33000
137#else
138
139#define WAIT_QUIETLY udelay(1)
140#define RTD_ADC_TIMEOUT 2000
141#define RTD_DAC_TIMEOUT 2000
142#define RTD_DMA_TIMEOUT 1000
143#endif
144
145
146
147
148
149
150#define PCI_VENDOR_ID_RTD 0x1435
151
152
153
154
155#define LCFG_PCIINDEX 0
156
157#define LAS0_PCIINDEX 2
158#define LAS1_PCIINDEX 3
159#define LCFG_PCISIZE 0x100
160#define LAS0_PCISIZE 0x200
161#define LAS1_PCISIZE 0x10
162
163#define RTD_CLOCK_RATE 8000000
164#define RTD_CLOCK_BASE 125
165
166
167#define RTD_MAX_SPEED 1625
168
169#define RTD_MAX_SPEED_1 875
170
171#define RTD_MIN_SPEED 2097151875
172
173#define RTD_MIN_SPEED_1 5000000
174
175#include "rtd520.h"
176#include "plx9080.h"
177
178
179#define DMA_MODE_BITS (\
180 PLX_LOCAL_BUS_16_WIDE_BITS \
181 | PLX_DMA_EN_READYIN_BIT \
182 | PLX_DMA_LOCAL_BURST_EN_BIT \
183 | PLX_EN_CHAIN_BIT \
184 | PLX_DMA_INTR_PCI_BIT \
185 | PLX_LOCAL_ADDR_CONST_BIT \
186 | PLX_DEMAND_MODE_BIT)
187
188#define DMA_TRANSFER_BITS (\
189 PLX_DESC_IN_PCI_BIT \
190 | PLX_INTR_TERM_COUNT \
191 | PLX_XFER_LOCAL_TO_PCI)
192
193
194
195
196
197
198
199
200static const struct comedi_lrange rtd_ai_7520_range = { 18, {
201
202 BIP_RANGE(5.0),
203 BIP_RANGE(5.0 / 2),
204 BIP_RANGE(5.0 / 4),
205 BIP_RANGE(5.0 / 8),
206 BIP_RANGE(5.0 /
207 16),
208 BIP_RANGE(5.0 /
209 32),
210
211 BIP_RANGE(10.0),
212 BIP_RANGE(10.0 /
213 2),
214 BIP_RANGE(10.0 /
215 4),
216 BIP_RANGE(10.0 /
217 8),
218 BIP_RANGE(10.0 /
219 16),
220 BIP_RANGE(10.0 /
221 32),
222
223 UNI_RANGE(10.0),
224 UNI_RANGE(10.0 /
225 2),
226 UNI_RANGE(10.0 /
227 4),
228 UNI_RANGE(10.0 /
229 8),
230 UNI_RANGE(10.0 /
231 16),
232 UNI_RANGE(10.0 /
233 32),
234
235 }
236};
237
238
239static const struct comedi_lrange rtd_ai_4520_range = { 24, {
240
241 BIP_RANGE(5.0),
242 BIP_RANGE(5.0 / 2),
243 BIP_RANGE(5.0 / 4),
244 BIP_RANGE(5.0 / 8),
245 BIP_RANGE(5.0 /
246 16),
247 BIP_RANGE(5.0 /
248 32),
249 BIP_RANGE(5.0 /
250 64),
251 BIP_RANGE(5.0 /
252 128),
253
254 BIP_RANGE(10.0),
255 BIP_RANGE(10.0 /
256 2),
257 BIP_RANGE(10.0 /
258 4),
259 BIP_RANGE(10.0 /
260 8),
261 BIP_RANGE(10.0 /
262 16),
263 BIP_RANGE(10.0 /
264 32),
265 BIP_RANGE(10.0 /
266 64),
267 BIP_RANGE(10.0 /
268 128),
269
270 UNI_RANGE(10.0),
271 UNI_RANGE(10.0 /
272 2),
273 UNI_RANGE(10.0 /
274 4),
275 UNI_RANGE(10.0 /
276 8),
277 UNI_RANGE(10.0 /
278 16),
279 UNI_RANGE(10.0 /
280 32),
281 UNI_RANGE(10.0 /
282 64),
283 UNI_RANGE(10.0 /
284 128),
285 }
286};
287
288
289static const struct comedi_lrange rtd_ao_range = { 4, {
290 RANGE(0, 5),
291 RANGE(0, 10),
292 RANGE(-5, 5),
293 RANGE(-10, 10),
294 }
295};
296
297
298
299
300struct rtdBoard {
301 const char *name;
302 int device_id;
303 int aiChans;
304 int aiBits;
305 int aiMaxGain;
306 int range10Start;
307 int rangeUniStart;
308};
309
310static const struct rtdBoard rtd520Boards[] = {
311 {
312 .name = "DM7520",
313 .device_id = 0x7520,
314 .aiChans = 16,
315 .aiBits = 12,
316 .aiMaxGain = 32,
317 .range10Start = 6,
318 .rangeUniStart = 12,
319 },
320 {
321 .name = "PCI4520",
322 .device_id = 0x4520,
323 .aiChans = 16,
324 .aiBits = 12,
325 .aiMaxGain = 128,
326 .range10Start = 8,
327 .rangeUniStart = 16,
328 },
329};
330
331static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
332 { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
333 { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
334 { 0 }
335};
336
337MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
338
339
340
341
342#define thisboard ((const struct rtdBoard *)dev->board_ptr)
343
344
345
346
347
348struct rtdPrivate {
349
350 void *las0;
351 void *las1;
352 void *lcfg;
353
354 unsigned long intCount;
355 long aiCount;
356 int transCount;
357 int flags;
358
359
360 struct pci_dev *pci_dev;
361 int got_regions;
362
363
364
365 unsigned char chanBipolar[RTD_MAX_CHANLIST / 8];
366
367
368 unsigned int aoValue[2];
369
370
371 u8 utcGate[4];
372
373
374
375 u16 intMask;
376 u16 intClearMask;
377 u8 utcCtrl[4];
378 u8 dioStatus;
379#ifdef USE_DMA
380
381
382 s16 dma0Offset;
383 uint16_t *dma0Buff[DMA_CHAIN_COUNT];
384 dma_addr_t dma0BuffPhysAddr[DMA_CHAIN_COUNT];
385 struct plx_dma_desc *dma0Chain;
386 dma_addr_t dma0ChainPhysAddr;
387
388 u8 dma0Control;
389 u8 dma1Control;
390#endif
391 unsigned fifoLen;
392};
393
394
395#define SEND_EOS 0x01
396#define DMA0_ACTIVE 0x02
397#define DMA1_ACTIVE 0x04
398
399
400#define CHAN_ARRAY_TEST(array, index) \
401 (((array)[(index)/8] >> ((index) & 0x7)) & 0x1)
402#define CHAN_ARRAY_SET(array, index) \
403 (((array)[(index)/8] |= 1 << ((index) & 0x7)))
404#define CHAN_ARRAY_CLEAR(array, index) \
405 (((array)[(index)/8] &= ~(1 << ((index) & 0x7))))
406
407
408
409
410
411#define devpriv ((struct rtdPrivate *)dev->private)
412
413
414
415
416#define RtdResetBoard(dev) \
417 writel(0, devpriv->las0+LAS0_BOARD_RESET)
418
419
420#define RtdResetCGT(dev) \
421 writel(0, devpriv->las0+LAS0_CGT_RESET)
422
423
424#define RtdClearCGT(dev) \
425 writel(0, devpriv->las0+LAS0_CGT_CLEAR)
426
427
428#define RtdEnableCGT(dev, v) \
429 writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_CGT_ENABLE)
430
431
432#define RtdWriteCGTable(dev, v) \
433 writel(v, devpriv->las0+LAS0_CGT_WRITE)
434
435
436#define RtdWriteCGLatch(dev, v) \
437 writel(v, devpriv->las0+LAS0_CGL_WRITE)
438
439
440#define RtdAdcClearFifo(dev) \
441 writel(0, devpriv->las0+LAS0_ADC_FIFO_CLEAR)
442
443
444#define RtdAdcConversionSource(dev, v) \
445 writel(v, devpriv->las0+LAS0_ADC_CONVERSION)
446
447
448#define RtdBurstStartSource(dev, v) \
449 writel(v, devpriv->las0+LAS0_BURST_START)
450
451
452#define RtdPacerStartSource(dev, v) \
453 writel(v, devpriv->las0+LAS0_PACER_START)
454
455
456#define RtdPacerStopSource(dev, v) \
457 writel(v, devpriv->las0+LAS0_PACER_STOP)
458
459
460#define RtdPacerClockSource(dev, v) \
461 writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_PACER_SELECT)
462
463
464#define RtdAdcSampleCounterSource(dev, v) \
465 writel(v, devpriv->las0+LAS0_ADC_SCNT_SRC)
466
467
468#define RtdPacerTriggerMode(dev, v) \
469 writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_PACER_REPEAT)
470
471
472#define RtdAboutStopEnable(dev, v) \
473 writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_ACNT_STOP_ENABLE)
474
475
476#define RtdTriggerPolarity(dev, v) \
477 writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_ETRG_POLARITY)
478
479
480#define RtdAdcStart(dev) \
481 writew(0, devpriv->las0+LAS0_ADC)
482
483
484
485#define RtdAdcFifoGet(dev) \
486 readw(devpriv->las1+LAS1_ADC_FIFO)
487
488
489#define RtdAdcFifoGet2(dev) \
490 readl(devpriv->las1+LAS1_ADC_FIFO)
491
492
493#define RtdFifoStatus(dev) \
494 readl(devpriv->las0+LAS0_ADC)
495
496
497#define RtdPacerStart(dev) \
498 readl(devpriv->las0+LAS0_PACER)
499#define RtdPacerStop(dev) \
500 writel(0, devpriv->las0+LAS0_PACER)
501
502
503#define RtdInterruptStatus(dev) \
504 readw(devpriv->las0+LAS0_IT)
505
506
507#define RtdInterruptMask(dev, v) \
508 writew((devpriv->intMask = (v)), devpriv->las0+LAS0_IT)
509
510
511#define RtdInterruptClear(dev) \
512 readw(devpriv->las0+LAS0_CLEAR)
513
514
515#define RtdInterruptClearMask(dev, v) \
516 writew((devpriv->intClearMask = (v)), devpriv->las0+LAS0_CLEAR)
517
518
519#define RtdInterruptOverrunStatus(dev) \
520 readl(devpriv->las0+LAS0_OVERRUN)
521
522
523#define RtdInterruptOverrunClear(dev) \
524 writel(0, devpriv->las0+LAS0_OVERRUN)
525
526
527#define RtdPacerCount(dev) \
528 readl(devpriv->las0+LAS0_PCLK)
529#define RtdPacerCounter(dev, v) \
530 writel((v) & 0xffffff, devpriv->las0+LAS0_PCLK)
531
532
533#define RtdBurstCount(dev) \
534 readl(devpriv->las0+LAS0_BCLK)
535#define RtdBurstCounter(dev, v) \
536 writel((v) & 0x3ff, devpriv->las0+LAS0_BCLK)
537
538
539#define RtdDelayCount(dev) \
540 readl(devpriv->las0+LAS0_DCLK)
541#define RtdDelayCounter(dev, v) \
542 writel((v) & 0xffff, devpriv->las0+LAS0_DCLK)
543
544
545#define RtdAboutCount(dev) \
546 readl(devpriv->las0+LAS0_ACNT)
547#define RtdAboutCounter(dev, v) \
548 writel((v) & 0xffff, devpriv->las0+LAS0_ACNT)
549
550
551#define RtdAdcSampleCount(dev) \
552 readl(devpriv->las0+LAS0_ADC_SCNT)
553#define RtdAdcSampleCounter(dev, v) \
554 writel((v) & 0x3ff, devpriv->las0+LAS0_ADC_SCNT)
555
556
557#define RtdUtcCounterGet(dev, n) \
558 readb(devpriv->las0 \
559 + ((n <= 0) ? LAS0_UTC0 : ((1 == n) ? LAS0_UTC1 : LAS0_UTC2)))
560
561#define RtdUtcCounterPut(dev, n, v) \
562 writeb((v) & 0xff, devpriv->las0 \
563 + ((n <= 0) ? LAS0_UTC0 : ((1 == n) ? LAS0_UTC1 : LAS0_UTC2)))
564
565
566#define RtdUtcCtrlPut(dev, n, v) \
567 writeb(devpriv->utcCtrl[(n) & 3] = (((n) & 3) << 6) | ((v) & 0x3f), \
568 devpriv->las0 + LAS0_UTC_CTRL)
569
570
571#define RtdUtcClockSource(dev, n, v) \
572 writew(v, devpriv->las0 \
573 + ((n <= 0) ? LAS0_UTC0_CLOCK : \
574 ((1 == n) ? LAS0_UTC1_CLOCK : LAS0_UTC2_CLOCK)))
575
576
577#define RtdUtcGateSource(dev, n, v) \
578 writew(v, devpriv->las0 \
579 + ((n <= 0) ? LAS0_UTC0_GATE : \
580 ((1 == n) ? LAS0_UTC1_GATE : LAS0_UTC2_GATE)))
581
582
583#define RtdUsrOutSource(dev, n, v) \
584 writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : LAS0_UOUT1_SELECT))
585
586
587#define RtdDio0Read(dev) \
588 (readw(devpriv->las0+LAS0_DIO0) & 0xff)
589#define RtdDio0Write(dev, v) \
590 writew((v) & 0xff, devpriv->las0+LAS0_DIO0)
591
592#define RtdDio1Read(dev) \
593 (readw(devpriv->las0+LAS0_DIO1) & 0xff)
594#define RtdDio1Write(dev, v) \
595 writew((v) & 0xff, devpriv->las0+LAS0_DIO1)
596
597#define RtdDioStatusRead(dev) \
598 (readw(devpriv->las0+LAS0_DIO_STATUS) & 0xff)
599#define RtdDioStatusWrite(dev, v) \
600 writew((devpriv->dioStatus = (v)), devpriv->las0+LAS0_DIO_STATUS)
601
602#define RtdDio0CtrlRead(dev) \
603 (readw(devpriv->las0+LAS0_DIO0_CTRL) & 0xff)
604#define RtdDio0CtrlWrite(dev, v) \
605 writew((v) & 0xff, devpriv->las0+LAS0_DIO0_CTRL)
606
607
608
609
610#define RtdDacFifoPut(dev, n, v) \
611 writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO))
612
613
614#define RtdDacUpdate(dev, n) \
615 writew(0, devpriv->las0 + (((n) == 0) ? LAS0_DAC1 : LAS0_DAC2))
616
617
618#define RtdDacBothUpdate(dev) \
619 writew(0, devpriv->las0+LAS0_DAC)
620
621
622#define RtdDacRange(dev, n, v) \
623 writew((v) & 7, devpriv->las0 \
624 +(((n) == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL))
625
626
627#define RtdDacClearFifo(dev, n) \
628 writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : LAS0_DAC2_RESET))
629
630
631#define RtdDma0Source(dev, n) \
632 writel((n) & 0xf, devpriv->las0+LAS0_DMA0_SRC)
633
634
635#define RtdDma1Source(dev, n) \
636 writel((n) & 0xf, devpriv->las0+LAS0_DMA1_SRC)
637
638
639#define RtdDma0Reset(dev) \
640 writel(0, devpriv->las0+LAS0_DMA0_RESET)
641
642
643#define RtdDma1Reset(dev) \
644 writel(0, devpriv->las0+LAS0_DMA1_SRC)
645
646
647#define RtdPlxInterruptRead(dev) \
648 readl(devpriv->lcfg+LCFG_ITCSR)
649#define RtdPlxInterruptWrite(dev, v) \
650 writel(v, devpriv->lcfg+LCFG_ITCSR)
651
652
653#define RtdDma0Mode(dev, m) \
654 writel((m), devpriv->lcfg+LCFG_DMAMODE0)
655
656
657#define RtdDma0PciAddr(dev, a) \
658 writel((a), devpriv->lcfg+LCFG_DMAPADR0)
659
660
661#define RtdDma0LocalAddr(dev, a) \
662 writel((a), devpriv->lcfg+LCFG_DMALADR0)
663
664
665#define RtdDma0Count(dev, c) \
666 writel((c), devpriv->lcfg+LCFG_DMASIZ0)
667
668
669#define RtdDma0Next(dev, a) \
670 writel((a), devpriv->lcfg+LCFG_DMADPR0)
671
672
673#define RtdDma1Mode(dev, m) \
674 writel((m), devpriv->lcfg+LCFG_DMAMODE1)
675
676
677#define RtdDma1PciAddr(dev, a) \
678 writel((a), devpriv->lcfg+LCFG_DMAADR1)
679
680
681#define RtdDma1LocalAddr(dev, a) \
682 writel((a), devpriv->lcfg+LCFG_DMALADR1)
683
684
685#define RtdDma1Count(dev, c) \
686 writel((c), devpriv->lcfg+LCFG_DMASIZ1)
687
688
689#define RtdDma1Next(dev, a) \
690 writel((a), devpriv->lcfg+LCFG_DMADPR1)
691
692
693#define RtdDma0Control(dev, n) \
694 writeb(devpriv->dma0Control = (n), devpriv->lcfg+LCFG_DMACSR0)
695
696
697#define RtdDma0Status(dev) \
698 readb(devpriv->lcfg+LCFG_DMACSR0)
699
700
701#define RtdDma1Control(dev, n) \
702 writeb(devpriv->dma1Control = (n), devpriv->lcfg+LCFG_DMACSR1)
703
704
705#define RtdDma1Status(dev) \
706 readb(devpriv->lcfg+LCFG_DMACSR1)
707
708
709
710
711
712
713
714static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it);
715static int rtd_detach(struct comedi_device *dev);
716
717static struct comedi_driver rtd520Driver = {
718 .driver_name = DRV_NAME,
719 .module = THIS_MODULE,
720 .attach = rtd_attach,
721 .detach = rtd_detach,
722};
723
724static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
725 struct comedi_insn *insn, unsigned int *data);
726static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
727 struct comedi_insn *insn, unsigned int *data);
728static int rtd_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
729 struct comedi_insn *insn, unsigned int *data);
730static int rtd_dio_insn_bits(struct comedi_device *dev,
731 struct comedi_subdevice *s,
732 struct comedi_insn *insn, unsigned int *data);
733static int rtd_dio_insn_config(struct comedi_device *dev,
734 struct comedi_subdevice *s,
735 struct comedi_insn *insn, unsigned int *data);
736static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
737 struct comedi_cmd *cmd);
738static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
739static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
740
741static int rtd_ns_to_timer(unsigned int *ns, int roundMode);
742static irqreturn_t rtd_interrupt(int irq, void *d);
743static int rtd520_probe_fifo_depth(struct comedi_device *dev);
744
745
746
747
748
749
750
751static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
752{
753 struct comedi_subdevice *s;
754 struct pci_dev *pcidev;
755 int ret;
756 resource_size_t physLas0;
757 resource_size_t physLas1;
758 resource_size_t physLcfg;
759#ifdef USE_DMA
760 int index;
761#endif
762
763 printk(KERN_INFO "comedi%d: rtd520 attaching.\n", dev->minor);
764
765#if defined(CONFIG_COMEDI_DEBUG) && defined(USE_DMA)
766
767 if (0 == comedi_debug)
768 comedi_debug = 1;
769#endif
770
771
772
773
774
775 if (alloc_private(dev, sizeof(struct rtdPrivate)) < 0)
776 return -ENOMEM;
777
778
779
780
781 for (pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, NULL);
782 pcidev != NULL;
783 pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, pcidev)) {
784 int i;
785
786 if (it->options[0] || it->options[1]) {
787 if (pcidev->bus->number != it->options[0]
788 || PCI_SLOT(pcidev->devfn) != it->options[1]) {
789 continue;
790 }
791 }
792 for (i = 0; i < ARRAY_SIZE(rtd520Boards); ++i) {
793 if (pcidev->device == rtd520Boards[i].device_id) {
794 dev->board_ptr = &rtd520Boards[i];
795 break;
796 }
797 }
798 if (dev->board_ptr)
799 break;
800 }
801 if (!pcidev) {
802 if (it->options[0] && it->options[1]) {
803 printk(KERN_INFO "No RTD card at bus=%d slot=%d.\n",
804 it->options[0], it->options[1]);
805 } else {
806 printk(KERN_INFO "No RTD card found.\n");
807 }
808 return -EIO;
809 }
810 devpriv->pci_dev = pcidev;
811 dev->board_name = thisboard->name;
812
813 ret = comedi_pci_enable(pcidev, DRV_NAME);
814 if (ret < 0) {
815 printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
816 return ret;
817 }
818 devpriv->got_regions = 1;
819
820
821
822
823
824 physLas0 = pci_resource_start(devpriv->pci_dev, LAS0_PCIINDEX);
825 physLas1 = pci_resource_start(devpriv->pci_dev, LAS1_PCIINDEX);
826 physLcfg = pci_resource_start(devpriv->pci_dev, LCFG_PCIINDEX);
827
828
829 devpriv->las0 = ioremap_nocache(physLas0, LAS0_PCISIZE);
830 devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
831 devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
832
833 if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
834 return -ENOMEM;
835
836
837 DPRINTK("%s: LAS0=%llx, LAS1=%llx, CFG=%llx.\n", dev->board_name,
838 (unsigned long long)physLas0, (unsigned long long)physLas1,
839 (unsigned long long)physLcfg);
840 {
841 unsigned char pci_latency;
842 u16 revision;
843
844
845 pci_read_config_word(devpriv->pci_dev, PCI_REVISION_ID,
846 &revision);
847 DPRINTK("%s: PCI revision %d.\n", dev->board_name, revision);
848
849 pci_read_config_byte(devpriv->pci_dev,
850 PCI_LATENCY_TIMER, &pci_latency);
851 if (pci_latency < 32) {
852 printk(KERN_INFO "%s: PCI latency changed from %d to %d\n",
853 dev->board_name, pci_latency, 32);
854 pci_write_config_byte(devpriv->pci_dev,
855 PCI_LATENCY_TIMER, 32);
856 } else {
857 DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
858 }
859
860
861
862
863
864
865
866
867
868
869 }
870
871
872 printk(KERN_INFO "%s:", dev->board_name);
873
874
875
876
877
878 if (alloc_subdevices(dev, 4) < 0)
879 return -ENOMEM;
880
881
882 s = dev->subdevices + 0;
883 dev->read_subdev = s;
884
885 s->type = COMEDI_SUBD_AI;
886 s->subdev_flags =
887 SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
888 s->n_chan = thisboard->aiChans;
889 s->maxdata = (1 << thisboard->aiBits) - 1;
890 if (thisboard->aiMaxGain <= 32)
891 s->range_table = &rtd_ai_7520_range;
892 else
893 s->range_table = &rtd_ai_4520_range;
894
895 s->len_chanlist = RTD_MAX_CHANLIST;
896 s->insn_read = rtd_ai_rinsn;
897 s->do_cmd = rtd_ai_cmd;
898 s->do_cmdtest = rtd_ai_cmdtest;
899 s->cancel = rtd_ai_cancel;
900
901
902 s = dev->subdevices + 1;
903
904 s->type = COMEDI_SUBD_AO;
905 s->subdev_flags = SDF_WRITABLE;
906 s->n_chan = 2;
907 s->maxdata = (1 << thisboard->aiBits) - 1;
908 s->range_table = &rtd_ao_range;
909 s->insn_write = rtd_ao_winsn;
910 s->insn_read = rtd_ao_rinsn;
911
912 s = dev->subdevices + 2;
913
914 s->type = COMEDI_SUBD_DIO;
915 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
916
917 s->n_chan = 8;
918 s->maxdata = 1;
919 s->range_table = &range_digital;
920 s->insn_bits = rtd_dio_insn_bits;
921 s->insn_config = rtd_dio_insn_config;
922
923
924 s = dev->subdevices + 3;
925 s->type = COMEDI_SUBD_COUNTER;
926 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
927 s->n_chan = 3;
928 s->maxdata = 0xffff;
929
930
931
932 RtdResetBoard(dev);
933 udelay(100);
934 RtdPlxInterruptWrite(dev, 0);
935 RtdInterruptMask(dev, 0);
936 RtdInterruptClearMask(dev, ~0);
937 RtdInterruptClear(dev);
938 RtdInterruptOverrunClear(dev);
939 RtdClearCGT(dev);
940 RtdAdcClearFifo(dev);
941 RtdDacClearFifo(dev, 0);
942 RtdDacClearFifo(dev, 1);
943
944 RtdDioStatusWrite(dev, 0);
945 RtdUtcCtrlPut(dev, 0, 0x30);
946 RtdUtcCtrlPut(dev, 1, 0x30);
947 RtdUtcCtrlPut(dev, 2, 0x30);
948 RtdUtcCtrlPut(dev, 3, 0);
949
950
951
952 ret = request_irq(devpriv->pci_dev->irq, rtd_interrupt,
953 IRQF_SHARED, DRV_NAME, dev);
954
955 if (ret < 0) {
956 printk("Could not get interrupt! (%u)\n",
957 devpriv->pci_dev->irq);
958 return ret;
959 }
960 dev->irq = devpriv->pci_dev->irq;
961 printk(KERN_INFO "( irq=%u )", dev->irq);
962
963 ret = rtd520_probe_fifo_depth(dev);
964 if (ret < 0)
965 return ret;
966
967 devpriv->fifoLen = ret;
968 printk("( fifoLen=%d )", devpriv->fifoLen);
969
970#ifdef USE_DMA
971 if (dev->irq > 0) {
972 printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
973
974
975
976 devpriv->dma0Offset = 0;
977
978 for (index = 0; index < DMA_CHAIN_COUNT; index++) {
979 devpriv->dma0Buff[index] =
980 pci_alloc_consistent(devpriv->pci_dev,
981 sizeof(u16) *
982 devpriv->fifoLen / 2,
983 &devpriv->
984 dma0BuffPhysAddr[index]);
985 if (devpriv->dma0Buff[index] == NULL) {
986 ret = -ENOMEM;
987 goto rtd_attach_die_error;
988 }
989
990
991
992 }
993
994
995 devpriv->dma0Chain =
996 pci_alloc_consistent(devpriv->pci_dev,
997 sizeof(struct plx_dma_desc) *
998 DMA_CHAIN_COUNT,
999 &devpriv->dma0ChainPhysAddr);
1000 for (index = 0; index < DMA_CHAIN_COUNT; index++) {
1001 devpriv->dma0Chain[index].pci_start_addr =
1002 devpriv->dma0BuffPhysAddr[index];
1003 devpriv->dma0Chain[index].local_start_addr =
1004 DMALADDR_ADC;
1005 devpriv->dma0Chain[index].transfer_size =
1006 sizeof(u16) * devpriv->fifoLen / 2;
1007 devpriv->dma0Chain[index].next =
1008 (devpriv->dma0ChainPhysAddr + ((index +
1009 1) %
1010 (DMA_CHAIN_COUNT))
1011 * sizeof(devpriv->dma0Chain[0]))
1012 | DMA_TRANSFER_BITS;
1013
1014
1015
1016
1017
1018
1019
1020
1021 }
1022
1023 if (devpriv->dma0Chain == NULL) {
1024 ret = -ENOMEM;
1025 goto rtd_attach_die_error;
1026 }
1027
1028 RtdDma0Mode(dev, DMA_MODE_BITS);
1029
1030 RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);
1031 } else {
1032 printk(KERN_INFO "( no IRQ->no DMA )");
1033 }
1034#endif
1035
1036 if (dev->irq) {
1037 RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
1038 }
1039
1040 printk("\ncomedi%d: rtd520 driver attached.\n", dev->minor);
1041
1042 return 1;
1043
1044#if 0
1045
1046
1047#ifdef USE_DMA
1048 for (index = 0; index < DMA_CHAIN_COUNT; index++) {
1049 if (NULL != devpriv->dma0Buff[index]) {
1050 pci_free_consistent(devpriv->pci_dev,
1051 sizeof(u16) * devpriv->fifoLen / 2,
1052 devpriv->dma0Buff[index],
1053 devpriv->dma0BuffPhysAddr[index]);
1054 devpriv->dma0Buff[index] = NULL;
1055 }
1056 }
1057 if (NULL != devpriv->dma0Chain) {
1058 pci_free_consistent(devpriv->pci_dev,
1059 sizeof(struct plx_dma_desc)
1060 * DMA_CHAIN_COUNT,
1061 devpriv->dma0Chain,
1062 devpriv->dma0ChainPhysAddr);
1063 devpriv->dma0Chain = NULL;
1064 }
1065#endif
1066
1067 if (dev->irq) {
1068
1069 RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
1070 & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E));
1071 free_irq(dev->irq, dev);
1072 }
1073
1074
1075 if (devpriv->las0)
1076 iounmap(devpriv->las0);
1077
1078 if (devpriv->las1)
1079 iounmap(devpriv->las1);
1080
1081 if (devpriv->lcfg)
1082 iounmap(devpriv->lcfg);
1083
1084 if (devpriv->pci_dev)
1085 pci_dev_put(devpriv->pci_dev);
1086
1087 return ret;
1088#endif
1089}
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099static int rtd_detach(struct comedi_device *dev)
1100{
1101#ifdef USE_DMA
1102 int index;
1103#endif
1104
1105 DPRINTK("comedi%d: rtd520: removing (%ld ints)\n",
1106 dev->minor, (devpriv ? devpriv->intCount : 0L));
1107 if (devpriv && devpriv->lcfg) {
1108 DPRINTK
1109 ("(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n",
1110 0xffff & RtdInterruptStatus(dev),
1111 0xffff & RtdInterruptOverrunStatus(dev),
1112 (0xffff & RtdFifoStatus(dev)) ^ 0x6666);
1113 }
1114
1115 if (devpriv) {
1116
1117#ifdef USE_DMA
1118 if (devpriv->lcfg) {
1119 RtdDma0Control(dev, 0);
1120 RtdDma1Control(dev, 0);
1121 RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
1122 }
1123#endif
1124 if (devpriv->las0) {
1125 RtdResetBoard(dev);
1126 RtdInterruptMask(dev, 0);
1127 RtdInterruptClearMask(dev, ~0);
1128 RtdInterruptClear(dev);
1129 }
1130#ifdef USE_DMA
1131
1132 for (index = 0; index < DMA_CHAIN_COUNT; index++) {
1133 if (NULL != devpriv->dma0Buff[index]) {
1134 pci_free_consistent(devpriv->pci_dev,
1135 sizeof(u16) *
1136 devpriv->fifoLen / 2,
1137 devpriv->dma0Buff[index],
1138 devpriv->
1139 dma0BuffPhysAddr[index]);
1140 devpriv->dma0Buff[index] = NULL;
1141 }
1142 }
1143 if (NULL != devpriv->dma0Chain) {
1144 pci_free_consistent(devpriv->pci_dev,
1145 sizeof(struct plx_dma_desc) *
1146 DMA_CHAIN_COUNT, devpriv->dma0Chain,
1147 devpriv->dma0ChainPhysAddr);
1148 devpriv->dma0Chain = NULL;
1149 }
1150#endif
1151
1152
1153 if (dev->irq) {
1154
1155 RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
1156 & ~(ICS_PLIE | ICS_DMA0_E |
1157 ICS_DMA1_E));
1158 free_irq(dev->irq, dev);
1159 }
1160
1161
1162 if (devpriv->las0)
1163 iounmap(devpriv->las0);
1164
1165 if (devpriv->las1)
1166 iounmap(devpriv->las1);
1167
1168 if (devpriv->lcfg)
1169 iounmap(devpriv->lcfg);
1170
1171 if (devpriv->pci_dev) {
1172 if (devpriv->got_regions)
1173 comedi_pci_disable(devpriv->pci_dev);
1174
1175 pci_dev_put(devpriv->pci_dev);
1176 }
1177 }
1178
1179 printk(KERN_INFO "comedi%d: rtd520: removed.\n", dev->minor);
1180
1181 return 0;
1182}
1183
1184
1185
1186
1187static unsigned short rtdConvertChanGain(struct comedi_device *dev,
1188 unsigned int comediChan, int chanIndex)
1189{
1190 unsigned int chan, range, aref;
1191 unsigned short r = 0;
1192
1193 chan = CR_CHAN(comediChan);
1194 range = CR_RANGE(comediChan);
1195 aref = CR_AREF(comediChan);
1196
1197 r |= chan & 0xf;
1198
1199
1200 if (range < thisboard->range10Start) {
1201 r |= 0x000;
1202 r |= (range & 0x7) << 4;
1203 CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
1204 } else if (range < thisboard->rangeUniStart) {
1205 r |= 0x100;
1206
1207 r |= ((range - thisboard->range10Start) & 0x7) << 4;
1208 CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
1209 } else {
1210 r |= 0x200;
1211
1212 r |= ((range - thisboard->rangeUniStart) & 0x7) << 4;
1213 CHAN_ARRAY_CLEAR(devpriv->chanBipolar, chanIndex);
1214 }
1215
1216 switch (aref) {
1217 case AREF_GROUND:
1218 break;
1219
1220 case AREF_COMMON:
1221 r |= 0x80;
1222 break;
1223
1224 case AREF_DIFF:
1225 r |= 0x400;
1226 break;
1227
1228 case AREF_OTHER:
1229 break;
1230 }
1231
1232
1233 return r;
1234}
1235
1236
1237
1238
1239static void rtd_load_channelgain_list(struct comedi_device *dev,
1240 unsigned int n_chan, unsigned int *list)
1241{
1242 if (n_chan > 1) {
1243 int ii;
1244 RtdClearCGT(dev);
1245 RtdEnableCGT(dev, 1);
1246 for (ii = 0; ii < n_chan; ii++) {
1247 RtdWriteCGTable(dev, rtdConvertChanGain(dev, list[ii],
1248 ii));
1249 }
1250 } else {
1251 RtdEnableCGT(dev, 0);
1252 RtdWriteCGLatch(dev, rtdConvertChanGain(dev, list[0], 0));
1253 }
1254}
1255
1256
1257
1258static int rtd520_probe_fifo_depth(struct comedi_device *dev)
1259{
1260 unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
1261 unsigned i;
1262 static const unsigned limit = 0x2000;
1263 unsigned fifo_size = 0;
1264
1265 RtdAdcClearFifo(dev);
1266 rtd_load_channelgain_list(dev, 1, &chanspec);
1267 RtdAdcConversionSource(dev, 0);
1268
1269 for (i = 0; i < limit; ++i) {
1270 unsigned fifo_status;
1271
1272 RtdAdcStart(dev);
1273 udelay(1);
1274 fifo_status = RtdFifoStatus(dev);
1275 if ((fifo_status & FS_ADC_HEMPTY) == 0) {
1276 fifo_size = 2 * i;
1277 break;
1278 }
1279 }
1280 if (i == limit) {
1281 printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME);
1282 return -EIO;
1283 }
1284 RtdAdcClearFifo(dev);
1285 if (fifo_size != 0x400 && fifo_size != 0x2000) {
1286 printk
1287 (KERN_INFO "\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n",
1288 DRV_NAME, fifo_size);
1289 return -EIO;
1290 }
1291 return fifo_size;
1292}
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302static int rtd_ai_rinsn(struct comedi_device *dev,
1303 struct comedi_subdevice *s, struct comedi_insn *insn,
1304 unsigned int *data)
1305{
1306 int n, ii;
1307 int stat;
1308
1309
1310 RtdAdcClearFifo(dev);
1311
1312
1313 rtd_load_channelgain_list(dev, 1, &insn->chanspec);
1314
1315
1316 RtdAdcConversionSource(dev, 0);
1317
1318
1319 for (n = 0; n < insn->n; n++) {
1320 s16 d;
1321
1322 RtdAdcStart(dev);
1323
1324 for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) {
1325 stat = RtdFifoStatus(dev);
1326 if (stat & FS_ADC_NOT_EMPTY)
1327 break;
1328 WAIT_QUIETLY;
1329 }
1330 if (ii >= RTD_ADC_TIMEOUT) {
1331 DPRINTK
1332 ("rtd520: Error: ADC never finished! FifoStatus=0x%x\n",
1333 stat ^ 0x6666);
1334 return -ETIMEDOUT;
1335 }
1336
1337
1338 d = RtdAdcFifoGet(dev);
1339
1340 d = d >> 3;
1341 if (CHAN_ARRAY_TEST(devpriv->chanBipolar, 0))
1342
1343 data[n] = d + 2048;
1344 else
1345 data[n] = d;
1346 }
1347
1348
1349 return n;
1350}
1351
1352
1353
1354
1355
1356
1357
1358static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
1359 int count)
1360{
1361 int ii;
1362
1363 for (ii = 0; ii < count; ii++) {
1364 short sample;
1365 s16 d;
1366
1367 if (0 == devpriv->aiCount) {
1368 d = RtdAdcFifoGet(dev);
1369 continue;
1370 }
1371#if 0
1372 if (0 == (RtdFifoStatus(dev) & FS_ADC_NOT_EMPTY)) {
1373 DPRINTK("comedi: READ OOPS on %d of %d\n", ii + 1,
1374 count);
1375 break;
1376 }
1377#endif
1378 d = RtdAdcFifoGet(dev);
1379
1380 d = d >> 3;
1381 if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
1382 sample = d + 2048;
1383 else
1384 sample = d;
1385
1386 if (!comedi_buf_put(s->async, sample))
1387 return -1;
1388
1389 if (devpriv->aiCount > 0)
1390 devpriv->aiCount--;
1391 }
1392 return 0;
1393}
1394
1395
1396
1397
1398static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
1399{
1400 while (RtdFifoStatus(dev) & FS_ADC_NOT_EMPTY) {
1401 short sample;
1402 s16 d = RtdAdcFifoGet(dev);
1403
1404 if (0 == devpriv->aiCount) {
1405 continue;
1406 }
1407
1408 d = d >> 3;
1409 if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
1410 sample = d + 2048;
1411 else
1412 sample = d;
1413
1414 if (!comedi_buf_put(s->async, sample))
1415 return -1;
1416
1417 if (devpriv->aiCount > 0)
1418 devpriv->aiCount--;
1419 }
1420 return 0;
1421}
1422
1423#ifdef USE_DMA
1424
1425
1426
1427void abort_dma(struct comedi_device *dev, unsigned int channel)
1428{
1429 unsigned long dma_cs_addr;
1430 uint8_t status;
1431 unsigned int ii;
1432
1433
1434 dma_cs_addr = (unsigned long)devpriv->lcfg
1435 + ((channel == 0) ? LCFG_DMACSR0 : LCFG_DMACSR1);
1436
1437
1438
1439
1440
1441 status = readb(dma_cs_addr);
1442 if ((status & PLX_DMA_EN_BIT) == 0) {
1443 DPRINTK("rtd520: AbortDma on non-active channel %d (0x%x)\n",
1444 channel, status);
1445 goto abortDmaExit;
1446 }
1447
1448
1449 for (ii = 0; (status & PLX_DMA_DONE_BIT) && ii < RTD_DMA_TIMEOUT; ii++) {
1450 WAIT_QUIETLY;
1451 status = readb(dma_cs_addr);
1452 }
1453 if (status & PLX_DMA_DONE_BIT) {
1454 printk("rtd520: Timeout waiting for dma %i done clear\n",
1455 channel);
1456 goto abortDmaExit;
1457 }
1458
1459
1460 writeb(0, dma_cs_addr);
1461 udelay(1);
1462
1463 writeb(PLX_DMA_ABORT_BIT, dma_cs_addr);
1464
1465
1466 status = readb(dma_cs_addr);
1467 for (ii = 0;
1468 (status & PLX_DMA_DONE_BIT) == 0 && ii < RTD_DMA_TIMEOUT; ii++) {
1469 status = readb(dma_cs_addr);
1470 WAIT_QUIETLY;
1471 }
1472 if ((status & PLX_DMA_DONE_BIT) == 0) {
1473 printk("rtd520: Timeout waiting for dma %i done set\n",
1474 channel);
1475 }
1476
1477abortDmaExit:
1478
1479}
1480
1481
1482
1483
1484
1485static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s)
1486{
1487 int ii, n;
1488 s16 *dp;
1489
1490 if (devpriv->aiCount == 0)
1491 return 0;
1492
1493 dp = devpriv->dma0Buff[devpriv->dma0Offset];
1494 for (ii = 0; ii < devpriv->fifoLen / 2;) {
1495 short sample;
1496
1497 if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
1498 sample = (*dp >> 3) + 2048;
1499 else
1500 sample = *dp >> 3;
1501
1502 *dp++ = sample;
1503
1504 if (++s->async->cur_chan >= s->async->cmd.chanlist_len)
1505 s->async->cur_chan = 0;
1506
1507 ++ii;
1508 if (devpriv->aiCount > 0) {
1509 if (--devpriv->aiCount == 0) {
1510
1511 break;
1512 }
1513 }
1514 }
1515
1516
1517 dp = devpriv->dma0Buff[devpriv->dma0Offset];
1518 n = comedi_buf_write_alloc(s->async, ii * sizeof(s16));
1519 if (n < (ii * sizeof(s16))) {
1520 DPRINTK("rtd520:ai_process_dma buffer overflow %d samples!\n",
1521 ii - (n / sizeof(s16)));
1522 s->async->events |= COMEDI_CB_ERROR;
1523 return -1;
1524 }
1525 comedi_buf_memcpy_to(s->async, 0, dp, n);
1526 comedi_buf_write_free(s->async, n);
1527
1528
1529 s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
1530
1531 if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) {
1532 devpriv->dma0Offset = 0;
1533 }
1534 return 0;
1535}
1536#endif
1537
1538
1539
1540
1541
1542
1543
1544static irqreturn_t rtd_interrupt(int irq,
1545 void *d)
1546{
1547 struct comedi_device *dev = d;
1548 u16 status;
1549 u16 fifoStatus;
1550 struct comedi_subdevice *s = dev->subdevices + 0;
1551
1552 if (!dev->attached)
1553 return IRQ_NONE;
1554
1555 devpriv->intCount++;
1556
1557 fifoStatus = RtdFifoStatus(dev);
1558
1559 if (!(fifoStatus & FS_ADC_NOT_FULL)) {
1560 DPRINTK("rtd520: FIFO full! fifo_status=0x%x\n", (fifoStatus ^ 0x6666) & 0x7777);
1561 goto abortTransfer;
1562 }
1563#ifdef USE_DMA
1564 if (devpriv->flags & DMA0_ACTIVE) {
1565 u32 istatus = RtdPlxInterruptRead(dev);
1566
1567 if (istatus & ICS_DMA0_A) {
1568 if (ai_process_dma(dev, s) < 0) {
1569 DPRINTK
1570 ("rtd520: comedi read buffer overflow (DMA) with %ld to go!\n",
1571 devpriv->aiCount);
1572 RtdDma0Control(dev,
1573 (devpriv->dma0Control &
1574 ~PLX_DMA_START_BIT)
1575 | PLX_CLEAR_DMA_INTR_BIT);
1576 goto abortTransfer;
1577 }
1578
1579
1580
1581 RtdDma0Control(dev,
1582 (devpriv->
1583 dma0Control & ~PLX_DMA_START_BIT)
1584 | PLX_CLEAR_DMA_INTR_BIT);
1585 if (0 == devpriv->aiCount) {
1586 DPRINTK("rtd520: Samples Done (DMA).\n");
1587 goto transferDone;
1588 }
1589 comedi_event(dev, s);
1590 } else {
1591
1592 }
1593 }
1594
1595#endif
1596
1597 status = RtdInterruptStatus(dev);
1598
1599 if (0 == status)
1600 return IRQ_HANDLED;
1601
1602 if (status & IRQM_ADC_ABOUT_CNT) {
1603
1604
1605
1606 if (!(fifoStatus & FS_ADC_HEMPTY)) {
1607
1608
1609 if (ai_read_n(dev, s, devpriv->fifoLen / 2) < 0) {
1610 DPRINTK
1611 ("rtd520: comedi read buffer overflow (1/2FIFO) with %ld to go!\n",
1612 devpriv->aiCount);
1613 goto abortTransfer;
1614 }
1615 if (0 == devpriv->aiCount) {
1616 DPRINTK("rtd520: Samples Done (1/2). fifo_status was 0x%x\n", (fifoStatus ^ 0x6666) & 0x7777);
1617 goto transferDone;
1618 }
1619 comedi_event(dev, s);
1620 } else if (devpriv->transCount > 0) {
1621
1622
1623 if (fifoStatus & FS_ADC_NOT_EMPTY) {
1624 if (ai_read_n(dev, s, devpriv->transCount) < 0) {
1625 DPRINTK
1626 ("rtd520: comedi read buffer overflow (N) with %ld to go!\n",
1627 devpriv->aiCount);
1628 goto abortTransfer;
1629 }
1630 if (0 == devpriv->aiCount) {
1631 DPRINTK
1632 ("rtd520: Samples Done (N). fifo_status was 0x%x\n",
1633 (fifoStatus ^ 0x6666) & 0x7777);
1634 goto transferDone;
1635 }
1636 comedi_event(dev, s);
1637 }
1638 } else {
1639 DPRINTK
1640 ("rtd520: Sample int. Wait for 1/2. fifo_status 0x%x\n",
1641 (fifoStatus ^ 0x6666) & 0x7777);
1642 }
1643 } else {
1644 DPRINTK("rtd520: unknown interrupt source!\n");
1645 }
1646
1647 if (0xffff & RtdInterruptOverrunStatus(dev)) {
1648 DPRINTK
1649 ("rtd520: Interrupt overrun with %ld to go! over_status=0x%x\n",
1650 devpriv->aiCount, 0xffff & RtdInterruptOverrunStatus(dev));
1651 goto abortTransfer;
1652 }
1653
1654
1655 RtdInterruptClearMask(dev, status);
1656 RtdInterruptClear(dev);
1657 return IRQ_HANDLED;
1658
1659abortTransfer:
1660 RtdAdcClearFifo(dev);
1661 s->async->events |= COMEDI_CB_ERROR;
1662 devpriv->aiCount = 0;
1663
1664
1665transferDone:
1666 RtdPacerStopSource(dev, 0);
1667 RtdPacerStop(dev);
1668 RtdAdcConversionSource(dev, 0);
1669 RtdInterruptMask(dev, 0);
1670#ifdef USE_DMA
1671 if (devpriv->flags & DMA0_ACTIVE) {
1672 RtdPlxInterruptWrite(dev,
1673 RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
1674 abort_dma(dev, 0);
1675 devpriv->flags &= ~DMA0_ACTIVE;
1676
1677 if (devpriv->aiCount > 0) {
1678 DPRINTK("rtd520: Lost DMA data! %ld remain\n",
1679 devpriv->aiCount);
1680 }
1681 }
1682#endif
1683
1684 if (devpriv->aiCount > 0) {
1685 fifoStatus = RtdFifoStatus(dev);
1686 DPRINTK("rtd520: Finishing up. %ld remain, fifoStat=%x\n", devpriv->aiCount, (fifoStatus ^ 0x6666) & 0x7777);
1687 ai_read_dregs(dev, s);
1688 }
1689
1690 s->async->events |= COMEDI_CB_EOA;
1691 comedi_event(dev, s);
1692
1693
1694 status = RtdInterruptStatus(dev);
1695 RtdInterruptClearMask(dev, status);
1696 RtdInterruptClear(dev);
1697
1698 fifoStatus = RtdFifoStatus(dev);
1699 DPRINTK
1700 ("rtd520: Acquisition complete. %ld ints, intStat=%x, overStat=%x\n",
1701 devpriv->intCount, status,
1702 0xffff & RtdInterruptOverrunStatus(dev));
1703
1704 return IRQ_HANDLED;
1705}
1706
1707#if 0
1708
1709
1710
1711static int rtd_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
1712{
1713
1714
1715 return s->async->buf_write_count - s->async->buf_read_count;
1716}
1717#endif
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728static int rtd_ai_cmdtest(struct comedi_device *dev,
1729 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1730{
1731 int err = 0;
1732 int tmp;
1733
1734
1735
1736 tmp = cmd->start_src;
1737 cmd->start_src &= TRIG_NOW;
1738 if (!cmd->start_src || tmp != cmd->start_src)
1739 err++;
1740
1741 tmp = cmd->scan_begin_src;
1742 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
1743 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1744 err++;
1745
1746
1747 tmp = cmd->convert_src;
1748 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1749 if (!cmd->convert_src || tmp != cmd->convert_src)
1750 err++;
1751
1752
1753 tmp = cmd->scan_end_src;
1754 cmd->scan_end_src &= TRIG_COUNT;
1755 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1756 err++;
1757
1758
1759 tmp = cmd->stop_src;
1760 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1761 if (!cmd->stop_src || tmp != cmd->stop_src)
1762 err++;
1763
1764
1765 if (err)
1766 return 1;
1767
1768
1769
1770
1771 if (cmd->scan_begin_src != TRIG_TIMER &&
1772 cmd->scan_begin_src != TRIG_EXT) {
1773 err++;
1774 }
1775 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1776 err++;
1777
1778 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1779 err++;
1780
1781 if (err)
1782 return 2;
1783
1784
1785
1786 if (cmd->start_arg != 0) {
1787 cmd->start_arg = 0;
1788 err++;
1789 }
1790
1791 if (cmd->scan_begin_src == TRIG_TIMER) {
1792
1793 if (1 == cmd->chanlist_len) {
1794 if (cmd->scan_begin_arg < RTD_MAX_SPEED_1) {
1795 cmd->scan_begin_arg = RTD_MAX_SPEED_1;
1796 rtd_ns_to_timer(&cmd->scan_begin_arg,
1797 TRIG_ROUND_UP);
1798 err++;
1799 }
1800 if (cmd->scan_begin_arg > RTD_MIN_SPEED_1) {
1801 cmd->scan_begin_arg = RTD_MIN_SPEED_1;
1802 rtd_ns_to_timer(&cmd->scan_begin_arg,
1803 TRIG_ROUND_DOWN);
1804 err++;
1805 }
1806 } else {
1807 if (cmd->scan_begin_arg < RTD_MAX_SPEED) {
1808 cmd->scan_begin_arg = RTD_MAX_SPEED;
1809 rtd_ns_to_timer(&cmd->scan_begin_arg,
1810 TRIG_ROUND_UP);
1811 err++;
1812 }
1813 if (cmd->scan_begin_arg > RTD_MIN_SPEED) {
1814 cmd->scan_begin_arg = RTD_MIN_SPEED;
1815 rtd_ns_to_timer(&cmd->scan_begin_arg,
1816 TRIG_ROUND_DOWN);
1817 err++;
1818 }
1819 }
1820 } else {
1821
1822
1823
1824 if (cmd->scan_begin_arg > 9) {
1825 cmd->scan_begin_arg = 9;
1826 err++;
1827 }
1828 }
1829 if (cmd->convert_src == TRIG_TIMER) {
1830 if (1 == cmd->chanlist_len) {
1831 if (cmd->convert_arg < RTD_MAX_SPEED_1) {
1832 cmd->convert_arg = RTD_MAX_SPEED_1;
1833 rtd_ns_to_timer(&cmd->convert_arg,
1834 TRIG_ROUND_UP);
1835 err++;
1836 }
1837 if (cmd->convert_arg > RTD_MIN_SPEED_1) {
1838 cmd->convert_arg = RTD_MIN_SPEED_1;
1839 rtd_ns_to_timer(&cmd->convert_arg,
1840 TRIG_ROUND_DOWN);
1841 err++;
1842 }
1843 } else {
1844 if (cmd->convert_arg < RTD_MAX_SPEED) {
1845 cmd->convert_arg = RTD_MAX_SPEED;
1846 rtd_ns_to_timer(&cmd->convert_arg,
1847 TRIG_ROUND_UP);
1848 err++;
1849 }
1850 if (cmd->convert_arg > RTD_MIN_SPEED) {
1851 cmd->convert_arg = RTD_MIN_SPEED;
1852 rtd_ns_to_timer(&cmd->convert_arg,
1853 TRIG_ROUND_DOWN);
1854 err++;
1855 }
1856 }
1857 } else {
1858
1859
1860 if (cmd->convert_arg > 9) {
1861 cmd->convert_arg = 9;
1862 err++;
1863 }
1864 }
1865
1866#if 0
1867 if (cmd->scan_end_arg != cmd->chanlist_len) {
1868 cmd->scan_end_arg = cmd->chanlist_len;
1869 err++;
1870 }
1871#endif
1872 if (cmd->stop_src == TRIG_COUNT) {
1873
1874
1875 } else {
1876
1877 if (cmd->stop_arg != 0) {
1878 cmd->stop_arg = 0;
1879 err++;
1880 }
1881 }
1882
1883 if (err)
1884 return 3;
1885
1886
1887
1888
1889 if (cmd->chanlist_len > RTD_MAX_CHANLIST) {
1890 cmd->chanlist_len = RTD_MAX_CHANLIST;
1891 err++;
1892 }
1893 if (cmd->scan_begin_src == TRIG_TIMER) {
1894 tmp = cmd->scan_begin_arg;
1895 rtd_ns_to_timer(&cmd->scan_begin_arg,
1896 cmd->flags & TRIG_ROUND_MASK);
1897 if (tmp != cmd->scan_begin_arg)
1898 err++;
1899
1900 }
1901 if (cmd->convert_src == TRIG_TIMER) {
1902 tmp = cmd->convert_arg;
1903 rtd_ns_to_timer(&cmd->convert_arg,
1904 cmd->flags & TRIG_ROUND_MASK);
1905 if (tmp != cmd->convert_arg)
1906 err++;
1907
1908 if (cmd->scan_begin_src == TRIG_TIMER
1909 && (cmd->scan_begin_arg
1910 < (cmd->convert_arg * cmd->scan_end_arg))) {
1911 cmd->scan_begin_arg =
1912 cmd->convert_arg * cmd->scan_end_arg;
1913 err++;
1914 }
1915 }
1916
1917 if (err)
1918 return 4;
1919
1920 return 0;
1921}
1922
1923
1924
1925
1926
1927
1928
1929static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1930{
1931 struct comedi_cmd *cmd = &s->async->cmd;
1932 int timer;
1933
1934
1935 RtdPacerStopSource(dev, 0);
1936 RtdPacerStop(dev);
1937 RtdAdcConversionSource(dev, 0);
1938 RtdInterruptMask(dev, 0);
1939#ifdef USE_DMA
1940 if (devpriv->flags & DMA0_ACTIVE) {
1941 RtdPlxInterruptWrite(dev,
1942 RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
1943 abort_dma(dev, 0);
1944 devpriv->flags &= ~DMA0_ACTIVE;
1945 if (RtdPlxInterruptRead(dev) & ICS_DMA0_A) {
1946 RtdDma0Control(dev, PLX_CLEAR_DMA_INTR_BIT);
1947 }
1948 }
1949 RtdDma0Reset(dev);
1950#endif
1951 RtdAdcClearFifo(dev);
1952 RtdInterruptOverrunClear(dev);
1953 devpriv->intCount = 0;
1954
1955 if (!dev->irq) {
1956 DPRINTK("rtd520: ERROR! No interrupt available!\n");
1957 return -ENXIO;
1958 }
1959
1960
1961
1962 rtd_load_channelgain_list(dev, cmd->chanlist_len, cmd->chanlist);
1963
1964
1965 if (cmd->chanlist_len > 1) {
1966
1967 RtdPacerStartSource(dev, 0);
1968 RtdBurstStartSource(dev, 1);
1969 RtdAdcConversionSource(dev, 2);
1970 } else {
1971
1972 RtdPacerStartSource(dev, 0);
1973 RtdAdcConversionSource(dev, 1);
1974 }
1975 RtdAboutCounter(dev, devpriv->fifoLen / 2 - 1);
1976
1977 if (TRIG_TIMER == cmd->scan_begin_src) {
1978
1979
1980 if (cmd->flags & TRIG_WAKE_EOS) {
1981
1982
1983 devpriv->transCount = cmd->chanlist_len;
1984 devpriv->flags |= SEND_EOS;
1985 } else {
1986
1987 devpriv->transCount
1988 =
1989 (TRANS_TARGET_PERIOD * cmd->chanlist_len) /
1990 cmd->scan_begin_arg;
1991 if (devpriv->transCount < cmd->chanlist_len) {
1992
1993 devpriv->transCount = cmd->chanlist_len;
1994 } else {
1995 devpriv->transCount =
1996 (devpriv->transCount +
1997 cmd->chanlist_len - 1)
1998 / cmd->chanlist_len;
1999 devpriv->transCount *= cmd->chanlist_len;
2000 }
2001 devpriv->flags |= SEND_EOS;
2002 }
2003 if (devpriv->transCount >= (devpriv->fifoLen / 2)) {
2004
2005 devpriv->transCount = 0;
2006 devpriv->flags &= ~SEND_EOS;
2007 } else {
2008
2009 RtdAboutCounter(dev, devpriv->transCount - 1);
2010 }
2011
2012 DPRINTK
2013 ("rtd520: scanLen=%d tranferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n",
2014 cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen,
2015 cmd->scan_begin_arg, devpriv->flags);
2016 } else {
2017 devpriv->transCount = 0;
2018 devpriv->flags &= ~SEND_EOS;
2019 }
2020 RtdPacerClockSource(dev, 1);
2021 RtdAboutStopEnable(dev, 1);
2022
2023
2024
2025
2026 switch (cmd->stop_src) {
2027 case TRIG_COUNT:
2028 devpriv->aiCount = cmd->stop_arg * cmd->chanlist_len;
2029 if ((devpriv->transCount > 0)
2030 && (devpriv->transCount > devpriv->aiCount)) {
2031 devpriv->transCount = devpriv->aiCount;
2032 }
2033 break;
2034
2035 case TRIG_NONE:
2036 devpriv->aiCount = -1;
2037 break;
2038
2039 default:
2040 DPRINTK("rtd520: Warning! ignoring stop_src mode %d\n",
2041 cmd->stop_src);
2042 }
2043
2044
2045 switch (cmd->scan_begin_src) {
2046 case TRIG_TIMER:
2047 timer = rtd_ns_to_timer(&cmd->scan_begin_arg,
2048 TRIG_ROUND_NEAREST);
2049
2050
2051 RtdPacerCounter(dev, timer);
2052
2053 break;
2054
2055 case TRIG_EXT:
2056 RtdPacerStartSource(dev, 1);
2057 break;
2058
2059 default:
2060 DPRINTK("rtd520: Warning! ignoring scan_begin_src mode %d\n",
2061 cmd->scan_begin_src);
2062 }
2063
2064
2065 switch (cmd->convert_src) {
2066 case TRIG_TIMER:
2067 if (cmd->chanlist_len > 1) {
2068 timer = rtd_ns_to_timer(&cmd->convert_arg,
2069 TRIG_ROUND_NEAREST);
2070
2071
2072 RtdBurstCounter(dev, timer);
2073 }
2074
2075 break;
2076
2077 case TRIG_EXT:
2078 RtdBurstStartSource(dev, 2);
2079 break;
2080
2081 default:
2082 DPRINTK("rtd520: Warning! ignoring convert_src mode %d\n",
2083 cmd->convert_src);
2084 }
2085
2086
2087
2088
2089 RtdInterruptClearMask(dev, ~0);
2090 RtdInterruptClear(dev);
2091
2092
2093 if (devpriv->transCount > 0) {
2094 RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
2095 DPRINTK("rtd520: Transferring every %d\n", devpriv->transCount);
2096 } else {
2097#ifdef USE_DMA
2098 devpriv->flags |= DMA0_ACTIVE;
2099
2100
2101 devpriv->dma0Offset = 0;
2102 RtdDma0Mode(dev, DMA_MODE_BITS);
2103 RtdDma0Next(dev,
2104 devpriv->dma0Chain[DMA_CHAIN_COUNT - 1].next);
2105 RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);
2106
2107 RtdPlxInterruptWrite(dev,
2108 RtdPlxInterruptRead(dev) | ICS_DMA0_E);
2109
2110 RtdDma0Control(dev, PLX_DMA_EN_BIT);
2111 RtdDma0Control(dev, PLX_DMA_EN_BIT | PLX_DMA_START_BIT);
2112 DPRINTK("rtd520: Using DMA0 transfers. plxInt %x RtdInt %x\n",
2113 RtdPlxInterruptRead(dev), devpriv->intMask);
2114#else
2115 RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
2116 DPRINTK("rtd520: Transferring every 1/2 FIFO\n");
2117#endif
2118 }
2119
2120
2121
2122 RtdPacerStart(dev);
2123 return 0;
2124}
2125
2126
2127
2128
2129static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
2130{
2131 u16 status;
2132
2133 RtdPacerStopSource(dev, 0);
2134 RtdPacerStop(dev);
2135 RtdAdcConversionSource(dev, 0);
2136 RtdInterruptMask(dev, 0);
2137 devpriv->aiCount = 0;
2138#ifdef USE_DMA
2139 if (devpriv->flags & DMA0_ACTIVE) {
2140 RtdPlxInterruptWrite(dev,
2141 RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
2142 abort_dma(dev, 0);
2143 devpriv->flags &= ~DMA0_ACTIVE;
2144 }
2145#endif
2146 status = RtdInterruptStatus(dev);
2147 DPRINTK
2148 ("rtd520: Acquisition canceled. %ld ints, intStat=%x, overStat=%x\n",
2149 devpriv->intCount, status,
2150 0xffff & RtdInterruptOverrunStatus(dev));
2151 return 0;
2152}
2153
2154
2155
2156
2157
2158
2159
2160static int rtd_ns_to_timer_base(unsigned int *nanosec,
2161 int round_mode, int base)
2162{
2163 int divider;
2164
2165 switch (round_mode) {
2166 case TRIG_ROUND_NEAREST:
2167 default:
2168 divider = (*nanosec + base / 2) / base;
2169 break;
2170 case TRIG_ROUND_DOWN:
2171 divider = (*nanosec) / base;
2172 break;
2173 case TRIG_ROUND_UP:
2174 divider = (*nanosec + base - 1) / base;
2175 break;
2176 }
2177 if (divider < 2)
2178 divider = 2;
2179
2180
2181
2182
2183 *nanosec = base * divider;
2184 return divider - 1;
2185}
2186
2187
2188
2189
2190
2191
2192static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
2193{
2194 return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE);
2195}
2196
2197
2198
2199
2200static int rtd_ao_winsn(struct comedi_device *dev,
2201 struct comedi_subdevice *s, struct comedi_insn *insn,
2202 unsigned int *data)
2203{
2204 int i;
2205 int chan = CR_CHAN(insn->chanspec);
2206 int range = CR_RANGE(insn->chanspec);
2207
2208
2209 RtdDacRange(dev, chan, range);
2210
2211
2212
2213 for (i = 0; i < insn->n; ++i) {
2214 int val = data[i] << 3;
2215 int stat = 0;
2216 int ii;
2217
2218
2219
2220 if ((range > 1)
2221 && (data[i] < 2048)) {
2222
2223 val = (((int)data[i]) - 2048) << 3;
2224 } else {
2225 val = data[i] << 3;
2226 }
2227
2228 DPRINTK
2229 ("comedi: rtd520 DAC chan=%d range=%d writing %d as 0x%x\n",
2230 chan, range, data[i], val);
2231
2232
2233 RtdDacFifoPut(dev, chan, val);
2234 RtdDacUpdate(dev, chan);
2235
2236 devpriv->aoValue[chan] = data[i];
2237
2238 for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
2239 stat = RtdFifoStatus(dev);
2240
2241 if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
2242 FS_DAC2_NOT_EMPTY))
2243 break;
2244 WAIT_QUIETLY;
2245 }
2246 if (ii >= RTD_DAC_TIMEOUT) {
2247 DPRINTK
2248 ("rtd520: Error: DAC never finished! FifoStatus=0x%x\n",
2249 stat ^ 0x6666);
2250 return -ETIMEDOUT;
2251 }
2252 }
2253
2254
2255 return i;
2256}
2257
2258
2259
2260static int rtd_ao_rinsn(struct comedi_device *dev,
2261 struct comedi_subdevice *s, struct comedi_insn *insn,
2262 unsigned int *data)
2263{
2264 int i;
2265 int chan = CR_CHAN(insn->chanspec);
2266
2267 for (i = 0; i < insn->n; i++)
2268 data[i] = devpriv->aoValue[chan];
2269
2270
2271 return i;
2272}
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284static int rtd_dio_insn_bits(struct comedi_device *dev,
2285 struct comedi_subdevice *s,
2286 struct comedi_insn *insn, unsigned int *data)
2287{
2288 if (insn->n != 2)
2289 return -EINVAL;
2290
2291
2292
2293 if (data[0]) {
2294 s->state &= ~data[0];
2295 s->state |= data[0] & data[1];
2296
2297
2298 RtdDio0Write(dev, s->state);
2299 }
2300
2301
2302 data[1] = RtdDio0Read(dev);
2303
2304
2305
2306 return 2;
2307}
2308
2309
2310
2311
2312static int rtd_dio_insn_config(struct comedi_device *dev,
2313 struct comedi_subdevice *s,
2314 struct comedi_insn *insn, unsigned int *data)
2315{
2316 int chan = CR_CHAN(insn->chanspec);
2317
2318
2319
2320
2321
2322 switch (data[0]) {
2323 case INSN_CONFIG_DIO_OUTPUT:
2324 s->io_bits |= 1 << chan;
2325 break;
2326 case INSN_CONFIG_DIO_INPUT:
2327 s->io_bits &= ~(1 << chan);
2328 break;
2329 case INSN_CONFIG_DIO_QUERY:
2330 data[1] =
2331 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
2332 return insn->n;
2333 break;
2334 default:
2335 return -EINVAL;
2336 }
2337
2338 DPRINTK("rtd520: port_0_direction=0x%x (1 means out)\n", s->io_bits);
2339
2340 RtdDioStatusWrite(dev, 0x01);
2341 RtdDio0CtrlWrite(dev, s->io_bits);
2342 RtdDioStatusWrite(dev, 0);
2343
2344
2345
2346
2347
2348 return 1;
2349}
2350
2351
2352
2353
2354
2355static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev,
2356 const struct pci_device_id *ent)
2357{
2358 return comedi_pci_auto_config(dev, rtd520Driver.driver_name);
2359}
2360
2361static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev)
2362{
2363 comedi_pci_auto_unconfig(dev);
2364}
2365
2366static struct pci_driver rtd520Driver_pci_driver = {
2367 .id_table = rtd520_pci_table,
2368 .probe = &rtd520Driver_pci_probe,
2369 .remove = __devexit_p(&rtd520Driver_pci_remove)
2370};
2371
2372static int __init rtd520Driver_init_module(void)
2373{
2374 int retval;
2375
2376 retval = comedi_driver_register(&rtd520Driver);
2377 if (retval < 0)
2378 return retval;
2379
2380 rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name;
2381 return pci_register_driver(&rtd520Driver_pci_driver);
2382}
2383
2384static void __exit rtd520Driver_cleanup_module(void)
2385{
2386 pci_unregister_driver(&rtd520Driver_pci_driver);
2387 comedi_driver_unregister(&rtd520Driver);
2388}
2389
2390module_init(rtd520Driver_init_module);
2391module_exit(rtd520Driver_cleanup_module);
2392
2393MODULE_AUTHOR("Comedi http://www.comedi.org");
2394MODULE_DESCRIPTION("Comedi low-level driver");
2395MODULE_LICENSE("GPL");
2396