Commit | Line | Data |
---|---|---|
ac52af96 DS |
1 | /* |
2 | comedi/drivers/poc.c | |
3 | Mini-drivers for POC (Piece of Crap) boards | |
4 | Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> | |
5 | Copyright (C) 2001 David A. Schleef <ds@schleef.org> | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | */ | |
21 | /* | |
22 | Driver: poc | |
23 | Description: Generic driver for very simple devices | |
24 | Author: ds | |
25 | Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733), | |
26 | PCL-734 (pcl734) | |
27 | Updated: Sat, 16 Mar 2002 17:34:48 -0800 | |
28 | Status: unknown | |
29 | ||
30 | This driver is indended to support very simple ISA-based devices, | |
31 | including: | |
32 | dac02 - Keithley DAC-02 analog output board | |
33 | pcl733 - Advantech PCL-733 | |
34 | pcl734 - Advantech PCL-734 | |
35 | ||
36 | Configuration options: | |
37 | [0] - I/O port base | |
38 | */ | |
39 | ||
40 | #include "../comedidev.h" | |
41 | ||
42 | #include <linux/ioport.h> | |
43 | ||
44 | static int poc_attach(comedi_device * dev, comedi_devconfig * it); | |
45 | static int poc_detach(comedi_device * dev); | |
46 | static int readback_insn(comedi_device * dev, comedi_subdevice * s, | |
47 | comedi_insn * insn, lsampl_t * data); | |
48 | ||
49 | static int dac02_ao_winsn(comedi_device * dev, comedi_subdevice * s, | |
50 | comedi_insn * insn, lsampl_t * data); | |
51 | static int pcl733_insn_bits(comedi_device * dev, comedi_subdevice * s, | |
52 | comedi_insn * insn, lsampl_t * data); | |
53 | static int pcl734_insn_bits(comedi_device * dev, comedi_subdevice * s, | |
54 | comedi_insn * insn, lsampl_t * data); | |
55 | ||
56 | struct boarddef_struct { | |
57 | const char *name; | |
58 | unsigned int iosize; | |
59 | int (*setup) (comedi_device *); | |
60 | int type; | |
61 | int n_chan; | |
62 | int n_bits; | |
63 | int (*winsn) (comedi_device *, comedi_subdevice *, comedi_insn *, | |
64 | lsampl_t *); | |
65 | int (*rinsn) (comedi_device *, comedi_subdevice *, comedi_insn *, | |
66 | lsampl_t *); | |
67 | int (*insnbits) (comedi_device *, comedi_subdevice *, comedi_insn *, | |
68 | lsampl_t *); | |
69 | const comedi_lrange *range; | |
70 | }; | |
71 | static const struct boarddef_struct boards[] = { | |
72 | { | |
73 | name: "dac02", | |
74 | iosize: 8, | |
75 | //setup: dac02_setup, | |
76 | type: COMEDI_SUBD_AO, | |
77 | n_chan: 2, | |
78 | n_bits: 12, | |
79 | winsn: dac02_ao_winsn, | |
80 | rinsn: readback_insn, | |
81 | range: &range_unknown, | |
82 | }, | |
83 | { | |
84 | name: "pcl733", | |
85 | iosize: 4, | |
86 | type: COMEDI_SUBD_DI, | |
87 | n_chan: 32, | |
88 | n_bits: 1, | |
89 | insnbits:pcl733_insn_bits, | |
90 | range: &range_digital, | |
91 | }, | |
92 | { | |
93 | name: "pcl734", | |
94 | iosize: 4, | |
95 | type: COMEDI_SUBD_DO, | |
96 | n_chan: 32, | |
97 | n_bits: 1, | |
98 | insnbits:pcl734_insn_bits, | |
99 | range: &range_digital, | |
100 | }, | |
101 | }; | |
102 | ||
103 | #define n_boards (sizeof(boards)/sizeof(boards[0])) | |
104 | #define this_board ((const struct boarddef_struct *)dev->board_ptr) | |
105 | ||
106 | static comedi_driver driver_poc = { | |
107 | driver_name:"poc", | |
108 | module:THIS_MODULE, | |
109 | attach:poc_attach, | |
110 | detach:poc_detach, | |
111 | board_name:&boards[0].name, | |
112 | num_names:n_boards, | |
113 | offset:sizeof(boards[0]), | |
114 | }; | |
115 | ||
116 | static int poc_attach(comedi_device * dev, comedi_devconfig * it) | |
117 | { | |
118 | comedi_subdevice *s; | |
119 | unsigned long iobase; | |
120 | unsigned int iosize; | |
121 | ||
122 | iobase = it->options[0]; | |
123 | printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, | |
124 | this_board->name, iobase); | |
125 | ||
126 | dev->board_name = this_board->name; | |
127 | ||
128 | if (iobase == 0) { | |
129 | printk("io base address required\n"); | |
130 | return -EINVAL; | |
131 | } | |
132 | ||
133 | iosize = this_board->iosize; | |
134 | /* check if io addresses are available */ | |
135 | if (!request_region(iobase, iosize, "dac02")) { | |
136 | printk("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); | |
137 | return -EIO; | |
138 | } | |
139 | dev->iobase = iobase; | |
140 | ||
141 | if (alloc_subdevices(dev, 1) < 0) | |
142 | return -ENOMEM; | |
143 | if (alloc_private(dev, sizeof(lsampl_t) * this_board->n_chan) < 0) | |
144 | return -ENOMEM; | |
145 | ||
146 | /* analog output subdevice */ | |
147 | s = dev->subdevices + 0; | |
148 | s->type = this_board->type; | |
149 | s->n_chan = this_board->n_chan; | |
150 | s->maxdata = (1 << this_board->n_bits) - 1; | |
151 | s->range_table = this_board->range; | |
152 | s->insn_write = this_board->winsn; | |
153 | s->insn_read = this_board->rinsn; | |
154 | s->insn_bits = this_board->insnbits; | |
155 | if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) { | |
156 | s->subdev_flags = SDF_WRITABLE; | |
157 | } | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
162 | static int poc_detach(comedi_device * dev) | |
163 | { | |
164 | /* only free stuff if it has been allocated by _attach */ | |
165 | if (dev->iobase) | |
166 | release_region(dev->iobase, this_board->iosize); | |
167 | ||
168 | printk("comedi%d: dac02: remove\n", dev->minor); | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | static int readback_insn(comedi_device * dev, comedi_subdevice * s, | |
174 | comedi_insn * insn, lsampl_t * data) | |
175 | { | |
176 | int chan; | |
177 | ||
178 | chan = CR_CHAN(insn->chanspec); | |
179 | data[0] = ((lsampl_t *) dev->private)[chan]; | |
180 | ||
181 | return 1; | |
182 | } | |
183 | ||
184 | /* DAC-02 registers */ | |
185 | #define DAC02_LSB(a) (2 * a) | |
186 | #define DAC02_MSB(a) (2 * a + 1) | |
187 | ||
188 | static int dac02_ao_winsn(comedi_device * dev, comedi_subdevice * s, | |
189 | comedi_insn * insn, lsampl_t * data) | |
190 | { | |
191 | int temp; | |
192 | int chan; | |
193 | int output; | |
194 | ||
195 | chan = CR_CHAN(insn->chanspec); | |
196 | ((lsampl_t *) dev->private)[chan] = data[0]; | |
197 | output = data[0]; | |
198 | #ifdef wrong | |
199 | // convert to complementary binary if range is bipolar | |
200 | if ((CR_RANGE(insn->chanspec) & 0x2) == 0) | |
201 | output = ~output; | |
202 | #endif | |
203 | temp = (output << 4) & 0xf0; | |
204 | outb(temp, dev->iobase + DAC02_LSB(chan)); | |
205 | temp = (output >> 4) & 0xff; | |
206 | outb(temp, dev->iobase + DAC02_MSB(chan)); | |
207 | ||
208 | return 1; | |
209 | } | |
210 | ||
211 | static int pcl733_insn_bits(comedi_device * dev, comedi_subdevice * s, | |
212 | comedi_insn * insn, lsampl_t * data) | |
213 | { | |
214 | if (insn->n != 2) | |
215 | return -EINVAL; | |
216 | ||
217 | data[1] = inb(dev->iobase + 0); | |
218 | data[1] |= (inb(dev->iobase + 1) << 8); | |
219 | data[1] |= (inb(dev->iobase + 2) << 16); | |
220 | data[1] |= (inb(dev->iobase + 3) << 24); | |
221 | ||
222 | return 2; | |
223 | } | |
224 | ||
225 | static int pcl734_insn_bits(comedi_device * dev, comedi_subdevice * s, | |
226 | comedi_insn * insn, lsampl_t * data) | |
227 | { | |
228 | if (insn->n != 2) | |
229 | return -EINVAL; | |
230 | if (data[0]) { | |
231 | s->state &= ~data[0]; | |
232 | s->state |= (data[0] & data[1]); | |
233 | if ((data[0] >> 0) & 0xff) | |
234 | outb((s->state >> 0) & 0xff, dev->iobase + 0); | |
235 | if ((data[0] >> 8) & 0xff) | |
236 | outb((s->state >> 8) & 0xff, dev->iobase + 1); | |
237 | if ((data[0] >> 16) & 0xff) | |
238 | outb((s->state >> 16) & 0xff, dev->iobase + 2); | |
239 | if ((data[0] >> 24) & 0xff) | |
240 | outb((s->state >> 24) & 0xff, dev->iobase + 3); | |
241 | } | |
242 | data[1] = s->state; | |
243 | ||
244 | return 2; | |
245 | } | |
246 | ||
247 | COMEDI_INITCLEANUP(driver_poc); |