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#include <linux/module.h>
32#include "../comedidev.h"
33
34#include "8255.h"
35
36struct subdev_8255_private {
37 unsigned long regbase;
38 int (*io)(struct comedi_device *dev, int dir, int port, int data,
39 unsigned long regbase);
40};
41
42static int subdev_8255_io(struct comedi_device *dev,
43 int dir, int port, int data, unsigned long regbase)
44{
45 if (dir) {
46 outb(data, dev->iobase + regbase + port);
47 return 0;
48 }
49 return inb(dev->iobase + regbase + port);
50}
51
52static int subdev_8255_mmio(struct comedi_device *dev,
53 int dir, int port, int data, unsigned long regbase)
54{
55 if (dir) {
56 writeb(data, dev->mmio + regbase + port);
57 return 0;
58 }
59 return readb(dev->mmio + regbase + port);
60}
61
62static int subdev_8255_insn(struct comedi_device *dev,
63 struct comedi_subdevice *s,
64 struct comedi_insn *insn,
65 unsigned int *data)
66{
67 struct subdev_8255_private *spriv = s->private;
68 unsigned long regbase = spriv->regbase;
69 unsigned int mask;
70 unsigned int v;
71
72 mask = comedi_dio_update_state(s, data);
73 if (mask) {
74 if (mask & 0xff)
75 spriv->io(dev, 1, I8255_DATA_A_REG,
76 s->state & 0xff, regbase);
77 if (mask & 0xff00)
78 spriv->io(dev, 1, I8255_DATA_B_REG,
79 (s->state >> 8) & 0xff, regbase);
80 if (mask & 0xff0000)
81 spriv->io(dev, 1, I8255_DATA_C_REG,
82 (s->state >> 16) & 0xff, regbase);
83 }
84
85 v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, regbase);
86 v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, regbase) << 8);
87 v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, regbase) << 16);
88
89 data[1] = v;
90
91 return insn->n;
92}
93
94static void subdev_8255_do_config(struct comedi_device *dev,
95 struct comedi_subdevice *s)
96{
97 struct subdev_8255_private *spriv = s->private;
98 unsigned long regbase = spriv->regbase;
99 int config;
100
101 config = I8255_CTRL_CW;
102
103 if (!(s->io_bits & 0x0000ff))
104 config |= I8255_CTRL_A_IO;
105 if (!(s->io_bits & 0x00ff00))
106 config |= I8255_CTRL_B_IO;
107 if (!(s->io_bits & 0x0f0000))
108 config |= I8255_CTRL_C_LO_IO;
109 if (!(s->io_bits & 0xf00000))
110 config |= I8255_CTRL_C_HI_IO;
111
112 spriv->io(dev, 1, I8255_CTRL_REG, config, regbase);
113}
114
115static int subdev_8255_insn_config(struct comedi_device *dev,
116 struct comedi_subdevice *s,
117 struct comedi_insn *insn,
118 unsigned int *data)
119{
120 unsigned int chan = CR_CHAN(insn->chanspec);
121 unsigned int mask;
122 int ret;
123
124 if (chan < 8)
125 mask = 0x0000ff;
126 else if (chan < 16)
127 mask = 0x00ff00;
128 else if (chan < 20)
129 mask = 0x0f0000;
130 else
131 mask = 0xf00000;
132
133 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
134 if (ret)
135 return ret;
136
137 subdev_8255_do_config(dev, s);
138
139 return insn->n;
140}
141
142static int __subdev_8255_init(struct comedi_device *dev,
143 struct comedi_subdevice *s,
144 int (*io)(struct comedi_device *dev,
145 int dir, int port, int data,
146 unsigned long regbase),
147 unsigned long regbase,
148 bool is_mmio)
149{
150 struct subdev_8255_private *spriv;
151
152 spriv = comedi_alloc_spriv(s, sizeof(*spriv));
153 if (!spriv)
154 return -ENOMEM;
155
156 if (io)
157 spriv->io = io;
158 else if (is_mmio)
159 spriv->io = subdev_8255_mmio;
160 else
161 spriv->io = subdev_8255_io;
162 spriv->regbase = regbase;
163
164 s->type = COMEDI_SUBD_DIO;
165 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
166 s->n_chan = 24;
167 s->range_table = &range_digital;
168 s->maxdata = 1;
169 s->insn_bits = subdev_8255_insn;
170 s->insn_config = subdev_8255_insn_config;
171
172 subdev_8255_do_config(dev, s);
173
174 return 0;
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
203int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
204 int (*io)(struct comedi_device *dev, int dir, int port,
205 int data, unsigned long regbase),
206 unsigned long regbase)
207{
208 return __subdev_8255_init(dev, s, io, regbase, false);
209}
210EXPORT_SYMBOL_GPL(subdev_8255_init);
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
239 int (*io)(struct comedi_device *dev, int dir, int port,
240 int data, unsigned long regbase),
241 unsigned long regbase)
242{
243 return __subdev_8255_init(dev, s, io, regbase, true);
244}
245EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
246
247
248
249
250
251
252
253
254
255unsigned long subdev_8255_regbase(struct comedi_subdevice *s)
256{
257 struct subdev_8255_private *spriv = s->private;
258
259 return spriv->regbase;
260}
261EXPORT_SYMBOL_GPL(subdev_8255_regbase);
262
263static int __init comedi_8255_module_init(void)
264{
265 return 0;
266}
267module_init(comedi_8255_module_init);
268
269static void __exit comedi_8255_module_exit(void)
270{
271}
272module_exit(comedi_8255_module_exit);
273
274MODULE_AUTHOR("Comedi http://www.comedi.org");
275MODULE_DESCRIPTION("Comedi: Generic 8255 digital I/O support");
276MODULE_LICENSE("GPL");
277