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