]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/comedi/drivers/cb_pcidda.c
Staging: comedi: fix read past end of array in cb_pcidda_attach()
[net-next-2.6.git] / drivers / staging / comedi / drivers / cb_pcidda.c
CommitLineData
086df5b5
IM
1/*
2 comedi/drivers/cb_pcidda.c
3 This intends to be a driver for the ComputerBoards / MeasurementComputing
4 PCI-DDA series.
5
6 Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com>
7 Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
8
9 COMEDI - Linux Control and Measurement Device Interface
10 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26*/
27/*
28Driver: cb_pcidda
29Description: MeasurementComputing PCI-DDA series
30Author: Ivan Martinez <ivanmr@altavista.com>, Frank Mori Hess <fmhess@users.sourceforge.net>
31Status: Supports 08/16, 04/16, 02/16, 08/12, 04/12, and 02/12
32Devices: [Measurement Computing] PCI-DDA08/12 (cb_pcidda), PCI-DDA04/12,
33 PCI-DDA02/12, PCI-DDA08/16, PCI-DDA04/16, PCI-DDA02/16
34
35Configuration options:
36 [0] - PCI bus of device (optional)
37 [1] - PCI slot of device (optional)
38 If bus/slot is not specified, the first available PCI
39 device will be used.
40
41Only simple analog output writing is supported.
42
43So far it has only been tested with:
44 - PCI-DDA08/12
45Please report success/failure with other different cards to
46<comedi@comedi.org>.
47*/
48
49#include "../comedidev.h"
50
51#include "comedi_pci.h"
52#include "8255.h"
53
2696fb57 54#define PCI_VENDOR_ID_CB 0x1307 /* PCI vendor number of ComputerBoards */
2696fb57
BP
55#define EEPROM_SIZE 128 /* number of entries in eeprom */
56#define MAX_AO_CHANNELS 8 /* maximum number of ao channels for supported boards */
086df5b5
IM
57
58/* PCI-DDA base addresses */
59#define DIGITALIO_BADRINDEX 2
2696fb57 60 /* DIGITAL I/O is pci_dev->resource[2] */
086df5b5 61#define DIGITALIO_SIZE 8
2696fb57 62 /* DIGITAL I/O uses 8 I/O port addresses */
086df5b5 63#define DAC_BADRINDEX 3
2696fb57 64 /* DAC is pci_dev->resource[3] */
086df5b5
IM
65
66/* Digital I/O registers */
2696fb57 67#define PORT1A 0 /* PORT 1A DATA */
086df5b5 68
2696fb57 69#define PORT1B 1 /* PORT 1B DATA */
086df5b5 70
2696fb57 71#define PORT1C 2 /* PORT 1C DATA */
086df5b5 72
2696fb57 73#define CONTROL1 3 /* CONTROL REGISTER 1 */
086df5b5 74
2696fb57 75#define PORT2A 4 /* PORT 2A DATA */
086df5b5 76
2696fb57 77#define PORT2B 5 /* PORT 2B DATA */
086df5b5 78
2696fb57 79#define PORT2C 6 /* PORT 2C DATA */
086df5b5 80
2696fb57 81#define CONTROL2 7 /* CONTROL REGISTER 2 */
086df5b5
IM
82
83/* DAC registers */
2696fb57
BP
84#define DACONTROL 0 /* D/A CONTROL REGISTER */
85#define SU 0000001 /* Simultaneous update enabled */
86#define NOSU 0000000 /* Simultaneous update disabled */
87#define ENABLEDAC 0000002 /* Enable specified DAC */
88#define DISABLEDAC 0000000 /* Disable specified DAC */
89#define RANGE2V5 0000000 /* 2.5V */
90#define RANGE5V 0000200 /* 5V */
91#define RANGE10V 0000300 /* 10V */
92#define UNIP 0000400 /* Unipolar outputs */
93#define BIP 0000000 /* Bipolar outputs */
94
95#define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */
96/* write bits */
97#define SERIAL_IN_BIT 0x1 /* serial data input for eeprom, caldacs, reference dac */
086df5b5
IM
98#define CAL_CHANNEL_MASK (0x7 << 1)
99#define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK)
2696fb57 100/* read bits */
086df5b5 101#define CAL_COUNTER_MASK 0x1f
2696fb57
BP
102#define CAL_COUNTER_OVERFLOW_BIT 0x20 /* calibration counter overflow status bit */
103#define AO_BELOW_REF_BIT 0x40 /* analog output is less than reference dac voltage */
104#define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */
086df5b5 105
2696fb57
BP
106#define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */
107#define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */
108#define DESELECT_REF_DAC_BIT 0x2 /* don't send serial data to MAX542 reference dac */
109#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) /* don't send serial data to caldac n */
110#define DUMMY_BIT 0x40 /* manual says to set this bit with no explanation */
086df5b5 111
2696fb57 112#define DADATA 8 /* FIRST D/A DATA REGISTER (0) */
086df5b5 113
9ced1de6 114static const struct comedi_lrange cb_pcidda_ranges = {
086df5b5
IM
115 6,
116 {
0a85b6f0
MT
117 BIP_RANGE(10),
118 BIP_RANGE(5),
119 BIP_RANGE(2.5),
120 UNI_RANGE(10),
121 UNI_RANGE(5),
122 UNI_RANGE(2.5),
123 }
086df5b5
IM
124};
125
126/*
127 * Board descriptions for two imaginary boards. Describing the
128 * boards in this way is optional, and completely driver-dependent.
129 * Some drivers use arrays such as this, other do not.
130 */
1657e325 131struct cb_pcidda_board {
086df5b5 132 const char *name;
2696fb57
BP
133 char status; /* Driver status: */
134
135 /*
136 * 0 - tested
137 * 1 - manual read, not tested
138 * 2 - manual not read
139 */
140
086df5b5
IM
141 unsigned short device_id;
142 int ao_chans;
143 int ao_bits;
9ced1de6 144 const struct comedi_lrange *ranges;
1657e325 145};
2696fb57 146
1657e325 147static const struct cb_pcidda_board cb_pcidda_boards[] = {
086df5b5 148 {
0a85b6f0
MT
149 .name = "pci-dda02/12",
150 .status = 1,
151 .device_id = 0x20,
152 .ao_chans = 2,
153 .ao_bits = 12,
154 .ranges = &cb_pcidda_ranges,
155 },
086df5b5 156 {
0a85b6f0
MT
157 .name = "pci-dda04/12",
158 .status = 1,
159 .device_id = 0x21,
160 .ao_chans = 4,
161 .ao_bits = 12,
162 .ranges = &cb_pcidda_ranges,
163 },
086df5b5 164 {
0a85b6f0
MT
165 .name = "pci-dda08/12",
166 .status = 0,
167 .device_id = 0x22,
168 .ao_chans = 8,
169 .ao_bits = 12,
170 .ranges = &cb_pcidda_ranges,
171 },
086df5b5 172 {
0a85b6f0
MT
173 .name = "pci-dda02/16",
174 .status = 2,
175 .device_id = 0x23,
176 .ao_chans = 2,
177 .ao_bits = 16,
178 .ranges = &cb_pcidda_ranges,
179 },
086df5b5 180 {
0a85b6f0
MT
181 .name = "pci-dda04/16",
182 .status = 2,
183 .device_id = 0x24,
184 .ao_chans = 4,
185 .ao_bits = 16,
186 .ranges = &cb_pcidda_ranges,
187 },
086df5b5 188 {
0a85b6f0
MT
189 .name = "pci-dda08/16",
190 .status = 0,
191 .device_id = 0x25,
192 .ao_chans = 8,
193 .ao_bits = 16,
194 .ranges = &cb_pcidda_ranges,
195 },
086df5b5
IM
196};
197
198static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
0a85b6f0
MT
199 {
200 PCI_VENDOR_ID_CB, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
201 PCI_VENDOR_ID_CB, 0x0021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
202 PCI_VENDOR_ID_CB, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
203 PCI_VENDOR_ID_CB, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
204 PCI_VENDOR_ID_CB, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
205 PCI_VENDOR_ID_CB, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
206 0}
086df5b5
IM
207};
208
209MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
210
211/*
212 * Useful for shorthand access to the particular board structure
213 */
1657e325 214#define thisboard ((const struct cb_pcidda_board *)dev->board_ptr)
086df5b5
IM
215
216/* this structure is for data unique to this hardware driver. If
217 several hardware drivers keep similar information in this structure,
71b5f4f1 218 feel free to suggest moving the variable to the struct comedi_device struct. */
cc7bb61e 219struct cb_pcidda_private {
086df5b5
IM
220 int data;
221
222 /* would be useful for a PCI device */
223 struct pci_dev *pci_dev;
224
225 unsigned long digitalio;
226 unsigned long dac;
2696fb57
BP
227
228 /* unsigned long control_status; */
229 /* unsigned long adc_fifo; */
230
231 unsigned int dac_cal1_bits; /* bits last written to da calibration register 1 */
232 unsigned int ao_range[MAX_AO_CHANNELS]; /* current range settings for output channels */
233 u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */
cc7bb61e 234};
086df5b5
IM
235
236/*
237 * most drivers define the following macro to make it easy to
238 * access the private structure.
239 */
cc7bb61e 240#define devpriv ((struct cb_pcidda_private *)dev->private)
086df5b5 241
0a85b6f0
MT
242static int cb_pcidda_attach(struct comedi_device *dev,
243 struct comedi_devconfig *it);
da91b269 244static int cb_pcidda_detach(struct comedi_device *dev);
2696fb57 245/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */
0a85b6f0
MT
246static int cb_pcidda_ao_winsn(struct comedi_device *dev,
247 struct comedi_subdevice *s,
248 struct comedi_insn *insn, unsigned int *data);
2696fb57
BP
249
250/* static int cb_pcidda_ai_cmd(struct comedi_device *dev, struct *comedi_subdevice *s);*/
251/* static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); */
252/* static int cb_pcidda_ns_to_timer(unsigned int *ns,int *round); */
253
da91b269
BP
254static unsigned int cb_pcidda_serial_in(struct comedi_device *dev);
255static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
0a85b6f0 256 unsigned int num_bits);
da91b269 257static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
0a85b6f0 258 unsigned int address);
da91b269 259static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
0a85b6f0 260 unsigned int range);
086df5b5
IM
261
262/*
139dfbdf 263 * The struct comedi_driver structure tells the Comedi core module
086df5b5
IM
264 * which functions to call to configure/deconfigure (attach/detach)
265 * the board, and also about the kernel module that contains
266 * the device code.
267 */
139dfbdf 268static struct comedi_driver driver_cb_pcidda = {
68c3dbff
BP
269 .driver_name = "cb_pcidda",
270 .module = THIS_MODULE,
271 .attach = cb_pcidda_attach,
272 .detach = cb_pcidda_detach,
086df5b5
IM
273};
274
275/*
276 * Attach is called by the Comedi core to configure the driver
277 * for a particular board.
278 */
0a85b6f0
MT
279static int cb_pcidda_attach(struct comedi_device *dev,
280 struct comedi_devconfig *it)
086df5b5 281{
34c43922 282 struct comedi_subdevice *s;
086df5b5
IM
283 struct pci_dev *pcidev;
284 int index;
285
286 printk("comedi%d: cb_pcidda: ", dev->minor);
287
288/*
289 * Allocate the private structure area.
290 */
cc7bb61e 291 if (alloc_private(dev, sizeof(struct cb_pcidda_private)) < 0)
086df5b5
IM
292 return -ENOMEM;
293
294/*
295 * Probe the device to determine what device in the series it is.
296 */
297 printk("\n");
298
299 for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
0a85b6f0
MT
300 pcidev != NULL;
301 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
086df5b5
IM
302 if (pcidev->vendor == PCI_VENDOR_ID_CB) {
303 if (it->options[0] || it->options[1]) {
304 if (pcidev->bus->number != it->options[0] ||
0a85b6f0 305 PCI_SLOT(pcidev->devfn) != it->options[1]) {
086df5b5
IM
306 continue;
307 }
308 }
821e67a1 309 for (index = 0; index < ARRAY_SIZE(cb_pcidda_boards); index++) {
086df5b5 310 if (cb_pcidda_boards[index].device_id ==
0a85b6f0 311 pcidev->device) {
086df5b5
IM
312 goto found;
313 }
314 }
315 }
316 }
317 if (!pcidev) {
0a85b6f0
MT
318 printk
319 ("Not a ComputerBoards/MeasurementComputing card on requested position\n");
086df5b5
IM
320 return -EIO;
321 }
0a85b6f0 322found:
086df5b5
IM
323 devpriv->pci_dev = pcidev;
324 dev->board_ptr = cb_pcidda_boards + index;
2696fb57 325 /* "thisboard" macro can be used from here. */
086df5b5
IM
326 printk("Found %s at requested position\n", thisboard->name);
327
328 /*
329 * Enable PCI device and request regions.
330 */
331 if (comedi_pci_enable(pcidev, thisboard->name)) {
0a85b6f0
MT
332 printk
333 ("cb_pcidda: failed to enable PCI device and request regions\n");
086df5b5
IM
334 return -EIO;
335 }
336
337/*
338 * Allocate the I/O ports.
339 */
340 devpriv->digitalio =
0a85b6f0 341 pci_resource_start(devpriv->pci_dev, DIGITALIO_BADRINDEX);
086df5b5
IM
342 devpriv->dac = pci_resource_start(devpriv->pci_dev, DAC_BADRINDEX);
343
344/*
345 * Warn about the status of the driver.
346 */
347 if (thisboard->status == 2)
0a85b6f0
MT
348 printk
349 ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. "
350 "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. "
351 "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n");
086df5b5
IM
352
353/*
354 * Initialize dev->board_name.
355 */
356 dev->board_name = thisboard->name;
357
358/*
359 * Allocate the subdevice structures.
360 */
361 if (alloc_subdevices(dev, 3) < 0)
362 return -ENOMEM;
363
364 s = dev->subdevices + 0;
365 /* analog output subdevice */
366 s->type = COMEDI_SUBD_AO;
367 s->subdev_flags = SDF_WRITABLE;
368 s->n_chan = thisboard->ao_chans;
369 s->maxdata = (1 << thisboard->ao_bits) - 1;
370 s->range_table = thisboard->ranges;
371 s->insn_write = cb_pcidda_ao_winsn;
086df5b5 372
2696fb57
BP
373 /* s->subdev_flags |= SDF_CMD_READ; */
374 /* s->do_cmd = cb_pcidda_ai_cmd; */
375 /* s->do_cmdtest = cb_pcidda_ai_cmdtest; */
376
377 /* two 8255 digital io subdevices */
086df5b5
IM
378 s = dev->subdevices + 1;
379 subdev_8255_init(dev, s, NULL, devpriv->digitalio);
380 s = dev->subdevices + 2;
381 subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A);
382
383 printk(" eeprom:");
384 for (index = 0; index < EEPROM_SIZE; index++) {
385 devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
386 printk(" %i:0x%x ", index, devpriv->eeprom_data[index]);
387 }
388 printk("\n");
389
2696fb57 390 /* set calibrations dacs */
086df5b5
IM
391 for (index = 0; index < thisboard->ao_chans; index++)
392 cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]);
393
394 return 1;
395}
396
397/*
398 * _detach is called to deconfigure a device. It should deallocate
399 * resources.
400 * This function is also called when _attach() fails, so it should be
401 * careful not to release resources that were not necessarily
402 * allocated by _attach(). dev->private and dev->subdevices are
403 * deallocated automatically by the core.
404 */
da91b269 405static int cb_pcidda_detach(struct comedi_device *dev)
086df5b5
IM
406{
407/*
408 * Deallocate the I/O ports.
409 */
410 if (devpriv) {
411 if (devpriv->pci_dev) {
20db7d7d 412 if (devpriv->dac)
086df5b5 413 comedi_pci_disable(devpriv->pci_dev);
086df5b5
IM
414 pci_dev_put(devpriv->pci_dev);
415 }
416 }
2696fb57 417 /* cleanup 8255 */
086df5b5
IM
418 if (dev->subdevices) {
419 subdev_8255_cleanup(dev, dev->subdevices + 1);
420 subdev_8255_cleanup(dev, dev->subdevices + 2);
421 }
422
423 printk("comedi%d: cb_pcidda: remove\n", dev->minor);
424
425 return 0;
426}
427
428/*
429 * I will program this later... ;-)
430 */
431#if 0
0a85b6f0
MT
432static int cb_pcidda_ai_cmd(struct comedi_device *dev,
433 struct comedi_subdevice *s)
086df5b5
IM
434{
435 printk("cb_pcidda_ai_cmd\n");
436 printk("subdev: %d\n", cmd->subdev);
437 printk("flags: %d\n", cmd->flags);
438 printk("start_src: %d\n", cmd->start_src);
439 printk("start_arg: %d\n", cmd->start_arg);
440 printk("scan_begin_src: %d\n", cmd->scan_begin_src);
441 printk("convert_src: %d\n", cmd->convert_src);
442 printk("convert_arg: %d\n", cmd->convert_arg);
443 printk("scan_end_src: %d\n", cmd->scan_end_src);
444 printk("scan_end_arg: %d\n", cmd->scan_end_arg);
445 printk("stop_src: %d\n", cmd->stop_src);
446 printk("stop_arg: %d\n", cmd->stop_arg);
447 printk("chanlist_len: %d\n", cmd->chanlist_len);
448}
449#endif
450
451#if 0
0a85b6f0
MT
452static int cb_pcidda_ai_cmdtest(struct comedi_device *dev,
453 struct comedi_subdevice *s,
454 struct comedi_cmd *cmd)
086df5b5
IM
455{
456 int err = 0;
457 int tmp;
458
459 /* cmdtest tests a particular command to see if it is valid.
460 * Using the cmdtest ioctl, a user can create a valid cmd
461 * and then have it executes by the cmd ioctl.
462 *
463 * cmdtest returns 1,2,3,4 or 0, depending on which tests
464 * the command passes. */
465
466 /* step 1: make sure trigger sources are trivially valid */
467
468 tmp = cmd->start_src;
469 cmd->start_src &= TRIG_NOW;
470 if (!cmd->start_src || tmp != cmd->start_src)
471 err++;
472
473 tmp = cmd->scan_begin_src;
474 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
475 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
476 err++;
477
478 tmp = cmd->convert_src;
479 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
480 if (!cmd->convert_src || tmp != cmd->convert_src)
481 err++;
482
483 tmp = cmd->scan_end_src;
484 cmd->scan_end_src &= TRIG_COUNT;
485 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
486 err++;
487
488 tmp = cmd->stop_src;
489 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
490 if (!cmd->stop_src || tmp != cmd->stop_src)
491 err++;
492
493 if (err)
494 return 1;
495
496 /* step 2: make sure trigger sources are unique and mutually compatible */
497
828684f9 498 /* note that mutual compatibility is not an issue here */
086df5b5 499 if (cmd->scan_begin_src != TRIG_TIMER
0a85b6f0 500 && cmd->scan_begin_src != TRIG_EXT)
086df5b5
IM
501 err++;
502 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
503 err++;
504 if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)
505 err++;
506
507 if (err)
508 return 2;
509
510 /* step 3: make sure arguments are trivially compatible */
511
512 if (cmd->start_arg != 0) {
513 cmd->start_arg = 0;
514 err++;
515 }
516#define MAX_SPEED 10000 /* in nanoseconds */
517#define MIN_SPEED 1000000000 /* in nanoseconds */
518
519 if (cmd->scan_begin_src == TRIG_TIMER) {
520 if (cmd->scan_begin_arg < MAX_SPEED) {
521 cmd->scan_begin_arg = MAX_SPEED;
522 err++;
523 }
524 if (cmd->scan_begin_arg > MIN_SPEED) {
525 cmd->scan_begin_arg = MIN_SPEED;
526 err++;
527 }
528 } else {
529 /* external trigger */
530 /* should be level/edge, hi/lo specification here */
531 /* should specify multiple external triggers */
532 if (cmd->scan_begin_arg > 9) {
533 cmd->scan_begin_arg = 9;
534 err++;
535 }
536 }
537 if (cmd->convert_src == TRIG_TIMER) {
538 if (cmd->convert_arg < MAX_SPEED) {
539 cmd->convert_arg = MAX_SPEED;
540 err++;
541 }
542 if (cmd->convert_arg > MIN_SPEED) {
543 cmd->convert_arg = MIN_SPEED;
544 err++;
545 }
546 } else {
547 /* external trigger */
548 /* see above */
549 if (cmd->convert_arg > 9) {
550 cmd->convert_arg = 9;
551 err++;
552 }
553 }
554
555 if (cmd->scan_end_arg != cmd->chanlist_len) {
556 cmd->scan_end_arg = cmd->chanlist_len;
557 err++;
558 }
559 if (cmd->stop_src == TRIG_COUNT) {
560 if (cmd->stop_arg > 0x00ffffff) {
561 cmd->stop_arg = 0x00ffffff;
562 err++;
563 }
564 } else {
565 /* TRIG_NONE */
566 if (cmd->stop_arg != 0) {
567 cmd->stop_arg = 0;
568 err++;
569 }
570 }
571
572 if (err)
573 return 3;
574
575 /* step 4: fix up any arguments */
576
577 if (cmd->scan_begin_src == TRIG_TIMER) {
578 tmp = cmd->scan_begin_arg;
579 cb_pcidda_ns_to_timer(&cmd->scan_begin_arg,
0a85b6f0 580 cmd->flags & TRIG_ROUND_MASK);
086df5b5
IM
581 if (tmp != cmd->scan_begin_arg)
582 err++;
583 }
584 if (cmd->convert_src == TRIG_TIMER) {
585 tmp = cmd->convert_arg;
586 cb_pcidda_ns_to_timer(&cmd->convert_arg,
0a85b6f0 587 cmd->flags & TRIG_ROUND_MASK);
086df5b5
IM
588 if (tmp != cmd->convert_arg)
589 err++;
590 if (cmd->scan_begin_src == TRIG_TIMER &&
0a85b6f0
MT
591 cmd->scan_begin_arg <
592 cmd->convert_arg * cmd->scan_end_arg) {
086df5b5 593 cmd->scan_begin_arg =
0a85b6f0 594 cmd->convert_arg * cmd->scan_end_arg;
086df5b5
IM
595 err++;
596 }
597 }
598
599 if (err)
600 return 4;
601
602 return 0;
603}
604#endif
605
606/* This function doesn't require a particular form, this is just
607 * what happens to be used in some of the drivers. It should
608 * convert ns nanoseconds to a counter value suitable for programming
609 * the device. Also, it should adjust ns so that it cooresponds to
610 * the actual time that the device will use. */
611#if 0
612static int cb_pcidda_ns_to_timer(unsigned int *ns, int round)
613{
614 /* trivial timer */
615 return *ns;
616}
617#endif
618
0a85b6f0
MT
619static int cb_pcidda_ao_winsn(struct comedi_device *dev,
620 struct comedi_subdevice *s,
621 struct comedi_insn *insn, unsigned int *data)
086df5b5
IM
622{
623 unsigned int command;
624 unsigned int channel, range;
625
626 channel = CR_CHAN(insn->chanspec);
627 range = CR_RANGE(insn->chanspec);
628
2696fb57 629 /* adjust calibration dacs if range has changed */
086df5b5
IM
630 if (range != devpriv->ao_range[channel])
631 cb_pcidda_calibrate(dev, channel, range);
632
633 /* output channel configuration */
634 command = NOSU | ENABLEDAC;
635
636 /* output channel range */
637 switch (range) {
638 case 0:
639 command |= BIP | RANGE10V;
640 break;
641 case 1:
642 command |= BIP | RANGE5V;
643 break;
644 case 2:
645 command |= BIP | RANGE2V5;
646 break;
647 case 3:
648 command |= UNIP | RANGE10V;
649 break;
650 case 4:
651 command |= UNIP | RANGE5V;
652 break;
653 case 5:
654 command |= UNIP | RANGE2V5;
655 break;
656 };
657
658 /* output channel specification */
659 command |= channel << 2;
660 outw(command, devpriv->dac + DACONTROL);
661
662 /* write data */
663 outw(data[0], devpriv->dac + DADATA + channel * 2);
664
665 /* return the number of samples read/written */
666 return 1;
667}
668
2696fb57 669/* lowlevel read from eeprom */
da91b269 670static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
086df5b5
IM
671{
672 unsigned int value = 0;
673 int i;
2696fb57 674 const int value_width = 16; /* number of bits wide values are */
086df5b5
IM
675
676 for (i = 1; i <= value_width; i++) {
2696fb57 677 /* read bits most significant bit first */
20db7d7d 678 if (inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT)
086df5b5 679 value |= 1 << (value_width - i);
086df5b5
IM
680 }
681
682 return value;
683}
684
2696fb57 685/* lowlevel write to eeprom/dac */
da91b269 686static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
0a85b6f0 687 unsigned int num_bits)
086df5b5
IM
688{
689 int i;
690
691 for (i = 1; i <= num_bits; i++) {
2696fb57 692 /* send bits most significant bit first */
086df5b5
IM
693 if (value & (1 << (num_bits - i)))
694 devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
695 else
696 devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
697 outw_p(devpriv->dac_cal1_bits, devpriv->dac + DACALIBRATION1);
698 }
699}
700
2696fb57 701/* reads a 16 bit value from board's eeprom */
da91b269 702static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
0a85b6f0 703 unsigned int address)
086df5b5
IM
704{
705 unsigned int i;
706 unsigned int cal2_bits;
707 unsigned int value;
2696fb57
BP
708 const int max_num_caldacs = 4; /* one caldac for every two dac channels */
709 const int read_instruction = 0x6; /* bits to send to tell eeprom we want to read */
086df5b5
IM
710 const int instruction_length = 3;
711 const int address_length = 8;
712
2696fb57 713 /* send serial output stream to eeprom */
086df5b5 714 cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
2696fb57 715 /* deactivate caldacs (one caldac for every two channels) */
20db7d7d 716 for (i = 0; i < max_num_caldacs; i++)
086df5b5 717 cal2_bits |= DESELECT_CALDAC_BIT(i);
086df5b5
IM
718 outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
719
2696fb57 720 /* tell eeprom we want to read */
086df5b5 721 cb_pcidda_serial_out(dev, read_instruction, instruction_length);
2696fb57 722 /* send address we want to read from */
086df5b5
IM
723 cb_pcidda_serial_out(dev, address, address_length);
724
725 value = cb_pcidda_serial_in(dev);
726
2696fb57 727 /* deactivate eeprom */
086df5b5
IM
728 cal2_bits &= ~SELECT_EEPROM_BIT;
729 outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
730
731 return value;
732}
733
2696fb57 734/* writes to 8 bit calibration dacs */
0a85b6f0
MT
735static void cb_pcidda_write_caldac(struct comedi_device *dev,
736 unsigned int caldac, unsigned int channel,
737 unsigned int value)
086df5b5
IM
738{
739 unsigned int cal2_bits;
740 unsigned int i;
2696fb57
BP
741 const int num_channel_bits = 3; /* caldacs use 3 bit channel specification */
742 const int num_caldac_bits = 8; /* 8 bit calibration dacs */
743 const int max_num_caldacs = 4; /* one caldac for every two dac channels */
086df5b5
IM
744
745 /* write 3 bit channel */
746 cb_pcidda_serial_out(dev, channel, num_channel_bits);
2696fb57 747 /* write 8 bit caldac value */
086df5b5
IM
748 cb_pcidda_serial_out(dev, value, num_caldac_bits);
749
2696fb57
BP
750/*
751* latch stream into appropriate caldac deselect reference dac
752*/
086df5b5 753 cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
2696fb57 754 /* deactivate caldacs (one caldac for every two channels) */
20db7d7d 755 for (i = 0; i < max_num_caldacs; i++)
086df5b5 756 cal2_bits |= DESELECT_CALDAC_BIT(i);
2696fb57 757 /* activate the caldac we want */
086df5b5
IM
758 cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
759 outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
2696fb57 760 /* deactivate caldac */
086df5b5
IM
761 cal2_bits |= DESELECT_CALDAC_BIT(caldac);
762 outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
763}
764
2696fb57 765/* returns caldac that calibrates given analog out channel */
086df5b5
IM
766static unsigned int caldac_number(unsigned int channel)
767{
768 return channel / 2;
769}
770
2696fb57 771/* returns caldac channel that provides fine gain for given ao channel */
086df5b5
IM
772static unsigned int fine_gain_channel(unsigned int ao_channel)
773{
774 return 4 * (ao_channel % 2);
775}
776
2696fb57 777/* returns caldac channel that provides coarse gain for given ao channel */
086df5b5
IM
778static unsigned int coarse_gain_channel(unsigned int ao_channel)
779{
780 return 1 + 4 * (ao_channel % 2);
781}
782
2696fb57 783/* returns caldac channel that provides coarse offset for given ao channel */
086df5b5
IM
784static unsigned int coarse_offset_channel(unsigned int ao_channel)
785{
786 return 2 + 4 * (ao_channel % 2);
787}
788
2696fb57 789/* returns caldac channel that provides fine offset for given ao channel */
086df5b5
IM
790static unsigned int fine_offset_channel(unsigned int ao_channel)
791{
792 return 3 + 4 * (ao_channel % 2);
793}
794
2696fb57 795/* returns eeprom address that provides offset for given ao channel and range */
086df5b5 796static unsigned int offset_eeprom_address(unsigned int ao_channel,
0a85b6f0 797 unsigned int range)
086df5b5
IM
798{
799 return 0x7 + 2 * range + 12 * ao_channel;
800}
801
2696fb57 802/* returns eeprom address that provides gain calibration for given ao channel and range */
086df5b5 803static unsigned int gain_eeprom_address(unsigned int ao_channel,
0a85b6f0 804 unsigned int range)
086df5b5
IM
805{
806 return 0x8 + 2 * range + 12 * ao_channel;
807}
808
2696fb57 809/* returns upper byte of eeprom entry, which gives the coarse adjustment values */
086df5b5
IM
810static unsigned int eeprom_coarse_byte(unsigned int word)
811{
812 return (word >> 8) & 0xff;
813}
814
2696fb57 815/* returns lower byte of eeprom entry, which gives the fine adjustment values */
086df5b5
IM
816static unsigned int eeprom_fine_byte(unsigned int word)
817{
818 return word & 0xff;
819}
820
2696fb57 821/* set caldacs to eeprom values for given channel and range */
da91b269 822static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
0a85b6f0 823 unsigned int range)
086df5b5
IM
824{
825 unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
826
2696fb57 827 /* remember range so we can tell when we need to readjust calibration */
086df5b5
IM
828 devpriv->ao_range[channel] = range;
829
2696fb57 830 /* get values from eeprom data */
086df5b5 831 coarse_offset =
0a85b6f0
MT
832 eeprom_coarse_byte(devpriv->eeprom_data
833 [offset_eeprom_address(channel, range)]);
086df5b5 834 fine_offset =
0a85b6f0
MT
835 eeprom_fine_byte(devpriv->eeprom_data
836 [offset_eeprom_address(channel, range)]);
086df5b5 837 coarse_gain =
0a85b6f0
MT
838 eeprom_coarse_byte(devpriv->eeprom_data
839 [gain_eeprom_address(channel, range)]);
086df5b5 840 fine_gain =
0a85b6f0
MT
841 eeprom_fine_byte(devpriv->eeprom_data
842 [gain_eeprom_address(channel, range)]);
086df5b5 843
2696fb57 844 /* set caldacs */
086df5b5 845 cb_pcidda_write_caldac(dev, caldac_number(channel),
0a85b6f0 846 coarse_offset_channel(channel), coarse_offset);
086df5b5 847 cb_pcidda_write_caldac(dev, caldac_number(channel),
0a85b6f0 848 fine_offset_channel(channel), fine_offset);
086df5b5 849 cb_pcidda_write_caldac(dev, caldac_number(channel),
0a85b6f0 850 coarse_gain_channel(channel), coarse_gain);
086df5b5 851 cb_pcidda_write_caldac(dev, caldac_number(channel),
0a85b6f0 852 fine_gain_channel(channel), fine_gain);
086df5b5
IM
853}
854
855/*
856 * A convenient macro that defines init_module() and cleanup_module(),
857 * as necessary.
858 */
859COMEDI_PCI_INITCLEANUP(driver_cb_pcidda, cb_pcidda_pci_table);