staging: comedi: ni_pcidio: remove custom DPRINTK macro
[firefly-linux-kernel-4.4.55.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         unsigned 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,
130                             unsigned int *data)
131 {
132         struct subdev_8255_private *spriv = s->private;
133         unsigned long iobase = spriv->iobase;
134         unsigned int mask;
135         unsigned int v;
136
137         mask = comedi_dio_update_state(s, data);
138         if (mask) {
139                 if (mask & 0xff)
140                         spriv->io(1, _8255_DATA, s->state & 0xff, iobase);
141                 if (mask & 0xff00)
142                         spriv->io(1, _8255_DATA + 1, (s->state >> 8) & 0xff,
143                                   iobase);
144                 if (mask & 0xff0000)
145                         spriv->io(1, _8255_DATA + 2, (s->state >> 16) & 0xff,
146                                   iobase);
147         }
148
149         v = spriv->io(0, _8255_DATA, 0, iobase);
150         v |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
151         v |= (spriv->io(0, _8255_DATA + 2, 0, iobase) << 16);
152
153         data[1] = v;
154
155         return insn->n;
156 }
157
158 static void subdev_8255_do_config(struct comedi_device *dev,
159                                   struct comedi_subdevice *s)
160 {
161         struct subdev_8255_private *spriv = s->private;
162         unsigned long iobase = spriv->iobase;
163         int config;
164
165         config = CR_CW;
166         /* 1 in io_bits indicates output, 1 in config indicates input */
167         if (!(s->io_bits & 0x0000ff))
168                 config |= CR_A_IO;
169         if (!(s->io_bits & 0x00ff00))
170                 config |= CR_B_IO;
171         if (!(s->io_bits & 0x0f0000))
172                 config |= CR_C_LO_IO;
173         if (!(s->io_bits & 0xf00000))
174                 config |= CR_C_HI_IO;
175
176         spriv->io(1, _8255_CR, config, iobase);
177 }
178
179 static int subdev_8255_insn_config(struct comedi_device *dev,
180                                    struct comedi_subdevice *s,
181                                    struct comedi_insn *insn,
182                                    unsigned int *data)
183 {
184         unsigned int chan = CR_CHAN(insn->chanspec);
185         unsigned int mask;
186         int ret;
187
188         if (chan < 8)
189                 mask = 0x0000ff;
190         else if (chan < 16)
191                 mask = 0x00ff00;
192         else if (chan < 20)
193                 mask = 0x0f0000;
194         else
195                 mask = 0xf00000;
196
197         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
198         if (ret)
199                 return ret;
200
201         subdev_8255_do_config(dev, s);
202
203         return insn->n;
204 }
205
206 static int subdev_8255_cmdtest(struct comedi_device *dev,
207                                struct comedi_subdevice *s,
208                                struct comedi_cmd *cmd)
209 {
210         int err = 0;
211
212         /* Step 1 : check if triggers are trivially valid */
213
214         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
215         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
216         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
217         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
218         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
219
220         if (err)
221                 return 1;
222
223         /* Step 2a : make sure trigger sources are unique */
224         /* Step 2b : and mutually compatible */
225
226         if (err)
227                 return 2;
228
229         /* Step 3: check if arguments are trivially valid */
230
231         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
232         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
233         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
234         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
235         err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
236
237         if (err)
238                 return 3;
239
240         /* step 4 */
241
242         if (err)
243                 return 4;
244
245         return 0;
246 }
247
248 static int subdev_8255_cmd(struct comedi_device *dev,
249                            struct comedi_subdevice *s)
250 {
251         /* FIXME */
252
253         return 0;
254 }
255
256 static int subdev_8255_cancel(struct comedi_device *dev,
257                               struct comedi_subdevice *s)
258 {
259         /* FIXME */
260
261         return 0;
262 }
263
264 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
265                      int (*io) (int, int, int, unsigned long),
266                      unsigned long iobase)
267 {
268         struct subdev_8255_private *spriv;
269
270         spriv = comedi_alloc_spriv(s, sizeof(*spriv));
271         if (!spriv)
272                 return -ENOMEM;
273
274         spriv->iobase   = iobase;
275         spriv->io       = io ? io : subdev_8255_io;
276
277         s->type         = COMEDI_SUBD_DIO;
278         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
279         s->n_chan       = 24;
280         s->range_table  = &range_digital;
281         s->maxdata      = 1;
282         s->insn_bits    = subdev_8255_insn;
283         s->insn_config  = subdev_8255_insn_config;
284
285         subdev_8255_do_config(dev, s);
286
287         return 0;
288 }
289 EXPORT_SYMBOL_GPL(subdev_8255_init);
290
291 int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
292                          int (*io) (int, int, int, unsigned long),
293                          unsigned long iobase)
294 {
295         int ret;
296
297         ret = subdev_8255_init(dev, s, io, iobase);
298         if (ret)
299                 return ret;
300
301         s->do_cmdtest   = subdev_8255_cmdtest;
302         s->do_cmd       = subdev_8255_cmd;
303         s->cancel       = subdev_8255_cancel;
304
305         return 0;
306 }
307 EXPORT_SYMBOL_GPL(subdev_8255_init_irq);
308
309 /*
310
311    Start of the 8255 standalone device
312
313  */
314
315 static int dev_8255_attach(struct comedi_device *dev,
316                            struct comedi_devconfig *it)
317 {
318         struct comedi_subdevice *s;
319         int ret;
320         unsigned long iobase;
321         int i;
322
323         for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
324                 iobase = it->options[i];
325                 if (!iobase)
326                         break;
327         }
328         if (i == 0) {
329                 dev_warn(dev->class_dev, "no devices specified\n");
330                 return -EINVAL;
331         }
332
333         ret = comedi_alloc_subdevices(dev, i);
334         if (ret)
335                 return ret;
336
337         for (i = 0; i < dev->n_subdevices; i++) {
338                 s = &dev->subdevices[i];
339                 iobase = it->options[i];
340
341                 ret = __comedi_request_region(dev, iobase, _8255_SIZE);
342                 if (ret) {
343                         s->type = COMEDI_SUBD_UNUSED;
344                 } else {
345                         ret = subdev_8255_init(dev, s, NULL, iobase);
346                         if (ret)
347                                 return ret;
348                 }
349         }
350
351         return 0;
352 }
353
354 static void dev_8255_detach(struct comedi_device *dev)
355 {
356         struct comedi_subdevice *s;
357         struct subdev_8255_private *spriv;
358         int i;
359
360         for (i = 0; i < dev->n_subdevices; i++) {
361                 s = &dev->subdevices[i];
362                 if (s->type != COMEDI_SUBD_UNUSED) {
363                         spriv = s->private;
364                         release_region(spriv->iobase, _8255_SIZE);
365                 }
366         }
367 }
368
369 static struct comedi_driver dev_8255_driver = {
370         .driver_name    = "8255",
371         .module         = THIS_MODULE,
372         .attach         = dev_8255_attach,
373         .detach         = dev_8255_detach,
374 };
375 module_comedi_driver(dev_8255_driver);
376
377 MODULE_AUTHOR("Comedi http://www.comedi.org");
378 MODULE_DESCRIPTION("Comedi low-level driver");
379 MODULE_LICENSE("GPL");