2 comedi/drivers/ni_670x.c
3 Hardware driver for NI 670x devices
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Description: National Instruments 670x
26 Author: Bart Joris <bjoris@advalvas.be>
27 Updated: Wed, 11 Dec 2002 18:25:35 -0800
28 Devices: [National Instruments] PCI-6703 (ni_670x), PCI-6704
31 Commands are not supported.
35 Bart Joris <bjoris@advalvas.be> Last updated on 20/08/2001
39 322110a.pdf PCI/PXI-6704 User Manual
40 322110b.pdf PCI/PXI-6703/6704 User Manual
44 #include <linux/interrupt.h>
45 #include <linux/slab.h>
46 #include "../comedidev.h"
50 #define AO_VALUE_OFFSET 0x00
51 #define AO_CHAN_OFFSET 0x0c
52 #define AO_STATUS_OFFSET 0x10
53 #define AO_CONTROL_OFFSET 0x10
54 #define DIO_PORT0_DIR_OFFSET 0x20
55 #define DIO_PORT0_DATA_OFFSET 0x24
56 #define DIO_PORT1_DIR_OFFSET 0x28
57 #define DIO_PORT1_DATA_OFFSET 0x2c
58 #define MISC_STATUS_OFFSET 0x14
59 #define MISC_CONTROL_OFFSET 0x14
61 /* Board description*/
63 struct ni_670x_board
{
65 unsigned short dev_id
;
66 unsigned short ao_chans
;
69 static const struct ni_670x_board ni_670x_boards
[] = {
85 struct ni_670x_private
{
87 struct mite_struct
*mite
;
90 unsigned int ao_readback
[32];
93 static struct comedi_lrange range_0_20mA
= { 1, {RANGE_mA(0, 20)} };
95 static int ni_670x_ao_winsn(struct comedi_device
*dev
,
96 struct comedi_subdevice
*s
,
97 struct comedi_insn
*insn
, unsigned int *data
)
99 struct ni_670x_private
*devpriv
= dev
->private;
101 int chan
= CR_CHAN(insn
->chanspec
);
103 /* Channel number mapping :
105 NI 6703/ NI 6704 | NI 6704 Only
106 ----------------------------------------------------
107 vch(0) : 0 | ich(16) : 1
108 vch(1) : 2 | ich(17) : 3
112 vch(15) : 30 | ich(31) : 31 */
114 for (i
= 0; i
< insn
->n
; i
++) {
115 /* First write in channel register which channel to use */
116 writel(((chan
& 15) << 1) | ((chan
& 16) >> 4),
117 devpriv
->mite
->daq_io_addr
+ AO_CHAN_OFFSET
);
118 /* write channel value */
119 writel(data
[i
], devpriv
->mite
->daq_io_addr
+ AO_VALUE_OFFSET
);
120 devpriv
->ao_readback
[chan
] = data
[i
];
126 static int ni_670x_ao_rinsn(struct comedi_device
*dev
,
127 struct comedi_subdevice
*s
,
128 struct comedi_insn
*insn
, unsigned int *data
)
130 struct ni_670x_private
*devpriv
= dev
->private;
132 int chan
= CR_CHAN(insn
->chanspec
);
134 for (i
= 0; i
< insn
->n
; i
++)
135 data
[i
] = devpriv
->ao_readback
[chan
];
140 static int ni_670x_dio_insn_bits(struct comedi_device
*dev
,
141 struct comedi_subdevice
*s
,
142 struct comedi_insn
*insn
, unsigned int *data
)
144 struct ni_670x_private
*devpriv
= dev
->private;
145 void __iomem
*io_addr
= devpriv
->mite
->daq_io_addr
+
146 DIO_PORT0_DATA_OFFSET
;
147 unsigned int mask
= data
[0];
148 unsigned int bits
= data
[1];
152 s
->state
|= (bits
& mask
);
154 writel(s
->state
, io_addr
);
157 data
[1] = readl(io_addr
);
162 static int ni_670x_dio_insn_config(struct comedi_device
*dev
,
163 struct comedi_subdevice
*s
,
164 struct comedi_insn
*insn
, unsigned int *data
)
166 struct ni_670x_private
*devpriv
= dev
->private;
167 int chan
= CR_CHAN(insn
->chanspec
);
170 case INSN_CONFIG_DIO_OUTPUT
:
171 s
->io_bits
|= 1 << chan
;
173 case INSN_CONFIG_DIO_INPUT
:
174 s
->io_bits
&= ~(1 << chan
);
176 case INSN_CONFIG_DIO_QUERY
:
178 (s
->io_bits
& (1 << chan
)) ? COMEDI_OUTPUT
: COMEDI_INPUT
;
185 writel(s
->io_bits
, devpriv
->mite
->daq_io_addr
+ DIO_PORT0_DIR_OFFSET
);
190 static const struct ni_670x_board
*
191 ni_670x_find_boardinfo(struct pci_dev
*pcidev
)
193 unsigned int dev_id
= pcidev
->device
;
196 for (n
= 0; n
< ARRAY_SIZE(ni_670x_boards
); n
++) {
197 const struct ni_670x_board
*board
= &ni_670x_boards
[n
];
198 if (board
->dev_id
== dev_id
)
204 static int __devinit
ni_670x_attach_pci(struct comedi_device
*dev
,
205 struct pci_dev
*pcidev
)
207 const struct ni_670x_board
*thisboard
;
208 struct ni_670x_private
*devpriv
;
209 struct comedi_subdevice
*s
;
213 devpriv
= kzalloc(sizeof(*devpriv
), GFP_KERNEL
);
216 dev
->private = devpriv
;
218 dev
->board_ptr
= ni_670x_find_boardinfo(pcidev
);
221 devpriv
->mite
= mite_alloc(pcidev
);
224 thisboard
= comedi_board(dev
);
226 ret
= mite_setup(devpriv
->mite
);
228 dev_warn(dev
->class_dev
, "error setting up mite\n");
231 dev
->board_name
= thisboard
->name
;
233 ret
= comedi_alloc_subdevices(dev
, 2);
237 s
= &dev
->subdevices
[0];
238 /* analog output subdevice */
239 s
->type
= COMEDI_SUBD_AO
;
240 s
->subdev_flags
= SDF_WRITABLE
;
241 s
->n_chan
= thisboard
->ao_chans
;
243 if (s
->n_chan
== 32) {
244 const struct comedi_lrange
**range_table_list
;
246 range_table_list
= kmalloc(sizeof(struct comedi_lrange
*) * 32,
248 if (!range_table_list
)
250 s
->range_table_list
= range_table_list
;
251 for (i
= 0; i
< 16; i
++) {
252 range_table_list
[i
] = &range_bipolar10
;
253 range_table_list
[16 + i
] = &range_0_20mA
;
256 s
->range_table
= &range_bipolar10
;
258 s
->insn_write
= &ni_670x_ao_winsn
;
259 s
->insn_read
= &ni_670x_ao_rinsn
;
261 s
= &dev
->subdevices
[1];
262 /* digital i/o subdevice */
263 s
->type
= COMEDI_SUBD_DIO
;
264 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
267 s
->range_table
= &range_digital
;
268 s
->insn_bits
= ni_670x_dio_insn_bits
;
269 s
->insn_config
= ni_670x_dio_insn_config
;
271 /* Config of misc registers */
272 writel(0x10, devpriv
->mite
->daq_io_addr
+ MISC_CONTROL_OFFSET
);
273 /* Config of ao registers */
274 writel(0x00, devpriv
->mite
->daq_io_addr
+ AO_CONTROL_OFFSET
);
276 dev_info(dev
->class_dev
, "%s: %s attached\n",
277 dev
->driver
->driver_name
, dev
->board_name
);
282 static void ni_670x_detach(struct comedi_device
*dev
)
284 struct ni_670x_private
*devpriv
= dev
->private;
285 struct comedi_subdevice
*s
;
287 if (dev
->n_subdevices
) {
288 s
= &dev
->subdevices
[0];
290 kfree(s
->range_table_list
);
292 if (devpriv
&& devpriv
->mite
) {
293 mite_unsetup(devpriv
->mite
);
294 mite_free(devpriv
->mite
);
298 static struct comedi_driver ni_670x_driver
= {
299 .driver_name
= "ni_670x",
300 .module
= THIS_MODULE
,
301 .attach_pci
= ni_670x_attach_pci
,
302 .detach
= ni_670x_detach
,
305 static int __devinit
ni_670x_pci_probe(struct pci_dev
*dev
,
306 const struct pci_device_id
*ent
)
308 return comedi_pci_auto_config(dev
, &ni_670x_driver
);
311 static void __devexit
ni_670x_pci_remove(struct pci_dev
*dev
)
313 comedi_pci_auto_unconfig(dev
);
316 static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table
) = {
317 { PCI_DEVICE(PCI_VENDOR_ID_NI
, 0x2c90) },
318 { PCI_DEVICE(PCI_VENDOR_ID_NI
, 0x1920) },
321 MODULE_DEVICE_TABLE(pci
, ni_670x_pci_table
);
323 static struct pci_driver ni_670x_pci_driver
= {
325 .id_table
= ni_670x_pci_table
,
326 .probe
= ni_670x_pci_probe
,
327 .remove
= __devexit_p(ni_670x_pci_remove
),
329 module_comedi_pci_driver(ni_670x_driver
, ni_670x_pci_driver
);
331 MODULE_AUTHOR("Comedi http://www.comedi.org");
332 MODULE_DESCRIPTION("Comedi low-level driver");
333 MODULE_LICENSE("GPL");