staging: comedi: remove inline alloc_private()
[deliverable/linux.git] / drivers / staging / comedi / drivers / pcmda12.c
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 /*
23 Driver: pcmda12
24 Description: A driver for the Winsystems PCM-D/A-12
25 Devices: [Winsystems] PCM-D/A-12 (pcmda12)
26 Author: Calin Culianu <calin@ajvar.org>
27 Updated: Fri, 13 Jan 2006 12:01:01 -0500
28 Status: works
29
30 A driver for the relatively straightforward-to-program PCM-D/A-12.
31 This board doesn't support commands, and the only way to set its
32 analog output range is to jumper the board. As such,
33 comedi_data_write() ignores the range value specified.
34
35 The board uses 16 consecutive I/O addresses starting at the I/O port
36 base address. Each address corresponds to the LSB then MSB of a
37 particular channel from 0-7.
38
39 Note that the board is not ISA-PNP capable and thus
40 needs the I/O port comedi_config parameter.
41
42 Note that passing a nonzero value as the second config option will
43 enable "simultaneous xfer" mode for this board, in which AO writes
44 will not take effect until a subsequent read of any AO channel. This
45 is so that one can speed up programming by preloading all AO registers
46 with values before simultaneously setting them to take effect with one
47 read command.
48
49 Configuration 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
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 /* note these have no effect and are merely here for reference..
68 these are configured by jumpering the board! */
69 static const struct comedi_lrange pcmda12_ranges = {
70 3,
71 {
72 UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5)
73 }
74 };
75
76 struct pcmda12_private {
77
78 unsigned int ao_readback[CHANS];
79 int simultaneous_xfer_mode;
80 };
81
82 static void zero_chans(struct comedi_device *dev)
83 { /* sets up an
84 ASIC chip to defaults */
85 int i;
86 for (i = 0; i < CHANS; ++i) {
87 /* /\* do this as one instruction?? *\/ */
88 /* outw(0, LSB_PORT(chan)); */
89 outb(0, LSB_PORT(i));
90 outb(0, MSB_PORT(i));
91 }
92 inb(LSB_PORT(0)); /* update chans. */
93 }
94
95 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
96 struct comedi_insn *insn, unsigned int *data)
97 {
98 struct pcmda12_private *devpriv = dev->private;
99 int i;
100 int chan = CR_CHAN(insn->chanspec);
101
102 /* Writing a list of values to an AO channel is probably not
103 * very useful, but that's how the interface is defined. */
104 for (i = 0; i < insn->n; ++i) {
105
106 /* /\* do this as one instruction?? *\/ */
107 /* outw(data[i], LSB_PORT(chan)); */
108
109 /* Need to do this as two instructions due to 8-bit bus?? */
110 /* first, load the low byte */
111 outb(LSB(data[i]), LSB_PORT(chan));
112 /* next, write the high byte */
113 outb(MSB(data[i]), MSB_PORT(chan));
114
115 /* save shadow register */
116 devpriv->ao_readback[chan] = data[i];
117
118 if (!devpriv->simultaneous_xfer_mode)
119 inb(LSB_PORT(chan));
120 }
121
122 /* return the number of samples written */
123 return i;
124 }
125
126 /* AO subdevices should have a read insn as well as a write insn.
127
128 Usually this means copying a value stored in devpriv->ao_readback.
129 However, since this driver supports simultaneous xfer then sometimes
130 this function actually accomplishes work.
131
132 Simultaneaous xfer mode is accomplished by loading ALL the values
133 you want for AO in all the channels, then READing off one of the AO
134 registers to initiate the instantaneous simultaneous update of all
135 DAC outputs, which makes all AO channels update simultaneously.
136 This is useful for some control applications, I would imagine.
137 */
138 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
139 struct comedi_insn *insn, unsigned int *data)
140 {
141 struct pcmda12_private *devpriv = dev->private;
142 int i;
143 int chan = CR_CHAN(insn->chanspec);
144
145 for (i = 0; i < insn->n; i++) {
146 if (devpriv->simultaneous_xfer_mode)
147 inb(LSB_PORT(chan));
148 /* read back shadow register */
149 data[i] = devpriv->ao_readback[chan];
150 }
151
152 return i;
153 }
154
155 static int pcmda12_attach(struct comedi_device *dev,
156 struct comedi_devconfig *it)
157 {
158 struct pcmda12_private *devpriv;
159 struct comedi_subdevice *s;
160 unsigned long iobase;
161 int ret;
162
163 iobase = it->options[0];
164 printk(KERN_INFO
165 "comedi%d: %s: io: %lx %s ", dev->minor, dev->driver->driver_name,
166 iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
167
168 if (!request_region(iobase, IOSIZE, dev->driver->driver_name)) {
169 printk("I/O port conflict\n");
170 return -EIO;
171 }
172 dev->iobase = iobase;
173
174 dev->board_name = dev->driver->driver_name;
175
176 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
177 if (!devpriv)
178 return -ENOMEM;
179 dev->private = devpriv;
180
181 devpriv->simultaneous_xfer_mode = it->options[1];
182
183 ret = comedi_alloc_subdevices(dev, 1);
184 if (ret)
185 return ret;
186
187 s = &dev->subdevices[0];
188 s->private = NULL;
189 s->maxdata = (0x1 << BITS) - 1;
190 s->range_table = &pcmda12_ranges;
191 s->type = COMEDI_SUBD_AO;
192 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
193 s->n_chan = CHANS;
194 s->insn_write = &ao_winsn;
195 s->insn_read = &ao_rinsn;
196
197 zero_chans(dev); /* clear out all the registers, basically */
198
199 printk(KERN_INFO "attached\n");
200
201 return 1;
202 }
203
204 static void pcmda12_detach(struct comedi_device *dev)
205 {
206 if (dev->iobase)
207 release_region(dev->iobase, IOSIZE);
208 }
209
210 static struct comedi_driver pcmda12_driver = {
211 .driver_name = "pcmda12",
212 .module = THIS_MODULE,
213 .attach = pcmda12_attach,
214 .detach = pcmda12_detach,
215 };
216 module_comedi_driver(pcmda12_driver);
217
218 MODULE_AUTHOR("Comedi http://www.comedi.org");
219 MODULE_DESCRIPTION("Comedi low-level driver");
220 MODULE_LICENSE("GPL");
This page took 0.064594 seconds and 5 git commands to generate.