staging: comedi: 8255.c: reformat comedi driver comment
[deliverable/linux.git] / drivers / staging / comedi / drivers / 8255.c
1 /*
2 * comedi/drivers/8255.c
3 * Driver for 8255
4 *
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 /*
20 * Driver: 8255
21 * Description: generic 8255 support
22 * Devices: [standard] 8255 (8255)
23 * Author: ds
24 * Status: works
25 * Updated: Fri, 7 Jun 2002 12:56:45 -0700
26 *
27 * The classic in digital I/O. The 8255 appears in Comedi as a single
28 * digital I/O subdevice with 24 channels. The channel 0 corresponds
29 * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
30 * 7. Direction configuration is done in blocks, with channels 0-7,
31 * 8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode
32 * supported is mode 0.
33 *
34 * You should enable compilation this driver if you plan to use a board
35 * that has an 8255 chip. For multifunction boards, the main driver will
36 * configure the 8255 subdevice automatically.
37 *
38 * This driver also works independently with ISA and PCI cards that
39 * directly map the 8255 registers to I/O ports, including cards with
40 * multiple 8255 chips. To configure the driver for such a card, the
41 * option list should be a list of the I/O port bases for each of the
42 * 8255 chips. For example,
43 *
44 * comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
45 *
46 * Note that most PCI 8255 boards do NOT work with this driver, and
47 * need a separate driver as a wrapper. For those that do work, the
48 * I/O port base address can be found in the output of 'lspci -v'.
49 */
50
51 /*
52 This file contains an exported subdevice for driving an 8255.
53
54 To use this subdevice as part of another driver, you need to
55 set up the subdevice in the attach function of the driver by
56 calling:
57
58 subdev_8255_init(device, subdevice, io_function, iobase)
59
60 device and subdevice are pointers to the device and subdevice
61 structures. io_function will be called to provide the
62 low-level input/output to the device, i.e., actual register
63 access. io_function will be called with the value of iobase
64 as the last parameter. If the 8255 device is mapped as 4
65 consecutive I/O ports, you can use NULL for io_function
66 and the I/O port base for iobase, and an internal function will
67 handle the register access.
68
69 In addition, if the main driver handles interrupts, you can
70 enable commands on the subdevice by calling subdev_8255_init_irq()
71 instead. Then, when you get an interrupt that is likely to be
72 from the 8255, you should call subdev_8255_interrupt(), which
73 will copy the latched value to a Comedi buffer.
74 */
75
76 #include <linux/module.h>
77 #include "../comedidev.h"
78
79 #include "comedi_fc.h"
80 #include "8255.h"
81
82 struct subdev_8255_private {
83 unsigned long regbase;
84 int (*io)(struct comedi_device *, int, int, int, unsigned long);
85 };
86
87 static int subdev_8255_io(struct comedi_device *dev,
88 int dir, int port, int data, unsigned long regbase)
89 {
90 if (dir) {
91 outb(data, dev->iobase + regbase + port);
92 return 0;
93 }
94 return inb(dev->iobase + regbase + port);
95 }
96
97 static int subdev_8255_mmio(struct comedi_device *dev,
98 int dir, int port, int data, unsigned long regbase)
99 {
100 if (dir) {
101 writeb(data, dev->mmio + regbase + port);
102 return 0;
103 }
104 return readb(dev->mmio + regbase + port);
105 }
106
107 static int subdev_8255_insn(struct comedi_device *dev,
108 struct comedi_subdevice *s,
109 struct comedi_insn *insn,
110 unsigned int *data)
111 {
112 struct subdev_8255_private *spriv = s->private;
113 unsigned long regbase = spriv->regbase;
114 unsigned int mask;
115 unsigned int v;
116
117 mask = comedi_dio_update_state(s, data);
118 if (mask) {
119 if (mask & 0xff)
120 spriv->io(dev, 1, I8255_DATA_A_REG,
121 s->state & 0xff, regbase);
122 if (mask & 0xff00)
123 spriv->io(dev, 1, I8255_DATA_B_REG,
124 (s->state >> 8) & 0xff, regbase);
125 if (mask & 0xff0000)
126 spriv->io(dev, 1, I8255_DATA_C_REG,
127 (s->state >> 16) & 0xff, regbase);
128 }
129
130 v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, regbase);
131 v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, regbase) << 8);
132 v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, regbase) << 16);
133
134 data[1] = v;
135
136 return insn->n;
137 }
138
139 static void subdev_8255_do_config(struct comedi_device *dev,
140 struct comedi_subdevice *s)
141 {
142 struct subdev_8255_private *spriv = s->private;
143 unsigned long regbase = spriv->regbase;
144 int config;
145
146 config = I8255_CTRL_CW;
147 /* 1 in io_bits indicates output, 1 in config indicates input */
148 if (!(s->io_bits & 0x0000ff))
149 config |= I8255_CTRL_A_IO;
150 if (!(s->io_bits & 0x00ff00))
151 config |= I8255_CTRL_B_IO;
152 if (!(s->io_bits & 0x0f0000))
153 config |= I8255_CTRL_C_LO_IO;
154 if (!(s->io_bits & 0xf00000))
155 config |= I8255_CTRL_C_HI_IO;
156
157 spriv->io(dev, 1, I8255_CTRL_REG, config, regbase);
158 }
159
160 static int subdev_8255_insn_config(struct comedi_device *dev,
161 struct comedi_subdevice *s,
162 struct comedi_insn *insn,
163 unsigned int *data)
164 {
165 unsigned int chan = CR_CHAN(insn->chanspec);
166 unsigned int mask;
167 int ret;
168
169 if (chan < 8)
170 mask = 0x0000ff;
171 else if (chan < 16)
172 mask = 0x00ff00;
173 else if (chan < 20)
174 mask = 0x0f0000;
175 else
176 mask = 0xf00000;
177
178 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
179 if (ret)
180 return ret;
181
182 subdev_8255_do_config(dev, s);
183
184 return insn->n;
185 }
186
187 static int __subdev_8255_init(struct comedi_device *dev,
188 struct comedi_subdevice *s,
189 int (*io)(struct comedi_device *,
190 int, int, int, unsigned long),
191 unsigned long regbase,
192 bool is_mmio)
193 {
194 struct subdev_8255_private *spriv;
195
196 spriv = comedi_alloc_spriv(s, sizeof(*spriv));
197 if (!spriv)
198 return -ENOMEM;
199
200 if (io)
201 spriv->io = io;
202 else if (is_mmio)
203 spriv->io = subdev_8255_mmio;
204 else
205 spriv->io = subdev_8255_io;
206 spriv->regbase = regbase;
207
208 s->type = COMEDI_SUBD_DIO;
209 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
210 s->n_chan = 24;
211 s->range_table = &range_digital;
212 s->maxdata = 1;
213 s->insn_bits = subdev_8255_insn;
214 s->insn_config = subdev_8255_insn_config;
215
216 subdev_8255_do_config(dev, s);
217
218 return 0;
219 }
220
221 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
222 int (*io)(struct comedi_device *,
223 int, int, int, unsigned long),
224 unsigned long regbase)
225 {
226 return __subdev_8255_init(dev, s, io, regbase, false);
227 }
228 EXPORT_SYMBOL_GPL(subdev_8255_init);
229
230 int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
231 int (*io)(struct comedi_device *,
232 int, int, int, unsigned long),
233 unsigned long regbase)
234 {
235 return __subdev_8255_init(dev, s, io, regbase, true);
236 }
237 EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
238 /*
239
240 Start of the 8255 standalone device
241
242 */
243
244 static int dev_8255_attach(struct comedi_device *dev,
245 struct comedi_devconfig *it)
246 {
247 struct comedi_subdevice *s;
248 unsigned long iobase;
249 int ret;
250 int i;
251
252 for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
253 iobase = it->options[i];
254 if (!iobase)
255 break;
256 }
257 if (i == 0) {
258 dev_warn(dev->class_dev, "no devices specified\n");
259 return -EINVAL;
260 }
261
262 ret = comedi_alloc_subdevices(dev, i);
263 if (ret)
264 return ret;
265
266 for (i = 0; i < dev->n_subdevices; i++) {
267 s = &dev->subdevices[i];
268 iobase = it->options[i];
269
270 /*
271 * __comedi_request_region() does not set dev->iobase.
272 *
273 * For 8255 devices that are manually attached using
274 * comedi_config, the 'iobase' is the actual I/O port
275 * base address of the chip.
276 */
277 ret = __comedi_request_region(dev, iobase, I8255_SIZE);
278 if (ret) {
279 s->type = COMEDI_SUBD_UNUSED;
280 } else {
281 ret = subdev_8255_init(dev, s, NULL, iobase);
282 if (ret)
283 return ret;
284 }
285 }
286
287 return 0;
288 }
289
290 static void dev_8255_detach(struct comedi_device *dev)
291 {
292 struct comedi_subdevice *s;
293 struct subdev_8255_private *spriv;
294 int i;
295
296 for (i = 0; i < dev->n_subdevices; i++) {
297 s = &dev->subdevices[i];
298 if (s->type != COMEDI_SUBD_UNUSED) {
299 spriv = s->private;
300 release_region(spriv->regbase, I8255_SIZE);
301 }
302 }
303 }
304
305 static struct comedi_driver dev_8255_driver = {
306 .driver_name = "8255",
307 .module = THIS_MODULE,
308 .attach = dev_8255_attach,
309 .detach = dev_8255_detach,
310 };
311 module_comedi_driver(dev_8255_driver);
312
313 MODULE_AUTHOR("Comedi http://www.comedi.org");
314 MODULE_DESCRIPTION("Comedi low-level driver");
315 MODULE_LICENSE("GPL");
This page took 0.041247 seconds and 5 git commands to generate.