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