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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208#include <linux/interrupt.h>
209#include <linux/slab.h>
210
211#include "../comedidev.h"
212
213#include "comedi_pci.h"
214
215#include "8255.h"
216#include "8253.h"
217
218#define DIO200_DRIVER_NAME "amplc_dio200"
219
220
221#define PCI_VENDOR_ID_AMPLICON 0x14dc
222#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
223#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
224#define PCI_DEVICE_ID_INVALID 0xffff
225
226
227#define DIO200_IO_SIZE 0x20
228#define DIO200_XCLK_SCE 0x18
229#define DIO200_YCLK_SCE 0x19
230#define DIO200_ZCLK_SCE 0x1a
231#define DIO200_XGAT_SCE 0x1b
232#define DIO200_YGAT_SCE 0x1c
233#define DIO200_ZGAT_SCE 0x1d
234#define DIO200_INT_SCE 0x1e
235
236
237
238
239
240
241
242
243
244#define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
245#define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
246
247
248
249
250static const unsigned clock_period[8] = {
251 0,
252 100,
253 1000,
254 10000,
255 100000,
256 1000000,
257 0,
258 0
259};
260
261
262
263
264
265enum dio200_bustype { isa_bustype, pci_bustype };
266
267enum dio200_model {
268 pc212e_model,
269 pc214e_model,
270 pc215e_model, pci215_model,
271 pc218e_model,
272 pc272e_model, pci272_model,
273 anypci_model
274};
275
276enum dio200_layout {
277 pc212_layout,
278 pc214_layout,
279 pc215_layout,
280 pc218_layout,
281 pc272_layout
282};
283
284struct dio200_board {
285 const char *name;
286 unsigned short devid;
287 enum dio200_bustype bustype;
288 enum dio200_model model;
289 enum dio200_layout layout;
290};
291
292static const struct dio200_board dio200_boards[] = {
293 {
294 .name = "pc212e",
295 .bustype = isa_bustype,
296 .model = pc212e_model,
297 .layout = pc212_layout,
298 },
299 {
300 .name = "pc214e",
301 .bustype = isa_bustype,
302 .model = pc214e_model,
303 .layout = pc214_layout,
304 },
305 {
306 .name = "pc215e",
307 .bustype = isa_bustype,
308 .model = pc215e_model,
309 .layout = pc215_layout,
310 },
311#ifdef CONFIG_COMEDI_PCI
312 {
313 .name = "pci215",
314 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
315 .bustype = pci_bustype,
316 .model = pci215_model,
317 .layout = pc215_layout,
318 },
319#endif
320 {
321 .name = "pc218e",
322 .bustype = isa_bustype,
323 .model = pc218e_model,
324 .layout = pc218_layout,
325 },
326 {
327 .name = "pc272e",
328 .bustype = isa_bustype,
329 .model = pc272e_model,
330 .layout = pc272_layout,
331 },
332#ifdef CONFIG_COMEDI_PCI
333 {
334 .name = "pci272",
335 .devid = PCI_DEVICE_ID_AMPLICON_PCI272,
336 .bustype = pci_bustype,
337 .model = pci272_model,
338 .layout = pc272_layout,
339 },
340#endif
341#ifdef CONFIG_COMEDI_PCI
342 {
343 .name = DIO200_DRIVER_NAME,
344 .devid = PCI_DEVICE_ID_INVALID,
345 .bustype = pci_bustype,
346 .model = anypci_model,
347 },
348#endif
349};
350
351
352
353
354
355
356enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
357
358#define DIO200_MAX_SUBDEVS 7
359#define DIO200_MAX_ISNS 6
360
361struct dio200_layout_struct {
362 unsigned short n_subdevs;
363 unsigned char sdtype[DIO200_MAX_SUBDEVS];
364 unsigned char sdinfo[DIO200_MAX_SUBDEVS];
365 char has_int_sce;
366 char has_clk_gat_sce;
367};
368
369static const struct dio200_layout_struct dio200_layouts[] = {
370 [pc212_layout] = {
371 .n_subdevs = 6,
372 .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
373 sd_8254,
374 sd_intr},
375 .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14,
376 0x3F},
377 .has_int_sce = 1,
378 .has_clk_gat_sce = 1,
379 },
380 [pc214_layout] = {
381 .n_subdevs = 4,
382 .sdtype = {sd_8255, sd_8255, sd_8254,
383 sd_intr},
384 .sdinfo = {0x00, 0x08, 0x10, 0x01},
385 .has_int_sce = 0,
386 .has_clk_gat_sce = 0,
387 },
388 [pc215_layout] = {
389 .n_subdevs = 5,
390 .sdtype = {sd_8255, sd_8255, sd_8254,
391 sd_8254,
392 sd_intr},
393 .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
394 .has_int_sce = 1,
395 .has_clk_gat_sce = 1,
396 },
397 [pc218_layout] = {
398 .n_subdevs = 7,
399 .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
400 sd_8254,
401 sd_intr},
402 .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10,
403 0x14,
404 0x3F},
405 .has_int_sce = 1,
406 .has_clk_gat_sce = 1,
407 },
408 [pc272_layout] = {
409 .n_subdevs = 4,
410 .sdtype = {sd_8255, sd_8255, sd_8255,
411 sd_intr},
412 .sdinfo = {0x00, 0x08, 0x10, 0x3F},
413 .has_int_sce = 1,
414 .has_clk_gat_sce = 0,
415 },
416};
417
418
419
420
421
422#ifdef CONFIG_COMEDI_PCI
423static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
424 {
425 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
426 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
427 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
428 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
429 0}
430};
431
432MODULE_DEVICE_TABLE(pci, dio200_pci_table);
433#endif
434
435
436
437
438#define thisboard ((const struct dio200_board *)dev->board_ptr)
439#define thislayout (&dio200_layouts[((struct dio200_board *) \
440 dev->board_ptr)->layout])
441
442
443
444
445
446struct dio200_private {
447#ifdef CONFIG_COMEDI_PCI
448 struct pci_dev *pci_dev;
449#endif
450 int intr_sd;
451};
452
453#define devpriv ((struct dio200_private *)dev->private)
454
455struct dio200_subdev_8254 {
456 unsigned long iobase;
457 unsigned long clk_sce_iobase;
458 unsigned long gat_sce_iobase;
459 int which;
460 int has_clk_gat_sce;
461 unsigned clock_src[3];
462 unsigned gate_src[3];
463 spinlock_t spinlock;
464};
465
466struct dio200_subdev_intr {
467 unsigned long iobase;
468 spinlock_t spinlock;
469 int active;
470 int has_int_sce;
471 unsigned int valid_isns;
472 unsigned int enabled_isns;
473 unsigned int stopcount;
474 int continuous;
475};
476
477
478
479
480
481
482
483static int dio200_attach(struct comedi_device *dev,
484 struct comedi_devconfig *it);
485static int dio200_detach(struct comedi_device *dev);
486static struct comedi_driver driver_amplc_dio200 = {
487 .driver_name = DIO200_DRIVER_NAME,
488 .module = THIS_MODULE,
489 .attach = dio200_attach,
490 .detach = dio200_detach,
491 .board_name = &dio200_boards[0].name,
492 .offset = sizeof(struct dio200_board),
493 .num_names = ARRAY_SIZE(dio200_boards),
494};
495
496#ifdef CONFIG_COMEDI_PCI
497static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
498 const struct pci_device_id
499 *ent)
500{
501 return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name);
502}
503
504static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
505{
506 comedi_pci_auto_unconfig(dev);
507}
508
509static struct pci_driver driver_amplc_dio200_pci_driver = {
510 .id_table = dio200_pci_table,
511 .probe = &driver_amplc_dio200_pci_probe,
512 .remove = __devexit_p(&driver_amplc_dio200_pci_remove)
513};
514
515static int __init driver_amplc_dio200_init_module(void)
516{
517 int retval;
518
519 retval = comedi_driver_register(&driver_amplc_dio200);
520 if (retval < 0)
521 return retval;
522
523 driver_amplc_dio200_pci_driver.name =
524 (char *)driver_amplc_dio200.driver_name;
525 return pci_register_driver(&driver_amplc_dio200_pci_driver);
526}
527
528static void __exit driver_amplc_dio200_cleanup_module(void)
529{
530 pci_unregister_driver(&driver_amplc_dio200_pci_driver);
531 comedi_driver_unregister(&driver_amplc_dio200);
532}
533
534module_init(driver_amplc_dio200_init_module);
535module_exit(driver_amplc_dio200_cleanup_module);
536#else
537static int __init driver_amplc_dio200_init_module(void)
538{
539 return comedi_driver_register(&driver_amplc_dio200);
540}
541
542static void __exit driver_amplc_dio200_cleanup_module(void)
543{
544 comedi_driver_unregister(&driver_amplc_dio200);
545}
546
547module_init(driver_amplc_dio200_init_module);
548module_exit(driver_amplc_dio200_cleanup_module);
549#endif
550
551
552
553
554
555#ifdef CONFIG_COMEDI_PCI
556static int
557dio200_find_pci(struct comedi_device *dev, int bus, int slot,
558 struct pci_dev **pci_dev_p)
559{
560 struct pci_dev *pci_dev = NULL;
561
562 *pci_dev_p = NULL;
563
564
565 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
566 pci_dev != NULL;
567 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
568 PCI_ANY_ID, pci_dev)) {
569
570 if (bus || slot) {
571 if (bus != pci_dev->bus->number
572 || slot != PCI_SLOT(pci_dev->devfn))
573 continue;
574 }
575 if (thisboard->model == anypci_model) {
576
577 int i;
578
579 for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
580 if (dio200_boards[i].bustype != pci_bustype)
581 continue;
582 if (pci_dev->device == dio200_boards[i].devid) {
583
584 dev->board_ptr = &dio200_boards[i];
585 break;
586 }
587 }
588 if (i == ARRAY_SIZE(dio200_boards))
589 continue;
590 } else {
591
592 if (pci_dev->device != thisboard->devid)
593 continue;
594 }
595
596
597 *pci_dev_p = pci_dev;
598 return 0;
599 }
600
601 if (bus || slot) {
602 printk(KERN_ERR
603 "comedi%d: error! no %s found at pci %02x:%02x!\n",
604 dev->minor, thisboard->name, bus, slot);
605 } else {
606 printk(KERN_ERR "comedi%d: error! no %s found!\n",
607 dev->minor, thisboard->name);
608 }
609 return -EIO;
610}
611#endif
612
613
614
615
616
617static int
618dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
619{
620 if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
621 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
622 minor, from, extent);
623 return -EIO;
624 }
625 return 0;
626}
627
628
629
630
631static int
632dio200_subdev_intr_insn_bits(struct comedi_device *dev,
633 struct comedi_subdevice *s,
634 struct comedi_insn *insn, unsigned int *data)
635{
636 struct dio200_subdev_intr *subpriv = s->private;
637
638 if (subpriv->has_int_sce) {
639
640 data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
641 } else {
642
643 data[0] = 0;
644 }
645
646 return 2;
647}
648
649
650
651
652static void dio200_stop_intr(struct comedi_device *dev,
653 struct comedi_subdevice *s)
654{
655 struct dio200_subdev_intr *subpriv = s->private;
656
657 subpriv->active = 0;
658 subpriv->enabled_isns = 0;
659 if (subpriv->has_int_sce)
660 outb(0, subpriv->iobase);
661}
662
663
664
665
666static int dio200_start_intr(struct comedi_device *dev,
667 struct comedi_subdevice *s)
668{
669 unsigned int n;
670 unsigned isn_bits;
671 struct dio200_subdev_intr *subpriv = s->private;
672 struct comedi_cmd *cmd = &s->async->cmd;
673 int retval = 0;
674
675 if (!subpriv->continuous && subpriv->stopcount == 0) {
676
677 s->async->events |= COMEDI_CB_EOA;
678 subpriv->active = 0;
679 retval = 1;
680 } else {
681
682 isn_bits = 0;
683 if (cmd->chanlist) {
684 for (n = 0; n < cmd->chanlist_len; n++)
685 isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
686 }
687 isn_bits &= subpriv->valid_isns;
688
689 subpriv->enabled_isns = isn_bits;
690 if (subpriv->has_int_sce)
691 outb(isn_bits, subpriv->iobase);
692 }
693
694 return retval;
695}
696
697
698
699
700static int
701dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
702 unsigned int trignum)
703{
704 struct dio200_subdev_intr *subpriv;
705 unsigned long flags;
706 int event = 0;
707
708 if (trignum != 0)
709 return -EINVAL;
710
711 subpriv = s->private;
712
713 spin_lock_irqsave(&subpriv->spinlock, flags);
714 s->async->inttrig = NULL;
715 if (subpriv->active)
716 event = dio200_start_intr(dev, s);
717
718 spin_unlock_irqrestore(&subpriv->spinlock, flags);
719
720 if (event)
721 comedi_event(dev, s);
722
723 return 1;
724}
725
726
727
728
729
730static int dio200_handle_read_intr(struct comedi_device *dev,
731 struct comedi_subdevice *s)
732{
733 struct dio200_subdev_intr *subpriv = s->private;
734 unsigned triggered;
735 unsigned intstat;
736 unsigned cur_enabled;
737 unsigned int oldevents;
738 unsigned long flags;
739
740 triggered = 0;
741
742 spin_lock_irqsave(&subpriv->spinlock, flags);
743 oldevents = s->async->events;
744 if (subpriv->has_int_sce) {
745
746
747
748
749
750
751
752
753
754
755 cur_enabled = subpriv->enabled_isns;
756 while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
757 & ~triggered)) != 0) {
758 triggered |= intstat;
759 cur_enabled &= ~triggered;
760 outb(cur_enabled, subpriv->iobase);
761 }
762 } else {
763
764
765
766
767 triggered = subpriv->enabled_isns;
768 }
769
770 if (triggered) {
771
772
773
774
775
776
777 cur_enabled = subpriv->enabled_isns;
778 if (subpriv->has_int_sce)
779 outb(cur_enabled, subpriv->iobase);
780
781 if (subpriv->active) {
782
783
784
785
786
787
788
789 if (triggered & subpriv->enabled_isns) {
790
791 short val;
792 unsigned int n, ch, len;
793
794 val = 0;
795 len = s->async->cmd.chanlist_len;
796 for (n = 0; n < len; n++) {
797 ch = CR_CHAN(s->async->cmd.chanlist[n]);
798 if (triggered & (1U << ch))
799 val |= (1U << n);
800 }
801
802 if (comedi_buf_put(s->async, val)) {
803 s->async->events |= (COMEDI_CB_BLOCK |
804 COMEDI_CB_EOS);
805 } else {
806
807 dio200_stop_intr(dev, s);
808 s->async->events |= COMEDI_CB_ERROR
809 | COMEDI_CB_OVERFLOW;
810 comedi_error(dev, "buffer overflow");
811 }
812
813
814 if (!subpriv->continuous) {
815
816 if (subpriv->stopcount > 0) {
817 subpriv->stopcount--;
818 if (subpriv->stopcount == 0) {
819 s->async->events |=
820 COMEDI_CB_EOA;
821 dio200_stop_intr(dev,
822 s);
823 }
824 }
825 }
826 }
827 }
828 }
829 spin_unlock_irqrestore(&subpriv->spinlock, flags);
830
831 if (oldevents != s->async->events)
832 comedi_event(dev, s);
833
834 return (triggered != 0);
835}
836
837
838
839
840static int dio200_subdev_intr_cancel(struct comedi_device *dev,
841 struct comedi_subdevice *s)
842{
843 struct dio200_subdev_intr *subpriv = s->private;
844 unsigned long flags;
845
846 spin_lock_irqsave(&subpriv->spinlock, flags);
847 if (subpriv->active)
848 dio200_stop_intr(dev, s);
849
850 spin_unlock_irqrestore(&subpriv->spinlock, flags);
851
852 return 0;
853}
854
855
856
857
858static int
859dio200_subdev_intr_cmdtest(struct comedi_device *dev,
860 struct comedi_subdevice *s, struct comedi_cmd *cmd)
861{
862 int err = 0;
863 unsigned int tmp;
864
865
866
867 tmp = cmd->start_src;
868 cmd->start_src &= (TRIG_NOW | TRIG_INT);
869 if (!cmd->start_src || tmp != cmd->start_src)
870 err++;
871
872 tmp = cmd->scan_begin_src;
873 cmd->scan_begin_src &= TRIG_EXT;
874 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
875 err++;
876
877 tmp = cmd->convert_src;
878 cmd->convert_src &= TRIG_NOW;
879 if (!cmd->convert_src || tmp != cmd->convert_src)
880 err++;
881
882 tmp = cmd->scan_end_src;
883 cmd->scan_end_src &= TRIG_COUNT;
884 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
885 err++;
886
887 tmp = cmd->stop_src;
888 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
889 if (!cmd->stop_src || tmp != cmd->stop_src)
890 err++;
891
892 if (err)
893 return 1;
894
895
896
897
898
899 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
900 err++;
901 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
902 err++;
903 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
904 err++;
905 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
906 err++;
907 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
908 err++;
909
910 if (err)
911 return 2;
912
913
914
915
916 if (cmd->start_arg != 0) {
917 cmd->start_arg = 0;
918 err++;
919 }
920
921
922 if (cmd->scan_begin_arg != 0) {
923 cmd->scan_begin_arg = 0;
924 err++;
925 }
926
927
928 if (cmd->convert_arg != 0) {
929 cmd->convert_arg = 0;
930 err++;
931 }
932
933
934 if (cmd->scan_end_arg != cmd->chanlist_len) {
935 cmd->scan_end_arg = cmd->chanlist_len;
936 err++;
937 }
938
939 switch (cmd->stop_src) {
940 case TRIG_COUNT:
941
942 break;
943 case TRIG_NONE:
944 if (cmd->stop_arg != 0) {
945 cmd->stop_arg = 0;
946 err++;
947 }
948 break;
949 default:
950 break;
951 }
952
953 if (err)
954 return 3;
955
956
957
958
959
960 return 0;
961}
962
963
964
965
966static int dio200_subdev_intr_cmd(struct comedi_device *dev,
967 struct comedi_subdevice *s)
968{
969 struct comedi_cmd *cmd = &s->async->cmd;
970 struct dio200_subdev_intr *subpriv = s->private;
971 unsigned long flags;
972 int event = 0;
973
974 spin_lock_irqsave(&subpriv->spinlock, flags);
975 subpriv->active = 1;
976
977
978 switch (cmd->stop_src) {
979 case TRIG_COUNT:
980 subpriv->continuous = 0;
981 subpriv->stopcount = cmd->stop_arg;
982 break;
983 default:
984
985 subpriv->continuous = 1;
986 subpriv->stopcount = 0;
987 break;
988 }
989
990
991 switch (cmd->start_src) {
992 case TRIG_INT:
993 s->async->inttrig = dio200_inttrig_start_intr;
994 break;
995 default:
996
997 event = dio200_start_intr(dev, s);
998 break;
999 }
1000 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1001
1002 if (event)
1003 comedi_event(dev, s);
1004
1005 return 0;
1006}
1007
1008
1009
1010
1011static int
1012dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
1013 unsigned long iobase, unsigned valid_isns,
1014 int has_int_sce)
1015{
1016 struct dio200_subdev_intr *subpriv;
1017
1018 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1019 if (!subpriv) {
1020 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1021 dev->minor);
1022 return -ENOMEM;
1023 }
1024 subpriv->iobase = iobase;
1025 subpriv->has_int_sce = has_int_sce;
1026 subpriv->valid_isns = valid_isns;
1027 spin_lock_init(&subpriv->spinlock);
1028
1029 if (has_int_sce)
1030 outb(0, subpriv->iobase);
1031
1032 s->private = subpriv;
1033 s->type = COMEDI_SUBD_DI;
1034 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1035 if (has_int_sce) {
1036 s->n_chan = DIO200_MAX_ISNS;
1037 s->len_chanlist = DIO200_MAX_ISNS;
1038 } else {
1039
1040 s->n_chan = 1;
1041 s->len_chanlist = 1;
1042 }
1043 s->range_table = &range_digital;
1044 s->maxdata = 1;
1045 s->insn_bits = dio200_subdev_intr_insn_bits;
1046 s->do_cmdtest = dio200_subdev_intr_cmdtest;
1047 s->do_cmd = dio200_subdev_intr_cmd;
1048 s->cancel = dio200_subdev_intr_cancel;
1049
1050 return 0;
1051}
1052
1053
1054
1055
1056static void
1057dio200_subdev_intr_cleanup(struct comedi_device *dev,
1058 struct comedi_subdevice *s)
1059{
1060 struct dio200_subdev_intr *subpriv = s->private;
1061 kfree(subpriv);
1062}
1063
1064
1065
1066
1067static irqreturn_t dio200_interrupt(int irq, void *d)
1068{
1069 struct comedi_device *dev = d;
1070 int handled;
1071
1072 if (!dev->attached)
1073 return IRQ_NONE;
1074
1075 if (devpriv->intr_sd >= 0) {
1076 handled = dio200_handle_read_intr(dev,
1077 dev->subdevices +
1078 devpriv->intr_sd);
1079 } else {
1080 handled = 0;
1081 }
1082
1083 return IRQ_RETVAL(handled);
1084}
1085
1086
1087
1088
1089static int
1090dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
1091 struct comedi_insn *insn, unsigned int *data)
1092{
1093 struct dio200_subdev_8254 *subpriv = s->private;
1094 int chan = CR_CHAN(insn->chanspec);
1095 unsigned long flags;
1096
1097 spin_lock_irqsave(&subpriv->spinlock, flags);
1098 data[0] = i8254_read(subpriv->iobase, 0, chan);
1099 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1100
1101 return 1;
1102}
1103
1104
1105
1106
1107static int
1108dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1109 struct comedi_insn *insn, unsigned int *data)
1110{
1111 struct dio200_subdev_8254 *subpriv = s->private;
1112 int chan = CR_CHAN(insn->chanspec);
1113 unsigned long flags;
1114
1115 spin_lock_irqsave(&subpriv->spinlock, flags);
1116 i8254_write(subpriv->iobase, 0, chan, data[0]);
1117 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1118
1119 return 1;
1120}
1121
1122
1123
1124
1125static int
1126dio200_set_gate_src(struct dio200_subdev_8254 *subpriv,
1127 unsigned int counter_number, unsigned int gate_src)
1128{
1129 unsigned char byte;
1130
1131 if (!subpriv->has_clk_gat_sce)
1132 return -1;
1133 if (counter_number > 2)
1134 return -1;
1135 if (gate_src > 7)
1136 return -1;
1137
1138 subpriv->gate_src[counter_number] = gate_src;
1139 byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1140 outb(byte, subpriv->gat_sce_iobase);
1141
1142 return 0;
1143}
1144
1145
1146
1147
1148static int
1149dio200_get_gate_src(struct dio200_subdev_8254 *subpriv,
1150 unsigned int counter_number)
1151{
1152 if (!subpriv->has_clk_gat_sce)
1153 return -1;
1154 if (counter_number > 2)
1155 return -1;
1156
1157 return subpriv->gate_src[counter_number];
1158}
1159
1160
1161
1162
1163static int
1164dio200_set_clock_src(struct dio200_subdev_8254 *subpriv,
1165 unsigned int counter_number, unsigned int clock_src)
1166{
1167 unsigned char byte;
1168
1169 if (!subpriv->has_clk_gat_sce)
1170 return -1;
1171 if (counter_number > 2)
1172 return -1;
1173 if (clock_src > 7)
1174 return -1;
1175
1176 subpriv->clock_src[counter_number] = clock_src;
1177 byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1178 outb(byte, subpriv->clk_sce_iobase);
1179
1180 return 0;
1181}
1182
1183
1184
1185
1186static int
1187dio200_get_clock_src(struct dio200_subdev_8254 *subpriv,
1188 unsigned int counter_number, unsigned int *period_ns)
1189{
1190 unsigned clock_src;
1191
1192 if (!subpriv->has_clk_gat_sce)
1193 return -1;
1194 if (counter_number > 2)
1195 return -1;
1196
1197 clock_src = subpriv->clock_src[counter_number];
1198 *period_ns = clock_period[clock_src];
1199 return clock_src;
1200}
1201
1202
1203
1204
1205static int
1206dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1207 struct comedi_insn *insn, unsigned int *data)
1208{
1209 struct dio200_subdev_8254 *subpriv = s->private;
1210 int ret = 0;
1211 int chan = CR_CHAN(insn->chanspec);
1212 unsigned long flags;
1213
1214 spin_lock_irqsave(&subpriv->spinlock, flags);
1215 switch (data[0]) {
1216 case INSN_CONFIG_SET_COUNTER_MODE:
1217 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1218 if (ret < 0)
1219 ret = -EINVAL;
1220 break;
1221 case INSN_CONFIG_8254_READ_STATUS:
1222 data[1] = i8254_status(subpriv->iobase, 0, chan);
1223 break;
1224 case INSN_CONFIG_SET_GATE_SRC:
1225 ret = dio200_set_gate_src(subpriv, chan, data[2]);
1226 if (ret < 0)
1227 ret = -EINVAL;
1228 break;
1229 case INSN_CONFIG_GET_GATE_SRC:
1230 ret = dio200_get_gate_src(subpriv, chan);
1231 if (ret < 0) {
1232 ret = -EINVAL;
1233 break;
1234 }
1235 data[2] = ret;
1236 break;
1237 case INSN_CONFIG_SET_CLOCK_SRC:
1238 ret = dio200_set_clock_src(subpriv, chan, data[1]);
1239 if (ret < 0)
1240 ret = -EINVAL;
1241 break;
1242 case INSN_CONFIG_GET_CLOCK_SRC:
1243 ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1244 if (ret < 0) {
1245 ret = -EINVAL;
1246 break;
1247 }
1248 data[1] = ret;
1249 break;
1250 default:
1251 ret = -EINVAL;
1252 break;
1253 }
1254 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1255 return ret < 0 ? ret : insn->n;
1256}
1257
1258
1259
1260
1261
1262
1263
1264static int
1265dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1266 unsigned long iobase, unsigned offset,
1267 int has_clk_gat_sce)
1268{
1269 struct dio200_subdev_8254 *subpriv;
1270 unsigned int chan;
1271
1272 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1273 if (!subpriv) {
1274 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1275 dev->minor);
1276 return -ENOMEM;
1277 }
1278
1279 s->private = subpriv;
1280 s->type = COMEDI_SUBD_COUNTER;
1281 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1282 s->n_chan = 3;
1283 s->maxdata = 0xFFFF;
1284 s->insn_read = dio200_subdev_8254_read;
1285 s->insn_write = dio200_subdev_8254_write;
1286 s->insn_config = dio200_subdev_8254_config;
1287
1288 spin_lock_init(&subpriv->spinlock);
1289 subpriv->iobase = offset + iobase;
1290 subpriv->has_clk_gat_sce = has_clk_gat_sce;
1291 if (has_clk_gat_sce) {
1292
1293
1294 subpriv->clk_sce_iobase =
1295 DIO200_XCLK_SCE + (offset >> 3) + iobase;
1296 subpriv->gat_sce_iobase =
1297 DIO200_XGAT_SCE + (offset >> 3) + iobase;
1298 subpriv->which = (offset >> 2) & 1;
1299 }
1300
1301
1302 for (chan = 0; chan < 3; chan++) {
1303 i8254_set_mode(subpriv->iobase, 0, chan,
1304 I8254_MODE0 | I8254_BINARY);
1305 if (subpriv->has_clk_gat_sce) {
1306
1307 dio200_set_gate_src(subpriv, chan, 0);
1308
1309 dio200_set_clock_src(subpriv, chan, 0);
1310 }
1311 }
1312
1313 return 0;
1314}
1315
1316
1317
1318
1319static void
1320dio200_subdev_8254_cleanup(struct comedi_device *dev,
1321 struct comedi_subdevice *s)
1322{
1323 struct dio200_subdev_intr *subpriv = s->private;
1324 kfree(subpriv);
1325}
1326
1327
1328
1329
1330
1331
1332
1333static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1334{
1335 struct comedi_subdevice *s;
1336 unsigned long iobase = 0;
1337 unsigned int irq = 0;
1338#ifdef CONFIG_COMEDI_PCI
1339 struct pci_dev *pci_dev = NULL;
1340 int bus = 0, slot = 0;
1341#endif
1342 const struct dio200_layout_struct *layout;
1343 int share_irq = 0;
1344 int sdx;
1345 unsigned n;
1346 int ret;
1347
1348 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1349 DIO200_DRIVER_NAME);
1350
1351 ret = alloc_private(dev, sizeof(struct dio200_private));
1352 if (ret < 0) {
1353 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1354 dev->minor);
1355 return ret;
1356 }
1357
1358
1359 switch (thisboard->bustype) {
1360 case isa_bustype:
1361 iobase = it->options[0];
1362 irq = it->options[1];
1363 share_irq = 0;
1364 break;
1365#ifdef CONFIG_COMEDI_PCI
1366 case pci_bustype:
1367 bus = it->options[0];
1368 slot = it->options[1];
1369 share_irq = 1;
1370
1371 ret = dio200_find_pci(dev, bus, slot, &pci_dev);
1372 if (ret < 0)
1373 return ret;
1374 devpriv->pci_dev = pci_dev;
1375 break;
1376#endif
1377 default:
1378 printk(KERN_ERR
1379 "comedi%d: %s: BUG! cannot determine board type!\n",
1380 dev->minor, DIO200_DRIVER_NAME);
1381 return -EINVAL;
1382 break;
1383 }
1384
1385 devpriv->intr_sd = -1;
1386
1387
1388#ifdef CONFIG_COMEDI_PCI
1389 if (pci_dev) {
1390 ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1391 if (ret < 0) {
1392 printk(KERN_ERR
1393 "comedi%d: error! cannot enable PCI device and request regions!\n",
1394 dev->minor);
1395 return ret;
1396 }
1397 iobase = pci_resource_start(pci_dev, 2);
1398 irq = pci_dev->irq;
1399 } else
1400#endif
1401 {
1402 ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
1403 if (ret < 0)
1404 return ret;
1405 }
1406 dev->iobase = iobase;
1407
1408 layout = thislayout;
1409
1410 ret = alloc_subdevices(dev, layout->n_subdevs);
1411 if (ret < 0) {
1412 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1413 dev->minor);
1414 return ret;
1415 }
1416
1417 for (n = 0; n < dev->n_subdevices; n++) {
1418 s = &dev->subdevices[n];
1419 switch (layout->sdtype[n]) {
1420 case sd_8254:
1421
1422 ret = dio200_subdev_8254_init(dev, s, iobase,
1423 layout->sdinfo[n],
1424 layout->has_clk_gat_sce);
1425 if (ret < 0)
1426 return ret;
1427
1428 break;
1429 case sd_8255:
1430
1431 ret = subdev_8255_init(dev, s, NULL,
1432 iobase + layout->sdinfo[n]);
1433 if (ret < 0)
1434 return ret;
1435
1436 break;
1437 case sd_intr:
1438
1439 if (irq) {
1440 ret = dio200_subdev_intr_init(dev, s,
1441 iobase +
1442 DIO200_INT_SCE,
1443 layout->sdinfo[n],
1444 layout->
1445 has_int_sce);
1446 if (ret < 0)
1447 return ret;
1448
1449 devpriv->intr_sd = n;
1450 } else {
1451 s->type = COMEDI_SUBD_UNUSED;
1452 }
1453 break;
1454 default:
1455 s->type = COMEDI_SUBD_UNUSED;
1456 break;
1457 }
1458 }
1459
1460 sdx = devpriv->intr_sd;
1461 if (sdx >= 0 && sdx < dev->n_subdevices)
1462 dev->read_subdev = &dev->subdevices[sdx];
1463
1464 dev->board_name = thisboard->name;
1465
1466 if (irq) {
1467 unsigned long flags = share_irq ? IRQF_SHARED : 0;
1468
1469 if (request_irq(irq, dio200_interrupt, flags,
1470 DIO200_DRIVER_NAME, dev) >= 0) {
1471 dev->irq = irq;
1472 } else {
1473 printk(KERN_WARNING
1474 "comedi%d: warning! irq %u unavailable!\n",
1475 dev->minor, irq);
1476 }
1477 }
1478
1479 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1480 if (thisboard->bustype == isa_bustype) {
1481 printk("(base %#lx) ", iobase);
1482 } else {
1483#ifdef CONFIG_COMEDI_PCI
1484 printk("(pci %s) ", pci_name(pci_dev));
1485#endif
1486 }
1487 if (irq)
1488 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1489 else
1490 printk("(no irq) ");
1491
1492 printk("attached\n");
1493
1494 return 1;
1495}
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505static int dio200_detach(struct comedi_device *dev)
1506{
1507 const struct dio200_layout_struct *layout;
1508 unsigned n;
1509
1510 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1511 DIO200_DRIVER_NAME);
1512
1513 if (dev->irq)
1514 free_irq(dev->irq, dev);
1515 if (dev->subdevices) {
1516 layout = thislayout;
1517 for (n = 0; n < dev->n_subdevices; n++) {
1518 struct comedi_subdevice *s = &dev->subdevices[n];
1519 switch (layout->sdtype[n]) {
1520 case sd_8254:
1521 dio200_subdev_8254_cleanup(dev, s);
1522 break;
1523 case sd_8255:
1524 subdev_8255_cleanup(dev, s);
1525 break;
1526 case sd_intr:
1527 dio200_subdev_intr_cleanup(dev, s);
1528 break;
1529 default:
1530 break;
1531 }
1532 }
1533 }
1534 if (devpriv) {
1535#ifdef CONFIG_COMEDI_PCI
1536 if (devpriv->pci_dev) {
1537 if (dev->iobase)
1538 comedi_pci_disable(devpriv->pci_dev);
1539 pci_dev_put(devpriv->pci_dev);
1540 } else
1541#endif
1542 {
1543 if (dev->iobase)
1544 release_region(dev->iobase, DIO200_IO_SIZE);
1545 }
1546 }
1547 if (dev->board_name)
1548 printk(KERN_INFO "comedi%d: %s removed\n",
1549 dev->minor, dev->board_name);
1550
1551 return 0;
1552}
1553
1554MODULE_AUTHOR("Comedi http://www.comedi.org");
1555MODULE_DESCRIPTION("Comedi low-level driver");
1556MODULE_LICENSE("GPL");
1557