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#include <linux/module.h>
31#include "../comedidev.h"
32
33
34
35
36
37
38
39
40
41#define CSCIR 0x22
42#define CSCDR 0x23
43#define PAMR 0xa5
44#define PADR 0xa9
45#define PBMR 0xa4
46#define PBDR 0xa8
47#define PCMR 0xa3
48#define PCDR 0xa7
49
50static int dnp_dio_insn_bits(struct comedi_device *dev,
51 struct comedi_subdevice *s,
52 struct comedi_insn *insn,
53 unsigned int *data)
54{
55 unsigned int mask;
56 unsigned int val;
57
58
59
60
61
62
63
64 mask = comedi_dio_update_state(s, data);
65 if (mask) {
66 outb(PADR, CSCIR);
67 outb(s->state & 0xff, CSCDR);
68
69 outb(PBDR, CSCIR);
70 outb((s->state >> 8) & 0xff, CSCDR);
71
72 outb(PCDR, CSCIR);
73 val = inb(CSCDR) & 0x0f;
74 outb(((s->state >> 12) & 0xf0) | val, CSCDR);
75 }
76
77 outb(PADR, CSCIR);
78 val = inb(CSCDR);
79 outb(PBDR, CSCIR);
80 val |= (inb(CSCDR) << 8);
81 outb(PCDR, CSCIR);
82 val |= ((inb(CSCDR) & 0xf0) << 12);
83
84 data[1] = val;
85
86 return insn->n;
87}
88
89static int dnp_dio_insn_config(struct comedi_device *dev,
90 struct comedi_subdevice *s,
91 struct comedi_insn *insn,
92 unsigned int *data)
93{
94 unsigned int chan = CR_CHAN(insn->chanspec);
95 unsigned int mask;
96 unsigned int val;
97 int ret;
98
99 ret = comedi_dio_insn_config(dev, s, insn, data, 0);
100 if (ret)
101 return ret;
102
103 if (chan < 8) {
104 mask = 1 << chan;
105 outb(PAMR, CSCIR);
106 } else if (chan < 16) {
107 mask = 1 << (chan - 8);
108 outb(PBMR, CSCIR);
109 } else {
110
111
112
113
114
115
116
117
118
119 mask = 1 << ((chan - 16) * 2);
120 outb(PCMR, CSCIR);
121 }
122
123 val = inb(CSCDR);
124 if (data[0] == COMEDI_OUTPUT)
125 val |= mask;
126 else
127 val &= ~mask;
128 outb(val, CSCDR);
129
130 return insn->n;
131}
132
133static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
134{
135 struct comedi_subdevice *s;
136 int ret;
137
138
139
140
141
142
143
144 ret = comedi_alloc_subdevices(dev, 1);
145 if (ret)
146 return ret;
147
148 s = &dev->subdevices[0];
149
150 s->type = COMEDI_SUBD_DIO;
151 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
152 s->n_chan = 20;
153 s->maxdata = 1;
154 s->range_table = &range_digital;
155 s->insn_bits = dnp_dio_insn_bits;
156 s->insn_config = dnp_dio_insn_config;
157
158
159 outb(PAMR, CSCIR);
160 outb(0x00, CSCDR);
161 outb(PBMR, CSCIR);
162 outb(0x00, CSCDR);
163 outb(PCMR, CSCIR);
164 outb((inb(CSCDR) & 0xAA), CSCDR);
165
166 return 0;
167}
168
169static void dnp_detach(struct comedi_device *dev)
170{
171 outb(PAMR, CSCIR);
172 outb(0x00, CSCDR);
173 outb(PBMR, CSCIR);
174 outb(0x00, CSCDR);
175 outb(PCMR, CSCIR);
176 outb((inb(CSCDR) & 0xAA), CSCDR);
177}
178
179static struct comedi_driver dnp_driver = {
180 .driver_name = "dnp-1486",
181 .module = THIS_MODULE,
182 .attach = dnp_attach,
183 .detach = dnp_detach,
184};
185module_comedi_driver(dnp_driver);
186
187MODULE_AUTHOR("Comedi http://www.comedi.org");
188MODULE_DESCRIPTION("Comedi low-level driver");
189MODULE_LICENSE("GPL");
190