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