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