Merge 3.9-rc5 into staging-next
[deliverable/linux.git] / drivers / staging / comedi / drivers / cb_pcidas.c
CommitLineData
59c7dd3d
IM
1/*
2 comedi/drivers/cb_pcidas.c
3
4 Developed by Ivan Martinez and Frank Mori Hess, with valuable help from
5 David Schleef and the rest of the Comedi developers comunity.
6
7 Copyright (C) 2001-2003 Ivan Martinez <imr@oersted.dtu.dk>
8 Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
9
10 COMEDI - Linux Control and Measurement Device Interface
11 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27************************************************************************
28*/
29/*
30Driver: cb_pcidas
d478b5f6
HS
31Description: MeasurementComputing PCI-DAS series
32 with the AMCC S5933 PCI controller
59c7dd3d
IM
33Author: Ivan Martinez <imr@oersted.dtu.dk>,
34 Frank Mori Hess <fmhess@users.sourceforge.net>
35Updated: 2003-3-11
36Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas),
37 PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr,
38 PCI-DAS1000, PCI-DAS1001, PCI_DAS1002
39
40Status:
41 There are many reports of the driver being used with most of the
42 supported cards. Despite no detailed log is maintained, it can
43 be said that the driver is quite tested and stable.
44
45 The boards may be autocalibrated using the comedi_calibrate
46 utility.
47
3b96f250 48Configuration options: not applicable, uses PCI auto config
59c7dd3d
IM
49
50For commands, the scanned channels must be consecutive
51(i.e. 4-5-6-7, 2-3-4,...), and must all have the same
52range and aref.
f1bc4343
BD
53
54AI Triggering:
55 For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used.
56 For 1602 series, the start_arg is interpreted as follows:
bc04bec0
MI
57 start_arg == 0 => gated trigger (level high)
58 start_arg == CR_INVERT => gated trigger (level low)
f1bc4343
BD
59 start_arg == CR_EDGE => Rising edge
60 start_arg == CR_EDGE | CR_INVERT => Falling edge
61 For the other boards the trigger will be done on rising edge
59c7dd3d
IM
62*/
63/*
64
65TODO:
66
67analog triggering on 1602 series
68*/
69
33782dd5 70#include <linux/pci.h>
59c7dd3d 71#include <linux/delay.h>
70265d24 72#include <linux/interrupt.h>
59c7dd3d 73
33782dd5
HS
74#include "../comedidev.h"
75
59c7dd3d
IM
76#include "8253.h"
77#include "8255.h"
78#include "amcc_s5933.h"
59c7dd3d
IM
79#include "comedi_fc.h"
80
6993197b
HS
81#define TIMER_BASE 100 /* 10MHz master clock */
82#define AI_BUFFER_SIZE 1024 /* max ai fifo size */
83#define AO_BUFFER_SIZE 1024 /* max ao fifo size */
84#define NUM_CHANNELS_8800 8
85#define NUM_CHANNELS_7376 1
86#define NUM_CHANNELS_8402 2
87#define NUM_CHANNELS_DAC08 1
59c7dd3d 88
59c7dd3d 89/* Control/Status registers */
6993197b
HS
90#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */
91#define INT_EOS 0x1 /* int end of scan */
92#define INT_FHF 0x2 /* int fifo half full */
93#define INT_FNE 0x3 /* int fifo not empty */
94#define INT_MASK 0x3 /* mask of int select bits */
95#define INTE 0x4 /* int enable */
96#define DAHFIE 0x8 /* dac half full int enable */
97#define EOAIE 0x10 /* end of acq. int enable */
98#define DAHFI 0x20 /* dac half full status / clear */
99#define EOAI 0x40 /* end of acq. int status / clear */
100#define INT 0x80 /* int status / clear */
101#define EOBI 0x200 /* end of burst int status */
102#define ADHFI 0x400 /* half-full int status */
103#define ADNEI 0x800 /* fifo not empty int status (latch) */
104#define ADNE 0x1000 /* fifo not empty status (realtime) */
105#define DAEMIE 0x1000 /* dac empty int enable */
106#define LADFUL 0x2000 /* fifo overflow / clear */
107#define DAEMI 0x4000 /* dac fifo empty int status / clear */
108
109#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL reg */
110#define BEGIN_SCAN(x) ((x) & 0xf)
111#define END_SCAN(x) (((x) & 0xf) << 4)
112#define GAIN_BITS(x) (((x) & 0x3) << 8)
113#define UNIP 0x800 /* Analog front-end unipolar mode */
114#define SE 0x400 /* Inputs in single-ended mode */
115#define PACER_MASK 0x3000 /* pacer source bits */
116#define PACER_INT 0x1000 /* int. pacer */
117#define PACER_EXT_FALL 0x2000 /* ext. falling edge */
118#define PACER_EXT_RISE 0x3000 /* ext. rising edge */
119#define EOC 0x4000 /* adc not busy */
120
121#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */
122#define SW_TRIGGER 0x1 /* software start trigger */
123#define EXT_TRIGGER 0x2 /* ext. start trigger */
124#define ANALOG_TRIGGER 0x3 /* ext. analog trigger */
125#define TRIGGER_MASK 0x3 /* start trigger mask */
126#define TGPOL 0x04 /* invert trigger (1602 only) */
127#define TGSEL 0x08 /* edge/level trigerred (1602 only) */
128#define TGEN 0x10 /* enable external start trigger */
129#define BURSTE 0x20 /* burst mode enable */
130#define XTRCL 0x80 /* clear external trigger */
131
132#define CALIBRATION_REG 6 /* CALIBRATION register */
133#define SELECT_8800_BIT 0x100 /* select 8800 caldac */
134#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */
135#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */
59c7dd3d 136#define CAL_SRC_BITS(x) (((x) & 0x7) << 11)
6993197b
HS
137#define CAL_EN_BIT 0x4000 /* calibration source enable */
138#define SERIAL_DATA_IN_BIT 0x8000 /* serial data bit going to caldac */
59c7dd3d 139
7368348c
HS
140#define DAC_CSR 0x8 /* dac control and status register */
141#define DACEN 0x02 /* dac enable */
142#define DAC_MODE_UPDATE_BOTH 0x80 /* update both dacs */
143
59c7dd3d
IM
144static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range)
145{
146 return (range & 0x3) << (8 + 2 * (channel & 0x1));
147}
0a85b6f0 148
59c7dd3d
IM
149static inline unsigned int DAC_RANGE_MASK(unsigned int channel)
150{
151 return 0x3 << (8 + 2 * (channel & 0x1));
152};
153
cf530aa4 154/* bits for 1602 series only */
6993197b
HS
155#define DAC_EMPTY 0x1 /* fifo empty, read, write clear */
156#define DAC_START 0x4 /* start/arm fifo operations */
157#define DAC_PACER_MASK 0x18 /* bits that set pacer source */
158#define DAC_PACER_INT 0x8 /* int. pacing */
159#define DAC_PACER_EXT_FALL 0x10 /* ext. pacing, falling edge */
160#define DAC_PACER_EXT_RISE 0x18 /* ext. pacing, rising edge */
7368348c 161
59c7dd3d
IM
162static inline unsigned int DAC_CHAN_EN(unsigned int channel)
163{
cf530aa4 164 return 1 << (5 + (channel & 0x1)); /* enable channel 0 or 1 */
59c7dd3d
IM
165};
166
167/* analog input fifo */
6993197b
HS
168#define ADCDATA 0 /* ADC DATA register */
169#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */
59c7dd3d 170
cf530aa4 171/* pacer, counter, dio registers */
6993197b
HS
172#define ADC8254 0
173#define DIO_8255 4
174#define DAC8254 8
59c7dd3d 175
cf530aa4 176/* analog output registers for 100x, 1200 series */
59c7dd3d
IM
177static inline unsigned int DAC_DATA_REG(unsigned int channel)
178{
179 return 2 * (channel & 0x1);
180}
181
182/* analog output registers for 1602 series*/
6993197b
HS
183#define DACDATA 0 /* DAC DATA register */
184#define DACFIFOCLR 2 /* DAC FIFO CLEAR */
185
186#define IS_UNIPOLAR 0x4 /* unipolar range mask */
59c7dd3d 187
cf530aa4 188/* analog input ranges for most boards */
9ced1de6 189static const struct comedi_lrange cb_pcidas_ranges = {
59c7dd3d
IM
190 8,
191 {
0a85b6f0
MT
192 BIP_RANGE(10),
193 BIP_RANGE(5),
194 BIP_RANGE(2.5),
195 BIP_RANGE(1.25),
196 UNI_RANGE(10),
197 UNI_RANGE(5),
198 UNI_RANGE(2.5),
199 UNI_RANGE(1.25)
200 }
59c7dd3d
IM
201};
202
cf530aa4 203/* pci-das1001 input ranges */
9ced1de6 204static const struct comedi_lrange cb_pcidas_alt_ranges = {
59c7dd3d
IM
205 8,
206 {
0a85b6f0
MT
207 BIP_RANGE(10),
208 BIP_RANGE(1),
209 BIP_RANGE(0.1),
210 BIP_RANGE(0.01),
211 UNI_RANGE(10),
212 UNI_RANGE(1),
213 UNI_RANGE(0.1),
214 UNI_RANGE(0.01)
215 }
59c7dd3d
IM
216};
217
cf530aa4 218/* analog output ranges */
9ced1de6 219static const struct comedi_lrange cb_pcidas_ao_ranges = {
59c7dd3d
IM
220 4,
221 {
0a85b6f0
MT
222 BIP_RANGE(5),
223 BIP_RANGE(10),
224 UNI_RANGE(5),
225 UNI_RANGE(10),
226 }
59c7dd3d
IM
227};
228
229enum trimpot_model {
230 AD7376,
231 AD8402,
232};
233
9b315bcb
HS
234enum cb_pcidas_boardid {
235 BOARD_PCIDAS1602_16,
236 BOARD_PCIDAS1200,
237 BOARD_PCIDAS1602_12,
238 BOARD_PCIDAS1200_JR,
239 BOARD_PCIDAS1602_16_JR,
240 BOARD_PCIDAS1000,
241 BOARD_PCIDAS1001,
242 BOARD_PCIDAS1002,
243};
244
5c2670cb 245struct cb_pcidas_board {
59c7dd3d 246 const char *name;
8f608fc8 247 int ai_nchan; /* Inputs in single-ended mode */
cf530aa4
BP
248 int ai_bits; /* analog input resolution */
249 int ai_speed; /* fastest conversion period in ns */
250 int ao_nchan; /* number of analog out channels */
251 int has_ao_fifo; /* analog output has fifo */
d478b5f6 252 int ao_scan_speed; /* analog output scan speed for 1602 series */
cf530aa4 253 int fifo_size; /* number of samples fifo can hold */
9ced1de6 254 const struct comedi_lrange *ranges;
59c7dd3d
IM
255 enum trimpot_model trimpot;
256 unsigned has_dac08:1;
23e3cce3 257 unsigned is_1602:1;
5c2670cb 258};
59c7dd3d 259
5c2670cb 260static const struct cb_pcidas_board cb_pcidas_boards[] = {
9b315bcb 261 [BOARD_PCIDAS1602_16] = {
17883d63 262 .name = "pci-das1602/16",
8f608fc8 263 .ai_nchan = 16,
17883d63
HS
264 .ai_bits = 16,
265 .ai_speed = 5000,
266 .ao_nchan = 2,
267 .has_ao_fifo = 1,
268 .ao_scan_speed = 10000,
269 .fifo_size = 512,
270 .ranges = &cb_pcidas_ranges,
271 .trimpot = AD8402,
272 .has_dac08 = 1,
273 .is_1602 = 1,
9b315bcb
HS
274 },
275 [BOARD_PCIDAS1200] = {
17883d63 276 .name = "pci-das1200",
8f608fc8 277 .ai_nchan = 16,
17883d63
HS
278 .ai_bits = 12,
279 .ai_speed = 3200,
280 .ao_nchan = 2,
17883d63
HS
281 .fifo_size = 1024,
282 .ranges = &cb_pcidas_ranges,
283 .trimpot = AD7376,
9b315bcb
HS
284 },
285 [BOARD_PCIDAS1602_12] = {
17883d63 286 .name = "pci-das1602/12",
8f608fc8 287 .ai_nchan = 16,
17883d63
HS
288 .ai_bits = 12,
289 .ai_speed = 3200,
290 .ao_nchan = 2,
291 .has_ao_fifo = 1,
292 .ao_scan_speed = 4000,
293 .fifo_size = 1024,
294 .ranges = &cb_pcidas_ranges,
295 .trimpot = AD7376,
17883d63 296 .is_1602 = 1,
9b315bcb
HS
297 },
298 [BOARD_PCIDAS1200_JR] = {
17883d63 299 .name = "pci-das1200/jr",
8f608fc8 300 .ai_nchan = 16,
17883d63
HS
301 .ai_bits = 12,
302 .ai_speed = 3200,
17883d63
HS
303 .fifo_size = 1024,
304 .ranges = &cb_pcidas_ranges,
305 .trimpot = AD7376,
9b315bcb
HS
306 },
307 [BOARD_PCIDAS1602_16_JR] = {
17883d63 308 .name = "pci-das1602/16/jr",
8f608fc8 309 .ai_nchan = 16,
17883d63
HS
310 .ai_bits = 16,
311 .ai_speed = 5000,
17883d63
HS
312 .fifo_size = 512,
313 .ranges = &cb_pcidas_ranges,
314 .trimpot = AD8402,
315 .has_dac08 = 1,
316 .is_1602 = 1,
9b315bcb
HS
317 },
318 [BOARD_PCIDAS1000] = {
17883d63 319 .name = "pci-das1000",
8f608fc8 320 .ai_nchan = 16,
17883d63
HS
321 .ai_bits = 12,
322 .ai_speed = 4000,
17883d63
HS
323 .fifo_size = 1024,
324 .ranges = &cb_pcidas_ranges,
325 .trimpot = AD7376,
9b315bcb
HS
326 },
327 [BOARD_PCIDAS1001] = {
17883d63 328 .name = "pci-das1001",
8f608fc8 329 .ai_nchan = 16,
17883d63
HS
330 .ai_bits = 12,
331 .ai_speed = 6800,
332 .ao_nchan = 2,
17883d63
HS
333 .fifo_size = 1024,
334 .ranges = &cb_pcidas_alt_ranges,
335 .trimpot = AD7376,
9b315bcb
HS
336 },
337 [BOARD_PCIDAS1002] = {
17883d63 338 .name = "pci-das1002",
8f608fc8 339 .ai_nchan = 16,
17883d63
HS
340 .ai_bits = 12,
341 .ai_speed = 6800,
342 .ao_nchan = 2,
17883d63
HS
343 .fifo_size = 1024,
344 .ranges = &cb_pcidas_ranges,
345 .trimpot = AD7376,
17883d63 346 },
59c7dd3d
IM
347};
348
c77e2589 349struct cb_pcidas_private {
0cdfbe15 350 /* base addresses */
59c7dd3d
IM
351 unsigned long s5933_config;
352 unsigned long control_status;
353 unsigned long adc_fifo;
354 unsigned long pacer_counter_dio;
355 unsigned long ao_registers;
0cdfbe15 356 /* divisors of master clock for analog input pacing */
59c7dd3d
IM
357 unsigned int divisor1;
358 unsigned int divisor2;
0cdfbe15
HS
359 /* number of analog input samples remaining */
360 unsigned int count;
361 /* bits to write to registers */
362 unsigned int adc_fifo_bits;
363 unsigned int s5933_intcsr_bits;
364 unsigned int ao_control_bits;
365 /* fifo buffers */
790c5541
BP
366 short ai_buffer[AI_BUFFER_SIZE];
367 short ao_buffer[AO_BUFFER_SIZE];
0cdfbe15 368 /* divisors of master clock for analog output pacing */
59c7dd3d
IM
369 unsigned int ao_divisor1;
370 unsigned int ao_divisor2;
0cdfbe15
HS
371 /* number of analog output samples remaining */
372 unsigned int ao_count;
373 /* cached values for readback */
374 int ao_value[2];
375 unsigned int caldac_value[NUM_CHANNELS_8800];
376 unsigned int trimpot_value[NUM_CHANNELS_8402];
59c7dd3d
IM
377 unsigned int dac08_value;
378 unsigned int calibration_source;
c77e2589 379};
59c7dd3d 380
814900c9 381static inline unsigned int cal_enable_bits(struct comedi_device *dev)
59c7dd3d 382{
82d8c74d
HS
383 struct cb_pcidas_private *devpriv = dev->private;
384
59c7dd3d
IM
385 return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
386}
387
0a85b6f0
MT
388static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
389 struct comedi_subdevice *s,
390 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 391{
82d8c74d 392 struct cb_pcidas_private *devpriv = dev->private;
f66faa57
HS
393 unsigned int chan = CR_CHAN(insn->chanspec);
394 unsigned int range = CR_RANGE(insn->chanspec);
395 unsigned int aref = CR_AREF(insn->chanspec);
59c7dd3d 396 unsigned int bits;
f66faa57
HS
397 int n, i;
398
399 /* enable calibration input if appropriate */
59c7dd3d
IM
400 if (insn->chanspec & CR_ALT_SOURCE) {
401 outw(cal_enable_bits(dev),
0a85b6f0 402 devpriv->control_status + CALIBRATION_REG);
f66faa57 403 chan = 0;
59c7dd3d
IM
404 } else {
405 outw(0, devpriv->control_status + CALIBRATION_REG);
59c7dd3d 406 }
f66faa57
HS
407
408 /* set mux limits and gain */
409 bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range);
410 /* set unipolar/bipolar */
411 if (range & IS_UNIPOLAR)
59c7dd3d 412 bits |= UNIP;
f66faa57
HS
413 /* set single-ended/differential */
414 if (aref != AREF_DIFF)
59c7dd3d
IM
415 bits |= SE;
416 outw(bits, devpriv->control_status + ADCMUX_CONT);
417
418 /* clear fifo */
419 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
420
421 /* convert n samples */
422 for (n = 0; n < insn->n; n++) {
423 /* trigger conversion */
424 outw(0, devpriv->adc_fifo + ADCDATA);
425
426 /* wait for conversion to end */
427 /* return -ETIMEDOUT if there is a timeout */
f66faa57 428 for (i = 0; i < 10000; i++) {
59c7dd3d
IM
429 if (inw(devpriv->control_status + ADCMUX_CONT) & EOC)
430 break;
431 }
f66faa57 432 if (i == 10000)
59c7dd3d
IM
433 return -ETIMEDOUT;
434
435 /* read data */
436 data[n] = inw(devpriv->adc_fifo + ADCDATA);
437 }
438
439 /* return the number of samples read/written */
440 return n;
441}
442
da91b269 443static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 444 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 445{
f3c34b2f 446 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 447 int id = data[0];
f3c34b2f 448 unsigned int source = data[1];
59c7dd3d
IM
449
450 switch (id) {
451 case INSN_CONFIG_ALT_SOURCE:
f3c34b2f
HS
452 if (source >= 8) {
453 dev_err(dev->class_dev,
454 "invalid calibration source: %i\n",
455 source);
456 return -EINVAL;
457 }
458 devpriv->calibration_source = source;
59c7dd3d
IM
459 break;
460 default:
461 return -EINVAL;
462 break;
463 }
f3c34b2f 464 return insn->n;
59c7dd3d
IM
465}
466
cf530aa4 467/* analog output insn for pcidas-1000 and 1200 series */
0a85b6f0
MT
468static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev,
469 struct comedi_subdevice *s,
470 struct comedi_insn *insn,
471 unsigned int *data)
59c7dd3d 472{
82d8c74d 473 struct cb_pcidas_private *devpriv = dev->private;
7671896c
HS
474 unsigned int chan = CR_CHAN(insn->chanspec);
475 unsigned int range = CR_RANGE(insn->chanspec);
59c7dd3d
IM
476 unsigned long flags;
477
7671896c 478 /* set channel and range */
5f74ea14 479 spin_lock_irqsave(&dev->spinlock, flags);
7671896c
HS
480 devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH &
481 ~DAC_RANGE_MASK(chan));
482 devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range));
59c7dd3d 483 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 484 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 485
7671896c
HS
486 /* remember value for readback */
487 devpriv->ao_value[chan] = data[0];
488
489 /* send data */
490 outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan));
59c7dd3d 491
7671896c 492 return insn->n;
59c7dd3d
IM
493}
494
cf530aa4 495/* analog output insn for pcidas-1602 series */
0a85b6f0
MT
496static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev,
497 struct comedi_subdevice *s,
498 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 499{
82d8c74d 500 struct cb_pcidas_private *devpriv = dev->private;
b78332da
HS
501 unsigned int chan = CR_CHAN(insn->chanspec);
502 unsigned int range = CR_RANGE(insn->chanspec);
59c7dd3d
IM
503 unsigned long flags;
504
b78332da 505 /* clear dac fifo */
59c7dd3d
IM
506 outw(0, devpriv->ao_registers + DACFIFOCLR);
507
b78332da 508 /* set channel and range */
5f74ea14 509 spin_lock_irqsave(&dev->spinlock, flags);
b78332da
HS
510 devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) &
511 ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK);
512 devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) |
513 DAC_CHAN_EN(chan) | DAC_START);
59c7dd3d 514 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 515 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 516
b78332da
HS
517 /* remember value for readback */
518 devpriv->ao_value[chan] = data[0];
519
520 /* send data */
59c7dd3d
IM
521 outw(data[0], devpriv->ao_registers + DACDATA);
522
b78332da 523 return insn->n;
59c7dd3d
IM
524}
525
0a85b6f0
MT
526static int cb_pcidas_ao_readback_insn(struct comedi_device *dev,
527 struct comedi_subdevice *s,
528 struct comedi_insn *insn,
529 unsigned int *data)
59c7dd3d 530{
82d8c74d
HS
531 struct cb_pcidas_private *devpriv = dev->private;
532
59c7dd3d
IM
533 data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
534
535 return 1;
536}
537
536af69e
HS
538static int wait_for_nvram_ready(unsigned long s5933_base_addr)
539{
540 static const int timeout = 1000;
541 unsigned int i;
542
543 for (i = 0; i < timeout; i++) {
544 if ((inb(s5933_base_addr +
545 AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY)
546 == 0)
547 return 0;
548 udelay(1);
549 }
550 return -1;
551}
552
553static int nvram_read(struct comedi_device *dev, unsigned int address,
554 uint8_t *data)
555{
82d8c74d 556 struct cb_pcidas_private *devpriv = dev->private;
536af69e
HS
557 unsigned long iobase = devpriv->s5933_config;
558
559 if (wait_for_nvram_ready(iobase) < 0)
560 return -ETIMEDOUT;
561
562 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR,
563 iobase + AMCC_OP_REG_MCSR_NVCMD);
564 outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
565 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR,
566 iobase + AMCC_OP_REG_MCSR_NVCMD);
567 outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
568 outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
569
570 if (wait_for_nvram_ready(iobase) < 0)
571 return -ETIMEDOUT;
572
573 *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
574
575 return 0;
576}
577
0a85b6f0
MT
578static int eeprom_read_insn(struct comedi_device *dev,
579 struct comedi_subdevice *s,
580 struct comedi_insn *insn, unsigned int *data)
59c7dd3d
IM
581{
582 uint8_t nvram_data;
583 int retval;
584
585 retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data);
586 if (retval < 0)
587 return retval;
588
589 data[0] = nvram_data;
590
591 return 1;
592}
593
0c15d553
HS
594static void write_calibration_bitstream(struct comedi_device *dev,
595 unsigned int register_bits,
596 unsigned int bitstream,
597 unsigned int bitstream_length)
598{
82d8c74d 599 struct cb_pcidas_private *devpriv = dev->private;
0c15d553
HS
600 static const int write_delay = 1;
601 unsigned int bit;
602
603 for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
604 if (bitstream & bit)
605 register_bits |= SERIAL_DATA_IN_BIT;
606 else
607 register_bits &= ~SERIAL_DATA_IN_BIT;
608 udelay(write_delay);
609 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
610 }
611}
612
613static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
614 uint8_t value)
615{
82d8c74d 616 struct cb_pcidas_private *devpriv = dev->private;
0c15d553
HS
617 static const int num_caldac_channels = 8;
618 static const int bitstream_length = 11;
619 unsigned int bitstream = ((address & 0x7) << 8) | value;
620 static const int caldac_8800_udelay = 1;
621
622 if (address >= num_caldac_channels) {
623 comedi_error(dev, "illegal caldac channel");
624 return -1;
625 }
626
627 if (value == devpriv->caldac_value[address])
628 return 1;
629
630 devpriv->caldac_value[address] = value;
631
632 write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream,
633 bitstream_length);
634
635 udelay(caldac_8800_udelay);
636 outw(cal_enable_bits(dev) | SELECT_8800_BIT,
637 devpriv->control_status + CALIBRATION_REG);
638 udelay(caldac_8800_udelay);
639 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
640
641 return 1;
642}
643
0a85b6f0
MT
644static int caldac_write_insn(struct comedi_device *dev,
645 struct comedi_subdevice *s,
646 struct comedi_insn *insn, unsigned int *data)
59c7dd3d
IM
647{
648 const unsigned int channel = CR_CHAN(insn->chanspec);
649
650 return caldac_8800_write(dev, channel, data[0]);
651}
652
0a85b6f0
MT
653static int caldac_read_insn(struct comedi_device *dev,
654 struct comedi_subdevice *s,
655 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 656{
82d8c74d
HS
657 struct cb_pcidas_private *devpriv = dev->private;
658
59c7dd3d
IM
659 data[0] = devpriv->caldac_value[CR_CHAN(insn->chanspec)];
660
661 return 1;
662}
663
664/* 1602/16 pregain offset */
ac55ca32 665static void dac08_write(struct comedi_device *dev, unsigned int value)
59c7dd3d 666{
82d8c74d 667 struct cb_pcidas_private *devpriv = dev->private;
b436356d 668 unsigned long cal_reg;
82d8c74d 669
b436356d
HS
670 if (devpriv->dac08_value != value) {
671 devpriv->dac08_value = value;
59c7dd3d 672
b436356d 673 cal_reg = devpriv->control_status + CALIBRATION_REG;
59c7dd3d 674
b436356d
HS
675 value &= 0xff;
676 value |= cal_enable_bits(dev);
59c7dd3d 677
b436356d
HS
678 /* latch the new value into the caldac */
679 outw(value, cal_reg);
680 udelay(1);
681 outw(value | SELECT_DAC08_BIT, cal_reg);
682 udelay(1);
683 outw(value, cal_reg);
684 udelay(1);
685 }
59c7dd3d
IM
686}
687
0a85b6f0
MT
688static int dac08_write_insn(struct comedi_device *dev,
689 struct comedi_subdevice *s,
690 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 691{
ac55ca32
HS
692 int i;
693
694 for (i = 0; i < insn->n; i++)
695 dac08_write(dev, data[i]);
696
697 return insn->n;
59c7dd3d
IM
698}
699
0a85b6f0
MT
700static int dac08_read_insn(struct comedi_device *dev,
701 struct comedi_subdevice *s, struct comedi_insn *insn,
702 unsigned int *data)
59c7dd3d 703{
82d8c74d
HS
704 struct cb_pcidas_private *devpriv = dev->private;
705
59c7dd3d
IM
706 data[0] = devpriv->dac08_value;
707
708 return 1;
709}
710
20535c1f
HS
711static int trimpot_7376_write(struct comedi_device *dev, uint8_t value)
712{
82d8c74d 713 struct cb_pcidas_private *devpriv = dev->private;
20535c1f
HS
714 static const int bitstream_length = 7;
715 unsigned int bitstream = value & 0x7f;
716 unsigned int register_bits;
717 static const int ad7376_udelay = 1;
718
719 register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
720 udelay(ad7376_udelay);
721 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
722
723 write_calibration_bitstream(dev, register_bits, bitstream,
724 bitstream_length);
725
726 udelay(ad7376_udelay);
727 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
728
729 return 0;
730}
731
732/* For 1602/16 only
733 * ch 0 : adc gain
734 * ch 1 : adc postgain offset */
735static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel,
736 uint8_t value)
737{
82d8c74d 738 struct cb_pcidas_private *devpriv = dev->private;
20535c1f
HS
739 static const int bitstream_length = 10;
740 unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
741 unsigned int register_bits;
742 static const int ad8402_udelay = 1;
743
744 register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
745 udelay(ad8402_udelay);
746 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
747
748 write_calibration_bitstream(dev, register_bits, bitstream,
749 bitstream_length);
750
751 udelay(ad8402_udelay);
752 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
753
754 return 0;
755}
756
da91b269 757static int cb_pcidas_trimpot_write(struct comedi_device *dev,
0a85b6f0 758 unsigned int channel, unsigned int value)
59c7dd3d 759{
82d8c74d
HS
760 const struct cb_pcidas_board *thisboard = comedi_board(dev);
761 struct cb_pcidas_private *devpriv = dev->private;
762
59c7dd3d
IM
763 if (devpriv->trimpot_value[channel] == value)
764 return 1;
765
766 devpriv->trimpot_value[channel] = value;
767 switch (thisboard->trimpot) {
768 case AD7376:
769 trimpot_7376_write(dev, value);
770 break;
771 case AD8402:
772 trimpot_8402_write(dev, channel, value);
773 break;
774 default:
775 comedi_error(dev, "driver bug?");
776 return -1;
777 break;
778 }
779
780 return 1;
781}
782
0a85b6f0
MT
783static int trimpot_write_insn(struct comedi_device *dev,
784 struct comedi_subdevice *s,
785 struct comedi_insn *insn, unsigned int *data)
59c7dd3d
IM
786{
787 unsigned int channel = CR_CHAN(insn->chanspec);
788
789 return cb_pcidas_trimpot_write(dev, channel, data[0]);
790}
791
0a85b6f0
MT
792static int trimpot_read_insn(struct comedi_device *dev,
793 struct comedi_subdevice *s,
794 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 795{
82d8c74d 796 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d
IM
797 unsigned int channel = CR_CHAN(insn->chanspec);
798
799 data[0] = devpriv->trimpot_value[channel];
800
801 return 1;
802}
803
0a85b6f0
MT
804static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
805 struct comedi_subdevice *s,
806 struct comedi_cmd *cmd)
59c7dd3d 807{
82d8c74d
HS
808 const struct cb_pcidas_board *thisboard = comedi_board(dev);
809 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d
IM
810 int err = 0;
811 int tmp;
812 int i, gain, start_chan;
813
27020ffe 814 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 815
27020ffe
HS
816 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
817 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
818 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
819 err |= cfc_check_trigger_src(&cmd->convert_src,
820 TRIG_TIMER | TRIG_NOW | TRIG_EXT);
821 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
822 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
823
824 if (err)
825 return 1;
826
27020ffe 827 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 828
27020ffe
HS
829 err |= cfc_check_trigger_is_unique(cmd->start_src);
830 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
831 err |= cfc_check_trigger_is_unique(cmd->convert_src);
832 err |= cfc_check_trigger_is_unique(cmd->stop_src);
833
834 /* Step 2b : and mutually compatible */
59c7dd3d 835
59c7dd3d 836 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
27020ffe 837 err |= -EINVAL;
59c7dd3d 838 if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
27020ffe 839 err |= -EINVAL;
59c7dd3d 840 if (cmd->start_src == TRIG_EXT &&
0a85b6f0 841 (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
27020ffe 842 err |= -EINVAL;
59c7dd3d
IM
843
844 if (err)
845 return 2;
846
0c4ef0b9 847 /* step 3: arguments are trivially compatible */
59c7dd3d 848
f1bc4343
BD
849 switch (cmd->start_src) {
850 case TRIG_EXT:
851 /* External trigger, only CR_EDGE and CR_INVERT flags allowed */
852 if ((cmd->start_arg
853 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
00d9c8cb
HS
854 cmd->start_arg &= ~(CR_FLAGS_MASK &
855 ~(CR_EDGE | CR_INVERT));
856 err |= -EINVAL;
f1bc4343 857 }
23e3cce3 858 if (!thisboard->is_1602 && (cmd->start_arg & CR_INVERT)) {
f1bc4343 859 cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT);
00d9c8cb 860 err |= -EINVAL;
f1bc4343
BD
861 }
862 break;
863 default:
00d9c8cb 864 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
f1bc4343 865 break;
59c7dd3d
IM
866 }
867
00d9c8cb
HS
868 if (cmd->scan_begin_src == TRIG_TIMER)
869 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
870 thisboard->ai_speed * cmd->chanlist_len);
59c7dd3d 871
00d9c8cb
HS
872 if (cmd->convert_src == TRIG_TIMER)
873 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
874 thisboard->ai_speed);
875
876 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
877
878 if (cmd->stop_src == TRIG_NONE)
879 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
880
881 if (err)
882 return 3;
883
884 /* step 4: fix up any arguments */
885
886 if (cmd->scan_begin_src == TRIG_TIMER) {
887 tmp = cmd->scan_begin_arg;
888 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
0a85b6f0
MT
889 &(devpriv->divisor1),
890 &(devpriv->divisor2),
891 &(cmd->scan_begin_arg),
892 cmd->flags & TRIG_ROUND_MASK);
59c7dd3d
IM
893 if (tmp != cmd->scan_begin_arg)
894 err++;
895 }
896 if (cmd->convert_src == TRIG_TIMER) {
897 tmp = cmd->convert_arg;
898 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
0a85b6f0
MT
899 &(devpriv->divisor1),
900 &(devpriv->divisor2),
901 &(cmd->convert_arg),
902 cmd->flags & TRIG_ROUND_MASK);
59c7dd3d
IM
903 if (tmp != cmd->convert_arg)
904 err++;
905 }
906
907 if (err)
908 return 4;
909
cf530aa4 910 /* check channel/gain list against card's limitations */
59c7dd3d
IM
911 if (cmd->chanlist) {
912 gain = CR_RANGE(cmd->chanlist[0]);
913 start_chan = CR_CHAN(cmd->chanlist[0]);
914 for (i = 1; i < cmd->chanlist_len; i++) {
915 if (CR_CHAN(cmd->chanlist[i]) !=
0a85b6f0 916 (start_chan + i) % s->n_chan) {
59c7dd3d 917 comedi_error(dev,
0a85b6f0 918 "entries in chanlist must be consecutive channels, counting upwards\n");
59c7dd3d
IM
919 err++;
920 }
921 if (CR_RANGE(cmd->chanlist[i]) != gain) {
922 comedi_error(dev,
0a85b6f0 923 "entries in chanlist must all have the same gain\n");
59c7dd3d
IM
924 err++;
925 }
926 }
927 }
928
929 if (err)
930 return 5;
931
932 return 0;
933}
934
bb036943
HS
935static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns,
936 int rounding_flags)
937{
82d8c74d
HS
938 struct cb_pcidas_private *devpriv = dev->private;
939
bb036943
HS
940 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
941 &(devpriv->divisor2), ns,
942 rounding_flags & TRIG_ROUND_MASK);
943
944 /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
945 i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1,
946 devpriv->divisor1, 2);
947 i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2,
948 devpriv->divisor2, 2);
949}
950
0a85b6f0
MT
951static int cb_pcidas_ai_cmd(struct comedi_device *dev,
952 struct comedi_subdevice *s)
59c7dd3d 953{
82d8c74d
HS
954 const struct cb_pcidas_board *thisboard = comedi_board(dev);
955 struct cb_pcidas_private *devpriv = dev->private;
d163679c 956 struct comedi_async *async = s->async;
ea6d0d4c 957 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
958 unsigned int bits;
959 unsigned long flags;
960
cf530aa4 961 /* make sure CAL_EN_BIT is disabled */
59c7dd3d 962 outw(0, devpriv->control_status + CALIBRATION_REG);
cf530aa4 963 /* initialize before settings pacer source and count values */
59c7dd3d 964 outw(0, devpriv->control_status + TRIG_CONTSTAT);
cf530aa4 965 /* clear fifo */
59c7dd3d
IM
966 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
967
cf530aa4 968 /* set mux limits, gain and pacer source */
59c7dd3d 969 bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) |
0a85b6f0
MT
970 END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
971 GAIN_BITS(CR_RANGE(cmd->chanlist[0]));
cf530aa4 972 /* set unipolar/bipolar */
59c7dd3d
IM
973 if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR)
974 bits |= UNIP;
cf530aa4 975 /* set singleended/differential */
59c7dd3d
IM
976 if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
977 bits |= SE;
cf530aa4 978 /* set pacer source */
59c7dd3d
IM
979 if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
980 bits |= PACER_EXT_RISE;
981 else
982 bits |= PACER_INT;
983 outw(bits, devpriv->control_status + ADCMUX_CONT);
984
cf530aa4 985 /* load counters */
59c7dd3d
IM
986 if (cmd->convert_src == TRIG_TIMER)
987 cb_pcidas_load_counters(dev, &cmd->convert_arg,
0a85b6f0 988 cmd->flags & TRIG_ROUND_MASK);
59c7dd3d
IM
989 else if (cmd->scan_begin_src == TRIG_TIMER)
990 cb_pcidas_load_counters(dev, &cmd->scan_begin_arg,
0a85b6f0 991 cmd->flags & TRIG_ROUND_MASK);
59c7dd3d 992
cf530aa4 993 /* set number of conversions */
2d238b29 994 if (cmd->stop_src == TRIG_COUNT)
59c7dd3d 995 devpriv->count = cmd->chanlist_len * cmd->stop_arg;
cf530aa4 996 /* enable interrupts */
5f74ea14 997 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
998 devpriv->adc_fifo_bits |= INTE;
999 devpriv->adc_fifo_bits &= ~INT_MASK;
1000 if (cmd->flags & TRIG_WAKE_EOS) {
55acaf2d
HS
1001 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
1002 /* interrupt end of burst */
1003 devpriv->adc_fifo_bits |= INT_EOS;
1004 } else {
1005 /* interrupt fifo not empty */
1006 devpriv->adc_fifo_bits |= INT_FNE;
1007 }
59c7dd3d 1008 } else {
55acaf2d
HS
1009 /* interrupt fifo half full */
1010 devpriv->adc_fifo_bits |= INT_FHF;
59c7dd3d 1011 }
193debd1 1012
cf530aa4 1013 /* enable (and clear) interrupts */
59c7dd3d 1014 outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL,
0a85b6f0 1015 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1016 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1017
cf530aa4 1018 /* set start trigger and burst mode */
59c7dd3d
IM
1019 bits = 0;
1020 if (cmd->start_src == TRIG_NOW)
1021 bits |= SW_TRIGGER;
f1bc4343 1022 else if (cmd->start_src == TRIG_EXT) {
59c7dd3d 1023 bits |= EXT_TRIGGER | TGEN | XTRCL;
23e3cce3 1024 if (thisboard->is_1602) {
93c58378 1025 if (cmd->start_arg & CR_INVERT)
23e3cce3
HS
1026 bits |= TGPOL;
1027 if (cmd->start_arg & CR_EDGE)
1028 bits |= TGSEL;
1029 }
f1bc4343 1030 } else {
59c7dd3d
IM
1031 comedi_error(dev, "bug!");
1032 return -1;
1033 }
1034 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
1035 bits |= BURSTE;
1036 outw(bits, devpriv->control_status + TRIG_CONTSTAT);
59c7dd3d
IM
1037
1038 return 0;
1039}
1040
0a85b6f0
MT
1041static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
1042 struct comedi_subdevice *s,
1043 struct comedi_cmd *cmd)
59c7dd3d 1044{
82d8c74d
HS
1045 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1046 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d
IM
1047 int err = 0;
1048 int tmp;
1049
27020ffe 1050 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 1051
27020ffe
HS
1052 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
1053 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
1054 TRIG_TIMER | TRIG_EXT);
1055 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
1056 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1057 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
1058
1059 if (err)
1060 return 1;
1061
27020ffe 1062 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 1063
27020ffe
HS
1064 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
1065 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1066
1067 /* Step 2b : and mutually compatible */
59c7dd3d
IM
1068
1069 if (err)
1070 return 2;
1071
00d9c8cb 1072 /* Step 3: check if arguments are trivially valid */
59c7dd3d 1073
00d9c8cb 1074 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
59c7dd3d 1075
00d9c8cb
HS
1076 if (cmd->scan_begin_src == TRIG_TIMER)
1077 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1078 thisboard->ao_scan_speed);
59c7dd3d 1079
00d9c8cb
HS
1080 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1081
1082 if (cmd->stop_src == TRIG_NONE)
1083 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
1084
1085 if (err)
1086 return 3;
1087
1088 /* step 4: fix up any arguments */
1089
1090 if (cmd->scan_begin_src == TRIG_TIMER) {
1091 tmp = cmd->scan_begin_arg;
1092 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
0a85b6f0
MT
1093 &(devpriv->ao_divisor1),
1094 &(devpriv->ao_divisor2),
1095 &(cmd->scan_begin_arg),
1096 cmd->flags & TRIG_ROUND_MASK);
59c7dd3d
IM
1097 if (tmp != cmd->scan_begin_arg)
1098 err++;
1099 }
1100
1101 if (err)
1102 return 4;
1103
cf530aa4 1104 /* check channel/gain list against card's limitations */
59c7dd3d
IM
1105 if (cmd->chanlist && cmd->chanlist_len > 1) {
1106 if (CR_CHAN(cmd->chanlist[0]) != 0 ||
0a85b6f0 1107 CR_CHAN(cmd->chanlist[1]) != 1) {
59c7dd3d 1108 comedi_error(dev,
0a85b6f0 1109 "channels must be ordered channel 0, channel 1 in chanlist\n");
59c7dd3d
IM
1110 err++;
1111 }
1112 }
1113
1114 if (err)
1115 return 5;
1116
1117 return 0;
1118}
1119
9a0f7631
HS
1120/* cancel analog input command */
1121static int cb_pcidas_cancel(struct comedi_device *dev,
1122 struct comedi_subdevice *s)
1123{
82d8c74d 1124 struct cb_pcidas_private *devpriv = dev->private;
9a0f7631
HS
1125 unsigned long flags;
1126
1127 spin_lock_irqsave(&dev->spinlock, flags);
1128 /* disable interrupts */
1129 devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
1130 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1131 spin_unlock_irqrestore(&dev->spinlock, flags);
1132
1133 /* disable start trigger source and burst mode */
1134 outw(0, devpriv->control_status + TRIG_CONTSTAT);
1135 /* software pacer source */
1136 outw(0, devpriv->control_status + ADCMUX_CONT);
1137
1138 return 0;
1139}
1140
1706fcc1
HS
1141static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1142 struct comedi_subdevice *s,
1143 unsigned int trig_num)
1144{
82d8c74d
HS
1145 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1146 struct cb_pcidas_private *devpriv = dev->private;
1706fcc1
HS
1147 unsigned int num_bytes, num_points = thisboard->fifo_size;
1148 struct comedi_async *async = s->async;
1149 struct comedi_cmd *cmd = &s->async->cmd;
1150 unsigned long flags;
1151
1152 if (trig_num != 0)
1153 return -EINVAL;
1154
1155 /* load up fifo */
1156 if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points)
1157 num_points = devpriv->ao_count;
1158
1159 num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1160 num_points * sizeof(short));
1161 num_points = num_bytes / sizeof(short);
1162
1163 if (cmd->stop_src == TRIG_COUNT)
1164 devpriv->ao_count -= num_points;
1165 /* write data to board's fifo */
1166 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes);
1167
1168 /* enable dac half-full and empty interrupts */
1169 spin_lock_irqsave(&dev->spinlock, flags);
1170 devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
193debd1 1171
1706fcc1
HS
1172 /* enable and clear interrupts */
1173 outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
1174 devpriv->control_status + INT_ADCFIFO);
1175
1176 /* start dac */
1177 devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
1178 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
193debd1 1179
1706fcc1
HS
1180 spin_unlock_irqrestore(&dev->spinlock, flags);
1181
1182 async->inttrig = NULL;
1183
1184 return 0;
1185}
1186
0a85b6f0
MT
1187static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1188 struct comedi_subdevice *s)
59c7dd3d 1189{
82d8c74d 1190 struct cb_pcidas_private *devpriv = dev->private;
d163679c 1191 struct comedi_async *async = s->async;
ea6d0d4c 1192 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
1193 unsigned int i;
1194 unsigned long flags;
1195
cf530aa4 1196 /* set channel limits, gain */
5f74ea14 1197 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1198 for (i = 0; i < cmd->chanlist_len; i++) {
cf530aa4 1199 /* enable channel */
59c7dd3d 1200 devpriv->ao_control_bits |=
0a85b6f0 1201 DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
cf530aa4 1202 /* set range */
59c7dd3d 1203 devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
0a85b6f0
MT
1204 CR_RANGE(cmd->
1205 chanlist[i]));
59c7dd3d
IM
1206 }
1207
cf530aa4 1208 /* disable analog out before settings pacer source and count values */
59c7dd3d 1209 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 1210 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1211
cf530aa4 1212 /* clear fifo */
59c7dd3d
IM
1213 outw(0, devpriv->ao_registers + DACFIFOCLR);
1214
cf530aa4 1215 /* load counters */
59c7dd3d
IM
1216 if (cmd->scan_begin_src == TRIG_TIMER) {
1217 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
0a85b6f0
MT
1218 &(devpriv->ao_divisor1),
1219 &(devpriv->ao_divisor2),
1220 &(cmd->scan_begin_arg),
1221 cmd->flags);
59c7dd3d
IM
1222
1223 /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
1224 i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1,
0a85b6f0 1225 devpriv->ao_divisor1, 2);
59c7dd3d 1226 i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2,
0a85b6f0 1227 devpriv->ao_divisor2, 2);
59c7dd3d 1228 }
cf530aa4 1229 /* set number of conversions */
2d238b29 1230 if (cmd->stop_src == TRIG_COUNT)
59c7dd3d 1231 devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
cf530aa4 1232 /* set pacer source */
5f74ea14 1233 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
1234 switch (cmd->scan_begin_src) {
1235 case TRIG_TIMER:
1236 devpriv->ao_control_bits |= DAC_PACER_INT;
1237 break;
1238 case TRIG_EXT:
1239 devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
1240 break;
1241 default:
5f74ea14 1242 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1243 comedi_error(dev, "error setting dac pacer source");
1244 return -1;
1245 break;
1246 }
5f74ea14 1247 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1248
1249 async->inttrig = cb_pcidas_ao_inttrig;
1250
1251 return 0;
1252}
1253
0aa20304
HS
1254/* cancel analog output command */
1255static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1256 struct comedi_subdevice *s)
1257{
82d8c74d 1258 struct cb_pcidas_private *devpriv = dev->private;
0aa20304
HS
1259 unsigned long flags;
1260
1261 spin_lock_irqsave(&dev->spinlock, flags);
1262 /* disable interrupts */
1263 devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
1264 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1265
1266 /* disable output */
1267 devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
1268 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1269 spin_unlock_irqrestore(&dev->spinlock, flags);
1270
1271 return 0;
1272}
1273
9e11d05f
HS
1274static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
1275{
82d8c74d
HS
1276 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1277 struct cb_pcidas_private *devpriv = dev->private;
9e11d05f
HS
1278 struct comedi_subdevice *s = dev->write_subdev;
1279 struct comedi_async *async = s->async;
1280 struct comedi_cmd *cmd = &async->cmd;
1281 unsigned int half_fifo = thisboard->fifo_size / 2;
1282 unsigned int num_points;
1283 unsigned long flags;
1284
1285 async->events = 0;
1286
1287 if (status & DAEMI) {
1288 /* clear dac empty interrupt latch */
1289 spin_lock_irqsave(&dev->spinlock, flags);
1290 outw(devpriv->adc_fifo_bits | DAEMI,
1291 devpriv->control_status + INT_ADCFIFO);
1292 spin_unlock_irqrestore(&dev->spinlock, flags);
1293 if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
1294 if (cmd->stop_src == TRIG_NONE ||
1295 (cmd->stop_src == TRIG_COUNT
1296 && devpriv->ao_count)) {
1297 comedi_error(dev, "dac fifo underflow");
1298 cb_pcidas_ao_cancel(dev, s);
1299 async->events |= COMEDI_CB_ERROR;
1300 }
1301 async->events |= COMEDI_CB_EOA;
1302 }
1303 } else if (status & DAHFI) {
1304 unsigned int num_bytes;
1305
1306 /* figure out how many points we are writing to fifo */
1307 num_points = half_fifo;
1308 if (cmd->stop_src == TRIG_COUNT &&
1309 devpriv->ao_count < num_points)
1310 num_points = devpriv->ao_count;
1311 num_bytes =
1312 cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1313 num_points * sizeof(short));
1314 num_points = num_bytes / sizeof(short);
1315
1316 if (async->cmd.stop_src == TRIG_COUNT)
1317 devpriv->ao_count -= num_points;
1318 /* write data to board's fifo */
1319 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
1320 num_points);
1321 /* clear half-full interrupt latch */
1322 spin_lock_irqsave(&dev->spinlock, flags);
1323 outw(devpriv->adc_fifo_bits | DAHFI,
1324 devpriv->control_status + INT_ADCFIFO);
1325 spin_unlock_irqrestore(&dev->spinlock, flags);
1326 }
1327
1328 comedi_event(dev, s);
1329}
1330
70265d24 1331static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
59c7dd3d 1332{
0a85b6f0 1333 struct comedi_device *dev = (struct comedi_device *)d;
82d8c74d
HS
1334 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1335 struct cb_pcidas_private *devpriv = dev->private;
34c43922 1336 struct comedi_subdevice *s = dev->read_subdev;
d163679c 1337 struct comedi_async *async;
59c7dd3d
IM
1338 int status, s5933_status;
1339 int half_fifo = thisboard->fifo_size / 2;
1340 unsigned int num_samples, i;
1341 static const int timeout = 10000;
1342 unsigned long flags;
1343
a7401cdd 1344 if (!dev->attached)
59c7dd3d 1345 return IRQ_NONE;
59c7dd3d
IM
1346
1347 async = s->async;
1348 async->events = 0;
1349
1350 s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1351
1352 if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
1353 return IRQ_NONE;
1354
cf530aa4 1355 /* make sure mailbox 4 is empty */
59c7dd3d 1356 inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
cf530aa4 1357 /* clear interrupt on amcc s5933 */
59c7dd3d 1358 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
0a85b6f0 1359 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1360
1361 status = inw(devpriv->control_status + INT_ADCFIFO);
59c7dd3d 1362
cf530aa4 1363 /* check for analog output interrupt */
2d238b29 1364 if (status & (DAHFI | DAEMI))
59c7dd3d 1365 handle_ao_interrupt(dev, status);
cf530aa4
BP
1366 /* check for analog input interrupts */
1367 /* if fifo half-full */
59c7dd3d 1368 if (status & ADHFI) {
cf530aa4 1369 /* read data */
59c7dd3d
IM
1370 num_samples = half_fifo;
1371 if (async->cmd.stop_src == TRIG_COUNT &&
0a85b6f0 1372 num_samples > devpriv->count) {
59c7dd3d
IM
1373 num_samples = devpriv->count;
1374 }
1375 insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
0a85b6f0 1376 num_samples);
59c7dd3d 1377 cfc_write_array_to_buffer(s, devpriv->ai_buffer,
0a85b6f0 1378 num_samples * sizeof(short));
59c7dd3d
IM
1379 devpriv->count -= num_samples;
1380 if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) {
1381 async->events |= COMEDI_CB_EOA;
1382 cb_pcidas_cancel(dev, s);
1383 }
cf530aa4 1384 /* clear half-full interrupt latch */
5f74ea14 1385 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1386 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1387 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1388 spin_unlock_irqrestore(&dev->spinlock, flags);
cf530aa4 1389 /* else if fifo not empty */
59c7dd3d
IM
1390 } else if (status & (ADNEI | EOBI)) {
1391 for (i = 0; i < timeout; i++) {
cf530aa4 1392 /* break if fifo is empty */
59c7dd3d 1393 if ((ADNE & inw(devpriv->control_status +
0a85b6f0 1394 INT_ADCFIFO)) == 0)
59c7dd3d
IM
1395 break;
1396 cfc_write_to_buffer(s, inw(devpriv->adc_fifo));
55acaf2d
HS
1397 if (async->cmd.stop_src == TRIG_COUNT &&
1398 --devpriv->count == 0) {
1399 /* end of acquisition */
59c7dd3d
IM
1400 cb_pcidas_cancel(dev, s);
1401 async->events |= COMEDI_CB_EOA;
1402 break;
1403 }
1404 }
cf530aa4 1405 /* clear not-empty interrupt latch */
5f74ea14 1406 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1407 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1408 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1409 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1410 } else if (status & EOAI) {
1411 comedi_error(dev,
25985edc 1412 "bug! encountered end of acquisition interrupt?");
cf530aa4 1413 /* clear EOA interrupt latch */
5f74ea14 1414 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1415 outw(devpriv->adc_fifo_bits | EOAI,
0a85b6f0 1416 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1417 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1418 }
cf530aa4 1419 /* check for fifo overflow */
59c7dd3d
IM
1420 if (status & LADFUL) {
1421 comedi_error(dev, "fifo overflow");
cf530aa4 1422 /* clear overflow interrupt latch */
5f74ea14 1423 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1424 outw(devpriv->adc_fifo_bits | LADFUL,
0a85b6f0 1425 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1426 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1427 cb_pcidas_cancel(dev, s);
1428 async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
1429 }
1430
1431 comedi_event(dev, s);
1432
1433 return IRQ_HANDLED;
1434}
1435
a690b7e5 1436static int cb_pcidas_auto_attach(struct comedi_device *dev,
9b315bcb 1437 unsigned long context)
327be979 1438{
750af5e5 1439 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
9b315bcb 1440 const struct cb_pcidas_board *thisboard = NULL;
327be979
HS
1441 struct cb_pcidas_private *devpriv;
1442 struct comedi_subdevice *s;
1443 int i;
1444 int ret;
e74f209c 1445
9b315bcb
HS
1446 if (context < ARRAY_SIZE(cb_pcidas_boards))
1447 thisboard = &cb_pcidas_boards[context];
3b96f250
HS
1448 if (!thisboard)
1449 return -ENODEV;
1450 dev->board_ptr = thisboard;
1451 dev->board_name = thisboard->name;
1452
c34fa261
HS
1453 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1454 if (!devpriv)
1455 return -ENOMEM;
1456 dev->private = devpriv;
3b96f250 1457
818f569f 1458 ret = comedi_pci_enable(dev);
3b96f250
HS
1459 if (ret)
1460 return ret;
7302abef 1461
ba36b9ba
HS
1462 devpriv->s5933_config = pci_resource_start(pcidev, 0);
1463 devpriv->control_status = pci_resource_start(pcidev, 1);
1464 devpriv->adc_fifo = pci_resource_start(pcidev, 2);
1465 devpriv->pacer_counter_dio = pci_resource_start(pcidev, 3);
7302abef 1466 if (thisboard->ao_nchan)
ba36b9ba 1467 devpriv->ao_registers = pci_resource_start(pcidev, 4);
7302abef 1468
e74f209c
HS
1469 /* disable and clear interrupts on amcc s5933 */
1470 outl(INTCSR_INBOX_INTR_STATUS,
1471 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1472
ba36b9ba 1473 if (request_irq(pcidev->irq, cb_pcidas_interrupt,
0a5aed48 1474 IRQF_SHARED, dev->driver->driver_name, dev)) {
e74f209c 1475 dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
ba36b9ba 1476 pcidev->irq);
e74f209c
HS
1477 return -EINVAL;
1478 }
ba36b9ba 1479 dev->irq = pcidev->irq;
e74f209c 1480
e74f209c
HS
1481 ret = comedi_alloc_subdevices(dev, 7);
1482 if (ret)
1483 return ret;
1484
e89c61b9 1485 s = &dev->subdevices[0];
e74f209c
HS
1486 /* analog input subdevice */
1487 dev->read_subdev = s;
1488 s->type = COMEDI_SUBD_AI;
1489 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
1490 /* WARNING: Number of inputs in differential mode is ignored */
8f608fc8
HS
1491 s->n_chan = thisboard->ai_nchan;
1492 s->len_chanlist = thisboard->ai_nchan;
e74f209c
HS
1493 s->maxdata = (1 << thisboard->ai_bits) - 1;
1494 s->range_table = thisboard->ranges;
1495 s->insn_read = cb_pcidas_ai_rinsn;
1496 s->insn_config = ai_config_insn;
1497 s->do_cmd = cb_pcidas_ai_cmd;
1498 s->do_cmdtest = cb_pcidas_ai_cmdtest;
1499 s->cancel = cb_pcidas_cancel;
1500
1501 /* analog output subdevice */
e89c61b9 1502 s = &dev->subdevices[1];
e74f209c
HS
1503 if (thisboard->ao_nchan) {
1504 s->type = COMEDI_SUBD_AO;
1505 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
1506 s->n_chan = thisboard->ao_nchan;
55acaf2d
HS
1507 /*
1508 * analog out resolution is the same as
1509 * analog input resolution, so use ai_bits
1510 */
e74f209c
HS
1511 s->maxdata = (1 << thisboard->ai_bits) - 1;
1512 s->range_table = &cb_pcidas_ao_ranges;
1513 s->insn_read = cb_pcidas_ao_readback_insn;
1514 if (thisboard->has_ao_fifo) {
1515 dev->write_subdev = s;
1516 s->subdev_flags |= SDF_CMD_WRITE;
1517 s->insn_write = cb_pcidas_ao_fifo_winsn;
1518 s->do_cmdtest = cb_pcidas_ao_cmdtest;
1519 s->do_cmd = cb_pcidas_ao_cmd;
1520 s->cancel = cb_pcidas_ao_cancel;
1521 } else {
1522 s->insn_write = cb_pcidas_ao_nofifo_winsn;
1523 }
1524 } else {
1525 s->type = COMEDI_SUBD_UNUSED;
1526 }
1527
1528 /* 8255 */
e89c61b9 1529 s = &dev->subdevices[2];
4f0036ef
HS
1530 ret = subdev_8255_init(dev, s, NULL,
1531 devpriv->pacer_counter_dio + DIO_8255);
1532 if (ret)
1533 return ret;
e74f209c
HS
1534
1535 /* serial EEPROM, */
e89c61b9 1536 s = &dev->subdevices[3];
e74f209c
HS
1537 s->type = COMEDI_SUBD_MEMORY;
1538 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1539 s->n_chan = 256;
1540 s->maxdata = 0xff;
1541 s->insn_read = eeprom_read_insn;
1542
1543 /* 8800 caldac */
e89c61b9 1544 s = &dev->subdevices[4];
e74f209c
HS
1545 s->type = COMEDI_SUBD_CALIB;
1546 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1547 s->n_chan = NUM_CHANNELS_8800;
1548 s->maxdata = 0xff;
1549 s->insn_read = caldac_read_insn;
1550 s->insn_write = caldac_write_insn;
1551 for (i = 0; i < s->n_chan; i++)
1552 caldac_8800_write(dev, i, s->maxdata / 2);
1553
1554 /* trim potentiometer */
e89c61b9 1555 s = &dev->subdevices[5];
e74f209c
HS
1556 s->type = COMEDI_SUBD_CALIB;
1557 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1558 if (thisboard->trimpot == AD7376) {
1559 s->n_chan = NUM_CHANNELS_7376;
1560 s->maxdata = 0x7f;
1561 } else {
1562 s->n_chan = NUM_CHANNELS_8402;
1563 s->maxdata = 0xff;
1564 }
1565 s->insn_read = trimpot_read_insn;
1566 s->insn_write = trimpot_write_insn;
1567 for (i = 0; i < s->n_chan; i++)
1568 cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
1569
1570 /* dac08 caldac */
e89c61b9 1571 s = &dev->subdevices[6];
e74f209c
HS
1572 if (thisboard->has_dac08) {
1573 s->type = COMEDI_SUBD_CALIB;
1574 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1575 s->n_chan = NUM_CHANNELS_DAC08;
1576 s->insn_read = dac08_read_insn;
1577 s->insn_write = dac08_write_insn;
1578 s->maxdata = 0xff;
1579 dac08_write(dev, s->maxdata / 2);
1580 } else
1581 s->type = COMEDI_SUBD_UNUSED;
1582
1583 /* make sure mailbox 4 is empty */
1584 inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1585 /* Set bits to enable incoming mailbox interrupts on amcc s5933. */
1586 devpriv->s5933_intcsr_bits =
1587 INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1588 INTCSR_INBOX_FULL_INT;
1589 /* clear and enable interrupt on amcc s5933 */
1590 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1591 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1592
3b96f250
HS
1593 dev_info(dev->class_dev, "%s: %s attached\n",
1594 dev->driver->driver_name, dev->board_name);
1595
1596 return 0;
e74f209c
HS
1597}
1598
1599static void cb_pcidas_detach(struct comedi_device *dev)
1600{
82d8c74d
HS
1601 struct cb_pcidas_private *devpriv = dev->private;
1602
e74f209c
HS
1603 if (devpriv) {
1604 if (devpriv->s5933_config) {
1605 outl(INTCSR_INBOX_INTR_STATUS,
1606 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1607 }
1608 }
1609 if (dev->irq)
1610 free_irq(dev->irq, dev);
1611 if (dev->subdevices)
e89c61b9 1612 subdev_8255_cleanup(dev, &dev->subdevices[2]);
7f072f54 1613 comedi_pci_disable(dev);
e74f209c
HS
1614}
1615
715b2284
HS
1616static struct comedi_driver cb_pcidas_driver = {
1617 .driver_name = "cb_pcidas",
1618 .module = THIS_MODULE,
750af5e5 1619 .auto_attach = cb_pcidas_auto_attach,
715b2284
HS
1620 .detach = cb_pcidas_detach,
1621};
1622
a690b7e5 1623static int cb_pcidas_pci_probe(struct pci_dev *dev,
b8f4ac23 1624 const struct pci_device_id *id)
727b286b 1625{
b8f4ac23
HS
1626 return comedi_pci_auto_config(dev, &cb_pcidas_driver,
1627 id->driver_data);
727b286b
AT
1628}
1629
715b2284 1630static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
9b315bcb
HS
1631 { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
1632 { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
1633 { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
1634 { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
1635 { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
1636 { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
1637 { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
1638 { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
715b2284 1639 { 0 }
727b286b 1640};
715b2284 1641MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
727b286b 1642
715b2284
HS
1643static struct pci_driver cb_pcidas_pci_driver = {
1644 .name = "cb_pcidas",
1645 .id_table = cb_pcidas_pci_table,
1646 .probe = cb_pcidas_pci_probe,
9901a4d7 1647 .remove = comedi_pci_auto_unconfig,
715b2284
HS
1648};
1649module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
90f703d3
AT
1650
1651MODULE_AUTHOR("Comedi http://www.comedi.org");
1652MODULE_DESCRIPTION("Comedi low-level driver");
1653MODULE_LICENSE("GPL");
This page took 0.527774 seconds and 5 git commands to generate.