staging: comedi: amplc_pci230: factor out chanlist checking from (*do_cmdtest)
[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
0a85b6f0
MT
806static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
807 struct comedi_subdevice *s,
808 struct comedi_cmd *cmd)
59c7dd3d 809{
82d8c74d
HS
810 const struct cb_pcidas_board *thisboard = comedi_board(dev);
811 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d
IM
812 int err = 0;
813 int tmp;
814 int i, gain, start_chan;
815
27020ffe 816 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 817
27020ffe
HS
818 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
819 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
820 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
821 err |= cfc_check_trigger_src(&cmd->convert_src,
822 TRIG_TIMER | TRIG_NOW | TRIG_EXT);
823 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
824 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
825
826 if (err)
827 return 1;
828
27020ffe 829 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 830
27020ffe
HS
831 err |= cfc_check_trigger_is_unique(cmd->start_src);
832 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
833 err |= cfc_check_trigger_is_unique(cmd->convert_src);
834 err |= cfc_check_trigger_is_unique(cmd->stop_src);
835
836 /* Step 2b : and mutually compatible */
59c7dd3d 837
59c7dd3d 838 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
27020ffe 839 err |= -EINVAL;
59c7dd3d 840 if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
27020ffe 841 err |= -EINVAL;
59c7dd3d 842 if (cmd->start_src == TRIG_EXT &&
0a85b6f0 843 (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
27020ffe 844 err |= -EINVAL;
59c7dd3d
IM
845
846 if (err)
847 return 2;
848
0c4ef0b9 849 /* step 3: arguments are trivially compatible */
59c7dd3d 850
f1bc4343
BD
851 switch (cmd->start_src) {
852 case TRIG_EXT:
853 /* External trigger, only CR_EDGE and CR_INVERT flags allowed */
854 if ((cmd->start_arg
855 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
00d9c8cb
HS
856 cmd->start_arg &= ~(CR_FLAGS_MASK &
857 ~(CR_EDGE | CR_INVERT));
858 err |= -EINVAL;
f1bc4343 859 }
23e3cce3 860 if (!thisboard->is_1602 && (cmd->start_arg & CR_INVERT)) {
f1bc4343 861 cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT);
00d9c8cb 862 err |= -EINVAL;
f1bc4343
BD
863 }
864 break;
865 default:
00d9c8cb 866 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
f1bc4343 867 break;
59c7dd3d
IM
868 }
869
00d9c8cb
HS
870 if (cmd->scan_begin_src == TRIG_TIMER)
871 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
872 thisboard->ai_speed * cmd->chanlist_len);
59c7dd3d 873
00d9c8cb
HS
874 if (cmd->convert_src == TRIG_TIMER)
875 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
876 thisboard->ai_speed);
877
878 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
879
880 if (cmd->stop_src == TRIG_NONE)
881 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
882
883 if (err)
884 return 3;
885
886 /* step 4: fix up any arguments */
887
888 if (cmd->scan_begin_src == TRIG_TIMER) {
889 tmp = cmd->scan_begin_arg;
cb9cfd7e
HS
890 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
891 &devpriv->divisor1,
892 &devpriv->divisor2,
893 &cmd->scan_begin_arg, cmd->flags);
59c7dd3d
IM
894 if (tmp != cmd->scan_begin_arg)
895 err++;
896 }
897 if (cmd->convert_src == TRIG_TIMER) {
898 tmp = cmd->convert_arg;
cb9cfd7e
HS
899 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
900 &devpriv->divisor1,
901 &devpriv->divisor2,
902 &cmd->convert_arg, cmd->flags);
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
cb9cfd7e
HS
940 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
941 &devpriv->divisor1, &devpriv->divisor2,
942 ns, rounding_flags);
bb036943
HS
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 1019 bits = 0;
8abc7287 1020 if (cmd->start_src == TRIG_NOW) {
59c7dd3d 1021 bits |= SW_TRIGGER;
8abc7287 1022 } else { /* 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 }
59c7dd3d
IM
1030 }
1031 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
1032 bits |= BURSTE;
1033 outw(bits, devpriv->control_status + TRIG_CONTSTAT);
59c7dd3d
IM
1034
1035 return 0;
1036}
1037
0a85b6f0
MT
1038static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
1039 struct comedi_subdevice *s,
1040 struct comedi_cmd *cmd)
59c7dd3d 1041{
82d8c74d
HS
1042 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1043 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d
IM
1044 int err = 0;
1045 int tmp;
1046
27020ffe 1047 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 1048
27020ffe
HS
1049 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
1050 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
1051 TRIG_TIMER | TRIG_EXT);
1052 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
1053 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1054 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
1055
1056 if (err)
1057 return 1;
1058
27020ffe 1059 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 1060
27020ffe
HS
1061 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
1062 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1063
1064 /* Step 2b : and mutually compatible */
59c7dd3d
IM
1065
1066 if (err)
1067 return 2;
1068
00d9c8cb 1069 /* Step 3: check if arguments are trivially valid */
59c7dd3d 1070
00d9c8cb 1071 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
59c7dd3d 1072
00d9c8cb
HS
1073 if (cmd->scan_begin_src == TRIG_TIMER)
1074 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1075 thisboard->ao_scan_speed);
59c7dd3d 1076
00d9c8cb
HS
1077 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1078
1079 if (cmd->stop_src == TRIG_NONE)
1080 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
1081
1082 if (err)
1083 return 3;
1084
1085 /* step 4: fix up any arguments */
1086
1087 if (cmd->scan_begin_src == TRIG_TIMER) {
1088 tmp = cmd->scan_begin_arg;
cb9cfd7e
HS
1089 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
1090 &devpriv->ao_divisor1,
1091 &devpriv->ao_divisor2,
1092 &cmd->scan_begin_arg, cmd->flags);
59c7dd3d
IM
1093 if (tmp != cmd->scan_begin_arg)
1094 err++;
1095 }
1096
1097 if (err)
1098 return 4;
1099
cf530aa4 1100 /* check channel/gain list against card's limitations */
59c7dd3d
IM
1101 if (cmd->chanlist && cmd->chanlist_len > 1) {
1102 if (CR_CHAN(cmd->chanlist[0]) != 0 ||
0a85b6f0 1103 CR_CHAN(cmd->chanlist[1]) != 1) {
59c7dd3d 1104 comedi_error(dev,
0a85b6f0 1105 "channels must be ordered channel 0, channel 1 in chanlist\n");
59c7dd3d
IM
1106 err++;
1107 }
1108 }
1109
1110 if (err)
1111 return 5;
1112
1113 return 0;
1114}
1115
9a0f7631
HS
1116/* cancel analog input command */
1117static int cb_pcidas_cancel(struct comedi_device *dev,
1118 struct comedi_subdevice *s)
1119{
82d8c74d 1120 struct cb_pcidas_private *devpriv = dev->private;
9a0f7631
HS
1121 unsigned long flags;
1122
1123 spin_lock_irqsave(&dev->spinlock, flags);
1124 /* disable interrupts */
1125 devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
1126 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1127 spin_unlock_irqrestore(&dev->spinlock, flags);
1128
1129 /* disable start trigger source and burst mode */
1130 outw(0, devpriv->control_status + TRIG_CONTSTAT);
1131 /* software pacer source */
1132 outw(0, devpriv->control_status + ADCMUX_CONT);
1133
1134 return 0;
1135}
1136
1706fcc1
HS
1137static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1138 struct comedi_subdevice *s,
1139 unsigned int trig_num)
1140{
82d8c74d
HS
1141 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1142 struct cb_pcidas_private *devpriv = dev->private;
1706fcc1
HS
1143 unsigned int num_bytes, num_points = thisboard->fifo_size;
1144 struct comedi_async *async = s->async;
1145 struct comedi_cmd *cmd = &s->async->cmd;
1146 unsigned long flags;
1147
1148 if (trig_num != 0)
1149 return -EINVAL;
1150
1151 /* load up fifo */
1152 if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points)
1153 num_points = devpriv->ao_count;
1154
1155 num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1156 num_points * sizeof(short));
1157 num_points = num_bytes / sizeof(short);
1158
1159 if (cmd->stop_src == TRIG_COUNT)
1160 devpriv->ao_count -= num_points;
1161 /* write data to board's fifo */
1162 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes);
1163
1164 /* enable dac half-full and empty interrupts */
1165 spin_lock_irqsave(&dev->spinlock, flags);
1166 devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
193debd1 1167
1706fcc1
HS
1168 /* enable and clear interrupts */
1169 outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
1170 devpriv->control_status + INT_ADCFIFO);
1171
1172 /* start dac */
1173 devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
1174 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
193debd1 1175
1706fcc1
HS
1176 spin_unlock_irqrestore(&dev->spinlock, flags);
1177
1178 async->inttrig = NULL;
1179
1180 return 0;
1181}
1182
0a85b6f0
MT
1183static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1184 struct comedi_subdevice *s)
59c7dd3d 1185{
82d8c74d 1186 struct cb_pcidas_private *devpriv = dev->private;
d163679c 1187 struct comedi_async *async = s->async;
ea6d0d4c 1188 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
1189 unsigned int i;
1190 unsigned long flags;
1191
cf530aa4 1192 /* set channel limits, gain */
5f74ea14 1193 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1194 for (i = 0; i < cmd->chanlist_len; i++) {
cf530aa4 1195 /* enable channel */
59c7dd3d 1196 devpriv->ao_control_bits |=
0a85b6f0 1197 DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
cf530aa4 1198 /* set range */
59c7dd3d 1199 devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
0a85b6f0
MT
1200 CR_RANGE(cmd->
1201 chanlist[i]));
59c7dd3d
IM
1202 }
1203
cf530aa4 1204 /* disable analog out before settings pacer source and count values */
59c7dd3d 1205 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 1206 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1207
cf530aa4 1208 /* clear fifo */
59c7dd3d
IM
1209 outw(0, devpriv->ao_registers + DACFIFOCLR);
1210
cf530aa4 1211 /* load counters */
59c7dd3d 1212 if (cmd->scan_begin_src == TRIG_TIMER) {
cb9cfd7e
HS
1213 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
1214 &devpriv->ao_divisor1,
1215 &devpriv->ao_divisor2,
1216 &cmd->scan_begin_arg, cmd->flags);
59c7dd3d
IM
1217
1218 /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
1219 i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1,
0a85b6f0 1220 devpriv->ao_divisor1, 2);
59c7dd3d 1221 i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2,
0a85b6f0 1222 devpriv->ao_divisor2, 2);
59c7dd3d 1223 }
cf530aa4 1224 /* set number of conversions */
2d238b29 1225 if (cmd->stop_src == TRIG_COUNT)
59c7dd3d 1226 devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
cf530aa4 1227 /* set pacer source */
5f74ea14 1228 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
1229 switch (cmd->scan_begin_src) {
1230 case TRIG_TIMER:
1231 devpriv->ao_control_bits |= DAC_PACER_INT;
1232 break;
1233 case TRIG_EXT:
1234 devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
1235 break;
1236 default:
5f74ea14 1237 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1238 comedi_error(dev, "error setting dac pacer source");
1239 return -1;
1240 break;
1241 }
5f74ea14 1242 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1243
1244 async->inttrig = cb_pcidas_ao_inttrig;
1245
1246 return 0;
1247}
1248
0aa20304
HS
1249/* cancel analog output command */
1250static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1251 struct comedi_subdevice *s)
1252{
82d8c74d 1253 struct cb_pcidas_private *devpriv = dev->private;
0aa20304
HS
1254 unsigned long flags;
1255
1256 spin_lock_irqsave(&dev->spinlock, flags);
1257 /* disable interrupts */
1258 devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
1259 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1260
1261 /* disable output */
1262 devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
1263 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1264 spin_unlock_irqrestore(&dev->spinlock, flags);
1265
1266 return 0;
1267}
1268
9e11d05f
HS
1269static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
1270{
82d8c74d
HS
1271 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1272 struct cb_pcidas_private *devpriv = dev->private;
9e11d05f
HS
1273 struct comedi_subdevice *s = dev->write_subdev;
1274 struct comedi_async *async = s->async;
1275 struct comedi_cmd *cmd = &async->cmd;
1276 unsigned int half_fifo = thisboard->fifo_size / 2;
1277 unsigned int num_points;
1278 unsigned long flags;
1279
9e11d05f
HS
1280 if (status & DAEMI) {
1281 /* clear dac empty interrupt latch */
1282 spin_lock_irqsave(&dev->spinlock, flags);
1283 outw(devpriv->adc_fifo_bits | DAEMI,
1284 devpriv->control_status + INT_ADCFIFO);
1285 spin_unlock_irqrestore(&dev->spinlock, flags);
1286 if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
1287 if (cmd->stop_src == TRIG_NONE ||
1288 (cmd->stop_src == TRIG_COUNT
1289 && devpriv->ao_count)) {
1290 comedi_error(dev, "dac fifo underflow");
9e11d05f
HS
1291 async->events |= COMEDI_CB_ERROR;
1292 }
1293 async->events |= COMEDI_CB_EOA;
1294 }
1295 } else if (status & DAHFI) {
1296 unsigned int num_bytes;
1297
1298 /* figure out how many points we are writing to fifo */
1299 num_points = half_fifo;
1300 if (cmd->stop_src == TRIG_COUNT &&
1301 devpriv->ao_count < num_points)
1302 num_points = devpriv->ao_count;
1303 num_bytes =
1304 cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1305 num_points * sizeof(short));
1306 num_points = num_bytes / sizeof(short);
1307
1308 if (async->cmd.stop_src == TRIG_COUNT)
1309 devpriv->ao_count -= num_points;
1310 /* write data to board's fifo */
1311 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
1312 num_points);
1313 /* clear half-full interrupt latch */
1314 spin_lock_irqsave(&dev->spinlock, flags);
1315 outw(devpriv->adc_fifo_bits | DAHFI,
1316 devpriv->control_status + INT_ADCFIFO);
1317 spin_unlock_irqrestore(&dev->spinlock, flags);
1318 }
1319
38255b62 1320 cfc_handle_events(dev, s);
9e11d05f
HS
1321}
1322
70265d24 1323static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
59c7dd3d 1324{
0a85b6f0 1325 struct comedi_device *dev = (struct comedi_device *)d;
82d8c74d
HS
1326 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1327 struct cb_pcidas_private *devpriv = dev->private;
34c43922 1328 struct comedi_subdevice *s = dev->read_subdev;
d163679c 1329 struct comedi_async *async;
59c7dd3d
IM
1330 int status, s5933_status;
1331 int half_fifo = thisboard->fifo_size / 2;
1332 unsigned int num_samples, i;
1333 static const int timeout = 10000;
1334 unsigned long flags;
1335
a7401cdd 1336 if (!dev->attached)
59c7dd3d 1337 return IRQ_NONE;
59c7dd3d
IM
1338
1339 async = s->async;
59c7dd3d
IM
1340
1341 s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1342
1343 if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
1344 return IRQ_NONE;
1345
cf530aa4 1346 /* make sure mailbox 4 is empty */
59c7dd3d 1347 inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
cf530aa4 1348 /* clear interrupt on amcc s5933 */
59c7dd3d 1349 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
0a85b6f0 1350 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1351
1352 status = inw(devpriv->control_status + INT_ADCFIFO);
59c7dd3d 1353
cf530aa4 1354 /* check for analog output interrupt */
2d238b29 1355 if (status & (DAHFI | DAEMI))
59c7dd3d 1356 handle_ao_interrupt(dev, status);
cf530aa4
BP
1357 /* check for analog input interrupts */
1358 /* if fifo half-full */
59c7dd3d 1359 if (status & ADHFI) {
cf530aa4 1360 /* read data */
59c7dd3d
IM
1361 num_samples = half_fifo;
1362 if (async->cmd.stop_src == TRIG_COUNT &&
0a85b6f0 1363 num_samples > devpriv->count) {
59c7dd3d
IM
1364 num_samples = devpriv->count;
1365 }
1366 insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
0a85b6f0 1367 num_samples);
59c7dd3d 1368 cfc_write_array_to_buffer(s, devpriv->ai_buffer,
0a85b6f0 1369 num_samples * sizeof(short));
59c7dd3d 1370 devpriv->count -= num_samples;
38255b62 1371 if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0)
59c7dd3d 1372 async->events |= COMEDI_CB_EOA;
cf530aa4 1373 /* clear half-full interrupt latch */
5f74ea14 1374 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1375 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1376 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1377 spin_unlock_irqrestore(&dev->spinlock, flags);
cf530aa4 1378 /* else if fifo not empty */
59c7dd3d
IM
1379 } else if (status & (ADNEI | EOBI)) {
1380 for (i = 0; i < timeout; i++) {
cf530aa4 1381 /* break if fifo is empty */
59c7dd3d 1382 if ((ADNE & inw(devpriv->control_status +
0a85b6f0 1383 INT_ADCFIFO)) == 0)
59c7dd3d
IM
1384 break;
1385 cfc_write_to_buffer(s, inw(devpriv->adc_fifo));
55acaf2d
HS
1386 if (async->cmd.stop_src == TRIG_COUNT &&
1387 --devpriv->count == 0) {
1388 /* end of acquisition */
59c7dd3d
IM
1389 async->events |= COMEDI_CB_EOA;
1390 break;
1391 }
1392 }
cf530aa4 1393 /* clear not-empty interrupt latch */
5f74ea14 1394 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1395 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1396 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1397 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1398 } else if (status & EOAI) {
1399 comedi_error(dev,
25985edc 1400 "bug! encountered end of acquisition interrupt?");
cf530aa4 1401 /* clear EOA interrupt latch */
5f74ea14 1402 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1403 outw(devpriv->adc_fifo_bits | EOAI,
0a85b6f0 1404 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1405 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1406 }
cf530aa4 1407 /* check for fifo overflow */
59c7dd3d
IM
1408 if (status & LADFUL) {
1409 comedi_error(dev, "fifo overflow");
cf530aa4 1410 /* clear overflow interrupt latch */
5f74ea14 1411 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1412 outw(devpriv->adc_fifo_bits | LADFUL,
0a85b6f0 1413 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1414 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1415 async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
1416 }
1417
38255b62 1418 cfc_handle_events(dev, s);
59c7dd3d
IM
1419
1420 return IRQ_HANDLED;
1421}
1422
a690b7e5 1423static int cb_pcidas_auto_attach(struct comedi_device *dev,
9b315bcb 1424 unsigned long context)
327be979 1425{
750af5e5 1426 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
9b315bcb 1427 const struct cb_pcidas_board *thisboard = NULL;
327be979
HS
1428 struct cb_pcidas_private *devpriv;
1429 struct comedi_subdevice *s;
1430 int i;
1431 int ret;
e74f209c 1432
9b315bcb
HS
1433 if (context < ARRAY_SIZE(cb_pcidas_boards))
1434 thisboard = &cb_pcidas_boards[context];
3b96f250
HS
1435 if (!thisboard)
1436 return -ENODEV;
1437 dev->board_ptr = thisboard;
1438 dev->board_name = thisboard->name;
1439
0bdab509 1440 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
1441 if (!devpriv)
1442 return -ENOMEM;
3b96f250 1443
818f569f 1444 ret = comedi_pci_enable(dev);
3b96f250
HS
1445 if (ret)
1446 return ret;
7302abef 1447
ba36b9ba
HS
1448 devpriv->s5933_config = pci_resource_start(pcidev, 0);
1449 devpriv->control_status = pci_resource_start(pcidev, 1);
1450 devpriv->adc_fifo = pci_resource_start(pcidev, 2);
1451 devpriv->pacer_counter_dio = pci_resource_start(pcidev, 3);
7302abef 1452 if (thisboard->ao_nchan)
ba36b9ba 1453 devpriv->ao_registers = pci_resource_start(pcidev, 4);
7302abef 1454
e74f209c
HS
1455 /* disable and clear interrupts on amcc s5933 */
1456 outl(INTCSR_INBOX_INTR_STATUS,
1457 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1458
ba36b9ba 1459 if (request_irq(pcidev->irq, cb_pcidas_interrupt,
0a5aed48 1460 IRQF_SHARED, dev->driver->driver_name, dev)) {
e74f209c 1461 dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
ba36b9ba 1462 pcidev->irq);
e74f209c
HS
1463 return -EINVAL;
1464 }
ba36b9ba 1465 dev->irq = pcidev->irq;
e74f209c 1466
e74f209c
HS
1467 ret = comedi_alloc_subdevices(dev, 7);
1468 if (ret)
1469 return ret;
1470
e89c61b9 1471 s = &dev->subdevices[0];
e74f209c
HS
1472 /* analog input subdevice */
1473 dev->read_subdev = s;
1474 s->type = COMEDI_SUBD_AI;
1475 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
1476 /* WARNING: Number of inputs in differential mode is ignored */
8f608fc8
HS
1477 s->n_chan = thisboard->ai_nchan;
1478 s->len_chanlist = thisboard->ai_nchan;
e74f209c
HS
1479 s->maxdata = (1 << thisboard->ai_bits) - 1;
1480 s->range_table = thisboard->ranges;
1481 s->insn_read = cb_pcidas_ai_rinsn;
1482 s->insn_config = ai_config_insn;
1483 s->do_cmd = cb_pcidas_ai_cmd;
1484 s->do_cmdtest = cb_pcidas_ai_cmdtest;
1485 s->cancel = cb_pcidas_cancel;
1486
1487 /* analog output subdevice */
e89c61b9 1488 s = &dev->subdevices[1];
e74f209c
HS
1489 if (thisboard->ao_nchan) {
1490 s->type = COMEDI_SUBD_AO;
1491 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
1492 s->n_chan = thisboard->ao_nchan;
55acaf2d
HS
1493 /*
1494 * analog out resolution is the same as
1495 * analog input resolution, so use ai_bits
1496 */
e74f209c
HS
1497 s->maxdata = (1 << thisboard->ai_bits) - 1;
1498 s->range_table = &cb_pcidas_ao_ranges;
1499 s->insn_read = cb_pcidas_ao_readback_insn;
1500 if (thisboard->has_ao_fifo) {
1501 dev->write_subdev = s;
1502 s->subdev_flags |= SDF_CMD_WRITE;
1503 s->insn_write = cb_pcidas_ao_fifo_winsn;
1504 s->do_cmdtest = cb_pcidas_ao_cmdtest;
1505 s->do_cmd = cb_pcidas_ao_cmd;
1506 s->cancel = cb_pcidas_ao_cancel;
1507 } else {
1508 s->insn_write = cb_pcidas_ao_nofifo_winsn;
1509 }
1510 } else {
1511 s->type = COMEDI_SUBD_UNUSED;
1512 }
1513
1514 /* 8255 */
e89c61b9 1515 s = &dev->subdevices[2];
4f0036ef
HS
1516 ret = subdev_8255_init(dev, s, NULL,
1517 devpriv->pacer_counter_dio + DIO_8255);
1518 if (ret)
1519 return ret;
e74f209c
HS
1520
1521 /* serial EEPROM, */
e89c61b9 1522 s = &dev->subdevices[3];
e74f209c
HS
1523 s->type = COMEDI_SUBD_MEMORY;
1524 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1525 s->n_chan = 256;
1526 s->maxdata = 0xff;
1527 s->insn_read = eeprom_read_insn;
1528
1529 /* 8800 caldac */
e89c61b9 1530 s = &dev->subdevices[4];
e74f209c
HS
1531 s->type = COMEDI_SUBD_CALIB;
1532 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1533 s->n_chan = NUM_CHANNELS_8800;
1534 s->maxdata = 0xff;
1535 s->insn_read = caldac_read_insn;
1536 s->insn_write = caldac_write_insn;
1537 for (i = 0; i < s->n_chan; i++)
1538 caldac_8800_write(dev, i, s->maxdata / 2);
1539
1540 /* trim potentiometer */
e89c61b9 1541 s = &dev->subdevices[5];
e74f209c
HS
1542 s->type = COMEDI_SUBD_CALIB;
1543 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1544 if (thisboard->trimpot == AD7376) {
1545 s->n_chan = NUM_CHANNELS_7376;
1546 s->maxdata = 0x7f;
1547 } else {
1548 s->n_chan = NUM_CHANNELS_8402;
1549 s->maxdata = 0xff;
1550 }
1551 s->insn_read = trimpot_read_insn;
1552 s->insn_write = trimpot_write_insn;
1553 for (i = 0; i < s->n_chan; i++)
1554 cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
1555
1556 /* dac08 caldac */
e89c61b9 1557 s = &dev->subdevices[6];
e74f209c
HS
1558 if (thisboard->has_dac08) {
1559 s->type = COMEDI_SUBD_CALIB;
1560 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1561 s->n_chan = NUM_CHANNELS_DAC08;
1562 s->insn_read = dac08_read_insn;
1563 s->insn_write = dac08_write_insn;
1564 s->maxdata = 0xff;
1565 dac08_write(dev, s->maxdata / 2);
1566 } else
1567 s->type = COMEDI_SUBD_UNUSED;
1568
1569 /* make sure mailbox 4 is empty */
1570 inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1571 /* Set bits to enable incoming mailbox interrupts on amcc s5933. */
1572 devpriv->s5933_intcsr_bits =
1573 INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1574 INTCSR_INBOX_FULL_INT;
1575 /* clear and enable interrupt on amcc s5933 */
1576 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1577 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1578
3b96f250 1579 return 0;
e74f209c
HS
1580}
1581
1582static void cb_pcidas_detach(struct comedi_device *dev)
1583{
82d8c74d
HS
1584 struct cb_pcidas_private *devpriv = dev->private;
1585
e74f209c
HS
1586 if (devpriv) {
1587 if (devpriv->s5933_config) {
1588 outl(INTCSR_INBOX_INTR_STATUS,
1589 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1590 }
1591 }
1592 if (dev->irq)
1593 free_irq(dev->irq, dev);
7f072f54 1594 comedi_pci_disable(dev);
e74f209c
HS
1595}
1596
715b2284
HS
1597static struct comedi_driver cb_pcidas_driver = {
1598 .driver_name = "cb_pcidas",
1599 .module = THIS_MODULE,
750af5e5 1600 .auto_attach = cb_pcidas_auto_attach,
715b2284
HS
1601 .detach = cb_pcidas_detach,
1602};
1603
a690b7e5 1604static int cb_pcidas_pci_probe(struct pci_dev *dev,
b8f4ac23 1605 const struct pci_device_id *id)
727b286b 1606{
b8f4ac23
HS
1607 return comedi_pci_auto_config(dev, &cb_pcidas_driver,
1608 id->driver_data);
727b286b
AT
1609}
1610
41e043fc 1611static const struct pci_device_id cb_pcidas_pci_table[] = {
9b315bcb
HS
1612 { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
1613 { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
1614 { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
1615 { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
1616 { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
1617 { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
1618 { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
1619 { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
715b2284 1620 { 0 }
727b286b 1621};
715b2284 1622MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
727b286b 1623
715b2284
HS
1624static struct pci_driver cb_pcidas_pci_driver = {
1625 .name = "cb_pcidas",
1626 .id_table = cb_pcidas_pci_table,
1627 .probe = cb_pcidas_pci_probe,
9901a4d7 1628 .remove = comedi_pci_auto_unconfig,
715b2284
HS
1629};
1630module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
90f703d3
AT
1631
1632MODULE_AUTHOR("Comedi http://www.comedi.org");
1633MODULE_DESCRIPTION("Comedi low-level driver");
1634MODULE_LICENSE("GPL");
This page took 0.635412 seconds and 5 git commands to generate.