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 | ||
ac52af96 DS |
44 | struct boarddef_struct { |
45 | const char *name; | |
46 | unsigned int iosize; | |
71b5f4f1 | 47 | int (*setup) (struct comedi_device *); |
ac52af96 DS |
48 | int type; |
49 | int n_chan; | |
50 | int n_bits; | |
0a85b6f0 MT |
51 | int (*winsn) (struct comedi_device *, struct comedi_subdevice *, |
52 | struct comedi_insn *, unsigned int *); | |
53 | int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, | |
54 | struct comedi_insn *, unsigned int *); | |
55 | int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, | |
56 | struct comedi_insn *, unsigned int *); | |
9ced1de6 | 57 | const struct comedi_lrange *range; |
ac52af96 | 58 | }; |
ac52af96 | 59 | |
22201cea HS |
60 | struct poc_private { |
61 | unsigned int ao_readback[32]; | |
62 | }; | |
63 | ||
da91b269 | 64 | static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 65 | struct comedi_insn *insn, unsigned int *data) |
ac52af96 | 66 | { |
22201cea | 67 | struct poc_private *devpriv = dev->private; |
ac52af96 DS |
68 | int chan; |
69 | ||
70 | chan = CR_CHAN(insn->chanspec); | |
22201cea | 71 | data[0] = devpriv->ao_readback[chan]; |
ac52af96 DS |
72 | |
73 | return 1; | |
74 | } | |
75 | ||
76 | /* DAC-02 registers */ | |
77 | #define DAC02_LSB(a) (2 * a) | |
78 | #define DAC02_MSB(a) (2 * a + 1) | |
79 | ||
da91b269 | 80 | static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 81 | struct comedi_insn *insn, unsigned int *data) |
ac52af96 | 82 | { |
22201cea | 83 | struct poc_private *devpriv = dev->private; |
ac52af96 DS |
84 | int temp; |
85 | int chan; | |
86 | int output; | |
87 | ||
88 | chan = CR_CHAN(insn->chanspec); | |
22201cea | 89 | devpriv->ao_readback[chan] = data[0]; |
ac52af96 DS |
90 | output = data[0]; |
91 | #ifdef wrong | |
2696fb57 | 92 | /* convert to complementary binary if range is bipolar */ |
ac52af96 DS |
93 | if ((CR_RANGE(insn->chanspec) & 0x2) == 0) |
94 | output = ~output; | |
95 | #endif | |
96 | temp = (output << 4) & 0xf0; | |
97 | outb(temp, dev->iobase + DAC02_LSB(chan)); | |
98 | temp = (output >> 4) & 0xff; | |
99 | outb(temp, dev->iobase + DAC02_MSB(chan)); | |
100 | ||
101 | return 1; | |
102 | } | |
103 | ||
0a85b6f0 MT |
104 | static int pcl733_insn_bits(struct comedi_device *dev, |
105 | struct comedi_subdevice *s, | |
106 | struct comedi_insn *insn, unsigned int *data) | |
ac52af96 | 107 | { |
ac52af96 DS |
108 | data[1] = inb(dev->iobase + 0); |
109 | data[1] |= (inb(dev->iobase + 1) << 8); | |
110 | data[1] |= (inb(dev->iobase + 2) << 16); | |
111 | data[1] |= (inb(dev->iobase + 3) << 24); | |
112 | ||
a2714e3e | 113 | return insn->n; |
ac52af96 DS |
114 | } |
115 | ||
0a85b6f0 MT |
116 | static int pcl734_insn_bits(struct comedi_device *dev, |
117 | struct comedi_subdevice *s, | |
118 | struct comedi_insn *insn, unsigned int *data) | |
ac52af96 | 119 | { |
ac52af96 DS |
120 | if (data[0]) { |
121 | s->state &= ~data[0]; | |
122 | s->state |= (data[0] & data[1]); | |
123 | if ((data[0] >> 0) & 0xff) | |
124 | outb((s->state >> 0) & 0xff, dev->iobase + 0); | |
125 | if ((data[0] >> 8) & 0xff) | |
126 | outb((s->state >> 8) & 0xff, dev->iobase + 1); | |
127 | if ((data[0] >> 16) & 0xff) | |
128 | outb((s->state >> 16) & 0xff, dev->iobase + 2); | |
129 | if ((data[0] >> 24) & 0xff) | |
130 | outb((s->state >> 24) & 0xff, dev->iobase + 3); | |
131 | } | |
132 | data[1] = s->state; | |
133 | ||
a2714e3e | 134 | return insn->n; |
ac52af96 DS |
135 | } |
136 | ||
9a644c40 HS |
137 | static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
138 | { | |
d5016e24 | 139 | const struct boarddef_struct *board = comedi_board(dev); |
22201cea | 140 | struct poc_private *devpriv; |
9a644c40 HS |
141 | struct comedi_subdevice *s; |
142 | unsigned long iobase; | |
143 | unsigned int iosize; | |
8b6c5694 | 144 | int ret; |
9a644c40 HS |
145 | |
146 | iobase = it->options[0]; | |
147 | printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, | |
d5016e24 | 148 | board->name, iobase); |
9a644c40 | 149 | |
d5016e24 | 150 | dev->board_name = board->name; |
9a644c40 HS |
151 | |
152 | if (iobase == 0) { | |
153 | printk(KERN_ERR "io base address required\n"); | |
154 | return -EINVAL; | |
155 | } | |
156 | ||
d5016e24 | 157 | iosize = board->iosize; |
9a644c40 HS |
158 | /* check if io addresses are available */ |
159 | if (!request_region(iobase, iosize, "dac02")) { | |
160 | printk(KERN_ERR "I/O port conflict: failed to allocate ports " | |
161 | "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); | |
162 | return -EIO; | |
163 | } | |
164 | dev->iobase = iobase; | |
165 | ||
8b6c5694 HS |
166 | ret = comedi_alloc_subdevices(dev, 1); |
167 | if (ret) | |
168 | return ret; | |
169 | ||
c34fa261 HS |
170 | devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); |
171 | if (!devpriv) | |
172 | return -ENOMEM; | |
173 | dev->private = devpriv; | |
9a644c40 HS |
174 | |
175 | /* analog output subdevice */ | |
eb31b63a | 176 | s = &dev->subdevices[0]; |
d5016e24 HS |
177 | s->type = board->type; |
178 | s->n_chan = board->n_chan; | |
179 | s->maxdata = (1 << board->n_bits) - 1; | |
180 | s->range_table = board->range; | |
181 | s->insn_write = board->winsn; | |
182 | s->insn_read = board->rinsn; | |
183 | s->insn_bits = board->insnbits; | |
9a644c40 HS |
184 | if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) |
185 | s->subdev_flags = SDF_WRITABLE; | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
484ecc95 | 190 | static void poc_detach(struct comedi_device *dev) |
9a644c40 | 191 | { |
d5016e24 HS |
192 | const struct boarddef_struct *board = comedi_board(dev); |
193 | ||
9a644c40 | 194 | if (dev->iobase) |
d5016e24 | 195 | release_region(dev->iobase, board->iosize); |
9a644c40 HS |
196 | } |
197 | ||
198 | static const struct boarddef_struct boards[] = { | |
199 | { | |
200 | .name = "dac02", | |
201 | .iosize = 8, | |
202 | /* .setup = dac02_setup, */ | |
203 | .type = COMEDI_SUBD_AO, | |
204 | .n_chan = 2, | |
205 | .n_bits = 12, | |
206 | .winsn = dac02_ao_winsn, | |
207 | .rinsn = readback_insn, | |
208 | .range = &range_unknown, | |
209 | }, { | |
210 | .name = "pcl733", | |
211 | .iosize = 4, | |
212 | .type = COMEDI_SUBD_DI, | |
213 | .n_chan = 32, | |
214 | .n_bits = 1, | |
215 | .insnbits = pcl733_insn_bits, | |
216 | .range = &range_digital, | |
217 | }, { | |
218 | .name = "pcl734", | |
219 | .iosize = 4, | |
220 | .type = COMEDI_SUBD_DO, | |
221 | .n_chan = 32, | |
222 | .n_bits = 1, | |
223 | .insnbits = pcl734_insn_bits, | |
224 | .range = &range_digital, | |
225 | }, | |
226 | }; | |
227 | ||
294f930d | 228 | static struct comedi_driver poc_driver = { |
9a644c40 HS |
229 | .driver_name = "poc", |
230 | .module = THIS_MODULE, | |
231 | .attach = poc_attach, | |
232 | .detach = poc_detach, | |
233 | .board_name = &boards[0].name, | |
234 | .num_names = ARRAY_SIZE(boards), | |
235 | .offset = sizeof(boards[0]), | |
236 | }; | |
294f930d | 237 | module_comedi_driver(poc_driver); |
90f703d3 AT |
238 | |
239 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
240 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
241 | MODULE_LICENSE("GPL"); |