File Index
Files and directories
Sign in
FILE

ni_atmio.c

File preview with syntax highlighting.

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