1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
106
107
108#define NI_SIZE 0x20
109
110#define MAX_N_CALDACS 32
111
112static const struct ni_board_struct ni_boards[] = {
113 {.device_id = 44,
114 .isapnp_id = 0x0000,
115 .name = "at-mio-16e-1",
116 .n_adchan = 16,
117 .adbits = 12,
118 .ai_fifo_depth = 8192,
119 .alwaysdither = 0,
120 .gainlkup = ai_gain_16,
121 .ai_speed = 800,
122 .n_aochan = 2,
123 .aobits = 12,
124 .ao_fifo_depth = 2048,
125 .ao_range_table = &range_ni_E_ao_ext,
126 .ao_unipolar = 1,
127 .ao_speed = 1000,
128 .has_8255 = 0,
129 .num_p0_dio_channels = 8,
130 .caldac = {mb88341},
131 },
132 {.device_id = 25,
133 .isapnp_id = 0x1900,
134 .name = "at-mio-16e-2",
135 .n_adchan = 16,
136 .adbits = 12,
137 .ai_fifo_depth = 2048,
138 .alwaysdither = 0,
139 .gainlkup = ai_gain_16,
140 .ai_speed = 2000,
141 .n_aochan = 2,
142 .aobits = 12,
143 .ao_fifo_depth = 2048,
144 .ao_range_table = &range_ni_E_ao_ext,
145 .ao_unipolar = 1,
146 .ao_speed = 1000,
147 .has_8255 = 0,
148 .num_p0_dio_channels = 8,
149 .caldac = {mb88341},
150 },
151 {.device_id = 36,
152 .isapnp_id = 0x2400,
153 .name = "at-mio-16e-10",
154 .n_adchan = 16,
155 .adbits = 12,
156 .ai_fifo_depth = 512,
157 .alwaysdither = 0,
158 .gainlkup = ai_gain_16,
159 .ai_speed = 10000,
160 .n_aochan = 2,
161 .aobits = 12,
162 .ao_fifo_depth = 0,
163 .ao_range_table = &range_ni_E_ao_ext,
164 .ao_unipolar = 1,
165 .ao_speed = 10000,
166 .num_p0_dio_channels = 8,
167 .caldac = {ad8804_debug},
168 .has_8255 = 0,
169 },
170 {.device_id = 37,
171 .isapnp_id = 0x2500,
172 .name = "at-mio-16de-10",
173 .n_adchan = 16,
174 .adbits = 12,
175 .ai_fifo_depth = 512,
176 .alwaysdither = 0,
177 .gainlkup = ai_gain_16,
178 .ai_speed = 10000,
179 .n_aochan = 2,
180 .aobits = 12,
181 .ao_fifo_depth = 0,
182 .ao_range_table = &range_ni_E_ao_ext,
183 .ao_unipolar = 1,
184 .ao_speed = 10000,
185 .num_p0_dio_channels = 8,
186 .caldac = {ad8804_debug},
187 .has_8255 = 1,
188 },
189 {.device_id = 38,
190 .isapnp_id = 0x2600,
191 .name = "at-mio-64e-3",
192 .n_adchan = 64,
193 .adbits = 12,
194 .ai_fifo_depth = 2048,
195 .alwaysdither = 0,
196 .gainlkup = ai_gain_16,
197 .ai_speed = 2000,
198 .n_aochan = 2,
199 .aobits = 12,
200 .ao_fifo_depth = 2048,
201 .ao_range_table = &range_ni_E_ao_ext,
202 .ao_unipolar = 1,
203 .ao_speed = 1000,
204 .has_8255 = 0,
205 .num_p0_dio_channels = 8,
206 .caldac = {ad8804_debug},
207 },
208 {.device_id = 39,
209 .isapnp_id = 0x2700,
210 .name = "at-mio-16xe-50",
211 .n_adchan = 16,
212 .adbits = 16,
213 .ai_fifo_depth = 512,
214 .alwaysdither = 1,
215 .gainlkup = ai_gain_8,
216 .ai_speed = 50000,
217 .n_aochan = 2,
218 .aobits = 12,
219 .ao_fifo_depth = 0,
220 .ao_range_table = &range_bipolar10,
221 .ao_unipolar = 0,
222 .ao_speed = 50000,
223 .num_p0_dio_channels = 8,
224 .caldac = {dac8800, dac8043},
225 .has_8255 = 0,
226 },
227 {.device_id = 50,
228 .isapnp_id = 0x0000,
229 .name = "at-mio-16xe-10",
230 .n_adchan = 16,
231 .adbits = 16,
232 .ai_fifo_depth = 512,
233 .alwaysdither = 1,
234 .gainlkup = ai_gain_14,
235 .ai_speed = 10000,
236 .n_aochan = 2,
237 .aobits = 16,
238 .ao_fifo_depth = 2048,
239 .ao_range_table = &range_ni_E_ao_ext,
240 .ao_unipolar = 1,
241 .ao_speed = 1000,
242 .num_p0_dio_channels = 8,
243 .caldac = {dac8800, dac8043, ad8522},
244 .has_8255 = 0,
245 },
246 {.device_id = 51,
247 .isapnp_id = 0x0000,
248 .name = "at-ai-16xe-10",
249 .n_adchan = 16,
250 .adbits = 16,
251 .ai_fifo_depth = 512,
252 .alwaysdither = 1,
253 .gainlkup = ai_gain_14,
254 .ai_speed = 10000,
255 .n_aochan = 0,
256 .aobits = 0,
257 .ao_fifo_depth = 0,
258 .ao_unipolar = 0,
259 .num_p0_dio_channels = 8,
260 .caldac = {dac8800, dac8043, ad8522},
261 .has_8255 = 0,
262 }
263};
264
265static const int ni_irqpin[] = {
266 -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
267};
268
269#define interrupt_pin(a) (ni_irqpin[(a)])
270
271#define IRQ_POLARITY 0
272
273#define NI_E_IRQ_FLAGS 0
274
275struct ni_private {
276 struct pnp_dev *isapnp_dev;
277 NI_PRIVATE_COMMON
278
279};
280
281
282
283#define ni_writel(a, b) (outl((a), (b)+dev->iobase))
284#define ni_readl(a) (inl((a)+dev->iobase))
285#define ni_writew(a, b) (outw((a), (b)+dev->iobase))
286#define ni_readw(a) (inw((a)+dev->iobase))
287#define ni_writeb(a, b) (outb((a), (b)+dev->iobase))
288#define ni_readb(a) (inb((a)+dev->iobase))
289
290
291
292
293
294
295
296static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr)
297{
298 struct ni_private *devpriv = dev->private;
299 unsigned long flags;
300
301 spin_lock_irqsave(&devpriv->window_lock, flags);
302 if ((addr) < 8) {
303 ni_writew(data, addr * 2);
304 } else {
305 ni_writew(addr, Window_Address);
306 ni_writew(data, Window_Data);
307 }
308 spin_unlock_irqrestore(&devpriv->window_lock, flags);
309}
310
311static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
312{
313 struct ni_private *devpriv = dev->private;
314 unsigned long flags;
315 uint16_t ret;
316
317 spin_lock_irqsave(&devpriv->window_lock, flags);
318 if (addr < 8) {
319 ret = ni_readw(addr * 2);
320 } else {
321 ni_writew(addr, Window_Address);
322 ret = ni_readw(Window_Data);
323 }
324 spin_unlock_irqrestore(&devpriv->window_lock, flags);
325
326 return ret;
327}
328
329static struct pnp_device_id device_ids[] = {
330 {.id = "NIC1900", .driver_data = 0},
331 {.id = "NIC2400", .driver_data = 0},
332 {.id = "NIC2500", .driver_data = 0},
333 {.id = "NIC2600", .driver_data = 0},
334 {.id = "NIC2700", .driver_data = 0},
335 {.id = ""}
336};
337
338MODULE_DEVICE_TABLE(pnp, device_ids);
339
340#include "ni_mio_common.c"
341
342static int ni_isapnp_find_board(struct pnp_dev **dev)
343{
344 struct pnp_dev *isapnp_dev = NULL;
345 int i;
346
347 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
348 isapnp_dev = pnp_find_dev(NULL,
349 ISAPNP_VENDOR('N', 'I', 'C'),
350 ISAPNP_FUNCTION(ni_boards[i].
351 isapnp_id), NULL);
352
353 if (isapnp_dev == NULL || isapnp_dev->card == NULL)
354 continue;
355
356 if (pnp_device_attach(isapnp_dev) < 0) {
357 printk
358 ("ni_atmio: %s found but already active, skipping.\n",
359 ni_boards[i].name);
360 continue;
361 }
362 if (pnp_activate_dev(isapnp_dev) < 0) {
363 pnp_device_detach(isapnp_dev);
364 return -EAGAIN;
365 }
366 if (!pnp_port_valid(isapnp_dev, 0)
367 || !pnp_irq_valid(isapnp_dev, 0)) {
368 pnp_device_detach(isapnp_dev);
369 printk("ni_atmio: pnp invalid port or irq, aborting\n");
370 return -ENOMEM;
371 }
372 break;
373 }
374 if (i == ARRAY_SIZE(ni_boards))
375 return -ENODEV;
376 *dev = isapnp_dev;
377 return 0;
378}
379
380static int ni_getboardtype(struct comedi_device *dev)
381{
382 int device_id = ni_read_eeprom(dev, 511);
383 int i;
384
385 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
386 if (ni_boards[i].device_id == device_id)
387 return i;
388
389 }
390 if (device_id == 255)
391 printk(" can't find board\n");
392 else if (device_id == 0)
393 printk(" EEPROM read error (?) or device not found\n");
394 else
395 printk(" unknown device ID %d -- contact author\n", device_id);
396
397 return -1;
398}
399
400static int ni_atmio_attach(struct comedi_device *dev,
401 struct comedi_devconfig *it)
402{
403 const struct ni_board_struct *boardtype;
404 struct ni_private *devpriv;
405 struct pnp_dev *isapnp_dev;
406 int ret;
407 unsigned long iobase;
408 int board;
409 unsigned int irq;
410
411 ret = ni_alloc_private(dev);
412 if (ret)
413 return ret;
414 devpriv = dev->private;
415
416 devpriv->stc_writew = &ni_atmio_win_out;
417 devpriv->stc_readw = &ni_atmio_win_in;
418 devpriv->stc_writel = &win_out2;
419 devpriv->stc_readl = &win_in2;
420
421 iobase = it->options[0];
422 irq = it->options[1];
423 isapnp_dev = NULL;
424 if (iobase == 0) {
425 ret = ni_isapnp_find_board(&isapnp_dev);
426 if (ret < 0)
427 return ret;
428
429 iobase = pnp_port_start(isapnp_dev, 0);
430 irq = pnp_irq(isapnp_dev, 0);
431 devpriv->isapnp_dev = isapnp_dev;
432 }
433
434 ret = comedi_request_region(dev, iobase, NI_SIZE);
435 if (ret)
436 return ret;
437
438
439
440 board = ni_getboardtype(dev);
441 if (board < 0)
442 return -EIO;
443
444 dev->board_ptr = ni_boards + board;
445 boardtype = comedi_board(dev);
446
447 printk(" %s", boardtype->name);
448 dev->board_name = boardtype->name;
449
450
451
452 if (irq != 0) {
453 if (irq > 15 || ni_irqpin[irq] == -1) {
454 printk(" invalid irq %u\n", irq);
455 return -EINVAL;
456 }
457 printk(" ( irq = %u )", irq);
458 ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
459 "ni_atmio", dev);
460
461 if (ret < 0) {
462 printk(" irq not available\n");
463 return -EINVAL;
464 }
465 dev->irq = irq;
466 }
467
468
469
470 ret = ni_E_init(dev);
471 if (ret < 0)
472 return ret;
473
474
475 return 0;
476}
477
478static void ni_atmio_detach(struct comedi_device *dev)
479{
480 struct ni_private *devpriv = dev->private;
481
482 mio_common_detach(dev);
483 comedi_legacy_detach(dev);
484 if (devpriv->isapnp_dev)
485 pnp_device_detach(devpriv->isapnp_dev);
486}
487
488static struct comedi_driver ni_atmio_driver = {
489 .driver_name = "ni_atmio",
490 .module = THIS_MODULE,
491 .attach = ni_atmio_attach,
492 .detach = ni_atmio_detach,
493};
494module_comedi_driver(ni_atmio_driver);
495