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