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