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