staging: comedi: drivers/*.c: alignment should match open parenthesis
[linux-2.6-block.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
96e56244 71#include "comedi_8254.h"
59c7dd3d
IM
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 {
96e56244 341 struct comedi_8254 *ao_pacer;
0cdfbe15 342 /* base addresses */
59c7dd3d
IM
343 unsigned long s5933_config;
344 unsigned long control_status;
345 unsigned long adc_fifo;
59c7dd3d 346 unsigned long ao_registers;
0cdfbe15
HS
347 /* bits to write to registers */
348 unsigned int adc_fifo_bits;
349 unsigned int s5933_intcsr_bits;
350 unsigned int ao_control_bits;
351 /* fifo buffers */
79e3b119
IA
352 unsigned short ai_buffer[AI_BUFFER_SIZE];
353 unsigned short ao_buffer[AO_BUFFER_SIZE];
59c7dd3d 354 unsigned int calibration_source;
c77e2589 355};
59c7dd3d 356
814900c9 357static inline unsigned int cal_enable_bits(struct comedi_device *dev)
59c7dd3d 358{
82d8c74d
HS
359 struct cb_pcidas_private *devpriv = dev->private;
360
59c7dd3d
IM
361 return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
362}
363
06cb9ba8
HS
364static int cb_pcidas_ai_eoc(struct comedi_device *dev,
365 struct comedi_subdevice *s,
366 struct comedi_insn *insn,
367 unsigned long context)
368{
369 struct cb_pcidas_private *devpriv = dev->private;
370 unsigned int status;
371
372 status = inw(devpriv->control_status + ADCMUX_CONT);
373 if (status & EOC)
374 return 0;
375 return -EBUSY;
376}
377
0a85b6f0
MT
378static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
379 struct comedi_subdevice *s,
380 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 381{
82d8c74d 382 struct cb_pcidas_private *devpriv = dev->private;
f66faa57
HS
383 unsigned int chan = CR_CHAN(insn->chanspec);
384 unsigned int range = CR_RANGE(insn->chanspec);
385 unsigned int aref = CR_AREF(insn->chanspec);
59c7dd3d 386 unsigned int bits;
06cb9ba8
HS
387 int ret;
388 int n;
f66faa57
HS
389
390 /* enable calibration input if appropriate */
59c7dd3d
IM
391 if (insn->chanspec & CR_ALT_SOURCE) {
392 outw(cal_enable_bits(dev),
0a85b6f0 393 devpriv->control_status + CALIBRATION_REG);
f66faa57 394 chan = 0;
59c7dd3d
IM
395 } else {
396 outw(0, devpriv->control_status + CALIBRATION_REG);
59c7dd3d 397 }
f66faa57
HS
398
399 /* set mux limits and gain */
400 bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range);
401 /* set unipolar/bipolar */
402 if (range & IS_UNIPOLAR)
59c7dd3d 403 bits |= UNIP;
f66faa57
HS
404 /* set single-ended/differential */
405 if (aref != AREF_DIFF)
59c7dd3d
IM
406 bits |= SE;
407 outw(bits, devpriv->control_status + ADCMUX_CONT);
408
409 /* clear fifo */
410 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
411
412 /* convert n samples */
413 for (n = 0; n < insn->n; n++) {
414 /* trigger conversion */
415 outw(0, devpriv->adc_fifo + ADCDATA);
416
417 /* wait for conversion to end */
06cb9ba8
HS
418 ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0);
419 if (ret)
420 return ret;
59c7dd3d
IM
421
422 /* read data */
423 data[n] = inw(devpriv->adc_fifo + ADCDATA);
424 }
425
426 /* return the number of samples read/written */
427 return n;
428}
429
da91b269 430static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 431 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 432{
f3c34b2f 433 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 434 int id = data[0];
f3c34b2f 435 unsigned int source = data[1];
59c7dd3d
IM
436
437 switch (id) {
438 case INSN_CONFIG_ALT_SOURCE:
f3c34b2f
HS
439 if (source >= 8) {
440 dev_err(dev->class_dev,
441 "invalid calibration source: %i\n",
442 source);
443 return -EINVAL;
444 }
445 devpriv->calibration_source = source;
59c7dd3d
IM
446 break;
447 default:
448 return -EINVAL;
59c7dd3d 449 }
f3c34b2f 450 return insn->n;
59c7dd3d
IM
451}
452
cf530aa4 453/* analog output insn for pcidas-1000 and 1200 series */
0a85b6f0
MT
454static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev,
455 struct comedi_subdevice *s,
456 struct comedi_insn *insn,
457 unsigned int *data)
59c7dd3d 458{
82d8c74d 459 struct cb_pcidas_private *devpriv = dev->private;
7671896c
HS
460 unsigned int chan = CR_CHAN(insn->chanspec);
461 unsigned int range = CR_RANGE(insn->chanspec);
59c7dd3d
IM
462 unsigned long flags;
463
7671896c 464 /* set channel and range */
5f74ea14 465 spin_lock_irqsave(&dev->spinlock, flags);
7671896c
HS
466 devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH &
467 ~DAC_RANGE_MASK(chan));
468 devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range));
59c7dd3d 469 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 470 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 471
7671896c 472 /* remember value for readback */
46da1c8f 473 s->readback[chan] = data[0];
7671896c
HS
474
475 /* send data */
476 outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan));
59c7dd3d 477
7671896c 478 return insn->n;
59c7dd3d
IM
479}
480
cf530aa4 481/* analog output insn for pcidas-1602 series */
0a85b6f0
MT
482static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev,
483 struct comedi_subdevice *s,
484 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 485{
82d8c74d 486 struct cb_pcidas_private *devpriv = dev->private;
b78332da
HS
487 unsigned int chan = CR_CHAN(insn->chanspec);
488 unsigned int range = CR_RANGE(insn->chanspec);
59c7dd3d
IM
489 unsigned long flags;
490
b78332da 491 /* clear dac fifo */
59c7dd3d
IM
492 outw(0, devpriv->ao_registers + DACFIFOCLR);
493
b78332da 494 /* set channel and range */
5f74ea14 495 spin_lock_irqsave(&dev->spinlock, flags);
b78332da
HS
496 devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) &
497 ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK);
498 devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) |
499 DAC_CHAN_EN(chan) | DAC_START);
59c7dd3d 500 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 501 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 502
b78332da 503 /* remember value for readback */
46da1c8f 504 s->readback[chan] = data[0];
b78332da
HS
505
506 /* send data */
59c7dd3d
IM
507 outw(data[0], devpriv->ao_registers + DACDATA);
508
b78332da 509 return insn->n;
59c7dd3d
IM
510}
511
536af69e
HS
512static int wait_for_nvram_ready(unsigned long s5933_base_addr)
513{
514 static const int timeout = 1000;
515 unsigned int i;
516
517 for (i = 0; i < timeout; i++) {
518 if ((inb(s5933_base_addr +
519 AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY)
520 == 0)
521 return 0;
522 udelay(1);
523 }
524 return -1;
525}
526
527static int nvram_read(struct comedi_device *dev, unsigned int address,
6c7d2c8b 528 uint8_t *data)
536af69e 529{
82d8c74d 530 struct cb_pcidas_private *devpriv = dev->private;
536af69e
HS
531 unsigned long iobase = devpriv->s5933_config;
532
533 if (wait_for_nvram_ready(iobase) < 0)
534 return -ETIMEDOUT;
535
536 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR,
537 iobase + AMCC_OP_REG_MCSR_NVCMD);
538 outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
539 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR,
540 iobase + AMCC_OP_REG_MCSR_NVCMD);
541 outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
542 outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
543
544 if (wait_for_nvram_ready(iobase) < 0)
545 return -ETIMEDOUT;
546
547 *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
548
549 return 0;
550}
551
0a85b6f0
MT
552static int eeprom_read_insn(struct comedi_device *dev,
553 struct comedi_subdevice *s,
554 struct comedi_insn *insn, unsigned int *data)
59c7dd3d
IM
555{
556 uint8_t nvram_data;
557 int retval;
558
559 retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data);
560 if (retval < 0)
561 return retval;
562
563 data[0] = nvram_data;
564
565 return 1;
566}
567
0c15d553
HS
568static void write_calibration_bitstream(struct comedi_device *dev,
569 unsigned int register_bits,
570 unsigned int bitstream,
571 unsigned int bitstream_length)
572{
82d8c74d 573 struct cb_pcidas_private *devpriv = dev->private;
0c15d553
HS
574 static const int write_delay = 1;
575 unsigned int bit;
576
577 for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
578 if (bitstream & bit)
579 register_bits |= SERIAL_DATA_IN_BIT;
580 else
581 register_bits &= ~SERIAL_DATA_IN_BIT;
582 udelay(write_delay);
583 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
584 }
585}
586
f52e5e44
HS
587static void caldac_8800_write(struct comedi_device *dev,
588 unsigned int chan, uint8_t val)
0c15d553 589{
82d8c74d 590 struct cb_pcidas_private *devpriv = dev->private;
0c15d553 591 static const int bitstream_length = 11;
f52e5e44 592 unsigned int bitstream = ((chan & 0x7) << 8) | val;
0c15d553
HS
593 static const int caldac_8800_udelay = 1;
594
0c15d553
HS
595 write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream,
596 bitstream_length);
597
598 udelay(caldac_8800_udelay);
599 outw(cal_enable_bits(dev) | SELECT_8800_BIT,
600 devpriv->control_status + CALIBRATION_REG);
601 udelay(caldac_8800_udelay);
602 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
0c15d553
HS
603}
604
f52e5e44
HS
605static int cb_pcidas_caldac_insn_write(struct comedi_device *dev,
606 struct comedi_subdevice *s,
607 struct comedi_insn *insn,
608 unsigned int *data)
59c7dd3d 609{
f52e5e44
HS
610 unsigned int chan = CR_CHAN(insn->chanspec);
611
612 if (insn->n) {
613 unsigned int val = data[insn->n - 1];
614
3f5ced0d 615 if (s->readback[chan] != val) {
f52e5e44 616 caldac_8800_write(dev, chan, val);
3f5ced0d 617 s->readback[chan] = val;
f52e5e44
HS
618 }
619 }
59c7dd3d 620
f52e5e44 621 return insn->n;
59c7dd3d
IM
622}
623
59c7dd3d 624/* 1602/16 pregain offset */
ac55ca32 625static void dac08_write(struct comedi_device *dev, unsigned int value)
59c7dd3d 626{
82d8c74d
HS
627 struct cb_pcidas_private *devpriv = dev->private;
628
9c034da1
HS
629 value &= 0xff;
630 value |= cal_enable_bits(dev);
59c7dd3d 631
9c034da1
HS
632 /* latch the new value into the caldac */
633 outw(value, devpriv->control_status + CALIBRATION_REG);
634 udelay(1);
635 outw(value | SELECT_DAC08_BIT,
636 devpriv->control_status + CALIBRATION_REG);
637 udelay(1);
638 outw(value, devpriv->control_status + CALIBRATION_REG);
639 udelay(1);
59c7dd3d
IM
640}
641
9c034da1
HS
642static int cb_pcidas_dac08_insn_write(struct comedi_device *dev,
643 struct comedi_subdevice *s,
644 struct comedi_insn *insn,
645 unsigned int *data)
59c7dd3d 646{
e42151f9 647 unsigned int chan = CR_CHAN(insn->chanspec);
9c034da1
HS
648
649 if (insn->n) {
650 unsigned int val = data[insn->n - 1];
ac55ca32 651
e42151f9 652 if (s->readback[chan] != val) {
9c034da1 653 dac08_write(dev, val);
e42151f9 654 s->readback[chan] = val;
9c034da1
HS
655 }
656 }
ac55ca32
HS
657
658 return insn->n;
59c7dd3d
IM
659}
660
20535c1f
HS
661static int trimpot_7376_write(struct comedi_device *dev, uint8_t value)
662{
82d8c74d 663 struct cb_pcidas_private *devpriv = dev->private;
20535c1f
HS
664 static const int bitstream_length = 7;
665 unsigned int bitstream = value & 0x7f;
666 unsigned int register_bits;
667 static const int ad7376_udelay = 1;
668
669 register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
670 udelay(ad7376_udelay);
671 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
672
673 write_calibration_bitstream(dev, register_bits, bitstream,
674 bitstream_length);
675
676 udelay(ad7376_udelay);
677 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
678
679 return 0;
680}
681
682/* For 1602/16 only
683 * ch 0 : adc gain
684 * ch 1 : adc postgain offset */
685static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel,
686 uint8_t value)
687{
82d8c74d 688 struct cb_pcidas_private *devpriv = dev->private;
20535c1f
HS
689 static const int bitstream_length = 10;
690 unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
691 unsigned int register_bits;
692 static const int ad8402_udelay = 1;
693
694 register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
695 udelay(ad8402_udelay);
696 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
697
698 write_calibration_bitstream(dev, register_bits, bitstream,
699 bitstream_length);
700
701 udelay(ad8402_udelay);
702 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
703
704 return 0;
705}
706
7a82a2c4
HS
707static void cb_pcidas_trimpot_write(struct comedi_device *dev,
708 unsigned int chan, unsigned int val)
59c7dd3d 709{
fa8e8c8b 710 const struct cb_pcidas_board *thisboard = dev->board_ptr;
59c7dd3d 711
59c7dd3d
IM
712 switch (thisboard->trimpot) {
713 case AD7376:
7a82a2c4 714 trimpot_7376_write(dev, val);
59c7dd3d
IM
715 break;
716 case AD8402:
7a82a2c4 717 trimpot_8402_write(dev, chan, val);
59c7dd3d
IM
718 break;
719 default:
7ef28904 720 dev_err(dev->class_dev, "driver bug?\n");
7a82a2c4 721 break;
59c7dd3d 722 }
59c7dd3d
IM
723}
724
7a82a2c4
HS
725static int cb_pcidas_trimpot_insn_write(struct comedi_device *dev,
726 struct comedi_subdevice *s,
727 struct comedi_insn *insn,
728 unsigned int *data)
59c7dd3d 729{
7a82a2c4
HS
730 unsigned int chan = CR_CHAN(insn->chanspec);
731
732 if (insn->n) {
733 unsigned int val = data[insn->n - 1];
734
a1c76758 735 if (s->readback[chan] != val) {
7a82a2c4 736 cb_pcidas_trimpot_write(dev, chan, val);
a1c76758 737 s->readback[chan] = val;
7a82a2c4
HS
738 }
739 }
59c7dd3d 740
7a82a2c4 741 return insn->n;
59c7dd3d
IM
742}
743
e74592e0
HS
744static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev,
745 struct comedi_subdevice *s,
746 struct comedi_cmd *cmd)
747{
748 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
749 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
750 int i;
751
752 for (i = 1; i < cmd->chanlist_len; i++) {
753 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
754 unsigned int range = CR_RANGE(cmd->chanlist[i]);
755
756 if (chan != (chan0 + i) % s->n_chan) {
757 dev_dbg(dev->class_dev,
758 "entries in chanlist must be consecutive channels, counting upwards\n");
759 return -EINVAL;
760 }
761
762 if (range != range0) {
763 dev_dbg(dev->class_dev,
764 "entries in chanlist must all have the same gain\n");
765 return -EINVAL;
766 }
767 }
768 return 0;
769}
770
0a85b6f0
MT
771static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
772 struct comedi_subdevice *s,
773 struct comedi_cmd *cmd)
59c7dd3d 774{
fa8e8c8b 775 const struct cb_pcidas_board *thisboard = dev->board_ptr;
59c7dd3d 776 int err = 0;
815bb5b5 777 unsigned int arg;
59c7dd3d 778
27020ffe 779 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 780
27020ffe
HS
781 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
782 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
783 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
784 err |= cfc_check_trigger_src(&cmd->convert_src,
785 TRIG_TIMER | TRIG_NOW | TRIG_EXT);
786 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
787 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
788
789 if (err)
790 return 1;
791
27020ffe 792 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 793
27020ffe
HS
794 err |= cfc_check_trigger_is_unique(cmd->start_src);
795 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
796 err |= cfc_check_trigger_is_unique(cmd->convert_src);
797 err |= cfc_check_trigger_is_unique(cmd->stop_src);
798
799 /* Step 2b : and mutually compatible */
59c7dd3d 800
59c7dd3d 801 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
27020ffe 802 err |= -EINVAL;
59c7dd3d 803 if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
27020ffe 804 err |= -EINVAL;
59c7dd3d 805 if (cmd->start_src == TRIG_EXT &&
0a85b6f0 806 (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
27020ffe 807 err |= -EINVAL;
59c7dd3d
IM
808
809 if (err)
810 return 2;
811
96997b0e 812 /* Step 3: check if arguments are trivially valid */
59c7dd3d 813
f1bc4343 814 switch (cmd->start_src) {
96997b0e
HS
815 case TRIG_NOW:
816 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
817 break;
f1bc4343
BD
818 case TRIG_EXT:
819 /* External trigger, only CR_EDGE and CR_INVERT flags allowed */
820 if ((cmd->start_arg
821 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
00d9c8cb
HS
822 cmd->start_arg &= ~(CR_FLAGS_MASK &
823 ~(CR_EDGE | CR_INVERT));
824 err |= -EINVAL;
f1bc4343 825 }
23e3cce3 826 if (!thisboard->is_1602 && (cmd->start_arg & CR_INVERT)) {
f1bc4343 827 cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT);
00d9c8cb 828 err |= -EINVAL;
f1bc4343
BD
829 }
830 break;
59c7dd3d
IM
831 }
832
00d9c8cb
HS
833 if (cmd->scan_begin_src == TRIG_TIMER)
834 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
835 thisboard->ai_speed * cmd->chanlist_len);
59c7dd3d 836
00d9c8cb
HS
837 if (cmd->convert_src == TRIG_TIMER)
838 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
839 thisboard->ai_speed);
840
841 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
842
c5d9973b
HS
843 if (cmd->stop_src == TRIG_COUNT)
844 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
845 else /* TRIG_NONE */
00d9c8cb 846 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
847
848 if (err)
849 return 3;
850
851 /* step 4: fix up any arguments */
852
853 if (cmd->scan_begin_src == TRIG_TIMER) {
815bb5b5 854 arg = cmd->scan_begin_arg;
96e56244 855 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
815bb5b5 856 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
59c7dd3d
IM
857 }
858 if (cmd->convert_src == TRIG_TIMER) {
815bb5b5 859 arg = cmd->convert_arg;
96e56244 860 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
815bb5b5 861 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
59c7dd3d
IM
862 }
863
864 if (err)
865 return 4;
866
e74592e0
HS
867 /* Step 5: check channel list if it exists */
868 if (cmd->chanlist && cmd->chanlist_len > 0)
869 err |= cb_pcidas_ai_check_chanlist(dev, s, cmd);
59c7dd3d
IM
870
871 if (err)
872 return 5;
873
874 return 0;
875}
876
0a85b6f0
MT
877static int cb_pcidas_ai_cmd(struct comedi_device *dev,
878 struct comedi_subdevice *s)
59c7dd3d 879{
fa8e8c8b 880 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 881 struct cb_pcidas_private *devpriv = dev->private;
d163679c 882 struct comedi_async *async = s->async;
ea6d0d4c 883 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
884 unsigned int bits;
885 unsigned long flags;
886
cf530aa4 887 /* make sure CAL_EN_BIT is disabled */
59c7dd3d 888 outw(0, devpriv->control_status + CALIBRATION_REG);
cf530aa4 889 /* initialize before settings pacer source and count values */
59c7dd3d 890 outw(0, devpriv->control_status + TRIG_CONTSTAT);
cf530aa4 891 /* clear fifo */
59c7dd3d
IM
892 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
893
cf530aa4 894 /* set mux limits, gain and pacer source */
59c7dd3d 895 bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) |
0a85b6f0
MT
896 END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
897 GAIN_BITS(CR_RANGE(cmd->chanlist[0]));
cf530aa4 898 /* set unipolar/bipolar */
59c7dd3d
IM
899 if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR)
900 bits |= UNIP;
cf530aa4 901 /* set singleended/differential */
59c7dd3d
IM
902 if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
903 bits |= SE;
cf530aa4 904 /* set pacer source */
59c7dd3d
IM
905 if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
906 bits |= PACER_EXT_RISE;
907 else
908 bits |= PACER_INT;
909 outw(bits, devpriv->control_status + ADCMUX_CONT);
910
cf530aa4 911 /* load counters */
96e56244
HS
912 if (cmd->scan_begin_src == TRIG_TIMER ||
913 cmd->convert_src == TRIG_TIMER) {
914 comedi_8254_update_divisors(dev->pacer);
915 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
916 }
59c7dd3d 917
cf530aa4 918 /* enable interrupts */
5f74ea14 919 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
920 devpriv->adc_fifo_bits |= INTE;
921 devpriv->adc_fifo_bits &= ~INT_MASK;
07b2eb0e 922 if (cmd->flags & CMDF_WAKE_EOS) {
55acaf2d
HS
923 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
924 /* interrupt end of burst */
925 devpriv->adc_fifo_bits |= INT_EOS;
926 } else {
927 /* interrupt fifo not empty */
928 devpriv->adc_fifo_bits |= INT_FNE;
929 }
59c7dd3d 930 } else {
55acaf2d
HS
931 /* interrupt fifo half full */
932 devpriv->adc_fifo_bits |= INT_FHF;
59c7dd3d 933 }
193debd1 934
cf530aa4 935 /* enable (and clear) interrupts */
59c7dd3d 936 outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL,
0a85b6f0 937 devpriv->control_status + INT_ADCFIFO);
5f74ea14 938 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 939
cf530aa4 940 /* set start trigger and burst mode */
59c7dd3d 941 bits = 0;
8abc7287 942 if (cmd->start_src == TRIG_NOW) {
59c7dd3d 943 bits |= SW_TRIGGER;
8abc7287 944 } else { /* TRIG_EXT */
59c7dd3d 945 bits |= EXT_TRIGGER | TGEN | XTRCL;
23e3cce3 946 if (thisboard->is_1602) {
93c58378 947 if (cmd->start_arg & CR_INVERT)
23e3cce3
HS
948 bits |= TGPOL;
949 if (cmd->start_arg & CR_EDGE)
950 bits |= TGSEL;
951 }
59c7dd3d
IM
952 }
953 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
954 bits |= BURSTE;
955 outw(bits, devpriv->control_status + TRIG_CONTSTAT);
59c7dd3d
IM
956
957 return 0;
958}
959
e74592e0
HS
960static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev,
961 struct comedi_subdevice *s,
962 struct comedi_cmd *cmd)
963{
964 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
965
966 if (cmd->chanlist_len > 1) {
967 unsigned int chan1 = CR_CHAN(cmd->chanlist[1]);
968
969 if (chan0 != 0 || chan1 != 1) {
970 dev_dbg(dev->class_dev,
971 "channels must be ordered channel 0, channel 1 in chanlist\n");
972 return -EINVAL;
973 }
974 }
975
976 return 0;
977}
978
0a85b6f0
MT
979static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
980 struct comedi_subdevice *s,
981 struct comedi_cmd *cmd)
59c7dd3d 982{
fa8e8c8b 983 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 984 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 985 int err = 0;
59c7dd3d 986
27020ffe 987 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 988
27020ffe
HS
989 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
990 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
991 TRIG_TIMER | TRIG_EXT);
992 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
993 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
994 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
995
996 if (err)
997 return 1;
998
27020ffe 999 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 1000
27020ffe
HS
1001 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
1002 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1003
1004 /* Step 2b : and mutually compatible */
59c7dd3d
IM
1005
1006 if (err)
1007 return 2;
1008
00d9c8cb 1009 /* Step 3: check if arguments are trivially valid */
59c7dd3d 1010
00d9c8cb 1011 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
59c7dd3d 1012
00d9c8cb
HS
1013 if (cmd->scan_begin_src == TRIG_TIMER)
1014 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1015 thisboard->ao_scan_speed);
59c7dd3d 1016
00d9c8cb
HS
1017 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1018
c5d9973b
HS
1019 if (cmd->stop_src == TRIG_COUNT)
1020 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1021 else /* TRIG_NONE */
00d9c8cb 1022 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
1023
1024 if (err)
1025 return 3;
1026
1027 /* step 4: fix up any arguments */
1028
1029 if (cmd->scan_begin_src == TRIG_TIMER) {
96e56244
HS
1030 unsigned int arg = cmd->scan_begin_arg;
1031
1032 comedi_8254_cascade_ns_to_timer(devpriv->ao_pacer,
1033 &arg, cmd->flags);
815bb5b5 1034 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
59c7dd3d
IM
1035 }
1036
1037 if (err)
1038 return 4;
1039
e74592e0
HS
1040 /* Step 5: check channel list if it exists */
1041 if (cmd->chanlist && cmd->chanlist_len > 0)
1042 err |= cb_pcidas_ao_check_chanlist(dev, s, cmd);
59c7dd3d
IM
1043
1044 if (err)
1045 return 5;
1046
1047 return 0;
1048}
1049
9a0f7631
HS
1050/* cancel analog input command */
1051static int cb_pcidas_cancel(struct comedi_device *dev,
1052 struct comedi_subdevice *s)
1053{
82d8c74d 1054 struct cb_pcidas_private *devpriv = dev->private;
9a0f7631
HS
1055 unsigned long flags;
1056
1057 spin_lock_irqsave(&dev->spinlock, flags);
1058 /* disable interrupts */
1059 devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
1060 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1061 spin_unlock_irqrestore(&dev->spinlock, flags);
1062
1063 /* disable start trigger source and burst mode */
1064 outw(0, devpriv->control_status + TRIG_CONTSTAT);
1065 /* software pacer source */
1066 outw(0, devpriv->control_status + ADCMUX_CONT);
1067
1068 return 0;
1069}
1070
2cc9854c
HS
1071static void cb_pcidas_ao_load_fifo(struct comedi_device *dev,
1072 struct comedi_subdevice *s,
1073 unsigned int nsamples)
1074{
1075 struct cb_pcidas_private *devpriv = dev->private;
2cc9854c
HS
1076 unsigned int nbytes;
1077
9e4d755c 1078 nsamples = comedi_nsamples_left(s, nsamples);
2cc9854c 1079 nbytes = comedi_buf_read_samples(s, devpriv->ao_buffer, nsamples);
2cc9854c 1080
9e4d755c 1081 nsamples = comedi_bytes_to_samples(s, nbytes);
2cc9854c
HS
1082 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, nsamples);
1083}
1084
1706fcc1
HS
1085static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1086 struct comedi_subdevice *s,
1087 unsigned int trig_num)
1088{
fa8e8c8b 1089 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1090 struct cb_pcidas_private *devpriv = dev->private;
1706fcc1 1091 struct comedi_async *async = s->async;
2cc9854c 1092 struct comedi_cmd *cmd = &async->cmd;
1706fcc1
HS
1093 unsigned long flags;
1094
384e483f 1095 if (trig_num != cmd->start_arg)
1706fcc1
HS
1096 return -EINVAL;
1097
2cc9854c 1098 cb_pcidas_ao_load_fifo(dev, s, thisboard->fifo_size);
1706fcc1
HS
1099
1100 /* enable dac half-full and empty interrupts */
1101 spin_lock_irqsave(&dev->spinlock, flags);
1102 devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
193debd1 1103
1706fcc1
HS
1104 /* enable and clear interrupts */
1105 outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
1106 devpriv->control_status + INT_ADCFIFO);
1107
1108 /* start dac */
1109 devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
1110 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
193debd1 1111
1706fcc1
HS
1112 spin_unlock_irqrestore(&dev->spinlock, flags);
1113
1114 async->inttrig = NULL;
1115
1116 return 0;
1117}
1118
0a85b6f0
MT
1119static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1120 struct comedi_subdevice *s)
59c7dd3d 1121{
82d8c74d 1122 struct cb_pcidas_private *devpriv = dev->private;
d163679c 1123 struct comedi_async *async = s->async;
ea6d0d4c 1124 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
1125 unsigned int i;
1126 unsigned long flags;
1127
cf530aa4 1128 /* set channel limits, gain */
5f74ea14 1129 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1130 for (i = 0; i < cmd->chanlist_len; i++) {
cf530aa4 1131 /* enable channel */
59c7dd3d 1132 devpriv->ao_control_bits |=
0a85b6f0 1133 DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
cf530aa4 1134 /* set range */
59c7dd3d 1135 devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
0a85b6f0
MT
1136 CR_RANGE(cmd->
1137 chanlist[i]));
59c7dd3d
IM
1138 }
1139
cf530aa4 1140 /* disable analog out before settings pacer source and count values */
59c7dd3d 1141 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 1142 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1143
cf530aa4 1144 /* clear fifo */
59c7dd3d
IM
1145 outw(0, devpriv->ao_registers + DACFIFOCLR);
1146
cf530aa4 1147 /* load counters */
96e56244
HS
1148 if (cmd->scan_begin_src == TRIG_TIMER) {
1149 comedi_8254_update_divisors(devpriv->ao_pacer);
1150 comedi_8254_pacer_enable(devpriv->ao_pacer, 1, 2, true);
1151 }
59c7dd3d 1152
cf530aa4 1153 /* set pacer source */
5f74ea14 1154 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
1155 switch (cmd->scan_begin_src) {
1156 case TRIG_TIMER:
1157 devpriv->ao_control_bits |= DAC_PACER_INT;
1158 break;
1159 case TRIG_EXT:
1160 devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
1161 break;
1162 default:
5f74ea14 1163 spin_unlock_irqrestore(&dev->spinlock, flags);
7ef28904 1164 dev_err(dev->class_dev, "error setting dac pacer source\n");
59c7dd3d 1165 return -1;
59c7dd3d 1166 }
5f74ea14 1167 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1168
1169 async->inttrig = cb_pcidas_ao_inttrig;
1170
1171 return 0;
1172}
1173
0aa20304
HS
1174/* cancel analog output command */
1175static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1176 struct comedi_subdevice *s)
1177{
82d8c74d 1178 struct cb_pcidas_private *devpriv = dev->private;
0aa20304
HS
1179 unsigned long flags;
1180
1181 spin_lock_irqsave(&dev->spinlock, flags);
1182 /* disable interrupts */
1183 devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
1184 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1185
1186 /* disable output */
1187 devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
1188 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1189 spin_unlock_irqrestore(&dev->spinlock, flags);
1190
1191 return 0;
1192}
1193
9e11d05f
HS
1194static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
1195{
fa8e8c8b 1196 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1197 struct cb_pcidas_private *devpriv = dev->private;
9e11d05f
HS
1198 struct comedi_subdevice *s = dev->write_subdev;
1199 struct comedi_async *async = s->async;
1200 struct comedi_cmd *cmd = &async->cmd;
9e11d05f
HS
1201 unsigned long flags;
1202
9e11d05f
HS
1203 if (status & DAEMI) {
1204 /* clear dac empty interrupt latch */
1205 spin_lock_irqsave(&dev->spinlock, flags);
1206 outw(devpriv->adc_fifo_bits | DAEMI,
1207 devpriv->control_status + INT_ADCFIFO);
1208 spin_unlock_irqrestore(&dev->spinlock, flags);
1209 if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
9e4d755c
HS
1210 if (cmd->stop_src == TRIG_COUNT &&
1211 async->scans_done >= cmd->stop_arg) {
1212 async->events |= COMEDI_CB_EOA;
1213 } else {
7ef28904 1214 dev_err(dev->class_dev, "dac fifo underflow\n");
9e11d05f
HS
1215 async->events |= COMEDI_CB_ERROR;
1216 }
9e11d05f
HS
1217 }
1218 } else if (status & DAHFI) {
2cc9854c
HS
1219 cb_pcidas_ao_load_fifo(dev, s, thisboard->fifo_size / 2);
1220
9e11d05f
HS
1221 /* clear half-full interrupt latch */
1222 spin_lock_irqsave(&dev->spinlock, flags);
1223 outw(devpriv->adc_fifo_bits | DAHFI,
1224 devpriv->control_status + INT_ADCFIFO);
1225 spin_unlock_irqrestore(&dev->spinlock, flags);
1226 }
1227
f923f780 1228 comedi_handle_events(dev, s);
9e11d05f
HS
1229}
1230
70265d24 1231static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
59c7dd3d 1232{
0a85b6f0 1233 struct comedi_device *dev = (struct comedi_device *)d;
fa8e8c8b 1234 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1235 struct cb_pcidas_private *devpriv = dev->private;
34c43922 1236 struct comedi_subdevice *s = dev->read_subdev;
d163679c 1237 struct comedi_async *async;
bedd62fc 1238 struct comedi_cmd *cmd;
59c7dd3d
IM
1239 int status, s5933_status;
1240 int half_fifo = thisboard->fifo_size / 2;
1241 unsigned int num_samples, i;
1242 static const int timeout = 10000;
1243 unsigned long flags;
1244
a7401cdd 1245 if (!dev->attached)
59c7dd3d 1246 return IRQ_NONE;
59c7dd3d
IM
1247
1248 async = s->async;
bedd62fc 1249 cmd = &async->cmd;
59c7dd3d
IM
1250
1251 s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1252
1253 if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
1254 return IRQ_NONE;
1255
cf530aa4 1256 /* make sure mailbox 4 is empty */
59c7dd3d 1257 inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
cf530aa4 1258 /* clear interrupt on amcc s5933 */
59c7dd3d 1259 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
0a85b6f0 1260 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1261
1262 status = inw(devpriv->control_status + INT_ADCFIFO);
59c7dd3d 1263
cf530aa4 1264 /* check for analog output interrupt */
2d238b29 1265 if (status & (DAHFI | DAEMI))
59c7dd3d 1266 handle_ao_interrupt(dev, status);
cf530aa4
BP
1267 /* check for analog input interrupts */
1268 /* if fifo half-full */
59c7dd3d 1269 if (status & ADHFI) {
cf530aa4 1270 /* read data */
f9f98382 1271 num_samples = comedi_nsamples_left(s, half_fifo);
59c7dd3d 1272 insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
0a85b6f0 1273 num_samples);
8d47c085 1274 comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples);
f9f98382
HS
1275
1276 if (cmd->stop_src == TRIG_COUNT &&
1277 async->scans_done >= cmd->stop_arg)
59c7dd3d 1278 async->events |= COMEDI_CB_EOA;
f9f98382 1279
cf530aa4 1280 /* clear half-full interrupt latch */
5f74ea14 1281 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1282 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1283 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1284 spin_unlock_irqrestore(&dev->spinlock, flags);
cf530aa4 1285 /* else if fifo not empty */
59c7dd3d
IM
1286 } else if (status & (ADNEI | EOBI)) {
1287 for (i = 0; i < timeout; i++) {
8d47c085
HS
1288 unsigned short val;
1289
cf530aa4 1290 /* break if fifo is empty */
59c7dd3d 1291 if ((ADNE & inw(devpriv->control_status +
0a85b6f0 1292 INT_ADCFIFO)) == 0)
59c7dd3d 1293 break;
8d47c085
HS
1294 val = inw(devpriv->adc_fifo);
1295 comedi_buf_write_samples(s, &val, 1);
f9f98382 1296
bedd62fc 1297 if (cmd->stop_src == TRIG_COUNT &&
f9f98382 1298 async->scans_done >= cmd->stop_arg) {
59c7dd3d
IM
1299 async->events |= COMEDI_CB_EOA;
1300 break;
1301 }
1302 }
cf530aa4 1303 /* clear not-empty interrupt latch */
5f74ea14 1304 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1305 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1306 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1307 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1308 } else if (status & EOAI) {
7ef28904
HS
1309 dev_err(dev->class_dev,
1310 "bug! encountered end of acquisition interrupt?\n");
cf530aa4 1311 /* clear EOA interrupt latch */
5f74ea14 1312 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1313 outw(devpriv->adc_fifo_bits | EOAI,
0a85b6f0 1314 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1315 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1316 }
cf530aa4 1317 /* check for fifo overflow */
59c7dd3d 1318 if (status & LADFUL) {
7ef28904 1319 dev_err(dev->class_dev, "fifo overflow\n");
cf530aa4 1320 /* clear overflow interrupt latch */
5f74ea14 1321 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1322 outw(devpriv->adc_fifo_bits | LADFUL,
0a85b6f0 1323 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1324 spin_unlock_irqrestore(&dev->spinlock, flags);
3e6cb74f 1325 async->events |= COMEDI_CB_ERROR;
59c7dd3d
IM
1326 }
1327
f923f780 1328 comedi_handle_events(dev, s);
59c7dd3d
IM
1329
1330 return IRQ_HANDLED;
1331}
1332
a690b7e5 1333static int cb_pcidas_auto_attach(struct comedi_device *dev,
9b315bcb 1334 unsigned long context)
327be979 1335{
750af5e5 1336 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
9b315bcb 1337 const struct cb_pcidas_board *thisboard = NULL;
327be979
HS
1338 struct cb_pcidas_private *devpriv;
1339 struct comedi_subdevice *s;
1340 int i;
1341 int ret;
e74f209c 1342
9b315bcb
HS
1343 if (context < ARRAY_SIZE(cb_pcidas_boards))
1344 thisboard = &cb_pcidas_boards[context];
3b96f250
HS
1345 if (!thisboard)
1346 return -ENODEV;
1347 dev->board_ptr = thisboard;
1348 dev->board_name = thisboard->name;
1349
0bdab509 1350 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
1351 if (!devpriv)
1352 return -ENOMEM;
3b96f250 1353
818f569f 1354 ret = comedi_pci_enable(dev);
3b96f250
HS
1355 if (ret)
1356 return ret;
7302abef 1357
ba36b9ba
HS
1358 devpriv->s5933_config = pci_resource_start(pcidev, 0);
1359 devpriv->control_status = pci_resource_start(pcidev, 1);
1360 devpriv->adc_fifo = pci_resource_start(pcidev, 2);
3a94180c 1361 dev->iobase = pci_resource_start(pcidev, 3);
7302abef 1362 if (thisboard->ao_nchan)
ba36b9ba 1363 devpriv->ao_registers = pci_resource_start(pcidev, 4);
7302abef 1364
e74f209c
HS
1365 /* disable and clear interrupts on amcc s5933 */
1366 outl(INTCSR_INBOX_INTR_STATUS,
1367 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1368
71e06874
HS
1369 ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED,
1370 dev->board_name, dev);
1371 if (ret) {
e74f209c 1372 dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
ba36b9ba 1373 pcidev->irq);
71e06874 1374 return ret;
e74f209c 1375 }
ba36b9ba 1376 dev->irq = pcidev->irq;
e74f209c 1377
96e56244
HS
1378 dev->pacer = comedi_8254_init(dev->iobase + ADC8254,
1379 I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
1380 if (!dev->pacer)
1381 return -ENOMEM;
1382
1383 devpriv->ao_pacer = comedi_8254_init(dev->iobase + DAC8254,
1384 I8254_OSC_BASE_10MHZ,
1385 I8254_IO8, 0);
1386 if (!devpriv->ao_pacer)
1387 return -ENOMEM;
1388
e74f209c
HS
1389 ret = comedi_alloc_subdevices(dev, 7);
1390 if (ret)
1391 return ret;
1392
e89c61b9 1393 s = &dev->subdevices[0];
e74f209c
HS
1394 /* analog input subdevice */
1395 dev->read_subdev = s;
1396 s->type = COMEDI_SUBD_AI;
1397 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
1398 /* WARNING: Number of inputs in differential mode is ignored */
8f608fc8
HS
1399 s->n_chan = thisboard->ai_nchan;
1400 s->len_chanlist = thisboard->ai_nchan;
e74f209c
HS
1401 s->maxdata = (1 << thisboard->ai_bits) - 1;
1402 s->range_table = thisboard->ranges;
1403 s->insn_read = cb_pcidas_ai_rinsn;
1404 s->insn_config = ai_config_insn;
1405 s->do_cmd = cb_pcidas_ai_cmd;
1406 s->do_cmdtest = cb_pcidas_ai_cmdtest;
1407 s->cancel = cb_pcidas_cancel;
1408
1409 /* analog output subdevice */
e89c61b9 1410 s = &dev->subdevices[1];
e74f209c
HS
1411 if (thisboard->ao_nchan) {
1412 s->type = COMEDI_SUBD_AO;
1413 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
1414 s->n_chan = thisboard->ao_nchan;
55acaf2d
HS
1415 /*
1416 * analog out resolution is the same as
1417 * analog input resolution, so use ai_bits
1418 */
e74f209c
HS
1419 s->maxdata = (1 << thisboard->ai_bits) - 1;
1420 s->range_table = &cb_pcidas_ao_ranges;
46da1c8f
HS
1421 /* default to no fifo (*insn_write) */
1422 s->insn_write = cb_pcidas_ao_nofifo_winsn;
46da1c8f
HS
1423
1424 ret = comedi_alloc_subdev_readback(s);
1425 if (ret)
1426 return ret;
1427
e74f209c
HS
1428 if (thisboard->has_ao_fifo) {
1429 dev->write_subdev = s;
1430 s->subdev_flags |= SDF_CMD_WRITE;
46da1c8f 1431 /* use fifo (*insn_write) instead */
e74f209c
HS
1432 s->insn_write = cb_pcidas_ao_fifo_winsn;
1433 s->do_cmdtest = cb_pcidas_ao_cmdtest;
1434 s->do_cmd = cb_pcidas_ao_cmd;
1435 s->cancel = cb_pcidas_ao_cancel;
e74f209c
HS
1436 }
1437 } else {
1438 s->type = COMEDI_SUBD_UNUSED;
1439 }
1440
1441 /* 8255 */
e89c61b9 1442 s = &dev->subdevices[2];
4085e93b 1443 ret = subdev_8255_init(dev, s, NULL, DIO_8255);
4f0036ef
HS
1444 if (ret)
1445 return ret;
e74f209c
HS
1446
1447 /* serial EEPROM, */
e89c61b9 1448 s = &dev->subdevices[3];
e74f209c
HS
1449 s->type = COMEDI_SUBD_MEMORY;
1450 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1451 s->n_chan = 256;
1452 s->maxdata = 0xff;
1453 s->insn_read = eeprom_read_insn;
1454
1455 /* 8800 caldac */
e89c61b9 1456 s = &dev->subdevices[4];
e74f209c
HS
1457 s->type = COMEDI_SUBD_CALIB;
1458 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1459 s->n_chan = NUM_CHANNELS_8800;
1460 s->maxdata = 0xff;
f52e5e44 1461 s->insn_write = cb_pcidas_caldac_insn_write;
3f5ced0d
HS
1462
1463 ret = comedi_alloc_subdev_readback(s);
1464 if (ret)
1465 return ret;
1466
f52e5e44 1467 for (i = 0; i < s->n_chan; i++) {
e74f209c 1468 caldac_8800_write(dev, i, s->maxdata / 2);
3f5ced0d 1469 s->readback[i] = s->maxdata / 2;
f52e5e44 1470 }
e74f209c
HS
1471
1472 /* trim potentiometer */
e89c61b9 1473 s = &dev->subdevices[5];
e74f209c
HS
1474 s->type = COMEDI_SUBD_CALIB;
1475 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1476 if (thisboard->trimpot == AD7376) {
1477 s->n_chan = NUM_CHANNELS_7376;
1478 s->maxdata = 0x7f;
1479 } else {
1480 s->n_chan = NUM_CHANNELS_8402;
1481 s->maxdata = 0xff;
1482 }
7a82a2c4 1483 s->insn_write = cb_pcidas_trimpot_insn_write;
a1c76758
HS
1484
1485 ret = comedi_alloc_subdev_readback(s);
1486 if (ret)
1487 return ret;
1488
7a82a2c4 1489 for (i = 0; i < s->n_chan; i++) {
e74f209c 1490 cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
a1c76758 1491 s->readback[i] = s->maxdata / 2;
7a82a2c4 1492 }
e74f209c
HS
1493
1494 /* dac08 caldac */
e89c61b9 1495 s = &dev->subdevices[6];
e74f209c
HS
1496 if (thisboard->has_dac08) {
1497 s->type = COMEDI_SUBD_CALIB;
1498 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1499 s->n_chan = NUM_CHANNELS_DAC08;
e74f209c 1500 s->maxdata = 0xff;
e42151f9
HS
1501 s->insn_write = cb_pcidas_dac08_insn_write;
1502
1503 ret = comedi_alloc_subdev_readback(s);
1504 if (ret)
1505 return ret;
1506
1507 for (i = 0; i < s->n_chan; i++) {
1508 dac08_write(dev, s->maxdata / 2);
1509 s->readback[i] = s->maxdata / 2;
1510 }
e74f209c
HS
1511 } else
1512 s->type = COMEDI_SUBD_UNUSED;
1513
1514 /* make sure mailbox 4 is empty */
1515 inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1516 /* Set bits to enable incoming mailbox interrupts on amcc s5933. */
1517 devpriv->s5933_intcsr_bits =
1518 INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1519 INTCSR_INBOX_FULL_INT;
1520 /* clear and enable interrupt on amcc s5933 */
1521 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1522 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1523
3b96f250 1524 return 0;
e74f209c
HS
1525}
1526
1527static void cb_pcidas_detach(struct comedi_device *dev)
1528{
82d8c74d
HS
1529 struct cb_pcidas_private *devpriv = dev->private;
1530
96e56244
HS
1531 if (devpriv) {
1532 if (devpriv->s5933_config)
1533 outl(INTCSR_INBOX_INTR_STATUS,
1534 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1535 kfree(devpriv->ao_pacer);
e74f209c 1536 }
aac307f9 1537 comedi_pci_detach(dev);
e74f209c
HS
1538}
1539
715b2284
HS
1540static struct comedi_driver cb_pcidas_driver = {
1541 .driver_name = "cb_pcidas",
1542 .module = THIS_MODULE,
750af5e5 1543 .auto_attach = cb_pcidas_auto_attach,
715b2284
HS
1544 .detach = cb_pcidas_detach,
1545};
1546
a690b7e5 1547static int cb_pcidas_pci_probe(struct pci_dev *dev,
b8f4ac23 1548 const struct pci_device_id *id)
727b286b 1549{
b8f4ac23
HS
1550 return comedi_pci_auto_config(dev, &cb_pcidas_driver,
1551 id->driver_data);
727b286b
AT
1552}
1553
41e043fc 1554static const struct pci_device_id cb_pcidas_pci_table[] = {
9b315bcb
HS
1555 { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
1556 { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
1557 { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
1558 { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
1559 { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
1560 { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
1561 { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
1562 { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
715b2284 1563 { 0 }
727b286b 1564};
715b2284 1565MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
727b286b 1566
715b2284
HS
1567static struct pci_driver cb_pcidas_pci_driver = {
1568 .name = "cb_pcidas",
1569 .id_table = cb_pcidas_pci_table,
1570 .probe = cb_pcidas_pci_probe,
9901a4d7 1571 .remove = comedi_pci_auto_unconfig,
715b2284
HS
1572};
1573module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
90f703d3
AT
1574
1575MODULE_AUTHOR("Comedi http://www.comedi.org");
1576MODULE_DESCRIPTION("Comedi low-level driver");
1577MODULE_LICENSE("GPL");