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