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