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