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