]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/staging/comedi/drivers/cb_pcidas.c
staging: comedi: amplc_pci230: use comedi_cmd pointer
[mirror_ubuntu-hirsute-kernel.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 839 int err = 0;
815bb5b5 840 unsigned int arg;
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) {
815bb5b5 915 arg = cmd->scan_begin_arg;
cb9cfd7e
HS
916 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
917 &devpriv->divisor1,
918 &devpriv->divisor2,
815bb5b5
HS
919 &arg, cmd->flags);
920 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
59c7dd3d
IM
921 }
922 if (cmd->convert_src == TRIG_TIMER) {
815bb5b5 923 arg = cmd->convert_arg;
cb9cfd7e
HS
924 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
925 &devpriv->divisor1,
926 &devpriv->divisor2,
815bb5b5
HS
927 &arg, cmd->flags);
928 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
59c7dd3d
IM
929 }
930
931 if (err)
932 return 4;
933
e74592e0
HS
934 /* Step 5: check channel list if it exists */
935 if (cmd->chanlist && cmd->chanlist_len > 0)
936 err |= cb_pcidas_ai_check_chanlist(dev, s, cmd);
59c7dd3d
IM
937
938 if (err)
939 return 5;
940
941 return 0;
942}
943
33eafb77 944static void cb_pcidas_ai_load_counters(struct comedi_device *dev)
bb036943 945{
82d8c74d 946 struct cb_pcidas_private *devpriv = dev->private;
f513b63f 947 unsigned long timer_base = devpriv->pacer_counter_dio + ADC8254;
82d8c74d 948
f513b63f
HS
949 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
950 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
bb036943 951
f513b63f
HS
952 i8254_write(timer_base, 0, 1, devpriv->divisor1);
953 i8254_write(timer_base, 0, 2, devpriv->divisor2);
bb036943
HS
954}
955
0a85b6f0
MT
956static int cb_pcidas_ai_cmd(struct comedi_device *dev,
957 struct comedi_subdevice *s)
59c7dd3d 958{
82d8c74d
HS
959 const struct cb_pcidas_board *thisboard = comedi_board(dev);
960 struct cb_pcidas_private *devpriv = dev->private;
d163679c 961 struct comedi_async *async = s->async;
ea6d0d4c 962 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
963 unsigned int bits;
964 unsigned long flags;
965
cf530aa4 966 /* make sure CAL_EN_BIT is disabled */
59c7dd3d 967 outw(0, devpriv->control_status + CALIBRATION_REG);
cf530aa4 968 /* initialize before settings pacer source and count values */
59c7dd3d 969 outw(0, devpriv->control_status + TRIG_CONTSTAT);
cf530aa4 970 /* clear fifo */
59c7dd3d
IM
971 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
972
cf530aa4 973 /* set mux limits, gain and pacer source */
59c7dd3d 974 bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) |
0a85b6f0
MT
975 END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
976 GAIN_BITS(CR_RANGE(cmd->chanlist[0]));
cf530aa4 977 /* set unipolar/bipolar */
59c7dd3d
IM
978 if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR)
979 bits |= UNIP;
cf530aa4 980 /* set singleended/differential */
59c7dd3d
IM
981 if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
982 bits |= SE;
cf530aa4 983 /* set pacer source */
59c7dd3d
IM
984 if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
985 bits |= PACER_EXT_RISE;
986 else
987 bits |= PACER_INT;
988 outw(bits, devpriv->control_status + ADCMUX_CONT);
989
cf530aa4 990 /* load counters */
f513b63f 991 if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER)
33eafb77 992 cb_pcidas_ai_load_counters(dev);
59c7dd3d 993
cf530aa4 994 /* set number of conversions */
2d238b29 995 if (cmd->stop_src == TRIG_COUNT)
59c7dd3d 996 devpriv->count = cmd->chanlist_len * cmd->stop_arg;
cf530aa4 997 /* enable interrupts */
5f74ea14 998 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
999 devpriv->adc_fifo_bits |= INTE;
1000 devpriv->adc_fifo_bits &= ~INT_MASK;
1001 if (cmd->flags & TRIG_WAKE_EOS) {
55acaf2d
HS
1002 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
1003 /* interrupt end of burst */
1004 devpriv->adc_fifo_bits |= INT_EOS;
1005 } else {
1006 /* interrupt fifo not empty */
1007 devpriv->adc_fifo_bits |= INT_FNE;
1008 }
59c7dd3d 1009 } else {
55acaf2d
HS
1010 /* interrupt fifo half full */
1011 devpriv->adc_fifo_bits |= INT_FHF;
59c7dd3d 1012 }
193debd1 1013
cf530aa4 1014 /* enable (and clear) interrupts */
59c7dd3d 1015 outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL,
0a85b6f0 1016 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1017 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1018
cf530aa4 1019 /* set start trigger and burst mode */
59c7dd3d 1020 bits = 0;
8abc7287 1021 if (cmd->start_src == TRIG_NOW) {
59c7dd3d 1022 bits |= SW_TRIGGER;
8abc7287 1023 } else { /* TRIG_EXT */
59c7dd3d 1024 bits |= EXT_TRIGGER | TGEN | XTRCL;
23e3cce3 1025 if (thisboard->is_1602) {
93c58378 1026 if (cmd->start_arg & CR_INVERT)
23e3cce3
HS
1027 bits |= TGPOL;
1028 if (cmd->start_arg & CR_EDGE)
1029 bits |= TGSEL;
1030 }
59c7dd3d
IM
1031 }
1032 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
1033 bits |= BURSTE;
1034 outw(bits, devpriv->control_status + TRIG_CONTSTAT);
59c7dd3d
IM
1035
1036 return 0;
1037}
1038
e74592e0
HS
1039static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev,
1040 struct comedi_subdevice *s,
1041 struct comedi_cmd *cmd)
1042{
1043 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
1044
1045 if (cmd->chanlist_len > 1) {
1046 unsigned int chan1 = CR_CHAN(cmd->chanlist[1]);
1047
1048 if (chan0 != 0 || chan1 != 1) {
1049 dev_dbg(dev->class_dev,
1050 "channels must be ordered channel 0, channel 1 in chanlist\n");
1051 return -EINVAL;
1052 }
1053 }
1054
1055 return 0;
1056}
1057
0a85b6f0
MT
1058static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
1059 struct comedi_subdevice *s,
1060 struct comedi_cmd *cmd)
59c7dd3d 1061{
82d8c74d
HS
1062 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1063 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 1064 int err = 0;
815bb5b5 1065 unsigned int arg;
59c7dd3d 1066
27020ffe 1067 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 1068
27020ffe
HS
1069 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
1070 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
1071 TRIG_TIMER | TRIG_EXT);
1072 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
1073 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1074 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
1075
1076 if (err)
1077 return 1;
1078
27020ffe 1079 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 1080
27020ffe
HS
1081 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
1082 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1083
1084 /* Step 2b : and mutually compatible */
59c7dd3d
IM
1085
1086 if (err)
1087 return 2;
1088
00d9c8cb 1089 /* Step 3: check if arguments are trivially valid */
59c7dd3d 1090
00d9c8cb 1091 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
59c7dd3d 1092
00d9c8cb
HS
1093 if (cmd->scan_begin_src == TRIG_TIMER)
1094 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1095 thisboard->ao_scan_speed);
59c7dd3d 1096
00d9c8cb
HS
1097 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1098
1099 if (cmd->stop_src == TRIG_NONE)
1100 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
1101
1102 if (err)
1103 return 3;
1104
1105 /* step 4: fix up any arguments */
1106
1107 if (cmd->scan_begin_src == TRIG_TIMER) {
815bb5b5 1108 arg = cmd->scan_begin_arg;
cb9cfd7e
HS
1109 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
1110 &devpriv->ao_divisor1,
1111 &devpriv->ao_divisor2,
815bb5b5
HS
1112 &arg, cmd->flags);
1113 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
59c7dd3d
IM
1114 }
1115
1116 if (err)
1117 return 4;
1118
e74592e0
HS
1119 /* Step 5: check channel list if it exists */
1120 if (cmd->chanlist && cmd->chanlist_len > 0)
1121 err |= cb_pcidas_ao_check_chanlist(dev, s, cmd);
59c7dd3d
IM
1122
1123 if (err)
1124 return 5;
1125
1126 return 0;
1127}
1128
9a0f7631
HS
1129/* cancel analog input command */
1130static int cb_pcidas_cancel(struct comedi_device *dev,
1131 struct comedi_subdevice *s)
1132{
82d8c74d 1133 struct cb_pcidas_private *devpriv = dev->private;
9a0f7631
HS
1134 unsigned long flags;
1135
1136 spin_lock_irqsave(&dev->spinlock, flags);
1137 /* disable interrupts */
1138 devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
1139 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1140 spin_unlock_irqrestore(&dev->spinlock, flags);
1141
1142 /* disable start trigger source and burst mode */
1143 outw(0, devpriv->control_status + TRIG_CONTSTAT);
1144 /* software pacer source */
1145 outw(0, devpriv->control_status + ADCMUX_CONT);
1146
1147 return 0;
1148}
1149
1706fcc1
HS
1150static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1151 struct comedi_subdevice *s,
1152 unsigned int trig_num)
1153{
82d8c74d
HS
1154 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1155 struct cb_pcidas_private *devpriv = dev->private;
1706fcc1
HS
1156 unsigned int num_bytes, num_points = thisboard->fifo_size;
1157 struct comedi_async *async = s->async;
1158 struct comedi_cmd *cmd = &s->async->cmd;
1159 unsigned long flags;
1160
384e483f 1161 if (trig_num != cmd->start_arg)
1706fcc1
HS
1162 return -EINVAL;
1163
1164 /* load up fifo */
1165 if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points)
1166 num_points = devpriv->ao_count;
1167
1168 num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1169 num_points * sizeof(short));
1170 num_points = num_bytes / sizeof(short);
1171
1172 if (cmd->stop_src == TRIG_COUNT)
1173 devpriv->ao_count -= num_points;
1174 /* write data to board's fifo */
1175 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes);
1176
1177 /* enable dac half-full and empty interrupts */
1178 spin_lock_irqsave(&dev->spinlock, flags);
1179 devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
193debd1 1180
1706fcc1
HS
1181 /* enable and clear interrupts */
1182 outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
1183 devpriv->control_status + INT_ADCFIFO);
1184
1185 /* start dac */
1186 devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
1187 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
193debd1 1188
1706fcc1
HS
1189 spin_unlock_irqrestore(&dev->spinlock, flags);
1190
1191 async->inttrig = NULL;
1192
1193 return 0;
1194}
1195
33eafb77
HS
1196static void cb_pcidas_ao_load_counters(struct comedi_device *dev)
1197{
1198 struct cb_pcidas_private *devpriv = dev->private;
1199 unsigned long timer_base = devpriv->pacer_counter_dio + DAC8254;
1200
1201 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
1202 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
1203
1204 i8254_write(timer_base, 0, 1, devpriv->ao_divisor1);
1205 i8254_write(timer_base, 0, 2, devpriv->ao_divisor2);
1206}
1207
0a85b6f0
MT
1208static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1209 struct comedi_subdevice *s)
59c7dd3d 1210{
82d8c74d 1211 struct cb_pcidas_private *devpriv = dev->private;
d163679c 1212 struct comedi_async *async = s->async;
ea6d0d4c 1213 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
1214 unsigned int i;
1215 unsigned long flags;
1216
cf530aa4 1217 /* set channel limits, gain */
5f74ea14 1218 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1219 for (i = 0; i < cmd->chanlist_len; i++) {
cf530aa4 1220 /* enable channel */
59c7dd3d 1221 devpriv->ao_control_bits |=
0a85b6f0 1222 DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
cf530aa4 1223 /* set range */
59c7dd3d 1224 devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
0a85b6f0
MT
1225 CR_RANGE(cmd->
1226 chanlist[i]));
59c7dd3d
IM
1227 }
1228
cf530aa4 1229 /* disable analog out before settings pacer source and count values */
59c7dd3d 1230 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 1231 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1232
cf530aa4 1233 /* clear fifo */
59c7dd3d
IM
1234 outw(0, devpriv->ao_registers + DACFIFOCLR);
1235
cf530aa4 1236 /* load counters */
33eafb77
HS
1237 if (cmd->scan_begin_src == TRIG_TIMER)
1238 cb_pcidas_ao_load_counters(dev);
59c7dd3d 1239
cf530aa4 1240 /* set number of conversions */
2d238b29 1241 if (cmd->stop_src == TRIG_COUNT)
59c7dd3d 1242 devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
cf530aa4 1243 /* set pacer source */
5f74ea14 1244 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
1245 switch (cmd->scan_begin_src) {
1246 case TRIG_TIMER:
1247 devpriv->ao_control_bits |= DAC_PACER_INT;
1248 break;
1249 case TRIG_EXT:
1250 devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
1251 break;
1252 default:
5f74ea14 1253 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1254 comedi_error(dev, "error setting dac pacer source");
1255 return -1;
1256 break;
1257 }
5f74ea14 1258 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1259
1260 async->inttrig = cb_pcidas_ao_inttrig;
1261
1262 return 0;
1263}
1264
0aa20304
HS
1265/* cancel analog output command */
1266static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1267 struct comedi_subdevice *s)
1268{
82d8c74d 1269 struct cb_pcidas_private *devpriv = dev->private;
0aa20304
HS
1270 unsigned long flags;
1271
1272 spin_lock_irqsave(&dev->spinlock, flags);
1273 /* disable interrupts */
1274 devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
1275 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1276
1277 /* disable output */
1278 devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
1279 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1280 spin_unlock_irqrestore(&dev->spinlock, flags);
1281
1282 return 0;
1283}
1284
9e11d05f
HS
1285static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
1286{
82d8c74d
HS
1287 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1288 struct cb_pcidas_private *devpriv = dev->private;
9e11d05f
HS
1289 struct comedi_subdevice *s = dev->write_subdev;
1290 struct comedi_async *async = s->async;
1291 struct comedi_cmd *cmd = &async->cmd;
1292 unsigned int half_fifo = thisboard->fifo_size / 2;
1293 unsigned int num_points;
1294 unsigned long flags;
1295
9e11d05f
HS
1296 if (status & DAEMI) {
1297 /* clear dac empty interrupt latch */
1298 spin_lock_irqsave(&dev->spinlock, flags);
1299 outw(devpriv->adc_fifo_bits | DAEMI,
1300 devpriv->control_status + INT_ADCFIFO);
1301 spin_unlock_irqrestore(&dev->spinlock, flags);
1302 if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
1303 if (cmd->stop_src == TRIG_NONE ||
1304 (cmd->stop_src == TRIG_COUNT
1305 && devpriv->ao_count)) {
1306 comedi_error(dev, "dac fifo underflow");
9e11d05f
HS
1307 async->events |= COMEDI_CB_ERROR;
1308 }
1309 async->events |= COMEDI_CB_EOA;
1310 }
1311 } else if (status & DAHFI) {
1312 unsigned int num_bytes;
1313
1314 /* figure out how many points we are writing to fifo */
1315 num_points = half_fifo;
1316 if (cmd->stop_src == TRIG_COUNT &&
1317 devpriv->ao_count < num_points)
1318 num_points = devpriv->ao_count;
1319 num_bytes =
1320 cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1321 num_points * sizeof(short));
1322 num_points = num_bytes / sizeof(short);
1323
1324 if (async->cmd.stop_src == TRIG_COUNT)
1325 devpriv->ao_count -= num_points;
1326 /* write data to board's fifo */
1327 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
1328 num_points);
1329 /* clear half-full interrupt latch */
1330 spin_lock_irqsave(&dev->spinlock, flags);
1331 outw(devpriv->adc_fifo_bits | DAHFI,
1332 devpriv->control_status + INT_ADCFIFO);
1333 spin_unlock_irqrestore(&dev->spinlock, flags);
1334 }
1335
38255b62 1336 cfc_handle_events(dev, s);
9e11d05f
HS
1337}
1338
70265d24 1339static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
59c7dd3d 1340{
0a85b6f0 1341 struct comedi_device *dev = (struct comedi_device *)d;
82d8c74d
HS
1342 const struct cb_pcidas_board *thisboard = comedi_board(dev);
1343 struct cb_pcidas_private *devpriv = dev->private;
34c43922 1344 struct comedi_subdevice *s = dev->read_subdev;
d163679c 1345 struct comedi_async *async;
59c7dd3d
IM
1346 int status, s5933_status;
1347 int half_fifo = thisboard->fifo_size / 2;
1348 unsigned int num_samples, i;
1349 static const int timeout = 10000;
1350 unsigned long flags;
1351
a7401cdd 1352 if (!dev->attached)
59c7dd3d 1353 return IRQ_NONE;
59c7dd3d
IM
1354
1355 async = s->async;
59c7dd3d
IM
1356
1357 s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1358
1359 if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
1360 return IRQ_NONE;
1361
cf530aa4 1362 /* make sure mailbox 4 is empty */
59c7dd3d 1363 inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
cf530aa4 1364 /* clear interrupt on amcc s5933 */
59c7dd3d 1365 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
0a85b6f0 1366 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1367
1368 status = inw(devpriv->control_status + INT_ADCFIFO);
59c7dd3d 1369
cf530aa4 1370 /* check for analog output interrupt */
2d238b29 1371 if (status & (DAHFI | DAEMI))
59c7dd3d 1372 handle_ao_interrupt(dev, status);
cf530aa4
BP
1373 /* check for analog input interrupts */
1374 /* if fifo half-full */
59c7dd3d 1375 if (status & ADHFI) {
cf530aa4 1376 /* read data */
59c7dd3d
IM
1377 num_samples = half_fifo;
1378 if (async->cmd.stop_src == TRIG_COUNT &&
0a85b6f0 1379 num_samples > devpriv->count) {
59c7dd3d
IM
1380 num_samples = devpriv->count;
1381 }
1382 insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
0a85b6f0 1383 num_samples);
59c7dd3d 1384 cfc_write_array_to_buffer(s, devpriv->ai_buffer,
0a85b6f0 1385 num_samples * sizeof(short));
59c7dd3d 1386 devpriv->count -= num_samples;
38255b62 1387 if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0)
59c7dd3d 1388 async->events |= COMEDI_CB_EOA;
cf530aa4 1389 /* clear half-full interrupt latch */
5f74ea14 1390 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1391 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1392 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1393 spin_unlock_irqrestore(&dev->spinlock, flags);
cf530aa4 1394 /* else if fifo not empty */
59c7dd3d
IM
1395 } else if (status & (ADNEI | EOBI)) {
1396 for (i = 0; i < timeout; i++) {
cf530aa4 1397 /* break if fifo is empty */
59c7dd3d 1398 if ((ADNE & inw(devpriv->control_status +
0a85b6f0 1399 INT_ADCFIFO)) == 0)
59c7dd3d
IM
1400 break;
1401 cfc_write_to_buffer(s, inw(devpriv->adc_fifo));
55acaf2d
HS
1402 if (async->cmd.stop_src == TRIG_COUNT &&
1403 --devpriv->count == 0) {
1404 /* end of acquisition */
59c7dd3d
IM
1405 async->events |= COMEDI_CB_EOA;
1406 break;
1407 }
1408 }
cf530aa4 1409 /* clear not-empty interrupt latch */
5f74ea14 1410 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1411 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1412 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1413 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1414 } else if (status & EOAI) {
1415 comedi_error(dev,
25985edc 1416 "bug! encountered end of acquisition interrupt?");
cf530aa4 1417 /* clear EOA interrupt latch */
5f74ea14 1418 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1419 outw(devpriv->adc_fifo_bits | EOAI,
0a85b6f0 1420 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1421 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1422 }
cf530aa4 1423 /* check for fifo overflow */
59c7dd3d
IM
1424 if (status & LADFUL) {
1425 comedi_error(dev, "fifo overflow");
cf530aa4 1426 /* clear overflow interrupt latch */
5f74ea14 1427 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1428 outw(devpriv->adc_fifo_bits | LADFUL,
0a85b6f0 1429 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1430 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1431 async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
1432 }
1433
38255b62 1434 cfc_handle_events(dev, s);
59c7dd3d
IM
1435
1436 return IRQ_HANDLED;
1437}
1438
a690b7e5 1439static int cb_pcidas_auto_attach(struct comedi_device *dev,
9b315bcb 1440 unsigned long context)
327be979 1441{
750af5e5 1442 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
9b315bcb 1443 const struct cb_pcidas_board *thisboard = NULL;
327be979
HS
1444 struct cb_pcidas_private *devpriv;
1445 struct comedi_subdevice *s;
1446 int i;
1447 int ret;
e74f209c 1448
9b315bcb
HS
1449 if (context < ARRAY_SIZE(cb_pcidas_boards))
1450 thisboard = &cb_pcidas_boards[context];
3b96f250
HS
1451 if (!thisboard)
1452 return -ENODEV;
1453 dev->board_ptr = thisboard;
1454 dev->board_name = thisboard->name;
1455
0bdab509 1456 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
1457 if (!devpriv)
1458 return -ENOMEM;
3b96f250 1459
818f569f 1460 ret = comedi_pci_enable(dev);
3b96f250
HS
1461 if (ret)
1462 return ret;
7302abef 1463
ba36b9ba
HS
1464 devpriv->s5933_config = pci_resource_start(pcidev, 0);
1465 devpriv->control_status = pci_resource_start(pcidev, 1);
1466 devpriv->adc_fifo = pci_resource_start(pcidev, 2);
1467 devpriv->pacer_counter_dio = pci_resource_start(pcidev, 3);
7302abef 1468 if (thisboard->ao_nchan)
ba36b9ba 1469 devpriv->ao_registers = pci_resource_start(pcidev, 4);
7302abef 1470
e74f209c
HS
1471 /* disable and clear interrupts on amcc s5933 */
1472 outl(INTCSR_INBOX_INTR_STATUS,
1473 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1474
ba36b9ba 1475 if (request_irq(pcidev->irq, cb_pcidas_interrupt,
0a5aed48 1476 IRQF_SHARED, dev->driver->driver_name, dev)) {
e74f209c 1477 dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
ba36b9ba 1478 pcidev->irq);
e74f209c
HS
1479 return -EINVAL;
1480 }
ba36b9ba 1481 dev->irq = pcidev->irq;
e74f209c 1482
e74f209c
HS
1483 ret = comedi_alloc_subdevices(dev, 7);
1484 if (ret)
1485 return ret;
1486
e89c61b9 1487 s = &dev->subdevices[0];
e74f209c
HS
1488 /* analog input subdevice */
1489 dev->read_subdev = s;
1490 s->type = COMEDI_SUBD_AI;
1491 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
1492 /* WARNING: Number of inputs in differential mode is ignored */
8f608fc8
HS
1493 s->n_chan = thisboard->ai_nchan;
1494 s->len_chanlist = thisboard->ai_nchan;
e74f209c
HS
1495 s->maxdata = (1 << thisboard->ai_bits) - 1;
1496 s->range_table = thisboard->ranges;
1497 s->insn_read = cb_pcidas_ai_rinsn;
1498 s->insn_config = ai_config_insn;
1499 s->do_cmd = cb_pcidas_ai_cmd;
1500 s->do_cmdtest = cb_pcidas_ai_cmdtest;
1501 s->cancel = cb_pcidas_cancel;
1502
1503 /* analog output subdevice */
e89c61b9 1504 s = &dev->subdevices[1];
e74f209c
HS
1505 if (thisboard->ao_nchan) {
1506 s->type = COMEDI_SUBD_AO;
1507 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
1508 s->n_chan = thisboard->ao_nchan;
55acaf2d
HS
1509 /*
1510 * analog out resolution is the same as
1511 * analog input resolution, so use ai_bits
1512 */
e74f209c
HS
1513 s->maxdata = (1 << thisboard->ai_bits) - 1;
1514 s->range_table = &cb_pcidas_ao_ranges;
1515 s->insn_read = cb_pcidas_ao_readback_insn;
1516 if (thisboard->has_ao_fifo) {
1517 dev->write_subdev = s;
1518 s->subdev_flags |= SDF_CMD_WRITE;
1519 s->insn_write = cb_pcidas_ao_fifo_winsn;
1520 s->do_cmdtest = cb_pcidas_ao_cmdtest;
1521 s->do_cmd = cb_pcidas_ao_cmd;
1522 s->cancel = cb_pcidas_ao_cancel;
1523 } else {
1524 s->insn_write = cb_pcidas_ao_nofifo_winsn;
1525 }
1526 } else {
1527 s->type = COMEDI_SUBD_UNUSED;
1528 }
1529
1530 /* 8255 */
e89c61b9 1531 s = &dev->subdevices[2];
4f0036ef
HS
1532 ret = subdev_8255_init(dev, s, NULL,
1533 devpriv->pacer_counter_dio + DIO_8255);
1534 if (ret)
1535 return ret;
e74f209c
HS
1536
1537 /* serial EEPROM, */
e89c61b9 1538 s = &dev->subdevices[3];
e74f209c
HS
1539 s->type = COMEDI_SUBD_MEMORY;
1540 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1541 s->n_chan = 256;
1542 s->maxdata = 0xff;
1543 s->insn_read = eeprom_read_insn;
1544
1545 /* 8800 caldac */
e89c61b9 1546 s = &dev->subdevices[4];
e74f209c
HS
1547 s->type = COMEDI_SUBD_CALIB;
1548 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1549 s->n_chan = NUM_CHANNELS_8800;
1550 s->maxdata = 0xff;
1551 s->insn_read = caldac_read_insn;
1552 s->insn_write = caldac_write_insn;
1553 for (i = 0; i < s->n_chan; i++)
1554 caldac_8800_write(dev, i, s->maxdata / 2);
1555
1556 /* trim potentiometer */
e89c61b9 1557 s = &dev->subdevices[5];
e74f209c
HS
1558 s->type = COMEDI_SUBD_CALIB;
1559 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1560 if (thisboard->trimpot == AD7376) {
1561 s->n_chan = NUM_CHANNELS_7376;
1562 s->maxdata = 0x7f;
1563 } else {
1564 s->n_chan = NUM_CHANNELS_8402;
1565 s->maxdata = 0xff;
1566 }
1567 s->insn_read = trimpot_read_insn;
1568 s->insn_write = trimpot_write_insn;
1569 for (i = 0; i < s->n_chan; i++)
1570 cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
1571
1572 /* dac08 caldac */
e89c61b9 1573 s = &dev->subdevices[6];
e74f209c
HS
1574 if (thisboard->has_dac08) {
1575 s->type = COMEDI_SUBD_CALIB;
1576 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1577 s->n_chan = NUM_CHANNELS_DAC08;
1578 s->insn_read = dac08_read_insn;
1579 s->insn_write = dac08_write_insn;
1580 s->maxdata = 0xff;
1581 dac08_write(dev, s->maxdata / 2);
1582 } else
1583 s->type = COMEDI_SUBD_UNUSED;
1584
1585 /* make sure mailbox 4 is empty */
1586 inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1587 /* Set bits to enable incoming mailbox interrupts on amcc s5933. */
1588 devpriv->s5933_intcsr_bits =
1589 INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1590 INTCSR_INBOX_FULL_INT;
1591 /* clear and enable interrupt on amcc s5933 */
1592 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1593 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1594
3b96f250 1595 return 0;
e74f209c
HS
1596}
1597
1598static void cb_pcidas_detach(struct comedi_device *dev)
1599{
82d8c74d
HS
1600 struct cb_pcidas_private *devpriv = dev->private;
1601
e74f209c
HS
1602 if (devpriv) {
1603 if (devpriv->s5933_config) {
1604 outl(INTCSR_INBOX_INTR_STATUS,
1605 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1606 }
1607 }
1608 if (dev->irq)
1609 free_irq(dev->irq, dev);
7f072f54 1610 comedi_pci_disable(dev);
e74f209c
HS
1611}
1612
715b2284
HS
1613static struct comedi_driver cb_pcidas_driver = {
1614 .driver_name = "cb_pcidas",
1615 .module = THIS_MODULE,
750af5e5 1616 .auto_attach = cb_pcidas_auto_attach,
715b2284
HS
1617 .detach = cb_pcidas_detach,
1618};
1619
a690b7e5 1620static int cb_pcidas_pci_probe(struct pci_dev *dev,
b8f4ac23 1621 const struct pci_device_id *id)
727b286b 1622{
b8f4ac23
HS
1623 return comedi_pci_auto_config(dev, &cb_pcidas_driver,
1624 id->driver_data);
727b286b
AT
1625}
1626
41e043fc 1627static const struct pci_device_id cb_pcidas_pci_table[] = {
9b315bcb
HS
1628 { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
1629 { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
1630 { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
1631 { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
1632 { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
1633 { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
1634 { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
1635 { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
715b2284 1636 { 0 }
727b286b 1637};
715b2284 1638MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
727b286b 1639
715b2284
HS
1640static struct pci_driver cb_pcidas_pci_driver = {
1641 .name = "cb_pcidas",
1642 .id_table = cb_pcidas_pci_table,
1643 .probe = cb_pcidas_pci_probe,
9901a4d7 1644 .remove = comedi_pci_auto_unconfig,
715b2284
HS
1645};
1646module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
90f703d3
AT
1647
1648MODULE_AUTHOR("Comedi http://www.comedi.org");
1649MODULE_DESCRIPTION("Comedi low-level driver");
1650MODULE_LICENSE("GPL");