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