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