Merge branch 'for-2.6.31' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / drivers / staging / comedi / drivers / dt2817.c
1 /*
2     comedi/drivers/dt2817.c
3     Hardware driver for Data Translation DT2817
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     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: dt2817
25 Description: Data Translation DT2817
26 Author: ds
27 Status: complete
28 Devices: [Data Translation] DT2817 (dt2817)
29
30 A very simple digital I/O card.  Four banks of 8 lines, each bank
31 is configurable for input or output.  One wonders why it takes a
32 50 page manual to describe this thing.
33
34 The driver (which, btw, is much less than 50 pages) has 1 subdevice
35 with 32 channels, configurable in groups of 8.
36
37 Configuration options:
38   [0] - I/O port base base address
39 */
40
41 #include "../comedidev.h"
42
43 #include <linux/ioport.h>
44
45 #define DT2817_SIZE 5
46
47 #define DT2817_CR 0
48 #define DT2817_DATA 1
49
50 static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it);
51 static int dt2817_detach(struct comedi_device *dev);
52 static struct comedi_driver driver_dt2817 = {
53         .driver_name = "dt2817",
54         .module = THIS_MODULE,
55         .attach = dt2817_attach,
56         .detach = dt2817_detach,
57 };
58
59 COMEDI_INITCLEANUP(driver_dt2817);
60
61 static int dt2817_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
62         struct comedi_insn *insn, unsigned int *data)
63 {
64         int mask;
65         int chan;
66         int oe = 0;
67
68         if (insn->n != 1)
69                 return -EINVAL;
70
71         chan = CR_CHAN(insn->chanspec);
72         if (chan < 8) {
73                 mask = 0xff;
74         } else if (chan < 16) {
75                 mask = 0xff00;
76         } else if (chan < 24) {
77                 mask = 0xff0000;
78         } else
79                 mask = 0xff000000;
80         if (data[0])
81                 s->io_bits |= mask;
82         else
83                 s->io_bits &= ~mask;
84
85         if (s->io_bits & 0x000000ff)
86                 oe |= 0x1;
87         if (s->io_bits & 0x0000ff00)
88                 oe |= 0x2;
89         if (s->io_bits & 0x00ff0000)
90                 oe |= 0x4;
91         if (s->io_bits & 0xff000000)
92                 oe |= 0x8;
93
94         outb(oe, dev->iobase + DT2817_CR);
95
96         return 1;
97 }
98
99 static int dt2817_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
100         struct comedi_insn *insn, unsigned int *data)
101 {
102         unsigned int changed;
103
104         /* It's questionable whether it is more important in
105          * a driver like this to be deterministic or fast.
106          * We choose fast. */
107
108         if (data[0]) {
109                 changed = s->state;
110                 s->state &= ~data[0];
111                 s->state |= (data[0] & data[1]);
112                 changed ^= s->state;
113                 changed &= s->io_bits;
114                 if (changed & 0x000000ff)
115                         outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0);
116                 if (changed & 0x0000ff00)
117                         outb((s->state >> 8) & 0xff,
118                                 dev->iobase + DT2817_DATA + 1);
119                 if (changed & 0x00ff0000)
120                         outb((s->state >> 16) & 0xff,
121                                 dev->iobase + DT2817_DATA + 2);
122                 if (changed & 0xff000000)
123                         outb((s->state >> 24) & 0xff,
124                                 dev->iobase + DT2817_DATA + 3);
125         }
126         data[1] = inb(dev->iobase + DT2817_DATA + 0);
127         data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8);
128         data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16);
129         data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24);
130
131         return 2;
132 }
133
134 static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
135 {
136         int ret;
137         struct comedi_subdevice *s;
138         unsigned long iobase;
139
140         iobase = it->options[0];
141         printk("comedi%d: dt2817: 0x%04lx ", dev->minor, iobase);
142         if (!request_region(iobase, DT2817_SIZE, "dt2817")) {
143                 printk("I/O port conflict\n");
144                 return -EIO;
145         }
146         dev->iobase = iobase;
147         dev->board_name = "dt2817";
148
149         ret = alloc_subdevices(dev, 1);
150         if (ret < 0)
151                 return ret;
152
153         s = dev->subdevices + 0;
154
155         s->n_chan = 32;
156         s->type = COMEDI_SUBD_DIO;
157         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
158         s->range_table = &range_digital;
159         s->maxdata = 1;
160         s->insn_bits = dt2817_dio_insn_bits;
161         s->insn_config = dt2817_dio_insn_config;
162
163         s->state = 0;
164         outb(0, dev->iobase + DT2817_CR);
165
166         printk("\n");
167
168         return 0;
169 }
170
171 static int dt2817_detach(struct comedi_device *dev)
172 {
173         printk("comedi%d: dt2817: remove\n", dev->minor);
174
175         if (dev->iobase)
176                 release_region(dev->iobase, DT2817_SIZE);
177
178         return 0;
179 }