This source file includes following definitions.
- apci1564_reset
- apci1564_interrupt
- apci1564_di_insn_bits
- apci1564_do_insn_bits
- apci1564_diag_insn_bits
- apci1564_cos_insn_config
- apci1564_cos_insn_bits
- apci1564_cos_cmdtest
- apci1564_cos_cmd
- apci1564_cos_cancel
- apci1564_timer_insn_config
- apci1564_timer_insn_write
- apci1564_timer_insn_read
- apci1564_counter_insn_config
- apci1564_counter_insn_write
- apci1564_counter_insn_read
- apci1564_auto_attach
- apci1564_detach
- apci1564_pci_probe
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 #include <linux/module.h>
70 #include <linux/interrupt.h>
71
72 #include "../comedi_pci.h"
73 #include "addi_tcw.h"
74 #include "addi_watchdog.h"
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 #define APCI1564_EEPROM_REG 0x00
91 #define APCI1564_EEPROM_VCC_STATUS BIT(8)
92 #define APCI1564_EEPROM_TO_REV(x) (((x) >> 4) & 0xf)
93 #define APCI1564_EEPROM_DI BIT(3)
94 #define APCI1564_EEPROM_DO BIT(2)
95 #define APCI1564_EEPROM_CS BIT(1)
96 #define APCI1564_EEPROM_CLK BIT(0)
97 #define APCI1564_REV1_TIMER_IOBASE 0x04
98 #define APCI1564_REV2_MAIN_IOBASE 0x04
99 #define APCI1564_REV2_TIMER_IOBASE 0x48
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 #define APCI1564_REV1_MAIN_IOBASE 0x00
115
116
117
118
119
120
121 #define APCI1564_DI_REG 0x00
122 #define APCI1564_DI_INT_MODE1_REG 0x04
123 #define APCI1564_DI_INT_MODE2_REG 0x08
124 #define APCI1564_DI_INT_MODE_MASK 0x000ffff0
125 #define APCI1564_DI_INT_STATUS_REG 0x0c
126 #define APCI1564_DI_IRQ_REG 0x10
127 #define APCI1564_DI_IRQ_ENA BIT(2)
128 #define APCI1564_DI_IRQ_MODE BIT(1)
129 #define APCI1564_DO_REG 0x14
130 #define APCI1564_DO_INT_CTRL_REG 0x18
131 #define APCI1564_DO_INT_CTRL_CC_INT_ENA BIT(1)
132 #define APCI1564_DO_INT_CTRL_VCC_INT_ENA BIT(0)
133 #define APCI1564_DO_INT_STATUS_REG 0x1c
134 #define APCI1564_DO_INT_STATUS_CC BIT(1)
135 #define APCI1564_DO_INT_STATUS_VCC BIT(0)
136 #define APCI1564_DO_IRQ_REG 0x20
137 #define APCI1564_DO_IRQ_INTR BIT(0)
138 #define APCI1564_WDOG_IOBASE 0x24
139
140
141
142
143
144
145
146
147
148
149
150 #define APCI1564_COUNTER(x) ((x) * 0x20)
151
152
153
154
155
156 #define APCI1564_EVENT_COS BIT(31)
157 #define APCI1564_EVENT_TIMER BIT(30)
158 #define APCI1564_EVENT_COUNTER(x) BIT(27 + (x))
159 #define APCI1564_EVENT_MASK 0xfff0000f
160
161 struct apci1564_private {
162 unsigned long eeprom;
163 unsigned long timer;
164 unsigned long counters;
165 unsigned int mode1;
166 unsigned int mode2;
167 unsigned int ctrl;
168 };
169
170 static int apci1564_reset(struct comedi_device *dev)
171 {
172 struct apci1564_private *devpriv = dev->private;
173
174
175 outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG);
176 inl(dev->iobase + APCI1564_DI_INT_STATUS_REG);
177 outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG);
178 outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG);
179
180
181 outl(0x0, dev->iobase + APCI1564_DO_REG);
182 outl(0x0, dev->iobase + APCI1564_DO_INT_CTRL_REG);
183
184
185 addi_watchdog_reset(dev->iobase + APCI1564_WDOG_IOBASE);
186
187
188 outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG);
189 outl(0x0, devpriv->timer + ADDI_TCW_RELOAD_REG);
190
191 if (devpriv->counters) {
192 unsigned long iobase = devpriv->counters + ADDI_TCW_CTRL_REG;
193
194
195 outl(0x0, iobase + APCI1564_COUNTER(0));
196 outl(0x0, iobase + APCI1564_COUNTER(1));
197 outl(0x0, iobase + APCI1564_COUNTER(2));
198 }
199
200 return 0;
201 }
202
203 static irqreturn_t apci1564_interrupt(int irq, void *d)
204 {
205 struct comedi_device *dev = d;
206 struct apci1564_private *devpriv = dev->private;
207 struct comedi_subdevice *s = dev->read_subdev;
208 unsigned int status;
209 unsigned int ctrl;
210 unsigned int chan;
211
212 s->state &= ~APCI1564_EVENT_MASK;
213
214 status = inl(dev->iobase + APCI1564_DI_IRQ_REG);
215 if (status & APCI1564_DI_IRQ_ENA) {
216
217 s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG);
218 s->state &= APCI1564_DI_INT_MODE_MASK;
219 s->state |= APCI1564_EVENT_COS;
220
221
222 outl(status & ~APCI1564_DI_IRQ_ENA,
223 dev->iobase + APCI1564_DI_IRQ_REG);
224 outl(status, dev->iobase + APCI1564_DI_IRQ_REG);
225 }
226
227 status = inl(devpriv->timer + ADDI_TCW_IRQ_REG);
228 if (status & ADDI_TCW_IRQ) {
229 s->state |= APCI1564_EVENT_TIMER;
230
231
232 ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG);
233 outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG);
234 outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG);
235 }
236
237 if (devpriv->counters) {
238 for (chan = 0; chan < 3; chan++) {
239 unsigned long iobase;
240
241 iobase = devpriv->counters + APCI1564_COUNTER(chan);
242
243 status = inl(iobase + ADDI_TCW_IRQ_REG);
244 if (status & ADDI_TCW_IRQ) {
245 s->state |= APCI1564_EVENT_COUNTER(chan);
246
247
248 ctrl = inl(iobase + ADDI_TCW_CTRL_REG);
249 outl(0x0, iobase + ADDI_TCW_CTRL_REG);
250 outl(ctrl, iobase + ADDI_TCW_CTRL_REG);
251 }
252 }
253 }
254
255 if (s->state & APCI1564_EVENT_MASK) {
256 comedi_buf_write_samples(s, &s->state, 1);
257 comedi_handle_events(dev, s);
258 }
259
260 return IRQ_HANDLED;
261 }
262
263 static int apci1564_di_insn_bits(struct comedi_device *dev,
264 struct comedi_subdevice *s,
265 struct comedi_insn *insn,
266 unsigned int *data)
267 {
268 data[1] = inl(dev->iobase + APCI1564_DI_REG);
269
270 return insn->n;
271 }
272
273 static int apci1564_do_insn_bits(struct comedi_device *dev,
274 struct comedi_subdevice *s,
275 struct comedi_insn *insn,
276 unsigned int *data)
277 {
278 s->state = inl(dev->iobase + APCI1564_DO_REG);
279
280 if (comedi_dio_update_state(s, data))
281 outl(s->state, dev->iobase + APCI1564_DO_REG);
282
283 data[1] = s->state;
284
285 return insn->n;
286 }
287
288 static int apci1564_diag_insn_bits(struct comedi_device *dev,
289 struct comedi_subdevice *s,
290 struct comedi_insn *insn,
291 unsigned int *data)
292 {
293 data[1] = inl(dev->iobase + APCI1564_DO_INT_STATUS_REG) & 3;
294
295 return insn->n;
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 static int apci1564_cos_insn_config(struct comedi_device *dev,
329 struct comedi_subdevice *s,
330 struct comedi_insn *insn,
331 unsigned int *data)
332 {
333 struct apci1564_private *devpriv = dev->private;
334 unsigned int shift, oldmask;
335
336 switch (data[0]) {
337 case INSN_CONFIG_DIGITAL_TRIG:
338 if (data[1] != 0)
339 return -EINVAL;
340 shift = data[3];
341 oldmask = (1U << shift) - 1;
342 switch (data[2]) {
343 case COMEDI_DIGITAL_TRIG_DISABLE:
344 devpriv->ctrl = 0;
345 devpriv->mode1 = 0;
346 devpriv->mode2 = 0;
347 outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG);
348 inl(dev->iobase + APCI1564_DI_INT_STATUS_REG);
349 outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG);
350 outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG);
351 break;
352 case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
353 if (devpriv->ctrl != APCI1564_DI_IRQ_ENA) {
354
355 devpriv->ctrl = APCI1564_DI_IRQ_ENA;
356
357 devpriv->mode1 = 0;
358 devpriv->mode2 = 0;
359 } else {
360
361 devpriv->mode1 &= oldmask;
362 devpriv->mode2 &= oldmask;
363 }
364
365 devpriv->mode1 |= data[4] << shift;
366 devpriv->mode2 |= data[5] << shift;
367 break;
368 case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
369 if (devpriv->ctrl != (APCI1564_DI_IRQ_ENA |
370 APCI1564_DI_IRQ_MODE)) {
371
372 devpriv->ctrl = APCI1564_DI_IRQ_ENA |
373 APCI1564_DI_IRQ_MODE;
374
375 devpriv->mode1 = 0;
376 devpriv->mode2 = 0;
377 } else {
378
379 devpriv->mode1 &= oldmask;
380 devpriv->mode2 &= oldmask;
381 }
382
383 devpriv->mode1 |= data[4] << shift;
384 devpriv->mode2 |= data[5] << shift;
385 break;
386 default:
387 return -EINVAL;
388 }
389
390
391 devpriv->mode1 &= APCI1564_DI_INT_MODE_MASK;
392 devpriv->mode2 &= APCI1564_DI_INT_MODE_MASK;
393 break;
394 default:
395 return -EINVAL;
396 }
397 return insn->n;
398 }
399
400 static int apci1564_cos_insn_bits(struct comedi_device *dev,
401 struct comedi_subdevice *s,
402 struct comedi_insn *insn,
403 unsigned int *data)
404 {
405 data[1] = s->state;
406
407 return 0;
408 }
409
410 static int apci1564_cos_cmdtest(struct comedi_device *dev,
411 struct comedi_subdevice *s,
412 struct comedi_cmd *cmd)
413 {
414 int err = 0;
415
416
417
418 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
419 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
420 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
421 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
422 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
423
424 if (err)
425 return 1;
426
427
428
429
430
431
432 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
433 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
434 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
435 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
436 cmd->chanlist_len);
437 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
438
439 if (err)
440 return 3;
441
442
443
444
445
446 return 0;
447 }
448
449
450
451
452
453
454 static int apci1564_cos_cmd(struct comedi_device *dev,
455 struct comedi_subdevice *s)
456 {
457 struct apci1564_private *devpriv = dev->private;
458
459 if (!devpriv->ctrl && !(devpriv->mode1 || devpriv->mode2)) {
460 dev_warn(dev->class_dev,
461 "Interrupts disabled due to mode configuration!\n");
462 return -EINVAL;
463 }
464
465 outl(devpriv->mode1, dev->iobase + APCI1564_DI_INT_MODE1_REG);
466 outl(devpriv->mode2, dev->iobase + APCI1564_DI_INT_MODE2_REG);
467 outl(devpriv->ctrl, dev->iobase + APCI1564_DI_IRQ_REG);
468
469 return 0;
470 }
471
472 static int apci1564_cos_cancel(struct comedi_device *dev,
473 struct comedi_subdevice *s)
474 {
475 outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG);
476 inl(dev->iobase + APCI1564_DI_INT_STATUS_REG);
477 outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG);
478 outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG);
479
480 return 0;
481 }
482
483 static int apci1564_timer_insn_config(struct comedi_device *dev,
484 struct comedi_subdevice *s,
485 struct comedi_insn *insn,
486 unsigned int *data)
487 {
488 struct apci1564_private *devpriv = dev->private;
489 unsigned int val;
490
491 switch (data[0]) {
492 case INSN_CONFIG_ARM:
493 if (data[1] > s->maxdata)
494 return -EINVAL;
495 outl(data[1], devpriv->timer + ADDI_TCW_RELOAD_REG);
496 outl(ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_TIMER_ENA,
497 devpriv->timer + ADDI_TCW_CTRL_REG);
498 break;
499 case INSN_CONFIG_DISARM:
500 outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG);
501 break;
502 case INSN_CONFIG_GET_COUNTER_STATUS:
503 data[1] = 0;
504 val = inl(devpriv->timer + ADDI_TCW_CTRL_REG);
505 if (val & ADDI_TCW_CTRL_IRQ_ENA)
506 data[1] |= COMEDI_COUNTER_ARMED;
507 if (val & ADDI_TCW_CTRL_TIMER_ENA)
508 data[1] |= COMEDI_COUNTER_COUNTING;
509 val = inl(devpriv->timer + ADDI_TCW_STATUS_REG);
510 if (val & ADDI_TCW_STATUS_OVERFLOW)
511 data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
512 data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
513 COMEDI_COUNTER_TERMINAL_COUNT;
514 break;
515 case INSN_CONFIG_SET_CLOCK_SRC:
516 if (data[2] > s->maxdata)
517 return -EINVAL;
518 outl(data[1], devpriv->timer + ADDI_TCW_TIMEBASE_REG);
519 outl(data[2], devpriv->timer + ADDI_TCW_RELOAD_REG);
520 break;
521 case INSN_CONFIG_GET_CLOCK_SRC:
522 data[1] = inl(devpriv->timer + ADDI_TCW_TIMEBASE_REG);
523 data[2] = inl(devpriv->timer + ADDI_TCW_RELOAD_REG);
524 break;
525 default:
526 return -EINVAL;
527 }
528
529 return insn->n;
530 }
531
532 static int apci1564_timer_insn_write(struct comedi_device *dev,
533 struct comedi_subdevice *s,
534 struct comedi_insn *insn,
535 unsigned int *data)
536 {
537 struct apci1564_private *devpriv = dev->private;
538
539
540 if (insn->n) {
541 unsigned int val = data[insn->n - 1];
542
543 outl(val, devpriv->timer + ADDI_TCW_RELOAD_REG);
544 }
545
546 return insn->n;
547 }
548
549 static int apci1564_timer_insn_read(struct comedi_device *dev,
550 struct comedi_subdevice *s,
551 struct comedi_insn *insn,
552 unsigned int *data)
553 {
554 struct apci1564_private *devpriv = dev->private;
555 int i;
556
557
558 for (i = 0; i < insn->n; i++)
559 data[i] = inl(devpriv->timer + ADDI_TCW_VAL_REG);
560
561 return insn->n;
562 }
563
564 static int apci1564_counter_insn_config(struct comedi_device *dev,
565 struct comedi_subdevice *s,
566 struct comedi_insn *insn,
567 unsigned int *data)
568 {
569 struct apci1564_private *devpriv = dev->private;
570 unsigned int chan = CR_CHAN(insn->chanspec);
571 unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan);
572 unsigned int val;
573
574 switch (data[0]) {
575 case INSN_CONFIG_ARM:
576 val = inl(iobase + ADDI_TCW_CTRL_REG);
577 val |= ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_CNTR_ENA;
578 outl(data[1], iobase + ADDI_TCW_RELOAD_REG);
579 outl(val, iobase + ADDI_TCW_CTRL_REG);
580 break;
581 case INSN_CONFIG_DISARM:
582 val = inl(iobase + ADDI_TCW_CTRL_REG);
583 val &= ~(ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_CNTR_ENA);
584 outl(val, iobase + ADDI_TCW_CTRL_REG);
585 break;
586 case INSN_CONFIG_SET_COUNTER_MODE:
587
588
589
590
591
592 outl(data[1], iobase + ADDI_TCW_CTRL_REG);
593 break;
594 case INSN_CONFIG_GET_COUNTER_STATUS:
595 data[1] = 0;
596 val = inl(iobase + ADDI_TCW_CTRL_REG);
597 if (val & ADDI_TCW_CTRL_IRQ_ENA)
598 data[1] |= COMEDI_COUNTER_ARMED;
599 if (val & ADDI_TCW_CTRL_CNTR_ENA)
600 data[1] |= COMEDI_COUNTER_COUNTING;
601 val = inl(iobase + ADDI_TCW_STATUS_REG);
602 if (val & ADDI_TCW_STATUS_OVERFLOW)
603 data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
604 data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
605 COMEDI_COUNTER_TERMINAL_COUNT;
606 break;
607 default:
608 return -EINVAL;
609 }
610
611 return insn->n;
612 }
613
614 static int apci1564_counter_insn_write(struct comedi_device *dev,
615 struct comedi_subdevice *s,
616 struct comedi_insn *insn,
617 unsigned int *data)
618 {
619 struct apci1564_private *devpriv = dev->private;
620 unsigned int chan = CR_CHAN(insn->chanspec);
621 unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan);
622
623
624 if (insn->n) {
625 unsigned int val = data[insn->n - 1];
626
627 outl(val, iobase + ADDI_TCW_RELOAD_REG);
628 }
629
630 return insn->n;
631 }
632
633 static int apci1564_counter_insn_read(struct comedi_device *dev,
634 struct comedi_subdevice *s,
635 struct comedi_insn *insn,
636 unsigned int *data)
637 {
638 struct apci1564_private *devpriv = dev->private;
639 unsigned int chan = CR_CHAN(insn->chanspec);
640 unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan);
641 int i;
642
643
644 for (i = 0; i < insn->n; i++)
645 data[i] = inl(iobase + ADDI_TCW_VAL_REG);
646
647 return insn->n;
648 }
649
650 static int apci1564_auto_attach(struct comedi_device *dev,
651 unsigned long context_unused)
652 {
653 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
654 struct apci1564_private *devpriv;
655 struct comedi_subdevice *s;
656 unsigned int val;
657 int ret;
658
659 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
660 if (!devpriv)
661 return -ENOMEM;
662
663 ret = comedi_pci_enable(dev);
664 if (ret)
665 return ret;
666
667
668 devpriv->eeprom = pci_resource_start(pcidev, 0);
669 val = inl(devpriv->eeprom + APCI1564_EEPROM_REG);
670 if (APCI1564_EEPROM_TO_REV(val) == 0) {
671
672 dev->iobase = pci_resource_start(pcidev, 1) +
673 APCI1564_REV1_MAIN_IOBASE;
674 devpriv->timer = devpriv->eeprom + APCI1564_REV1_TIMER_IOBASE;
675 } else {
676
677 dev->iobase = devpriv->eeprom + APCI1564_REV2_MAIN_IOBASE;
678 devpriv->timer = devpriv->eeprom + APCI1564_REV2_TIMER_IOBASE;
679 devpriv->counters = pci_resource_start(pcidev, 1);
680 }
681
682 apci1564_reset(dev);
683
684 if (pcidev->irq > 0) {
685 ret = request_irq(pcidev->irq, apci1564_interrupt, IRQF_SHARED,
686 dev->board_name, dev);
687 if (ret == 0)
688 dev->irq = pcidev->irq;
689 }
690
691 ret = comedi_alloc_subdevices(dev, 7);
692 if (ret)
693 return ret;
694
695
696 s = &dev->subdevices[0];
697 s->type = COMEDI_SUBD_DI;
698 s->subdev_flags = SDF_READABLE;
699 s->n_chan = 32;
700 s->maxdata = 1;
701 s->range_table = &range_digital;
702 s->insn_bits = apci1564_di_insn_bits;
703
704
705 s = &dev->subdevices[1];
706 s->type = COMEDI_SUBD_DO;
707 s->subdev_flags = SDF_WRITABLE;
708 s->n_chan = 32;
709 s->maxdata = 1;
710 s->range_table = &range_digital;
711 s->insn_bits = apci1564_do_insn_bits;
712
713
714 s = &dev->subdevices[2];
715 if (dev->irq) {
716 dev->read_subdev = s;
717 s->type = COMEDI_SUBD_DI;
718 s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_LSAMPL;
719 s->n_chan = 1;
720 s->maxdata = 1;
721 s->range_table = &range_digital;
722 s->len_chanlist = 1;
723 s->insn_config = apci1564_cos_insn_config;
724 s->insn_bits = apci1564_cos_insn_bits;
725 s->do_cmdtest = apci1564_cos_cmdtest;
726 s->do_cmd = apci1564_cos_cmd;
727 s->cancel = apci1564_cos_cancel;
728 } else {
729 s->type = COMEDI_SUBD_UNUSED;
730 }
731
732
733 s = &dev->subdevices[3];
734 s->type = COMEDI_SUBD_TIMER;
735 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
736 s->n_chan = 1;
737 s->maxdata = 0x0fff;
738 s->range_table = &range_digital;
739 s->insn_config = apci1564_timer_insn_config;
740 s->insn_write = apci1564_timer_insn_write;
741 s->insn_read = apci1564_timer_insn_read;
742
743
744 s = &dev->subdevices[4];
745 if (devpriv->counters) {
746 s->type = COMEDI_SUBD_COUNTER;
747 s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
748 s->n_chan = 3;
749 s->maxdata = 0xffffffff;
750 s->range_table = &range_digital;
751 s->insn_config = apci1564_counter_insn_config;
752 s->insn_write = apci1564_counter_insn_write;
753 s->insn_read = apci1564_counter_insn_read;
754 } else {
755 s->type = COMEDI_SUBD_UNUSED;
756 }
757
758
759 s = &dev->subdevices[5];
760 ret = addi_watchdog_init(s, dev->iobase + APCI1564_WDOG_IOBASE);
761 if (ret)
762 return ret;
763
764
765 s = &dev->subdevices[6];
766 s->type = COMEDI_SUBD_DI;
767 s->subdev_flags = SDF_READABLE;
768 s->n_chan = 2;
769 s->maxdata = 1;
770 s->range_table = &range_digital;
771 s->insn_bits = apci1564_diag_insn_bits;
772
773 return 0;
774 }
775
776 static void apci1564_detach(struct comedi_device *dev)
777 {
778 if (dev->iobase)
779 apci1564_reset(dev);
780 comedi_pci_detach(dev);
781 }
782
783 static struct comedi_driver apci1564_driver = {
784 .driver_name = "addi_apci_1564",
785 .module = THIS_MODULE,
786 .auto_attach = apci1564_auto_attach,
787 .detach = apci1564_detach,
788 };
789
790 static int apci1564_pci_probe(struct pci_dev *dev,
791 const struct pci_device_id *id)
792 {
793 return comedi_pci_auto_config(dev, &apci1564_driver, id->driver_data);
794 }
795
796 static const struct pci_device_id apci1564_pci_table[] = {
797 { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1006) },
798 { 0 }
799 };
800 MODULE_DEVICE_TABLE(pci, apci1564_pci_table);
801
802 static struct pci_driver apci1564_pci_driver = {
803 .name = "addi_apci_1564",
804 .id_table = apci1564_pci_table,
805 .probe = apci1564_pci_probe,
806 .remove = comedi_pci_auto_unconfig,
807 };
808 module_comedi_pci_driver(apci1564_driver, apci1564_pci_driver);
809
810 MODULE_AUTHOR("Comedi http://www.comedi.org");
811 MODULE_DESCRIPTION("ADDI-DATA APCI-1564, 32 channel DI / 32 channel DO boards");
812 MODULE_LICENSE("GPL");