ni_atmio.c revision 32d878a285250fd30acda57033a9e51e77ab50a3
1/*
2    comedi/drivers/ni_atmio.c
3    Hardware driver for NI AT-MIO E series cards
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
7
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.
12
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.
17*/
18/*
19Driver: ni_atmio
20Description: National Instruments AT-MIO-E series
21Author: ds
22Devices: [National Instruments] AT-MIO-16E-1 (ni_atmio),
23  AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3,
24  AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10
25Status: works
26Updated: Thu May  1 20:03:02 CDT 2003
27
28The driver has 2.6 kernel isapnp support, and
29will automatically probe for a supported board if the
30I/O base is left unspecified with comedi_config.
31However, many of
32the isapnp id numbers are unknown.  If your board is not
33recognized, please send the output of 'cat /proc/isapnp'
34(you may need to modprobe the isa-pnp module for
35/proc/isapnp to exist) so the
36id numbers for your board can be added to the driver.
37
38Otherwise, you can use the isapnptools package to configure
39your board.  Use isapnp to
40configure the I/O base and IRQ for the board, and then pass
41the same values as
42parameters in comedi_config.  A sample isapnp.conf file is included
43in the etc/ directory of Comedilib.
44
45Comedilib includes a utility to autocalibrate these boards.  The
46boards seem to boot into a state where the all calibration DACs
47are at one extreme of their range, thus the default calibration
48is terrible.  Calibration at boot is strongly encouraged.
49
50To use the extended digital I/O on some of the boards, enable the
518255 driver when configuring the Comedi source tree.
52
53External triggering is supported for some events.  The channel index
54(scan_begin_arg, etc.) maps to PFI0 - PFI9.
55
56Some of the more esoteric triggering possibilities of these boards
57are not supported.
58*/
59/*
60	The real guts of the driver is in ni_mio_common.c, which is included
61	both here and in ni_pcimio.c
62
63	Interrupt support added by Truxton Fulton <trux@truxton.com>
64
65	References for specifications:
66
67	   340747b.pdf  Register Level Programmer Manual (obsolete)
68	   340747c.pdf  Register Level Programmer Manual (new)
69	   DAQ-STC reference manual
70
71	Other possibly relevant info:
72
73	   320517c.pdf  User manual (obsolete)
74	   320517f.pdf  User manual (new)
75	   320889a.pdf  delete
76	   320906c.pdf  maximum signal ratings
77	   321066a.pdf  about 16x
78	   321791a.pdf  discontinuation of at-mio-16e-10 rev. c
79	   321808a.pdf  about at-mio-16e-10 rev P
80	   321837a.pdf  discontinuation of at-mio-16de-10 rev d
81	   321838a.pdf  about at-mio-16de-10 rev N
82
83	ISSUES:
84
85	need to deal with external reference for DAC, and other DAC
86	properties in board properties
87
88	deal with at-mio-16de-10 revision D to N changes, etc.
89
90*/
91
92#include <linux/module.h>
93#include <linux/interrupt.h>
94#include "../comedidev.h"
95
96#include <linux/isapnp.h>
97
98#include "ni_stc.h"
99#include "8255.h"
100
101#define ATMIO 1
102#undef PCIMIO
103
104/*
105 *  AT specific setup
106 */
107
108#define NI_SIZE 0x20
109
110static const struct ni_board_struct ni_boards[] = {
111	{.device_id = 44,
112	 .isapnp_id = 0x0000,	/* XXX unknown */
113	 .name = "at-mio-16e-1",
114	 .n_adchan = 16,
115	 .adbits = 12,
116	 .ai_fifo_depth = 8192,
117	 .alwaysdither = 0,
118	 .gainlkup = ai_gain_16,
119	 .ai_speed = 800,
120	 .n_aochan = 2,
121	 .aobits = 12,
122	 .ao_fifo_depth = 2048,
123	 .ao_range_table = &range_ni_E_ao_ext,
124	 .ao_unipolar = 1,
125	 .ao_speed = 1000,
126	 .has_8255 = 0,
127	 .num_p0_dio_channels = 8,
128	 .caldac = {mb88341},
129	 },
130	{.device_id = 25,
131	 .isapnp_id = 0x1900,
132	 .name = "at-mio-16e-2",
133	 .n_adchan = 16,
134	 .adbits = 12,
135	 .ai_fifo_depth = 2048,
136	 .alwaysdither = 0,
137	 .gainlkup = ai_gain_16,
138	 .ai_speed = 2000,
139	 .n_aochan = 2,
140	 .aobits = 12,
141	 .ao_fifo_depth = 2048,
142	 .ao_range_table = &range_ni_E_ao_ext,
143	 .ao_unipolar = 1,
144	 .ao_speed = 1000,
145	 .has_8255 = 0,
146	 .num_p0_dio_channels = 8,
147	 .caldac = {mb88341},
148	 },
149	{.device_id = 36,
150	 .isapnp_id = 0x2400,
151	 .name = "at-mio-16e-10",
152	 .n_adchan = 16,
153	 .adbits = 12,
154	 .ai_fifo_depth = 512,
155	 .alwaysdither = 0,
156	 .gainlkup = ai_gain_16,
157	 .ai_speed = 10000,
158	 .n_aochan = 2,
159	 .aobits = 12,
160	 .ao_fifo_depth = 0,
161	 .ao_range_table = &range_ni_E_ao_ext,
162	 .ao_unipolar = 1,
163	 .ao_speed = 10000,
164	 .num_p0_dio_channels = 8,
165	 .caldac = {ad8804_debug},
166	 .has_8255 = 0,
167	 },
168	{.device_id = 37,
169	 .isapnp_id = 0x2500,
170	 .name = "at-mio-16de-10",
171	 .n_adchan = 16,
172	 .adbits = 12,
173	 .ai_fifo_depth = 512,
174	 .alwaysdither = 0,
175	 .gainlkup = ai_gain_16,
176	 .ai_speed = 10000,
177	 .n_aochan = 2,
178	 .aobits = 12,
179	 .ao_fifo_depth = 0,
180	 .ao_range_table = &range_ni_E_ao_ext,
181	 .ao_unipolar = 1,
182	 .ao_speed = 10000,
183	 .num_p0_dio_channels = 8,
184	 .caldac = {ad8804_debug},
185	 .has_8255 = 1,
186	 },
187	{.device_id = 38,
188	 .isapnp_id = 0x2600,
189	 .name = "at-mio-64e-3",
190	 .n_adchan = 64,
191	 .adbits = 12,
192	 .ai_fifo_depth = 2048,
193	 .alwaysdither = 0,
194	 .gainlkup = ai_gain_16,
195	 .ai_speed = 2000,
196	 .n_aochan = 2,
197	 .aobits = 12,
198	 .ao_fifo_depth = 2048,
199	 .ao_range_table = &range_ni_E_ao_ext,
200	 .ao_unipolar = 1,
201	 .ao_speed = 1000,
202	 .has_8255 = 0,
203	 .num_p0_dio_channels = 8,
204	 .caldac = {ad8804_debug},
205	 },
206	{.device_id = 39,
207	 .isapnp_id = 0x2700,
208	 .name = "at-mio-16xe-50",
209	 .n_adchan = 16,
210	 .adbits = 16,
211	 .ai_fifo_depth = 512,
212	 .alwaysdither = 1,
213	 .gainlkup = ai_gain_8,
214	 .ai_speed = 50000,
215	 .n_aochan = 2,
216	 .aobits = 12,
217	 .ao_fifo_depth = 0,
218	 .ao_range_table = &range_bipolar10,
219	 .ao_unipolar = 0,
220	 .ao_speed = 50000,
221	 .num_p0_dio_channels = 8,
222	 .caldac = {dac8800, dac8043},
223	 .has_8255 = 0,
224	 },
225	{.device_id = 50,
226	 .isapnp_id = 0x0000,	/* XXX unknown */
227	 .name = "at-mio-16xe-10",
228	 .n_adchan = 16,
229	 .adbits = 16,
230	 .ai_fifo_depth = 512,
231	 .alwaysdither = 1,
232	 .gainlkup = ai_gain_14,
233	 .ai_speed = 10000,
234	 .n_aochan = 2,
235	 .aobits = 16,
236	 .ao_fifo_depth = 2048,
237	 .ao_range_table = &range_ni_E_ao_ext,
238	 .ao_unipolar = 1,
239	 .ao_speed = 1000,
240	 .num_p0_dio_channels = 8,
241	 .caldac = {dac8800, dac8043, ad8522},
242	 .has_8255 = 0,
243	 },
244	{.device_id = 51,
245	 .isapnp_id = 0x0000,	/* XXX unknown */
246	 .name = "at-ai-16xe-10",
247	 .n_adchan = 16,
248	 .adbits = 16,
249	 .ai_fifo_depth = 512,
250	 .alwaysdither = 1,	/* unknown */
251	 .gainlkup = ai_gain_14,
252	 .ai_speed = 10000,
253	 .n_aochan = 0,
254	 .aobits = 0,
255	 .ao_fifo_depth = 0,
256	 .ao_unipolar = 0,
257	 .num_p0_dio_channels = 8,
258	 .caldac = {dac8800, dac8043, ad8522},
259	 .has_8255 = 0,
260	 }
261};
262
263static const int ni_irqpin[] = {
264	-1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
265};
266
267#define IRQ_POLARITY 0
268
269#include "ni_mio_common.c"
270
271static struct pnp_device_id device_ids[] = {
272	{.id = "NIC1900", .driver_data = 0},
273	{.id = "NIC2400", .driver_data = 0},
274	{.id = "NIC2500", .driver_data = 0},
275	{.id = "NIC2600", .driver_data = 0},
276	{.id = "NIC2700", .driver_data = 0},
277	{.id = ""}
278};
279
280MODULE_DEVICE_TABLE(pnp, device_ids);
281
282static int ni_isapnp_find_board(struct pnp_dev **dev)
283{
284	struct pnp_dev *isapnp_dev = NULL;
285	int i;
286
287	for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
288		isapnp_dev = pnp_find_dev(NULL,
289					  ISAPNP_VENDOR('N', 'I', 'C'),
290					  ISAPNP_FUNCTION(ni_boards[i].
291							  isapnp_id), NULL);
292
293		if (isapnp_dev == NULL || isapnp_dev->card == NULL)
294			continue;
295
296		if (pnp_device_attach(isapnp_dev) < 0) {
297			printk
298			 ("ni_atmio: %s found but already active, skipping.\n",
299			  ni_boards[i].name);
300			continue;
301		}
302		if (pnp_activate_dev(isapnp_dev) < 0) {
303			pnp_device_detach(isapnp_dev);
304			return -EAGAIN;
305		}
306		if (!pnp_port_valid(isapnp_dev, 0)
307		    || !pnp_irq_valid(isapnp_dev, 0)) {
308			pnp_device_detach(isapnp_dev);
309			printk("ni_atmio: pnp invalid port or irq, aborting\n");
310			return -ENOMEM;
311		}
312		break;
313	}
314	if (i == ARRAY_SIZE(ni_boards))
315		return -ENODEV;
316	*dev = isapnp_dev;
317	return 0;
318}
319
320static int ni_getboardtype(struct comedi_device *dev)
321{
322	int device_id = ni_read_eeprom(dev, 511);
323	int i;
324
325	for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
326		if (ni_boards[i].device_id == device_id)
327			return i;
328
329	}
330	if (device_id == 255)
331		printk(" can't find board\n");
332	 else if (device_id == 0)
333		printk(" EEPROM read error (?) or device not found\n");
334	 else
335		printk(" unknown device ID %d -- contact author\n", device_id);
336
337	return -1;
338}
339
340static int ni_atmio_attach(struct comedi_device *dev,
341			   struct comedi_devconfig *it)
342{
343	const struct ni_board_struct *boardtype;
344	struct ni_private *devpriv;
345	struct pnp_dev *isapnp_dev;
346	int ret;
347	unsigned long iobase;
348	int board;
349	unsigned int irq;
350
351	ret = ni_alloc_private(dev);
352	if (ret)
353		return ret;
354	devpriv = dev->private;
355
356	iobase = it->options[0];
357	irq = it->options[1];
358	isapnp_dev = NULL;
359	if (iobase == 0) {
360		ret = ni_isapnp_find_board(&isapnp_dev);
361		if (ret < 0)
362			return ret;
363
364		iobase = pnp_port_start(isapnp_dev, 0);
365		irq = pnp_irq(isapnp_dev, 0);
366		comedi_set_hw_dev(dev, &isapnp_dev->dev);
367	}
368
369	ret = comedi_request_region(dev, iobase, NI_SIZE);
370	if (ret)
371		return ret;
372
373	/* get board type */
374
375	board = ni_getboardtype(dev);
376	if (board < 0)
377		return -EIO;
378
379	dev->board_ptr = ni_boards + board;
380	boardtype = comedi_board(dev);
381
382	printk(" %s", boardtype->name);
383	dev->board_name = boardtype->name;
384
385	/* irq stuff */
386
387	if (irq != 0) {
388		if (irq > 15 || ni_irqpin[irq] == -1) {
389			printk(" invalid irq %u\n", irq);
390			return -EINVAL;
391		}
392		printk(" ( irq = %u )", irq);
393		ret = request_irq(irq, ni_E_interrupt, 0,
394				  "ni_atmio", dev);
395
396		if (ret < 0) {
397			printk(" irq not available\n");
398			return -EINVAL;
399		}
400		dev->irq = irq;
401	}
402
403	/* generic E series stuff in ni_mio_common.c */
404
405	ret = ni_E_init(dev, ni_irqpin[dev->irq]);
406	if (ret < 0)
407		return ret;
408
409
410	return 0;
411}
412
413static void ni_atmio_detach(struct comedi_device *dev)
414{
415	struct pnp_dev *isapnp_dev;
416
417	mio_common_detach(dev);
418	comedi_legacy_detach(dev);
419
420	isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL;
421	if (isapnp_dev)
422		pnp_device_detach(isapnp_dev);
423}
424
425static struct comedi_driver ni_atmio_driver = {
426	.driver_name	= "ni_atmio",
427	.module		= THIS_MODULE,
428	.attach		= ni_atmio_attach,
429	.detach		= ni_atmio_detach,
430};
431module_comedi_driver(ni_atmio_driver);
432