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