]>
Commit | Line | Data |
---|---|---|
e184e2be | 1 | // SPDX-License-Identifier: GPL-2.0+ |
a8b77430 | 2 | /* |
44a678b9 HS |
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> | |
44a678b9 | 7 | */ |
a8b77430 | 8 | |
a8b77430 | 9 | /* |
44a678b9 HS |
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 | */ | |
a8b77430 | 45 | |
a8b77430 | 46 | /* |
44a678b9 HS |
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 | */ | |
a8b77430 | 73 | |
ce157f80 | 74 | #include <linux/module.h> |
25436dc9 | 75 | #include <linux/interrupt.h> |
a8b77430 DS |
76 | #include "../comedidev.h" |
77 | ||
a8b77430 DS |
78 | #include <linux/isapnp.h> |
79 | ||
80 | #include "ni_stc.h" | |
81 | #include "8255.h" | |
82 | ||
da91a80a | 83 | /* AT specific setup */ |
8ab41df0 | 84 | static const struct ni_board_struct ni_boards[] = { |
25294851 | 85 | { |
b674f9df | 86 | .name = "at-mio-16e-1", |
25294851 HS |
87 | .device_id = 44, |
88 | .isapnp_id = 0x0000, /* XXX unknown */ | |
25294851 | 89 | .n_adchan = 16, |
db2255f5 | 90 | .ai_maxdata = 0x0fff, |
25294851 HS |
91 | .ai_fifo_depth = 8192, |
92 | .gainlkup = ai_gain_16, | |
93 | .ai_speed = 800, | |
94 | .n_aochan = 2, | |
c5f26499 | 95 | .ao_maxdata = 0x0fff, |
25294851 HS |
96 | .ao_fifo_depth = 2048, |
97 | .ao_range_table = &range_ni_E_ao_ext, | |
25294851 | 98 | .ao_speed = 1000, |
25294851 HS |
99 | .caldac = { mb88341 }, |
100 | }, { | |
b674f9df | 101 | .name = "at-mio-16e-2", |
25294851 HS |
102 | .device_id = 25, |
103 | .isapnp_id = 0x1900, | |
25294851 | 104 | .n_adchan = 16, |
db2255f5 | 105 | .ai_maxdata = 0x0fff, |
25294851 HS |
106 | .ai_fifo_depth = 2048, |
107 | .gainlkup = ai_gain_16, | |
108 | .ai_speed = 2000, | |
109 | .n_aochan = 2, | |
c5f26499 | 110 | .ao_maxdata = 0x0fff, |
25294851 HS |
111 | .ao_fifo_depth = 2048, |
112 | .ao_range_table = &range_ni_E_ao_ext, | |
25294851 | 113 | .ao_speed = 1000, |
25294851 HS |
114 | .caldac = { mb88341 }, |
115 | }, { | |
b674f9df | 116 | .name = "at-mio-16e-10", |
25294851 HS |
117 | .device_id = 36, |
118 | .isapnp_id = 0x2400, | |
25294851 | 119 | .n_adchan = 16, |
db2255f5 | 120 | .ai_maxdata = 0x0fff, |
25294851 HS |
121 | .ai_fifo_depth = 512, |
122 | .gainlkup = ai_gain_16, | |
123 | .ai_speed = 10000, | |
124 | .n_aochan = 2, | |
c5f26499 | 125 | .ao_maxdata = 0x0fff, |
25294851 | 126 | .ao_range_table = &range_ni_E_ao_ext, |
25294851 | 127 | .ao_speed = 10000, |
25294851 HS |
128 | .caldac = { ad8804_debug }, |
129 | }, { | |
b674f9df | 130 | .name = "at-mio-16de-10", |
25294851 HS |
131 | .device_id = 37, |
132 | .isapnp_id = 0x2500, | |
25294851 | 133 | .n_adchan = 16, |
db2255f5 | 134 | .ai_maxdata = 0x0fff, |
25294851 HS |
135 | .ai_fifo_depth = 512, |
136 | .gainlkup = ai_gain_16, | |
137 | .ai_speed = 10000, | |
138 | .n_aochan = 2, | |
c5f26499 | 139 | .ao_maxdata = 0x0fff, |
25294851 | 140 | .ao_range_table = &range_ni_E_ao_ext, |
25294851 | 141 | .ao_speed = 10000, |
25294851 HS |
142 | .caldac = { ad8804_debug }, |
143 | .has_8255 = 1, | |
144 | }, { | |
b674f9df | 145 | .name = "at-mio-64e-3", |
25294851 HS |
146 | .device_id = 38, |
147 | .isapnp_id = 0x2600, | |
25294851 | 148 | .n_adchan = 64, |
db2255f5 | 149 | .ai_maxdata = 0x0fff, |
25294851 HS |
150 | .ai_fifo_depth = 2048, |
151 | .gainlkup = ai_gain_16, | |
152 | .ai_speed = 2000, | |
153 | .n_aochan = 2, | |
c5f26499 | 154 | .ao_maxdata = 0x0fff, |
25294851 HS |
155 | .ao_fifo_depth = 2048, |
156 | .ao_range_table = &range_ni_E_ao_ext, | |
25294851 | 157 | .ao_speed = 1000, |
25294851 HS |
158 | .caldac = { ad8804_debug }, |
159 | }, { | |
b674f9df | 160 | .name = "at-mio-16xe-50", |
25294851 HS |
161 | .device_id = 39, |
162 | .isapnp_id = 0x2700, | |
25294851 | 163 | .n_adchan = 16, |
db2255f5 | 164 | .ai_maxdata = 0xffff, |
25294851 HS |
165 | .ai_fifo_depth = 512, |
166 | .alwaysdither = 1, | |
167 | .gainlkup = ai_gain_8, | |
168 | .ai_speed = 50000, | |
169 | .n_aochan = 2, | |
c5f26499 | 170 | .ao_maxdata = 0x0fff, |
25294851 HS |
171 | .ao_range_table = &range_bipolar10, |
172 | .ao_speed = 50000, | |
25294851 HS |
173 | .caldac = { dac8800, dac8043 }, |
174 | }, { | |
b674f9df | 175 | .name = "at-mio-16xe-10", |
25294851 HS |
176 | .device_id = 50, |
177 | .isapnp_id = 0x0000, /* XXX unknown */ | |
25294851 | 178 | .n_adchan = 16, |
db2255f5 | 179 | .ai_maxdata = 0xffff, |
25294851 HS |
180 | .ai_fifo_depth = 512, |
181 | .alwaysdither = 1, | |
182 | .gainlkup = ai_gain_14, | |
183 | .ai_speed = 10000, | |
184 | .n_aochan = 2, | |
c5f26499 | 185 | .ao_maxdata = 0xffff, |
25294851 HS |
186 | .ao_fifo_depth = 2048, |
187 | .ao_range_table = &range_ni_E_ao_ext, | |
25294851 | 188 | .ao_speed = 1000, |
25294851 HS |
189 | .caldac = { dac8800, dac8043, ad8522 }, |
190 | }, { | |
b674f9df | 191 | .name = "at-ai-16xe-10", |
25294851 HS |
192 | .device_id = 51, |
193 | .isapnp_id = 0x0000, /* XXX unknown */ | |
25294851 | 194 | .n_adchan = 16, |
db2255f5 | 195 | .ai_maxdata = 0xffff, |
25294851 | 196 | .ai_fifo_depth = 512, |
da91a80a | 197 | .alwaysdither = 1, /* unknown */ |
25294851 HS |
198 | .gainlkup = ai_gain_14, |
199 | .ai_speed = 10000, | |
25294851 HS |
200 | .caldac = { dac8800, dac8043, ad8522 }, |
201 | }, | |
a8b77430 DS |
202 | }; |
203 | ||
963ff774 JB |
204 | static const int ni_irqpin[] = { |
205 | -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 | |
206 | }; | |
a8b77430 | 207 | |
ac63baf5 | 208 | #include "ni_mio_common.c" |
a8b77430 | 209 | |
08680307 | 210 | static const struct pnp_device_id device_ids[] = { |
bc2955dd GH |
211 | {.id = "NIC1900", .driver_data = 0}, |
212 | {.id = "NIC2400", .driver_data = 0}, | |
213 | {.id = "NIC2500", .driver_data = 0}, | |
214 | {.id = "NIC2600", .driver_data = 0}, | |
215 | {.id = "NIC2700", .driver_data = 0}, | |
a8b77430 DS |
216 | {.id = ""} |
217 | }; | |
218 | ||
219 | MODULE_DEVICE_TABLE(pnp, device_ids); | |
220 | ||
a8b77430 DS |
221 | static int ni_isapnp_find_board(struct pnp_dev **dev) |
222 | { | |
223 | struct pnp_dev *isapnp_dev = NULL; | |
224 | int i; | |
225 | ||
ca4d4aa6 | 226 | for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { |
988f4a3b PJ |
227 | isapnp_dev = |
228 | pnp_find_dev(NULL, | |
229 | ISAPNP_VENDOR('N', 'I', 'C'), | |
230 | ISAPNP_FUNCTION(ni_boards[i].isapnp_id), | |
231 | NULL); | |
a8b77430 | 232 | |
77ba71f6 | 233 | if (!isapnp_dev || !isapnp_dev->card) |
a8b77430 DS |
234 | continue; |
235 | ||
ee68d168 | 236 | if (pnp_device_attach(isapnp_dev) < 0) |
a8b77430 | 237 | continue; |
ee68d168 | 238 | |
a8b77430 DS |
239 | if (pnp_activate_dev(isapnp_dev) < 0) { |
240 | pnp_device_detach(isapnp_dev); | |
241 | return -EAGAIN; | |
242 | } | |
ee68d168 HS |
243 | |
244 | if (!pnp_port_valid(isapnp_dev, 0) || | |
245 | !pnp_irq_valid(isapnp_dev, 0)) { | |
a8b77430 | 246 | pnp_device_detach(isapnp_dev); |
a8b77430 DS |
247 | return -ENOMEM; |
248 | } | |
249 | break; | |
250 | } | |
ca4d4aa6 | 251 | if (i == ARRAY_SIZE(ni_boards)) |
a8b77430 DS |
252 | return -ENODEV; |
253 | *dev = isapnp_dev; | |
254 | return 0; | |
255 | } | |
256 | ||
1ee02fe1 | 257 | static const struct ni_board_struct *ni_atmio_probe(struct comedi_device *dev) |
5aac8294 HS |
258 | { |
259 | int device_id = ni_read_eeprom(dev, 511); | |
260 | int i; | |
261 | ||
ca4d4aa6 | 262 | for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { |
1ee02fe1 HS |
263 | const struct ni_board_struct *board = &ni_boards[i]; |
264 | ||
265 | if (board->device_id == device_id) | |
266 | return board; | |
5aac8294 HS |
267 | } |
268 | if (device_id == 255) | |
b252ebfc | 269 | dev_err(dev->class_dev, "can't find board\n"); |
da91a80a | 270 | else if (device_id == 0) |
b252ebfc HS |
271 | dev_err(dev->class_dev, |
272 | "EEPROM read error (?) or device not found\n"); | |
da91a80a | 273 | else |
b252ebfc HS |
274 | dev_err(dev->class_dev, |
275 | "unknown device ID %d -- contact author\n", device_id); | |
5aac8294 | 276 | |
1ee02fe1 | 277 | return NULL; |
5aac8294 HS |
278 | } |
279 | ||
0a85b6f0 MT |
280 | static int ni_atmio_attach(struct comedi_device *dev, |
281 | struct comedi_devconfig *it) | |
a8b77430 | 282 | { |
1ee02fe1 | 283 | const struct ni_board_struct *board; |
a8b77430 DS |
284 | struct pnp_dev *isapnp_dev; |
285 | int ret; | |
286 | unsigned long iobase; | |
a8b77430 DS |
287 | unsigned int irq; |
288 | ||
c3744138 | 289 | ret = ni_alloc_private(dev); |
0e05c552 | 290 | if (ret) |
a8b77430 | 291 | return ret; |
c3744138 | 292 | |
a8b77430 DS |
293 | iobase = it->options[0]; |
294 | irq = it->options[1]; | |
295 | isapnp_dev = NULL; | |
296 | if (iobase == 0) { | |
297 | ret = ni_isapnp_find_board(&isapnp_dev); | |
298 | if (ret < 0) | |
299 | return ret; | |
300 | ||
301 | iobase = pnp_port_start(isapnp_dev, 0); | |
302 | irq = pnp_irq(isapnp_dev, 0); | |
ffd0a782 | 303 | comedi_set_hw_dev(dev, &isapnp_dev->dev); |
a8b77430 DS |
304 | } |
305 | ||
551d7939 | 306 | ret = comedi_request_region(dev, iobase, 0x20); |
b1bc9276 HS |
307 | if (ret) |
308 | return ret; | |
a8b77430 | 309 | |
1ee02fe1 HS |
310 | board = ni_atmio_probe(dev); |
311 | if (!board) | |
312 | return -ENODEV; | |
313 | dev->board_ptr = board; | |
314 | dev->board_name = board->name; | |
a8b77430 DS |
315 | |
316 | /* irq stuff */ | |
317 | ||
318 | if (irq != 0) { | |
221fa08c | 319 | if (irq > 15 || ni_irqpin[irq] == -1) |
a8b77430 | 320 | return -EINVAL; |
32d878a2 | 321 | ret = request_irq(irq, ni_E_interrupt, 0, |
71e06874 | 322 | dev->board_name, dev); |
221fa08c | 323 | if (ret < 0) |
a8b77430 | 324 | return -EINVAL; |
a8b77430 DS |
325 | dev->irq = irq; |
326 | } | |
327 | ||
328 | /* generic E series stuff in ni_mio_common.c */ | |
329 | ||
1fa955ba | 330 | ret = ni_E_init(dev, ni_irqpin[dev->irq], 0); |
bc2955dd | 331 | if (ret < 0) |
a8b77430 | 332 | return ret; |
bc2955dd | 333 | |
a8b77430 DS |
334 | return 0; |
335 | } | |
336 | ||
484ecc95 | 337 | static void ni_atmio_detach(struct comedi_device *dev) |
a8b77430 | 338 | { |
ffd0a782 | 339 | struct pnp_dev *isapnp_dev; |
0e05c552 | 340 | |
5aac8294 | 341 | mio_common_detach(dev); |
a32c6d00 | 342 | comedi_legacy_detach(dev); |
ffd0a782 HS |
343 | |
344 | isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL; | |
345 | if (isapnp_dev) | |
346 | pnp_device_detach(isapnp_dev); | |
a8b77430 | 347 | } |
5aac8294 HS |
348 | |
349 | static struct comedi_driver ni_atmio_driver = { | |
350 | .driver_name = "ni_atmio", | |
351 | .module = THIS_MODULE, | |
352 | .attach = ni_atmio_attach, | |
353 | .detach = ni_atmio_detach, | |
354 | }; | |
355 | module_comedi_driver(ni_atmio_driver); | |
02d69c03 | 356 | |
3659743d | 357 | MODULE_AUTHOR("Comedi https://www.comedi.org"); |
02d69c03 MG |
358 | MODULE_DESCRIPTION("Comedi low-level driver"); |
359 | MODULE_LICENSE("GPL"); | |
360 |