]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/staging/comedi/drivers/pcmda12.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mirror_ubuntu-hirsute-kernel.git] / drivers / staging / comedi / drivers / pcmda12.c
CommitLineData
647d8b45
CC
1/*
2 comedi/drivers/pcmda12.c
3 Driver for Winsystems PC-104 based PCM-D/A-12 8-channel AO board.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2006 Calin A. Culianu <calin@ajvar.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/*
23Driver: pcmda12
24Description: A driver for the Winsystems PCM-D/A-12
25Devices: [Winsystems] PCM-D/A-12 (pcmda12)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Fri, 13 Jan 2006 12:01:01 -0500
28Status: works
29
30A driver for the relatively straightforward-to-program PCM-D/A-12.
31This board doesn't support commands, and the only way to set its
32analog output range is to jumper the board. As such,
33comedi_data_write() ignores the range value specified.
34
35The board uses 16 consecutive I/O addresses starting at the I/O port
36base address. Each address corresponds to the LSB then MSB of a
37particular channel from 0-7.
38
39Note that the board is not ISA-PNP capable and thus
40needs the I/O port comedi_config parameter.
41
42Note that passing a nonzero value as the second config option will
43enable "simultaneous xfer" mode for this board, in which AO writes
44will not take effect until a subsequent read of any AO channel. This
45is so that one can speed up programming by preloading all AO registers
46with values before simultaneously setting them to take effect with one
47read command.
48
49Configuration Options:
50 [0] - I/O port base address
51 [1] - Do Simultaneous Xfer (see description)
52*/
53
54#include "../comedidev.h"
55
56#include <linux/pci.h> /* for PCI devices */
57
647d8b45
CC
58#define SDEV_NO ((int)(s - dev->subdevices))
59#define CHANS 8
60#define IOSIZE 16
61#define LSB(x) ((unsigned char)((x) & 0xff))
62#define MSB(x) ((unsigned char)((((unsigned short)(x))>>8) & 0xff))
63#define LSB_PORT(chan) (dev->iobase + (chan)*2)
64#define MSB_PORT(chan) (LSB_PORT(chan)+1)
65#define BITS 12
66
67/*
68 * Bords
69 */
387c136a 70struct pcmda12_board {
647d8b45 71 const char *name;
387c136a 72};
647d8b45
CC
73
74/* note these have no effect and are merely here for reference..
75 these are configured by jumpering the board! */
9ced1de6 76static const struct comedi_lrange pcmda12_ranges = {
647d8b45
CC
77 3,
78 {
0a85b6f0
MT
79 UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5)
80 }
647d8b45
CC
81};
82
387c136a 83static const struct pcmda12_board pcmda12_boards[] = {
647d8b45 84 {
0a85b6f0
MT
85 .name = "pcmda12",
86 },
647d8b45
CC
87};
88
89/*
90 * Useful for shorthand access to the particular board structure
91 */
387c136a 92#define thisboard ((const struct pcmda12_board *)dev->board_ptr)
647d8b45 93
39eb312d
BP
94struct pcmda12_private {
95
790c5541 96 unsigned int ao_readback[CHANS];
647d8b45 97 int simultaneous_xfer_mode;
39eb312d
BP
98};
99
39eb312d 100#define devpriv ((struct pcmda12_private *)(dev->private))
647d8b45
CC
101
102/*
139dfbdf 103 * The struct comedi_driver structure tells the Comedi core module
647d8b45
CC
104 * which functions to call to configure/deconfigure (attach/detach)
105 * the board, and also about the kernel module that contains
106 * the device code.
107 */
0a85b6f0
MT
108static int pcmda12_attach(struct comedi_device *dev,
109 struct comedi_devconfig *it);
da91b269 110static int pcmda12_detach(struct comedi_device *dev);
647d8b45 111
da91b269 112static void zero_chans(struct comedi_device *dev);
647d8b45 113
139dfbdf 114static struct comedi_driver driver = {
68c3dbff
BP
115 .driver_name = "pcmda12",
116 .module = THIS_MODULE,
117 .attach = pcmda12_attach,
118 .detach = pcmda12_detach,
647d8b45
CC
119/* It is not necessary to implement the following members if you are
120 * writing a driver for a ISA PnP or PCI card */
121 /* Most drivers will support multiple types of boards by
122 * having an array of board structures. These were defined
123 * in pcmda12_boards[] above. Note that the element 'name'
124 * was first in the structure -- Comedi uses this fact to
125 * extract the name of the board without knowing any details
126 * about the structure except for its length.
127 * When a device is attached (by comedi_config), the name
128 * of the device is given to Comedi, and Comedi tries to
129 * match it by going through the list of board names. If
130 * there is a match, the address of the pointer is put
131 * into dev->board_ptr and driver->attach() is called.
132 *
133 * Note that these are not necessary if you can determine
134 * the type of board in software. ISA PnP, PCI, and PCMCIA
135 * devices are such boards.
136 */
68c3dbff
BP
137 .board_name = &pcmda12_boards[0].name,
138 .offset = sizeof(struct pcmda12_board),
8629efa4 139 .num_names = ARRAY_SIZE(pcmda12_boards),
647d8b45
CC
140};
141
da91b269 142static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 143 struct comedi_insn *insn, unsigned int *data);
da91b269 144static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 145 struct comedi_insn *insn, unsigned int *data);
647d8b45
CC
146
147/*
148 * Attach is called by the Comedi core to configure the driver
149 * for a particular board. If you specified a board_name array
150 * in the driver structure, dev->board_ptr contains that
151 * address.
152 */
0a85b6f0
MT
153static int pcmda12_attach(struct comedi_device *dev,
154 struct comedi_devconfig *it)
647d8b45 155{
34c43922 156 struct comedi_subdevice *s;
647d8b45
CC
157 unsigned long iobase;
158
159 iobase = it->options[0];
160 printk("comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
0a85b6f0 161 iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
647d8b45
CC
162
163 if (!request_region(iobase, IOSIZE, driver.driver_name)) {
164 printk("I/O port conflict\n");
165 return -EIO;
166 }
167 dev->iobase = iobase;
168
169/*
170 * Initialize dev->board_name. Note that we can use the "thisboard"
171 * macro now, since we just initialized it in the last line.
172 */
173 dev->board_name = thisboard->name;
174
175/*
176 * Allocate the private structure area. alloc_private() is a
177 * convenient macro defined in comedidev.h.
178 */
39eb312d 179 if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
647d8b45
CC
180 printk("cannot allocate private data structure\n");
181 return -ENOMEM;
182 }
183
184 devpriv->simultaneous_xfer_mode = it->options[1];
185
186 /*
187 * Allocate the subdevice structures. alloc_subdevice() is a
188 * convenient macro defined in comedidev.h.
189 *
190 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
191 * 96-channel version of the board.
192 */
193 if (alloc_subdevices(dev, 1) < 0) {
194 printk("cannot allocate subdevice data structures\n");
195 return -ENOMEM;
196 }
197
198 s = dev->subdevices;
199 s->private = NULL;
200 s->maxdata = (0x1 << BITS) - 1;
201 s->range_table = &pcmda12_ranges;
202 s->type = COMEDI_SUBD_AO;
203 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
204 s->n_chan = CHANS;
205 s->insn_write = &ao_winsn;
206 s->insn_read = &ao_rinsn;
207
208 zero_chans(dev); /* clear out all the registers, basically */
209
210 printk("attached\n");
211
212 return 1;
213}
214
215/*
216 * _detach is called to deconfigure a device. It should deallocate
217 * resources.
218 * This function is also called when _attach() fails, so it should be
219 * careful not to release resources that were not necessarily
220 * allocated by _attach(). dev->private and dev->subdevices are
221 * deallocated automatically by the core.
222 */
da91b269 223static int pcmda12_detach(struct comedi_device *dev)
647d8b45
CC
224{
225 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
226 if (dev->iobase)
227 release_region(dev->iobase, IOSIZE);
228 return 0;
229}
230
da91b269 231static void zero_chans(struct comedi_device *dev)
647d8b45
CC
232{ /* sets up an
233 ASIC chip to defaults */
234 int i;
235 for (i = 0; i < CHANS; ++i) {
236/* /\* do this as one instruction?? *\/ */
237/* outw(0, LSB_PORT(chan)); */
238 outb(0, LSB_PORT(i));
239 outb(0, MSB_PORT(i));
240 }
241 inb(LSB_PORT(0)); /* update chans. */
242}
243
da91b269 244static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 245 struct comedi_insn *insn, unsigned int *data)
647d8b45
CC
246{
247 int i;
248 int chan = CR_CHAN(insn->chanspec);
249
250 /* Writing a list of values to an AO channel is probably not
251 * very useful, but that's how the interface is defined. */
252 for (i = 0; i < insn->n; ++i) {
253
254/* /\* do this as one instruction?? *\/ */
255/* outw(data[i], LSB_PORT(chan)); */
256
257 /* Need to do this as two instructions due to 8-bit bus?? */
258 /* first, load the low byte */
259 outb(LSB(data[i]), LSB_PORT(chan));
260 /* next, write the high byte */
261 outb(MSB(data[i]), MSB_PORT(chan));
262
263 /* save shadow register */
264 devpriv->ao_readback[chan] = data[i];
265
266 if (!devpriv->simultaneous_xfer_mode)
267 inb(LSB_PORT(chan));
268 }
269
270 /* return the number of samples written */
271 return i;
272}
273
274/* AO subdevices should have a read insn as well as a write insn.
275
276 Usually this means copying a value stored in devpriv->ao_readback.
277 However, since this driver supports simultaneous xfer then sometimes
278 this function actually accomplishes work.
279
280 Simultaneaous xfer mode is accomplished by loading ALL the values
281 you want for AO in all the channels, then READing off one of the AO
282 registers to initiate the instantaneous simultaneous update of all
283 DAC outputs, which makes all AO channels update simultaneously.
284 This is useful for some control applications, I would imagine.
285*/
da91b269 286static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 287 struct comedi_insn *insn, unsigned int *data)
647d8b45
CC
288{
289 int i;
290 int chan = CR_CHAN(insn->chanspec);
291
292 for (i = 0; i < insn->n; i++) {
293 if (devpriv->simultaneous_xfer_mode)
294 inb(LSB_PORT(chan));
295 /* read back shadow register */
296 data[i] = devpriv->ao_readback[chan];
297 }
298
299 return i;
300}
301
302/*
303 * A convenient macro that defines init_module() and cleanup_module(),
304 * as necessary.
305 */
306COMEDI_INITCLEANUP(driver);