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#include <linux/module.h>
60#include <linux/interrupt.h>
61
62#include "../comedi_pci.h"
63
64
65
66
67
68
69#define NI_65XX_ID_REG 0x00
70#define NI_65XX_CLR_REG 0x01
71#define NI_65XX_CLR_WDOG_INT BIT(6)
72#define NI_65XX_CLR_WDOG_PING BIT(5)
73#define NI_65XX_CLR_WDOG_EXP BIT(4)
74#define NI_65XX_CLR_EDGE_INT BIT(3)
75#define NI_65XX_CLR_OVERFLOW_INT BIT(2)
76#define NI_65XX_STATUS_REG 0x02
77#define NI_65XX_STATUS_WDOG_INT BIT(5)
78#define NI_65XX_STATUS_FALL_EDGE BIT(4)
79#define NI_65XX_STATUS_RISE_EDGE BIT(3)
80#define NI_65XX_STATUS_INT BIT(2)
81#define NI_65XX_STATUS_OVERFLOW_INT BIT(1)
82#define NI_65XX_STATUS_EDGE_INT BIT(0)
83#define NI_65XX_CTRL_REG 0x03
84#define NI_65XX_CTRL_WDOG_ENA BIT(5)
85#define NI_65XX_CTRL_FALL_EDGE_ENA BIT(4)
86#define NI_65XX_CTRL_RISE_EDGE_ENA BIT(3)
87#define NI_65XX_CTRL_INT_ENA BIT(2)
88#define NI_65XX_CTRL_OVERFLOW_ENA BIT(1)
89#define NI_65XX_CTRL_EDGE_ENA BIT(0)
90#define NI_65XX_REV_REG 0x04
91#define NI_65XX_FILTER_REG 0x08
92#define NI_65XX_RTSI_ROUTE_REG 0x0c
93#define NI_65XX_RTSI_EDGE_REG 0x0e
94#define NI_65XX_RTSI_WDOG_REG 0x10
95#define NI_65XX_RTSI_TRIG_REG 0x12
96#define NI_65XX_AUTO_CLK_SEL_REG 0x14
97#define NI_65XX_AUTO_CLK_SEL_STATUS BIT(1)
98#define NI_65XX_AUTO_CLK_SEL_DISABLE BIT(0)
99#define NI_65XX_WDOG_CTRL_REG 0x15
100#define NI_65XX_WDOG_CTRL_ENA BIT(0)
101#define NI_65XX_RTSI_CFG_REG 0x16
102#define NI_65XX_RTSI_CFG_RISE_SENSE BIT(2)
103#define NI_65XX_RTSI_CFG_FALL_SENSE BIT(1)
104#define NI_65XX_RTSI_CFG_SYNC_DETECT BIT(0)
105#define NI_65XX_WDOG_STATUS_REG 0x17
106#define NI_65XX_WDOG_STATUS_EXP BIT(0)
107#define NI_65XX_WDOG_INTERVAL_REG 0x18
108
109
110#define NI_65XX_PORT(x) ((x) * 0x10)
111#define NI_65XX_IO_DATA_REG(x) (0x40 + NI_65XX_PORT(x))
112#define NI_65XX_IO_SEL_REG(x) (0x41 + NI_65XX_PORT(x))
113#define NI_65XX_IO_SEL_OUTPUT 0
114#define NI_65XX_IO_SEL_INPUT BIT(0)
115#define NI_65XX_RISE_EDGE_ENA_REG(x) (0x42 + NI_65XX_PORT(x))
116#define NI_65XX_FALL_EDGE_ENA_REG(x) (0x43 + NI_65XX_PORT(x))
117#define NI_65XX_FILTER_ENA(x) (0x44 + NI_65XX_PORT(x))
118#define NI_65XX_WDOG_HIZ_REG(x) (0x46 + NI_65XX_PORT(x))
119#define NI_65XX_WDOG_ENA(x) (0x47 + NI_65XX_PORT(x))
120#define NI_65XX_WDOG_HI_LO_REG(x) (0x48 + NI_65XX_PORT(x))
121#define NI_65XX_RTSI_ENA(x) (0x49 + NI_65XX_PORT(x))
122
123#define NI_65XX_PORT_TO_CHAN(x) ((x) * 8)
124#define NI_65XX_CHAN_TO_PORT(x) ((x) / 8)
125#define NI_65XX_CHAN_TO_MASK(x) (1 << ((x) % 8))
126
127enum ni_65xx_boardid {
128 BOARD_PCI6509,
129 BOARD_PXI6509,
130 BOARD_PCI6510,
131 BOARD_PCI6511,
132 BOARD_PXI6511,
133 BOARD_PCI6512,
134 BOARD_PXI6512,
135 BOARD_PCI6513,
136 BOARD_PXI6513,
137 BOARD_PCI6514,
138 BOARD_PXI6514,
139 BOARD_PCI6515,
140 BOARD_PXI6515,
141 BOARD_PCI6516,
142 BOARD_PCI6517,
143 BOARD_PCI6518,
144 BOARD_PCI6519,
145 BOARD_PCI6520,
146 BOARD_PCI6521,
147 BOARD_PXI6521,
148 BOARD_PCI6528,
149 BOARD_PXI6528,
150};
151
152struct ni_65xx_board {
153 const char *name;
154 unsigned int num_dio_ports;
155 unsigned int num_di_ports;
156 unsigned int num_do_ports;
157 unsigned int legacy_invert:1;
158};
159
160static const struct ni_65xx_board ni_65xx_boards[] = {
161 [BOARD_PCI6509] = {
162 .name = "pci-6509",
163 .num_dio_ports = 12,
164 },
165 [BOARD_PXI6509] = {
166 .name = "pxi-6509",
167 .num_dio_ports = 12,
168 },
169 [BOARD_PCI6510] = {
170 .name = "pci-6510",
171 .num_di_ports = 4,
172 },
173 [BOARD_PCI6511] = {
174 .name = "pci-6511",
175 .num_di_ports = 8,
176 },
177 [BOARD_PXI6511] = {
178 .name = "pxi-6511",
179 .num_di_ports = 8,
180 },
181 [BOARD_PCI6512] = {
182 .name = "pci-6512",
183 .num_do_ports = 8,
184 },
185 [BOARD_PXI6512] = {
186 .name = "pxi-6512",
187 .num_do_ports = 8,
188 },
189 [BOARD_PCI6513] = {
190 .name = "pci-6513",
191 .num_do_ports = 8,
192 .legacy_invert = 1,
193 },
194 [BOARD_PXI6513] = {
195 .name = "pxi-6513",
196 .num_do_ports = 8,
197 .legacy_invert = 1,
198 },
199 [BOARD_PCI6514] = {
200 .name = "pci-6514",
201 .num_di_ports = 4,
202 .num_do_ports = 4,
203 .legacy_invert = 1,
204 },
205 [BOARD_PXI6514] = {
206 .name = "pxi-6514",
207 .num_di_ports = 4,
208 .num_do_ports = 4,
209 .legacy_invert = 1,
210 },
211 [BOARD_PCI6515] = {
212 .name = "pci-6515",
213 .num_di_ports = 4,
214 .num_do_ports = 4,
215 .legacy_invert = 1,
216 },
217 [BOARD_PXI6515] = {
218 .name = "pxi-6515",
219 .num_di_ports = 4,
220 .num_do_ports = 4,
221 .legacy_invert = 1,
222 },
223 [BOARD_PCI6516] = {
224 .name = "pci-6516",
225 .num_do_ports = 4,
226 .legacy_invert = 1,
227 },
228 [BOARD_PCI6517] = {
229 .name = "pci-6517",
230 .num_do_ports = 4,
231 .legacy_invert = 1,
232 },
233 [BOARD_PCI6518] = {
234 .name = "pci-6518",
235 .num_di_ports = 2,
236 .num_do_ports = 2,
237 .legacy_invert = 1,
238 },
239 [BOARD_PCI6519] = {
240 .name = "pci-6519",
241 .num_di_ports = 2,
242 .num_do_ports = 2,
243 .legacy_invert = 1,
244 },
245 [BOARD_PCI6520] = {
246 .name = "pci-6520",
247 .num_di_ports = 1,
248 .num_do_ports = 1,
249 },
250 [BOARD_PCI6521] = {
251 .name = "pci-6521",
252 .num_di_ports = 1,
253 .num_do_ports = 1,
254 },
255 [BOARD_PXI6521] = {
256 .name = "pxi-6521",
257 .num_di_ports = 1,
258 .num_do_ports = 1,
259 },
260 [BOARD_PCI6528] = {
261 .name = "pci-6528",
262 .num_di_ports = 3,
263 .num_do_ports = 3,
264 },
265 [BOARD_PXI6528] = {
266 .name = "pxi-6528",
267 .num_di_ports = 3,
268 .num_do_ports = 3,
269 },
270};
271
272static bool ni_65xx_legacy_invert_outputs;
273module_param_named(legacy_invert_outputs, ni_65xx_legacy_invert_outputs,
274 bool, 0444);
275MODULE_PARM_DESC(legacy_invert_outputs,
276 "invert outputs of PCI/PXI-6513/6514/6515/6516/6517/6518/6519 for compatibility with old user code");
277
278static unsigned int ni_65xx_num_ports(struct comedi_device *dev)
279{
280 const struct ni_65xx_board *board = dev->board_ptr;
281
282 return board->num_dio_ports + board->num_di_ports + board->num_do_ports;
283}
284
285static void ni_65xx_disable_input_filters(struct comedi_device *dev)
286{
287 unsigned int num_ports = ni_65xx_num_ports(dev);
288 int i;
289
290
291 for (i = 0; i < num_ports; ++i)
292 writeb(0x00, dev->mmio + NI_65XX_FILTER_ENA(i));
293
294
295 writel(0x00000000, dev->mmio + NI_65XX_FILTER_REG);
296}
297
298
299static void ni_65xx_update_edge_detection(struct comedi_device *dev,
300 unsigned int base_chan,
301 unsigned int rising,
302 unsigned int falling)
303{
304 unsigned int num_ports = ni_65xx_num_ports(dev);
305 unsigned int port;
306
307 if (base_chan >= NI_65XX_PORT_TO_CHAN(num_ports))
308 return;
309
310 for (port = NI_65XX_CHAN_TO_PORT(base_chan); port < num_ports; port++) {
311 int bitshift = (int)(NI_65XX_PORT_TO_CHAN(port) - base_chan);
312 unsigned int port_mask, port_rising, port_falling;
313
314 if (bitshift >= 32)
315 break;
316
317 if (bitshift >= 0) {
318 port_mask = ~0U >> bitshift;
319 port_rising = rising >> bitshift;
320 port_falling = falling >> bitshift;
321 } else {
322 port_mask = ~0U << -bitshift;
323 port_rising = rising << -bitshift;
324 port_falling = falling << -bitshift;
325 }
326 if (port_mask & 0xff) {
327 if (~port_mask & 0xff) {
328 port_rising |=
329 readb(dev->mmio +
330 NI_65XX_RISE_EDGE_ENA_REG(port)) &
331 ~port_mask;
332 port_falling |=
333 readb(dev->mmio +
334 NI_65XX_FALL_EDGE_ENA_REG(port)) &
335 ~port_mask;
336 }
337 writeb(port_rising & 0xff,
338 dev->mmio + NI_65XX_RISE_EDGE_ENA_REG(port));
339 writeb(port_falling & 0xff,
340 dev->mmio + NI_65XX_FALL_EDGE_ENA_REG(port));
341 }
342 }
343}
344
345static void ni_65xx_disable_edge_detection(struct comedi_device *dev)
346{
347
348 ni_65xx_update_edge_detection(dev, 0, 0, 0);
349
350 ni_65xx_update_edge_detection(dev, 32, 0, 0);
351
352 ni_65xx_update_edge_detection(dev, 64, 0, 0);
353}
354
355static int ni_65xx_dio_insn_config(struct comedi_device *dev,
356 struct comedi_subdevice *s,
357 struct comedi_insn *insn,
358 unsigned int *data)
359{
360 unsigned long base_port = (unsigned long)s->private;
361 unsigned int chan = CR_CHAN(insn->chanspec);
362 unsigned int chan_mask = NI_65XX_CHAN_TO_MASK(chan);
363 unsigned int port = base_port + NI_65XX_CHAN_TO_PORT(chan);
364 unsigned int interval;
365 unsigned int val;
366
367 switch (data[0]) {
368 case INSN_CONFIG_FILTER:
369
370
371
372
373
374 interval = (data[1] + 100) / 200;
375 if (interval > 0xfffff)
376 interval = 0xfffff;
377 data[1] = interval * 200;
378
379
380
381
382
383
384 val = readb(dev->mmio + NI_65XX_FILTER_ENA(port));
385 if (interval) {
386 writel(interval, dev->mmio + NI_65XX_FILTER_REG);
387 val |= chan_mask;
388 } else {
389 val &= ~chan_mask;
390 }
391 writeb(val, dev->mmio + NI_65XX_FILTER_ENA(port));
392 break;
393
394 case INSN_CONFIG_DIO_OUTPUT:
395 if (s->type != COMEDI_SUBD_DIO)
396 return -EINVAL;
397 writeb(NI_65XX_IO_SEL_OUTPUT,
398 dev->mmio + NI_65XX_IO_SEL_REG(port));
399 break;
400
401 case INSN_CONFIG_DIO_INPUT:
402 if (s->type != COMEDI_SUBD_DIO)
403 return -EINVAL;
404 writeb(NI_65XX_IO_SEL_INPUT,
405 dev->mmio + NI_65XX_IO_SEL_REG(port));
406 break;
407
408 case INSN_CONFIG_DIO_QUERY:
409 if (s->type != COMEDI_SUBD_DIO)
410 return -EINVAL;
411 val = readb(dev->mmio + NI_65XX_IO_SEL_REG(port));
412 data[1] = (val == NI_65XX_IO_SEL_INPUT) ? COMEDI_INPUT
413 : COMEDI_OUTPUT;
414 break;
415
416 default:
417 return -EINVAL;
418 }
419
420 return insn->n;
421}
422
423static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
424 struct comedi_subdevice *s,
425 struct comedi_insn *insn,
426 unsigned int *data)
427{
428 unsigned long base_port = (unsigned long)s->private;
429 unsigned int base_chan = CR_CHAN(insn->chanspec);
430 int last_port_offset = NI_65XX_CHAN_TO_PORT(s->n_chan - 1);
431 unsigned int read_bits = 0;
432 int port_offset;
433
434 for (port_offset = NI_65XX_CHAN_TO_PORT(base_chan);
435 port_offset <= last_port_offset; port_offset++) {
436 unsigned int port = base_port + port_offset;
437 int base_port_channel = NI_65XX_PORT_TO_CHAN(port_offset);
438 unsigned int port_mask, port_data, bits;
439 int bitshift = base_port_channel - base_chan;
440
441 if (bitshift >= 32)
442 break;
443 port_mask = data[0];
444 port_data = data[1];
445 if (bitshift > 0) {
446 port_mask >>= bitshift;
447 port_data >>= bitshift;
448 } else {
449 port_mask <<= -bitshift;
450 port_data <<= -bitshift;
451 }
452 port_mask &= 0xff;
453 port_data &= 0xff;
454
455
456 if (port_mask) {
457 bits = readb(dev->mmio + NI_65XX_IO_DATA_REG(port));
458 bits ^= s->io_bits;
459 bits &= ~port_mask;
460 bits |= (port_data & port_mask);
461 bits ^= s->io_bits;
462 writeb(bits, dev->mmio + NI_65XX_IO_DATA_REG(port));
463 }
464
465
466 bits = readb(dev->mmio + NI_65XX_IO_DATA_REG(port));
467 bits ^= s->io_bits;
468 if (bitshift > 0)
469 bits <<= bitshift;
470 else
471 bits >>= -bitshift;
472
473 read_bits |= bits;
474 }
475 data[1] = read_bits;
476 return insn->n;
477}
478
479static irqreturn_t ni_65xx_interrupt(int irq, void *d)
480{
481 struct comedi_device *dev = d;
482 struct comedi_subdevice *s = dev->read_subdev;
483 unsigned int status;
484
485 status = readb(dev->mmio + NI_65XX_STATUS_REG);
486 if ((status & NI_65XX_STATUS_INT) == 0)
487 return IRQ_NONE;
488 if ((status & NI_65XX_STATUS_EDGE_INT) == 0)
489 return IRQ_NONE;
490
491 writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT,
492 dev->mmio + NI_65XX_CLR_REG);
493
494 comedi_buf_write_samples(s, &s->state, 1);
495 comedi_handle_events(dev, s);
496
497 return IRQ_HANDLED;
498}
499
500static int ni_65xx_intr_cmdtest(struct comedi_device *dev,
501 struct comedi_subdevice *s,
502 struct comedi_cmd *cmd)
503{
504 int err = 0;
505
506
507
508 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
509 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER);
510 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
511 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
512 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
513
514 if (err)
515 return 1;
516
517
518
519
520
521
522 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
523 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
524 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
525 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
526 cmd->chanlist_len);
527 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
528
529 if (err)
530 return 3;
531
532
533
534
535
536 return 0;
537}
538
539static int ni_65xx_intr_cmd(struct comedi_device *dev,
540 struct comedi_subdevice *s)
541{
542 writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT,
543 dev->mmio + NI_65XX_CLR_REG);
544 writeb(NI_65XX_CTRL_FALL_EDGE_ENA | NI_65XX_CTRL_RISE_EDGE_ENA |
545 NI_65XX_CTRL_INT_ENA | NI_65XX_CTRL_EDGE_ENA,
546 dev->mmio + NI_65XX_CTRL_REG);
547
548 return 0;
549}
550
551static int ni_65xx_intr_cancel(struct comedi_device *dev,
552 struct comedi_subdevice *s)
553{
554 writeb(0x00, dev->mmio + NI_65XX_CTRL_REG);
555
556 return 0;
557}
558
559static int ni_65xx_intr_insn_bits(struct comedi_device *dev,
560 struct comedi_subdevice *s,
561 struct comedi_insn *insn,
562 unsigned int *data)
563{
564 data[1] = 0;
565 return insn->n;
566}
567
568static int ni_65xx_intr_insn_config(struct comedi_device *dev,
569 struct comedi_subdevice *s,
570 struct comedi_insn *insn,
571 unsigned int *data)
572{
573 switch (data[0]) {
574 case INSN_CONFIG_CHANGE_NOTIFY:
575
576 if (insn->n != 3)
577 return -EINVAL;
578
579
580 ni_65xx_update_edge_detection(dev, 0, data[1], data[2]);
581
582 ni_65xx_update_edge_detection(dev, 32, 0, 0);
583
584 ni_65xx_update_edge_detection(dev, 64, 0, 0);
585 break;
586 case INSN_CONFIG_DIGITAL_TRIG:
587
588 if (data[1] != 0)
589 return -EINVAL;
590
591 switch (data[2]) {
592 case COMEDI_DIGITAL_TRIG_DISABLE:
593 ni_65xx_disable_edge_detection(dev);
594 break;
595 case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
596
597
598
599
600 ni_65xx_update_edge_detection(dev, data[3],
601 data[4], data[5]);
602 break;
603 default:
604 return -EINVAL;
605 }
606 break;
607 default:
608 return -EINVAL;
609 }
610
611 return insn->n;
612}
613
614
615#define MITE_IODWBSR 0xc0
616#define WENAB BIT(7)
617
618static int ni_65xx_mite_init(struct pci_dev *pcidev)
619{
620 void __iomem *mite_base;
621 u32 main_phys_addr;
622
623
624 mite_base = pci_ioremap_bar(pcidev, 0);
625 if (!mite_base)
626 return -ENOMEM;
627
628
629 main_phys_addr = pci_resource_start(pcidev, 1);
630 writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR);
631
632
633 iounmap(mite_base);
634 return 0;
635}
636
637static int ni_65xx_auto_attach(struct comedi_device *dev,
638 unsigned long context)
639{
640 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
641 const struct ni_65xx_board *board = NULL;
642 struct comedi_subdevice *s;
643 unsigned int i;
644 int ret;
645
646 if (context < ARRAY_SIZE(ni_65xx_boards))
647 board = &ni_65xx_boards[context];
648 if (!board)
649 return -ENODEV;
650 dev->board_ptr = board;
651 dev->board_name = board->name;
652
653 ret = comedi_pci_enable(dev);
654 if (ret)
655 return ret;
656
657 ret = ni_65xx_mite_init(pcidev);
658 if (ret)
659 return ret;
660
661 dev->mmio = pci_ioremap_bar(pcidev, 1);
662 if (!dev->mmio)
663 return -ENOMEM;
664
665 writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT,
666 dev->mmio + NI_65XX_CLR_REG);
667 writeb(0x00, dev->mmio + NI_65XX_CTRL_REG);
668
669 if (pcidev->irq) {
670 ret = request_irq(pcidev->irq, ni_65xx_interrupt, IRQF_SHARED,
671 dev->board_name, dev);
672 if (ret == 0)
673 dev->irq = pcidev->irq;
674 }
675
676 dev_info(dev->class_dev, "board: %s, ID=0x%02x", dev->board_name,
677 readb(dev->mmio + NI_65XX_ID_REG));
678
679 ret = comedi_alloc_subdevices(dev, 4);
680 if (ret)
681 return ret;
682
683 s = &dev->subdevices[0];
684 if (board->num_di_ports) {
685 s->type = COMEDI_SUBD_DI;
686 s->subdev_flags = SDF_READABLE;
687 s->n_chan = NI_65XX_PORT_TO_CHAN(board->num_di_ports);
688 s->maxdata = 1;
689 s->range_table = &range_digital;
690 s->insn_bits = ni_65xx_dio_insn_bits;
691 s->insn_config = ni_65xx_dio_insn_config;
692
693
694 s->private = (void *)0;
695 } else {
696 s->type = COMEDI_SUBD_UNUSED;
697 }
698
699 s = &dev->subdevices[1];
700 if (board->num_do_ports) {
701 s->type = COMEDI_SUBD_DO;
702 s->subdev_flags = SDF_WRITABLE;
703 s->n_chan = NI_65XX_PORT_TO_CHAN(board->num_do_ports);
704 s->maxdata = 1;
705 s->range_table = &range_digital;
706 s->insn_bits = ni_65xx_dio_insn_bits;
707
708
709 s->private = (void *)(unsigned long)board->num_di_ports;
710
711
712
713
714
715
716 if (ni_65xx_legacy_invert_outputs && board->legacy_invert)
717 s->io_bits = 0xff;
718
719
720 for (i = 0; i < board->num_do_ports; ++i) {
721 writeb(s->io_bits,
722 dev->mmio +
723 NI_65XX_IO_DATA_REG(board->num_di_ports + i));
724 }
725 } else {
726 s->type = COMEDI_SUBD_UNUSED;
727 }
728
729 s = &dev->subdevices[2];
730 if (board->num_dio_ports) {
731 s->type = COMEDI_SUBD_DIO;
732 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
733 s->n_chan = NI_65XX_PORT_TO_CHAN(board->num_dio_ports);
734 s->maxdata = 1;
735 s->range_table = &range_digital;
736 s->insn_bits = ni_65xx_dio_insn_bits;
737 s->insn_config = ni_65xx_dio_insn_config;
738
739
740 s->private = (void *)0;
741
742
743 for (i = 0; i < board->num_dio_ports; ++i) {
744 writeb(NI_65XX_IO_SEL_INPUT,
745 dev->mmio + NI_65XX_IO_SEL_REG(i));
746 }
747 } else {
748 s->type = COMEDI_SUBD_UNUSED;
749 }
750
751 s = &dev->subdevices[3];
752 s->type = COMEDI_SUBD_DI;
753 s->subdev_flags = SDF_READABLE;
754 s->n_chan = 1;
755 s->maxdata = 1;
756 s->range_table = &range_digital;
757 s->insn_bits = ni_65xx_intr_insn_bits;
758 if (dev->irq) {
759 dev->read_subdev = s;
760 s->subdev_flags |= SDF_CMD_READ;
761 s->len_chanlist = 1;
762 s->insn_config = ni_65xx_intr_insn_config;
763 s->do_cmdtest = ni_65xx_intr_cmdtest;
764 s->do_cmd = ni_65xx_intr_cmd;
765 s->cancel = ni_65xx_intr_cancel;
766 }
767
768 ni_65xx_disable_input_filters(dev);
769 ni_65xx_disable_edge_detection(dev);
770
771 return 0;
772}
773
774static void ni_65xx_detach(struct comedi_device *dev)
775{
776 if (dev->mmio)
777 writeb(0x00, dev->mmio + NI_65XX_CTRL_REG);
778 comedi_pci_detach(dev);
779}
780
781static struct comedi_driver ni_65xx_driver = {
782 .driver_name = "ni_65xx",
783 .module = THIS_MODULE,
784 .auto_attach = ni_65xx_auto_attach,
785 .detach = ni_65xx_detach,
786};
787
788static int ni_65xx_pci_probe(struct pci_dev *dev,
789 const struct pci_device_id *id)
790{
791 return comedi_pci_auto_config(dev, &ni_65xx_driver, id->driver_data);
792}
793
794static const struct pci_device_id ni_65xx_pci_table[] = {
795 { PCI_VDEVICE(NI, 0x1710), BOARD_PXI6509 },
796 { PCI_VDEVICE(NI, 0x7085), BOARD_PCI6509 },
797 { PCI_VDEVICE(NI, 0x7086), BOARD_PXI6528 },
798 { PCI_VDEVICE(NI, 0x7087), BOARD_PCI6515 },
799 { PCI_VDEVICE(NI, 0x7088), BOARD_PCI6514 },
800 { PCI_VDEVICE(NI, 0x70a9), BOARD_PCI6528 },
801 { PCI_VDEVICE(NI, 0x70c3), BOARD_PCI6511 },
802 { PCI_VDEVICE(NI, 0x70c8), BOARD_PCI6513 },
803 { PCI_VDEVICE(NI, 0x70c9), BOARD_PXI6515 },
804 { PCI_VDEVICE(NI, 0x70cc), BOARD_PCI6512 },
805 { PCI_VDEVICE(NI, 0x70cd), BOARD_PXI6514 },
806 { PCI_VDEVICE(NI, 0x70d1), BOARD_PXI6513 },
807 { PCI_VDEVICE(NI, 0x70d2), BOARD_PXI6512 },
808 { PCI_VDEVICE(NI, 0x70d3), BOARD_PXI6511 },
809 { PCI_VDEVICE(NI, 0x7124), BOARD_PCI6510 },
810 { PCI_VDEVICE(NI, 0x7125), BOARD_PCI6516 },
811 { PCI_VDEVICE(NI, 0x7126), BOARD_PCI6517 },
812 { PCI_VDEVICE(NI, 0x7127), BOARD_PCI6518 },
813 { PCI_VDEVICE(NI, 0x7128), BOARD_PCI6519 },
814 { PCI_VDEVICE(NI, 0x718b), BOARD_PCI6521 },
815 { PCI_VDEVICE(NI, 0x718c), BOARD_PXI6521 },
816 { PCI_VDEVICE(NI, 0x71c5), BOARD_PCI6520 },
817 { 0 }
818};
819MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table);
820
821static struct pci_driver ni_65xx_pci_driver = {
822 .name = "ni_65xx",
823 .id_table = ni_65xx_pci_table,
824 .probe = ni_65xx_pci_probe,
825 .remove = comedi_pci_auto_unconfig,
826};
827module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver);
828
829MODULE_AUTHOR("Comedi http://www.comedi.org");
830MODULE_DESCRIPTION("Comedi driver for NI PCI-65xx static dio boards");
831MODULE_LICENSE("GPL");
832