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