cb_pcidda.c revision 086df5b5fea9c6bd1374acb6dea2c558247d4637
1086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
2086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    comedi/drivers/cb_pcidda.c
3086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    This intends to be a driver for the ComputerBoards / MeasurementComputing
4086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    PCI-DDA series.
5086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
6086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com>
7086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
8086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
9086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    COMEDI - Linux Control and Measurement Device Interface
10086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
11086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
12086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    This program is free software; you can redistribute it and/or modify
13086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    it under the terms of the GNU General Public License as published by
14086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    the Free Software Foundation; either version 2 of the License, or
15086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    (at your option) any later version.
16086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
17086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    This program is distributed in the hope that it will be useful,
18086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    but WITHOUT ANY WARRANTY; without even the implied warranty of
19086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    GNU General Public License for more details.
21086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
22086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    You should have received a copy of the GNU General Public License
23086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    along with this program; if not, write to the Free Software
24086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
26086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez*/
27086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
28086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezDriver: cb_pcidda
29086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezDescription: MeasurementComputing PCI-DDA series
30086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezAuthor: Ivan Martinez <ivanmr@altavista.com>, Frank Mori Hess <fmhess@users.sourceforge.net>
31086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezStatus: Supports 08/16, 04/16, 02/16, 08/12, 04/12, and 02/12
32086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezDevices: [Measurement Computing] PCI-DDA08/12 (cb_pcidda), PCI-DDA04/12,
33086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez  PCI-DDA02/12, PCI-DDA08/16, PCI-DDA04/16, PCI-DDA02/16
34086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
35086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezConfiguration options:
36086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez  [0] - PCI bus of device (optional)
37086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez  [1] - PCI slot of device (optional)
38086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez  If bus/slot is not specified, the first available PCI
39086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez  device will be used.
40086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
41086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezOnly simple analog output writing is supported.
42086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
43086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezSo far it has only been tested with:
44086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez  - PCI-DDA08/12
45086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezPlease report success/failure with other different cards to
46086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez<comedi@comedi.org>.
47086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez*/
48086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
49086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#include "../comedidev.h"
50086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
51086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#include "comedi_pci.h"
52086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#include "8255.h"
53086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
54086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PCI_VENDOR_ID_CB	0x1307	// PCI vendor number of ComputerBoards
55086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define N_BOARDS	10	// Number of boards in cb_pcidda_boards
56086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define EEPROM_SIZE	128	// number of entries in eeprom
57086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define MAX_AO_CHANNELS 8	// maximum number of ao channels for supported boards
58086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
59086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/* PCI-DDA base addresses */
60086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DIGITALIO_BADRINDEX	2
61086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// DIGITAL I/O is pci_dev->resource[2]
62086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DIGITALIO_SIZE 8
63086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// DIGITAL I/O uses 8 I/O port addresses
64086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DAC_BADRINDEX	3
65086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// DAC is pci_dev->resource[3]
66086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
67086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/* Digital I/O registers */
68086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PORT1A 0		// PORT 1A DATA
69086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
70086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PORT1B 1		// PORT 1B DATA
71086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
72086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PORT1C 2		// PORT 1C DATA
73086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
74086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define CONTROL1 3		// CONTROL REGISTER 1
75086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
76086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PORT2A 4		// PORT 2A DATA
77086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
78086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PORT2B 5		// PORT 2B DATA
79086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
80086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define PORT2C 6		// PORT 2C DATA
81086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
82086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define CONTROL2 7		// CONTROL REGISTER 2
83086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
84086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/* DAC registers */
85086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DACONTROL	0	// D/A CONTROL REGISTER
86086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	SU	0000001		// Simultaneous update enabled
87086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define NOSU	0000000		// Simultaneous update disabled
88086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	ENABLEDAC	0000002	// Enable specified DAC
89086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	DISABLEDAC	0000000	// Disable specified DAC
90086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define RANGE2V5	0000000	// 2.5V
91086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define RANGE5V	0000200		// 5V
92086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define RANGE10V	0000300	// 10V
93086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define UNIP	0000400		// Unipolar outputs
94086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define BIP	0000000		// Bipolar outputs
95086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
96086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DACALIBRATION1	4	// D/A CALIBRATION REGISTER 1
97086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//write bits
98086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	SERIAL_IN_BIT	0x1	// serial data input for eeprom, caldacs, reference dac
99086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	CAL_CHANNEL_MASK	(0x7 << 1)
100086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	CAL_CHANNEL_BITS(channel)	(((channel) << 1) & CAL_CHANNEL_MASK)
101086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//read bits
102086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	CAL_COUNTER_MASK	0x1f
103086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	CAL_COUNTER_OVERFLOW_BIT	0x20	// calibration counter overflow status bit
104086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	AO_BELOW_REF_BIT	0x40	// analog output is less than reference dac voltage
105086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	SERIAL_OUT_BIT	0x80	// serial data out, for reading from eeprom
106086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
107086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DACALIBRATION2	6	// D/A CALIBRATION REGISTER 2
108086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	SELECT_EEPROM_BIT	0x1	// send serial data in to eeprom
109086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	DESELECT_REF_DAC_BIT	0x2	// don't send serial data to MAX542 reference dac
110086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	DESELECT_CALDAC_BIT(n)	(0x4 << (n))	// don't send serial data to caldac n
111086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define	DUMMY_BIT	0x40	// manual says to set this bit with no explanation
112086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
113086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define DADATA	8		// FIRST D/A DATA REGISTER (0)
114086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
115086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic const comedi_lrange cb_pcidda_ranges = {
116086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	6,
117086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
118086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			BIP_RANGE(10),
119086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			BIP_RANGE(5),
120086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			BIP_RANGE(2.5),
121086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			UNI_RANGE(10),
122086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			UNI_RANGE(5),
123086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			UNI_RANGE(2.5),
124086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
125086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez};
126086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
127086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
128086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Board descriptions for two imaginary boards.  Describing the
129086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * boards in this way is optional, and completely driver-dependent.
130086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Some drivers use arrays such as this, other do not.
131086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
132086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martineztypedef struct cb_pcidda_board_struct {
133086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const char *name;
134086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	char status;		// Driver status:
135086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// 0 - tested
136086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// 1 - manual read, not tested
137086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// 2 - manual not read
138086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned short device_id;
139086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int ao_chans;
140086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int ao_bits;
141086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const comedi_lrange *ranges;
142086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez} cb_pcidda_board;
143086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic const cb_pcidda_board cb_pcidda_boards[] = {
144086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
145086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      name:	"pci-dda02/12",
146086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      status:	1,
147086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      device_id:0x20,
148086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_chans:2,
149086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_bits:	12,
150086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ranges:	&cb_pcidda_ranges,
151086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		},
152086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
153086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      name:	"pci-dda04/12",
154086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      status:	1,
155086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      device_id:0x21,
156086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_chans:4,
157086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_bits:	12,
158086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ranges:	&cb_pcidda_ranges,
159086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		},
160086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
161086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      name:	"pci-dda08/12",
162086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      status:	0,
163086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      device_id:0x22,
164086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_chans:8,
165086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_bits:	12,
166086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ranges:	&cb_pcidda_ranges,
167086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		},
168086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
169086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      name:	"pci-dda02/16",
170086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      status:	2,
171086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      device_id:0x23,
172086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_chans:2,
173086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_bits:	16,
174086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ranges:	&cb_pcidda_ranges,
175086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		},
176086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
177086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      name:	"pci-dda04/16",
178086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      status:	2,
179086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      device_id:0x24,
180086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_chans:4,
181086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_bits:	16,
182086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ranges:	&cb_pcidda_ranges,
183086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		},
184086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{
185086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      name:	"pci-dda08/16",
186086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      status:	0,
187086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      device_id:0x25,
188086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_chans:8,
189086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ao_bits:	16,
190086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	      ranges:	&cb_pcidda_ranges,
191086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		},
192086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez};
193086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
194086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
195086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{PCI_VENDOR_ID_CB, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
196086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{PCI_VENDOR_ID_CB, 0x0021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
197086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{PCI_VENDOR_ID_CB, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
198086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{PCI_VENDOR_ID_CB, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
199086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{PCI_VENDOR_ID_CB, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
200086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{PCI_VENDOR_ID_CB, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
201086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	{0}
202086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez};
203086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
204086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezMODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
205086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
206086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
207086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Useful for shorthand access to the particular board structure
208086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
209086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define thisboard ((const cb_pcidda_board *)dev->board_ptr)
210086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
211086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/* this structure is for data unique to this hardware driver.  If
212086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez   several hardware drivers keep similar information in this structure,
213086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez   feel free to suggest moving the variable to the comedi_device struct.  */
214086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martineztypedef struct {
215086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int data;
216086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
217086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* would be useful for a PCI device */
218086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	struct pci_dev *pci_dev;
219086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
220086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned long digitalio;
221086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned long dac;
222086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	//unsigned long control_status;
223086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	//unsigned long adc_fifo;
224086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int dac_cal1_bits;	// bits last written to da calibration register 1
225086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int ao_range[MAX_AO_CHANNELS];	// current range settings for output channels
226086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	u16 eeprom_data[EEPROM_SIZE];	// software copy of board's eeprom
227086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez} cb_pcidda_private;
228086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
229086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
230086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * most drivers define the following macro to make it easy to
231086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * access the private structure.
232086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
233086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define devpriv ((cb_pcidda_private *)dev->private)
234086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
235086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_attach(comedi_device * dev, comedi_devconfig * it);
236086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_detach(comedi_device * dev);
237086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//static int cb_pcidda_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
238086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_ao_winsn(comedi_device * dev, comedi_subdevice * s,
239086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	comedi_insn * insn, lsampl_t * data);
240086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//static int cb_pcidda_ai_cmd(comedi_device *dev,comedi_subdevice *s);
241086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//static int cb_pcidda_ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);
242086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//static int cb_pcidda_ns_to_timer(unsigned int *ns,int round);
243086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int cb_pcidda_serial_in(comedi_device * dev);
244086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic void cb_pcidda_serial_out(comedi_device * dev, unsigned int value,
245086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int num_bits);
246086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int cb_pcidda_read_eeprom(comedi_device * dev,
247086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int address);
248086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic void cb_pcidda_calibrate(comedi_device * dev, unsigned int channel,
249086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int range);
250086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
251086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
252086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * The comedi_driver structure tells the Comedi core module
253086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * which functions to call to configure/deconfigure (attach/detach)
254086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * the board, and also about the kernel module that contains
255086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * the device code.
256086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
257086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic comedi_driver driver_cb_pcidda = {
258086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez      driver_name:"cb_pcidda",
259086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez      module:THIS_MODULE,
260086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez      attach:cb_pcidda_attach,
261086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez      detach:cb_pcidda_detach,
262086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez};
263086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
264086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
265086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Attach is called by the Comedi core to configure the driver
266086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * for a particular board.
267086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
268086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_attach(comedi_device * dev, comedi_devconfig * it)
269086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
270086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	comedi_subdevice *s;
271086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	struct pci_dev *pcidev;
272086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int index;
273086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
274086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("comedi%d: cb_pcidda: ", dev->minor);
275086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
276086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
277086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Allocate the private structure area.
278086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
279086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (alloc_private(dev, sizeof(cb_pcidda_private)) < 0)
280086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return -ENOMEM;
281086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
282086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
283086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Probe the device to determine what device in the series it is.
284086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
285086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("\n");
286086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
287086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
288086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		pcidev != NULL;
289086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
290086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (pcidev->vendor == PCI_VENDOR_ID_CB) {
291086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			if (it->options[0] || it->options[1]) {
292086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez				if (pcidev->bus->number != it->options[0] ||
293086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez					PCI_SLOT(pcidev->devfn) !=
294086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez					it->options[1]) {
295086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez					continue;
296086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez				}
297086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			}
298086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			for (index = 0; index < N_BOARDS; index++) {
299086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez				if (cb_pcidda_boards[index].device_id ==
300086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez					pcidev->device) {
301086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez					goto found;
302086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez				}
303086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			}
304086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
305086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
306086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (!pcidev) {
307086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		printk("Not a ComputerBoards/MeasurementComputing card on requested position\n");
308086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return -EIO;
309086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
310086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez      found:
311086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	devpriv->pci_dev = pcidev;
312086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	dev->board_ptr = cb_pcidda_boards + index;
313086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// "thisboard" macro can be used from here.
314086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("Found %s at requested position\n", thisboard->name);
315086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
316086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/*
317086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 * Enable PCI device and request regions.
318086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 */
319086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (comedi_pci_enable(pcidev, thisboard->name)) {
320086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		printk("cb_pcidda: failed to enable PCI device and request regions\n");
321086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return -EIO;
322086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
323086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
324086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
325086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Allocate the I/O ports.
326086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
327086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	devpriv->digitalio =
328086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		pci_resource_start(devpriv->pci_dev, DIGITALIO_BADRINDEX);
329086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	devpriv->dac = pci_resource_start(devpriv->pci_dev, DAC_BADRINDEX);
330086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
331086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
332086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Warn about the status of the driver.
333086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
334086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (thisboard->status == 2)
335086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		printk("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. " "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. " "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n");
336086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
337086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
338086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Initialize dev->board_name.
339086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
340086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	dev->board_name = thisboard->name;
341086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
342086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
343086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Allocate the subdevice structures.
344086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
345086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (alloc_subdevices(dev, 3) < 0)
346086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return -ENOMEM;
347086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
348086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s = dev->subdevices + 0;
349086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* analog output subdevice */
350086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s->type = COMEDI_SUBD_AO;
351086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s->subdev_flags = SDF_WRITABLE;
352086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s->n_chan = thisboard->ao_chans;
353086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s->maxdata = (1 << thisboard->ao_bits) - 1;
354086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s->range_table = thisboard->ranges;
355086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s->insn_write = cb_pcidda_ao_winsn;
356086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//      s->subdev_flags |= SDF_CMD_READ;
357086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//      s->do_cmd = cb_pcidda_ai_cmd;
358086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez//      s->do_cmdtest = cb_pcidda_ai_cmdtest;
359086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
360086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// two 8255 digital io subdevices
361086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s = dev->subdevices + 1;
362086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	subdev_8255_init(dev, s, NULL, devpriv->digitalio);
363086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	s = dev->subdevices + 2;
364086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A);
365086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
366086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk(" eeprom:");
367086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (index = 0; index < EEPROM_SIZE; index++) {
368086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
369086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		printk(" %i:0x%x ", index, devpriv->eeprom_data[index]);
370086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
371086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("\n");
372086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
373086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// set calibrations dacs
374086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (index = 0; index < thisboard->ao_chans; index++)
375086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]);
376086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
377086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 1;
378086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
379086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
380086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
381086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * _detach is called to deconfigure a device.  It should deallocate
382086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * resources.
383086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * This function is also called when _attach() fails, so it should be
384086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * careful not to release resources that were not necessarily
385086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * allocated by _attach().  dev->private and dev->subdevices are
386086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * deallocated automatically by the core.
387086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
388086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_detach(comedi_device * dev)
389086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
390086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
391086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * Deallocate the I/O ports.
392086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
393086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (devpriv) {
394086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (devpriv->pci_dev) {
395086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			if (devpriv->dac) {
396086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez				comedi_pci_disable(devpriv->pci_dev);
397086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			}
398086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			pci_dev_put(devpriv->pci_dev);
399086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
400086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
401086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// cleanup 8255
402086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (dev->subdevices) {
403086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		subdev_8255_cleanup(dev, dev->subdevices + 1);
404086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		subdev_8255_cleanup(dev, dev->subdevices + 2);
405086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
406086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
407086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("comedi%d: cb_pcidda: remove\n", dev->minor);
408086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
409086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 0;
410086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
411086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
412086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
413086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * I will program this later... ;-)
414086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
415086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#if 0
416086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_ai_cmd(comedi_device * dev, comedi_subdevice * s)
417086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
418086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("cb_pcidda_ai_cmd\n");
419086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("subdev: %d\n", cmd->subdev);
420086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("flags: %d\n", cmd->flags);
421086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("start_src: %d\n", cmd->start_src);
422086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("start_arg: %d\n", cmd->start_arg);
423086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("scan_begin_src: %d\n", cmd->scan_begin_src);
424086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("convert_src: %d\n", cmd->convert_src);
425086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("convert_arg: %d\n", cmd->convert_arg);
426086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("scan_end_src: %d\n", cmd->scan_end_src);
427086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("scan_end_arg: %d\n", cmd->scan_end_arg);
428086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("stop_src: %d\n", cmd->stop_src);
429086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("stop_arg: %d\n", cmd->stop_arg);
430086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	printk("chanlist_len: %d\n", cmd->chanlist_len);
431086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
432086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#endif
433086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
434086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#if 0
435086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
436086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	comedi_cmd * cmd)
437086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
438086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int err = 0;
439086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int tmp;
440086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
441086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* cmdtest tests a particular command to see if it is valid.
442086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 * Using the cmdtest ioctl, a user can create a valid cmd
443086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 * and then have it executes by the cmd ioctl.
444086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 *
445086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
446086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	 * the command passes. */
447086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
448086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* step 1: make sure trigger sources are trivially valid */
449086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
450086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	tmp = cmd->start_src;
451086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cmd->start_src &= TRIG_NOW;
452086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (!cmd->start_src || tmp != cmd->start_src)
453086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
454086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
455086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	tmp = cmd->scan_begin_src;
456086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
457086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
458086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
459086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
460086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	tmp = cmd->convert_src;
461086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
462086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (!cmd->convert_src || tmp != cmd->convert_src)
463086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
464086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
465086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	tmp = cmd->scan_end_src;
466086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cmd->scan_end_src &= TRIG_COUNT;
467086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
468086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
469086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
470086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	tmp = cmd->stop_src;
471086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
472086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (!cmd->stop_src || tmp != cmd->stop_src)
473086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
474086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
475086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (err)
476086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return 1;
477086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
478086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* step 2: make sure trigger sources are unique and mutually compatible */
479086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
480086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* note that mutual compatiblity is not an issue here */
481086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->scan_begin_src != TRIG_TIMER
482086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		&& cmd->scan_begin_src != TRIG_EXT)
483086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
484086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
485086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
486086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)
487086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
488086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
489086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (err)
490086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return 2;
491086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
492086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* step 3: make sure arguments are trivially compatible */
493086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
494086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->start_arg != 0) {
495086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cmd->start_arg = 0;
496086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
497086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
498086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define MAX_SPEED	10000	/* in nanoseconds */
499086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#define MIN_SPEED	1000000000	/* in nanoseconds */
500086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
501086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
502086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->scan_begin_arg < MAX_SPEED) {
503086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->scan_begin_arg = MAX_SPEED;
504086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
505086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
506086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->scan_begin_arg > MIN_SPEED) {
507086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->scan_begin_arg = MIN_SPEED;
508086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
509086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
510086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	} else {
511086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		/* external trigger */
512086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		/* should be level/edge, hi/lo specification here */
513086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		/* should specify multiple external triggers */
514086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->scan_begin_arg > 9) {
515086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->scan_begin_arg = 9;
516086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
517086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
518086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
519086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->convert_src == TRIG_TIMER) {
520086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->convert_arg < MAX_SPEED) {
521086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->convert_arg = MAX_SPEED;
522086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
523086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
524086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->convert_arg > MIN_SPEED) {
525086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->convert_arg = MIN_SPEED;
526086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
527086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
528086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	} else {
529086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		/* external trigger */
530086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		/* see above */
531086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->convert_arg > 9) {
532086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->convert_arg = 9;
533086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
534086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
535086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
536086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
537086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->scan_end_arg != cmd->chanlist_len) {
538086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cmd->scan_end_arg = cmd->chanlist_len;
539086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		err++;
540086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
541086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->stop_src == TRIG_COUNT) {
542086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->stop_arg > 0x00ffffff) {
543086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->stop_arg = 0x00ffffff;
544086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
545086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
546086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	} else {
547086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		/* TRIG_NONE */
548086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->stop_arg != 0) {
549086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->stop_arg = 0;
550086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
551086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
552086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
553086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
554086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (err)
555086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return 3;
556086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
557086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* step 4: fix up any arguments */
558086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
559086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->scan_begin_src == TRIG_TIMER) {
560086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		tmp = cmd->scan_begin_arg;
561086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cb_pcidda_ns_to_timer(&cmd->scan_begin_arg,
562086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->flags & TRIG_ROUND_MASK);
563086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (tmp != cmd->scan_begin_arg)
564086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
565086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
566086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (cmd->convert_src == TRIG_TIMER) {
567086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		tmp = cmd->convert_arg;
568086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cb_pcidda_ns_to_timer(&cmd->convert_arg,
569086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->flags & TRIG_ROUND_MASK);
570086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (tmp != cmd->convert_arg)
571086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
572086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (cmd->scan_begin_src == TRIG_TIMER &&
573086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->scan_begin_arg <
574086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->convert_arg * cmd->scan_end_arg) {
575086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			cmd->scan_begin_arg =
576086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez				cmd->convert_arg * cmd->scan_end_arg;
577086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			err++;
578086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
579086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
580086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
581086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (err)
582086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		return 4;
583086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
584086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 0;
585086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
586086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#endif
587086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
588086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/* This function doesn't require a particular form, this is just
589086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * what happens to be used in some of the drivers.  It should
590086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * convert ns nanoseconds to a counter value suitable for programming
591086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * the device.  Also, it should adjust ns so that it cooresponds to
592086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * the actual time that the device will use. */
593086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#if 0
594086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_ns_to_timer(unsigned int *ns, int round)
595086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
596086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* trivial timer */
597086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return *ns;
598086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
599086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez#endif
600086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
601086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic int cb_pcidda_ao_winsn(comedi_device * dev, comedi_subdevice * s,
602086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	comedi_insn * insn, lsampl_t * data)
603086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
604086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int command;
605086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int channel, range;
606086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
607086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	channel = CR_CHAN(insn->chanspec);
608086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	range = CR_RANGE(insn->chanspec);
609086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
610086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// adjust calibration dacs if range has changed
611086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	if (range != devpriv->ao_range[channel])
612086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cb_pcidda_calibrate(dev, channel, range);
613086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
614086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* output channel configuration */
615086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	command = NOSU | ENABLEDAC;
616086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
617086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* output channel range */
618086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	switch (range) {
619086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	case 0:
620086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		command |= BIP | RANGE10V;
621086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		break;
622086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	case 1:
623086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		command |= BIP | RANGE5V;
624086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		break;
625086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	case 2:
626086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		command |= BIP | RANGE2V5;
627086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		break;
628086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	case 3:
629086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		command |= UNIP | RANGE10V;
630086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		break;
631086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	case 4:
632086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		command |= UNIP | RANGE5V;
633086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		break;
634086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	case 5:
635086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		command |= UNIP | RANGE2V5;
636086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		break;
637086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	};
638086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
639086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* output channel specification */
640086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	command |= channel << 2;
641086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	outw(command, devpriv->dac + DACONTROL);
642086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
643086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* write data */
644086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	outw(data[0], devpriv->dac + DADATA + channel * 2);
645086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
646086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* return the number of samples read/written */
647086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 1;
648086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
649086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
650086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// lowlevel read from eeprom
651086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int cb_pcidda_serial_in(comedi_device * dev)
652086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
653086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int value = 0;
654086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int i;
655086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int value_width = 16;	// number of bits wide values are
656086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
657086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (i = 1; i <= value_width; i++) {
658086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		// read bits most significant bit first
659086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT) {
660086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			value |= 1 << (value_width - i);
661086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		}
662086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
663086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
664086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return value;
665086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
666086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
667086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// lowlevel write to eeprom/dac
668086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic void cb_pcidda_serial_out(comedi_device * dev, unsigned int value,
669086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int num_bits)
670086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
671086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	int i;
672086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
673086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (i = 1; i <= num_bits; i++) {
674086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		// send bits most significant bit first
675086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		if (value & (1 << (num_bits - i)))
676086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
677086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		else
678086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez			devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
679086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		outw_p(devpriv->dac_cal1_bits, devpriv->dac + DACALIBRATION1);
680086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
681086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
682086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
683086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// reads a 16 bit value from board's eeprom
684086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int cb_pcidda_read_eeprom(comedi_device * dev,
685086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int address)
686086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
687086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int i;
688086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int cal2_bits;
689086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int value;
690086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int max_num_caldacs = 4;	// one caldac for every two dac channels
691086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int read_instruction = 0x6;	// bits to send to tell eeprom we want to read
692086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int instruction_length = 3;
693086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int address_length = 8;
694086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
695086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// send serial output stream to eeprom
696086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
697086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// deactivate caldacs (one caldac for every two channels)
698086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (i = 0; i < max_num_caldacs; i++) {
699086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cal2_bits |= DESELECT_CALDAC_BIT(i);
700086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
701086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
702086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
703086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// tell eeprom we want to read
704086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_serial_out(dev, read_instruction, instruction_length);
705086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// send address we want to read from
706086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_serial_out(dev, address, address_length);
707086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
708086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	value = cb_pcidda_serial_in(dev);
709086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
710086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// deactivate eeprom
711086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cal2_bits &= ~SELECT_EEPROM_BIT;
712086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
713086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
714086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return value;
715086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
716086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
717086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// writes to 8 bit calibration dacs
718086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic void cb_pcidda_write_caldac(comedi_device * dev, unsigned int caldac,
719086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int channel, unsigned int value)
720086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
721086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int cal2_bits;
722086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int i;
723086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int num_channel_bits = 3;	// caldacs use 3 bit channel specification
724086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int num_caldac_bits = 8;	// 8 bit calibration dacs
725086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	const int max_num_caldacs = 4;	// one caldac for every two dac channels
726086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
727086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	/* write 3 bit channel */
728086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_serial_out(dev, channel, num_channel_bits);
729086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// write 8 bit caldac value
730086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_serial_out(dev, value, num_caldac_bits);
731086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
732086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// latch stream into appropriate caldac
733086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// deselect reference dac
734086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
735086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// deactivate caldacs (one caldac for every two channels)
736086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	for (i = 0; i < max_num_caldacs; i++) {
737086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		cal2_bits |= DESELECT_CALDAC_BIT(i);
738086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	}
739086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// activate the caldac we want
740086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
741086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
742086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// deactivate caldac
743086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cal2_bits |= DESELECT_CALDAC_BIT(caldac);
744086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
745086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
746086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
747086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns caldac that calibrates given analog out channel
748086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int caldac_number(unsigned int channel)
749086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
750086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return channel / 2;
751086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
752086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
753086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns caldac channel that provides fine gain for given ao channel
754086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int fine_gain_channel(unsigned int ao_channel)
755086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
756086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 4 * (ao_channel % 2);
757086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
758086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
759086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns caldac channel that provides coarse gain for given ao channel
760086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int coarse_gain_channel(unsigned int ao_channel)
761086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
762086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 1 + 4 * (ao_channel % 2);
763086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
764086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
765086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns caldac channel that provides coarse offset for given ao channel
766086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int coarse_offset_channel(unsigned int ao_channel)
767086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
768086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 2 + 4 * (ao_channel % 2);
769086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
770086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
771086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns caldac channel that provides fine offset for given ao channel
772086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int fine_offset_channel(unsigned int ao_channel)
773086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
774086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 3 + 4 * (ao_channel % 2);
775086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
776086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
777086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns eeprom address that provides offset for given ao channel and range
778086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int offset_eeprom_address(unsigned int ao_channel,
779086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int range)
780086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
781086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 0x7 + 2 * range + 12 * ao_channel;
782086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
783086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
784086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns eeprom address that provides gain calibration for given ao channel and range
785086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int gain_eeprom_address(unsigned int ao_channel,
786086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int range)
787086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
788086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return 0x8 + 2 * range + 12 * ao_channel;
789086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
790086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
791086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns upper byte of eeprom entry, which gives the coarse adjustment values
792086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int eeprom_coarse_byte(unsigned int word)
793086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
794086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return (word >> 8) & 0xff;
795086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
796086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
797086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// returns lower byte of eeprom entry, which gives the fine adjustment values
798086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic unsigned int eeprom_fine_byte(unsigned int word)
799086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
800086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	return word & 0xff;
801086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
802086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
803086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez// set caldacs to eeprom values for given channel and range
804086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinezstatic void cb_pcidda_calibrate(comedi_device * dev, unsigned int channel,
805086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int range)
806086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez{
807086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
808086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
809086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// remember range so we can tell when we need to readjust calibration
810086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	devpriv->ao_range[channel] = range;
811086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
812086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// get values from eeprom data
813086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	coarse_offset =
814086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_coarse_byte(devpriv->
815086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_data[offset_eeprom_address(channel, range)]);
816086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	fine_offset =
817086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_fine_byte(devpriv->
818086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_data[offset_eeprom_address(channel, range)]);
819086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	coarse_gain =
820086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_coarse_byte(devpriv->
821086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_data[gain_eeprom_address(channel, range)]);
822086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	fine_gain =
823086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_fine_byte(devpriv->
824086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		eeprom_data[gain_eeprom_address(channel, range)]);
825086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
826086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	// set caldacs
827086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_write_caldac(dev, caldac_number(channel),
828086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		coarse_offset_channel(channel), coarse_offset);
829086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_write_caldac(dev, caldac_number(channel),
830086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		fine_offset_channel(channel), fine_offset);
831086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_write_caldac(dev, caldac_number(channel),
832086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		coarse_gain_channel(channel), coarse_gain);
833086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez	cb_pcidda_write_caldac(dev, caldac_number(channel),
834086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez		fine_gain_channel(channel), fine_gain);
835086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez}
836086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez
837086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez/*
838086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * A convenient macro that defines init_module() and cleanup_module(),
839086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez * as necessary.
840086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan Martinez */
841086df5b5fea9c6bd1374acb6dea2c558247d4637Ivan MartinezCOMEDI_PCI_INITCLEANUP(driver_cb_pcidda, cb_pcidda_pci_table);
842