Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/staging/comedi/drivers/daqboard2000.c

  1 /*
  2    comedi/drivers/daqboard2000.c
  3    hardware driver for IOtech DAQboard/2000
  4 
  5    COMEDI - Linux Control and Measurement Device Interface
  6    Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
  7 
  8    This program is free software; you can redistribute it and/or modify
  9    it under the terms of the GNU General Public License as published by
 10    the Free Software Foundation; either version 2 of the License, or
 11    (at your option) any later version.
 12 
 13    This program is distributed in the hope that it will be useful,
 14    but WITHOUT ANY WARRANTY; without even the implied warranty of
 15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16    GNU General Public License for more details.
 17  */
 18 /*
 19 Driver: daqboard2000
 20 Description: IOTech DAQBoard/2000
 21 Author: Anders Blomdell <anders.blomdell@control.lth.se>
 22 Status: works
 23 Updated: Mon, 14 Apr 2008 15:28:52 +0100
 24 Devices: [IOTech] DAQBoard/2000 (daqboard2000)
 25 
 26 Much of the functionality of this driver was determined from reading
 27 the source code for the Windows driver.
 28 
 29 The FPGA on the board requires fimware, which is available from
 30 http://www.comedi.org in the comedi_nonfree_firmware tarball.
 31 
 32 Configuration options: not applicable, uses PCI auto config
 33 */
 34 /*
 35    This card was obviously never intended to leave the Windows world,
 36    since it lacked all kind of hardware documentation (except for cable
 37    pinouts, plug and pray has something to catch up with yet).
 38 
 39    With some help from our swedish distributor, we got the Windows sourcecode
 40    for the card, and here are the findings so far.
 41 
 42    1. A good document that describes the PCI interface chip is 9080db-106.pdf
 43       available from http://www.plxtech.com/products/io/pci9080 
 44 
 45    2. The initialization done so far is:
 46         a. program the FPGA (windows code sans a lot of error messages)
 47         b.
 48 
 49    3. Analog out seems to work OK with DAC's disabled, if DAC's are enabled,
 50       you have to output values to all enabled DAC's until result appears, I
 51       guess that it has something to do with pacer clocks, but the source
 52       gives me no clues. I'll keep it simple so far.
 53 
 54    4. Analog in.
 55         Each channel in the scanlist seems to be controlled by four
 56         control words:
 57 
 58         Word0:
 59           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 60           ! | | | ! | | | ! | | | ! | | | !
 61           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 62 
 63         Word1:
 64           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 65           ! | | | ! | | | ! | | | ! | | | !
 66           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 67            |             |       | | | | |
 68            +------+------+       | | | | +-- Digital input (??)
 69                   |              | | | +---- 10 us settling time
 70                   |              | | +------ Suspend acquisition (last to scan)
 71                   |              | +-------- Simultaneous sample and hold
 72                   |              +---------- Signed data format
 73                   +------------------------- Correction offset low
 74 
 75         Word2:
 76           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 77           ! | | | ! | | | ! | | | ! | | | !
 78           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 79            |     | |     | | | | | |     |
 80            +-----+ +--+--+ +++ +++ +--+--+
 81               |       |     |   |     +----- Expansion channel
 82               |       |     |   +----------- Expansion gain
 83               |       |     +--------------- Channel (low)
 84               |       +--------------------- Correction offset high
 85               +----------------------------- Correction gain low
 86         Word3:
 87           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 88           ! | | | ! | | | ! | | | ! | | | !
 89           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 90            |             | | | |   | | | |
 91            +------+------+ | | +-+-+ | | +-- Low bank enable
 92                   |        | |   |   | +---- High bank enable
 93                   |        | |   |   +------ Hi/low select
 94                   |        | |   +---------- Gain (1,?,2,4,8,16,32,64)
 95                   |        | +-------------- differential/single ended
 96                   |        +---------------- Unipolar
 97                   +------------------------- Correction gain high
 98 
 99    999. The card seems to have an incredible amount of capabilities, but
100         trying to reverse engineer them from the Windows source is beyond my
101         patience.
102 
103  */
104 
105 #include <linux/module.h>
106 #include <linux/pci.h>
107 #include <linux/delay.h>
108 #include <linux/interrupt.h>
109 
110 #include "../comedidev.h"
111 
112 #include "8255.h"
113 
114 #define DAQBOARD2000_FIRMWARE           "daqboard2000_firmware.bin"
115 
116 #define DAQBOARD2000_SUBSYSTEM_IDS2     0x0002  /* Daqboard/2000 - 2 Dacs */
117 #define DAQBOARD2000_SUBSYSTEM_IDS4     0x0004  /* Daqboard/2000 - 4 Dacs */
118 
119 /* Initialization bits for the Serial EEPROM Control Register */
120 #define DAQBOARD2000_SECRProgPinHi      0x8001767e
121 #define DAQBOARD2000_SECRProgPinLo      0x8000767e
122 #define DAQBOARD2000_SECRLocalBusHi     0xc000767e
123 #define DAQBOARD2000_SECRLocalBusLo     0x8000767e
124 #define DAQBOARD2000_SECRReloadHi       0xa000767e
125 #define DAQBOARD2000_SECRReloadLo       0x8000767e
126 
127 /* SECR status bits */
128 #define DAQBOARD2000_EEPROM_PRESENT     0x10000000
129 
130 /* CPLD status bits */
131 #define DAQBOARD2000_CPLD_INIT          0x0002
132 #define DAQBOARD2000_CPLD_DONE          0x0004
133 
134 static const struct comedi_lrange range_daqboard2000_ai = {
135         13, {
136                 BIP_RANGE(10),
137                 BIP_RANGE(5),
138                 BIP_RANGE(2.5),
139                 BIP_RANGE(1.25),
140                 BIP_RANGE(0.625),
141                 BIP_RANGE(0.3125),
142                 BIP_RANGE(0.156),
143                 UNI_RANGE(10),
144                 UNI_RANGE(5),
145                 UNI_RANGE(2.5),
146                 UNI_RANGE(1.25),
147                 UNI_RANGE(0.625),
148                 UNI_RANGE(0.3125)
149         }
150 };
151 
152 /*
153  * Register Memory Map
154  */
155 #define acqControl                      0x00            /* u16 */
156 #define acqScanListFIFO                 0x02            /* u16 */
157 #define acqPacerClockDivLow             0x04            /* u32 */
158 #define acqScanCounter                  0x08            /* u16 */
159 #define acqPacerClockDivHigh            0x0a            /* u16 */
160 #define acqTriggerCount                 0x0c            /* u16 */
161 #define acqResultsFIFO                  0x10            /* u16 */
162 #define acqResultsShadow                0x14            /* u16 */
163 #define acqAdcResult                    0x18            /* u16 */
164 #define dacScanCounter                  0x1c            /* u16 */
165 #define dacControl                      0x20            /* u16 */
166 #define dacFIFO                         0x24            /* s16 */
167 #define dacPacerClockDiv                0x2a            /* u16 */
168 #define refDacs                         0x2c            /* u16 */
169 #define dioControl                      0x30            /* u16 */
170 #define dioP3hsioData                   0x32            /* s16 */
171 #define dioP3Control                    0x34            /* u16 */
172 #define calEepromControl                0x36            /* u16 */
173 #define dacSetting(x)                   (0x38 + (x)*2)  /* s16 */
174 #define dioP2ExpansionIO8Bit            0x40            /* s16 */
175 #define ctrTmrControl                   0x80            /* u16 */
176 #define ctrInput(x)                     (0x88 + (x)*2)  /* s16 */
177 #define timerDivisor(x)                 (0xa0 + (x)*2)  /* u16 */
178 #define dmaControl                      0xb0            /* u16 */
179 #define trigControl                     0xb2            /* u16 */
180 #define calEeprom                       0xb8            /* u16 */
181 #define acqDigitalMark                  0xba            /* u16 */
182 #define trigDacs                        0xbc            /* u16 */
183 #define dioP2ExpansionIO16Bit(x)        (0xc0 + (x)*2)  /* s16 */
184 
185 /* Scan Sequencer programming */
186 #define DAQBOARD2000_SeqStartScanList            0x0011
187 #define DAQBOARD2000_SeqStopScanList             0x0010
188 
189 /* Prepare for acquisition */
190 #define DAQBOARD2000_AcqResetScanListFifo        0x0004
191 #define DAQBOARD2000_AcqResetResultsFifo         0x0002
192 #define DAQBOARD2000_AcqResetConfigPipe          0x0001
193 
194 /* Acqusition status bits */
195 #define DAQBOARD2000_AcqResultsFIFOMore1Sample   0x0001
196 #define DAQBOARD2000_AcqResultsFIFOHasValidData  0x0002
197 #define DAQBOARD2000_AcqResultsFIFOOverrun       0x0004
198 #define DAQBOARD2000_AcqLogicScanning            0x0008
199 #define DAQBOARD2000_AcqConfigPipeFull           0x0010
200 #define DAQBOARD2000_AcqScanListFIFOEmpty        0x0020
201 #define DAQBOARD2000_AcqAdcNotReady              0x0040
202 #define DAQBOARD2000_ArbitrationFailure          0x0080
203 #define DAQBOARD2000_AcqPacerOverrun             0x0100
204 #define DAQBOARD2000_DacPacerOverrun             0x0200
205 #define DAQBOARD2000_AcqHardwareError            0x01c0
206 
207 /* Scan Sequencer programming */
208 #define DAQBOARD2000_SeqStartScanList            0x0011
209 #define DAQBOARD2000_SeqStopScanList             0x0010
210 
211 /* Pacer Clock Control */
212 #define DAQBOARD2000_AdcPacerInternal            0x0030
213 #define DAQBOARD2000_AdcPacerExternal            0x0032
214 #define DAQBOARD2000_AdcPacerEnable              0x0031
215 #define DAQBOARD2000_AdcPacerEnableDacPacer      0x0034
216 #define DAQBOARD2000_AdcPacerDisable             0x0030
217 #define DAQBOARD2000_AdcPacerNormalMode          0x0060
218 #define DAQBOARD2000_AdcPacerCompatibilityMode   0x0061
219 #define DAQBOARD2000_AdcPacerInternalOutEnable   0x0008
220 #define DAQBOARD2000_AdcPacerExternalRising      0x0100
221 
222 /* DAC status */
223 #define DAQBOARD2000_DacFull                     0x0001
224 #define DAQBOARD2000_RefBusy                     0x0002
225 #define DAQBOARD2000_TrgBusy                     0x0004
226 #define DAQBOARD2000_CalBusy                     0x0008
227 #define DAQBOARD2000_Dac0Busy                    0x0010
228 #define DAQBOARD2000_Dac1Busy                    0x0020
229 #define DAQBOARD2000_Dac2Busy                    0x0040
230 #define DAQBOARD2000_Dac3Busy                    0x0080
231 
232 /* DAC control */
233 #define DAQBOARD2000_Dac0Enable                  0x0021
234 #define DAQBOARD2000_Dac1Enable                  0x0031
235 #define DAQBOARD2000_Dac2Enable                  0x0041
236 #define DAQBOARD2000_Dac3Enable                  0x0051
237 #define DAQBOARD2000_DacEnableBit                0x0001
238 #define DAQBOARD2000_Dac0Disable                 0x0020
239 #define DAQBOARD2000_Dac1Disable                 0x0030
240 #define DAQBOARD2000_Dac2Disable                 0x0040
241 #define DAQBOARD2000_Dac3Disable                 0x0050
242 #define DAQBOARD2000_DacResetFifo                0x0004
243 #define DAQBOARD2000_DacPatternDisable           0x0060
244 #define DAQBOARD2000_DacPatternEnable            0x0061
245 #define DAQBOARD2000_DacSelectSignedData         0x0002
246 #define DAQBOARD2000_DacSelectUnsignedData       0x0000
247 
248 /* Trigger Control */
249 #define DAQBOARD2000_TrigAnalog                  0x0000
250 #define DAQBOARD2000_TrigTTL                     0x0010
251 #define DAQBOARD2000_TrigTransHiLo               0x0004
252 #define DAQBOARD2000_TrigTransLoHi               0x0000
253 #define DAQBOARD2000_TrigAbove                   0x0000
254 #define DAQBOARD2000_TrigBelow                   0x0004
255 #define DAQBOARD2000_TrigLevelSense              0x0002
256 #define DAQBOARD2000_TrigEdgeSense               0x0000
257 #define DAQBOARD2000_TrigEnable                  0x0001
258 #define DAQBOARD2000_TrigDisable                 0x0000
259 
260 /* Reference Dac Selection */
261 #define DAQBOARD2000_PosRefDacSelect             0x0100
262 #define DAQBOARD2000_NegRefDacSelect             0x0000
263 
264 struct daq200_boardtype {
265         const char *name;
266         int id;
267 };
268 static const struct daq200_boardtype boardtypes[] = {
269         {"ids2", DAQBOARD2000_SUBSYSTEM_IDS2},
270         {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
271 };
272 
273 struct daqboard2000_private {
274         enum {
275                 card_daqboard_2000
276         } card;
277         void __iomem *daq;
278         void __iomem *plx;
279         unsigned int ao_readback[2];
280 };
281 
282 static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry)
283 {
284         struct daqboard2000_private *devpriv = dev->private;
285 
286         /* udelay(4); */
287         writew(entry & 0x00ff, devpriv->daq + acqScanListFIFO);
288         /* udelay(4); */
289         writew((entry >> 8) & 0x00ff, devpriv->daq + acqScanListFIFO);
290 }
291 
292 static void setup_sampling(struct comedi_device *dev, int chan, int gain)
293 {
294         u16 word0, word1, word2, word3;
295 
296         /* Channel 0-7 diff, channel 8-23 single ended */
297         word0 = 0;
298         word1 = 0x0004;         /* Last scan */
299         word2 = (chan << 6) & 0x00c0;
300         switch (chan / 4) {
301         case 0:
302                 word3 = 0x0001;
303                 break;
304         case 1:
305                 word3 = 0x0002;
306                 break;
307         case 2:
308                 word3 = 0x0005;
309                 break;
310         case 3:
311                 word3 = 0x0006;
312                 break;
313         case 4:
314                 word3 = 0x0041;
315                 break;
316         case 5:
317                 word3 = 0x0042;
318                 break;
319         default:
320                 word3 = 0;
321                 break;
322         }
323 /*
324   dev->eeprom.correctionDACSE[i][j][k].offset = 0x800;
325   dev->eeprom.correctionDACSE[i][j][k].gain = 0xc00;
326 */
327         /* These should be read from EEPROM */
328         word2 |= 0x0800;
329         word3 |= 0xc000;
330         writeAcqScanListEntry(dev, word0);
331         writeAcqScanListEntry(dev, word1);
332         writeAcqScanListEntry(dev, word2);
333         writeAcqScanListEntry(dev, word3);
334 }
335 
336 static int daqboard2000_ai_status(struct comedi_device *dev,
337                                   struct comedi_subdevice *s,
338                                   struct comedi_insn *insn,
339                                   unsigned long context)
340 {
341         struct daqboard2000_private *devpriv = dev->private;
342         unsigned int status;
343 
344         status = readw(devpriv->daq + acqControl);
345         if (status & context)
346                 return 0;
347         return -EBUSY;
348 }
349 
350 static int daqboard2000_ai_insn_read(struct comedi_device *dev,
351                                      struct comedi_subdevice *s,
352                                      struct comedi_insn *insn,
353                                      unsigned int *data)
354 {
355         struct daqboard2000_private *devpriv = dev->private;
356         int gain, chan;
357         int ret;
358         int i;
359 
360         writew(DAQBOARD2000_AcqResetScanListFifo |
361                DAQBOARD2000_AcqResetResultsFifo |
362                DAQBOARD2000_AcqResetConfigPipe, devpriv->daq + acqControl);
363 
364         /*
365          * If pacer clock is not set to some high value (> 10 us), we
366          * risk multiple samples to be put into the result FIFO.
367          */
368         /* 1 second, should be long enough */
369         writel(1000000, devpriv->daq + acqPacerClockDivLow);
370         writew(0, devpriv->daq + acqPacerClockDivHigh);
371 
372         gain = CR_RANGE(insn->chanspec);
373         chan = CR_CHAN(insn->chanspec);
374 
375         /* This doesn't look efficient.  I decided to take the conservative
376          * approach when I did the insn conversion.  Perhaps it would be
377          * better to have broken it completely, then someone would have been
378          * forced to fix it.  --ds */
379         for (i = 0; i < insn->n; i++) {
380                 setup_sampling(dev, chan, gain);
381                 /* Enable reading from the scanlist FIFO */
382                 writew(DAQBOARD2000_SeqStartScanList,
383                        devpriv->daq + acqControl);
384 
385                 ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
386                                      DAQBOARD2000_AcqConfigPipeFull);
387                 if (ret)
388                         return ret;
389 
390                 writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl);
391 
392                 ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
393                                      DAQBOARD2000_AcqLogicScanning);
394                 if (ret)
395                         return ret;
396 
397                 ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
398                                      DAQBOARD2000_AcqResultsFIFOHasValidData);
399                 if (ret)
400                         return ret;
401 
402                 data[i] = readw(devpriv->daq + acqResultsFIFO);
403                 writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
404                 writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
405         }
406 
407         return i;
408 }
409 
410 static int daqboard2000_ao_insn_read(struct comedi_device *dev,
411                                      struct comedi_subdevice *s,
412                                      struct comedi_insn *insn,
413                                      unsigned int *data)
414 {
415         struct daqboard2000_private *devpriv = dev->private;
416         int chan = CR_CHAN(insn->chanspec);
417         int i;
418 
419         for (i = 0; i < insn->n; i++)
420                 data[i] = devpriv->ao_readback[chan];
421 
422         return i;
423 }
424 
425 static int daqboard2000_ao_eoc(struct comedi_device *dev,
426                                struct comedi_subdevice *s,
427                                struct comedi_insn *insn,
428                                unsigned long context)
429 {
430         struct daqboard2000_private *devpriv = dev->private;
431         unsigned int chan = CR_CHAN(insn->chanspec);
432         unsigned int status;
433 
434         status = readw(devpriv->daq + dacControl);
435         if ((status & ((chan + 1) * 0x0010)) == 0)
436                 return 0;
437         return -EBUSY;
438 }
439 
440 static int daqboard2000_ao_insn_write(struct comedi_device *dev,
441                                       struct comedi_subdevice *s,
442                                       struct comedi_insn *insn,
443                                       unsigned int *data)
444 {
445         struct daqboard2000_private *devpriv = dev->private;
446         int chan = CR_CHAN(insn->chanspec);
447         int ret;
448         int i;
449 
450         for (i = 0; i < insn->n; i++) {
451 #if 0
452                 /*
453                  * OK, since it works OK without enabling the DAC's,
454                  * let's keep it as simple as possible...
455                  */
456                 writew((chan + 2) * 0x0010 | 0x0001,
457                        devpriv->daq + dacControl);
458                 udelay(1000);
459 #endif
460                 writew(data[i], devpriv->daq + dacSetting(chan));
461 
462                 ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0);
463                 if (ret)
464                         return ret;
465 
466                 devpriv->ao_readback[chan] = data[i];
467 #if 0
468                 /*
469                  * Since we never enabled the DAC's, we don't need
470                  * to disable it...
471                  */
472                 writew((chan + 2) * 0x0010 | 0x0000,
473                        devpriv->daq + dacControl);
474                 udelay(1000);
475 #endif
476         }
477 
478         return i;
479 }
480 
481 static void daqboard2000_resetLocalBus(struct comedi_device *dev)
482 {
483         struct daqboard2000_private *devpriv = dev->private;
484 
485         writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c);
486         mdelay(10);
487         writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c);
488         mdelay(10);
489 }
490 
491 static void daqboard2000_reloadPLX(struct comedi_device *dev)
492 {
493         struct daqboard2000_private *devpriv = dev->private;
494 
495         writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
496         mdelay(10);
497         writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c);
498         mdelay(10);
499         writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
500         mdelay(10);
501 }
502 
503 static void daqboard2000_pulseProgPin(struct comedi_device *dev)
504 {
505         struct daqboard2000_private *devpriv = dev->private;
506 
507         writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c);
508         mdelay(10);
509         writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c);
510         mdelay(10);     /* Not in the original code, but I like symmetry... */
511 }
512 
513 static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask)
514 {
515         struct daqboard2000_private *devpriv = dev->private;
516         int result = 0;
517         int i;
518         int cpld;
519 
520         /* timeout after 50 tries -> 5ms */
521         for (i = 0; i < 50; i++) {
522                 cpld = readw(devpriv->daq + 0x1000);
523                 if ((cpld & mask) == mask) {
524                         result = 1;
525                         break;
526                 }
527                 udelay(100);
528         }
529         udelay(5);
530         return result;
531 }
532 
533 static int daqboard2000_writeCPLD(struct comedi_device *dev, int data)
534 {
535         struct daqboard2000_private *devpriv = dev->private;
536         int result = 0;
537 
538         udelay(10);
539         writew(data, devpriv->daq + 0x1000);
540         if ((readw(devpriv->daq + 0x1000) & DAQBOARD2000_CPLD_INIT) ==
541             DAQBOARD2000_CPLD_INIT) {
542                 result = 1;
543         }
544         return result;
545 }
546 
547 static int initialize_daqboard2000(struct comedi_device *dev,
548                                    const u8 *cpld_array, size_t len,
549                                    unsigned long context)
550 {
551         struct daqboard2000_private *devpriv = dev->private;
552         int result = -EIO;
553         /* Read the serial EEPROM control register */
554         int secr;
555         int retry;
556         size_t i;
557 
558         /* Check to make sure the serial eeprom is present on the board */
559         secr = readl(devpriv->plx + 0x6c);
560         if (!(secr & DAQBOARD2000_EEPROM_PRESENT))
561                 return -EIO;
562 
563         for (retry = 0; retry < 3; retry++) {
564                 daqboard2000_resetLocalBus(dev);
565                 daqboard2000_reloadPLX(dev);
566                 daqboard2000_pulseProgPin(dev);
567                 if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) {
568                         for (i = 0; i < len; i++) {
569                                 if (cpld_array[i] == 0xff &&
570                                     cpld_array[i + 1] == 0x20)
571                                         break;
572                         }
573                         for (; i < len; i += 2) {
574                                 int data =
575                                     (cpld_array[i] << 8) + cpld_array[i + 1];
576                                 if (!daqboard2000_writeCPLD(dev, data))
577                                         break;
578                         }
579                         if (i >= len) {
580                                 daqboard2000_resetLocalBus(dev);
581                                 daqboard2000_reloadPLX(dev);
582                                 result = 0;
583                                 break;
584                         }
585                 }
586         }
587         return result;
588 }
589 
590 static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev)
591 {
592 }
593 
594 static void daqboard2000_adcDisarm(struct comedi_device *dev)
595 {
596         struct daqboard2000_private *devpriv = dev->private;
597 
598         /* Disable hardware triggers */
599         udelay(2);
600         writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable,
601                devpriv->daq + trigControl);
602         udelay(2);
603         writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable,
604                devpriv->daq + trigControl);
605 
606         /* Stop the scan list FIFO from loading the configuration pipe */
607         udelay(2);
608         writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
609 
610         /* Stop the pacer clock */
611         udelay(2);
612         writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
613 
614         /* Stop the input dma (abort channel 1) */
615         daqboard2000_adcStopDmaTransfer(dev);
616 }
617 
618 static void daqboard2000_activateReferenceDacs(struct comedi_device *dev)
619 {
620         struct daqboard2000_private *devpriv = dev->private;
621         unsigned int val;
622         int timeout;
623 
624         /*  Set the + reference dac value in the FPGA */
625         writew(0x80 | DAQBOARD2000_PosRefDacSelect, devpriv->daq + refDacs);
626         for (timeout = 0; timeout < 20; timeout++) {
627                 val = readw(devpriv->daq + dacControl);
628                 if ((val & DAQBOARD2000_RefBusy) == 0)
629                         break;
630                 udelay(2);
631         }
632 
633         /*  Set the - reference dac value in the FPGA */
634         writew(0x80 | DAQBOARD2000_NegRefDacSelect, devpriv->daq + refDacs);
635         for (timeout = 0; timeout < 20; timeout++) {
636                 val = readw(devpriv->daq + dacControl);
637                 if ((val & DAQBOARD2000_RefBusy) == 0)
638                         break;
639                 udelay(2);
640         }
641 }
642 
643 static void daqboard2000_initializeCtrs(struct comedi_device *dev)
644 {
645 }
646 
647 static void daqboard2000_initializeTmrs(struct comedi_device *dev)
648 {
649 }
650 
651 static void daqboard2000_dacDisarm(struct comedi_device *dev)
652 {
653 }
654 
655 static void daqboard2000_initializeAdc(struct comedi_device *dev)
656 {
657         daqboard2000_adcDisarm(dev);
658         daqboard2000_activateReferenceDacs(dev);
659         daqboard2000_initializeCtrs(dev);
660         daqboard2000_initializeTmrs(dev);
661 }
662 
663 static void daqboard2000_initializeDac(struct comedi_device *dev)
664 {
665         daqboard2000_dacDisarm(dev);
666 }
667 
668 static int daqboard2000_8255_cb(int dir, int port, int data,
669                                 unsigned long ioaddr)
670 {
671         void __iomem *mmio_base = (void __iomem *)ioaddr;
672 
673         if (dir) {
674                 writew(data, mmio_base + port * 2);
675                 return 0;
676         } else {
677                 return readw(mmio_base + port * 2);
678         }
679 }
680 
681 static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
682                                                struct pci_dev *pcidev)
683 {
684         const struct daq200_boardtype *board;
685         int i;
686 
687         if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
688                 return NULL;
689 
690         for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
691                 board = &boardtypes[i];
692                 if (pcidev->subsystem_device == board->id)
693                         return board;
694         }
695         return NULL;
696 }
697 
698 static int daqboard2000_auto_attach(struct comedi_device *dev,
699                                               unsigned long context_unused)
700 {
701         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
702         const struct daq200_boardtype *board;
703         struct daqboard2000_private *devpriv;
704         struct comedi_subdevice *s;
705         int result;
706 
707         board = daqboard2000_find_boardinfo(dev, pcidev);
708         if (!board)
709                 return -ENODEV;
710         dev->board_ptr = board;
711         dev->board_name = board->name;
712 
713         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
714         if (!devpriv)
715                 return -ENOMEM;
716 
717         result = comedi_pci_enable(dev);
718         if (result)
719                 return result;
720 
721         devpriv->plx = pci_ioremap_bar(pcidev, 0);
722         devpriv->daq = pci_ioremap_bar(pcidev, 2);
723         if (!devpriv->plx || !devpriv->daq)
724                 return -ENOMEM;
725 
726         result = comedi_alloc_subdevices(dev, 3);
727         if (result)
728                 return result;
729 
730         readl(devpriv->plx + 0x6c);
731 
732         result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
733                                       DAQBOARD2000_FIRMWARE,
734                                       initialize_daqboard2000, 0);
735         if (result < 0)
736                 return result;
737 
738         daqboard2000_initializeAdc(dev);
739         daqboard2000_initializeDac(dev);
740 
741         s = &dev->subdevices[0];
742         /* ai subdevice */
743         s->type = COMEDI_SUBD_AI;
744         s->subdev_flags = SDF_READABLE | SDF_GROUND;
745         s->n_chan = 24;
746         s->maxdata = 0xffff;
747         s->insn_read = daqboard2000_ai_insn_read;
748         s->range_table = &range_daqboard2000_ai;
749 
750         s = &dev->subdevices[1];
751         /* ao subdevice */
752         s->type = COMEDI_SUBD_AO;
753         s->subdev_flags = SDF_WRITABLE;
754         s->n_chan = 2;
755         s->maxdata = 0xffff;
756         s->insn_read = daqboard2000_ao_insn_read;
757         s->insn_write = daqboard2000_ao_insn_write;
758         s->range_table = &range_bipolar10;
759 
760         s = &dev->subdevices[2];
761         result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
762                         (unsigned long)(devpriv->daq + dioP2ExpansionIO8Bit));
763         if (result)
764                 return result;
765 
766         return 0;
767 }
768 
769 static void daqboard2000_detach(struct comedi_device *dev)
770 {
771         struct daqboard2000_private *devpriv = dev->private;
772 
773         if (dev->irq)
774                 free_irq(dev->irq, dev);
775         if (devpriv) {
776                 if (devpriv->daq)
777                         iounmap(devpriv->daq);
778                 if (devpriv->plx)
779                         iounmap(devpriv->plx);
780         }
781         comedi_pci_disable(dev);
782 }
783 
784 static struct comedi_driver daqboard2000_driver = {
785         .driver_name    = "daqboard2000",
786         .module         = THIS_MODULE,
787         .auto_attach    = daqboard2000_auto_attach,
788         .detach         = daqboard2000_detach,
789 };
790 
791 static int daqboard2000_pci_probe(struct pci_dev *dev,
792                                   const struct pci_device_id *id)
793 {
794         return comedi_pci_auto_config(dev, &daqboard2000_driver,
795                                       id->driver_data);
796 }
797 
798 static const struct pci_device_id daqboard2000_pci_table[] = {
799         { PCI_DEVICE(PCI_VENDOR_ID_IOTECH, 0x0409) },
800         { 0 }
801 };
802 MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
803 
804 static struct pci_driver daqboard2000_pci_driver = {
805         .name           = "daqboard2000",
806         .id_table       = daqboard2000_pci_table,
807         .probe          = daqboard2000_pci_probe,
808         .remove         = comedi_pci_auto_unconfig,
809 };
810 module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver);
811 
812 MODULE_AUTHOR("Comedi http://www.comedi.org");
813 MODULE_DESCRIPTION("Comedi low-level driver");
814 MODULE_LICENSE("GPL");
815 MODULE_FIRMWARE(DAQBOARD2000_FIRMWARE);
816 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us