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
105
106
107
108
109
110
111
112
113
114
115
116#include "../comedidev.h"
117
118#include <linux/delay.h>
119#include <linux/interrupt.h>
120
121#include "comedi_pci.h"
122#include "8255.h"
123
124#define DAQBOARD2000_SUBSYSTEM_IDS2 0x00021616
125#define DAQBOARD2000_SUBSYSTEM_IDS4 0x00041616
126
127#define DAQBOARD2000_DAQ_SIZE 0x1002
128#define DAQBOARD2000_PLX_SIZE 0x100
129
130
131#define DAQBOARD2000_SECRProgPinHi 0x8001767e
132#define DAQBOARD2000_SECRProgPinLo 0x8000767e
133#define DAQBOARD2000_SECRLocalBusHi 0xc000767e
134#define DAQBOARD2000_SECRLocalBusLo 0x8000767e
135#define DAQBOARD2000_SECRReloadHi 0xa000767e
136#define DAQBOARD2000_SECRReloadLo 0x8000767e
137
138
139#define DAQBOARD2000_EEPROM_PRESENT 0x10000000
140
141
142#define DAQBOARD2000_CPLD_INIT 0x0002
143#define DAQBOARD2000_CPLD_DONE 0x0004
144
145
146static const struct comedi_lrange range_daqboard2000_ai = { 13, {
147 RANGE(-10, 10),
148 RANGE(-5, 5),
149 RANGE(-2.5,
150 2.5),
151 RANGE(-1.25,
152 1.25),
153 RANGE(-0.625,
154 0.625),
155 RANGE(-0.3125,
156 0.3125),
157 RANGE(-0.156,
158 0.156),
159 RANGE(0, 10),
160 RANGE(0, 5),
161 RANGE(0, 2.5),
162 RANGE(0, 1.25),
163 RANGE(0,
164 0.625),
165 RANGE(0,
166 0.3125)
167 }
168};
169
170static const struct comedi_lrange range_daqboard2000_ao = { 1, {
171 RANGE(-10, 10)
172 }
173};
174
175struct daqboard2000_hw {
176 volatile u16 acqControl;
177 volatile u16 acqScanListFIFO;
178 volatile u32 acqPacerClockDivLow;
179
180 volatile u16 acqScanCounter;
181 volatile u16 acqPacerClockDivHigh;
182 volatile u16 acqTriggerCount;
183 volatile u16 fill2;
184 volatile u16 acqResultsFIFO;
185 volatile u16 fill3;
186 volatile u16 acqResultsShadow;
187 volatile u16 fill4;
188 volatile u16 acqAdcResult;
189 volatile u16 fill5;
190 volatile u16 dacScanCounter;
191 volatile u16 fill6;
192
193 volatile u16 dacControl;
194 volatile u16 fill7;
195 volatile s16 dacFIFO;
196 volatile u16 fill8[2];
197 volatile u16 dacPacerClockDiv;
198 volatile u16 refDacs;
199 volatile u16 fill9;
200
201 volatile u16 dioControl;
202 volatile s16 dioP3hsioData;
203 volatile u16 dioP3Control;
204 volatile u16 calEepromControl;
205 volatile s16 dacSetting[4];
206 volatile s16 dioP2ExpansionIO8Bit[32];
207
208 volatile u16 ctrTmrControl;
209 volatile u16 fill10[3];
210 volatile s16 ctrInput[4];
211 volatile u16 fill11[8];
212 volatile u16 timerDivisor[2];
213 volatile u16 fill12[6];
214
215 volatile u16 dmaControl;
216 volatile u16 trigControl;
217 volatile u16 fill13[2];
218 volatile u16 calEeprom;
219 volatile u16 acqDigitalMark;
220 volatile u16 trigDacs;
221 volatile u16 fill14;
222 volatile s16 dioP2ExpansionIO16Bit[32];
223};
224
225
226#define DAQBOARD2000_SeqStartScanList 0x0011
227#define DAQBOARD2000_SeqStopScanList 0x0010
228
229
230#define DAQBOARD2000_AcqResetScanListFifo 0x0004
231#define DAQBOARD2000_AcqResetResultsFifo 0x0002
232#define DAQBOARD2000_AcqResetConfigPipe 0x0001
233
234
235#define DAQBOARD2000_AcqResultsFIFOMore1Sample 0x0001
236#define DAQBOARD2000_AcqResultsFIFOHasValidData 0x0002
237#define DAQBOARD2000_AcqResultsFIFOOverrun 0x0004
238#define DAQBOARD2000_AcqLogicScanning 0x0008
239#define DAQBOARD2000_AcqConfigPipeFull 0x0010
240#define DAQBOARD2000_AcqScanListFIFOEmpty 0x0020
241#define DAQBOARD2000_AcqAdcNotReady 0x0040
242#define DAQBOARD2000_ArbitrationFailure 0x0080
243#define DAQBOARD2000_AcqPacerOverrun 0x0100
244#define DAQBOARD2000_DacPacerOverrun 0x0200
245#define DAQBOARD2000_AcqHardwareError 0x01c0
246
247
248#define DAQBOARD2000_SeqStartScanList 0x0011
249#define DAQBOARD2000_SeqStopScanList 0x0010
250
251
252#define DAQBOARD2000_AdcPacerInternal 0x0030
253#define DAQBOARD2000_AdcPacerExternal 0x0032
254#define DAQBOARD2000_AdcPacerEnable 0x0031
255#define DAQBOARD2000_AdcPacerEnableDacPacer 0x0034
256#define DAQBOARD2000_AdcPacerDisable 0x0030
257#define DAQBOARD2000_AdcPacerNormalMode 0x0060
258#define DAQBOARD2000_AdcPacerCompatibilityMode 0x0061
259#define DAQBOARD2000_AdcPacerInternalOutEnable 0x0008
260#define DAQBOARD2000_AdcPacerExternalRising 0x0100
261
262
263#define DAQBOARD2000_DacFull 0x0001
264#define DAQBOARD2000_RefBusy 0x0002
265#define DAQBOARD2000_TrgBusy 0x0004
266#define DAQBOARD2000_CalBusy 0x0008
267#define DAQBOARD2000_Dac0Busy 0x0010
268#define DAQBOARD2000_Dac1Busy 0x0020
269#define DAQBOARD2000_Dac2Busy 0x0040
270#define DAQBOARD2000_Dac3Busy 0x0080
271
272
273#define DAQBOARD2000_Dac0Enable 0x0021
274#define DAQBOARD2000_Dac1Enable 0x0031
275#define DAQBOARD2000_Dac2Enable 0x0041
276#define DAQBOARD2000_Dac3Enable 0x0051
277#define DAQBOARD2000_DacEnableBit 0x0001
278#define DAQBOARD2000_Dac0Disable 0x0020
279#define DAQBOARD2000_Dac1Disable 0x0030
280#define DAQBOARD2000_Dac2Disable 0x0040
281#define DAQBOARD2000_Dac3Disable 0x0050
282#define DAQBOARD2000_DacResetFifo 0x0004
283#define DAQBOARD2000_DacPatternDisable 0x0060
284#define DAQBOARD2000_DacPatternEnable 0x0061
285#define DAQBOARD2000_DacSelectSignedData 0x0002
286#define DAQBOARD2000_DacSelectUnsignedData 0x0000
287
288
289#define DAQBOARD2000_TrigAnalog 0x0000
290#define DAQBOARD2000_TrigTTL 0x0010
291#define DAQBOARD2000_TrigTransHiLo 0x0004
292#define DAQBOARD2000_TrigTransLoHi 0x0000
293#define DAQBOARD2000_TrigAbove 0x0000
294#define DAQBOARD2000_TrigBelow 0x0004
295#define DAQBOARD2000_TrigLevelSense 0x0002
296#define DAQBOARD2000_TrigEdgeSense 0x0000
297#define DAQBOARD2000_TrigEnable 0x0001
298#define DAQBOARD2000_TrigDisable 0x0000
299
300
301#define DAQBOARD2000_PosRefDacSelect 0x0100
302#define DAQBOARD2000_NegRefDacSelect 0x0000
303
304static int daqboard2000_attach(struct comedi_device *dev,
305 struct comedi_devconfig *it);
306static int daqboard2000_detach(struct comedi_device *dev);
307
308static struct comedi_driver driver_daqboard2000 = {
309 .driver_name = "daqboard2000",
310 .module = THIS_MODULE,
311 .attach = daqboard2000_attach,
312 .detach = daqboard2000_detach,
313};
314
315struct daq200_boardtype {
316 const char *name;
317 int id;
318};
319static const struct daq200_boardtype boardtypes[] = {
320 {"ids2", DAQBOARD2000_SUBSYSTEM_IDS2},
321 {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
322};
323
324#define n_boardtypes (sizeof(boardtypes)/sizeof(struct daq200_boardtype))
325#define this_board ((const struct daq200_boardtype *)dev->board_ptr)
326
327static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
328 {
329 0x1616, 0x0409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
330 0}
331};
332
333MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
334
335struct daqboard2000_private {
336 enum {
337 card_daqboard_2000
338 } card;
339 struct pci_dev *pci_dev;
340 void *daq;
341 void *plx;
342 int got_regions;
343 unsigned int ao_readback[2];
344};
345
346#define devpriv ((struct daqboard2000_private *)dev->private)
347
348static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry)
349{
350 struct daqboard2000_hw *fpga = devpriv->daq;
351
352
353 fpga->acqScanListFIFO = entry & 0x00ff;
354
355 fpga->acqScanListFIFO = (entry >> 8) & 0x00ff;
356}
357
358static void setup_sampling(struct comedi_device *dev, int chan, int gain)
359{
360 u16 word0, word1, word2, word3;
361
362
363 word0 = 0;
364 word1 = 0x0004;
365 word2 = (chan << 6) & 0x00c0;
366 switch (chan / 4) {
367 case 0:
368 word3 = 0x0001;
369 break;
370 case 1:
371 word3 = 0x0002;
372 break;
373 case 2:
374 word3 = 0x0005;
375 break;
376 case 3:
377 word3 = 0x0006;
378 break;
379 case 4:
380 word3 = 0x0041;
381 break;
382 case 5:
383 word3 = 0x0042;
384 break;
385 default:
386 word3 = 0;
387 break;
388 }
389
390
391
392
393
394 word2 |= 0x0800;
395 word3 |= 0xc000;
396
397 writeAcqScanListEntry(dev, word0);
398 writeAcqScanListEntry(dev, word1);
399 writeAcqScanListEntry(dev, word2);
400 writeAcqScanListEntry(dev, word3);
401}
402
403static int daqboard2000_ai_insn_read(struct comedi_device *dev,
404 struct comedi_subdevice *s,
405 struct comedi_insn *insn,
406 unsigned int *data)
407{
408 int i;
409 struct daqboard2000_hw *fpga = devpriv->daq;
410 int gain, chan, timeout;
411
412 fpga->acqControl =
413 DAQBOARD2000_AcqResetScanListFifo |
414 DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe;
415
416
417
418 fpga->acqPacerClockDivLow = 1000000;
419 fpga->acqPacerClockDivHigh = 0;
420
421 gain = CR_RANGE(insn->chanspec);
422 chan = CR_CHAN(insn->chanspec);
423
424
425
426
427
428 for (i = 0; i < insn->n; i++) {
429 setup_sampling(dev, chan, gain);
430
431 fpga->acqControl = DAQBOARD2000_SeqStartScanList;
432 for (timeout = 0; timeout < 20; timeout++) {
433 if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull) {
434 break;
435 }
436
437 }
438 fpga->acqControl = DAQBOARD2000_AdcPacerEnable;
439 for (timeout = 0; timeout < 20; timeout++) {
440 if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning) {
441 break;
442 }
443
444 }
445 for (timeout = 0; timeout < 20; timeout++) {
446 if (fpga->acqControl &
447 DAQBOARD2000_AcqResultsFIFOHasValidData) {
448 break;
449 }
450
451 }
452 data[i] = fpga->acqResultsFIFO;
453 fpga->acqControl = DAQBOARD2000_AdcPacerDisable;
454 fpga->acqControl = DAQBOARD2000_SeqStopScanList;
455 }
456
457 return i;
458}
459
460static int daqboard2000_ao_insn_read(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 struct comedi_insn *insn,
463 unsigned int *data)
464{
465 int i;
466 int chan = CR_CHAN(insn->chanspec);
467
468 for (i = 0; i < insn->n; i++) {
469 data[i] = devpriv->ao_readback[chan];
470 }
471
472 return i;
473}
474
475static int daqboard2000_ao_insn_write(struct comedi_device *dev,
476 struct comedi_subdevice *s,
477 struct comedi_insn *insn,
478 unsigned int *data)
479{
480 int i;
481 int chan = CR_CHAN(insn->chanspec);
482 struct daqboard2000_hw *fpga = devpriv->daq;
483 int timeout;
484
485 for (i = 0; i < insn->n; i++) {
486
487
488
489
490
491 fpga->dacSetting[chan] = data[i];
492 for (timeout = 0; timeout < 20; timeout++) {
493 if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0) {
494 break;
495 }
496
497 }
498 devpriv->ao_readback[chan] = data[i];
499
500
501
502
503 }
504
505 return i;
506}
507
508static void daqboard2000_resetLocalBus(struct comedi_device *dev)
509{
510 printk("daqboard2000_resetLocalBus\n");
511 writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c);
512 udelay(10000);
513 writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c);
514 udelay(10000);
515}
516
517static void daqboard2000_reloadPLX(struct comedi_device *dev)
518{
519 printk("daqboard2000_reloadPLX\n");
520 writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
521 udelay(10000);
522 writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c);
523 udelay(10000);
524 writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
525 udelay(10000);
526}
527
528static void daqboard2000_pulseProgPin(struct comedi_device *dev)
529{
530 printk("daqboard2000_pulseProgPin 1\n");
531 writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c);
532 udelay(10000);
533 writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c);
534 udelay(10000);
535}
536
537static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask)
538{
539 int result = 0;
540 int i;
541 int cpld;
542
543
544 for (i = 0; i < 50; i++) {
545 cpld = readw(devpriv->daq + 0x1000);
546 if ((cpld & mask) == mask) {
547 result = 1;
548 break;
549 }
550 udelay(100);
551 }
552 udelay(5);
553 return result;
554}
555
556static int daqboard2000_writeCPLD(struct comedi_device *dev, int data)
557{
558 int result = 0;
559
560 udelay(10);
561 writew(data, devpriv->daq + 0x1000);
562 if ((readw(devpriv->daq + 0x1000) & DAQBOARD2000_CPLD_INIT) ==
563 DAQBOARD2000_CPLD_INIT) {
564 result = 1;
565 }
566 return result;
567}
568
569static int initialize_daqboard2000(struct comedi_device *dev,
570 unsigned char *cpld_array, int len)
571{
572 int result = -EIO;
573
574 int secr;
575 int retry;
576 int i;
577
578
579 secr = readl(devpriv->plx + 0x6c);
580 if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) {
581#ifdef DEBUG_EEPROM
582 printk("no serial eeprom\n");
583#endif
584 return -EIO;
585 }
586
587 for (retry = 0; retry < 3; retry++) {
588#ifdef DEBUG_EEPROM
589 printk("Programming EEPROM try %x\n", retry);
590#endif
591
592 daqboard2000_resetLocalBus(dev);
593 daqboard2000_reloadPLX(dev);
594 daqboard2000_pulseProgPin(dev);
595 if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) {
596 for (i = 0; i < len; i++) {
597 if (cpld_array[i] == 0xff
598 && cpld_array[i + 1] == 0x20) {
599#ifdef DEBUG_EEPROM
600 printk("Preamble found at %d\n", i);
601#endif
602 break;
603 }
604 }
605 for (; i < len; i += 2) {
606 int data =
607 (cpld_array[i] << 8) + cpld_array[i + 1];
608 if (!daqboard2000_writeCPLD(dev, data)) {
609 break;
610 }
611 }
612 if (i >= len) {
613#ifdef DEBUG_EEPROM
614 printk("Programmed\n");
615#endif
616 daqboard2000_resetLocalBus(dev);
617 daqboard2000_reloadPLX(dev);
618 result = 0;
619 break;
620 }
621 }
622 }
623 return result;
624}
625
626static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev)
627{
628
629}
630
631static void daqboard2000_adcDisarm(struct comedi_device *dev)
632{
633 struct daqboard2000_hw *fpga = devpriv->daq;
634
635
636 udelay(2);
637 fpga->trigControl = DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable;
638 udelay(2);
639 fpga->trigControl = DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable;
640
641
642 udelay(2);
643 fpga->acqControl = DAQBOARD2000_SeqStopScanList;
644
645
646 udelay(2);
647 fpga->acqControl = DAQBOARD2000_AdcPacerDisable;
648
649
650 daqboard2000_adcStopDmaTransfer(dev);
651}
652
653static void daqboard2000_activateReferenceDacs(struct comedi_device *dev)
654{
655 struct daqboard2000_hw *fpga = devpriv->daq;
656 int timeout;
657
658
659 fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect;
660 for (timeout = 0; timeout < 20; timeout++) {
661 if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) {
662 break;
663 }
664 udelay(2);
665 }
666
667
668
669 fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect;
670 for (timeout = 0; timeout < 20; timeout++) {
671 if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) {
672 break;
673 }
674 udelay(2);
675 }
676
677}
678
679static void daqboard2000_initializeCtrs(struct comedi_device *dev)
680{
681
682}
683
684static void daqboard2000_initializeTmrs(struct comedi_device *dev)
685{
686
687}
688
689static void daqboard2000_dacDisarm(struct comedi_device *dev)
690{
691
692}
693
694static void daqboard2000_initializeAdc(struct comedi_device *dev)
695{
696 daqboard2000_adcDisarm(dev);
697 daqboard2000_activateReferenceDacs(dev);
698 daqboard2000_initializeCtrs(dev);
699 daqboard2000_initializeTmrs(dev);
700}
701
702static void daqboard2000_initializeDac(struct comedi_device *dev)
703{
704 daqboard2000_dacDisarm(dev);
705}
706
707
708
709
710
711
712
713static int daqboard2000_8255_cb(int dir, int port, int data,
714 unsigned long ioaddr)
715{
716 int result = 0;
717 if (dir) {
718 writew(data, ((void *)ioaddr) + port * 2);
719 result = 0;
720 } else {
721 result = readw(((void *)ioaddr) + port * 2);
722 }
723
724
725
726
727 return result;
728}
729
730static int daqboard2000_attach(struct comedi_device *dev,
731 struct comedi_devconfig *it)
732{
733 int result = 0;
734 struct comedi_subdevice *s;
735 struct pci_dev *card = NULL;
736 void *aux_data;
737 unsigned int aux_len;
738 int bus, slot;
739
740 printk("comedi%d: daqboard2000:", dev->minor);
741
742 bus = it->options[0];
743 slot = it->options[1];
744
745 result = alloc_private(dev, sizeof(struct daqboard2000_private));
746 if (result < 0) {
747 return -ENOMEM;
748 }
749 for (card = pci_get_device(0x1616, 0x0409, NULL);
750 card != NULL; card = pci_get_device(0x1616, 0x0409, card)) {
751 if (bus || slot) {
752
753 if (card->bus->number != bus ||
754 PCI_SLOT(card->devfn) != slot) {
755 continue;
756 }
757 }
758 break;
759 }
760 if (!card) {
761 if (bus || slot)
762 printk(" no daqboard2000 found at bus/slot: %d/%d\n",
763 bus, slot);
764 else
765 printk(" no daqboard2000 found\n");
766 return -EIO;
767 } else {
768 u32 id;
769 int i;
770 devpriv->pci_dev = card;
771 id = ((u32) card->
772 subsystem_device << 16) | card->subsystem_vendor;
773 for (i = 0; i < n_boardtypes; i++) {
774 if (boardtypes[i].id == id) {
775 printk(" %s", boardtypes[i].name);
776 dev->board_ptr = boardtypes + i;
777 }
778 }
779 if (!dev->board_ptr) {
780 printk
781 (" unknown subsystem id %08x (pretend it is an ids2)",
782 id);
783 dev->board_ptr = boardtypes;
784 }
785 }
786
787 result = comedi_pci_enable(card, "daqboard2000");
788 if (result < 0) {
789 printk(" failed to enable PCI device and request regions\n");
790 return -EIO;
791 }
792 devpriv->got_regions = 1;
793 devpriv->plx =
794 ioremap(pci_resource_start(card, 0), DAQBOARD2000_PLX_SIZE);
795 devpriv->daq =
796 ioremap(pci_resource_start(card, 2), DAQBOARD2000_DAQ_SIZE);
797 if (!devpriv->plx || !devpriv->daq) {
798 return -ENOMEM;
799 }
800
801 result = alloc_subdevices(dev, 3);
802 if (result < 0)
803 goto out;
804
805 readl(devpriv->plx + 0x6c);
806
807
808
809
810
811
812
813
814 aux_data = comedi_aux_data(it->options, 0);
815 aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
816
817 if (aux_data && aux_len) {
818 result = initialize_daqboard2000(dev, aux_data, aux_len);
819 } else {
820 printk("no FPGA initialization code, aborting\n");
821 result = -EIO;
822 }
823 if (result < 0)
824 goto out;
825 daqboard2000_initializeAdc(dev);
826 daqboard2000_initializeDac(dev);
827
828
829
830
831
832
833 dev->iobase = (unsigned long)devpriv->daq;
834
835 dev->board_name = this_board->name;
836
837 s = dev->subdevices + 0;
838
839 s->type = COMEDI_SUBD_AI;
840 s->subdev_flags = SDF_READABLE | SDF_GROUND;
841 s->n_chan = 24;
842 s->maxdata = 0xffff;
843 s->insn_read = daqboard2000_ai_insn_read;
844 s->range_table = &range_daqboard2000_ai;
845
846 s = dev->subdevices + 1;
847
848 s->type = COMEDI_SUBD_AO;
849 s->subdev_flags = SDF_WRITABLE;
850 s->n_chan = 2;
851 s->maxdata = 0xffff;
852 s->insn_read = daqboard2000_ao_insn_read;
853 s->insn_write = daqboard2000_ao_insn_write;
854 s->range_table = &range_daqboard2000_ao;
855
856 s = dev->subdevices + 2;
857 result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
858 (unsigned long)(dev->iobase + 0x40));
859
860 printk("\n");
861out:
862 return result;
863}
864
865static int daqboard2000_detach(struct comedi_device *dev)
866{
867 printk("comedi%d: daqboard2000: remove\n", dev->minor);
868
869 if (dev->subdevices)
870 subdev_8255_cleanup(dev, dev->subdevices + 2);
871
872 if (dev->irq) {
873 free_irq(dev->irq, dev);
874 }
875 if (devpriv) {
876 if (devpriv->daq)
877 iounmap(devpriv->daq);
878 if (devpriv->plx)
879 iounmap(devpriv->plx);
880 if (devpriv->pci_dev) {
881 if (devpriv->got_regions) {
882 comedi_pci_disable(devpriv->pci_dev);
883 }
884 pci_dev_put(devpriv->pci_dev);
885 }
886 }
887 return 0;
888}
889
890COMEDI_PCI_INITCLEANUP(driver_daqboard2000, daqboard2000_pci_table);
891