Commit | Line | Data |
---|---|---|
0e221af2 DS |
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 | ||
0a85b6f0 MT |
50 | static int dt2817_attach(struct comedi_device *dev, |
51 | struct comedi_devconfig *it); | |
da91b269 | 52 | static int dt2817_detach(struct comedi_device *dev); |
139dfbdf | 53 | static struct comedi_driver driver_dt2817 = { |
68c3dbff BP |
54 | .driver_name = "dt2817", |
55 | .module = THIS_MODULE, | |
56 | .attach = dt2817_attach, | |
57 | .detach = dt2817_detach, | |
0e221af2 DS |
58 | }; |
59 | ||
7114a280 AT |
60 | static int __init driver_dt2817_init_module(void) |
61 | { | |
62 | return comedi_driver_register(&driver_dt2817); | |
63 | } | |
64 | ||
65 | static void __exit driver_dt2817_cleanup_module(void) | |
66 | { | |
67 | comedi_driver_unregister(&driver_dt2817); | |
68 | } | |
69 | ||
70 | module_init(driver_dt2817_init_module); | |
71 | module_exit(driver_dt2817_cleanup_module); | |
0e221af2 | 72 | |
0a85b6f0 MT |
73 | static int dt2817_dio_insn_config(struct comedi_device *dev, |
74 | struct comedi_subdevice *s, | |
75 | struct comedi_insn *insn, unsigned int *data) | |
0e221af2 DS |
76 | { |
77 | int mask; | |
78 | int chan; | |
79 | int oe = 0; | |
80 | ||
81 | if (insn->n != 1) | |
82 | return -EINVAL; | |
83 | ||
84 | chan = CR_CHAN(insn->chanspec); | |
85 | if (chan < 8) { | |
86 | mask = 0xff; | |
87 | } else if (chan < 16) { | |
88 | mask = 0xff00; | |
89 | } else if (chan < 24) { | |
90 | mask = 0xff0000; | |
91 | } else | |
92 | mask = 0xff000000; | |
93 | if (data[0]) | |
94 | s->io_bits |= mask; | |
95 | else | |
96 | s->io_bits &= ~mask; | |
97 | ||
98 | if (s->io_bits & 0x000000ff) | |
99 | oe |= 0x1; | |
100 | if (s->io_bits & 0x0000ff00) | |
101 | oe |= 0x2; | |
102 | if (s->io_bits & 0x00ff0000) | |
103 | oe |= 0x4; | |
104 | if (s->io_bits & 0xff000000) | |
105 | oe |= 0x8; | |
106 | ||
107 | outb(oe, dev->iobase + DT2817_CR); | |
108 | ||
109 | return 1; | |
110 | } | |
111 | ||
0a85b6f0 MT |
112 | static int dt2817_dio_insn_bits(struct comedi_device *dev, |
113 | struct comedi_subdevice *s, | |
114 | struct comedi_insn *insn, unsigned int *data) | |
0e221af2 DS |
115 | { |
116 | unsigned int changed; | |
117 | ||
118 | /* It's questionable whether it is more important in | |
119 | * a driver like this to be deterministic or fast. | |
120 | * We choose fast. */ | |
121 | ||
122 | if (data[0]) { | |
123 | changed = s->state; | |
124 | s->state &= ~data[0]; | |
125 | s->state |= (data[0] & data[1]); | |
126 | changed ^= s->state; | |
127 | changed &= s->io_bits; | |
128 | if (changed & 0x000000ff) | |
129 | outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0); | |
130 | if (changed & 0x0000ff00) | |
131 | outb((s->state >> 8) & 0xff, | |
0a85b6f0 | 132 | dev->iobase + DT2817_DATA + 1); |
0e221af2 DS |
133 | if (changed & 0x00ff0000) |
134 | outb((s->state >> 16) & 0xff, | |
0a85b6f0 | 135 | dev->iobase + DT2817_DATA + 2); |
0e221af2 DS |
136 | if (changed & 0xff000000) |
137 | outb((s->state >> 24) & 0xff, | |
0a85b6f0 | 138 | dev->iobase + DT2817_DATA + 3); |
0e221af2 DS |
139 | } |
140 | data[1] = inb(dev->iobase + DT2817_DATA + 0); | |
141 | data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8); | |
142 | data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16); | |
143 | data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24); | |
144 | ||
145 | return 2; | |
146 | } | |
147 | ||
da91b269 | 148 | static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
0e221af2 DS |
149 | { |
150 | int ret; | |
34c43922 | 151 | struct comedi_subdevice *s; |
0e221af2 DS |
152 | unsigned long iobase; |
153 | ||
154 | iobase = it->options[0]; | |
155 | printk("comedi%d: dt2817: 0x%04lx ", dev->minor, iobase); | |
156 | if (!request_region(iobase, DT2817_SIZE, "dt2817")) { | |
157 | printk("I/O port conflict\n"); | |
158 | return -EIO; | |
159 | } | |
160 | dev->iobase = iobase; | |
161 | dev->board_name = "dt2817"; | |
162 | ||
c3744138 BP |
163 | ret = alloc_subdevices(dev, 1); |
164 | if (ret < 0) | |
0e221af2 DS |
165 | return ret; |
166 | ||
167 | s = dev->subdevices + 0; | |
168 | ||
169 | s->n_chan = 32; | |
170 | s->type = COMEDI_SUBD_DIO; | |
171 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; | |
172 | s->range_table = &range_digital; | |
173 | s->maxdata = 1; | |
174 | s->insn_bits = dt2817_dio_insn_bits; | |
175 | s->insn_config = dt2817_dio_insn_config; | |
176 | ||
177 | s->state = 0; | |
178 | outb(0, dev->iobase + DT2817_CR); | |
179 | ||
180 | printk("\n"); | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
da91b269 | 185 | static int dt2817_detach(struct comedi_device *dev) |
0e221af2 DS |
186 | { |
187 | printk("comedi%d: dt2817: remove\n", dev->minor); | |
188 | ||
189 | if (dev->iobase) | |
190 | release_region(dev->iobase, DT2817_SIZE); | |
191 | ||
192 | return 0; | |
193 | } | |
90f703d3 AT |
194 | |
195 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
196 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
197 | MODULE_LICENSE("GPL"); |