ni_atmio.c revision b674f9df207dc7da7b77ada82e0fb072ba06267c
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
108static const struct ni_board_struct ni_boards[] = {
109	{
110		.name		= "at-mio-16e-1",
111		.device_id	= 44,
112		.isapnp_id	= 0x0000,	/* XXX unknown */
113		.n_adchan	= 16,
114		.adbits		= 12,
115		.ai_fifo_depth	= 8192,
116		.gainlkup	= ai_gain_16,
117		.ai_speed	= 800,
118		.n_aochan	= 2,
119		.aobits		= 12,
120		.ao_fifo_depth	= 2048,
121		.ao_range_table	= &range_ni_E_ao_ext,
122		.ao_unipolar	= 1,
123		.ao_speed	= 1000,
124		.num_p0_dio_channels = 8,
125		.caldac		= { mb88341 },
126	}, {
127		.name		= "at-mio-16e-2",
128		.device_id	= 25,
129		.isapnp_id	= 0x1900,
130		.n_adchan	= 16,
131		.adbits		= 12,
132		.ai_fifo_depth	= 2048,
133		.gainlkup	= ai_gain_16,
134		.ai_speed	= 2000,
135		.n_aochan	= 2,
136		.aobits		= 12,
137		.ao_fifo_depth	= 2048,
138		.ao_range_table	= &range_ni_E_ao_ext,
139		.ao_unipolar	= 1,
140		.ao_speed	= 1000,
141		.num_p0_dio_channels = 8,
142		.caldac		= { mb88341 },
143	}, {
144		.name		= "at-mio-16e-10",
145		.device_id	= 36,
146		.isapnp_id	= 0x2400,
147		.n_adchan	= 16,
148		.adbits		= 12,
149		.ai_fifo_depth	= 512,
150		.gainlkup	= ai_gain_16,
151		.ai_speed	= 10000,
152		.n_aochan	= 2,
153		.aobits		= 12,
154		.ao_range_table	= &range_ni_E_ao_ext,
155		.ao_unipolar	= 1,
156		.ao_speed	= 10000,
157		.num_p0_dio_channels = 8,
158		.caldac		= { ad8804_debug },
159	}, {
160		.name		= "at-mio-16de-10",
161		.device_id	= 37,
162		.isapnp_id	= 0x2500,
163		.n_adchan	= 16,
164		.adbits		= 12,
165		.ai_fifo_depth	= 512,
166		.gainlkup	= ai_gain_16,
167		.ai_speed	= 10000,
168		.n_aochan	= 2,
169		.aobits		= 12,
170		.ao_range_table	= &range_ni_E_ao_ext,
171		.ao_unipolar	= 1,
172		.ao_speed	= 10000,
173		.num_p0_dio_channels = 8,
174		.caldac		= { ad8804_debug },
175		.has_8255	= 1,
176	}, {
177		.name		= "at-mio-64e-3",
178		.device_id	= 38,
179		.isapnp_id	= 0x2600,
180		.n_adchan	= 64,
181		.adbits		= 12,
182		.ai_fifo_depth	= 2048,
183		.gainlkup	= ai_gain_16,
184		.ai_speed	= 2000,
185		.n_aochan	= 2,
186		.aobits		= 12,
187		.ao_fifo_depth	= 2048,
188		.ao_range_table	= &range_ni_E_ao_ext,
189		.ao_unipolar	= 1,
190		.ao_speed	= 1000,
191		.num_p0_dio_channels = 8,
192		.caldac		= { ad8804_debug },
193	}, {
194		.name		= "at-mio-16xe-50",
195		.device_id	= 39,
196		.isapnp_id	= 0x2700,
197		.n_adchan	= 16,
198		.adbits		= 16,
199		.ai_fifo_depth	= 512,
200		.alwaysdither	= 1,
201		.gainlkup	= ai_gain_8,
202		.ai_speed	= 50000,
203		.n_aochan	= 2,
204		.aobits		= 12,
205		.ao_range_table	= &range_bipolar10,
206		.ao_speed	= 50000,
207		.num_p0_dio_channels = 8,
208		.caldac		= { dac8800, dac8043 },
209	}, {
210		.name		= "at-mio-16xe-10",
211		.device_id	= 50,
212		.isapnp_id	= 0x0000,	/* XXX unknown */
213		.n_adchan	= 16,
214		.adbits		= 16,
215		.ai_fifo_depth	= 512,
216		.alwaysdither	= 1,
217		.gainlkup	= ai_gain_14,
218		.ai_speed	= 10000,
219		.n_aochan	= 2,
220		.aobits		= 16,
221		.ao_fifo_depth	= 2048,
222		.ao_range_table	= &range_ni_E_ao_ext,
223		.ao_unipolar	= 1,
224		.ao_speed	= 1000,
225		.num_p0_dio_channels = 8,
226		.caldac		= { dac8800, dac8043, ad8522 },
227	}, {
228		.name		= "at-ai-16xe-10",
229		.device_id	= 51,
230		.isapnp_id	= 0x0000,	/* XXX unknown */
231		.n_adchan	= 16,
232		.adbits		= 16,
233		.ai_fifo_depth	= 512,
234		.alwaysdither	= 1,	/* unknown */
235		.gainlkup	= ai_gain_14,
236		.ai_speed	= 10000,
237		.num_p0_dio_channels = 8,
238		.caldac		= { dac8800, dac8043, ad8522 },
239	},
240};
241
242static const int ni_irqpin[] = {
243	-1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
244};
245
246#include "ni_mio_common.c"
247
248static struct pnp_device_id device_ids[] = {
249	{.id = "NIC1900", .driver_data = 0},
250	{.id = "NIC2400", .driver_data = 0},
251	{.id = "NIC2500", .driver_data = 0},
252	{.id = "NIC2600", .driver_data = 0},
253	{.id = "NIC2700", .driver_data = 0},
254	{.id = ""}
255};
256
257MODULE_DEVICE_TABLE(pnp, device_ids);
258
259static int ni_isapnp_find_board(struct pnp_dev **dev)
260{
261	struct pnp_dev *isapnp_dev = NULL;
262	int i;
263
264	for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
265		isapnp_dev = pnp_find_dev(NULL,
266					  ISAPNP_VENDOR('N', 'I', 'C'),
267					  ISAPNP_FUNCTION(ni_boards[i].
268							  isapnp_id), NULL);
269
270		if (isapnp_dev == NULL || isapnp_dev->card == NULL)
271			continue;
272
273		if (pnp_device_attach(isapnp_dev) < 0) {
274			printk
275			 ("ni_atmio: %s found but already active, skipping.\n",
276			  ni_boards[i].name);
277			continue;
278		}
279		if (pnp_activate_dev(isapnp_dev) < 0) {
280			pnp_device_detach(isapnp_dev);
281			return -EAGAIN;
282		}
283		if (!pnp_port_valid(isapnp_dev, 0)
284		    || !pnp_irq_valid(isapnp_dev, 0)) {
285			pnp_device_detach(isapnp_dev);
286			printk("ni_atmio: pnp invalid port or irq, aborting\n");
287			return -ENOMEM;
288		}
289		break;
290	}
291	if (i == ARRAY_SIZE(ni_boards))
292		return -ENODEV;
293	*dev = isapnp_dev;
294	return 0;
295}
296
297static int ni_getboardtype(struct comedi_device *dev)
298{
299	int device_id = ni_read_eeprom(dev, 511);
300	int i;
301
302	for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
303		if (ni_boards[i].device_id == device_id)
304			return i;
305
306	}
307	if (device_id == 255)
308		printk(" can't find board\n");
309	 else if (device_id == 0)
310		printk(" EEPROM read error (?) or device not found\n");
311	 else
312		printk(" unknown device ID %d -- contact author\n", device_id);
313
314	return -1;
315}
316
317static int ni_atmio_attach(struct comedi_device *dev,
318			   struct comedi_devconfig *it)
319{
320	const struct ni_board_struct *boardtype;
321	struct ni_private *devpriv;
322	struct pnp_dev *isapnp_dev;
323	int ret;
324	unsigned long iobase;
325	int board;
326	unsigned int irq;
327
328	ret = ni_alloc_private(dev);
329	if (ret)
330		return ret;
331	devpriv = dev->private;
332
333	iobase = it->options[0];
334	irq = it->options[1];
335	isapnp_dev = NULL;
336	if (iobase == 0) {
337		ret = ni_isapnp_find_board(&isapnp_dev);
338		if (ret < 0)
339			return ret;
340
341		iobase = pnp_port_start(isapnp_dev, 0);
342		irq = pnp_irq(isapnp_dev, 0);
343		comedi_set_hw_dev(dev, &isapnp_dev->dev);
344	}
345
346	ret = comedi_request_region(dev, iobase, 0x20);
347	if (ret)
348		return ret;
349
350	/* get board type */
351
352	board = ni_getboardtype(dev);
353	if (board < 0)
354		return -EIO;
355
356	dev->board_ptr = ni_boards + board;
357	boardtype = comedi_board(dev);
358
359	printk(" %s", boardtype->name);
360	dev->board_name = boardtype->name;
361
362	/* irq stuff */
363
364	if (irq != 0) {
365		if (irq > 15 || ni_irqpin[irq] == -1) {
366			printk(" invalid irq %u\n", irq);
367			return -EINVAL;
368		}
369		printk(" ( irq = %u )", irq);
370		ret = request_irq(irq, ni_E_interrupt, 0,
371				  "ni_atmio", dev);
372
373		if (ret < 0) {
374			printk(" irq not available\n");
375			return -EINVAL;
376		}
377		dev->irq = irq;
378	}
379
380	/* generic E series stuff in ni_mio_common.c */
381
382	ret = ni_E_init(dev, ni_irqpin[dev->irq], 0);
383	if (ret < 0)
384		return ret;
385
386
387	return 0;
388}
389
390static void ni_atmio_detach(struct comedi_device *dev)
391{
392	struct pnp_dev *isapnp_dev;
393
394	mio_common_detach(dev);
395	comedi_legacy_detach(dev);
396
397	isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL;
398	if (isapnp_dev)
399		pnp_device_detach(isapnp_dev);
400}
401
402static struct comedi_driver ni_atmio_driver = {
403	.driver_name	= "ni_atmio",
404	.module		= THIS_MODULE,
405	.attach		= ni_atmio_attach,
406	.detach		= ni_atmio_detach,
407};
408module_comedi_driver(ni_atmio_driver);
409