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 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
425 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
426 {0}
427};
428
429MODULE_DEVICE_TABLE(pci, dio200_pci_table);
430#endif
431
432
433
434
435#define thisboard ((const struct dio200_board *)dev->board_ptr)
436#define thislayout (&dio200_layouts[((struct dio200_board *) \
437 dev->board_ptr)->layout])
438
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 spinlock_t spinlock;
461};
462
463struct dio200_subdev_intr {
464 unsigned long iobase;
465 spinlock_t spinlock;
466 int active;
467 int has_int_sce;
468 unsigned int valid_isns;
469 unsigned int enabled_isns;
470 unsigned int stopcount;
471 int continuous;
472};
473
474
475
476
477
478
479
480static int dio200_attach(struct comedi_device *dev,
481 struct comedi_devconfig *it);
482static int dio200_detach(struct comedi_device *dev);
483static struct comedi_driver driver_amplc_dio200 = {
484 .driver_name = DIO200_DRIVER_NAME,
485 .module = THIS_MODULE,
486 .attach = dio200_attach,
487 .detach = dio200_detach,
488 .board_name = &dio200_boards[0].name,
489 .offset = sizeof(struct dio200_board),
490 .num_names = ARRAY_SIZE(dio200_boards),
491};
492
493#ifdef CONFIG_COMEDI_PCI
494static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
495 const struct pci_device_id
496 *ent)
497{
498 return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name);
499}
500
501static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
502{
503 comedi_pci_auto_unconfig(dev);
504}
505
506static struct pci_driver driver_amplc_dio200_pci_driver = {
507 .id_table = dio200_pci_table,
508 .probe = &driver_amplc_dio200_pci_probe,
509 .remove = __devexit_p(&driver_amplc_dio200_pci_remove)
510};
511
512static int __init driver_amplc_dio200_init_module(void)
513{
514 int retval;
515
516 retval = comedi_driver_register(&driver_amplc_dio200);
517 if (retval < 0)
518 return retval;
519
520 driver_amplc_dio200_pci_driver.name =
521 (char *)driver_amplc_dio200.driver_name;
522 return pci_register_driver(&driver_amplc_dio200_pci_driver);
523}
524
525static void __exit driver_amplc_dio200_cleanup_module(void)
526{
527 pci_unregister_driver(&driver_amplc_dio200_pci_driver);
528 comedi_driver_unregister(&driver_amplc_dio200);
529}
530
531module_init(driver_amplc_dio200_init_module);
532module_exit(driver_amplc_dio200_cleanup_module);
533#else
534static int __init driver_amplc_dio200_init_module(void)
535{
536 return comedi_driver_register(&driver_amplc_dio200);
537}
538
539static void __exit driver_amplc_dio200_cleanup_module(void)
540{
541 comedi_driver_unregister(&driver_amplc_dio200);
542}
543
544module_init(driver_amplc_dio200_init_module);
545module_exit(driver_amplc_dio200_cleanup_module);
546#endif
547
548
549
550
551
552#ifdef CONFIG_COMEDI_PCI
553static int
554dio200_find_pci(struct comedi_device *dev, int bus, int slot,
555 struct pci_dev **pci_dev_p)
556{
557 struct pci_dev *pci_dev = NULL;
558
559 *pci_dev_p = NULL;
560
561
562 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
563 pci_dev != NULL;
564 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
565 PCI_ANY_ID, pci_dev)) {
566
567 if (bus || slot) {
568 if (bus != pci_dev->bus->number
569 || slot != PCI_SLOT(pci_dev->devfn))
570 continue;
571 }
572 if (thisboard->model == anypci_model) {
573
574 int i;
575
576 for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
577 if (dio200_boards[i].bustype != pci_bustype)
578 continue;
579 if (pci_dev->device == dio200_boards[i].devid) {
580
581 dev->board_ptr = &dio200_boards[i];
582 break;
583 }
584 }
585 if (i == ARRAY_SIZE(dio200_boards))
586 continue;
587 } else {
588
589 if (pci_dev->device != thisboard->devid)
590 continue;
591 }
592
593
594 *pci_dev_p = pci_dev;
595 return 0;
596 }
597
598 if (bus || slot) {
599 printk(KERN_ERR
600 "comedi%d: error! no %s found at pci %02x:%02x!\n",
601 dev->minor, thisboard->name, bus, slot);
602 } else {
603 printk(KERN_ERR "comedi%d: error! no %s found!\n",
604 dev->minor, thisboard->name);
605 }
606 return -EIO;
607}
608#endif
609
610
611
612
613
614static int
615dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
616{
617 if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
618 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
619 minor, from, extent);
620 return -EIO;
621 }
622 return 0;
623}
624
625
626
627
628static int
629dio200_subdev_intr_insn_bits(struct comedi_device *dev,
630 struct comedi_subdevice *s,
631 struct comedi_insn *insn, unsigned int *data)
632{
633 struct dio200_subdev_intr *subpriv = s->private;
634
635 if (subpriv->has_int_sce) {
636
637 data[1] = inb(subpriv->iobase) & subpriv->valid_isns;
638 } else {
639
640 data[0] = 0;
641 }
642
643 return 2;
644}
645
646
647
648
649static void dio200_stop_intr(struct comedi_device *dev,
650 struct comedi_subdevice *s)
651{
652 struct dio200_subdev_intr *subpriv = s->private;
653
654 subpriv->active = 0;
655 subpriv->enabled_isns = 0;
656 if (subpriv->has_int_sce)
657 outb(0, subpriv->iobase);
658}
659
660
661
662
663static int dio200_start_intr(struct comedi_device *dev,
664 struct comedi_subdevice *s)
665{
666 unsigned int n;
667 unsigned isn_bits;
668 struct dio200_subdev_intr *subpriv = s->private;
669 struct comedi_cmd *cmd = &s->async->cmd;
670 int retval = 0;
671
672 if (!subpriv->continuous && subpriv->stopcount == 0) {
673
674 s->async->events |= COMEDI_CB_EOA;
675 subpriv->active = 0;
676 retval = 1;
677 } else {
678
679 isn_bits = 0;
680 if (cmd->chanlist) {
681 for (n = 0; n < cmd->chanlist_len; n++)
682 isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
683 }
684 isn_bits &= subpriv->valid_isns;
685
686 subpriv->enabled_isns = isn_bits;
687 if (subpriv->has_int_sce)
688 outb(isn_bits, subpriv->iobase);
689 }
690
691 return retval;
692}
693
694
695
696
697static int
698dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
699 unsigned int trignum)
700{
701 struct dio200_subdev_intr *subpriv;
702 unsigned long flags;
703 int event = 0;
704
705 if (trignum != 0)
706 return -EINVAL;
707
708 subpriv = s->private;
709
710 spin_lock_irqsave(&subpriv->spinlock, flags);
711 s->async->inttrig = NULL;
712 if (subpriv->active)
713 event = dio200_start_intr(dev, s);
714
715 spin_unlock_irqrestore(&subpriv->spinlock, flags);
716
717 if (event)
718 comedi_event(dev, s);
719
720 return 1;
721}
722
723
724
725
726
727static int dio200_handle_read_intr(struct comedi_device *dev,
728 struct comedi_subdevice *s)
729{
730 struct dio200_subdev_intr *subpriv = s->private;
731 unsigned triggered;
732 unsigned intstat;
733 unsigned cur_enabled;
734 unsigned int oldevents;
735 unsigned long flags;
736
737 triggered = 0;
738
739 spin_lock_irqsave(&subpriv->spinlock, flags);
740 oldevents = s->async->events;
741 if (subpriv->has_int_sce) {
742
743
744
745
746
747
748
749
750
751
752 cur_enabled = subpriv->enabled_isns;
753 while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
754 & ~triggered)) != 0) {
755 triggered |= intstat;
756 cur_enabled &= ~triggered;
757 outb(cur_enabled, subpriv->iobase);
758 }
759 } else {
760
761
762
763
764 triggered = subpriv->enabled_isns;
765 }
766
767 if (triggered) {
768
769
770
771
772
773
774 cur_enabled = subpriv->enabled_isns;
775 if (subpriv->has_int_sce)
776 outb(cur_enabled, subpriv->iobase);
777
778 if (subpriv->active) {
779
780
781
782
783
784
785
786 if (triggered & subpriv->enabled_isns) {
787
788 short val;
789 unsigned int n, ch, len;
790
791 val = 0;
792 len = s->async->cmd.chanlist_len;
793 for (n = 0; n < len; n++) {
794 ch = CR_CHAN(s->async->cmd.chanlist[n]);
795 if (triggered & (1U << ch))
796 val |= (1U << n);
797 }
798
799 if (comedi_buf_put(s->async, val)) {
800 s->async->events |= (COMEDI_CB_BLOCK |
801 COMEDI_CB_EOS);
802 } else {
803
804 dio200_stop_intr(dev, s);
805 s->async->events |= COMEDI_CB_ERROR
806 | COMEDI_CB_OVERFLOW;
807 comedi_error(dev, "buffer overflow");
808 }
809
810
811 if (!subpriv->continuous) {
812
813 if (subpriv->stopcount > 0) {
814 subpriv->stopcount--;
815 if (subpriv->stopcount == 0) {
816 s->async->events |=
817 COMEDI_CB_EOA;
818 dio200_stop_intr(dev,
819 s);
820 }
821 }
822 }
823 }
824 }
825 }
826 spin_unlock_irqrestore(&subpriv->spinlock, flags);
827
828 if (oldevents != s->async->events)
829 comedi_event(dev, s);
830
831 return (triggered != 0);
832}
833
834
835
836
837static int dio200_subdev_intr_cancel(struct comedi_device *dev,
838 struct comedi_subdevice *s)
839{
840 struct dio200_subdev_intr *subpriv = s->private;
841 unsigned long flags;
842
843 spin_lock_irqsave(&subpriv->spinlock, flags);
844 if (subpriv->active)
845 dio200_stop_intr(dev, s);
846
847 spin_unlock_irqrestore(&subpriv->spinlock, flags);
848
849 return 0;
850}
851
852
853
854
855static int
856dio200_subdev_intr_cmdtest(struct comedi_device *dev,
857 struct comedi_subdevice *s, struct comedi_cmd *cmd)
858{
859 int err = 0;
860 unsigned int tmp;
861
862
863
864 tmp = cmd->start_src;
865 cmd->start_src &= (TRIG_NOW | TRIG_INT);
866 if (!cmd->start_src || tmp != cmd->start_src)
867 err++;
868
869 tmp = cmd->scan_begin_src;
870 cmd->scan_begin_src &= TRIG_EXT;
871 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
872 err++;
873
874 tmp = cmd->convert_src;
875 cmd->convert_src &= TRIG_NOW;
876 if (!cmd->convert_src || tmp != cmd->convert_src)
877 err++;
878
879 tmp = cmd->scan_end_src;
880 cmd->scan_end_src &= TRIG_COUNT;
881 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
882 err++;
883
884 tmp = cmd->stop_src;
885 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
886 if (!cmd->stop_src || tmp != cmd->stop_src)
887 err++;
888
889 if (err)
890 return 1;
891
892
893
894
895
896 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
897 err++;
898 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
899 err++;
900 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
901 err++;
902 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
903 err++;
904 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
905 err++;
906
907 if (err)
908 return 2;
909
910
911
912
913 if (cmd->start_arg != 0) {
914 cmd->start_arg = 0;
915 err++;
916 }
917
918
919 if (cmd->scan_begin_arg != 0) {
920 cmd->scan_begin_arg = 0;
921 err++;
922 }
923
924
925 if (cmd->convert_arg != 0) {
926 cmd->convert_arg = 0;
927 err++;
928 }
929
930
931 if (cmd->scan_end_arg != cmd->chanlist_len) {
932 cmd->scan_end_arg = cmd->chanlist_len;
933 err++;
934 }
935
936 switch (cmd->stop_src) {
937 case TRIG_COUNT:
938
939 break;
940 case TRIG_NONE:
941 if (cmd->stop_arg != 0) {
942 cmd->stop_arg = 0;
943 err++;
944 }
945 break;
946 default:
947 break;
948 }
949
950 if (err)
951 return 3;
952
953
954
955
956
957 return 0;
958}
959
960
961
962
963static int dio200_subdev_intr_cmd(struct comedi_device *dev,
964 struct comedi_subdevice *s)
965{
966 struct comedi_cmd *cmd = &s->async->cmd;
967 struct dio200_subdev_intr *subpriv = s->private;
968 unsigned long flags;
969 int event = 0;
970
971 spin_lock_irqsave(&subpriv->spinlock, flags);
972 subpriv->active = 1;
973
974
975 switch (cmd->stop_src) {
976 case TRIG_COUNT:
977 subpriv->continuous = 0;
978 subpriv->stopcount = cmd->stop_arg;
979 break;
980 default:
981
982 subpriv->continuous = 1;
983 subpriv->stopcount = 0;
984 break;
985 }
986
987
988 switch (cmd->start_src) {
989 case TRIG_INT:
990 s->async->inttrig = dio200_inttrig_start_intr;
991 break;
992 default:
993
994 event = dio200_start_intr(dev, s);
995 break;
996 }
997 spin_unlock_irqrestore(&subpriv->spinlock, flags);
998
999 if (event)
1000 comedi_event(dev, s);
1001
1002 return 0;
1003}
1004
1005
1006
1007
1008static int
1009dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
1010 unsigned long iobase, unsigned valid_isns,
1011 int has_int_sce)
1012{
1013 struct dio200_subdev_intr *subpriv;
1014
1015 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1016 if (!subpriv) {
1017 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1018 dev->minor);
1019 return -ENOMEM;
1020 }
1021 subpriv->iobase = iobase;
1022 subpriv->has_int_sce = has_int_sce;
1023 subpriv->valid_isns = valid_isns;
1024 spin_lock_init(&subpriv->spinlock);
1025
1026 if (has_int_sce)
1027 outb(0, subpriv->iobase);
1028
1029 s->private = subpriv;
1030 s->type = COMEDI_SUBD_DI;
1031 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1032 if (has_int_sce) {
1033 s->n_chan = DIO200_MAX_ISNS;
1034 s->len_chanlist = DIO200_MAX_ISNS;
1035 } else {
1036
1037 s->n_chan = 1;
1038 s->len_chanlist = 1;
1039 }
1040 s->range_table = &range_digital;
1041 s->maxdata = 1;
1042 s->insn_bits = dio200_subdev_intr_insn_bits;
1043 s->do_cmdtest = dio200_subdev_intr_cmdtest;
1044 s->do_cmd = dio200_subdev_intr_cmd;
1045 s->cancel = dio200_subdev_intr_cancel;
1046
1047 return 0;
1048}
1049
1050
1051
1052
1053static void
1054dio200_subdev_intr_cleanup(struct comedi_device *dev,
1055 struct comedi_subdevice *s)
1056{
1057 struct dio200_subdev_intr *subpriv = s->private;
1058 kfree(subpriv);
1059}
1060
1061
1062
1063
1064static irqreturn_t dio200_interrupt(int irq, void *d)
1065{
1066 struct comedi_device *dev = d;
1067 int handled;
1068
1069 if (!dev->attached)
1070 return IRQ_NONE;
1071
1072 if (devpriv->intr_sd >= 0) {
1073 handled = dio200_handle_read_intr(dev,
1074 dev->subdevices +
1075 devpriv->intr_sd);
1076 } else {
1077 handled = 0;
1078 }
1079
1080 return IRQ_RETVAL(handled);
1081}
1082
1083
1084
1085
1086static int
1087dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
1088 struct comedi_insn *insn, unsigned int *data)
1089{
1090 struct dio200_subdev_8254 *subpriv = s->private;
1091 int chan = CR_CHAN(insn->chanspec);
1092 unsigned long flags;
1093
1094 spin_lock_irqsave(&subpriv->spinlock, flags);
1095 data[0] = i8254_read(subpriv->iobase, 0, chan);
1096 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1097
1098 return 1;
1099}
1100
1101
1102
1103
1104static int
1105dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1106 struct comedi_insn *insn, unsigned int *data)
1107{
1108 struct dio200_subdev_8254 *subpriv = s->private;
1109 int chan = CR_CHAN(insn->chanspec);
1110 unsigned long flags;
1111
1112 spin_lock_irqsave(&subpriv->spinlock, flags);
1113 i8254_write(subpriv->iobase, 0, chan, data[0]);
1114 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1115
1116 return 1;
1117}
1118
1119
1120
1121
1122static int
1123dio200_set_gate_src(struct dio200_subdev_8254 *subpriv,
1124 unsigned int counter_number, unsigned int gate_src)
1125{
1126 unsigned char byte;
1127
1128 if (!subpriv->has_clk_gat_sce)
1129 return -1;
1130 if (counter_number > 2)
1131 return -1;
1132 if (gate_src > 7)
1133 return -1;
1134
1135 subpriv->gate_src[counter_number] = gate_src;
1136 byte = GAT_SCE(subpriv->which, counter_number, gate_src);
1137 outb(byte, subpriv->gat_sce_iobase);
1138
1139 return 0;
1140}
1141
1142
1143
1144
1145static int
1146dio200_get_gate_src(struct dio200_subdev_8254 *subpriv,
1147 unsigned int counter_number)
1148{
1149 if (!subpriv->has_clk_gat_sce)
1150 return -1;
1151 if (counter_number > 2)
1152 return -1;
1153
1154 return subpriv->gate_src[counter_number];
1155}
1156
1157
1158
1159
1160static int
1161dio200_set_clock_src(struct dio200_subdev_8254 *subpriv,
1162 unsigned int counter_number, unsigned int clock_src)
1163{
1164 unsigned char byte;
1165
1166 if (!subpriv->has_clk_gat_sce)
1167 return -1;
1168 if (counter_number > 2)
1169 return -1;
1170 if (clock_src > 7)
1171 return -1;
1172
1173 subpriv->clock_src[counter_number] = clock_src;
1174 byte = CLK_SCE(subpriv->which, counter_number, clock_src);
1175 outb(byte, subpriv->clk_sce_iobase);
1176
1177 return 0;
1178}
1179
1180
1181
1182
1183static int
1184dio200_get_clock_src(struct dio200_subdev_8254 *subpriv,
1185 unsigned int counter_number, unsigned int *period_ns)
1186{
1187 unsigned clock_src;
1188
1189 if (!subpriv->has_clk_gat_sce)
1190 return -1;
1191 if (counter_number > 2)
1192 return -1;
1193
1194 clock_src = subpriv->clock_src[counter_number];
1195 *period_ns = clock_period[clock_src];
1196 return clock_src;
1197}
1198
1199
1200
1201
1202static int
1203dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1204 struct comedi_insn *insn, unsigned int *data)
1205{
1206 struct dio200_subdev_8254 *subpriv = s->private;
1207 int ret = 0;
1208 int chan = CR_CHAN(insn->chanspec);
1209 unsigned long flags;
1210
1211 spin_lock_irqsave(&subpriv->spinlock, flags);
1212 switch (data[0]) {
1213 case INSN_CONFIG_SET_COUNTER_MODE:
1214 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1215 if (ret < 0)
1216 ret = -EINVAL;
1217 break;
1218 case INSN_CONFIG_8254_READ_STATUS:
1219 data[1] = i8254_status(subpriv->iobase, 0, chan);
1220 break;
1221 case INSN_CONFIG_SET_GATE_SRC:
1222 ret = dio200_set_gate_src(subpriv, chan, data[2]);
1223 if (ret < 0)
1224 ret = -EINVAL;
1225 break;
1226 case INSN_CONFIG_GET_GATE_SRC:
1227 ret = dio200_get_gate_src(subpriv, chan);
1228 if (ret < 0) {
1229 ret = -EINVAL;
1230 break;
1231 }
1232 data[2] = ret;
1233 break;
1234 case INSN_CONFIG_SET_CLOCK_SRC:
1235 ret = dio200_set_clock_src(subpriv, chan, data[1]);
1236 if (ret < 0)
1237 ret = -EINVAL;
1238 break;
1239 case INSN_CONFIG_GET_CLOCK_SRC:
1240 ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1241 if (ret < 0) {
1242 ret = -EINVAL;
1243 break;
1244 }
1245 data[1] = ret;
1246 break;
1247 default:
1248 ret = -EINVAL;
1249 break;
1250 }
1251 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1252 return ret < 0 ? ret : insn->n;
1253}
1254
1255
1256
1257
1258
1259
1260
1261static int
1262dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1263 unsigned long iobase, unsigned offset,
1264 int has_clk_gat_sce)
1265{
1266 struct dio200_subdev_8254 *subpriv;
1267 unsigned int chan;
1268
1269 subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
1270 if (!subpriv) {
1271 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1272 dev->minor);
1273 return -ENOMEM;
1274 }
1275
1276 s->private = subpriv;
1277 s->type = COMEDI_SUBD_COUNTER;
1278 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1279 s->n_chan = 3;
1280 s->maxdata = 0xFFFF;
1281 s->insn_read = dio200_subdev_8254_read;
1282 s->insn_write = dio200_subdev_8254_write;
1283 s->insn_config = dio200_subdev_8254_config;
1284
1285 spin_lock_init(&subpriv->spinlock);
1286 subpriv->iobase = offset + iobase;
1287 subpriv->has_clk_gat_sce = has_clk_gat_sce;
1288 if (has_clk_gat_sce) {
1289
1290
1291 subpriv->clk_sce_iobase =
1292 DIO200_XCLK_SCE + (offset >> 3) + iobase;
1293 subpriv->gat_sce_iobase =
1294 DIO200_XGAT_SCE + (offset >> 3) + iobase;
1295 subpriv->which = (offset >> 2) & 1;
1296 }
1297
1298
1299 for (chan = 0; chan < 3; chan++) {
1300 i8254_set_mode(subpriv->iobase, 0, chan,
1301 I8254_MODE0 | I8254_BINARY);
1302 if (subpriv->has_clk_gat_sce) {
1303
1304 dio200_set_gate_src(subpriv, chan, 0);
1305
1306 dio200_set_clock_src(subpriv, chan, 0);
1307 }
1308 }
1309
1310 return 0;
1311}
1312
1313
1314
1315
1316static void
1317dio200_subdev_8254_cleanup(struct comedi_device *dev,
1318 struct comedi_subdevice *s)
1319{
1320 struct dio200_subdev_intr *subpriv = s->private;
1321 kfree(subpriv);
1322}
1323
1324
1325
1326
1327
1328
1329
1330static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1331{
1332 struct comedi_subdevice *s;
1333 unsigned long iobase = 0;
1334 unsigned int irq = 0;
1335#ifdef CONFIG_COMEDI_PCI
1336 struct pci_dev *pci_dev = NULL;
1337 int bus = 0, slot = 0;
1338#endif
1339 const struct dio200_layout_struct *layout;
1340 int share_irq = 0;
1341 int sdx;
1342 unsigned n;
1343 int ret;
1344
1345 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
1346 DIO200_DRIVER_NAME);
1347
1348 ret = alloc_private(dev, sizeof(struct dio200_private));
1349 if (ret < 0) {
1350 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1351 dev->minor);
1352 return ret;
1353 }
1354
1355
1356 switch (thisboard->bustype) {
1357 case isa_bustype:
1358 iobase = it->options[0];
1359 irq = it->options[1];
1360 share_irq = 0;
1361 break;
1362#ifdef CONFIG_COMEDI_PCI
1363 case pci_bustype:
1364 bus = it->options[0];
1365 slot = it->options[1];
1366 share_irq = 1;
1367
1368 ret = dio200_find_pci(dev, bus, slot, &pci_dev);
1369 if (ret < 0)
1370 return ret;
1371 devpriv->pci_dev = pci_dev;
1372 break;
1373#endif
1374 default:
1375 printk(KERN_ERR
1376 "comedi%d: %s: BUG! cannot determine board type!\n",
1377 dev->minor, DIO200_DRIVER_NAME);
1378 return -EINVAL;
1379 break;
1380 }
1381
1382 devpriv->intr_sd = -1;
1383
1384
1385#ifdef CONFIG_COMEDI_PCI
1386 if (pci_dev) {
1387 ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
1388 if (ret < 0) {
1389 printk(KERN_ERR
1390 "comedi%d: error! cannot enable PCI device and request regions!\n",
1391 dev->minor);
1392 return ret;
1393 }
1394 iobase = pci_resource_start(pci_dev, 2);
1395 irq = pci_dev->irq;
1396 } else
1397#endif
1398 {
1399 ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
1400 if (ret < 0)
1401 return ret;
1402 }
1403 dev->iobase = iobase;
1404
1405 layout = thislayout;
1406
1407 ret = alloc_subdevices(dev, layout->n_subdevs);
1408 if (ret < 0) {
1409 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1410 dev->minor);
1411 return ret;
1412 }
1413
1414 for (n = 0; n < dev->n_subdevices; n++) {
1415 s = &dev->subdevices[n];
1416 switch (layout->sdtype[n]) {
1417 case sd_8254:
1418
1419 ret = dio200_subdev_8254_init(dev, s, iobase,
1420 layout->sdinfo[n],
1421 layout->has_clk_gat_sce);
1422 if (ret < 0)
1423 return ret;
1424
1425 break;
1426 case sd_8255:
1427
1428 ret = subdev_8255_init(dev, s, NULL,
1429 iobase + layout->sdinfo[n]);
1430 if (ret < 0)
1431 return ret;
1432
1433 break;
1434 case sd_intr:
1435
1436 if (irq) {
1437 ret = dio200_subdev_intr_init(dev, s,
1438 iobase +
1439 DIO200_INT_SCE,
1440 layout->sdinfo[n],
1441 layout->
1442 has_int_sce);
1443 if (ret < 0)
1444 return ret;
1445
1446 devpriv->intr_sd = n;
1447 } else {
1448 s->type = COMEDI_SUBD_UNUSED;
1449 }
1450 break;
1451 default:
1452 s->type = COMEDI_SUBD_UNUSED;
1453 break;
1454 }
1455 }
1456
1457 sdx = devpriv->intr_sd;
1458 if (sdx >= 0 && sdx < dev->n_subdevices)
1459 dev->read_subdev = &dev->subdevices[sdx];
1460
1461 dev->board_name = thisboard->name;
1462
1463 if (irq) {
1464 unsigned long flags = share_irq ? IRQF_SHARED : 0;
1465
1466 if (request_irq(irq, dio200_interrupt, flags,
1467 DIO200_DRIVER_NAME, dev) >= 0) {
1468 dev->irq = irq;
1469 } else {
1470 printk(KERN_WARNING
1471 "comedi%d: warning! irq %u unavailable!\n",
1472 dev->minor, irq);
1473 }
1474 }
1475
1476 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1477 if (thisboard->bustype == isa_bustype) {
1478 printk("(base %#lx) ", iobase);
1479 } else {
1480#ifdef CONFIG_COMEDI_PCI
1481 printk("(pci %s) ", pci_name(pci_dev));
1482#endif
1483 }
1484 if (irq)
1485 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1486 else
1487 printk("(no irq) ");
1488
1489 printk("attached\n");
1490
1491 return 1;
1492}
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502static int dio200_detach(struct comedi_device *dev)
1503{
1504 const struct dio200_layout_struct *layout;
1505 unsigned n;
1506
1507 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
1508 DIO200_DRIVER_NAME);
1509
1510 if (dev->irq)
1511 free_irq(dev->irq, dev);
1512 if (dev->subdevices) {
1513 layout = thislayout;
1514 for (n = 0; n < dev->n_subdevices; n++) {
1515 struct comedi_subdevice *s = &dev->subdevices[n];
1516 switch (layout->sdtype[n]) {
1517 case sd_8254:
1518 dio200_subdev_8254_cleanup(dev, s);
1519 break;
1520 case sd_8255:
1521 subdev_8255_cleanup(dev, s);
1522 break;
1523 case sd_intr:
1524 dio200_subdev_intr_cleanup(dev, s);
1525 break;
1526 default:
1527 break;
1528 }
1529 }
1530 }
1531 if (devpriv) {
1532#ifdef CONFIG_COMEDI_PCI
1533 if (devpriv->pci_dev) {
1534 if (dev->iobase)
1535 comedi_pci_disable(devpriv->pci_dev);
1536 pci_dev_put(devpriv->pci_dev);
1537 } else
1538#endif
1539 {
1540 if (dev->iobase)
1541 release_region(dev->iobase, DIO200_IO_SIZE);
1542 }
1543 }
1544 if (dev->board_name)
1545 printk(KERN_INFO "comedi%d: %s removed\n",
1546 dev->minor, dev->board_name);
1547
1548 return 0;
1549}
1550
1551MODULE_AUTHOR("Comedi http://www.comedi.org");
1552MODULE_DESCRIPTION("Comedi low-level driver");
1553MODULE_LICENSE("GPL");
1554