]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/8255.c
Merge branch 'next' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[karo-tx-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 Driver: 8255
20 Description: generic 8255 support
21 Devices: [standard] 8255 (8255)
22 Author: ds
23 Status: works
24 Updated: Fri,  7 Jun 2002 12:56:45 -0700
25
26 The classic in digital I/O.  The 8255 appears in Comedi as a single
27 digital I/O subdevice with 24 channels.  The channel 0 corresponds
28 to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
29 7.  Direction configuration is done in blocks, with channels 0-7,
30 8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
31 supported is mode 0.
32
33 You should enable compilation this driver if you plan to use a board
34 that has an 8255 chip.  For multifunction boards, the main driver will
35 configure the 8255 subdevice automatically.
36
37 This driver also works independently with ISA and PCI cards that
38 directly map the 8255 registers to I/O ports, including cards with
39 multiple 8255 chips.  To configure the driver for such a card, the
40 option list should be a list of the I/O port bases for each of the
41 8255 chips.  For example,
42
43   comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
44
45 Note that most PCI 8255 boards do NOT work with this driver, and
46 need a separate driver as a wrapper.  For those that do work, the
47 I/O port base address can be found in the output of 'lspci -v'.
48
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 #define _8255_SIZE      4
83
84 #define _8255_DATA      0
85 #define _8255_CR        3
86
87 #define CR_C_LO_IO      0x01
88 #define CR_B_IO         0x02
89 #define CR_B_MODE       0x04
90 #define CR_C_HI_IO      0x08
91 #define CR_A_IO         0x10
92 #define CR_A_MODE(a)    ((a)<<5)
93 #define CR_CW           0x80
94
95 struct subdev_8255_private {
96         unsigned long iobase;
97         int (*io) (int, int, int, unsigned long);
98 };
99
100 static int subdev_8255_io(int dir, int port, int data, unsigned long iobase)
101 {
102         if (dir) {
103                 outb(data, iobase + port);
104                 return 0;
105         } else {
106                 return inb(iobase + port);
107         }
108 }
109
110 void subdev_8255_interrupt(struct comedi_device *dev,
111                            struct comedi_subdevice *s)
112 {
113         struct subdev_8255_private *spriv = s->private;
114         unsigned long iobase = spriv->iobase;
115         short d;
116
117         d = spriv->io(0, _8255_DATA, 0, iobase);
118         d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
119
120         comedi_buf_put(s->async, d);
121         s->async->events |= COMEDI_CB_EOS;
122
123         comedi_event(dev, s);
124 }
125 EXPORT_SYMBOL_GPL(subdev_8255_interrupt);
126
127 static int subdev_8255_insn(struct comedi_device *dev,
128                             struct comedi_subdevice *s,
129                             struct comedi_insn *insn, unsigned int *data)
130 {
131         struct subdev_8255_private *spriv = s->private;
132         unsigned long iobase = spriv->iobase;
133         unsigned int mask;
134         unsigned int bits;
135         unsigned int v;
136
137         mask = data[0];
138         bits = data[1];
139
140         if (mask) {
141                 v = s->state;
142                 v &= ~mask;
143                 v |= (bits & mask);
144
145                 if (mask & 0xff)
146                         spriv->io(1, _8255_DATA, v & 0xff, iobase);
147                 if (mask & 0xff00)
148                         spriv->io(1, _8255_DATA + 1, (v >> 8) & 0xff, iobase);
149                 if (mask & 0xff0000)
150                         spriv->io(1, _8255_DATA + 2, (v >> 16) & 0xff, iobase);
151
152                 s->state = v;
153         }
154
155         v = spriv->io(0, _8255_DATA, 0, iobase);
156         v |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
157         v |= (spriv->io(0, _8255_DATA + 2, 0, iobase) << 16);
158
159         data[1] = v;
160
161         return insn->n;
162 }
163
164 static void subdev_8255_do_config(struct comedi_device *dev,
165                                   struct comedi_subdevice *s)
166 {
167         struct subdev_8255_private *spriv = s->private;
168         unsigned long iobase = spriv->iobase;
169         int config;
170
171         config = CR_CW;
172         /* 1 in io_bits indicates output, 1 in config indicates input */
173         if (!(s->io_bits & 0x0000ff))
174                 config |= CR_A_IO;
175         if (!(s->io_bits & 0x00ff00))
176                 config |= CR_B_IO;
177         if (!(s->io_bits & 0x0f0000))
178                 config |= CR_C_LO_IO;
179         if (!(s->io_bits & 0xf00000))
180                 config |= CR_C_HI_IO;
181
182         spriv->io(1, _8255_CR, config, iobase);
183 }
184
185 static int subdev_8255_insn_config(struct comedi_device *dev,
186                                    struct comedi_subdevice *s,
187                                    struct comedi_insn *insn,
188                                    unsigned int *data)
189 {
190         unsigned int chan = CR_CHAN(insn->chanspec);
191         unsigned int mask;
192         int ret;
193
194         if (chan < 8)
195                 mask = 0x0000ff;
196         else if (chan < 16)
197                 mask = 0x00ff00;
198         else if (chan < 20)
199                 mask = 0x0f0000;
200         else
201                 mask = 0xf00000;
202
203         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
204         if (ret)
205                 return ret;
206
207         subdev_8255_do_config(dev, s);
208
209         return insn->n;
210 }
211
212 static int subdev_8255_cmdtest(struct comedi_device *dev,
213                                struct comedi_subdevice *s,
214                                struct comedi_cmd *cmd)
215 {
216         int err = 0;
217
218         /* Step 1 : check if triggers are trivially valid */
219
220         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
221         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
222         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
223         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
224         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
225
226         if (err)
227                 return 1;
228
229         /* Step 2a : make sure trigger sources are unique */
230         /* Step 2b : and mutually compatible */
231
232         if (err)
233                 return 2;
234
235         /* Step 3: check if arguments are trivially valid */
236
237         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
238         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
239         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
240         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
241         err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
242
243         if (err)
244                 return 3;
245
246         /* step 4 */
247
248         if (err)
249                 return 4;
250
251         return 0;
252 }
253
254 static int subdev_8255_cmd(struct comedi_device *dev,
255                            struct comedi_subdevice *s)
256 {
257         /* FIXME */
258
259         return 0;
260 }
261
262 static int subdev_8255_cancel(struct comedi_device *dev,
263                               struct comedi_subdevice *s)
264 {
265         /* FIXME */
266
267         return 0;
268 }
269
270 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
271                      int (*io) (int, int, int, unsigned long),
272                      unsigned long iobase)
273 {
274         struct subdev_8255_private *spriv;
275
276         spriv = comedi_alloc_spriv(s, sizeof(*spriv));
277         if (!spriv)
278                 return -ENOMEM;
279
280         spriv->iobase   = iobase;
281         spriv->io       = io ? io : subdev_8255_io;
282
283         s->type         = COMEDI_SUBD_DIO;
284         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
285         s->n_chan       = 24;
286         s->range_table  = &range_digital;
287         s->maxdata      = 1;
288         s->insn_bits    = subdev_8255_insn;
289         s->insn_config  = subdev_8255_insn_config;
290
291         s->state        = 0;
292         s->io_bits      = 0;
293
294         subdev_8255_do_config(dev, s);
295
296         return 0;
297 }
298 EXPORT_SYMBOL_GPL(subdev_8255_init);
299
300 int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
301                          int (*io) (int, int, int, unsigned long),
302                          unsigned long iobase)
303 {
304         int ret;
305
306         ret = subdev_8255_init(dev, s, io, iobase);
307         if (ret)
308                 return ret;
309
310         s->do_cmdtest   = subdev_8255_cmdtest;
311         s->do_cmd       = subdev_8255_cmd;
312         s->cancel       = subdev_8255_cancel;
313
314         return 0;
315 }
316 EXPORT_SYMBOL_GPL(subdev_8255_init_irq);
317
318 /*
319
320    Start of the 8255 standalone device
321
322  */
323
324 static int dev_8255_attach(struct comedi_device *dev,
325                            struct comedi_devconfig *it)
326 {
327         struct comedi_subdevice *s;
328         int ret;
329         unsigned long iobase;
330         int i;
331
332         for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
333                 iobase = it->options[i];
334                 if (!iobase)
335                         break;
336         }
337         if (i == 0) {
338                 dev_warn(dev->class_dev, "no devices specified\n");
339                 return -EINVAL;
340         }
341
342         ret = comedi_alloc_subdevices(dev, i);
343         if (ret)
344                 return ret;
345
346         for (i = 0; i < dev->n_subdevices; i++) {
347                 s = &dev->subdevices[i];
348                 iobase = it->options[i];
349
350                 ret = __comedi_request_region(dev, iobase, _8255_SIZE);
351                 if (ret) {
352                         s->type = COMEDI_SUBD_UNUSED;
353                 } else {
354                         ret = subdev_8255_init(dev, s, NULL, iobase);
355                         if (ret)
356                                 return ret;
357                 }
358         }
359
360         return 0;
361 }
362
363 static void dev_8255_detach(struct comedi_device *dev)
364 {
365         struct comedi_subdevice *s;
366         struct subdev_8255_private *spriv;
367         int i;
368
369         for (i = 0; i < dev->n_subdevices; i++) {
370                 s = &dev->subdevices[i];
371                 if (s->type != COMEDI_SUBD_UNUSED) {
372                         spriv = s->private;
373                         release_region(spriv->iobase, _8255_SIZE);
374                 }
375         }
376 }
377
378 static struct comedi_driver dev_8255_driver = {
379         .driver_name    = "8255",
380         .module         = THIS_MODULE,
381         .attach         = dev_8255_attach,
382         .detach         = dev_8255_detach,
383 };
384 module_comedi_driver(dev_8255_driver);
385
386 MODULE_AUTHOR("Comedi http://www.comedi.org");
387 MODULE_DESCRIPTION("Comedi low-level driver");
388 MODULE_LICENSE("GPL");